From 2aa7f2292622bcd7c2496d39c0ace30c31eb7b9b Mon Sep 17 00:00:00 2001 From: ahocevar Date: Mon, 13 Apr 2009 13:35:13 +0000 Subject: [PATCH] * added stroke, fill and graphic symbolizer properties (all boolean) to control whether or not to render a stroke, fill and graphic. * added a defaultsPerSymbolizer property to OpenLayers.Style to allow for extending incomplete symbolizers with defaults for stroke, fill or graphic. This also makes Format.SLD read/write round trips possible without modifying empty or incomplete , and constructs. r=tschaub (closes #1876) git-svn-id: http://svn.openlayers.org/trunk/openlayers@9278 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf --- examples/symbolizers-fill-stroke-graphic.html | 122 ++++++++++++++++++ lib/OpenLayers/Format/SLD/v1.js | 5 +- lib/OpenLayers/Renderer/Canvas.js | 94 ++++++++------ lib/OpenLayers/Renderer/Elements.js | 12 +- lib/OpenLayers/Renderer/SVG.js | 5 +- lib/OpenLayers/Style.js | 49 ++++++- tests/Style.html | 85 ++++++++++++ 7 files changed, 327 insertions(+), 45 deletions(-) create mode 100644 examples/symbolizers-fill-stroke-graphic.html diff --git a/examples/symbolizers-fill-stroke-graphic.html b/examples/symbolizers-fill-stroke-graphic.html new file mode 100644 index 0000000000..387ac2e313 --- /dev/null +++ b/examples/symbolizers-fill-stroke-graphic.html @@ -0,0 +1,122 @@ + + + OpenLayers Fill, Stroke, and Graphic Example + + + + + + +

OpenLayers Example

+
+

+ Demonstrate fill, stroke, and graphic property of symbolizers. +

+
+
+ This example shows how to use symbolizers with defaults for stroke, fill, and graphic. +
+ + diff --git a/lib/OpenLayers/Format/SLD/v1.js b/lib/OpenLayers/Format/SLD/v1.js index 9bfe6dcb91..29f546bdbc 100644 --- a/lib/OpenLayers/Format/SLD/v1.js +++ b/lib/OpenLayers/Format/SLD/v1.js @@ -137,7 +137,7 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { ); }, "UserStyle": function(node, layer) { - var obj = {rules: []}; + var obj = {defaultsPerSymbolizer: true, rules: []}; this.readChildNodes(node, obj); var style = new OpenLayers.Style(this.defaultSymbolizer, obj); layer.userStyles.push(style); @@ -232,9 +232,11 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { rule.symbolizer["Point"] = symbolizer; }, "Stroke": function(node, symbolizer) { + symbolizer.stroke = true; this.readChildNodes(node, symbolizer); }, "Fill": function(node, symbolizer) { + symbolizer.fill = true; this.readChildNodes(node, symbolizer); }, "CssParameter": function(node, symbolizer) { @@ -250,6 +252,7 @@ OpenLayers.Format.SLD.v1 = OpenLayers.Class(OpenLayers.Format.Filter.v1_0_0, { } }, "Graphic": function(node, symbolizer) { + symbolizer.graphic = true; var graphic = {}; // painter's order not respected here, clobber previous with next this.readChildNodes(node, graphic); diff --git a/lib/OpenLayers/Renderer/Canvas.js b/lib/OpenLayers/Renderer/Canvas.js index 9105feeb44..e59838883f 100644 --- a/lib/OpenLayers/Renderer/Canvas.js +++ b/lib/OpenLayers/Renderer/Canvas.js @@ -244,21 +244,27 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { * style - {Object} */ drawPoint: function(geometry, style) { - var pt = this.getLocalXY(geometry); - - if (style.externalGraphic) { - this.drawExternalGraphic(pt, style); - } else { - this.setCanvasStyle("fill", style); - this.canvas.beginPath(); - this.canvas.arc(pt[0], pt[1], 6, 0, Math.PI*2, true); - this.canvas.fill(); + if(style.graphic !== false) { + var pt = this.getLocalXY(geometry); - this.setCanvasStyle("stroke", style); - this.canvas.beginPath(); - this.canvas.arc(pt[0], pt[1], 6, 0, Math.PI*2, true); - this.canvas.stroke(); - this.setCanvasStyle("reset"); + if (style.externalGraphic) { + this.drawExternalGraphic(pt, style); + } else { + if(style.fill !== false) { + this.setCanvasStyle("fill", style); + this.canvas.beginPath(); + this.canvas.arc(pt[0], pt[1], 6, 0, Math.PI*2, true); + this.canvas.fill(); + } + + if(style.stroke !== false) { + this.setCanvasStyle("stroke", style); + this.canvas.beginPath(); + this.canvas.arc(pt[0], pt[1], 6, 0, Math.PI*2, true); + this.canvas.stroke(); + this.setCanvasStyle("reset"); + } + } } }, @@ -271,15 +277,17 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { * style - {Object} */ drawLineString: function(geometry, style) { - this.setCanvasStyle("stroke", style); - this.canvas.beginPath(); - var start = this.getLocalXY(geometry.components[0]); - this.canvas.moveTo(start[0], start[1]); - for(var i = 1; i < geometry.components.length; i++) { - var pt = this.getLocalXY(geometry.components[i]); - this.canvas.lineTo(pt[0], pt[1]); + if(style.stroke !== false) { + this.setCanvasStyle("stroke", style); + this.canvas.beginPath(); + var start = this.getLocalXY(geometry.components[0]); + this.canvas.moveTo(start[0], start[1]); + for(var i = 1; i < geometry.components.length; i++) { + var pt = this.getLocalXY(geometry.components[i]); + this.canvas.lineTo(pt[0], pt[1]); + } + this.canvas.stroke(); } - this.canvas.stroke(); this.setCanvasStyle("reset"); }, @@ -292,26 +300,30 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { * style - {Object} */ drawLinearRing: function(geometry, style) { - this.setCanvasStyle("fill", style); - this.canvas.beginPath(); - var start = this.getLocalXY(geometry.components[0]); - this.canvas.moveTo(start[0], start[1]); - for(var i = 1; i < geometry.components.length - 1 ; i++) { - var pt = this.getLocalXY(geometry.components[i]); - this.canvas.lineTo(pt[0], pt[1]); + if(style.fill !== false) { + this.setCanvasStyle("fill", style); + this.canvas.beginPath(); + var start = this.getLocalXY(geometry.components[0]); + this.canvas.moveTo(start[0], start[1]); + for(var i = 1; i < geometry.components.length - 1 ; i++) { + var pt = this.getLocalXY(geometry.components[i]); + this.canvas.lineTo(pt[0], pt[1]); + } + this.canvas.fill(); } - this.canvas.fill(); - var oldWidth = this.canvas.lineWidth; - this.setCanvasStyle("stroke", style); - this.canvas.beginPath(); - var start = this.getLocalXY(geometry.components[0]); - this.canvas.moveTo(start[0], start[1]); - for(var i = 1; i < geometry.components.length; i++) { - var pt = this.getLocalXY(geometry.components[i]); - this.canvas.lineTo(pt[0], pt[1]); + if(style.stroke !== false) { + var oldWidth = this.canvas.lineWidth; + this.setCanvasStyle("stroke", style); + this.canvas.beginPath(); + var start = this.getLocalXY(geometry.components[0]); + this.canvas.moveTo(start[0], start[1]); + for(var i = 1; i < geometry.components.length; i++) { + var pt = this.getLocalXY(geometry.components[i]); + this.canvas.lineTo(pt[0], pt[1]); + } + this.canvas.stroke(); } - this.canvas.stroke(); this.setCanvasStyle("reset"); }, @@ -345,6 +357,10 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, { * style - {Object} */ drawText: function(location, style) { + style = OpenLayers.Util.extend({ + fontColor: "#000000", + labelAlign: "cm" + }, style); var pt = this.getLocalXY(location); this.setCanvasStyle("reset"); diff --git a/lib/OpenLayers/Renderer/Elements.js b/lib/OpenLayers/Renderer/Elements.js index dac4078ca5..db9feed132 100644 --- a/lib/OpenLayers/Renderer/Elements.js +++ b/lib/OpenLayers/Renderer/Elements.js @@ -661,12 +661,20 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, { OpenLayers.Util.applyDefaults(style, this.minimumSymbolizer); var options = { - 'isFilled': true, - 'isStroked': !!style.strokeWidth + 'isFilled': style.fill === undefined ? + true : + style.fill, + 'isStroked': style.stroke === undefined ? + !!style.strokeWidth : + style.stroke }; var drawn; switch (geometry.CLASS_NAME) { case "OpenLayers.Geometry.Point": + if(style.graphic === false) { + options.isFilled = false; + options.isStroked = false; + } drawn = this.drawPoint(node, geometry); break; case "OpenLayers.Geometry.LineString": diff --git a/lib/OpenLayers/Renderer/SVG.js b/lib/OpenLayers/Renderer/SVG.js index 74eff8895d..f3630f8c47 100644 --- a/lib/OpenLayers/Renderer/SVG.js +++ b/lib/OpenLayers/Renderer/SVG.js @@ -254,7 +254,10 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, { var widthFactor = 1; var pos; if (node._geometryClass == "OpenLayers.Geometry.Point" && r) { - if (style.externalGraphic) { + node.style.visibility = ""; + if (style.graphic === false) { + node.style.visibility = "hidden"; + } else if (style.externalGraphic) { pos = this.getPosition(node); if (style.graphicTitle) { diff --git a/lib/OpenLayers/Style.js b/lib/OpenLayers/Style.js index 487448c045..617b3f35e0 100644 --- a/lib/OpenLayers/Style.js +++ b/lib/OpenLayers/Style.js @@ -64,10 +64,21 @@ OpenLayers.Style = OpenLayers.Class({ * Property: defaultStyle * {Object} hash of style properties to use as default for merging * rule-based style symbolizers onto. If no rules are defined, - * createSymbolizer will return this style. + * createSymbolizer will return this style. If is set to + * true, the defaultStyle will only be taken into account if there are + * rules defined. */ defaultStyle: null, + /** + * Property: defaultsPerSymbolizer + * {Boolean} If set to true, the will extend the symbolizer + * of every rule. Properties of the will also be used to set + * missing symbolizer properties if the symbolizer has stroke, fill or + * graphic set to true. Default is false. + */ + defaultsPerSymbolizer: false, + /** * Property: propertyStyles * {Hash of Boolean} cache of style properties that need to be parsed for @@ -135,7 +146,7 @@ OpenLayers.Style = OpenLayers.Class({ * {Object} symbolizer hash */ createSymbolizer: function(feature) { - var style = this.createLiterals( + var style = this.defaultsPerSymbolizer ? {} : this.createLiterals( OpenLayers.Util.extend({}, this.defaultStyle), feature); var rules = this.rules; @@ -191,6 +202,40 @@ OpenLayers.Style = OpenLayers.Class({ OpenLayers.Style.SYMBOLIZER_PREFIXES[0]; var symbolizer = rule.symbolizer[symbolizerPrefix] || rule.symbolizer; + + if(this.defaultsPerSymbolizer === true) { + var defaults = this.defaultStyle; + OpenLayers.Util.applyDefaults(symbolizer, { + pointRadius: defaults.pointRadius + }) + if(symbolizer.stroke === true || symbolizer.graphic === true) { + OpenLayers.Util.applyDefaults(symbolizer, { + strokeWidth: defaults.strokeWidth, + strokeColor: defaults.strokeColor, + strokeOpacity: defaults.strokeOpacity, + strokeDashstyle: defaults.strokeDashstyle, + strokeLinecap: defaults.strokeLinecap + }); + } + if(symbolizer.fill === true || symbolizer.graphic === true) { + OpenLayers.Util.applyDefaults(symbolizer, { + fillColor: defaults.fillColor, + fillOpacity: defaults.fillOpacity + }); + } + if(symbolizer.graphic === true) { + OpenLayers.Util.applyDefaults(symbolizer, { + pointRadius: this.defaultStyle.pointRadius, + externalGraphic: this.defaultStyle.externalGraphic, + graphicName: this.defaultStyle.graphicName, + graphicOpacity: this.defaultStyle.graphicOpacity, + graphicWidth: this.defaultStyle.graphicWidth, + graphicHeight: this.defaultStyle.graphicHeight, + graphicXOffset: this.defaultStyle.graphicXOffset, + graphicYOffset: this.defaultStyle.graphicYOffset + }); + } + } // merge the style with the current style return this.createLiterals( diff --git a/tests/Style.html b/tests/Style.html index 9423b78a9b..5bab4ad56d 100644 --- a/tests/Style.html +++ b/tests/Style.html @@ -151,6 +151,91 @@ style.createSymbolizer(new OpenLayers.Feature.Vector()); } + function test_Style_applySymbolizer(t) { + t.plan(15); + + var feature = new OpenLayers.Feature.Vector(); + var defaults = OpenLayers.Feature.Vector.style["default"]; + var style, symbolizer; + + style = new OpenLayers.Style(); + symbolizer = style.createSymbolizer(feature); + t.eq(symbolizer.pointRadius, defaults.pointRadius, "symbolizer has the correct pointRadius"); + t.eq(symbolizer.strokeWidth, defaults.strokeWidth, "symbolizer has the correct strokeWidth"); + t.eq(symbolizer.fillColor, defaults.fillColor, "symbolizer has the correct fillColor"); + t.eq(symbolizer.graphicName, defaults.graphicName, "symbolizer has the correct graphicName"); + + style = new OpenLayers.Style(null, { + defaultsPerSymbolizer: true, + rules: [ + new OpenLayers.Rule({ + symbolizer: { + stroke: true + } + }) + ] + }); + symbolizer = style.createSymbolizer(feature); + t.eq(symbolizer.strokeWidth, defaults.strokeWidth, "symbolizer has the correct strokeWidth"); + t.ok(symbolizer.fillColor == undefined, "fillColor is undefined"); + + style = new OpenLayers.Style(null, { + defaultsPerSymbolizer: true, + rules: [ + new OpenLayers.Rule({ + symbolizer: { + } + }) + ] + }); + symbolizer = style.createSymbolizer(feature); + t.eq(symbolizer.pointRadius, defaults.pointRadius, "symbolizer has the correct pointRadius"); + t.ok(symbolizer.strokeWidth == undefined, "strokeWidth is undefined"); + t.ok(symbolizer.fillColor == undefined, "fillColor is undefined"); + t.ok(symbolizer.graphicName == undefined, "graphicName is undefined"); + + style = new OpenLayers.Style(null, { + defaultsPerSymbolizer: true, + rules: [ + new OpenLayers.Rule({ + symbolizer: { + stroke: true + } + }) + ] + }); + symbolizer = style.createSymbolizer(feature); + t.eq(symbolizer.strokeWidth, defaults.strokeWidth, "symbolizer has the correct strokeWidth"); + t.ok(symbolizer.fillColor == undefined, "fillColor is undefined"); + + style = new OpenLayers.Style(null, { + defaultsPerSymbolizer: true, + rules: [ + new OpenLayers.Rule({ + symbolizer: { + fill: true + } + }) + ] + }); + symbolizer = style.createSymbolizer(feature); + t.eq(symbolizer.fillColor, defaults.fillColor, "symbolizer has the correct fillColor"); + t.ok(symbolizer.strokeWidth == undefined, "strokeWidth is undefined"); + + style = new OpenLayers.Style(null, { + defaultsPerSymbolizer: true, + rules: [ + new OpenLayers.Rule({ + symbolizer: { + graphic: true + } + }) + ] + }); + symbolizer = style.createSymbolizer(feature); + t.eq(symbolizer.graphicName, defaults.graphicName, "symbolizer has the correct graphicName"); + } + function test_Style_context(t) { t.plan(2); var rule = new OpenLayers.Rule({