diff --git a/src/ol/style/circlestyle.js b/src/ol/style/circlestyle.js
index 7983b0a280..dd5f63c8f2 100644
--- a/src/ol/style/circlestyle.js
+++ b/src/ol/style/circlestyle.js
@@ -1,5 +1,6 @@
goog.provide('ol.style.Circle');
+goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('ol.color');
@@ -26,12 +27,17 @@ ol.style.Circle = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
+ /**
+ * @private
+ * @type {Array.
|null}
+ */
+ this.checksums_ = null;
+
/**
* @private
* @type {HTMLCanvasElement}
*/
- this.canvas_ = /** @type {HTMLCanvasElement} */
- (goog.dom.createElement(goog.dom.TagName.CANVAS));
+ this.canvas_ = null;
/**
* @private
@@ -47,9 +53,9 @@ ol.style.Circle = function(opt_options) {
/**
* @private
- * @type {Array.}
+ * @type {ol.style.Stroke}
*/
- this.origin_ = [0, 0];
+ this.stroke_ = goog.isDef(options.stroke) ? options.stroke : null;
/**
* @private
@@ -59,29 +65,29 @@ ol.style.Circle = function(opt_options) {
/**
* @private
- * @type {ol.style.Stroke}
+ * @type {Array.}
*/
- this.stroke_ = goog.isDef(options.stroke) ? options.stroke : null;
-
- var size = this.render_();
+ this.origin_ = [0, 0];
/**
* @private
* @type {Array.}
*/
- this.anchor_ = [size / 2, size / 2];
+ this.anchor_ = null;
/**
* @private
* @type {ol.Size}
*/
- this.size_ = [size, size];
+ this.size_ = null;
/**
* @private
- * @type {Array.|null}
+ * @type {ol.Size}
*/
- this.checksums_ = null;
+ this.imageSize_ = null;
+
+ this.render_(options.atlasManager);
/**
* @type {boolean}
@@ -149,7 +155,7 @@ ol.style.Circle.prototype.getImageState = function() {
* @inheritDoc
*/
ol.style.Circle.prototype.getImageSize = function() {
- return this.size_;
+ return this.imageSize_;
};
@@ -208,16 +214,20 @@ ol.style.Circle.prototype.unlistenImageChange = goog.nullFunction;
/**
- * @private
- * @return {number} Size.
+ * @typedef {{strokeStyle: (string|undefined), strokeWidth: number,
+ * size: number}}
*/
-ol.style.Circle.prototype.render_ = function() {
- var canvas = this.canvas_;
- var strokeStyle, strokeWidth;
+ol.style.Circle.RenderOptions;
- 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());
strokeWidth = this.stroke_.getWidth();
if (!goog.isDef(strokeWidth)) {
@@ -227,54 +237,112 @@ ol.style.Circle.prototype.render_ = function() {
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;
- canvas.width = size;
+ if (!goog.isDef(atlasManager)) {
+ // 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
- size = canvas.width;
+ // canvas.width and height are rounded to the closest integer
+ size = this.canvas_.width;
+ imageSize = size;
- var context = /** @type {CanvasRenderingContext2D} */
- (canvas.getContext('2d'));
- context.arc(size / 2, size / 2, this.radius_, 0, 2 * Math.PI, true);
+ // draw the circle on the canvas
+ var context = /** @type {CanvasRenderingContext2D} */
+ (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_)) {
context.fillStyle = ol.color.asString(this.fill_.getColor());
context.fill();
}
if (!goog.isNull(this.stroke_)) {
- context.strokeStyle = strokeStyle;
- context.lineWidth = strokeWidth;
+ context.strokeStyle = renderOptions.strokeStyle;
+ context.lineWidth = renderOptions.strokeWidth;
context.stroke();
}
+ context.closePath();
+};
- // deal with the hit detection canvas
- if (!goog.isNull(this.fill_)) {
- this.hitDetectionCanvas_ = canvas;
- } else {
- this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */
- (goog.dom.createElement(goog.dom.TagName.CANVAS));
- canvas = this.hitDetectionCanvas_;
+/**
+ * @private
+ * @param {ol.style.Circle.RenderOptions} renderOptions
+ */
+ol.style.Circle.prototype.createHitDetectionCanvas_ = function(renderOptions) {
+ this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */
+ (goog.dom.createElement(goog.dom.TagName.CANVAS));
+ var canvas = this.hitDetectionCanvas_;
- canvas.height = size;
- canvas.width = size;
+ canvas.height = renderOptions.size;
+ canvas.width = renderOptions.size;
- context = /** @type {CanvasRenderingContext2D} */
- (canvas.getContext('2d'));
- context.arc(size / 2, size / 2, this.radius_, 0, 2 * Math.PI, true);
+ var context = /** @type {CanvasRenderingContext2D} */
+ (canvas.getContext('2d'));
+ context.arc(
+ renderOptions.size / 2, renderOptions.size / 2,
+ this.radius_, 0, 2 * Math.PI, true);
- context.fillStyle = ol.render.canvas.defaultFillStyle;
- context.fill();
- if (!goog.isNull(this.stroke_)) {
- context.strokeStyle = strokeStyle;
- context.lineWidth = strokeWidth;
- context.stroke();
- }
+ context.fillStyle = ol.render.canvas.defaultFillStyle;
+ context.fill();
+ if (!goog.isNull(this.stroke_)) {
+ context.strokeStyle = renderOptions.strokeStyle;
+ context.lineWidth = renderOptions.strokeWidth;
+ context.stroke();
}
-
- return size;
};
diff --git a/test/spec/ol/style/circlestyle.test.js b/test/spec/ol/style/circlestyle.test.js
index 00eb1765a6..40c9f66b5a 100644
--- a/test/spec/ol/style/circlestyle.test.js
+++ b/test/spec/ol/style/circlestyle.test.js
@@ -3,6 +3,32 @@ goog.provide('ol.test.style.Circle');
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() {
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.Fill');
goog.require('ol.style.Stroke');