OpenLayers OpenLayers

Ticket #1531: 1531-r7060-A0.patch

File 1531-r7060-A0.patch, 18.4 kB (added by ahocevar, 8 months ago)
  • tests/Format/SLD/v1_0_0.html

    old new  
    1515                '<Name>AAA161</Name>' +  
    1616                '<UserStyle>' +  
    1717                    '<FeatureTypeStyle>' +  
     18                        '<SemanticTypeIdentifier>generic:geometry</SemanticTypeIdentifier>' + 
    1819                        '<Rule>' +  
    1920                            '<Name>stortsteen</Name>' +  
    2021                            '<ogc:Filter>' + 
  • tests/StyleMap.html

    old new  
    3636        t.ok(!styleMap.styles, "StyleMap styles successfully destroyed"); 
    3737    } 
    3838     
     39    function test_StyleMap_makeGeometryTypeAware(t) { 
     40        t.plan(7); 
     41        var styleMap = new OpenLayers.StyleMap({"Point": "foo", "Line": "bar"}); 
     42        styleMap.styles["default"].addRules([new OpenLayers.Rule({symbolizer: { 
     43            "Polygon": "foobar"}})]); 
     44        styleMap.makeGeometryTypeAware(); 
     45        t.eq(styleMap.styles["default"].rules.length, 3, "correct number of rules created"); 
     46        t.eq(styleMap.styles["default"].rules[0].symbolizer, "foo", "assigned point symbolizer from defaultStyle correctly to point rule"); 
     47        t.eq(styleMap.styles["default"].rules[0].geometryType, "generic:point", "assign geometry type correctly to point rule"); 
     48        t.eq(styleMap.styles["default"].rules[1].symbolizer, "bar", "assigned line symbolizer from defaultStyle correctly to point rule"); 
     49        t.eq(styleMap.styles["default"].rules[1].geometryType, "generic:line", "assign geometry type correctly to line rule"); 
     50        t.eq(styleMap.styles["default"].rules[2].symbolizer, "foobar", "assigned polygon symbolizer correctly to polygon rule"); 
     51        t.eq(styleMap.styles["default"].rules[2].geometryType, "generic:polygon", "assign geometry type correctly to polygon rule"); 
     52    } 
     53     
    3954    </script>  
    4055</head>  
    4156<body>  
  • tests/Rule.html

    old new  
    2121        rule.destroy(); 
    2222        t.eq(rule.symbolizer, null, "symbolizer hash nulled properly"); 
    2323    } 
     24     
     25    function test_Rule_evaluate(t) { 
     26        t.plan(2); 
     27         
     28        var rule = new OpenLayers.Rule(); 
     29        rule.geometryType = "generic:line"; 
    2430 
     31        var feature = {geometry: new OpenLayers.Geometry.MultiLineString()}; 
     32        t.eq(rule.evaluate(feature), true, "Rule correctly evaluated for line feature"); 
     33 
     34        feature.geometry = new OpenLayers.Geometry.Point(); 
     35        t.eq(rule.evaluate(feature), false, "Rule correctly evaluated for point feature"); 
     36    } 
     37 
    2538    </script>  
    2639</head>  
    2740<body>  
  • tests/Style.html

    old new  
    102102    } 
    103103     
    104104    function test_Style_createSymbolizer(t) { 
    105         t.plan(2); 
     105        t.plan(4); 
    106106        var style = new OpenLayers.Style(); 
    107107        var rule = new OpenLayers.Rule({ 
    108             id: Math.random() 
     108            symbolizer: { 
     109                id: Math.random() 
     110            } 
    109111        }); 
    110112        var elseRule = new OpenLayers.Rule({ 
    111             id: Math.random(), 
     113            symbolizer: { 
     114                id: Math.random() 
     115            }, 
    112116            elseFilter: true 
    113117        }); 
    114118        style.addRules([rule, elseRule]); 
    115119 
    116120        // test that applySymbolizer is only called with rule 
    117         style.applySymbolizer = function(r) { 
    118             t.eq(r.id, rule.id, "(plain) applySymbolizer called with correct rule"); 
     121        style.applySymbolizer = function(m, s) { 
     122            t.eq(s.id, rule.symbolizer.id, "(plain) applySymbolizer called with correct rule"); 
     123            return s; 
    119124        } 
     125        style.defaultStyle.id = rule.symbolizer.id; 
    120126        style.createSymbolizer(new OpenLayers.Feature.Vector()); 
    121127 
    122128        rule.evaluate = function() {return false;}; 
    123         style.applySymbolizer = function(r) { 
    124             t.eq(r.id, elseRule.id, "(else) applySymbolizer called with correct rule"); 
     129        style.applySymbolizer = function(m, s) { 
     130            t.eq(s.id, elseRule.symbolizer.id, "(else) applySymbolizer called with correct rule"); 
     131            return s; 
    125132        } 
     133        style.defaultStyle.id = elseRule.symbolizer.id; 
    126134        style.createSymbolizer(new OpenLayers.Feature.Vector()); 
    127135    } 
    128136     
  • lib/OpenLayers/Format/SLD/v1.js

    old new  
    137137            }, 
    138138            "FeatureTypeStyle": function(node, style) { 
    139139                // OpenLayers doesn't have a place for FeatureTypeStyle 
    140                 // Name, Title, Abstract, FeatureTypeName, or 
    141                 // SemanticTypeIdentifier so, we make a temporary object 
    142                 // and later just use the Rule(s). 
     140                // Name, Title, Abstract, or FeatureTypeName, so we make 
     141                // a temporary object and later just use the Rule(s), which 
     142                // will hold the SemanticTypeIdentifier from the 
     143                // FeatureTypeStyle. 
    143144                var obj = { 
     145                    semanticTypeIdentifier: null, 
    144146                    rules: [] 
    145147                }; 
    146148                this.readChildNodes(node, obj); 
    147149                style.rules = obj.rules; 
    148150            }, 
     151            "SemanticTypeIdentifier": function(node, obj) { 
     152                obj.semanticTypeIdentifier = this.getChildValue(node); 
     153            }, 
    149154            "Rule": function(node, obj) { 
    150155                var rule = new OpenLayers.Rule(); 
    151156                this.readChildNodes(node, rule); 
     157                rule.geometryType = obj.semanticTypeIdentifier; 
    152158                obj.rules.push(rule); 
    153159            }, 
    154160            "ElseFilter": function(node, rule) { 
     
    602608                } 
    603609                 
    604610                // add FeatureTypeStyles 
    605                 this.writeNode(node, "FeatureTypeStyle", style); 
     611                // create one FeatureTypeStyle for each SemanticTypeIdentifier 
     612                var featureTypeStyles = {}; 
     613                var rule, geometryType; 
     614                for(var i=0; i<style.rules.length; ++i) { 
     615                    rule = style.rules[i]; 
     616                    geometryType = rule.geometryType; 
     617                    if (!geometryType) { 
     618                        geometryType = "ol:undefined"; 
     619                    } 
     620                    if (!featureTypeStyles[geometryType]) { 
     621                        featureTypeStyles[geometryType] = [rule]; 
     622                    } else { 
     623                        featureTypeStyles[geometryType].push(rule); 
     624                    } 
     625                } 
     626                for (var i in featureTypeStyles) { 
     627                    this.writeNode(node, "FeatureTypeStyle", { 
     628                        rules: featureTypeStyles[i], 
     629                        semanticTypeIdentifier: i 
     630                    }); 
     631                } 
    606632                 
    607633                return node; 
    608634            }, 
     
    611637                    "IsDefault", {value: (bool) ? "1" : "0"} 
    612638                ); 
    613639            }, 
    614             "FeatureTypeStyle": function(style) { 
     640            "FeatureTypeStyle": function(featureTypeStyle) { 
     641                var rules = featureTypeStyle.rules; 
     642                var semanticTypeIdentifier = 
     643                        featureTypeStyle.semanticTypeIdentifier; 
     644                 
    615645                var node = this.createElementNSPlus("FeatureTypeStyle"); 
    616646                 
    617647                // OpenLayers currently stores no Name, Title, Abstract, 
    618648                // FeatureTypeName, or SemanticTypeIdentifier information 
    619                 // related to FeatureTypeStyle 
     649                // related to FeatureTypeStyle. So we create one 
     650                // FeatureTypeStyle for each SemanticTypeIdentifier (i.e. 
     651                // geometryType) found inside our rules 
    620652                 
     653                if (semanticTypeIdentifier != "ol:undefined") { 
     654                    this.writeNode(node, "SemanticTypeIdentifier", 
     655                            semanticTypeIdentifier); 
     656                } 
     657                 
    621658                // add in rules 
    622                 for(var i=0; i<style.rules.length; ++i) { 
    623                     this.writeNode(node, "Rule", style.rules[i]); 
     659                for (var i=0; i<rules.length; ++i) { 
     660                    this.writeNode(node, "Rule", rules[i]); 
    624661                } 
    625662                 
    626663                return node; 
    627664            }, 
     665            "SemanticTypeIdentifier": function(identifier) { 
     666                return this.createElementNSPlus( 
     667                    "SemanticTypeIdentifier", {value: identifier}); 
     668            }, 
    628669            "Rule": function(rule) { 
    629670                var node = this.createElementNSPlus("Rule"); 
    630671 
  • lib/OpenLayers/StyleMap.js

    old new  
    144144            })); 
    145145        } 
    146146        this.styles[renderIntent].addRules(rules); 
     147        return this; 
    147148    }, 
     149     
     150    /** 
     151     * Method: makeGeometryTypeAware 
     152     * Convenience method that converts a rule with a symbolizer hash 
     153     * keyed by geometry types for which the symbolizers are intended, to 
     154     * geometry type aware rules. In SLD, a rule with different symbolizers 
     155     * for point, line and polygon means that the feature will be rendered as 
     156     * point, line and polygon, independent of its original feature type. 
     157     * This allows us to e.g. render a point symbol at the centroid point of a 
     158     * polygon. People sometimes define symbolizers like that, hoping that 
     159     * this means if we have a point, line or polygon feature, only the point, 
     160     * line or polygon symbolizer will be applied. This method will convert 
     161     * the whole style map so that rules with such symbolizers become a set of 
     162     * rules with an according {<OpenLayers.Rule.geometryType>}.  
     163     *  
     164     * Parameters: 
     165     * mapping - {Object} A hash that maps the geometry type keys found in 
     166     *     the symbolizer hash to SemanticTypeIdentifier compliant geometry 
     167     *     type identifiers. If not specified, the following default mapping 
     168     *     will be used: 
     169     *     (code) 
     170     *     { 
     171     *        "Point":   "generic:point", 
     172     *        "Line":    "generic:line", 
     173     *        "Polygon": "generic:polygon" 
     174     *     } 
     175     *     (end) 
     176     *  
     177     * Returns: 
     178     * {<OpenLayers.StyleMap>} the modified style map (which will also be 
     179     *     modified inline). 
     180     */ 
     181    makeGeometryTypeAware: function(mapping) { 
     182        if (!mapping) { 
     183            mapping = { 
     184                "Point":   "generic:point", 
     185                "Line":    "generic:line", 
     186                "Polygon": "generic:polygon" 
     187            } 
     188        } 
     189         
     190        var modified; 
     191        var defaultRule, style, rules, rule, symbolizer; 
     192        for (var s in this.styles) { 
     193            style = this.styles[s]; 
     194            rules = style.rules || []; 
     195            defaultRule = new OpenLayers.Rule( 
     196                {symbolizer: style.defaultStyle}); 
     197            rules.push(defaultRule); 
     198            for (var i=rules.length-1; i>=0; --i) { 
     199                rule = rules[i]; 
     200                for (var m in mapping) { 
     201                    symbolizer = rule.symbolizer[m]; 
     202                    modified = false; 
     203                    if (symbolizer) { 
     204                        rules.push(OpenLayers.Util.applyDefaults({ 
     205                            id: OpenLayers.Util.createUniqueID( 
     206                                    rule.CLASS_NAME + "_"), 
     207                            symbolizer: symbolizer, 
     208                            geometryType: mapping[m] 
     209                        }, rule)); 
     210                        modified = true; 
     211                    } 
     212                } 
     213                if (modified == true || rule == defaultRule) { 
     214                    OpenLayers.Util.removeItem(rules, rule); 
     215                } 
     216            } 
     217        } 
     218        return this; 
     219    }, 
    148220 
    149221    CLASS_NAME: "OpenLayers.StyleMap" 
    150222}); 
  • lib/OpenLayers/Rule.js

    old new  
    6666     * Property: symbolizer 
    6767     * {Object} Symbolizer or hash of symbolizers for this rule. If hash of 
    6868     * symbolizers, keys are one or more of ["Point", "Line", "Polygon"]. The 
    69      * latter if useful if it is required to style e.g. vertices of a line 
    70      * with a point symbolizer. Note, however, that this is not implemented 
    71      * yet in OpenLayers, but it is the way how symbolizers are defined in 
    72      * SLD
     69     * latter if useful if it is required to style e.g. the centroid of a 
     70     * polygon with a point symbolizer. Note, however, that this is not 
     71     * implemented yet in OpenLayers. To specify a rule that only applies 
     72     * to specific geometry types, the <geometryType> property can be used
    7373     */ 
    7474    symbolizer: null, 
    7575     
    7676    /** 
     77     * Property: geometryType 
     78     * {String} If set, the rule will only be applied to feature geometries of 
     79     * a specified geometry type. The values used here are the generic values 
     80     * defined in the SLD spec for the <SemanticTypeIdentifier> property of a 
     81     * FeatureTypeStyle. Supported values are: 
     82     * - "generic:point"  
     83     * - "generic:line" 
     84     * - "generic:polygon" 
     85     */ 
     86    geometryType: null, 
     87     
     88    /** 
    7789     * APIProperty: minScaleDenominator 
    7890     * {Number} or {String} minimum scale at which to draw the feature. 
    7991     * In the case of a String, this can be a combination of text and 
     
    132144    evaluate: function(feature) { 
    133145        var context = this.getContext(feature); 
    134146        var applies = true; 
     147         
     148        // check geometry type 
     149        var semanticType = this.geometryType; 
     150        if (semanticType) { 
     151            var geomType = semanticType.substring( 
     152                    semanticType.lastIndexOf(":") + 1).toLowerCase(); 
     153            switch(geomType) { 
     154                case "point": 
     155                case "line": 
     156                case "polygon": 
     157                    if (feature.geometry.CLASS_NAME.toLowerCase().indexOf( 
     158                            geomType) == -1) { 
     159                        return false; 
     160                    } 
     161                    break; 
     162            } 
     163        } 
    135164 
    136165        if (this.minScaleDenominator || this.maxScaleDenominator) { 
    137166            var scale = feature.layer.map.getScale(); 
    138167        } 
    139168         
    140169        // check if within minScale/maxScale bounds 
    141         if (this.minScaleDenominator) { 
     170        if (applies && this.minScaleDenominator) { 
    142171            applies = scale >= OpenLayers.Style.createLiteral( 
    143172                    this.minScaleDenominator, context); 
    144173        } 
  • lib/OpenLayers/Style.js

    old new  
    127127     * {Object} symbolizer hash 
    128128     */ 
    129129    createSymbolizer: function(feature) { 
    130         var style = this.createLiterals( 
    131             OpenLayers.Util.extend({}, this.defaultStyle), feature); 
     130        var style = this.applySymbolizer({}, this.defaultStyle, feature); 
    132131         
    133132        var rules = this.rules; 
    134133 
     
    145144                    elseRules.push(rule); 
    146145                } else { 
    147146                    appliedRules = true; 
    148                     this.applySymbolizer(rule, style, feature); 
     147                    this.applySymbolizer(style, rule.symbolizer, feature); 
    149148                } 
    150149            } 
    151150        } 
     
    154153        if(appliedRules == false && elseRules.length > 0) { 
    155154            appliedRules = true; 
    156155            for(var i=0; i<elseRules.length; i++) { 
    157                 this.applySymbolizer(elseRules[i], style, feature); 
     156                this.applySymbolizer(style, elseRules[i].symbolizer, feature); 
    158157            } 
    159158        } 
    160159 
     
    172171     * Method: applySymbolizer 
    173172     * 
    174173     * Parameters: 
    175      * rule - {OpenLayers.Rule
    176      * style - {Object} 
     174     * mergedSymbolizer - {Object
     175     * symbolizer - {Object} 
    177176     * feature - {<OpenLayer.Feature.Vector>} 
    178177     * 
    179178     * Returns: 
    180      * {Object} A style with new symbolizer applied. 
     179     * {Object} The merged symbolizer with a new symbolizer applied. 
    181180     */ 
    182     applySymbolizer: function(rule, style, feature) { 
     181    applySymbolizer: function(mergedSymbolizer, symbolizer, feature) { 
     182        // TBD This is not the behavior as intended by the SLD spec. 
     183        // Currently, we only apply PointSymbolizers to points, 
     184        // LineSymbolizers to lines and so on. In the future, a 
     185        // PointSymbolizer should also be applyable e.g. to a polygon, which 
     186        // means we want to render a point at its centroid point. 
    183187        var symbolizerPrefix = feature.geometry ? 
    184188                this.getSymbolizerPrefix(feature.geometry) : 
    185189                OpenLayers.Style.SYMBOLIZER_PREFIXES[0]; 
    186190 
    187         var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer; 
    188  
    189191        // merge the style with the current style 
     192        // TBD In the future, we should render a separate geometry for each 
     193        // symbolizer. This will make it possible to render e.g. a highway 
     194        // with a narrow black line on top a wide yellow line 
    190195        return this.createLiterals( 
    191                 OpenLayers.Util.extend(style, symbolizer), feature); 
     196                OpenLayers.Util.extend(mergedSymbolizer, 
     197                symbolizer[symbolizerPrefix] || symbolizer), feature); 
    192198    }, 
    193199     
    194200    /** 
  • examples/tasmania/sld-tasmania.xml

    old new  
    1818        <sld:Title>title</sld:Title> 
    1919        <sld:Abstract>abstract</sld:Abstract> 
    2020        <sld:FeatureTypeName>Feature</sld:FeatureTypeName> 
    21         <sld:SemanticTypeIdentifier>generic:geometry</sld:SemanticTypeIdentifier> 
     21        <sld:SemanticTypeIdentifier>generic:polygon</sld:SemanticTypeIdentifier> 
    2222        <sld:Rule> 
    2323          <sld:Name>testRuleName</sld:Name> 
    2424          <sld:Title>title</sld:Title>