Adding point, line, polygon, text, and raster symbolizer constructors. This paves the way for rendering multiple symbolizers per rule. The SLD parser now successfully round-trips documents with multiple symbolizers and multiple FeatureTypeStyle elements (through the symbolizer zIndex property). The Style2 (yes, ack) constructor is used to represent a collection of rules with multiple symbolizers. Style2 objects are currently only used by the SLD parser if the multipleSymbolizer property is set to true. Future enhancements to the renderers can be made to account for multiple symbolizers. r=ahocevar (closes #2760).

git-svn-id: http://svn.openlayers.org/trunk/openlayers@10560 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
Tim Schaub
2010-08-02 19:49:52 +00:00
parent 9fd7463680
commit 6c0952934f
21 changed files with 1498 additions and 55 deletions

View File

@@ -39,6 +39,27 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
* {String} Schema location for a particular minor version.
*/
schemaLocation: null,
/**
* APIProperty: multipleSymbolizers
* {Boolean} Support multiple symbolizers per rule. Default is false. if
* true, an OpenLayers.Style2 instance will be created to represent
* user styles instead of an OpenLayers.Style instace. The
* OpenLayers.Style2 class allows collections of rules with multiple
* symbolizers, but is not currently useful for client side rendering.
* If multiple symbolizers is true, multiple FeatureTypeStyle elements
* are preserved in reading/writing by setting symbolizer zIndex values.
* In addition, the <defaultSymbolizer> property is ignored if
* multiple symbolizers are supported (defaults should be applied
* when rendering).
*/
multipleSymbolizers: false,
/**
* Property: featureTypeCounter
* {Number} Private counter for multiple feature type styles.
*/
featureTypeCounter: null,
/**
* APIProperty: defaultSymbolizer.
@@ -138,8 +159,15 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
},
"UserStyle": function(node, layer) {
var obj = {defaultsPerSymbolizer: true, rules: []};
this.featureTypeCounter = -1;
this.readChildNodes(node, obj);
var style = new OpenLayers.Style(this.defaultSymbolizer, obj);
var style;
if (this.multipleSymbolizers) {
delete obj.defaultsPerSymbolizer;
style = new OpenLayers.Style2(obj);
} else {
style = new OpenLayers.Style(this.defaultSymbolizer, obj);
}
layer.userStyles.push(style);
},
"IsDefault": function(node, style) {
@@ -148,18 +176,21 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
}
},
"FeatureTypeStyle": function(node, style) {
// OpenLayers doesn't have a place for FeatureTypeStyle
// Name, Title, Abstract, FeatureTypeName, or
// SemanticTypeIdentifier so, we make a temporary object
// and later just use the Rule(s).
++this.featureTypeCounter;
var obj = {
rules: []
rules: this.multipleSymbolizers ? style.rules : []
};
this.readChildNodes(node, obj);
style.rules = obj.rules;
if (!this.multipleSymbolizers) {
style.rules = obj.rules;
}
},
"Rule": function(node, obj) {
var rule = new OpenLayers.Rule();
var config;
if (this.multipleSymbolizers) {
config = {symbolizers: []};
}
var rule = new OpenLayers.Rule(config);
this.readChildNodes(node, rule);
obj.rules.push(rule);
},
@@ -173,11 +204,18 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
rule.maxScaleDenominator = parseFloat(this.getChildValue(node));
},
"TextSymbolizer": function(node, rule) {
// OpenLayers doens't do painter's order, instead we extend
var symbolizer = rule.symbolizer["Text"] || {};
this.readChildNodes(node, symbolizer);
// in case it didn't exist before
rule.symbolizer["Text"] = symbolizer;
var config = {};
this.readChildNodes(node, config);
if (this.multipleSymbolizers) {
config.zIndex = this.featureTypeCounter;
rule.symbolizers.push(
new OpenLayers.Symbolizer.Text(config)
);
} else {
rule.symbolizer["Text"] = OpenLayers.Util.applyDefaults(
config, rule.symbolizer["Text"]
);
}
},
"Label": function(node, symbolizer) {
// only supporting literal or property name
@@ -211,11 +249,18 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
}
},
"RasterSymbolizer": function(node, rule) {
// OpenLayers doesn't do painter's order, instead we extend
var symbolizer = rule.symbolizer["Raster"] || {};
this.readChildNodes(node, symbolizer);
// in case it didn't exist before
rule.symbolizer["Raster"] = symbolizer;
var config = {};
this.readChildNodes(node, config);
if (this.multipleSymbolizers) {
config.zIndex = this.featureTypeCounter;
rule.symbolizers.push(
new OpenLayers.Symbolizer.Raster(config)
);
} else {
rule.symbolizer["Raster"] = OpenLayers.Util.applyDefaults(
config, rule.symbolizer["Raster"]
);
}
},
"Geometry": function(node, obj) {
obj.geometry = {};
@@ -236,32 +281,55 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
});
},
"LineSymbolizer": function(node, rule) {
// OpenLayers doesn't do painter's order, instead we extend
var symbolizer = rule.symbolizer["Line"] || {};
this.readChildNodes(node, symbolizer);
// in case it didn't exist before
rule.symbolizer["Line"] = symbolizer;
var config = {};
this.readChildNodes(node, config);
if (this.multipleSymbolizers) {
config.zIndex = this.featureTypeCounter;
rule.symbolizers.push(
new OpenLayers.Symbolizer.Line(config)
);
} else {
rule.symbolizer["Line"] = OpenLayers.Util.applyDefaults(
config, rule.symbolizer["Line"]
);
}
},
"PolygonSymbolizer": function(node, rule) {
// OpenLayers doens't do painter's order, instead we extend
var symbolizer = rule.symbolizer["Polygon"] || {
var config = {
fill: false,
stroke: false
};
this.readChildNodes(node, symbolizer);
// in case it didn't exist before
rule.symbolizer["Polygon"] = symbolizer;
if (!this.multipleSymbolizers) {
config = rule.symbolizer["Polygon"] || config;
}
this.readChildNodes(node, config);
if (this.multipleSymbolizers) {
config.zIndex = this.featureTypeCounter;
rule.symbolizers.push(
new OpenLayers.Symbolizer.Polygon(config)
);
} else {
rule.symbolizer["Polygon"] = config;
}
},
"PointSymbolizer": function(node, rule) {
// OpenLayers doens't do painter's order, instead we extend
var symbolizer = rule.symbolizer["Point"] || {
var config = {
fill: false,
stroke: false,
graphic: false
};
this.readChildNodes(node, symbolizer);
// in case it didn't exist before
rule.symbolizer["Point"] = symbolizer;
if (!this.multipleSymbolizers) {
config = rule.symbolizer["Point"] || config;
}
this.readChildNodes(node, config);
if (this.multipleSymbolizers) {
config.zIndex = this.featureTypeCounter;
rule.symbolizers.push(
new OpenLayers.Symbolizer.Point(config)
);
} else {
rule.symbolizer["Point"] = config;
}
},
"Stroke": function(node, symbolizer) {
symbolizer.stroke = true;
@@ -566,7 +634,53 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
}
// add FeatureTypeStyles
this.writeNode("FeatureTypeStyle", style, node);
if (this.multipleSymbolizers && style.rules) {
// group style objects by symbolizer zIndex
var rulesByZ = {
0: []
};
var zValues = [0];
var rule, ruleMap, symbolizer, zIndex, clone;
for (var i=0, ii=style.rules.length; i<ii; ++i) {
rule = style.rules[i];
if (rule.symbolizers) {
ruleMap = {};
for (var j=0, jj=rule.symbolizers.length; j<jj; ++j) {
symbolizer = rule.symbolizers[j];
zIndex = symbolizer.zIndex;
if (!(zIndex in ruleMap)) {
clone = rule.clone();
clone.symbolizers = [];
ruleMap[zIndex] = clone;
}
ruleMap[zIndex].symbolizers.push(symbolizer.clone());
}
for (zIndex in ruleMap) {
if (!(zIndex in rulesByZ)) {
zValues.push(zIndex);
rulesByZ[zIndex] = [];
}
rulesByZ[zIndex].push(ruleMap[zIndex]);
}
} else {
// no symbolizers in rule
rulesByZ[0].push(rule.clone());
}
}
// write one FeatureTypeStyle per zIndex
zValues.sort();
var rules;
for (var i=0, ii=zValues.length; i<ii; ++i) {
rules = rulesByZ[zValues[i]];
if (rules.length > 0) {
clone = style.clone();
clone.rules = rulesByZ[zValues[i]];
this.writeNode("FeatureTypeStyle", clone, node);
}
}
} else {
this.writeNode("FeatureTypeStyle", style, node);
}
return node;
},
@@ -626,17 +740,28 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
);
}
// add in symbolizers (relies on geometry type keys)
var types = OpenLayers.Style.SYMBOLIZER_PREFIXES;
var type, symbolizer;
for(var i=0, len=types.length; i<len; ++i) {
type = types[i];
symbolizer = rule.symbolizer[type];
if(symbolizer) {
if (this.multipleSymbolizers && rule.symbolizers) {
var symbolizer;
for (var i=0, ii=rule.symbolizers.length; i<ii; ++i) {
symbolizer = rule.symbolizers[i];
type = symbolizer.CLASS_NAME.split(".").pop();
this.writeNode(
type + "Symbolizer", symbolizer, node
);
}
} else {
// add in symbolizers (relies on geometry type keys)
var types = OpenLayers.Style.SYMBOLIZER_PREFIXES;
for(var i=0, len=types.length; i<len; ++i) {
type = types[i];
symbolizer = rule.symbolizer[type];
if(symbolizer) {
this.writeNode(
type + "Symbolizer", symbolizer, node
);
}
}
}
return node;
@@ -925,8 +1050,12 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
if(symbolizer.graphicName) {
this.writeNode("WellKnownName", symbolizer.graphicName, node);
}
this.writeNode("Fill", symbolizer, node);
this.writeNode("Stroke", symbolizer, node);
if (symbolizer.fill !== false) {
this.writeNode("Fill", symbolizer, node);
}
if (symbolizer.stroke !== false) {
this.writeNode("Stroke", symbolizer, node);
}
return node;
},
"WellKnownName": function(name) {
@@ -967,4 +1096,4 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, {
CLASS_NAME: "OpenLayers.Format.SLD.v1"
});
});