Skip to content
This repository has been archived by the owner on Mar 6, 2019. It is now read-only.

Commit

Permalink
Merge branch 'master' of github.com:openlayers/openlayers into sld
Browse files Browse the repository at this point in the history
  • Loading branch information
Bart van den Eijnden committed Feb 23, 2012
2 parents 7fb62b6 + 8ce712a commit 330777d
Showing 1 changed file with 162 additions and 2 deletions.
164 changes: 162 additions & 2 deletions lib/OpenLayers/Renderer/Canvas.js
Expand Up @@ -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
*
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -633,7 +786,7 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
* layer.
*/
getFeatureIdFromEvent: function(evt) {
var feature;
var featureId, feature;
if (this.hitDetection) {
// this dragging check should go in the feature handler
if (!this.map.dragging) {
Expand All @@ -644,7 +797,14 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
if (data[3] === 255) { // antialiased
var id = data[2] + (256 * (data[1] + (256 * data[0])));
if (id) {
feature = this.features["OpenLayers.Feature.Vector_" + (id - 1 + this.hitOverflow)][0];
featureId = "OpenLayers.Feature.Vector_" + (id - 1 + this.hitOverflow);
try {
feature = this.features[featureId][0];
} catch(err) {
// Because of antialiasing on the canvas, when the hit location is at a point where the edge of
// one symbol intersects the interior of another symbol, a wrong hit color (and therefore id) results.
// todo: set Antialiasing = 'off' on the hitContext as soon as browsers allow it.
}
}
}
}
Expand Down

0 comments on commit 330777d

Please sign in to comment.