diff --git a/src/ol/style/regularshapestyle.js b/src/ol/style/regularshapestyle.js index 381a674d5d..9eb5864ade 100644 --- a/src/ol/style/regularshapestyle.js +++ b/src/ol/style/regularshapestyle.js @@ -56,6 +56,12 @@ ol.style.RegularShape = function(opt_options) { */ this.origin_ = [0, 0]; + /** + * @private + * @type {Array.} + */ + this.hitDetectionOrigin_ = [0, 0]; + /** * @private * @type {number} @@ -105,6 +111,12 @@ ol.style.RegularShape = function(opt_options) { */ this.imageSize_ = null; + /** + * @private + * @type {ol.Size} + */ + this.hitDetectionImageSize_ = null; + this.render_(options.atlasManager); /** @@ -168,6 +180,14 @@ ol.style.RegularShape.prototype.getImageSize = function() { }; +/** + * @inheritDoc + */ +ol.style.RegularShape.prototype.getHitDetectionImageSize = function() { + return this.hitDetectionImageSize_; +}; + + /** * @inheritDoc */ @@ -185,6 +205,14 @@ ol.style.RegularShape.prototype.getOrigin = function() { }; +/** + * @inheritDoc + */ +ol.style.RegularShape.prototype.getHitDetectionOrigin = function() { + return this.hitDetectionOrigin_; +}; + + /** * @return {number} Radius. * @api @@ -276,30 +304,45 @@ ol.style.RegularShape.prototype.render_ = function(atlasManager) { var context = /** @type {CanvasRenderingContext2D} */ (this.canvas_.getContext('2d')); this.draw_(renderOptions, context, 0, 0); + + this.createHitDetectionCanvas_(renderOptions); } else { // an atlas manager is used, add the symbol to an atlas size = Math.round(size); + var hasCustomHitDetectionImage = goog.isNull(this.fill_); + var renderHitDetectionCallback; + if (hasCustomHitDetectionImage) { + // render the hit-detection image into a separate atlas image + renderHitDetectionCallback = + goog.bind(this.drawHitDetectionCanvas_, this, renderOptions); + } + var id = this.getChecksum(); var info = atlasManager.add( - id, size, size, goog.bind(this.draw_, this, renderOptions)); + id, size, size, goog.bind(this.draw_, this, renderOptions), + renderHitDetectionCallback); goog.asserts.assert(info !== null, 'shape size is too large'); this.canvas_ = info.image; this.origin_ = [info.offsetX, info.offsetY]; imageSize = info.image.width; + + if (hasCustomHitDetectionImage) { + this.hitDetectionCanvas_ = info.hitImage; + this.hitDetectionOrigin_ = [info.hitOffsetX, info.hitOffsetY]; + this.hitDetectionImageSize_ = + [info.hitImage.width, info.hitImage.height]; + } else { + this.hitDetectionCanvas_ = this.canvas_; + this.hitDetectionOrigin_ = this.origin_; + this.hitDetectionImageSize_ = [imageSize, imageSize]; + } } this.anchor_ = [size / 2, size / 2]; this.size_ = [size, size]; this.imageSize_ = [imageSize, imageSize]; - - // deal with the hit detection canvas - if (!goog.isNull(this.fill_)) { - this.hitDetectionCanvas_ = this.canvas_; - } else { - this.createHitDetectionCanvas_(renderOptions); - } }; @@ -348,6 +391,14 @@ ol.style.RegularShape.prototype.draw_ = function(renderOptions, context, x, y) { */ ol.style.RegularShape.prototype.createHitDetectionCanvas_ = function(renderOptions) { + this.hitDetectionImageSize_ = [renderOptions.size, renderOptions.size]; + if (!goog.isNull(this.fill_)) { + this.hitDetectionCanvas_ = this.canvas_; + return; + } + + // if no fill style is set, create an extra hit-detection image with a + // default fill style this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */ (goog.dom.createElement(goog.dom.TagName.CANVAS)); var canvas = this.hitDetectionCanvas_; @@ -357,6 +408,25 @@ ol.style.RegularShape.prototype.createHitDetectionCanvas_ = var context = /** @type {CanvasRenderingContext2D} */ (canvas.getContext('2d')); + this.drawHitDetectionCanvas_(renderOptions, context, 0, 0); +}; + + +/** + * @private + * @param {ol.style.RegularShape.RenderOptions} renderOptions + * @param {CanvasRenderingContext2D} context + * @param {number} x The origin for the symbol (x). + * @param {number} y The origin for the symbol (y). + */ +ol.style.RegularShape.prototype.drawHitDetectionCanvas_ = + function(renderOptions, context, x, y) { + // reset transform + context.setTransform(1, 0, 0, 1, 0, 0); + + // then move to (x, y) + context.translate(x, y); + context.beginPath(); if (this.radius2_ !== this.radius_) { this.points_ = 2 * this.points_; @@ -376,6 +446,7 @@ ol.style.RegularShape.prototype.createHitDetectionCanvas_ = context.lineWidth = renderOptions.strokeWidth; context.stroke(); } + context.closePath(); }; diff --git a/test/spec/ol/style/regularshapestyle.test.js b/test/spec/ol/style/regularshapestyle.test.js index c382da8a59..585d34c2f6 100644 --- a/test/spec/ol/style/regularshapestyle.test.js +++ b/test/spec/ol/style/regularshapestyle.test.js @@ -5,18 +5,40 @@ describe('ol.style.RegularShape', function() { describe('#constructor', function() { - it('creates a canvas if no atlas is used', function() { + it('creates a canvas if no atlas is used (no fill-style)', function() { var style = new ol.style.RegularShape({radius: 10}); expect(style.getImage()).to.be.an(HTMLCanvasElement); expect(style.getSize()).to.eql([21, 21]); expect(style.getImageSize()).to.eql([21, 21]); expect(style.getOrigin()).to.eql([0, 0]); expect(style.getAnchor()).to.eql([10.5, 10.5]); + // hit-detection image is created, because no fill style is set expect(style.getImage()).to.not.be(style.getHitDetectionImage()); expect(style.getHitDetectionImage()).to.be.an(HTMLCanvasElement); + expect(style.getHitDetectionImageSize()).to.eql([21, 21]); + expect(style.getHitDetectionOrigin()).to.eql([0, 0]); }); - it('adds itself to an atlas manager', function() { + it('creates a canvas if no atlas is used (fill-style)', function() { + var style = new ol.style.RegularShape({ + radius: 10, + fill: new ol.style.Fill({ + color: '#FFFF00' + }) + }); + expect(style.getImage()).to.be.an(HTMLCanvasElement); + expect(style.getSize()).to.eql([21, 21]); + expect(style.getImageSize()).to.eql([21, 21]); + expect(style.getOrigin()).to.eql([0, 0]); + expect(style.getAnchor()).to.eql([10.5, 10.5]); + // no hit-detection image is created, because fill style is set + expect(style.getImage()).to.be(style.getHitDetectionImage()); + expect(style.getHitDetectionImage()).to.be.an(HTMLCanvasElement); + expect(style.getHitDetectionImageSize()).to.eql([21, 21]); + expect(style.getHitDetectionOrigin()).to.eql([0, 0]); + }); + + it('adds itself to an atlas manager (no fill-style)', function() { var atlasManager = new ol.style.AtlasManager({size: 512}); var style = new ol.style.RegularShape( {radius: 10, atlasManager: atlasManager}); @@ -25,8 +47,32 @@ describe('ol.style.RegularShape', function() { expect(style.getImageSize()).to.eql([512, 512]); expect(style.getOrigin()).to.eql([1, 1]); expect(style.getAnchor()).to.eql([10.5, 10.5]); + // hit-detection image is created, because no fill style is set expect(style.getImage()).to.not.be(style.getHitDetectionImage()); expect(style.getHitDetectionImage()).to.be.an(HTMLCanvasElement); + expect(style.getHitDetectionImageSize()).to.eql([512, 512]); + expect(style.getHitDetectionOrigin()).to.eql([1, 1]); + }); + + it('adds itself to an atlas manager (fill-style)', function() { + var atlasManager = new ol.style.AtlasManager({size: 512}); + var style = new ol.style.RegularShape({ + radius: 10, + atlasManager: atlasManager, + fill: new ol.style.Fill({ + color: '#FFFF00' + }) + }); + expect(style.getImage()).to.be.an(HTMLCanvasElement); + expect(style.getSize()).to.eql([21, 21]); + expect(style.getImageSize()).to.eql([512, 512]); + expect(style.getOrigin()).to.eql([1, 1]); + expect(style.getAnchor()).to.eql([10.5, 10.5]); + // no hit-detection image is created, because fill style is set + expect(style.getImage()).to.be(style.getHitDetectionImage()); + expect(style.getHitDetectionImage()).to.be.an(HTMLCanvasElement); + expect(style.getHitDetectionImageSize()).to.eql([512, 512]); + expect(style.getHitDetectionOrigin()).to.eql([1, 1]); }); });