Implemented rotation of externalGraphic vector point features. r=tschaub (closes #1433)

git-svn-id: http://svn.openlayers.org/trunk/openlayers@7324 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
ahocevar
2008-06-06 18:42:44 +00:00
parent 6670fb6cfd
commit aa486090f1
5 changed files with 250 additions and 1 deletions

View File

@@ -222,6 +222,12 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
} 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) {

View File

@@ -171,6 +171,7 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
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 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
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);
@@ -249,6 +259,112 @@ OpenLayers.Renderer.VML = OpenLayers.Class(OpenLayers.Renderer.Elements, {
return node;
},
/**
* 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