Use atlas manager for circle style

This commit is contained in:
tsauerwein
2014-11-12 17:09:05 +01:00
parent ffced21893
commit b3b7579f84
2 changed files with 147 additions and 52 deletions
+120 -52
View File
@@ -1,5 +1,6 @@
goog.provide('ol.style.Circle'); goog.provide('ol.style.Circle');
goog.require('goog.asserts');
goog.require('goog.dom'); goog.require('goog.dom');
goog.require('goog.dom.TagName'); goog.require('goog.dom.TagName');
goog.require('ol.color'); goog.require('ol.color');
@@ -26,12 +27,17 @@ ol.style.Circle = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {}; var options = goog.isDef(opt_options) ? opt_options : {};
/**
* @private
* @type {Array.<ol.structs.Checksum>|null}
*/
this.checksums_ = null;
/** /**
* @private * @private
* @type {HTMLCanvasElement} * @type {HTMLCanvasElement}
*/ */
this.canvas_ = /** @type {HTMLCanvasElement} */ this.canvas_ = null;
(goog.dom.createElement(goog.dom.TagName.CANVAS));
/** /**
* @private * @private
@@ -47,9 +53,9 @@ ol.style.Circle = function(opt_options) {
/** /**
* @private * @private
* @type {Array.<number>} * @type {ol.style.Stroke}
*/ */
this.origin_ = [0, 0]; this.stroke_ = goog.isDef(options.stroke) ? options.stroke : null;
/** /**
* @private * @private
@@ -59,29 +65,29 @@ ol.style.Circle = function(opt_options) {
/** /**
* @private * @private
* @type {ol.style.Stroke} * @type {Array.<number>}
*/ */
this.stroke_ = goog.isDef(options.stroke) ? options.stroke : null; this.origin_ = [0, 0];
var size = this.render_();
/** /**
* @private * @private
* @type {Array.<number>} * @type {Array.<number>}
*/ */
this.anchor_ = [size / 2, size / 2]; this.anchor_ = null;
/** /**
* @private * @private
* @type {ol.Size} * @type {ol.Size}
*/ */
this.size_ = [size, size]; this.size_ = null;
/** /**
* @private * @private
* @type {Array.<ol.structs.Checksum>|null} * @type {ol.Size}
*/ */
this.checksums_ = null; this.imageSize_ = null;
this.render_(options.atlasManager);
/** /**
* @type {boolean} * @type {boolean}
@@ -149,7 +155,7 @@ ol.style.Circle.prototype.getImageState = function() {
* @inheritDoc * @inheritDoc
*/ */
ol.style.Circle.prototype.getImageSize = function() { ol.style.Circle.prototype.getImageSize = function() {
return this.size_; return this.imageSize_;
}; };
@@ -208,16 +214,20 @@ ol.style.Circle.prototype.unlistenImageChange = goog.nullFunction;
/** /**
* @private * @typedef {{strokeStyle: (string|undefined), strokeWidth: number,
* @return {number} Size. * size: number}}
*/ */
ol.style.Circle.prototype.render_ = function() { ol.style.Circle.RenderOptions;
var canvas = this.canvas_;
var strokeStyle, strokeWidth;
if (goog.isNull(this.stroke_)) {
strokeWidth = 0; /**
} else { * @private
* @param {ol.style.AtlasManager|undefined} atlasManager
*/
ol.style.Circle.prototype.render_ = function(atlasManager) {
var strokeStyle, strokeWidth = 0, imageSize;
if (!goog.isNull(this.stroke_)) {
strokeStyle = ol.color.asString(this.stroke_.getColor()); strokeStyle = ol.color.asString(this.stroke_.getColor());
strokeWidth = this.stroke_.getWidth(); strokeWidth = this.stroke_.getWidth();
if (!goog.isDef(strokeWidth)) { if (!goog.isDef(strokeWidth)) {
@@ -227,54 +237,112 @@ ol.style.Circle.prototype.render_ = function() {
var size = 2 * (this.radius_ + strokeWidth) + 1; var size = 2 * (this.radius_ + strokeWidth) + 1;
// draw the circle on the canvas /** @type {ol.style.Circle.RenderOptions} */
var renderOptions = {
strokeStyle: strokeStyle,
strokeWidth: strokeWidth,
size: size
};
canvas.height = size; if (!goog.isDef(atlasManager)) {
canvas.width = size; // no atlas manager is used, create a new canvas
this.canvas_ = /** @type {HTMLCanvasElement} */
(goog.dom.createElement(goog.dom.TagName.CANVAS));
this.canvas_.height = size;
this.canvas_.width = size;
// canvas.width and height are rounded to the closest integer // canvas.width and height are rounded to the closest integer
size = canvas.width; size = this.canvas_.width;
imageSize = size;
var context = /** @type {CanvasRenderingContext2D} */ // draw the circle on the canvas
(canvas.getContext('2d')); var context = /** @type {CanvasRenderingContext2D} */
context.arc(size / 2, size / 2, this.radius_, 0, 2 * Math.PI, true); (this.canvas_.getContext('2d'));
this.draw_(renderOptions, context, 0, 0);
} else {
// an atlas manager is used, add the symbol to an atlas
size = Math.round(size);
var id = this.getChecksum();
var info = atlasManager.add(
id, size, size, goog.bind(this.draw_, this, renderOptions));
goog.asserts.assert(info !== null, 'circle radius is too large');
this.canvas_ = info.image;
this.origin_ = [info.offsetX, info.offsetY];
imageSize = info.image.width;
}
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);
}
};
/**
* @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.draw_ = 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);
if (!goog.isNull(this.fill_)) { if (!goog.isNull(this.fill_)) {
context.fillStyle = ol.color.asString(this.fill_.getColor()); context.fillStyle = ol.color.asString(this.fill_.getColor());
context.fill(); context.fill();
} }
if (!goog.isNull(this.stroke_)) { if (!goog.isNull(this.stroke_)) {
context.strokeStyle = strokeStyle; context.strokeStyle = renderOptions.strokeStyle;
context.lineWidth = strokeWidth; context.lineWidth = renderOptions.strokeWidth;
context.stroke(); context.stroke();
} }
context.closePath();
};
// deal with the hit detection canvas
if (!goog.isNull(this.fill_)) { /**
this.hitDetectionCanvas_ = canvas; * @private
} else { * @param {ol.style.Circle.RenderOptions} renderOptions
this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */ */
(goog.dom.createElement(goog.dom.TagName.CANVAS)); ol.style.Circle.prototype.createHitDetectionCanvas_ = function(renderOptions) {
canvas = this.hitDetectionCanvas_; this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */
(goog.dom.createElement(goog.dom.TagName.CANVAS));
var canvas = this.hitDetectionCanvas_;
canvas.height = size; canvas.height = renderOptions.size;
canvas.width = size; canvas.width = renderOptions.size;
context = /** @type {CanvasRenderingContext2D} */ var context = /** @type {CanvasRenderingContext2D} */
(canvas.getContext('2d')); (canvas.getContext('2d'));
context.arc(size / 2, size / 2, this.radius_, 0, 2 * Math.PI, true); context.arc(
renderOptions.size / 2, renderOptions.size / 2,
this.radius_, 0, 2 * Math.PI, true);
context.fillStyle = ol.render.canvas.defaultFillStyle; context.fillStyle = ol.render.canvas.defaultFillStyle;
context.fill(); context.fill();
if (!goog.isNull(this.stroke_)) { if (!goog.isNull(this.stroke_)) {
context.strokeStyle = strokeStyle; context.strokeStyle = renderOptions.strokeStyle;
context.lineWidth = strokeWidth; context.lineWidth = renderOptions.strokeWidth;
context.stroke(); context.stroke();
}
} }
return size;
}; };
+27
View File
@@ -3,6 +3,32 @@ goog.provide('ol.test.style.Circle');
describe('ol.style.Circle', function() { describe('ol.style.Circle', function() {
describe('#constructor', function() {
it('creates a canvas if no atlas is used', 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]);
expect(style.getImage()).to.not.be(style.getHitDetectionImage());
expect(style.getHitDetectionImage()).to.be.an(HTMLCanvasElement);
});
it('adds itself to an atlas manager', 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);
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]);
expect(style.getImage()).to.not.be(style.getHitDetectionImage());
expect(style.getHitDetectionImage()).to.be.an(HTMLCanvasElement);
});
});
describe('#getChecksum', function() { describe('#getChecksum', function() {
it('calculates the same hash code for default options', function() { it('calculates the same hash code for default options', function() {
@@ -162,6 +188,7 @@ describe('ol.style.Circle', function() {
}); });
}); });
goog.require('ol.style.AtlasManager');
goog.require('ol.style.Circle'); goog.require('ol.style.Circle');
goog.require('ol.style.Fill'); goog.require('ol.style.Fill');
goog.require('ol.style.Stroke'); goog.require('ol.style.Stroke');