Files
openlayers/lib/OpenLayers/Renderer/VML.js
crschmidt 3948913bfc Merge all changes from the naturaldocs sandbox. This brings all the work that
has been done in the NaturalDocs branch back to trunk. Thanks to everyone who
helped out in making this happen. (I could list people, but the list would
be long, and I'm already mentally on vacation.)


git-svn-id: http://svn.openlayers.org/trunk/openlayers@3545 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
2007-06-29 15:59:20 +00:00

515 lines
14 KiB
JavaScript

/* Copyright (c) 2006 MetaCarta, Inc., published under a modified BSD license.
* See http://svn.openlayers.org/trunk/openlayers/repository-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.create();
OpenLayers.Renderer.VML.prototype =
OpenLayers.Class.inherit(OpenLayers.Renderer.Elements, {
/**
* Property: xmlns
* {String} XML Namespace URN
*/
xmlns: "urn:schemas-microsoft-com:vml",
/**
* 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;
}
document.namespaces.add("v", "urn:schemas-microsoft-com:vml");
var style = document.createStyleSheet();
style.addRule('v\\:*', "behavior: url(#default#VML); " +
"position: relative; display: inline-block;");
OpenLayers.Renderer.Elements.prototype.initialize.apply(this,
arguments);
},
/**
* APIMethod: destroy
* Deconstruct the renderer.
*/
destroy: function() {
OpenLayers.Renderer.Elements.prototype.destroy.apply(this, arguments);
},
/**
* APIMethod: supported
* Determine whether a browser supports this renderer.
*
* Return:
* {Boolean} The browser supports the VML renderer
*/
supported: function() {
var supported = document.namespaces;
return supported;
},
/**
* Method: setExtent
* Set the renderer's extent
*
* Parameters:
* extent - {<OpenLayers.Bounds>}
*/
setExtent: function(extent) {
OpenLayers.Renderer.Elements.prototype.setExtent.apply(this,
arguments);
var resolution = this.getResolution();
var org = extent.left/resolution + " " +
extent.top/resolution;
this.root.setAttribute("coordorigin", org);
var size = extent.getWidth()/resolution + " " +
-extent.getHeight()/resolution;
this.root.setAttribute("coordsize", size);
},
/**
* 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);
this.rendererRoot.style.width = this.size.w;
this.rendererRoot.style.height = this.size.h;
this.root.style.width = "100%";
this.root.style.height = "100%";
},
/**
* Method: getNodeType
* Get the noode type for a geometry
*
* Parameters:
* geometry - {<OpenLayers.Geometry>}
*
* Return:
* {String} The corresponding node type for the specified geometry
*/
getNodeType: function(geometry) {
var nodeType = null;
switch (geometry.CLASS_NAME) {
case "OpenLayers.Geometry.Point":
nodeType = "v:oval";
break;
case "OpenLayers.Geometry.Rectangle":
nodeType = "v:rect";
break;
case "OpenLayers.Geometry.LineString":
case "OpenLayers.Geometry.LinearRing":
case "OpenLayers.Geometry.Polygon":
case "OpenLayers.Geometry.Curve":
case "OpenLayers.Geometry.Surface":
nodeType = "v:shape";
break;
default:
break;
}
return nodeType;
},
/**
* Method: setStyle
* Use to set all the style attributes to a VML node.
*
* Parameters:
* node - {DOMElement}
* style - {Object}
* options - {Object}
* isFilled - {Boolean}
* isStroked - {Boolean}
* geometry - {<OpenLayers.Geometry>}
*/
setStyle: function(node, style, options, geometry) {
style = style || node._style;
options = options || node._options;
if (node._geometryClass == "OpenLayers.Geometry.Point") {
this.drawCircle(node, geometry, style.pointRadius);
}
//fill
var fillColor = (options.isFilled) ? style.fillColor : "none";
node.setAttribute("fillcolor", fillColor);
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('v:fill', node.id + "_fill");
node.appendChild(fill);
}
fill.setAttribute("opacity", style.fillOpacity);
}
//stroke
var strokeColor = (options.isStroked) ? style.strokeColor : "none";
node.setAttribute("strokecolor", strokeColor);
node.setAttribute("strokeweight", style.strokeWidth);
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('v:stroke', node.id + "_stroke");
node.appendChild(stroke);
}
stroke.setAttribute("opacity", style.strokeOpacity);
stroke.setAttribute("endcap", !style.strokeLinecap || style.strokeLinecap == 'butt' ? 'flat' : style.strokeLinecap);
}
if (style.cursor) {
node.style.cursor = style.cursor;
}
},
/**
* Method: setNodeDimension
* Get the geometry's bounds, convert it to our vml coordinate system,
* then set the node's position, size, and local coordinate system.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
setNodeDimension: function(node, geometry) {
var bbox = geometry.getBounds();
var resolution = this.getResolution();
var scaledBox =
new OpenLayers.Bounds((bbox.left/resolution).toFixed(),
(bbox.bottom/resolution).toFixed(),
(bbox.right/resolution).toFixed(),
(bbox.top/resolution).toFixed());
// Set the internal coordinate system to draw the path
node.style.left = scaledBox.left;
node.style.top = scaledBox.top;
node.style.width = scaledBox.getWidth();
node.style.height = scaledBox.getHeight();
node.coordorigin = scaledBox.left + " " + scaledBox.top;
node.coordsize = scaledBox.getWidth()+ " " + scaledBox.getHeight();
},
/**
* Method: createNode
* Create a new node
*
* Parameters:
* type - {String} Kind of node to draw
* id - {String} Id for node
*
* Return:
* {DOMElement} A new node of the given type and id
*/
createNode: function(type, id) {
var node = document.createElement(type);
if (id) {
node.setAttribute('id', id);
}
return node;
},
/**
* Method: nodeTypeCompare
* Determine whether a node is of a given type
*
* Parameters:
* type - {String} Kind of node to draw
* id - {String} Id for node
*
* Return:
* {Boolean} Whether or not the specified node is of the specified type
*/
nodeTypeCompare: function(node, type) {
//split type
var subType = type;
var splitIndex = subType.indexOf(":");
if (splitIndex != -1) {
subType = subType.substr(splitIndex+1);
}
//split nodeName
var nodeName = node.nodeName;
splitIndex = nodeName.indexOf(":");
if (splitIndex != -1) {
nodeName = nodeName.substr(splitIndex+1);
}
return (subType == nodeName);
},
/**
* Method: createRenderRoot
* Create the renderer root
*
* Return:
* {DOMElement} The specific render engine's root element
*/
createRenderRoot: function() {
var id = this.container.id + "_vmlRoot";
var rendererRoot = this.nodeFactory(id, "div");
return rendererRoot;
},
/**
* Method: createRoot
* Create the main root element
*
* Return:
* {DOMElement} The main root element to which we'll add vectors
*/
createRoot: function() {
var id = this.container.id + "_root";
var root = this.nodeFactory(id, "v:group");
return root;
},
/**************************************
* *
* GEOMETRY DRAWING FUNCTIONS *
* *
**************************************/
/**
* Method: drawPoint
* Render a point
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawPoint: function(node, geometry) {
this.drawCircle(node, geometry, 1);
},
/**
* Method: drawCircle
* Render a circle.
* Size and Center a circle given geometry (x,y center) and radius
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
* radius - {float}
*/
drawCircle: function(node, geometry, radius) {
var resolution = this.getResolution();
node.style.left = (geometry.x /resolution).toFixed() - radius;
node.style.top = (geometry.y /resolution).toFixed() - radius;
var diameter = radius * 2;
node.style.width = diameter;
node.style.height = diameter;
},
/**
* Method: drawLineString
* Render a linestring.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawLineString: function(node, geometry) {
this.drawLine(node, geometry, false);
},
/**
* Method: drawLinearRing
* Render a linearring
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawLinearRing: function(node, geometry) {
this.drawLine(node, geometry, true);
},
/**
* Method: DrawLine
* Render a line.
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
* closeLine - {Boolean} Close the line? (make it a ring?)
*/
drawLine: function(node, geometry, closeLine) {
this.setNodeDimension(node, geometry);
var resolution = this.getResolution();
var path = "m";
for (var i = 0; i < geometry.components.length; i++) {
var x = (geometry.components[i].x/resolution);
var y = (geometry.components[i].y/resolution);
path += " " + x.toFixed() + "," + y.toFixed() + " l ";
}
if (closeLine) {
path += " x";
}
path += " e";
node.path = path;
},
/**
* Method: drawPolygon
* Render a polygon
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawPolygon: function(node, geometry) {
this.setNodeDimension(node, geometry);
var resolution = this.getResolution();
var path = "";
for (var j = 0; j < geometry.components.length; j++) {
var linearRing = geometry.components[j];
path += "m";
for (var i = 0; i < linearRing.components.length; i++) {
var x = linearRing.components[i].x / resolution;
var y = linearRing.components[i].y / resolution;
path += " " + x.toFixed() + "," + y.toFixed();
if (i==0) {
path += " l";
}
}
path += " x ";
}
path += "e";
node.path = path;
},
/**
* Method: drawRectangle
* Render a rectangle
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawRectangle: function(node, geometry) {
var resolution = this.getResolution();
node.style.left = geometry.x/resolution;
node.style.top = geometry.y/resolution;
node.style.width = geometry.width/resolution;
node.style.height = geometry.height/resolution;
},
/**
* Method: drawCurve
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawCurve: function(node, geometry) {
this.setNodeDimension(node, geometry);
var resolution = this.getResolution();
var path = "";
for (var i = 0; i < geometry.components.length; i++) {
var x = geometry.components[i].x / resolution;
var y = geometry.components[i].y / resolution;
if ((i%3)==0 && (i/3)==0) {
path += "m"
} else if ((i%3)==1) {
path += " c"
}
path += " " + x + "," + y;
}
path += " x e";
node.path = path;
},
/**
* Method: drawSurface
*
* Parameters:
* node - {DOMElement}
* geometry - {<OpenLayers.Geometry>}
*/
drawSurface: function(node, geometry) {
this.setNodeDimension(node, geometry);
var resolution = this.getResolution();
var path = "";
for (var i = 0; i < geometry.components.length; i++) {
var x = geometry.components[i].x / resolution;
var y = geometry.components[i].y / resolution;
if ((i%3)==0 && (i/3)==0) {
path += "m";
} else if ((i%3)==1) {
path += " c";
}
path += " " + x + "," + y;
}
path += " x e";
node.path = path;
},
/** @final @type String*/
CLASS_NAME: "OpenLayers.Renderer.VML"
});