Added support for named graphics to Canvas renderer
This commit is contained in:
@@ -51,6 +51,12 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
|
||||
*/
|
||||
pendingRedraw: false,
|
||||
|
||||
/**
|
||||
* Property: cachedSymbolBounds
|
||||
* {Object} Internal cache of calculated symbol extents.
|
||||
*/
|
||||
cachedSymbolBounds: {},
|
||||
|
||||
/**
|
||||
* Constructor: OpenLayers.Renderer.Canvas
|
||||
*
|
||||
@@ -283,6 +289,151 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
|
||||
img.src = style.externalGraphic;
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: drawNamedSymbol
|
||||
* Called to draw Well Known Graphic Symbol Name.
|
||||
* This method is only called by the renderer itself.
|
||||
*
|
||||
* Parameters:
|
||||
* geometry - {<OpenLayers.Geometry>}
|
||||
* style - {Object}
|
||||
* featureId - {String}
|
||||
*/
|
||||
drawNamedSymbol: function(geometry, style, featureId) {
|
||||
var x, y, cx, cy, i, symbolBounds, scaling, angle;
|
||||
var unscaledStrokeWidth;
|
||||
var deg2rad = Math.PI / 180.0;
|
||||
|
||||
var symbol = OpenLayers.Renderer.symbol[style.graphicName];
|
||||
|
||||
if (!symbol) {
|
||||
throw new Error(style.graphicName + ' is not a valid symbol name');
|
||||
}
|
||||
|
||||
if (!symbol.length || symbol.length < 2) return;
|
||||
|
||||
var pt = this.getLocalXY(geometry);
|
||||
var p0 = pt[0];
|
||||
var p1 = pt[1];
|
||||
|
||||
if (isNaN(p0) || isNaN(p1)) return;
|
||||
|
||||
// Use rounded line caps
|
||||
this.canvas.lineCap = "round";
|
||||
this.canvas.lineJoin = "round";
|
||||
|
||||
// Scale and rotate symbols, using precalculated bounds whenever possible.
|
||||
if (style.graphicName in this.cachedSymbolBounds) {
|
||||
symbolBounds = this.cachedSymbolBounds[style.graphicName];
|
||||
} else {
|
||||
symbolBounds = new OpenLayers.Bounds();
|
||||
for(i = 0; i < symbol.length; i+=2) {
|
||||
symbolBounds.extend(new OpenLayers.LonLat(symbol[i], symbol[i+1]));
|
||||
}
|
||||
this.cachedSymbolBounds[style.graphicName] = symbolBounds;
|
||||
}
|
||||
|
||||
// Push symbol scaling, translation and rotation onto the transformation stack in reverse order.
|
||||
// Don't forget to apply all canvas transformations to the hitContext canvas as well(!)
|
||||
this.canvas.save();
|
||||
if (this.hitDetection) this.hitContext.save();
|
||||
|
||||
// Step 3: place symbol at the desired location
|
||||
this.canvas.translate(p0,p1);
|
||||
if (this.hitDetection) this.hitContext.translate(p0,p1);
|
||||
|
||||
// Step 2a. rotate the symbol if necessary
|
||||
angle = deg2rad * style.rotation; // will be NaN when style.rotation is undefined.
|
||||
if (!isNaN(angle)) {
|
||||
this.canvas.rotate(angle);
|
||||
if (this.hitDetection) this.hitContext.rotate(angle);
|
||||
}
|
||||
|
||||
// // Step 2: scale symbol such that pointRadius equals half the maximum symbol dimension.
|
||||
scaling = 2.0 * style.pointRadius / Math.max(symbolBounds.getWidth(), symbolBounds.getHeight());
|
||||
this.canvas.scale(scaling,scaling);
|
||||
if (this.hitDetection) this.hitContext.scale(scaling,scaling);
|
||||
|
||||
// Step 1: center the symbol at the origin
|
||||
cx = symbolBounds.getCenterLonLat().lon;
|
||||
cy = symbolBounds.getCenterLonLat().lat;
|
||||
this.canvas.translate(-cx,-cy);
|
||||
if (this.hitDetection) this.hitContext.translate(-cx,-cy);
|
||||
|
||||
// Don't forget to scale stroke widths, because they are affected by canvas scale transformations as well(!)
|
||||
// Alternative: scale symbol coordinates manually, so stroke width scaling is not needed anymore.
|
||||
unscaledStrokeWidth = style.strokeWidth;
|
||||
style.strokeWidth = unscaledStrokeWidth / scaling;
|
||||
|
||||
if (style.fill !== false) {
|
||||
this.setCanvasStyle("fill", style);
|
||||
this.canvas.beginPath();
|
||||
for (i=0; i<symbol.length; i=i+2) {
|
||||
x = symbol[i];
|
||||
y = symbol[i+1];
|
||||
if (i == 0) this.canvas.moveTo(x,y);
|
||||
this.canvas.lineTo(x,y);
|
||||
}
|
||||
this.canvas.closePath();
|
||||
this.canvas.fill();
|
||||
|
||||
if (this.hitDetection) {
|
||||
this.setHitContextStyle("fill", featureId, style);
|
||||
this.hitContext.beginPath();
|
||||
for (i=0; i<symbol.length; i=i+2) {
|
||||
x = symbol[i];
|
||||
y = symbol[i+1];
|
||||
if (i == 0) this.canvas.moveTo(x,y);
|
||||
this.hitContext.lineTo(x,y);
|
||||
}
|
||||
this.hitContext.closePath();
|
||||
this.hitContext.fill();
|
||||
}
|
||||
}
|
||||
|
||||
if (style.stroke !== false) {
|
||||
this.setCanvasStyle("stroke", style);
|
||||
|
||||
this.canvas.beginPath();
|
||||
|
||||
for (i=0; i<symbol.length; i=i+2) {
|
||||
x = symbol[i];
|
||||
y = symbol[i+1];
|
||||
if (i == 0) this.canvas.moveTo(x,y);
|
||||
this.canvas.lineTo(x,y);
|
||||
}
|
||||
this.canvas.closePath();
|
||||
this.canvas.stroke();
|
||||
}
|
||||
|
||||
style.strokeWidth = unscaledStrokeWidth;
|
||||
this.canvas.restore();
|
||||
if (this.hitDetection) this.hitContext.restore();
|
||||
this.setCanvasStyle("reset");
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: setCanvasStyle
|
||||
* Prepare the canvas for drawing by setting various global settings.
|
||||
*
|
||||
* Parameters:
|
||||
* type - {String} one of 'stroke', 'fill', or 'reset'
|
||||
* style - {Object} Symbolizer hash
|
||||
*/
|
||||
setCanvasStyle: function(type, style) {
|
||||
if (type === "fill") {
|
||||
this.canvas.globalAlpha = style['fillOpacity'];
|
||||
this.canvas.fillStyle = style['fillColor'];
|
||||
} else if (type === "stroke") {
|
||||
this.canvas.globalAlpha = style['strokeOpacity'];
|
||||
this.canvas.strokeStyle = style['strokeColor'];
|
||||
this.canvas.lineWidth = style['strokeWidth'];
|
||||
} else {
|
||||
this.canvas.globalAlpha = 0;
|
||||
this.canvas.lineWidth = 1;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Method: setCanvasStyle
|
||||
* Prepare the canvas for drawing by setting various global settings.
|
||||
@@ -365,6 +516,8 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
|
||||
if(style.graphic !== false) {
|
||||
if(style.externalGraphic) {
|
||||
this.drawExternalGraphic(geometry, style, featureId);
|
||||
} else if (style.graphicName && (style.graphicName != "circle")) {
|
||||
this.drawNamedSymbol(geometry, style, featureId);
|
||||
} else {
|
||||
var pt = this.getLocalXY(geometry);
|
||||
var p0 = pt[0];
|
||||
|
||||
Reference in New Issue
Block a user