Integrate atlas manager into RegularShape

This commit is contained in:
tsauerwein
2014-11-13 11:48:23 +01:00
parent 7593a18a19
commit e9e76954b2
2 changed files with 148 additions and 56 deletions

View File

@@ -1,5 +1,6 @@
goog.provide('ol.style.RegularShape'); goog.provide('ol.style.RegularShape');
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');
@@ -35,8 +36,7 @@ ol.style.RegularShape = function(opt_options) {
* @private * @private
* @type {HTMLCanvasElement} * @type {HTMLCanvasElement}
*/ */
this.canvas_ = /** @type {HTMLCanvasElement} */ this.canvas_ = null;
(goog.dom.createElement(goog.dom.TagName.CANVAS));
/** /**
* @private * @private
@@ -87,19 +87,25 @@ ol.style.RegularShape = function(opt_options) {
*/ */
this.stroke_ = goog.isDef(options.stroke) ? options.stroke : null; this.stroke_ = goog.isDef(options.stroke) ? options.stroke : null;
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
* @type {ol.Size}
*/
this.imageSize_ = null;
this.render_(options.atlasManager);
/** /**
* @type {boolean} * @type {boolean}
@@ -158,7 +164,7 @@ ol.style.RegularShape.prototype.getImage = function(pixelRatio) {
* @inheritDoc * @inheritDoc
*/ */
ol.style.RegularShape.prototype.getImageSize = function() { ol.style.RegularShape.prototype.getImageSize = function() {
return this.size_; return this.imageSize_;
}; };
@@ -225,16 +231,20 @@ ol.style.RegularShape.prototype.unlistenImageChange = goog.nullFunction;
/** /**
* @private * @typedef {{strokeStyle: (string|undefined), strokeWidth: number,
* @return {number} Size. * size: number}}
*/ */
ol.style.RegularShape.prototype.render_ = function() { ol.style.RegularShape.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.RegularShape.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)) {
@@ -244,17 +254,70 @@ ol.style.RegularShape.prototype.render_ = function() {
var size = 2 * (this.radius_ + strokeWidth) + 1; var size = 2 * (this.radius_ + strokeWidth) + 1;
// draw the regular shape on the canvas /** @type {ol.style.RegularShape.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} */ var context = /** @type {CanvasRenderingContext2D} */
(canvas.getContext('2d')); (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, 'shape size 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.RegularShape.prototype.draw_ = function(renderOptions, context, x, y) {
var i, angle0, radiusC; var i, angle0, radiusC;
// reset transform
context.setTransform(1, 0, 0, 1, 0, 0);
// then move to (x, y)
context.translate(x, y);
context.beginPath(); context.beginPath();
if (this.radius2_ !== this.radius_) { if (this.radius2_ !== this.radius_) {
this.points_ = 2 * this.points_; this.points_ = 2 * this.points_;
@@ -262,8 +325,8 @@ ol.style.RegularShape.prototype.render_ = function() {
for (i = 0; i <= this.points_; i++) { for (i = 0; i <= this.points_; i++) {
angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_; angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_;
radiusC = i % 2 === 0 ? this.radius_ : this.radius2_; radiusC = i % 2 === 0 ? this.radius_ : this.radius2_;
context.lineTo(size / 2 + radiusC * Math.cos(angle0), context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),
size / 2 + radiusC * Math.sin(angle0)); renderOptions.size / 2 + radiusC * Math.sin(angle0));
} }
if (!goog.isNull(this.fill_)) { if (!goog.isNull(this.fill_)) {
@@ -271,46 +334,48 @@ ol.style.RegularShape.prototype.render_ = function() {
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.RegularShape.RenderOptions} renderOptions
*/
ol.style.RegularShape.prototype.createHitDetectionCanvas_ =
function(renderOptions) {
this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */ this.hitDetectionCanvas_ = /** @type {HTMLCanvasElement} */
(goog.dom.createElement(goog.dom.TagName.CANVAS)); (goog.dom.createElement(goog.dom.TagName.CANVAS));
canvas = this.hitDetectionCanvas_; 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.beginPath(); context.beginPath();
if (this.radius2_ !== this.radius_) { if (this.radius2_ !== this.radius_) {
this.points_ = 2 * this.points_; this.points_ = 2 * this.points_;
} }
var i, radiusC, angle0;
for (i = 0; i <= this.points_; i++) { for (i = 0; i <= this.points_; i++) {
angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_; angle0 = i * 2 * Math.PI / this.points_ - Math.PI / 2 + this.angle_;
radiusC = i % 2 === 0 ? this.radius_ : this.radius2_; radiusC = i % 2 === 0 ? this.radius_ : this.radius2_;
context.lineTo(size / 2 + radiusC * Math.cos(angle0), context.lineTo(renderOptions.size / 2 + radiusC * Math.cos(angle0),
size / 2 + radiusC * Math.sin(angle0)); renderOptions.size / 2 + radiusC * Math.sin(angle0));
} }
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;
}; };

View File

@@ -3,6 +3,33 @@ goog.provide('ol.test.style.RegularShape');
describe('ol.style.RegularShape', function() { describe('ol.style.RegularShape', function() {
describe('#constructor', function() {
it('creates a canvas if no atlas is used', 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]);
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.RegularShape(
{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() {