OpenLayers OpenLayers

Changeset 7324

Show
Ignore:
Timestamp:
06/06/08 14:42:44 (3 months ago)
Author:
ahocevar
Message:

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

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/openlayers/lib/OpenLayers/Format/SLD/v1.js

    r7160 r7324  
    227227                if(graphic.href != undefined) { 
    228228                    symbolizer.externalGraphic = graphic.href; 
     229                } 
     230                if(graphic.rotation != undefined) { 
     231                    symbolizer.rotation = graphic.rotation; 
    229232                } 
    230233            }, 
  • trunk/openlayers/lib/OpenLayers/Renderer/SVG.js

    r6581 r7324  
    223223                node.setAttributeNS(null, "r", style.pointRadius); 
    224224            } 
     225 
     226            if (style.rotation) { 
     227                var rotation = OpenLayers.String.format( 
     228                    "rotate(${0} ${1} ${2})", [style.rotation, x, y]); 
     229                node.setAttributeNS(null, "transform", rotation); 
     230            } 
    225231        } 
    226232         
  • trunk/openlayers/lib/OpenLayers/Renderer/VML.js

    r6764 r7324  
    172172                node.style.width = width; 
    173173                node.style.height = height;     
     174                node.style.flip = "y"; 
    174175                 
    175176                // modify style/options for fill and stroke styling below 
     
    210211                fill.setAttribute("src", style.externalGraphic); 
    211212                fill.setAttribute("type", "frame"); 
    212                 node.style.flip = "y"; 
    213213                 
    214214                if (!(style.graphicWidth && style.graphicHeight)) { 
    215215                  fill.aspect = "atmost"; 
    216216                }                 
     217                          
     218                // additional rendering for rotated graphics 
     219                if (style.rotation) { 
     220                    this.graphicRotate(node, xOffset, yOffset); 
     221                    // make the fill fully transparent, because we now have 
     222                    // the graphic as imagedata element. We cannot just remove 
     223                    // the fill, because this is part of the hack described 
     224                    // in graphicRotate 
     225                    fill.setAttribute("opacity", 0); 
     226                } 
    217227            } 
    218228            if (fill.parentNode != node) { 
     
    248258        } 
    249259        return node; 
     260    }, 
     261 
     262    /** 
     263     * Method: graphicRotate 
     264     * If a point is to be styled with externalGraphic and rotation, VML fills 
     265     * cannot be used to display the graphic, because rotation of graphic 
     266     * fills is not supported by the VML implementation of Internet Explorer. 
     267     * This method creates a olv:imagedata element inside the VML node, 
     268     * DXImageTransform.Matrix and BasicImage filters for rotation and 
     269     * opacity, and a 3-step hack to remove rendering artefacts from the 
     270     * graphic and preserve the ability of graphics to trigger events. 
     271     * Finally, OpenLayers methods are used to determine the correct 
     272     * insertion point of the rotated image, because DXImageTransform.Matrix 
     273     * does the rotation without the ability to specify a rotation center 
     274     * point. 
     275     *  
     276     * Parameters: 
     277     * node    - {DOMElement} 
     278     * xOffset - {Number} rotation center relative to image, x coordinate 
     279     * yOffset - {Number} rotation center relative to image, y coordinate 
     280     */ 
     281    graphicRotate: function(node, xOffset, yOffset) { 
     282        var style = style || node._style; 
     283        var options = node._options; 
     284         
     285        var aspectRatio, size; 
     286        if (!(style.graphicWidth && style.graphicHeight)) { 
     287            // load the image to determine its size 
     288            var img = new Image(); 
     289            img.onreadystatechange = OpenLayers.Function.bind(function() { 
     290                if(img.readyState == "complete" || 
     291                        img.readyState == "interactive") { 
     292                    aspectRatio = img.width / img.height; 
     293                    size = Math.max(style.pointRadius * 2,  
     294                        style.graphicWidth || 0, 
     295                        style.graphicHeight || 0); 
     296                    xOffset = xOffset * aspectRatio; 
     297                    style.graphicWidth = size * aspectRatio; 
     298                    style.graphicHeight = size; 
     299                    this.graphicRotate(node, xOffset, yOffset) 
     300                } 
     301            }, this); 
     302            img.src = style.externalGraphic; 
     303             
     304            // will be called again by the onreadystate handler 
     305            return; 
     306        } else { 
     307            size = Math.max(style.graphicWidth, style.graphicHeight); 
     308            aspectRatio = style.graphicWidth / style.graphicHeight; 
     309        } 
     310         
     311        var width = Math.round(style.graphicWidth || size * aspectRatio); 
     312        var height = Math.round(style.graphicHeight || size); 
     313        node.style.width = width; 
     314        node.style.height = height; 
     315         
     316        // Three steps are required to remove artefacts for images with 
     317        // transparent backgrounds (resulting from using DXImageTransform 
     318        // filters on svg objects), while preserving awareness for browser 
     319        // events on images: 
     320        // - Use the fill as usual (like for unrotated images) to handle 
     321        //   events 
     322        // - specify an imagedata element with the same src as the fill 
     323        // - style the imagedata element with an AlphaImageLoader filter 
     324        //   with empty src 
     325        var image = document.getElementById(node.id + "_image"); 
     326        if (!image) { 
     327            image = this.createNode("olv:imagedata", node.id + "_image"); 
     328            node.appendChild(image); 
     329        } 
     330        image.style.width = width; 
     331        image.style.height = height; 
     332        image.src = style.externalGraphic; 
     333        image.style.filter = 
     334            "progid:DXImageTransform.Microsoft.AlphaImageLoader(" +  
     335            "src='', sizingMethod='scale')"; 
     336 
     337        var rotation = style.rotation * Math.PI / 180; 
     338        var sintheta = Math.sin(rotation); 
     339        var costheta = Math.cos(rotation); 
     340 
     341        // do the rotation on the image 
     342        var filter = 
     343            "progid:DXImageTransform.Microsoft.Matrix(M11=" + costheta + 
     344            ",M12=" + (-sintheta) + ",M21=" + sintheta + ",M22=" + costheta + 
     345            ",SizingMethod='auto expand')\n" 
     346 
     347        // set the opacity (needed for the imagedata) 
     348        var opacity = style.graphicOpacity || style.fillOpacity; 
     349        if (opacity && opacity != 1) { 
     350            filter +=  
     351                "progid:DXImageTransform.Microsoft.BasicImage(opacity=" +  
     352                opacity+")\n"; 
     353        } 
     354        node.style.filter = filter; 
     355 
     356        // do the rotation again on a box, so we know the insertion point 
     357        var centerPoint = new OpenLayers.Geometry.Point(-xOffset, -yOffset); 
     358        var imgBox = new OpenLayers.Bounds(0, 0, width, height).toGeometry(); 
     359        imgBox.rotate(style.rotation, centerPoint); 
     360        var imgBounds = imgBox.getBounds(); 
     361 
     362        node.style.left = Math.round( 
     363            parseInt(node.style.left) + imgBounds.left); 
     364        node.style.top = Math.round( 
     365            parseInt(node.style.top) - imgBounds.bottom); 
    250366    }, 
    251367 
  • trunk/openlayers/tests/Renderer/VML.html

    r6719 r7324  
    143143        t.eq(node.style.width, (2 * radius) + "px", "width is correct"); 
    144144        t.eq(node.style.height, (2 * radius) + "px", "height is correct"); 
     145    } 
     146     
     147    function test_VML_drawGraphic(t) { 
     148        if (!OpenLayers.Renderer.VML.prototype.supported()) { 
     149            t.plan(0); 
     150            return; 
     151        } 
     152         
     153        t.plan(6); 
     154         
     155        var r = new OpenLayers.Renderer.VML(document.body); 
     156        r.resolution = 1; 
     157         
     158        var node = document.createElement('div'); 
     159        node.id = "test" 
     160        node._geometryClass = "OpenLayers.Geometry.Point"; 
     161         
     162        var geometry = { 
     163            x: 1, 
     164            y: 2 
     165        } 
     166         
     167        var style = { 
     168            externalGraphic: "foo.png", 
     169            graphicWidth: 7, 
     170            graphicHeight: 10 
     171        } 
     172         
     173        r.drawGeometryNode(node, geometry, style); 
     174 
     175        t.eq(node.childNodes[0].id, "test_fill", "fill child node correctly created"); 
     176        t.eq(node.style.left, "-3px", "x of insertion point with calculated xOffset correct"); 
     177        t.eq(node.style.top, "-3px", "y of insertion point with calculated yOffset correct"); 
     178         
     179        style.rotation = 90; 
     180         
     181        r.drawGeometryNode(node, geometry, style); 
     182         
     183        t.eq(node.childNodes[1].id, "test_image", "image child node correctly created"); 
     184        t.eq(node.style.left, "-4px", "x of insertion point of rotated image correct"); 
     185        t.eq(node.style.top, "-4px", "y of insertion point of rotated image correct"); 
    145186    } 
    146187