diff --git a/src/BaseLayer.js b/src/BaseLayer.js index 795ba4cc..126b023e 100644 --- a/src/BaseLayer.js +++ b/src/BaseLayer.js @@ -49,6 +49,9 @@ this.getHitCanvas().getContext().clear(bounds); return this; }, + clearHitCache: function() { + this._hitImageData = undefined; + }, // extend Node.prototype.setZIndex setZIndex: function(index) { Kinetic.Node.prototype.setZIndex.call(this, index); diff --git a/src/Container.js b/src/Container.js index 9cf7e01d..4c55e869 100644 --- a/src/Container.js +++ b/src/Container.js @@ -308,7 +308,7 @@ if (this.shouldDrawHit(canvas)) { if (layer) { - layer.imageData = null; // Clear getImageData cache + layer.clearHitCache(); } if (cachedHitCanvas) { this._drawCachedHitCanvas(context); diff --git a/src/Layer.js b/src/Layer.js index 01e9b431..b01a436b 100644 --- a/src/Layer.js +++ b/src/Layer.js @@ -92,28 +92,20 @@ return null; } }, - /** - * Get ImageData.data array for an individual pixel on the hit canvas. - * Data is cached as getImageData is an expensive method to call often. - * - * @param {Number} x - * @param {Number} x - * @returns {Array} One-dimensional array containing the data in the RGBA order, with integer values between 0 and 255 - */ _getImageData: function(x, y) { var width = this.hitCanvas.width || 1, height = this.hitCanvas.height || 1, index = (y * width ) + x; - if (!this.imageData) { - this.imageData = this.hitCanvas.context._context.getImageData(0, 0, width, height); + if (!this._hitImageData) { + this._hitImageData = this.hitCanvas.context.getImageData(0, 0, width, height); } return [ - this.imageData.data[4 * index + 0] , // Red - this.imageData.data[4 * index + 1], // Green - this.imageData.data[4 * index + 2], // Blue - this.imageData.data[4 * index + 3] // Alpha + this._hitImageData.data[4 * index + 0] , // Red + this._hitImageData.data[4 * index + 1], // Green + this._hitImageData.data[4 * index + 2], // Blue + this._hitImageData.data[4 * index + 3] // Alpha ]; }, _getIntersection: function(pos) { diff --git a/src/Shape.js b/src/Shape.js index b50906cd..cfcb6049 100644 --- a/src/Shape.js +++ b/src/Shape.js @@ -210,7 +210,7 @@ if(this.shouldDrawHit(canvas)) { if (layer) { - layer.imageData = null; // Clear getImageData cache + layer.clearHitCache(); } if (cachedHitCanvas) { this._drawCachedHitCanvas(context); diff --git a/test/unit/Layer-test.js b/test/unit/Layer-test.js index 17d57d7b..4b2872a7 100644 --- a/test/unit/Layer-test.js +++ b/test/unit/Layer-test.js @@ -292,4 +292,62 @@ suite('Layer', function() { assert.equal(layer.hitGraphEnabled(), true); assert.equal(layer.shouldDrawHit(), true); }); + + // ====================================================== + test('hit graph caching', function() { + var stage = addStage(); + var layer = new Kinetic.Layer(); + var originGetImageData = layer.getHitCanvas().getContext().getImageData; + var count = 0; + layer.getHitCanvas().getContext().getImageData = function() { + count += 1; + return originGetImageData.apply(this, arguments); + }; + + stage.add(layer); + + var circle = new Kinetic.Circle({ + x: stage.getWidth() / 2, + y: stage.getHeight() / 2, + radius: 70, + fill: 'red', + stroke: 'black', + strokeWidth: 4 + }); + layer.add(circle); + layer.draw(); + assert.equal(count, 0, 'draw should not touch getImageData'); + var top = stage.content.getBoundingClientRect().top; + stage._mousemove({ + clientX: stage.getWidth() / 2, + clientY: stage.getHeight() / 2 + top + }); + + // while mouse event we need hit canvas info + assert.equal(count, 1, 'getImageData should be called once'); + + stage._mousemove({ + clientX: stage.getWidth() / 2, + clientY: stage.getHeight() / 2 + top + 2 + }); + + assert.equal(count, 1, 'getImageData should not be called, because data is cached'); + + var group = new Kinetic.Group(); + group.cache({ + width : 1, + height : 1 + }); + layer.add(group); + + group.draw(); + + stage._mousemove({ + clientX: stage.getWidth() / 2, + clientY: stage.getHeight() / 2 + top + 2 + }); + + // after drawing group hit cache should be cleared + assert.equal(count, 2, 'while creating new cache getImageData should be called'); + }); }); \ No newline at end of file