From 140e9ba355ce34b1c0cbba25598cee50edf98c05 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Fri, 18 Jan 2013 17:22:07 -0700 Subject: [PATCH] General purpose canvas renderer Currently only renders points as circles. Eventually will have methods for other geometry types and other symbolizer types. Also provides static methods to render point symbolizers (returning a canvas that can be drawn on another). --- src/ol/renderer/canvas/canvasrenderer.js | 128 ++++++++++++++++++----- src/ol/style/point.js | 2 +- 2 files changed, 100 insertions(+), 30 deletions(-) diff --git a/src/ol/renderer/canvas/canvasrenderer.js b/src/ol/renderer/canvas/canvasrenderer.js index da8c2d0cff..a22dcfa427 100644 --- a/src/ol/renderer/canvas/canvasrenderer.js +++ b/src/ol/renderer/canvas/canvasrenderer.js @@ -1,17 +1,17 @@ goog.provide('ol.renderer.canvas'); -goog.provide('ol.renderer.canvas.CanvasRenderer'); +goog.provide('ol.renderer.canvas.Renderer'); goog.require('goog.asserts'); +goog.require('goog.vec.Mat4'); goog.require('ol.Coordinate'); goog.require('ol.Pixel'); goog.require('ol.canvas'); goog.require('ol.geom.Geometry'); goog.require('ol.geom.Point'); goog.require('ol.renderer.Layer'); -goog.require('ol.style.LiteralFill'); +goog.require('ol.style.LiteralPoint'); goog.require('ol.style.LiteralShape'); -goog.require('ol.style.LiteralStroke'); -goog.require('ol.style.LiteralSymbolizer'); +goog.require('ol.style.ShapeType'); /** @@ -23,48 +23,118 @@ ol.renderer.canvas.isSupported = ol.canvas.isSupported; /** * @constructor + * @param {!HTMLCanvasElement} canvas Target canvas. + * @param {!goog.vec.Mat4.Number} transform Transform. + * @param {ol.Pixel=} opt_offset Pixel offset for top-left corner. This is + * provided as an optional argument as a convenience in cases where the + * transform applies to a separate canvas. */ -ol.renderer.canvas.CanvasRenderer = function() { +ol.renderer.canvas.Renderer = function(canvas, transform, opt_offset) { + + var context = /** @type {CanvasRenderingContext2D} */ + (canvas.getContext('2d')), + dx = goog.isDef(opt_offset) ? opt_offset.x : 0, + dy = goog.isDef(opt_offset) ? opt_offset.y : 0; + + context.setTransform( + goog.vec.Mat4.getElement(transform, 0, 0), + goog.vec.Mat4.getElement(transform, 1, 0), + goog.vec.Mat4.getElement(transform, 0, 1), + goog.vec.Mat4.getElement(transform, 1, 1), + goog.vec.Mat4.getElement(transform, 0, 3) + dx, + goog.vec.Mat4.getElement(transform, 1, 3) + dy); /** * @type {CanvasRenderingContext2D} * @private */ - this.context_ = null; - - /** - * @type {ol.Pixel} - * @private - */ - this.offset_ = null; + this.context_ = context; }; /** - * Confirm that we're ready to render. + * @param {Array.} points Point array. + * @param {ol.style.LiteralPoint} symbolizer Point symbolizer. + */ +ol.renderer.canvas.Renderer.prototype.renderPoints = + function(points, symbolizer) { + + var context = this.context_, + canvas, i, ii, coords; + + if (symbolizer instanceof ol.style.LiteralShape) { + canvas = ol.renderer.canvas.Renderer.renderShape(symbolizer); + } else { + throw new Error('Unsupported symbolizer: ' + symbolizer); + } + + var mid = canvas.width / 2; + context.save(); + context.translate(-mid, -mid); + context.globalAlpha = 1; + for (i = 0, ii = points.length; i < ii; ++i) { + coords = points[i].coordinates; + context.drawImage(canvas, coords[0], coords[1]); + } + context.restore(); + +}; + + +/** + * @param {ol.style.LiteralShape} circle Shape symbolizer. + * @return {!HTMLCanvasElement} Canvas element. * @private */ -ol.renderer.canvas.CanvasRenderer.prototype.assertReady_ = function() { - goog.asserts.assert(!goog.isNull(this.context_), - 'Call setTarget before rendering'); - goog.asserts.assert(!goog.isNull(this.offset_), - 'Call setOffset before rendering'); +ol.renderer.canvas.Renderer.renderCircle_ = function(circle) { + var size = circle.size + (2 * circle.strokeWidth) + 1, + mid = size / 2, + canvas = /** @type {HTMLCanvasElement} */ + (goog.dom.createElement(goog.dom.TagName.CANVAS)), + context = /** @type {CanvasRenderingContext2D} */ + (canvas.getContext('2d')), + fillStyle = circle.fillStyle, + strokeStyle = circle.strokeStyle, + twoPi = Math.PI * 2; + + canvas.height = size; + canvas.width = size; + + context.globalAlpha = circle.opacity; + + if (fillStyle) { + context.fillStyle = circle.fillStyle; + } + if (strokeStyle) { + context.lineWidth = circle.strokeWidth; + context.strokeStyle = circle.strokeStyle; + } + + context.beginPath(); + context.arc(mid, mid, circle.size / 2, 0, twoPi, true); + + if (fillStyle) { + context.fill(); + } + if (strokeStyle) { + context.stroke(); + } + return canvas; }; /** - * @param {ol.Pixel} offset Pixel offset of top left corner of canvas. + * @param {ol.style.LiteralShape} shape Shape symbolizer. + * @return {!HTMLCanvasElement} Canvas element. */ -ol.renderer.canvas.CanvasRenderer.prototype.setOffset = function(offset) { - this.offset_ = offset; -}; - - -/** - * @param {Element} canvas Target canvas element. - */ -ol.renderer.canvas.CanvasRenderer.prototype.setTarget = function(canvas) { - this.context_ = canvas.getContext('2d'); +ol.renderer.canvas.Renderer.renderShape = function(shape) { + var canvas; + if (shape.type === ol.style.ShapeType.CIRCLE) { + canvas = ol.renderer.canvas.Renderer.renderCircle_(shape); + } else { + throw new Error('Unsupported shape type: ' + shape); + } + return canvas; }; diff --git a/src/ol/style/point.js b/src/ol/style/point.js index d15cf89383..e937a188a5 100644 --- a/src/ol/style/point.js +++ b/src/ol/style/point.js @@ -6,6 +6,6 @@ goog.require('ol.style.LiteralSymbolizer'); /** * @interface - * @implements {ol.style.LiteralSymbolizer} + * @extends {ol.style.LiteralSymbolizer} */ ol.style.LiteralPoint = function() {};