OpenLayers OpenLayers

Changeset 7634

Show
Ignore:
Timestamp:
07/31/08 13:02:10 (4 months ago)
Author:
ahocevar
Message:

added new graphicName symbolizer property, which allows to render well-known graphic symbols named "square", "cross", "x" and "triangle", in addition to the existing "circle". Thanks Tim for the tweaks and the example. r=tschaub,elemoine (closes #1398)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/openlayers/examples/tasmania/TasmaniaCities.xml

    r5520 r7634  
    2424    </topp:tasmania_cities> 
    2525  </gml:featureMember> 
     26  <gml:featureMember> 
     27    <topp:tasmania_cities fid="tasmania_cities.2"> 
     28      <topp:the_geom> 
     29        <gml:MultiPoint srsName="http://www.opengis.net/gml/srs/epsg.xml#4326"> 
     30          <gml:pointMember> 
     31            <gml:Point> 
     32              <gml:coordinates xmlns:gml="http://www.opengis.net/gml" decimal="." cs="," ts=" ">147,-41.1</gml:coordinates> 
     33            </gml:Point> 
     34          </gml:pointMember> 
     35        </gml:MultiPoint> 
     36      </topp:the_geom> 
     37      <topp:CNTRY_NAME>Australia</topp:CNTRY_NAME> 
     38    </topp:tasmania_cities> 
     39  </gml:featureMember> 
    2640</wfs:FeatureCollection> 
  • trunk/openlayers/examples/tasmania/sld-tasmania.xml

    r6645 r7634  
    529529      <sld:FeatureTypeStyle> 
    530530        <sld:Rule> 
     531          <ogc:Filter> 
     532            <ogc:FeatureId fid="tasmania_cities.1"/> 
     533          </ogc:Filter> 
    531534          <sld:PointSymbolizer> 
    532535            <sld:Graphic> 
     
    535538                <sld:Format>image/png</sld:Format> 
    536539              </sld:ExternalGraphic> 
    537               <sld:Opacity>0.5</sld:Opacity> 
     540              <sld:Opacity>0.7</sld:Opacity> 
     541              <sld:Size>14</sld:Size> 
     542            </sld:Graphic> 
     543          </sld:PointSymbolizer> 
     544        </sld:Rule> 
     545        <sld:Rule> 
     546          <sld:ElseFilter/> 
     547          <sld:PointSymbolizer> 
     548            <sld:Graphic> 
     549              <sld:Mark> 
     550                <sld:WellKnownName>cross</sld:WellKnownName> 
     551              </sld:Mark> 
    538552              <sld:Size>10</sld:Size> 
    539553            </sld:Graphic> 
  • trunk/openlayers/examples/vector-features.html

    r7534 r7634  
    2727            style_blue.strokeColor = "blue"; 
    2828            style_blue.fillColor = "blue"; 
     29            style_blue.graphicName = "star"; 
     30            style_blue.pointRadius = 10; 
     31            style_blue.strokeWidth = 3; 
     32            style_blue.rotation = 45; 
     33            style_blue.strokeLinecap = "butt"; 
    2934 
    3035            /* 
  • trunk/openlayers/lib/OpenLayers/Feature/Vector.js

    r7593 r7634  
    324324 *  - graphicWidth, 
    325325 *  - graphicHeight, 
    326  *  - graphicOpacity 
    327  *  - graphicXOffset 
    328  *  - graphicYOffset 
     326 *  - graphicOpacity, 
     327 *  - graphicXOffset, 
     328 *  - graphicYOffset, 
     329 *  - graphicName, 
    329330 *  - display 
    330331 */  
  • trunk/openlayers/lib/OpenLayers/Format/SLD/v1.js

    r7627 r7634  
    5353        strokeOpacity: 1, 
    5454        strokeWidth: 1, 
    55         pointRadius: 6 
     55        pointRadius: 3, 
     56        graphicName: "square" 
    5657    }, 
    5758     
  • trunk/openlayers/lib/OpenLayers/Renderer/Elements.js

    r7627 r7634  
    372372        return node; 
    373373    }, 
    374  
     374     
     375    /** 
     376     * Method: isComplexSymbol 
     377     * Determines if a symbol cannot be rendered using drawCircle 
     378     *  
     379     * Parameters: 
     380     * graphicName - {String} 
     381     *  
     382     * Returns 
     383     * {Boolean} true if the symbol is complex, false if not 
     384     */ 
     385    isComplexSymbol: function(graphicName) { 
     386        return (graphicName != "circle") && !!graphicName; 
     387    }, 
     388     
    375389    CLASS_NAME: "OpenLayers.Renderer.Elements" 
    376390}); 
     391 
     392 
     393/** 
     394 * Constant: OpenLayers.Renderer.symbol 
     395 * Coordinate arrays for well known (named) symbols. 
     396 */ 
     397OpenLayers.Renderer.symbol = { 
     398    "star": [350,75, 379,161, 469,161, 397,215, 423,301, 350,250, 277,301, 
     399            303,215, 231,161, 321,161, 350,75], 
     400    "cross": [4,0, 6,0, 6,4, 10,4, 10,6, 6,6, 6,10, 4,10, 4,6, 0,6, 0,4, 4,4, 
     401            4,0], 
     402    "x": [0,0, 25,0, 50,35, 75,0, 100,0, 65,50, 100,100, 75,100, 50,65, 25,100, 0,100, 35,50, 0,0], 
     403    "square": [0,0, 0,1, 1,1, 1,0, 0,0], 
     404    "triangle": [0,10, 10,10, 5,0, 0,10] 
     405} 
  • trunk/openlayers/lib/OpenLayers/Renderer/SVG.js

    r7627 r7634  
    2020     */ 
    2121    xmlns: "http://www.w3.org/2000/svg", 
     22     
     23    /** 
     24     * Property: xlinkns 
     25     * {String} 
     26     */ 
     27    xlinkns: "http://www.w3.org/1999/xlink", 
    2228 
    2329    /** 
     
    3440     */ 
    3541    localResolution: null, 
     42     
     43    /** 
     44     * Property: symbolSize 
     45     * {Object} Cache for symbol sizes according to their svg coordinate space 
     46     */ 
     47    symbolSize: {}, 
    3648 
    3749    /** 
     
    155167        switch (geometry.CLASS_NAME) { 
    156168            case "OpenLayers.Geometry.Point": 
    157                 nodeType = style.externalGraphic ? "image" : "circle"; 
     169                if (style.externalGraphic) { 
     170                    nodeType = "image"; 
     171                } else if (this.isComplexSymbol(style.graphicName)) { 
     172                    nodeType = "use"; 
     173                } else { 
     174                    nodeType = "circle"; 
     175                } 
    158176                break; 
    159177            case "OpenLayers.Geometry.Rectangle": 
     
    195213        options = options || node._options; 
    196214        var r = parseFloat(node.getAttributeNS(null, "r")); 
     215        var widthFactor = 1; 
     216        var pos; 
    197217        if (node._geometryClass == "OpenLayers.Geometry.Point" && r) { 
    198218            if (style.externalGraphic) { 
    199                 var x = parseFloat(node.getAttributeNS(null, "cx")); 
    200                 var y = parseFloat(node.getAttributeNS(null, "cy")); 
     219                pos = this.getPosition(node); 
    201220                 
    202221                if (style.graphicWidth && style.graphicHeight) { 
     
    214233                var opacity = style.graphicOpacity || style.fillOpacity; 
    215234                 
    216                 node.setAttributeNS(null, "x", (x + xOffset).toFixed()); 
    217                 node.setAttributeNS(null, "y", (y + yOffset).toFixed()); 
     235                node.setAttributeNS(null, "x", (pos.x + xOffset).toFixed()); 
     236                node.setAttributeNS(null, "y", (pos.y + yOffset).toFixed()); 
    218237                node.setAttributeNS(null, "width", width); 
    219238                node.setAttributeNS(null, "height", height); 
    220                 node.setAttributeNS("http://www.w3.org/1999/xlink", "href", style.externalGraphic); 
     239                node.setAttributeNS(this.xlinkns, "href", style.externalGraphic); 
    221240                node.setAttributeNS(null, "style", "opacity: "+opacity); 
     241            } else if (this.isComplexSymbol(style.graphicName)) { 
     242                // the symbol viewBox is three times as large as the symbol 
     243                var offset = style.pointRadius * 3; 
     244                var size = offset * 2; 
     245                var id = this.importSymbol(style.graphicName); 
     246                pos = this.getPosition(node); 
     247                widthFactor = this.symbolSize[id] / size; 
     248                node.setAttributeNS(this.xlinkns, "href", "#" + id); 
     249                node.setAttributeNS(null, "width", size); 
     250                node.setAttributeNS(null, "height", size); 
     251                node.setAttributeNS(null, "x", pos.x - offset); 
     252                node.setAttributeNS(null, "y", pos.y - offset); 
    222253            } else { 
    223254                node.setAttributeNS(null, "r", style.pointRadius); 
    224255            } 
    225256 
    226             if (style.rotation) { 
     257            if (style.rotation && pos) { 
    227258                var rotation = OpenLayers.String.format( 
    228                     "rotate(${0} ${1} ${2})", [style.rotation, x, y]); 
     259                    "rotate(${0} ${1} ${2})", [style.rotation, pos.x, pos.y]); 
    229260                node.setAttributeNS(null, "transform", rotation); 
    230261            } 
     
    241272            node.setAttributeNS(null, "stroke", style.strokeColor); 
    242273            node.setAttributeNS(null, "stroke-opacity", style.strokeOpacity); 
    243             node.setAttributeNS(null, "stroke-width", style.strokeWidth); 
     274            node.setAttributeNS(null, "stroke-width", style.strokeWidth * widthFactor); 
    244275            node.setAttributeNS(null, "stroke-linecap", style.strokeLinecap); 
    245276        } else { 
     
    307338    createRoot: function() { 
    308339        return this.nodeFactory(this.container.id + "_root", "g"); 
     340    }, 
     341 
     342    /** 
     343     * Method: createDefs 
     344     * 
     345     * Returns: 
     346     * {DOMElement} The element to which we'll add the symbol definitions 
     347     */ 
     348    createDefs: function() { 
     349        var defs = this.nodeFactory("ol-renderer-defs", "defs"); 
     350        this.rendererRoot.appendChild(defs); 
     351        return defs; 
    309352    }, 
    310353 
     
    511554        } 
    512555    }, 
     556     
     557    /** 
     558     * Method: getPosition 
     559     * Finds the position of an svg node. 
     560     *  
     561     * Parameters: 
     562     * node - {DOMElement} 
     563     *  
     564     * Returns: 
     565     * {Object} hash with x and y properties, representing the coordinates 
     566     *     within the svg coordinate system 
     567     */ 
     568    getPosition: function(node) { 
     569        return({ 
     570            x: parseFloat(node.getAttributeNS(null, "cx")), 
     571            y: parseFloat(node.getAttributeNS(null, "cy")) 
     572        }); 
     573    }, 
     574 
     575    /** 
     576     * Method: importSymbol 
     577     * add a new symbol definition from the rendererer's symbol hash 
     578     *  
     579     * Parameters: 
     580     * graphicName - {String} name of the symbol to import 
     581     *  
     582     * Returns: 
     583     * {String} - id of the imported symbol 
     584     */       
     585    importSymbol: function (graphicName)  { 
     586        if (!this.defs) { 
     587            // create svg defs tag 
     588            this.defs = this.createDefs(); 
     589        } 
     590        var id = this.container.id + "-" + graphicName; 
     591         
     592        // check if symbol already exists in the defs 
     593        if (document.getElementById(id) != null) { 
     594            return id; 
     595        } 
     596         
     597        var symbol = OpenLayers.Renderer.symbol[graphicName]; 
     598        if (!symbol) { 
     599            throw new Error(graphicName + ' is not a valid symbol name'); 
     600            return; 
     601        } 
     602 
     603        var symbolNode = this.nodeFactory(id, "symbol"); 
     604        var node = this.nodeFactory(null, "polygon"); 
     605        symbolNode.appendChild(node); 
     606        var symbolExtent = new OpenLayers.Bounds( 
     607                                    Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); 
     608 
     609        var points = ""; 
     610        var x,y; 
     611        for (var i=0; i<symbol.length; i=i+2) { 
     612            x = symbol[i]; 
     613            y = symbol[i+1]; 
     614            symbolExtent.left = Math.min(symbolExtent.left, x); 
     615            symbolExtent.bottom = Math.min(symbolExtent.bottom, y); 
     616            symbolExtent.right = Math.max(symbolExtent.right, x); 
     617            symbolExtent.top = Math.max(symbolExtent.top, y); 
     618            points += " " + x + "," + y; 
     619        } 
     620         
     621        node.setAttributeNS(null, "points", points); 
     622        // Hard-coded linejoin for now, to make it look the same as in VML. 
     623        // There is no strokeLinejoin property yet for symbolizers. 
     624        node.setAttributeNS(null, "stroke-linejoin", "round"); 
     625         
     626        var width = symbolExtent.getWidth(); 
     627        var height = symbolExtent.getHeight(); 
     628        // create a viewBox three times as large as the symbol itself, 
     629        // to allow for strokeWidth being displayed correctly at the corners. 
     630        var viewBox = [symbolExtent.left - width, 
     631                        symbolExtent.bottom - height, width * 3, height * 3]; 
     632        symbolNode.setAttributeNS(null, "viewBox", viewBox.join(" ")); 
     633        this.symbolSize[id] = Math.max(width, height) * 3; 
     634         
     635        this.defs.appendChild(symbolNode); 
     636        return symbolNode.id; 
     637    }, 
    513638 
    514639    CLASS_NAME: "OpenLayers.Renderer.SVG" 
  • trunk/openlayers/lib/OpenLayers/Renderer/VML.js

    r7627 r7634  
    2626     */ 
    2727    xmlns: "urn:schemas-microsoft-com:vml", 
     28     
     29    /** 
     30     * Property: symbolCache 
     31     * {DOMElement} node holding symbols. This hash is keyed by symbol name, 
     32     *     and each value is a hash with a "path" and an "extent" property. 
     33     */ 
     34    symbolCache: {}, 
    2835 
    2936    /** 
     
    124131        switch (geometry.CLASS_NAME) { 
    125132            case "OpenLayers.Geometry.Point": 
    126                 nodeType = style.externalGraphic ? "olv:rect" : "olv:oval"; 
     133                if (style.externalGraphic) { 
     134                    nodeType = "olv:rect"; 
     135                } else if (this.isComplexSymbol(style.graphicName)) { 
     136                    nodeType = "olv:shape"; 
     137                } else { 
     138                    nodeType = "olv:oval"; 
     139                } 
    127140                break; 
    128141            case "OpenLayers.Geometry.Rectangle": 
     
    157170        style = style  || node._style; 
    158171        options = options || node._options; 
     172        var widthFactor = 1; 
    159173         
    160174        if (node._geometryClass == "OpenLayers.Geometry.Point") { 
     
    180194                style.fillColor = "none"; 
    181195                options.isStroked = false; 
    182                           
     196            } else if (this.isComplexSymbol(style.graphicName)) { 
     197                var cache = this.importSymbol(style.graphicName); 
     198                var symbolExtent = cache.extent; 
     199                var width = symbolExtent.getWidth(); 
     200                var height = symbolExtent.getHeight(); 
     201                node.setAttribute("path", cache.path); 
     202                node.setAttribute("coordorigin", symbolExtent.left + "," + 
     203                                                                symbolExtent.bottom); 
     204                node.setAttribute("coordsize", width + "," + height); 
     205                node.style.left = symbolExtent.left + "px"; 
     206                node.style.top = symbolExtent.bottom + "px"; 
     207                node.style.width = width + "px"; 
     208                node.style.height = height + "px"; 
     209         
     210                this.drawCircle(node, geometry, style.pointRadius); 
     211                node.style.flip = "y"; 
    183212            } else { 
    184213                this.drawCircle(node, geometry, style.pointRadius); 
     
    218247                  fill.aspect = "atmost"; 
    219248                }                 
    220                           
    221                 // additional rendering for rotated graphics 
    222                 if (style.rotation) { 
    223                     this.graphicRotate(node, xOffset, yOffset); 
    224                     // make the fill fully transparent, because we now have 
    225                     // the graphic as imagedata element. We cannot just remove 
    226                     // the fill, because this is part of the hack described 
    227                     // in graphicRotate 
    228                     fill.setAttribute("opacity", 0); 
    229                 } 
    230249            } 
    231250            if (fill.parentNode != node) { 
     
    234253        } 
    235254 
     255        // additional rendering for rotated graphics or symbols 
     256        if (style.rotation) { 
     257            if (style.externalGraphic) { 
     258                this.graphicRotate(node, xOffset, yOffset); 
     259                // make the fill fully transparent, because we now have 
     260                // the graphic as imagedata element. We cannot just remove 
     261                // the fill, because this is part of the hack described 
     262                // in graphicRotate 
     263                fill.setAttribute("opacity", 0); 
     264            } else { 
     265                node.style.rotation = style.rotation; 
     266            } 
     267        } 
    236268 
    237269        // stroke  
     
    695727        node.path = path.join(""); 
    696728    }, 
    697  
     729     
     730    /** 
     731     * Method: importSymbol 
     732     * add a new symbol definition from the rendererer's symbol hash 
     733     *  
     734     * Parameters: 
     735     * graphicName - {String} name of the symbol to import 
     736     *  
     737     * Returns: 
     738     * {Object} - hash of {DOMElement} "symbol" and {Number} "size" 
     739     */       
     740    importSymbol: function (graphicName)  { 
     741        var id = this.container.id + "-" + graphicName; 
     742         
     743        // check if symbol already exists in the cache 
     744        var cache = this.symbolCache[id]; 
     745        if (cache) { 
     746            return cache; 
     747        } 
     748         
     749        var symbol = OpenLayers.Renderer.symbol[graphicName]; 
     750        if (!symbol) { 
     751            throw new Error(graphicName + ' is not a valid symbol name'); 
     752            return; 
     753        } 
     754 
     755        var symbolExtent = new OpenLayers.Bounds( 
     756                                    Number.MAX_VALUE, Number.MAX_VALUE, 0, 0); 
     757         
     758        var pathitems = ["m"]; 
     759        for (var i=0; i<symbol.length; i=i+2) { 
     760            x = symbol[i]; 
     761            y = symbol[i+1]; 
     762            symbolExtent.left = Math.min(symbolExtent.left, x); 
     763            symbolExtent.bottom = Math.min(symbolExtent.bottom, y); 
     764            symbolExtent.right = Math.max(symbolExtent.right, x); 
     765            symbolExtent.top = Math.max(symbolExtent.top, y); 
     766 
     767            pathitems.push(x); 
     768            pathitems.push(y); 
     769            if (i == 0) { 
     770                pathitems.push("l"); 
     771            } 
     772        } 
     773        pathitems.push("x e"); 
     774        var path = pathitems.join(" "); 
     775         
     776        cache = { 
     777            path: path, 
     778            extent: symbolExtent 
     779        }; 
     780        this.symbolCache[id] = cache; 
     781         
     782        return cache; 
     783    }, 
     784     
    698785    CLASS_NAME: "OpenLayers.Renderer.VML" 
    699786}); 
  • trunk/openlayers/tests/Renderer/SVG.html

    r7586 r7634  
    372372    } 
    373373     
    374      
    375  
     374    function test_svg_getnodetype(t) { 
     375        if (!OpenLayers.Renderer.SVG.prototype.supported()) { 
     376            t.plan(0); 
     377            return; 
     378        } 
     379 
     380        t.plan(1); 
     381         
     382        var r = new OpenLayers.Renderer.SVG(document.body); 
     383 
     384        var g = {CLASS_NAME: "OpenLayers.Geometry.Point"} 
     385        var s = {graphicName: "square"}; 
     386         
     387        t.eq(r.getNodeType(g, s), "use", "Correct node type for well known symbols"); 
     388    } 
     389         
     390    function test_svg_importsymbol(t) { 
     391        if (!OpenLayers.Renderer.SVG.prototype.supported()) { 
     392            t.plan(0); 
     393            return; 
     394        } 
     395 
     396        t.plan(2); 
     397         
     398        var r = new OpenLayers.Renderer.SVG(document.body); 
     399 
     400        r.importSymbol("square"); 
     401 
     402        var polygon = document.getElementById("ol-renderer-defs").firstChild.firstChild; 
     403 
     404        t.eq(polygon.getAttribute("points"), "0,0 0,1 1,1 1,0 0,0", "Square symbol rendered correctly"); 
     405        t.ok(r.symbolSize["-square"], "Symbol size cached correctly."); 
     406    } 
     407         
    376408  </script> 
    377409</head> 
  • trunk/openlayers/tests/Renderer/VML.html

    r7586 r7634  
    339339    } 
    340340     
    341  
     341    function test_vml_getnodetype(t) { 
     342        if (!OpenLayers.Renderer.VML.prototype.supported()) { 
     343            t.plan(0); 
     344            return; 
     345        } 
     346 
     347        t.plan(1); 
     348         
     349        var r = new OpenLayers.Renderer.VML(document.body); 
     350 
     351        var g = {CLASS_NAME: "OpenLayers.Geometry.Point"} 
     352        var s = {graphicName: "square"}; 
     353         
     354        t.eq(r.getNodeType(g, s), "olv:shape", "Correct node type for well known symbols"); 
     355    } 
     356 
     357    function test_vml_importsymbol(t) { 
     358        if (!OpenLayers.Renderer.VML.prototype.supported()) { 
     359            t.plan(0); 
     360            return; 
     361        } 
     362 
     363        t.plan(2); 
     364         
     365        var r = new OpenLayers.Renderer.VML(document.body); 
     366 
     367        var cache = r.importSymbol("square"); 
     368 
     369        t.eq(cache.path, "m 0 0 l 0 1 1 1 1 0 0 0 x e", "Square symbol rendered correctly"); 
     370        t.ok(r.symbolCache["-square"], "Symbol has been cached correctly."); 
     371         
     372    } 
     373         
    342374  </script> 
    343375</head>