diff --git a/src/RenderWebGL.js b/src/RenderWebGL.js index 28fec5f7e..54bb09cf8 100644 --- a/src/RenderWebGL.js +++ b/src/RenderWebGL.js @@ -1880,9 +1880,16 @@ class RenderWebGL extends EventEmitter { return [x, y]; } + const skin = drawable._skin; + if (!skin) { + // A target can move while its skin is still loading or after it was destroyed. + // There is nothing to fence against, so keep the requested position. + return [x, y]; + } + const dx = x - drawable._position[0]; const dy = y - drawable._position[1]; - const aabb = drawable._skin.getFenceBounds(drawable, __fenceBounds); + const aabb = skin.getFenceBounds(drawable, __fenceBounds); const inset = Math.floor(Math.min(aabb.width, aabb.height) / 2); const sx = this._xRight - Math.min(FENCE_WIDTH, inset); diff --git a/test/unit/RenderWebGLOptimizationTests.js b/test/unit/RenderWebGLOptimizationTests.js index 2711883af..dcab93a2b 100644 --- a/test/unit/RenderWebGLOptimizationTests.js +++ b/test/unit/RenderWebGLOptimizationTests.js @@ -40,3 +40,11 @@ test('skin sizes tolerate asynchronous loading and destroyed skins', t => { t.same(renderer.getSkinSize(123), [0, 0]); t.end(); }); + +test('fencing keeps the requested position while a drawable has no skin', t => { + const renderer = Object.create(RenderWebGL.prototype); + renderer._allDrawables = [{_position: [0, 0], _skin: null}]; + t.same(renderer.getFencedPositionOfDrawable(0, [500, -400]), [500, -400]); + t.same(renderer.getFencedPositionOfDrawable(7, [12, 34]), [12, 34]); + t.end(); +});