Add hit-detection image to atlas (Circle)

This commit is contained in:
tsauerwein
2014-11-21 09:41:10 +01:00
parent 97f8e4ac8d
commit 4132505313
2 changed files with 128 additions and 10 deletions

View File

@@ -69,6 +69,12 @@ ol.style.Circle = function(opt_options) {
*/
this.origin_ = [0, 0];
/**
* @private
* @type {Array.<number>}
*/
this.hitDetectionOrigin_ = [0, 0];
/**
* @private
* @type {Array.<number>}
@@ -87,6 +93,12 @@ ol.style.Circle = function(opt_options) {
*/
this.imageSize_ = null;
/**
* @private
* @type {ol.Size}
*/
this.hitDetectionImageSize_ = null;
this.render_(options.atlasManager);
/**
@@ -159,6 +171,14 @@ ol.style.Circle.prototype.getImageSize = function() {
};
/**
* @inheritDoc
*/
ol.style.Circle.prototype.getHitDetectionImageSize = function() {
return this.hitDetectionImageSize_;
};
/**
* @inheritDoc
* @api
@@ -168,6 +188,14 @@ ol.style.Circle.prototype.getOrigin = function() {
};
/**
* @inheritDoc
*/
ol.style.Circle.prototype.getHitDetectionOrigin = function() {
return this.hitDetectionOrigin_;
};
/**
* @return {number} Radius.
* @api
@@ -259,30 +287,45 @@ ol.style.Circle.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, 'circle radius 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);
}
};
@@ -323,6 +366,14 @@ ol.style.Circle.prototype.draw_ = function(renderOptions, context, x, y) {
* @param {ol.style.Circle.RenderOptions} renderOptions
*/
ol.style.Circle.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_;
@@ -332,6 +383,26 @@ ol.style.Circle.prototype.createHitDetectionCanvas_ = function(renderOptions) {
var context = /** @type {CanvasRenderingContext2D} */
(canvas.getContext('2d'));
this.drawHitDetectionCanvas_(renderOptions, context, 0, 0);
};
/**
* @private
* @param {ol.style.Circle.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.Circle.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();
context.arc(
renderOptions.size / 2, renderOptions.size / 2,
this.radius_, 0, 2 * Math.PI, true);
@@ -343,6 +414,7 @@ ol.style.Circle.prototype.createHitDetectionCanvas_ = function(renderOptions) {
context.lineWidth = renderOptions.strokeWidth;
context.stroke();
}
context.closePath();
};

View File

@@ -5,18 +5,40 @@ describe('ol.style.Circle', 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.Circle({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.Circle({
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.Circle({radius: 10, atlasManager: atlasManager});
expect(style.getImage()).to.be.an(HTMLCanvasElement);
@@ -24,8 +46,32 @@ describe('ol.style.Circle', 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.Circle({
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]);
});
});