Created
September 4, 2009 18:18
-
-
Save tmcw/181018 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Copyright (c) 2006-2008 MetaCarta, Inc., 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/Elements.js | |
*/ | |
/** | |
* Class: OpenLayers.Renderer.VML | |
* Render vector features in browsers with VML capability. Construct a new | |
* VML renderer with the <OpenLayers.Renderer.VML> constructor. | |
* | |
* Note that for all calculations in this class, we use toFixed() to round a | |
* float value to an integer. This is done because it seems that VML doesn't | |
* support float values. | |
* | |
* Inherits from: | |
* - <OpenLayers.Renderer.Elements> | |
*/ | |
OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, { | |
/** | |
* Property: xmlns | |
* {String} XML Namespace URN | |
*/ | |
xmlns: "urn:schemas-microsoft-com:vml", | |
/** | |
* Property: symbolCache | |
* {DOMElement} node holding symbols. This hash is keyed by symbol name, | |
* and each value is a hash with a "path" and an "extent" property. | |
*/ | |
symbolCache: {}, | |
/** | |
* Property: offset | |
* {Object} Hash with "x" and "y" properties | |
*/ | |
offset: null, | |
/** | |
* Constructor: OpenLayers.Renderer.VML | |
* Create a new VML renderer. | |
* | |
* Parameters: | |
* containerID - {String} The id for the element that contains the renderer | |
*/ | |
initialize: function(containerID) { | |
if (!this.supported()) { | |
return; | |
} | |
if (!document.documentElement.getAttribute('xmlns:olv') || !document.namespaces.olv) { | |
document.documentElement.setAttribute("xmlns:olv", this.xmlns); | |
var style = document.createStyleSheet(); | |
var shapes = ['shape','rect', 'oval', 'fill', 'stroke', 'imagedata', 'group','textbox']; | |
for (var i = 0, len = shapes.length; i < len; i++) { | |
style.addRule('olv\\:' + shapes[i], "behavior: url(#default#VML); " + | |
"position: absolute; display: inline-block;"); | |
} | |
} | |
OpenLayers.Renderer.Elements.prototype.initialize.apply(this, | |
arguments); | |
this.offset = {x: 0, y: 0}; | |
}, | |
/** | |
* APIMethod: destroy | |
* Deconstruct the renderer. | |
*/ | |
destroy: function() { | |
OpenLayers.Renderer.Elements.prototype.destroy.apply(this, arguments); | |
}, | |
/** | |
* APIMethod: supported | |
* Determine whether a browser supports this renderer. | |
* | |
* Returns: | |
* {Boolean} The browser supports the VML renderer | |
*/ | |
supported: function() { | |
return (OpenLayers.Util.getBrowserName() == 'msie'); | |
}, | |
/** | |
* Method: setExtent | |
* Set the renderer's extent | |
* | |
* Parameters: | |
* extent - {<OpenLayers.Bounds>} | |
* resolutionChanged - {Boolean} | |
* | |
* Returns: | |
* {Boolean} true to notify the layer that the new extent does not exceed | |
* the coordinate range, and the features will not need to be redrawn. | |
*/ | |
setExtent: function(extent, resolutionChanged) { | |
OpenLayers.Renderer.Elements.prototype.setExtent.apply(this, | |
arguments); | |
var resolution = this.getResolution(); | |
var left = extent.left/resolution; | |
var top = extent.top/resolution - this.size.h; | |
if (resolutionChanged) { | |
this.offset = {x: left, y: top}; | |
left = 0; | |
top = 0; | |
} else { | |
left = left - this.offset.x; | |
top = top - this.offset.y; | |
} | |
var org = left + " " + top; | |
this.root.coordorigin = org; | |
var roots = [this.root, this.vectorRoot, this.textRoot]; | |
var root; | |
for(var i=0, len=roots.length; i<len; ++i) { | |
root = roots[i]; | |
var size = this.size.w + " " + this.size.h; | |
root.coordsize = size; | |
} | |
// flip the VML display Y axis upside down so it | |
// matches the display Y axis of the map | |
this.root.style.flip = "y"; | |
return true; | |
}, | |
/** | |
* Method: setSize | |
* Set the size of the drawing surface | |
* | |
* Parameters: | |
* size - {<OpenLayers.Size>} the size of the drawing surface | |
*/ | |
setSize: function(size) { | |
OpenLayers.Renderer.prototype.setSize.apply(this, arguments); | |
// setting width and height on all roots to avoid flicker which we | |
// would get with 100% width and height on child roots | |
var roots = [ | |
this.rendererRoot, | |
this.root, | |
this.vectorRoot, | |
this.textRoot | |
]; | |
var w = this.size.w + "px"; | |
var h = this.size.h + "px"; | |
var root; | |
for(var i=0, len=roots.length; i<len; ++i) { | |
root = roots[i]; | |
root.style.width = w; | |
root.style.height = h; | |
} | |
}, | |
/** | |
* Method: getNodeType | |
* Get the node type for a geometry and style | |
* | |
* Parameters: | |
* geometry - {<OpenLayers.Geometry>} | |
* style - {Object} | |
* | |
* Returns: | |
* {String} The corresponding node type for the specified geometry | |
*/ | |
getNodeType: function(geometry, style) { | |
var nodeType = null; | |
switch (geometry.CLASS_NAME) { | |
case "OpenLayers.Geometry.Point": | |
if (style.externalGraphic) { | |
nodeType = "olv:rect"; | |
} else if (this.isComplexSymbol(style.graphicName)) { | |
nodeType = "olv:shape"; | |
} else { | |
nodeType = "olv:oval"; | |
} | |
break; | |
case "OpenLayers.Geometry.Rectangle": | |
nodeType = "olv:rect"; | |
break; | |
case "OpenLayers.Geometry.LineString": | |
case "OpenLayers.Geometry.LinearRing": | |
case "OpenLayers.Geometry.Polygon": | |
case "OpenLayers.Geometry.Curve": | |
case "OpenLayers.Geometry.Surface": | |
nodeType = "olv:shape"; | |
break; | |
default: | |
break; | |
} | |
return nodeType; | |
}, | |
/** | |
* Method: setStyle | |
* Use to set all the style attributes to a VML node. | |
* | |
* Parameters: | |
* node - {DOMElement} An VML element to decorate | |
* style - {Object} | |
* options - {Object} Currently supported options include | |
* 'isFilled' {Boolean} and | |
* 'isStroked' {Boolean} | |
* geometry - {<OpenLayers.Geometry>} | |
*/ | |
setStyle: function(node, style, options, geometry) { | |
style = style || node._style; | |
options = options || node._options; | |
var widthFactor = 1; | |
if (node._geometryClass == "OpenLayers.Geometry.Point") { | |
if (style.externalGraphic) { | |
if (style.graphicTitle) { | |
node.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 resolution = this.getResolution(); | |
var xOffset = (style.graphicXOffset != undefined) ? | |
style.graphicXOffset : -(0.5 * width); | |
var yOffset = (style.graphicYOffset != undefined) ? | |
style.graphicYOffset : -(0.5 * height); | |
node.style.left = ((geometry.x/resolution - this.offset.x)+xOffset).toFixed(); | |
node.style.top = ((geometry.y/resolution - this.offset.y)-(yOffset+height)).toFixed(); | |
node.style.width = width + "px"; | |
node.style.height = height + "px"; | |
node.style.flip = "y"; | |
// modify style/options for fill and stroke styling below | |
style.fillColor = "none"; | |
options.isStroked = false; | |
} else if (this.isComplexSymbol(style.graphicName)) { | |
var cache = this.importSymbol(style.graphicName); | |
node.path = cache.path; | |
node.coordorigin = cache.left + "," + cache.bottom; | |
var size = cache.size; | |
node.coordsize = size + "," + size; | |
this.drawCircle(node, geometry, style.pointRadius); | |
node.style.flip = "y"; | |
} else { | |
this.drawCircle(node, geometry, style.pointRadius); | |
} | |
} | |
// fill | |
if (options.isFilled) { | |
node.fillcolor = style.fillColor; | |
} else { | |
node.filled = "false"; | |
} | |
var fills = node.getElementsByTagName("fill"); | |
var fill = (fills.length == 0) ? null : fills[0]; | |
if (!options.isFilled) { | |
if (fill) { | |
node.removeChild(fill); | |
} | |
} else { | |
if (!fill) { | |
fill = this.createNode('olv:fill', node.id + "_fill"); | |
} | |
fill.opacity = style.fillOpacity; | |
if (node._geometryClass == "OpenLayers.Geometry.Point" && | |
style.externalGraphic) { | |
// override fillOpacity | |
if (style.graphicOpacity) { | |
fill.opacity = style.graphicOpacity; | |
} | |
fill.src = style.externalGraphic; | |
fill.type = "frame"; | |
if (!(style.graphicWidth && style.graphicHeight)) { | |
fill.aspect = "atmost"; | |
} | |
} | |
if (fill.parentNode != node) { | |
node.appendChild(fill); | |
} | |
} | |
// additional rendering for rotated graphics or symbols | |
if (typeof style.rotation != "undefined") { | |
if (style.externalGraphic) { | |
this.graphicRotate(node, xOffset, yOffset); | |
// make the fill fully transparent, because we now have | |
// the graphic as imagedata element. We cannot just remove | |
// the fill, because this is part of the hack described | |
// in graphicRotate | |
fill.opacity = 0; | |
} else { | |
node.style.rotation = style.rotation; | |
} | |
} | |
// stroke | |
if (options.isStroked) { | |
node.strokecolor = style.strokeColor; | |
node.strokeweight = style.strokeWidth + "px"; | |
} else { | |
node.stroked = false; | |
} | |
var strokes = node.getElementsByTagName("stroke"); | |
var stroke = (strokes.length == 0) ? null : strokes[0]; | |
if (!options.isStroked) { | |
if (stroke) { | |
node.removeChild(stroke); | |
} | |
} else { | |
if (!stroke) { | |
stroke = this.createNode('olv:stroke', node.id + "_stroke"); | |
node.appendChild(stroke); | |
} | |
stroke.opacity = style.strokeOpacity; | |
stroke.endcap = !style.strokeLinecap || style.strokeLinecap == 'butt' ? 'flat' : style.strokeLinecap; | |
stroke.dashstyle = this.dashStyle(style); | |
} | |
if (style.cursor != "inherit" && style.cursor != null) { | |
node.style.cursor = style.cursor; | |
} | |
return node; %0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment