910 lines
32 KiB
JavaScript
910 lines
32 KiB
JavaScript
goog.provide('ol.parser.ogc.SLD_v1');
|
|
goog.require('goog.asserts');
|
|
goog.require('goog.dom.xml');
|
|
goog.require('goog.object');
|
|
goog.require('ol.expr.Literal');
|
|
goog.require('ol.parser.XML');
|
|
goog.require('ol.parser.ogc.Filter_v1_0_0');
|
|
goog.require('ol.style.Fill');
|
|
goog.require('ol.style.Icon');
|
|
goog.require('ol.style.Rule');
|
|
goog.require('ol.style.Shape');
|
|
goog.require('ol.style.Stroke');
|
|
goog.require('ol.style.Style');
|
|
goog.require('ol.style.Text');
|
|
|
|
|
|
|
|
/**
|
|
* Read Styled Layer Descriptor (SLD).
|
|
*
|
|
* @constructor
|
|
* @extends {ol.parser.XML}
|
|
*/
|
|
ol.parser.ogc.SLD_v1 = function() {
|
|
this.defaultNamespaceURI = 'http://www.opengis.net/sld';
|
|
this.readers = {
|
|
'http://www.opengis.net/sld': {
|
|
'StyledLayerDescriptor': function(node, sld) {
|
|
sld.version = node.getAttribute('version');
|
|
this.readChildNodes(node, sld);
|
|
},
|
|
'Name': function(node, obj) {
|
|
obj.name = this.getChildValue(node);
|
|
},
|
|
'Title': function(node, obj) {
|
|
obj.title = this.getChildValue(node);
|
|
},
|
|
'Abstract': function(node, obj) {
|
|
obj.description = this.getChildValue(node);
|
|
},
|
|
'NamedLayer': function(node, sld) {
|
|
var layer = {
|
|
userStyles: [],
|
|
namedStyles: []
|
|
};
|
|
this.readChildNodes(node, layer);
|
|
sld.namedLayers[layer.name] = layer;
|
|
},
|
|
'NamedStyle': function(node, layer) {
|
|
layer.namedStyles.push(
|
|
this.getChildValue(node.firstChild)
|
|
);
|
|
},
|
|
'UserStyle': function(node, layer) {
|
|
var obj = {rules: []};
|
|
this.featureTypeCounter = -1;
|
|
this.readChildNodes(node, obj);
|
|
layer.userStyles.push(new ol.style.Style(obj));
|
|
},
|
|
'IsDefault': function(node, style) {
|
|
if (this.getChildValue(node) === '1') {
|
|
style.isDefault = true;
|
|
}
|
|
},
|
|
'FeatureTypeStyle': function(node, style) {
|
|
++this.featureTypeCounter;
|
|
var obj = {
|
|
rules: style.rules
|
|
};
|
|
this.readChildNodes(node, obj);
|
|
},
|
|
'Rule': function(node, obj) {
|
|
var config = {symbolizers: []};
|
|
this.readChildNodes(node, config);
|
|
var rule = new ol.style.Rule(config);
|
|
obj.rules.push(rule);
|
|
},
|
|
'ElseFilter': function(node, rule) {
|
|
rule.elseFilter = true;
|
|
},
|
|
'MinScaleDenominator': function(node, rule) {
|
|
rule.minResolution = this.getResolutionFromScaleDenominator_(
|
|
parseFloat(this.getChildValue(node)));
|
|
},
|
|
'MaxScaleDenominator': function(node, rule) {
|
|
rule.maxResolution = this.getResolutionFromScaleDenominator_(
|
|
parseFloat(this.getChildValue(node)));
|
|
},
|
|
'TextSymbolizer': function(node, rule) {
|
|
var config = {};
|
|
this.readChildNodes(node, config);
|
|
config.color = config.fill.fillColor;
|
|
delete config.fill;
|
|
config.zIndex = this.featureTypeCounter;
|
|
rule.symbolizers.push(
|
|
new ol.style.Text(/** @type {ol.style.TextOptions} */(config))
|
|
);
|
|
},
|
|
'LabelPlacement': function(node, symbolizer) {
|
|
this.readChildNodes(node, symbolizer);
|
|
},
|
|
'PointPlacement': function(node, symbolizer) {
|
|
var config = {};
|
|
this.readChildNodes(node, config);
|
|
config.labelRotation = config.rotation;
|
|
delete config.rotation;
|
|
var labelAlign,
|
|
x = symbolizer.labelAnchorPointX,
|
|
y = symbolizer.labelAnchorPointY;
|
|
if (x <= 1 / 3) {
|
|
labelAlign = 'l';
|
|
} else if (x > 1 / 3 && x < 2 / 3) {
|
|
labelAlign = 'c';
|
|
} else if (x >= 2 / 3) {
|
|
labelAlign = 'r';
|
|
}
|
|
if (y <= 1 / 3) {
|
|
labelAlign += 'b';
|
|
} else if (y > 1 / 3 && y < 2 / 3) {
|
|
labelAlign += 'm';
|
|
} else if (y >= 2 / 3) {
|
|
labelAlign += 't';
|
|
}
|
|
config.labelAlign = labelAlign;
|
|
goog.object.extend(symbolizer, config);
|
|
},
|
|
'AnchorPoint': function(node, symbolizer) {
|
|
this.readChildNodes(node, symbolizer);
|
|
},
|
|
'AnchorPointX': function(node, symbolizer) {
|
|
var ogcreaders = this.readers['http://www.opengis.net/ogc'];
|
|
var labelAnchorPointX = ogcreaders._expression.call(this, node);
|
|
// always string, could be empty string
|
|
if (labelAnchorPointX) {
|
|
symbolizer.labelAnchorPointX = labelAnchorPointX;
|
|
}
|
|
},
|
|
'AnchorPointY': function(node, symbolizer) {
|
|
var ogcreaders = this.readers['http://www.opengis.net/ogc'];
|
|
var labelAnchorPointY = ogcreaders._expression.call(this, node);
|
|
// always string, could be empty string
|
|
if (labelAnchorPointY) {
|
|
symbolizer.labelAnchorPointY = labelAnchorPointY;
|
|
}
|
|
},
|
|
'Displacement': function(node, symbolizer) {
|
|
this.readChildNodes(node, symbolizer);
|
|
},
|
|
'DisplacementX': function(node, symbolizer) {
|
|
var ogcreaders = this.readers['http://www.opengis.net/ogc'];
|
|
var labelXOffset = ogcreaders._expression.call(this, node);
|
|
// always string, could be empty string
|
|
if (labelXOffset) {
|
|
symbolizer.labelXOffset = labelXOffset;
|
|
}
|
|
},
|
|
'DisplacementY': function(node, symbolizer) {
|
|
var ogcreaders = this.readers['http://www.opengis.net/ogc'];
|
|
var labelYOffset = ogcreaders._expression.call(this, node);
|
|
// always string, could be empty string
|
|
if (labelYOffset) {
|
|
symbolizer.labelYOffset = labelYOffset;
|
|
}
|
|
},
|
|
'LinePlacement': function(node, symbolizer) {
|
|
this.readChildNodes(node, symbolizer);
|
|
},
|
|
'PerpendicularOffset': function(node, symbolizer) {
|
|
var ogcreaders = this.readers['http://www.opengis.net/ogc'];
|
|
var labelPerpendicularOffset = ogcreaders._expression.call(this, node);
|
|
// always string, could be empty string
|
|
if (labelPerpendicularOffset) {
|
|
symbolizer.labelPerpendicularOffset = labelPerpendicularOffset;
|
|
}
|
|
},
|
|
'Label': function(node, symbolizer) {
|
|
var ogcreaders = this.readers['http://www.opengis.net/ogc'];
|
|
var value = ogcreaders._expression.call(this, node);
|
|
if (value) {
|
|
symbolizer.text = value;
|
|
}
|
|
},
|
|
'Font': function(node, symbolizer) {
|
|
this.readChildNodes(node, symbolizer);
|
|
},
|
|
'Halo': function(node, symbolizer) {
|
|
var obj = {};
|
|
this.readChildNodes(node, obj);
|
|
symbolizer.stroke = new ol.style.Stroke({
|
|
color: goog.isDef(obj.fill.fillColor) ? obj.fill.fillColor :
|
|
ol.parser.ogc.SLD_v1.defaults_.haloColor,
|
|
width: goog.isDef(obj.haloRadius) ? obj.haloRadius * 2 :
|
|
ol.parser.ogc.SLD_v1.defaults_.haloRadius,
|
|
opacity: goog.isDef(obj.fill.fillOpacity) ? obj.fill.fillOpacity :
|
|
ol.parser.ogc.SLD_v1.defaults_.haloOpacity
|
|
});
|
|
},
|
|
'Radius': function(node, symbolizer) {
|
|
var ogcreaders = this.readers['http://www.opengis.net/ogc'];
|
|
var radius = ogcreaders._expression.call(this, node);
|
|
goog.asserts.assertInstanceof(radius, ol.expr.Literal,
|
|
'radius expected to be an ol.expr.Literal');
|
|
if (goog.isDef(radius)) {
|
|
symbolizer.haloRadius = radius.getValue();
|
|
}
|
|
},
|
|
'RasterSymbolizer': function(node, rule) {
|
|
var config = {};
|
|
this.readChildNodes(node, config);
|
|
config.zIndex = this.featureTypeCounter;
|
|
/* TODO
|
|
rule.symbolizers.push(
|
|
new OpenLayers.Symbolizer.Raster(config)
|
|
);
|
|
*/
|
|
},
|
|
'Geometry': function(node, obj) {
|
|
obj.geometry = {};
|
|
this.readChildNodes(node, obj.geometry);
|
|
},
|
|
'ColorMap': function(node, symbolizer) {
|
|
symbolizer.colorMap = [];
|
|
this.readChildNodes(node, symbolizer.colorMap);
|
|
},
|
|
'ColorMapEntry': function(node, colorMap) {
|
|
var q = node.getAttribute('quantity');
|
|
var o = node.getAttribute('opacity');
|
|
colorMap.push({
|
|
color: node.getAttribute('color'),
|
|
quantity: q !== null ? parseFloat(q) : undefined,
|
|
label: node.getAttribute('label') || undefined,
|
|
opacity: o !== null ? parseFloat(o) : undefined
|
|
});
|
|
},
|
|
'LineSymbolizer': function(node, rule) {
|
|
var config = {};
|
|
this.readChildNodes(node, config);
|
|
config.zIndex = this.featureTypeCounter;
|
|
rule.symbolizers.push(
|
|
new ol.style.Stroke(config)
|
|
);
|
|
},
|
|
'PolygonSymbolizer': function(node, rule) {
|
|
var config = {};
|
|
this.readChildNodes(node, config);
|
|
config.zIndex = this.featureTypeCounter;
|
|
if (goog.isDef(config.fill)) {
|
|
var fill = {
|
|
color: config.fill.fillColor.getValue(),
|
|
opacity: goog.isDef(config.fill.fillOpacity) ?
|
|
config.fill.fillOpacity :
|
|
ol.parser.ogc.SLD_v1.defaults_.fillOpacity
|
|
};
|
|
rule.symbolizers.push(
|
|
new ol.style.Fill(fill)
|
|
);
|
|
delete config.fill;
|
|
}
|
|
if (goog.isDef(config.stroke)) {
|
|
var stroke = {
|
|
color: config.stroke.strokeColor.getValue(),
|
|
opacity: goog.isDef(config.stroke.strokeOpacity) ?
|
|
config.stroke.strokeOpacity :
|
|
ol.parser.ogc.SLD_v1.defaults_.strokeOpacity,
|
|
width: goog.isDef(config.stroke.strokeWidth) ?
|
|
config.stroke.strokeWidth :
|
|
ol.parser.ogc.SLD_v1.defaults_.strokeWidth
|
|
};
|
|
rule.symbolizers.push(
|
|
new ol.style.Stroke(stroke)
|
|
);
|
|
delete config.stroke;
|
|
}
|
|
|
|
},
|
|
'PointSymbolizer': function(node, rule) {
|
|
var config = {};
|
|
this.readChildNodes(node, config);
|
|
config.zIndex = this.featureTypeCounter;
|
|
if (config.fill) {
|
|
config.fill = new ol.style.Fill(config.fill);
|
|
}
|
|
if (config.stroke) {
|
|
config.stroke = new ol.style.Stroke(config.stroke);
|
|
}
|
|
// TODO shape or icon?
|
|
rule.symbolizers.push(
|
|
new ol.style.Shape(config)
|
|
);
|
|
},
|
|
'Stroke': function(node, symbolizer) {
|
|
var stroke = {};
|
|
this.readChildNodes(node, stroke);
|
|
symbolizer.stroke = stroke;
|
|
},
|
|
'Fill': function(node, symbolizer) {
|
|
var fill = {};
|
|
this.readChildNodes(node, fill);
|
|
symbolizer.fill = fill;
|
|
},
|
|
'CssParameter': function(node, symbolizer) {
|
|
var cssProperty = node.getAttribute('name');
|
|
var symProperty = ol.parser.ogc.SLD_v1.cssMap_[cssProperty];
|
|
// for labels, fill should map to fontColor and fill-opacity
|
|
// to fontOpacity
|
|
if (symbolizer.label) {
|
|
if (cssProperty === 'fill') {
|
|
symProperty = 'fontColor';
|
|
} else if (cssProperty === 'fill-opacity') {
|
|
symProperty = 'fontOpacity';
|
|
}
|
|
}
|
|
if (symProperty) {
|
|
// Limited support for parsing of OGC expressions
|
|
var ogcreaders = this.readers['http://www.opengis.net/ogc'];
|
|
var value = ogcreaders._expression.call(this, node);
|
|
// always string, could be an empty string
|
|
if (value) {
|
|
symbolizer[symProperty] = value;
|
|
}
|
|
}
|
|
},
|
|
'Graphic': function(node, symbolizer) {
|
|
symbolizer.graphic = true;
|
|
var graphic = {};
|
|
// painter's order not respected here, clobber previous with next
|
|
this.readChildNodes(node, graphic);
|
|
// directly properties with names that match symbolizer properties
|
|
var properties = [
|
|
'stroke', 'strokeColor', 'strokeWidth', 'strokeOpacity',
|
|
'strokeLinecap', 'fill', 'fillColor', 'fillOpacity',
|
|
'graphicName', 'rotation', 'graphicFormat'
|
|
];
|
|
var prop, value;
|
|
for (var i = 0, ii = properties.length; i < ii; ++i) {
|
|
prop = properties[i];
|
|
value = graphic[prop];
|
|
if (goog.isDef(value)) {
|
|
symbolizer[prop] = value;
|
|
}
|
|
}
|
|
// set other generic properties with specific graphic property names
|
|
if (goog.isDef(graphic.opacity)) {
|
|
symbolizer.graphicOpacity = graphic.opacity;
|
|
}
|
|
if (goog.isDef(graphic.size)) {
|
|
var pointRadius = graphic.size / 2;
|
|
if (isNaN(pointRadius)) {
|
|
// likely a property name
|
|
symbolizer.graphicWidth = graphic.size;
|
|
} else {
|
|
symbolizer.pointRadius = graphic.size / 2;
|
|
}
|
|
}
|
|
if (goog.isDef(graphic.href)) {
|
|
symbolizer.externalGraphic = graphic.href;
|
|
}
|
|
if (goog.isDef(graphic.rotation)) {
|
|
symbolizer.rotation = graphic.rotation;
|
|
}
|
|
},
|
|
'ExternalGraphic': function(node, graphic) {
|
|
this.readChildNodes(node, graphic);
|
|
},
|
|
'Mark': function(node, graphic) {
|
|
this.readChildNodes(node, graphic);
|
|
},
|
|
'WellKnownName': function(node, graphic) {
|
|
graphic.graphicName = this.getChildValue(node);
|
|
},
|
|
'Opacity': function(node, obj) {
|
|
var ogcreaders = this.readers['http://www.opengis.net/ogc'];
|
|
var opacity = ogcreaders._expression.call(this, node);
|
|
// always string, could be empty string
|
|
if (opacity) {
|
|
obj.opacity = opacity;
|
|
}
|
|
},
|
|
'Size': function(node, obj) {
|
|
var ogcreaders = this.readers['http://www.opengis.net/ogc'];
|
|
var size = ogcreaders._expression.call(this, node);
|
|
// always string, could be empty string
|
|
if (size) {
|
|
obj.size = size;
|
|
}
|
|
},
|
|
'Rotation': function(node, obj) {
|
|
var ogcreaders = this.readers['http://www.opengis.net/ogc'];
|
|
var rotation = ogcreaders._expression.call(this, node);
|
|
// always string, could be empty string
|
|
if (rotation) {
|
|
obj.rotation = rotation;
|
|
}
|
|
},
|
|
'OnlineResource': function(node, obj) {
|
|
obj.href = this.getAttributeNS(
|
|
node, 'http://www.w3.org/1999/xlink', 'href'
|
|
);
|
|
},
|
|
'Format': function(node, graphic) {
|
|
graphic.graphicFormat = this.getChildValue(node);
|
|
}
|
|
}
|
|
};
|
|
this.writers = {
|
|
'http://www.opengis.net/sld': {
|
|
'StyledLayerDescriptor': function(sld) {
|
|
var node = this.createElementNS('sld:StyledLayerDescriptor');
|
|
node.setAttribute('version', this.version);
|
|
if (goog.isDef(sld.name)) {
|
|
this.writeNode('Name', sld.name, null, node);
|
|
}
|
|
if (goog.isDef(sld.title)) {
|
|
this.writeNode('Title', sld.title, null, node);
|
|
}
|
|
if (goog.isDef(sld.description)) {
|
|
this.writeNode('Abstract', sld.description, null, node);
|
|
}
|
|
goog.object.forEach(sld.namedLayers, function(layer) {
|
|
this.writeNode('NamedLayer', layer, null, node);
|
|
}, this);
|
|
return node;
|
|
},
|
|
'Name': function(name) {
|
|
var node = this.createElementNS('sld:Name');
|
|
node.appendChild(this.createTextNode(name));
|
|
return node;
|
|
},
|
|
'Title': function(title) {
|
|
var node = this.createElementNS('sld:Title');
|
|
node.appendChild(this.createTextNode(title));
|
|
return node;
|
|
},
|
|
'Abstract': function(description) {
|
|
var node = this.createElementNS('sld:Abstract');
|
|
node.appendChild(this.createTextNode(description));
|
|
return node;
|
|
},
|
|
'NamedLayer': function(layer) {
|
|
var node = this.createElementNS('sld:NamedLayer');
|
|
this.writeNode('Name', layer.name, null, node);
|
|
var i, ii;
|
|
if (layer.namedStyles) {
|
|
for (i = 0, ii = layer.namedStyles.length; i < ii; ++i) {
|
|
this.writeNode('NamedStyle', layer.namedStyles[i], null, node);
|
|
}
|
|
}
|
|
if (layer.userStyles) {
|
|
for (i = 0, ii = layer.userStyles.length; i < ii; ++i) {
|
|
this.writeNode('UserStyle', layer.userStyles[i], null, node);
|
|
}
|
|
}
|
|
return node;
|
|
},
|
|
'NamedStyle': function(name) {
|
|
var node = this.createElementNS('sld:NamedStyle');
|
|
this.writeNode('Name', name, null, node);
|
|
return node;
|
|
},
|
|
'UserStyle': function(style) {
|
|
var node = this.createElementNS('sld:UserStyle');
|
|
if (style.name) {
|
|
this.writeNode('Name', style.name, null, node);
|
|
}
|
|
if (style.title) {
|
|
this.writeNode('Title', style.title, null, node);
|
|
}
|
|
if (style.description) {
|
|
this.writeNode('Abstract', style.description, null, node);
|
|
}
|
|
if (style.isDefault) {
|
|
this.writeNode('IsDefault', style.isDefault, null, node);
|
|
}
|
|
if (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];
|
|
var symbolizers = rule.getSymbolizers();
|
|
if (symbolizers) {
|
|
ruleMap = {};
|
|
for (var j = 0, jj = symbolizers.length; j < jj; ++j) {
|
|
symbolizer = symbolizers[j];
|
|
zIndex = symbolizer.zIndex;
|
|
if (!(zIndex in ruleMap)) {
|
|
// TODO check if clone works?
|
|
clone = goog.object.clone(rule);
|
|
clone.setSymbolizers([]);
|
|
ruleMap[zIndex] = clone;
|
|
}
|
|
// TODO check if clone works
|
|
ruleMap[zIndex].getSymbolizers().push(
|
|
goog.object.clone(symbolizer));
|
|
}
|
|
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(goog.object.clone(rule));
|
|
}
|
|
}
|
|
// 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 = goog.object.clone(style);
|
|
clone.setRules(rulesByZ[zValues[i]]);
|
|
this.writeNode('FeatureTypeStyle', clone, null, node);
|
|
}
|
|
}
|
|
} else {
|
|
this.writeNode('FeatureTypeStyle', style, null, node);
|
|
}
|
|
return node;
|
|
},
|
|
'IsDefault': function(bool) {
|
|
var node = this.createElementNS('sld:IsDefault');
|
|
node.appendChild(this.createTextNode((bool) ? '1' : '0'));
|
|
return node;
|
|
},
|
|
'FeatureTypeStyle': function(style) {
|
|
var node = this.createElementNS('sld:FeatureTypeStyle');
|
|
// OpenLayers currently stores no Name, Title, Abstract,
|
|
// FeatureTypeName, or SemanticTypeIdentifier information
|
|
// related to FeatureTypeStyle
|
|
// add in rules
|
|
var rules = style.getRules();
|
|
for (var i = 0, ii = rules.length; i < ii; ++i) {
|
|
this.writeNode('Rule', rules[i], null, node);
|
|
}
|
|
return node;
|
|
},
|
|
'Rule': function(rule) {
|
|
var node = this.createElementNS('sld:Rule');
|
|
var filter = rule.getFilter();
|
|
if (!goog.isNull(rule.getName())) {
|
|
this.writeNode('Name', rule.getName(), null, node);
|
|
}
|
|
if (!goog.isNull(rule.getTitle())) {
|
|
this.writeNode('Title', rule.title, null, node);
|
|
}
|
|
if (rule.elseFilter) {
|
|
this.writeNode('ElseFilter', null, null, node);
|
|
} else if (filter) {
|
|
this.writeNode('Filter', filter, 'http://www.opengis.net/ogc', node);
|
|
}
|
|
var minResolution = rule.getMinResolution();
|
|
if (minResolution > 0) {
|
|
this.writeNode('MinScaleDenominator',
|
|
this.getScaleDenominatorFromResolution_(minResolution),
|
|
null, node);
|
|
}
|
|
var maxResolution = rule.getMaxResolution();
|
|
if (maxResolution < Infinity) {
|
|
this.writeNode('MaxScaleDenominator',
|
|
this.getScaleDenominatorFromResolution_(maxResolution),
|
|
null, node);
|
|
}
|
|
var type, symbolizer, symbolizers = rule.getSymbolizers();
|
|
if (symbolizers) {
|
|
for (var i = 0, ii = symbolizers.length; i < ii; ++i) {
|
|
symbolizer = symbolizers[i];
|
|
// TODO other types of symbolizers
|
|
if (symbolizer instanceof ol.style.Text) {
|
|
type = 'Text';
|
|
} else if (symbolizer instanceof ol.style.Stroke) {
|
|
type = 'Line';
|
|
} else if (symbolizer instanceof ol.style.Fill) {
|
|
type = 'Polygon';
|
|
} else if (symbolizer instanceof ol.style.Shape ||
|
|
symbolizer instanceof ol.style.Icon) {
|
|
type = 'Point';
|
|
}
|
|
if (goog.isDef(type)) {
|
|
this.writeNode(type + 'Symbolizer', symbolizer, null, node);
|
|
}
|
|
}
|
|
}
|
|
return node;
|
|
},
|
|
'PointSymbolizer': function(symbolizer) {
|
|
var node = this.createElementNS('sld:PointSymbolizer');
|
|
this.writeNode('Graphic', symbolizer, null, node);
|
|
return node;
|
|
},
|
|
'Mark': function(symbolizer) {
|
|
var node = this.createElementNS('sld:Mark');
|
|
this.writeNode('WellKnownName', symbolizer.getType(), null, node);
|
|
var fill = symbolizer.getFill();
|
|
if (!goog.isNull(fill)) {
|
|
this.writeNode('Fill', fill, null, node);
|
|
}
|
|
var stroke = symbolizer.getStroke();
|
|
if (!goog.isNull(stroke)) {
|
|
this.writeNode('Stroke', stroke, null, node);
|
|
}
|
|
return node;
|
|
},
|
|
'WellKnownName': function(name) {
|
|
var node = this.createElementNS('sld:WellKnownName');
|
|
node.appendChild(this.createTextNode(name));
|
|
return node;
|
|
},
|
|
'Graphic': function(symbolizer) {
|
|
var node = this.createElementNS('sld:Graphic');
|
|
var size;
|
|
if (symbolizer instanceof ol.style.Icon) {
|
|
this.writeNode('ExternalGraphic', symbolizer, null, node);
|
|
var opacity = symbolizer.getOpacity();
|
|
goog.asserts.assertInstanceof(opacity, ol.expr.Literal,
|
|
'Only ol.expr.Literal supported for graphicOpacity');
|
|
this.writeNode('Opacity', opacity.getValue(), null, node);
|
|
size = symbolizer.getWidth();
|
|
} else if (symbolizer instanceof ol.style.Shape) {
|
|
this.writeNode('Mark', symbolizer, null, node);
|
|
size = symbolizer.getSize();
|
|
}
|
|
goog.asserts.assertInstanceof(size, ol.expr.Literal,
|
|
'Only ol.expr.Literal supported for in Size');
|
|
this.writeNode('Size', size.getValue(), null, node);
|
|
if (symbolizer instanceof ol.style.Icon) {
|
|
var rotation = symbolizer.getRotation();
|
|
goog.asserts.assertInstanceof(rotation, ol.expr.Literal,
|
|
'Only ol.expr.Literal supported for rotation');
|
|
this.writeNode('Rotation', rotation.getValue(), null, node);
|
|
}
|
|
return node;
|
|
},
|
|
'PolygonSymbolizer': function(symbolizer) {
|
|
var node = this.createElementNS('sld:PolygonSymbolizer');
|
|
this.writeNode('Fill', symbolizer, null, node);
|
|
return node;
|
|
},
|
|
'Fill': function(symbolizer) {
|
|
var node = this.createElementNS('sld:Fill');
|
|
var fillColor = symbolizer.getColor();
|
|
var msg = 'Only ol.expr.Literal supported for Fill properties';
|
|
goog.asserts.assertInstanceof(fillColor, ol.expr.Literal, msg);
|
|
this.writeNode('CssParameter', {
|
|
value: fillColor.getValue(),
|
|
key: 'fillColor'
|
|
}, null, node);
|
|
var fillOpacity = symbolizer.getOpacity();
|
|
goog.asserts.assertInstanceof(fillOpacity, ol.expr.Literal, msg);
|
|
this.writeNode('CssParameter', {
|
|
value: fillOpacity.getValue(),
|
|
key: 'fillOpacity'
|
|
}, null, node);
|
|
return node;
|
|
},
|
|
'TextSymbolizer': function(symbolizer) {
|
|
var node = this.createElementNS('sld:TextSymbolizer');
|
|
var text = symbolizer.getText();
|
|
// TODO in SLD optional, but in ol3 required?
|
|
this.writeNode('Label', text, null, node);
|
|
// TODO in SLD optional, but in ol3 required?
|
|
this.writeNode('Font', symbolizer, null, node);
|
|
// TODO map align to labelAnchorPoint etc.
|
|
var stroke = symbolizer.getStroke();
|
|
if (!goog.isNull(stroke)) {
|
|
this.writeNode('Halo', stroke, null, node);
|
|
}
|
|
var color = symbolizer.getColor();
|
|
goog.asserts.assertInstanceof(color, ol.expr.Literal,
|
|
'font color should be ol.expr.Literal');
|
|
this.writeNode('Fill', symbolizer, null, node);
|
|
return node;
|
|
},
|
|
'Halo': function(symbolizer) {
|
|
var node = this.createElementNS('sld:Halo');
|
|
goog.asserts.assertInstanceof(symbolizer.getWidth(), ol.expr.Literal,
|
|
'Only ol.expr.Literal supported for haloRadius');
|
|
this.writeNode('Radius', symbolizer.getWidth().getValue() / 2, null,
|
|
node);
|
|
this.writeNode('Fill', symbolizer, null, node);
|
|
return node;
|
|
},
|
|
'Radius': function(value) {
|
|
var node = this.createElementNS('sld:Radius');
|
|
node.appendChild(this.createTextNode(value));
|
|
return node;
|
|
},
|
|
'LineSymbolizer': function(symbolizer) {
|
|
var node = this.createElementNS('sld:LineSymbolizer');
|
|
this.writeNode('Stroke', symbolizer, null, node);
|
|
return node;
|
|
},
|
|
'Stroke': function(symbolizer) {
|
|
var node = this.createElementNS('sld:Stroke');
|
|
var strokeColor = symbolizer.getColor();
|
|
var msg = 'SLD writing of stroke properties only supported ' +
|
|
'for ol.expr.Literal';
|
|
goog.asserts.assertInstanceof(strokeColor, ol.expr.Literal, msg);
|
|
this.writeNode('CssParameter', {
|
|
value: strokeColor.getValue(),
|
|
key: 'strokeColor'
|
|
}, null, node);
|
|
var strokeOpacity = symbolizer.getOpacity();
|
|
goog.asserts.assertInstanceof(strokeOpacity, ol.expr.Literal, msg);
|
|
this.writeNode('CssParameter', {
|
|
value: strokeOpacity.getValue(),
|
|
key: 'strokeOpacity'
|
|
}, null, node);
|
|
var strokeWidth = symbolizer.getWidth();
|
|
goog.asserts.assertInstanceof(strokeWidth, ol.expr.Literal, msg);
|
|
this.writeNode('CssParameter', {
|
|
value: strokeWidth.getValue(),
|
|
key: 'strokeWidth'
|
|
}, null, node);
|
|
// TODO strokeDashstyle and strokeLinecap
|
|
return node;
|
|
},
|
|
'CssParameter': function(obj) {
|
|
// not handling ogc:expressions for now
|
|
var name = ol.parser.ogc.SLD_v1.getCssProperty_(obj.key);
|
|
if (goog.isDef(name) && obj.value !==
|
|
ol.parser.ogc.SLD_v1.defaults_[obj.key]) {
|
|
var node = this.createElementNS('sld:CssParameter');
|
|
node.setAttribute('name', name);
|
|
node.appendChild(this.createTextNode(obj.value));
|
|
return node;
|
|
}
|
|
},
|
|
'Label': function(label) {
|
|
var node = this.createElementNS('sld:Label');
|
|
this.filter_.writeOgcExpression(label, node);
|
|
return node;
|
|
},
|
|
'Font': function(symbolizer) {
|
|
var node = this.createElementNS('sld:Font');
|
|
this.writeNode('CssParameter', {
|
|
key: 'fontFamily',
|
|
value: symbolizer.getFontFamily().getValue()
|
|
}, null, node);
|
|
this.writeNode('CssParameter', {
|
|
key: 'fontSize',
|
|
value: symbolizer.getFontSize().getValue()
|
|
}, null, node);
|
|
// TODO fontWeight and fontStyle
|
|
return node;
|
|
},
|
|
'MinScaleDenominator': function(scale) {
|
|
var node = this.createElementNS('sld:MinScaleDenominator');
|
|
node.appendChild(this.createTextNode(scale));
|
|
return node;
|
|
},
|
|
'MaxScaleDenominator': function(scale) {
|
|
var node = this.createElementNS('sld:MaxScaleDenominator');
|
|
node.appendChild(this.createTextNode(scale));
|
|
return node;
|
|
},
|
|
'Size': function(value) {
|
|
var node = this.createElementNS('sld:Size');
|
|
this.filter_.writeOgcExpression(value, node);
|
|
return node;
|
|
}
|
|
}
|
|
};
|
|
this.filter_ = new ol.parser.ogc.Filter_v1_0_0();
|
|
for (var uri in this.filter_.readers) {
|
|
for (var key in this.filter_.readers[uri]) {
|
|
if (!goog.isDef(this.readers[uri])) {
|
|
this.readers[uri] = {};
|
|
}
|
|
this.readers[uri][key] = goog.bind(this.filter_.readers[uri][key],
|
|
this.filter_);
|
|
}
|
|
}
|
|
for (var uri in this.filter_.writers) {
|
|
for (var key in this.filter_.writers[uri]) {
|
|
if (!goog.isDef(this.writers[uri])) {
|
|
this.writers[uri] = {};
|
|
}
|
|
this.writers[uri][key] = goog.bind(this.filter_.writers[uri][key],
|
|
this.filter_);
|
|
}
|
|
}
|
|
goog.base(this);
|
|
};
|
|
goog.inherits(ol.parser.ogc.SLD_v1, ol.parser.XML);
|
|
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
ol.parser.ogc.SLD_v1.cssMap_ = {
|
|
'stroke': 'strokeColor',
|
|
'stroke-opacity': 'strokeOpacity',
|
|
'stroke-width': 'strokeWidth',
|
|
'stroke-linecap': 'strokeLinecap',
|
|
'stroke-dasharray': 'strokeDashstyle',
|
|
'fill': 'fillColor',
|
|
'fill-opacity': 'fillOpacity',
|
|
'font-family': 'fontFamily',
|
|
'font-size': 'fontSize',
|
|
'font-weight': 'fontWeight',
|
|
'font-style': 'fontStyle'
|
|
};
|
|
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
ol.parser.ogc.SLD_v1.defaults_ = {
|
|
fillOpacity: 1,
|
|
strokeOpacity: 1,
|
|
strokeWidth: 1,
|
|
haloColor: '#FFFFFF',
|
|
haloOpacity: 1,
|
|
haloRadius: 1
|
|
};
|
|
|
|
|
|
/**
|
|
* @private
|
|
* @param {string} sym Symbolizer property.
|
|
* @return {string|undefined} The css property that matches the symbolizer
|
|
* property.
|
|
*/
|
|
ol.parser.ogc.SLD_v1.getCssProperty_ = function(sym) {
|
|
return goog.object.findKey(ol.parser.ogc.SLD_v1.cssMap_,
|
|
function(value, key, obj) {
|
|
return (sym === value);
|
|
}
|
|
);
|
|
};
|
|
|
|
|
|
/**
|
|
* @private
|
|
* @param {number} scaleDenominator The scale denominator to convert to
|
|
* resolution.
|
|
* @return {number} resolution.
|
|
*/
|
|
ol.parser.ogc.SLD_v1.prototype.getResolutionFromScaleDenominator_ =
|
|
function(scaleDenominator) {
|
|
var dpi = 25.4 / 0.28;
|
|
var mpu = ol.METERS_PER_UNIT[this.units];
|
|
return 1 / ((1 / scaleDenominator) * (mpu * 39.37) * dpi);
|
|
};
|
|
|
|
|
|
/**
|
|
* @private
|
|
* @param {number} resolution The resolution to convert to scale denominator.
|
|
* @return {number} scale denominator.
|
|
*/
|
|
ol.parser.ogc.SLD_v1.prototype.getScaleDenominatorFromResolution_ =
|
|
function(resolution) {
|
|
var dpi = 25.4 / 0.28;
|
|
var mpu = ol.METERS_PER_UNIT[this.units];
|
|
return resolution * mpu * 39.37 * dpi;
|
|
};
|
|
|
|
|
|
/**
|
|
* @param {string|Document|Element} data Data to read.
|
|
* @param {ol.parser.SLDReadOptions=} opt_options Read options.
|
|
* @return {Object} An object representing the document.
|
|
*/
|
|
ol.parser.ogc.SLD_v1.prototype.read = function(data, opt_options) {
|
|
var units = 'm';
|
|
if (goog.isDef(opt_options) && goog.isDef(opt_options.units)) {
|
|
units = opt_options.units;
|
|
}
|
|
this.units = units;
|
|
if (goog.isString(data)) {
|
|
data = goog.dom.xml.loadXml(data);
|
|
}
|
|
if (data && data.nodeType == 9) {
|
|
data = data.documentElement;
|
|
}
|
|
var obj = {namedLayers: {}};
|
|
this.readNode(data, obj);
|
|
delete this.units;
|
|
return obj;
|
|
};
|
|
|
|
|
|
/**
|
|
* @param {Object} style The style to write out.
|
|
* @param {ol.parser.SLDWriteOptions=} opt_options Write options.
|
|
* @return {string} The serialized SLD.
|
|
*/
|
|
ol.parser.ogc.SLD_v1.prototype.write = function(style, opt_options) {
|
|
var units = 'm';
|
|
if (goog.isDef(opt_options) && goog.isDef(opt_options.units)) {
|
|
units = opt_options.units;
|
|
}
|
|
this.units = units;
|
|
var root = this.writeNode('StyledLayerDescriptor', style);
|
|
this.setAttributeNS(
|
|
root, 'http://www.w3.org/2001/XMLSchema-instance',
|
|
'xsi:schemaLocation', this.schemaLocation);
|
|
var result = this.serialize(root);
|
|
delete this.units;
|
|
return result;
|
|
};
|