OpenLayers OpenLayers

Changeset 6396

Show
Ignore:
Timestamp:
02/28/08 12:57:37 (6 months ago)
Author:
ahocevar
Message:

* Style and Rule now have separate context properties

  • new convenience method addUniqueValueRules in OL.StyleMap. This can actually be used to achieve what I was trying to show in the example of this ticket's description.
  • some refactoring of OL.Style to remove duplicate code (with tests)
  • a new example showing how to add a "unique value" legend to a point layer using the new addUniqueValueRules method
  • Rule.symbolizer can now also be just a symbolizer, instead of a hash of symbolizers keyed by "Point", "Line", "Polygon". This will make things even simpler (as can be seen in the styles-unique.html example)

r=tschaub (closes #1373)

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/openlayers/lib/OpenLayers/Rule.js

    r6131 r6396  
    2323    /** 
    2424     * Property: context 
    25      * {Object} An optional object with properties that the rule and its 
    26      * symbolizers' property values should be evaluatad against. If no 
    27      * context is specified, feature.attributes will be used 
     25     * {Object} An optional object with properties that the rule should be 
     26     * evaluatad against. If no context is specified, feature.attributes will 
     27     * be used. 
    2828     */ 
    2929    context: null, 
     
    4141    /** 
    4242     * Property: symbolizer 
    43      * {Object} Hash of styles for this rule. Contains hashes of feature 
    44      * styles. Keys are one or more of ["Point", "Line", "Polygon"] 
     43     * {Object} Symbolizer or hash of symbolizers for this rule. If hash of 
     44     * symbolizers, keys are one or more of ["Point", "Line", "Polygon"] 
    4545     */ 
    4646    symbolizer: null, 
  • trunk/openlayers/lib/OpenLayers/Style.js

    r6246 r6396  
    4242     
    4343    /** 
     44     * Property: context 
     45     * {Object} An optional object with properties that symbolizers' property 
     46     * values should be evaluatad against. If no context is specified, 
     47     * feature.attributes will be used 
     48     */ 
     49    context: null, 
     50 
     51    /** 
    4452     * Property: defaultStyle 
    4553     * {Object} hash of style properties to use as default for merging 
     
    117125        for(var i=0; i<rules.length; i++) { 
    118126            rule = rules[i]; 
    119             context = rule.context; 
    120             if (!context) { 
    121                 context = feature.attributes || feature.data; 
    122             } 
    123127            // does the rule apply? 
    124128            var applies = rule.evaluate(feature); 
     
    129133                } else { 
    130134                    appliedRules = true; 
    131                     this.applySymbolizer(rule, style, feature, context); 
     135                    this.applySymbolizer(rule, style, feature); 
    132136                } 
    133137            } 
     
    138142            appliedRules = true; 
    139143            for(var i=0; i<elseRules.length; i++) { 
    140                 this.applySymbolizer(elseRules[i], style, feature, context); 
     144                this.applySymbolizer(elseRules[i], style, feature); 
    141145            } 
    142146        } 
     
    159163     * style - {Object} 
    160164     * feature - {<OpenLayer.Feature.Vector>} 
    161      * context - {Object} 
    162165     * 
    163166     * Returns: 
    164167     * {Object} A style with new symbolizer applied. 
    165168     */ 
    166     applySymbolizer: function(rule, style, feature, context) { 
     169    applySymbolizer: function(rule, style, feature) { 
    167170        var symbolizerPrefix = feature.geometry ? 
    168171                this.getSymbolizerPrefix(feature.geometry) : 
    169172                OpenLayers.Style.SYMBOLIZER_PREFIXES[0]; 
    170173 
    171         var symbolizer = rule.symbolizer[symbolizerPrefix]; 
    172  
     174        var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer; 
     175 
     176        var context = this.context || feature.attributes || feature.data; 
     177         
    173178        // merge the style with the current style 
    174179        return this.createLiterals( 
     
    213218        // check the default style 
    214219        var style = this.defaultStyle; 
    215         for (var i in style) { 
    216             if (typeof style[i] == "string" && style[i].match(/\$\{\w+\}/)) {   
    217                 propertyStyles[i] = true; 
    218             } 
    219         } 
     220        this.addPropertyStyles(propertyStyles, style); 
    220221 
    221222        // walk through all rules to check for properties in their symbolizer 
    222223        var rules = this.rules; 
    223         var prefixes = OpenLayers.Style.SYMBOLIZER_PREFIXES
     224        var symbolizer, value
    224225        for (var i=0; i<rules.length; i++) { 
    225             for (var s=0; s<prefixes.length; s++) { 
    226                 style = rules[i].symbolizer[prefixes[s]]; 
    227                 for (var j in style) { 
    228                     if (typeof style[j] == "string" && 
    229                             style[j].match(/\$\{\w+\}/)) { 
    230                         propertyStyles[j] = true; 
    231                     } 
     226            var symbolizer = rules[i].symbolizer; 
     227            for (var key in symbolizer) { 
     228                value = symbolizer[key]; 
     229                if (typeof value == "object") { 
     230                    // symbolizer key is "Point", "Line" or "Polygon" 
     231                    this.addPropertyStyles(propertyStyles, value); 
     232                } else { 
     233                    // symbolizer is a hash of style properties 
     234                    this.addPropertyStyles(propertyStyles, symbolizer); 
     235                    break; 
    232236                } 
     237            } 
     238        } 
     239        return propertyStyles; 
     240    }, 
     241     
     242    /** 
     243     * Method: addPropertyStyles 
     244     *  
     245     * Parameters: 
     246     * propertyStyles - {Object} hash to add new property styles to. Will be 
     247     *                  modified inline 
     248     * symbolizer     - {Object} search this symbolizer for property styles 
     249     *  
     250     * Returns: 
     251     * {Object} propertyStyles hash 
     252     */ 
     253    addPropertyStyles: function(propertyStyles, symbolizer) { 
     254        var property; 
     255        for (var key in symbolizer) { 
     256            property = symbolizer[key]; 
     257            if (typeof property == "string" && 
     258                    property.match(/\$\{\w+\}/)) { 
     259                propertyStyles[key] = true; 
    233260            } 
    234261        } 
  • trunk/openlayers/lib/OpenLayers/StyleMap.js

    r6240 r6396  
    111111            this.styles[intent].createSymbolizer(feature)); 
    112112    }, 
     113     
     114    /** 
     115     * Method: addUniqueValueRules 
     116     * Convenience method to create comparison rules for unique values of a 
     117     * property. The rules will be added to the style object for a specified 
     118     * rendering intent. This method is a shortcut for creating something like 
     119     * the "unique value legends" familiar from well known desktop GIS systems 
     120     *  
     121     * Parameters: 
     122     * renderIntent - {String} rendering intent to add the rules to 
     123     * property     - {String} values of feature attributes to create the 
     124     *                rules for 
     125     * symbolizers  - {Object} Hash of symbolizers, keyed by the desired 
     126     *                property values  
     127     */ 
     128    addUniqueValueRules: function(renderIntent, property, symbolizers) { 
     129        var rules = []; 
     130        for (var value in symbolizers) { 
     131            rules.push(new OpenLayers.Rule.Comparison({ 
     132                type: OpenLayers.Rule.Comparison.EQUAL_TO, 
     133                property: property, 
     134                value: value, 
     135                symbolizer: symbolizers[value]})); 
     136        } 
     137        this.styles[renderIntent].addRules(rules); 
     138    }, 
    113139 
    114140    CLASS_NAME: "OpenLayers.StyleMap" 
  • trunk/openlayers/tests/Rule/test_Comparison.html

    r6131 r6396  
    3939     
    4040    function test_Comparison_evaluate(t) { 
    41         t.plan(3); 
     41        t.plan(4); 
    4242         
    4343        var rule = new OpenLayers.Rule.Comparison({ 
     
    6363                    " evaluates to "+result.toString()+" correctly."); 
    6464        } 
     65        rule.context = { 
     66            area: 4998 
     67        } 
     68        var result = rule.evaluate(); 
     69        t.eq(result, true, "evaluation against custom rule context works."); 
    6570    } 
    6671    </script>  
  • trunk/openlayers/tests/test_Style.html

    r6240 r6396  
    117117    function test_Style_context(t) { 
    118118        t.plan(1); 
    119         var context = { 
    120             foo: "bar", 
    121             size: 10}; 
    122119        var rule = new OpenLayers.Rule.Comparison({ 
    123120            type: OpenLayers.Rule.Comparison.LESS_THAN, 
    124             context: context, 
    125121            property: "size", 
    126122            value: 11, 
    127             symbolizer: {"Point": {externalGraphic: "${foo}.png"}}}); 
     123            symbolizer: {"Point": {externalGraphic: "${img1}"}}}); 
    128124        var style = new OpenLayers.Style(); 
     125        style.context = { 
     126            "img1": "myImage.png" 
     127        }; 
    129128        style.addRules([rule]); 
    130         var styleHash = style.createSymbolizer(new OpenLayers.Feature.Vector()); 
    131         t.eq(styleHash.externalGraphic, "bar.png", "correctly evaluated rule against a custom context"); 
     129        var feature = new OpenLayers.Feature.Vector(); 
     130        feature.attributes = {size: 10}; 
     131        var styleHash = style.createSymbolizer(feature); 
     132        t.eq(styleHash.externalGraphic, "myImage.png", "correctly evaluated rule and calculated property styles from a custom context"); 
     133    } 
     134     
     135    function test_Style_findPropertyStyles(t) { 
     136        t.plan(4); 
     137        var rule1 = new OpenLayers.Rule({symbolizer: { 
     138            pointRadius: 3, 
     139            externalGraphic: "${foo}.bar" 
     140        }}); 
     141        var rule2 = new OpenLayers.Rule({symbolizer: {"Point": { 
     142            strokeWidth: "${foo}" 
     143        }}}); 
     144        var style = new OpenLayers.Style({ 
     145            strokeOpacity: 1, 
     146            strokeColor: "${foo}" 
     147        }); 
     148        style.addRules([rule1, rule2]); 
     149        var propertyStyles = style.findPropertyStyles(); 
     150        t.ok(propertyStyles.externalGraphic, "detected externalGraphic from rule correctly"); 
     151        t.ok(propertyStyles.strokeWidth, "detected strokeWidth from Point symbolizer correctly"); 
     152        t.ok(propertyStyles.strokeColor, "detected strokeColor from style correctly"); 
     153        t.eq(typeof propertyStyles.pointRadius, "undefined", "correctly detected pointRadius as non-property style"); 
    132154    } 
    133155