[OpenLayers-Commits] r7324 - in trunk/openlayers: examples lib/OpenLayers/Format/SLD lib/OpenLayers/Renderer tests/Renderer
commits at openlayers.org
commits at openlayers.org
Fri Jun 6 14:42:44 EDT 2008
Author: ahocevar
Date: 2008-06-06 14:42:44 -0400 (Fri, 06 Jun 2008)
New Revision: 7324
Added:
trunk/openlayers/examples/styles-rotation.html
Modified:
trunk/openlayers/lib/OpenLayers/Format/SLD/v1.js
trunk/openlayers/lib/OpenLayers/Renderer/SVG.js
trunk/openlayers/lib/OpenLayers/Renderer/VML.js
trunk/openlayers/tests/Renderer/VML.html
Log:
Implemented rotation of externalGraphic vector point features. r=tschaub (closes #1433)
Added: trunk/openlayers/examples/styles-rotation.html
===================================================================
--- trunk/openlayers/examples/styles-rotation.html (rev 0)
+++ trunk/openlayers/examples/styles-rotation.html 2008-06-06 18:42:44 UTC (rev 7324)
@@ -0,0 +1,83 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>OpenLayers Styles Rotation Example</title>
+ <style type="text/css">
+ #map {
+ width: 800px;
+ height: 475px;
+ border: 1px solid black;
+ }
+ </style>
+ <script src="../lib/OpenLayers.js" type="text/javascript"></script>
+ <script type="text/javascript">
+
+ var map;
+ var vectors;
+
+ function init(){
+ map = new OpenLayers.Map('map');
+ var wms = new OpenLayers.Layer.WMS(
+ "OpenLayers WMS",
+ "http://labs.metacarta.com/wms/vmap0",
+ {layers: 'basic'}
+ );
+
+ vectors = new OpenLayers.Layer.Vector(
+ "Simple Geometry",
+ {
+ styleMap: new OpenLayers.StyleMap({
+ "default": {
+ externalGraphic: "../img/marker-gold.png",
+ //graphicWidth: 17,
+ graphicHeight: 20,
+ graphicYOffset: -19,
+ rotation: "${angle}",
+ fillOpacity: "${opacity}"
+ },
+ "select": {
+ cursor: "crosshair",
+ externalGraphic: "../img/marker.png"
+ }
+ })
+ }
+ );
+
+ map.addLayers([wms, vectors]);
+
+ var features = [];
+ var x = -111.04;
+ var y = 45.68;
+ for(var i = 0; i < 10; i++){
+ x += i * .5;
+ y += i * .1;
+ features.push(
+ new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.Point(x, y), {angle: (i*36)%360-180, opacity:i/10+.1}
+ )
+ );
+ features.push(
+ new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.Point(x, y), {angle: (i*36)%360, opacity:i/10+.1}
+ )
+ );
+ }
+
+ map.setCenter(new OpenLayers.LonLat(x-10, y), 5);
+ vectors.addFeatures(features);
+
+ var selectControl = new OpenLayers.Control.SelectFeature(
+ vectors, {hover: true});
+ map.addControl(selectControl);
+ selectControl.activate();
+
+ };
+
+ </script>
+ </head>
+ <body onload="init()">
+ <h1 id="title">Rotation Styles Example</h1>
+ <p id="shortdesc">Vector point feature symbolizers can have a <tt>rotation</tt> property. The center of the rotation is the point of the image specified by <tt>graphicXOffset</tt> and <tt>graphicYOffset</tt>.</p>
+ <div id="map"></div>
+ <div id="docs"/>
+ </body>
+</html>
Property changes on: trunk/openlayers/examples/styles-rotation.html
___________________________________________________________________
Name: svn:keywords
+ Id Author Date Revision
Name: svn:eol-style
+ native
Modified: trunk/openlayers/lib/OpenLayers/Format/SLD/v1.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Format/SLD/v1.js 2008-06-06 16:37:34 UTC (rev 7323)
+++ trunk/openlayers/lib/OpenLayers/Format/SLD/v1.js 2008-06-06 18:42:44 UTC (rev 7324)
@@ -227,6 +227,9 @@
if(graphic.href != undefined) {
symbolizer.externalGraphic = graphic.href;
}
+ if(graphic.rotation != undefined) {
+ symbolizer.rotation = graphic.rotation;
+ }
},
"ExternalGraphic": function(node, graphic) {
this.readChildNodes(node, graphic);
Modified: trunk/openlayers/lib/OpenLayers/Renderer/SVG.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Renderer/SVG.js 2008-06-06 16:37:34 UTC (rev 7323)
+++ trunk/openlayers/lib/OpenLayers/Renderer/SVG.js 2008-06-06 18:42:44 UTC (rev 7324)
@@ -222,6 +222,12 @@
} else {
node.setAttributeNS(null, "r", style.pointRadius);
}
+
+ if (style.rotation) {
+ var rotation = OpenLayers.String.format(
+ "rotate(${0} ${1} ${2})", [style.rotation, x, y]);
+ node.setAttributeNS(null, "transform", rotation);
+ }
}
if (options.isFilled) {
Modified: trunk/openlayers/lib/OpenLayers/Renderer/VML.js
===================================================================
--- trunk/openlayers/lib/OpenLayers/Renderer/VML.js 2008-06-06 16:37:34 UTC (rev 7323)
+++ trunk/openlayers/lib/OpenLayers/Renderer/VML.js 2008-06-06 18:42:44 UTC (rev 7324)
@@ -171,6 +171,7 @@
node.style.top = ((geometry.y/resolution)-(yOffset+height)).toFixed();
node.style.width = width;
node.style.height = height;
+ node.style.flip = "y";
// modify style/options for fill and stroke styling below
style.fillColor = "none";
@@ -209,11 +210,20 @@
fill.setAttribute("src", style.externalGraphic);
fill.setAttribute("type", "frame");
- node.style.flip = "y";
if (!(style.graphicWidth && style.graphicHeight)) {
fill.aspect = "atmost";
}
+
+ // additional rendering for rotated graphics
+ if (style.rotation) {
+ 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.setAttribute("opacity", 0);
+ }
}
if (fill.parentNode != node) {
node.appendChild(fill);
@@ -250,6 +260,112 @@
},
/**
+ * Method: graphicRotate
+ * If a point is to be styled with externalGraphic and rotation, VML fills
+ * cannot be used to display the graphic, because rotation of graphic
+ * fills is not supported by the VML implementation of Internet Explorer.
+ * This method creates a olv:imagedata element inside the VML node,
+ * DXImageTransform.Matrix and BasicImage filters for rotation and
+ * opacity, and a 3-step hack to remove rendering artefacts from the
+ * graphic and preserve the ability of graphics to trigger events.
+ * Finally, OpenLayers methods are used to determine the correct
+ * insertion point of the rotated image, because DXImageTransform.Matrix
+ * does the rotation without the ability to specify a rotation center
+ * point.
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * xOffset - {Number} rotation center relative to image, x coordinate
+ * yOffset - {Number} rotation center relative to image, y coordinate
+ */
+ graphicRotate: function(node, xOffset, yOffset) {
+ var style = style || node._style;
+ var options = node._options;
+
+ var aspectRatio, size;
+ if (!(style.graphicWidth && style.graphicHeight)) {
+ // load the image to determine its size
+ var img = new Image();
+ img.onreadystatechange = OpenLayers.Function.bind(function() {
+ if(img.readyState == "complete" ||
+ img.readyState == "interactive") {
+ aspectRatio = img.width / img.height;
+ size = Math.max(style.pointRadius * 2,
+ style.graphicWidth || 0,
+ style.graphicHeight || 0);
+ xOffset = xOffset * aspectRatio;
+ style.graphicWidth = size * aspectRatio;
+ style.graphicHeight = size;
+ this.graphicRotate(node, xOffset, yOffset)
+ }
+ }, this);
+ img.src = style.externalGraphic;
+
+ // will be called again by the onreadystate handler
+ return;
+ } else {
+ size = Math.max(style.graphicWidth, style.graphicHeight);
+ aspectRatio = style.graphicWidth / style.graphicHeight;
+ }
+
+ var width = Math.round(style.graphicWidth || size * aspectRatio);
+ var height = Math.round(style.graphicHeight || size);
+ node.style.width = width;
+ node.style.height = height;
+
+ // Three steps are required to remove artefacts for images with
+ // transparent backgrounds (resulting from using DXImageTransform
+ // filters on svg objects), while preserving awareness for browser
+ // events on images:
+ // - Use the fill as usual (like for unrotated images) to handle
+ // events
+ // - specify an imagedata element with the same src as the fill
+ // - style the imagedata element with an AlphaImageLoader filter
+ // with empty src
+ var image = document.getElementById(node.id + "_image");
+ if (!image) {
+ image = this.createNode("olv:imagedata", node.id + "_image");
+ node.appendChild(image);
+ }
+ image.style.width = width;
+ image.style.height = height;
+ image.src = style.externalGraphic;
+ image.style.filter =
+ "progid:DXImageTransform.Microsoft.AlphaImageLoader(" +
+ "src='', sizingMethod='scale')";
+
+ var rotation = style.rotation * Math.PI / 180;
+ var sintheta = Math.sin(rotation);
+ var costheta = Math.cos(rotation);
+
+ // do the rotation on the image
+ var filter =
+ "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta +
+ ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta +
+ ",SizingMethod='auto expand')\n"
+
+ // set the opacity (needed for the imagedata)
+ var opacity = style.graphicOpacity || style.fillOpacity;
+ if (opacity && opacity != 1) {
+ filter +=
+ "progid:DXImageTransform.Microsoft.BasicImage(opacity=" +
+ opacity+")\n";
+ }
+ node.style.filter = filter;
+
+ // do the rotation again on a box, so we know the insertion point
+ var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset);
+ var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry();
+ imgBox.rotate(style.rotation, centerPoint);
+ var imgBounds = imgBox.getBounds();
+
+ node.style.left = Math.round(
+ parseInt(node.style.left) + imgBounds.left);
+ node.style.top = Math.round(
+ parseInt(node.style.top) - imgBounds.bottom);
+ },
+
+ /**
* Method: postDraw
* Some versions of Internet Explorer seem to be unable to set fillcolor
* and strokecolor to "none" correctly before the fill node is appended to
Modified: trunk/openlayers/tests/Renderer/VML.html
===================================================================
--- trunk/openlayers/tests/Renderer/VML.html 2008-06-06 16:37:34 UTC (rev 7323)
+++ trunk/openlayers/tests/Renderer/VML.html 2008-06-06 18:42:44 UTC (rev 7324)
@@ -143,7 +143,48 @@
t.eq(node.style.width, (2 * radius) + "px", "width is correct");
t.eq(node.style.height, (2 * radius) + "px", "height is correct");
}
+
+ function test_VML_drawGraphic(t) {
+ if (!OpenLayers.Renderer.VML.prototype.supported()) {
+ t.plan(0);
+ return;
+ }
+
+ t.plan(6);
+
+ var r = new OpenLayers.Renderer.VML(document.body);
+ r.resolution = 1;
+
+ var node = document.createElement('div');
+ node.id = "test"
+ node._geometryClass = "OpenLayers.Geometry.Point";
+
+ var geometry = {
+ x: 1,
+ y: 2
+ }
+
+ var style = {
+ externalGraphic: "foo.png",
+ graphicWidth: 7,
+ graphicHeight: 10
+ }
+
+ r.drawGeometryNode(node, geometry, style);
+ t.eq(node.childNodes[0].id, "test_fill", "fill child node correctly created");
+ t.eq(node.style.left, "-3px", "x of insertion point with calculated xOffset correct");
+ t.eq(node.style.top, "-3px", "y of insertion point with calculated yOffset correct");
+
+ style.rotation = 90;
+
+ r.drawGeometryNode(node, geometry, style);
+
+ t.eq(node.childNodes[1].id, "test_image", "image child node correctly created");
+ t.eq(node.style.left, "-4px", "x of insertion point of rotated image correct");
+ t.eq(node.style.top, "-4px", "y of insertion point of rotated image correct");
+ }
+
function test_VML_drawlinestring(t) {
if (!OpenLayers.Renderer.VML.prototype.supported()) {
t.plan(0);
More information about the Commits
mailing list