|
/* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for |
|
* full list of contributors). Published under the Clear BSD license. |
|
* See http://svn.openlayers.org/trunk/openlayers/license.txt for the |
|
* full text of the license. */ |
|
|
|
/** |
|
* @requires OpenLayers/Renderer.js |
|
*/ |
|
|
|
/** |
|
* Class: OpenLayers.Renderer.Canvas |
|
* A renderer based on the 2D 'canvas' drawing element.element |
|
* |
|
* Inherits: |
|
* - <OpenLayers.Renderer> |
|
*/ |
|
OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { |
|
|
|
/** |
|
* Property: canvas |
|
* {Canvas} The canvas context object. |
|
*/ |
|
canvas: null, |
|
|
|
/** |
|
* Property: features |
|
* {Object} Internal object of feature/style pairs for use in redrawing the layer. |
|
*/ |
|
features: null, |
|
|
|
/** |
|
* Constructor: OpenLayers.Renderer.Canvas |
|
* |
|
* Parameters: |
|
* containerID - {<String>} |
|
*/ |
|
initialize: function(containerID) { |
|
OpenLayers.Renderer.prototype.initialize.apply(this, arguments); |
|
this.root = document.createElement("canvas"); |
|
this.container.appendChild(this.root); |
|
this.canvas = this.root.getContext("2d"); |
|
this.features = {}; |
|
}, |
|
|
|
/** |
|
* Method: eraseGeometry |
|
* Erase a geometry from the renderer. Because the Canvas renderer has |
|
* 'memory' of the features that it has drawn, we have to remove the |
|
* feature so it doesn't redraw. |
|
* |
|
* Parameters: |
|
* geometry - {<OpenLayers.Geometry>} |
|
* featureId - {String} |
|
*/ |
|
eraseGeometry: function(geometry, featureId) { |
|
this.eraseFeatures(this.features[featureId][0]); |
|
}, |
|
|
|
/** |
|
* APIMethod: supported |
|
* |
|
* Returns: |
|
* {Boolean} Whether or not the browser supports the renderer class |
|
*/ |
|
supported: function() { |
|
var canvas = document.createElement("canvas"); |
|
return !!canvas.getContext; |
|
}, |
|
|
|
/** |
|
* Method: setExtent |
|
* Set the visible part of the layer. |
|
* |
|
* Resolution has probably changed, so we nullify the resolution |
|
* cache (this.resolution), then redraw. |
|
* |
|
* Parameters: |
|
* extent - {<OpenLayers.Bounds>} |
|
*/ |
|
setExtent: function(extent) { |
|
this.extent = extent.clone(); |
|
this.resolution = null; |
|
this.redraw(); |
|
}, |
|
|
|
/** |
|
* Method: setSize |
|
* Sets the size of the drawing surface. |
|
* |
|
* Once the size is updated, redraw the canvas. |
|
* |
|
* Parameters: |
|
* size - {<OpenLayers.Size>} |
|
*/ |
|
setSize: function(size) { |
|
this.size = size.clone(); |
|
this.root.style.width = size.w + "px"; |
|
this.root.style.height = size.h + "px"; |
|
this.root.width = size.w; |
|
this.root.height = size.h; |
|
this.resolution = null; |
|
}, |
|
|
|
/** |
|
* Method: drawFeature |
|
* Draw the feature. Stores the feature in the features list, |
|
* then redraws the layer. |
|
* |
|
* Parameters: |
|
* feature - {<OpenLayers.Feature.Vector>} |
|
* style - {<Object>} |
|
*/ |
|
drawFeature: function(feature, style) { |
|
style = style || feature.style; |
|
style = this.applyDefaultSymbolizer(style); |
|
|
|
this.features[feature.id] = [feature, style]; |
|
this.redraw(); |
|
}, |
|
|
|
|
|
/** |
|
* Method: drawGeometry |
|
* Used when looping (in redraw) over the features; draws |
|
* the canvas. |
|
* |
|
* Parameters: |
|
* geometry - {<OpenLayers.Geometry>} |
|
* style - {Object} |
|
*/ |
|
drawGeometry: function(geometry, style) { |
|
var className = geometry.CLASS_NAME; |
|
if ((className == "OpenLayers.Geometry.Collection") || |
|
(className == "OpenLayers.Geometry.MultiPoint") || |
|
(className == "OpenLayers.Geometry.MultiLineString") || |
|
(className == "OpenLayers.Geometry.MultiPolygon")) { |
|
for (var i = 0; i < geometry.components.length; i++) { |
|
this.drawGeometry(geometry.components[i], style); |
|
} |
|
return; |
|
} |
|
switch (geometry.CLASS_NAME) { |
|
case "OpenLayers.Geometry.Point": |
|
this.drawPoint(geometry, style); |
|
break; |
|
case "OpenLayers.Geometry.LineString": |
|
this.drawLineString(geometry, style); |
|
break; |
|
case "OpenLayers.Geometry.LinearRing": |
|
this.drawLinearRing(geometry, style); |
|
break; |
|
case "OpenLayers.Geometry.Polygon": |
|
this.drawPolygon(geometry, style); |
|
break; |
|
default: |
|
break; |
|
} |
|
}, |
|
|
|
/** |
|
* Method: drawExternalGraphic |
|
* Called to draw External graphics. |
|
* |
|
* Parameters: |
|
* geometry - {<OpenLayers.Geometry>} |
|
* style - {Object} |
|
*/ |
|
drawExternalGraphic: function(pt, style) { |
|
var img = new Image(); |
|
|
|
if(style.graphicTitle) { |
|
img.title=style.graphicTitle; |
|
} |
|
|
|
var width = style.graphicWidth || style.graphicHeight; |
|
var height = style.graphicHeight || style.graphicWidth; |
|
width = width ? width : style.pointRadius*2; |
|
height = height ? height : style.pointRadius*2; |
|
var xOffset = (style.graphicXOffset != undefined) ? |
|
style.graphicXOffset : -(0.5 * width); |
|
var yOffset = (style.graphicYOffset != undefined) ? |
|
style.graphicYOffset : -(0.5 * height); |
|
|
|
var context = { img: img, |
|
x: (pt[0]+xOffset), |
|
y: (pt[1]+yOffset), |
|
width: width, |
|
height: height, |
|
opacity: style.graphicOpacity || style.fillOpacity, |
|
canvas: this.canvas }; |
|
|
|
img.onload = OpenLayers.Function.bind( function() { |
|
this.canvas.globalAlpha = this.opacity; |
|
this.canvas.drawImage(this.img, this.x, |
|
this.y, this.width, this.height); |
|
}, context); |
|
img.src = style.externalGraphic; |
|
}, |
|
|
|
/** |
|
* 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: drawPoint |
|
* This method is only called by the renderer itself. |
|
* |
|
* Parameters: |
|
* geometry - {<OpenLayers.Geometry>} |
|
* style - {Object} |
|
*/ |
|
drawPoint: function(geometry, style) { |
|
if(style.graphic !== false) { |
|
var pt = this.getLocalXY(geometry); |
|
|
|
if (style.externalGraphic) { |
|
this.drawExternalGraphic(pt, style); |
|
} else { |
|
if(style.fill !== false) { |
|
this.setCanvasStyle("fill", style); |
|
this.canvas.beginPath(); |
|
this.canvas.arc(pt[0], pt[1], style.pointRadius, 0, Math.PI*2, true); |
|
this.canvas.fill(); |
|
} |
|
|
|
if(style.stroke !== false) { |
|
this.setCanvasStyle("stroke", style); |
|
this.canvas.beginPath(); |
|
this.canvas.arc(pt[0], pt[1], style.pointRadius, 0, Math.PI*2, true); |
|
this.canvas.stroke(); |
|
this.setCanvasStyle("reset"); |
|
} |
|
} |
|
} |
|
}, |
|
|
|
/** |
|
* Method: drawLineString |
|
* This method is only called by the renderer itself. |
|
* |
|
* Parameters: |
|
* geometry - {<OpenLayers.Geometry>} |
|
* style - {Object} |
|
*/ |
|
drawLineString: function(geometry, style) { |
|
if(style.stroke !== false) { |
|
this.setCanvasStyle("stroke", style); |
|
this.canvas.beginPath(); |
|
var start = this.getLocalXY(geometry.components[0]); |
|
this.canvas.moveTo(start[0], start[1]); |
|
for(var i = 1; i < geometry.components.length; i++) { |
|
var pt = this.getLocalXY(geometry.components[i]); |
|
this.canvas.lineTo(pt[0], pt[1]); |
|
} |
|
this.canvas.stroke(); |
|
} |
|
this.setCanvasStyle("reset"); |
|
}, |
|
|
|
/** |
|
* Method: drawLinearRing |
|
* This method is only called by the renderer itself. |
|
* |
|
* Parameters: |
|
* geometry - {<OpenLayers.Geometry>} |
|
* style - {Object} |
|
*/ |
|
drawLinearRing: function(geometry, style) { |
|
if(style.fill !== false) { |
|
this.setCanvasStyle("fill", style); |
|
this.canvas.beginPath(); |
|
var start = this.getLocalXY(geometry.components[0]); |
|
this.canvas.moveTo(start[0], start[1]); |
|
for(var i = 1; i < geometry.components.length - 1 ; i++) { |
|
var pt = this.getLocalXY(geometry.components[i]); |
|
this.canvas.lineTo(pt[0], pt[1]); |
|
} |
|
this.canvas.fill(); |
|
} |
|
|
|
if(style.stroke !== false) { |
|
this.setCanvasStyle("stroke", style); |
|
this.canvas.beginPath(); |
|
var start = this.getLocalXY(geometry.components[0]); |
|
this.canvas.moveTo(start[0], start[1]); |
|
for(var i = 1; i < geometry.components.length; i++) { |
|
var pt = this.getLocalXY(geometry.components[i]); |
|
this.canvas.lineTo(pt[0], pt[1]); |
|
} |
|
this.canvas.stroke(); |
|
} |
|
this.setCanvasStyle("reset"); |
|
}, |
|
|
|
/** |
|
* Method: drawPolygon |
|
* This method is only called by the renderer itself. |
|
* |
|
* Parameters: |
|
* geometry - {<OpenLayers.Geometry>} |
|
* style - {Object} |
|
*/ |
|
drawPolygon: function(geometry, style) { |
|
this.drawLinearRing(geometry.components[0], style); |
|
for (var i = 1; i < geometry.components.length; i++) { |
|
this.drawLinearRing(geometry.components[i], { |
|
fillOpacity: 0, |
|
strokeWidth: 0, |
|
strokeOpacity: 0, |
|
strokeColor: '#000000', |
|
fillColor: '#000000'} |
|
); // inner rings are 'empty' |
|
} |
|
}, |
|
|
|
/** |
|
* Method: drawText |
|
* This method is only called by the renderer itself. |
|
* |
|
* Parameters: |
|
* location - {<OpenLayers.Point>} |
|
* style - {Object} |
|
*/ |
|
drawText: function(location, style) { |
|
style = OpenLayers.Util.extend({ |
|
fontColor: "#000000", |
|
labelAlign: "cm" |
|
}, style); |
|
var pt = this.getLocalXY(location); |
|
|
|
this.setCanvasStyle("reset"); |
|
this.canvas.fillStyle = style.fontColor; |
|
this.canvas.globalAlpha = style.fontOpacity || 1.0; |
|
var fontStyle = style.fontWeight + " " + style.fontSize + " " + style.fontFamily; |
|
if (this.canvas.fillText) { |
|
// HTML5 |
|
var labelAlign = |
|
OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[0]] || |
|
"center"; |
|
this.canvas.font = fontStyle; |
|
this.canvas.textAlign = labelAlign; |
|
this.canvas.fillText(style.label, pt[0], pt[1]); |
|
} else if (this.canvas.mozDrawText) { |
|
// Mozilla pre-Gecko1.9.1 (<FF3.1) |
|
this.canvas.mozTextStyle = fontStyle; |
|
// No built-in text alignment, so we measure and adjust the position |
|
var len = this.canvas.mozMeasureText(style.label); |
|
switch(style.labelAlign[0]) { |
|
case "l": |
|
break; |
|
case "r": |
|
pt[0] -= len; |
|
break; |
|
case "c": |
|
default: |
|
pt[0] -= len / 2; |
|
} |
|