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

View File

@@ -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.<ol.structs.Checksum>|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.<number>}
* @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.<number>}
*/
this.stroke_ = goog.isDef(options.stroke) ? options.stroke : null;
var size = this.render_();
this.origin_ = [0, 0];
/**
* @private
* @type {Array.<number>}
*/
this.anchor_ = [size / 2, size / 2];
this.anchor_ = null;
/**
* @private
* @type {ol.Size}
*/
this.size_ = [size, size];
this.size_ = null;
/**
* @private
* @type {Array.<ol.structs.Checksum>|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;
};

View File

@@ -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');