Skip to content

Instantly share code, notes, and snippets.

@tmcw
Created September 4, 2009 18:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tmcw/181018 to your computer and use it in GitHub Desktop.
Save tmcw/181018 to your computer and use it in GitHub Desktop.
/* 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