From bad401bc171d2f5eae4014689395b1a960d8be80 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Thu, 15 Aug 2013 10:34:24 -0400 Subject: [PATCH] Add support for "else" symbolizers When a style has no rules, the "else" symbolizers apply. When a style has rules and none of them apply to the given feature, the "else" symbolizers apply. Note that this is different than default symbolizer properties that might be merged into all symbolizers (as in OL2) - I don't think we should support that. --- examples/kml-timezones.js | 24 ++++----- examples/topojson.js | 28 +++++----- src/objectliterals.jsdoc | 5 +- src/ol/style/style.js | 44 ++++++++------- test/spec/ol/style/style.test.js | 93 +++++++++++++++++++++++++++++++- 5 files changed, 145 insertions(+), 49 deletions(-) diff --git a/examples/kml-timezones.js b/examples/kml-timezones.js index f5b93ee1e6..1bce4ed208 100644 --- a/examples/kml-timezones.js +++ b/examples/kml-timezones.js @@ -41,19 +41,17 @@ ol.expr.register('getOpacity', function() { return 0.75 * (1 - delta / 12); }); -var style = new ol.style.Style({rules: [ - new ol.style.Rule({ - symbolizers: [ - new ol.style.Fill({ - color: '#ffff33', - opacity: ol.expr.parse('getOpacity()') - }), - new ol.style.Stroke({ - color: '#ffffff', - }) - ] - }) -]}); +var style = new ol.style.Style({ + symbolizers: [ + new ol.style.Fill({ + color: '#ffff33', + opacity: ol.expr.parse('getOpacity()') + }), + new ol.style.Stroke({ + color: '#ffffff', + }) + ] +}); var vector = new ol.layer.Vector({ source: new ol.source.Vector({ diff --git a/examples/topojson.js b/examples/topojson.js index 9f172aecf8..75a4187120 100644 --- a/examples/topojson.js +++ b/examples/topojson.js @@ -23,21 +23,19 @@ var vector = new ol.layer.Vector({ url: 'data/topojson/world-110m.json', parser: new ol.parser.TopoJSON() }), - style: new ol.style.Style({rules: [ - new ol.style.Rule({ - symbolizers: [ - new ol.style.Fill({ - color: '#BADA55', - opacity: 0.5 - }), - new ol.style.Stroke({ - color: '#FFF', - opacity: 1, - width: 1.5 - }) - ] - }) - ]}) + style: new ol.style.Style({ + symbolizers: [ + new ol.style.Fill({ + color: '#BADA55', + opacity: 0.5 + }), + new ol.style.Stroke({ + color: '#FFF', + opacity: 1, + width: 1.5 + }) + ] + }) }); var map = new ol.Map({ diff --git a/src/objectliterals.jsdoc b/src/objectliterals.jsdoc index 8bef3bb5b5..cc90365820 100644 --- a/src/objectliterals.jsdoc +++ b/src/objectliterals.jsdoc @@ -642,7 +642,10 @@ /** * @typedef {Object} ol.style.StyleOptions - * @property {Array.} rules Rules. + * @property {Array.|undefined} rules Rules. + * @property {Array.|undefined} symbolizers Symbolizers + * (that apply if no rules are provided or where none of the provided rules + * apply). */ /** diff --git a/src/ol/style/style.js b/src/ol/style/style.js index 7932ee652e..d5e7c42298 100644 --- a/src/ol/style/style.js +++ b/src/ol/style/style.js @@ -9,6 +9,7 @@ goog.require('ol.style.PolygonLiteral'); goog.require('ol.style.Rule'); goog.require('ol.style.Shape'); goog.require('ol.style.Stroke'); +goog.require('ol.style.Symbolizer'); @@ -24,6 +25,15 @@ ol.style.Style = function(options) { */ this.rules_ = goog.isDef(options.rules) ? options.rules : []; + /** + * Symbolizers that apply if no rules are given or where none of the given + * rules apply (these are the "else" symbolizers). + * @type {Array.} + * @private + */ + this.symbolizers_ = goog.isDef(options.symbolizers) ? + options.symbolizers : []; + }; @@ -35,18 +45,20 @@ ol.style.Style = function(options) { */ ol.style.Style.prototype.createLiterals = function(feature) { var rules = this.rules_, - literals = [], - rule, symbolizers; + symbolizers = [], + applies = false, + rule; for (var i = 0, ii = rules.length; i < ii; ++i) { rule = rules[i]; if (rule.applies(feature)) { - symbolizers = rule.getSymbolizers(); - for (var j = 0, jj = symbolizers.length; j < jj; ++j) { - literals.push(symbolizers[j].createLiteral(feature)); - } + applies = true; + symbolizers.push.apply(symbolizers, rule.getSymbolizers()); } + } if (!applies) { + // these are the "else" symbolizers + symbolizers = this.symbolizers_; } - return ol.style.Style.reduceLiterals_(literals); + return ol.style.Style.createLiterals(symbolizers, feature); }; @@ -55,17 +67,13 @@ ol.style.Style.prototype.createLiterals = function(feature) { * @type {ol.style.Style} */ ol.style.Style.defaults = new ol.style.Style({ - rules: [ - new ol.style.Rule({ - symbolizers: [ - new ol.style.Shape({ - fill: new ol.style.Fill(), - stroke: new ol.style.Stroke() - }), - new ol.style.Fill(), - new ol.style.Stroke() - ] - }) + symbolizers: [ + new ol.style.Shape({ + fill: new ol.style.Fill(), + stroke: new ol.style.Stroke() + }), + new ol.style.Fill(), + new ol.style.Stroke() ] }); diff --git a/test/spec/ol/style/style.test.js b/test/spec/ol/style/style.test.js index 296193d206..8eb2ec2fe0 100644 --- a/test/spec/ol/style/style.test.js +++ b/test/spec/ol/style/style.test.js @@ -2,10 +2,40 @@ goog.provide('ol.test.style.Style'); describe('ol.style.Style', function() { + describe('constructor', function() { + + it('creates a style instance given rules', function() { + var style = new ol.style.Style({ + rules: [ + new ol.style.Rule({ + filter: 'foo == "bar"', + symbolizers: [ + new ol.style.Fill({ + color: '#ff0000' + }) + ] + }) + ] + }); + expect(style).to.be.a(ol.style.Style); + }); + + it('creates a style instance given only "else" symbolizers', function() { + var style = new ol.style.Style({ + symbolizers: [ + new ol.style.Fill({ + color: '#ff0000' + }) + ] + }); + expect(style).to.be.a(ol.style.Style); + }); + + }); + describe('#createLiterals()', function() { it('creates symbolizer literals for a feature', function() { - var style = new ol.style.Style({ rules: [ new ol.style.Rule({ @@ -13,16 +43,20 @@ describe('ol.style.Style', function() { symbolizers: [ new ol.style.Shape({ size: 4, - fill: new ol.style.Fill({color: '#BADA55'}) + fill: new ol.style.Fill({ + color: ol.expr.parse('fillColor') + }) }) ] }) ] }); var feature = new ol.Feature({ + fillColor: '#BADA55', geometry: new ol.geom.Point([1, 2]) }); feature.set('foo', 'bar'); + var literals = style.createLiterals(feature); expect(literals).to.have.length(1); expect(literals[0].fillColor).to.be('#BADA55'); @@ -31,6 +65,61 @@ describe('ol.style.Style', function() { expect(style.createLiterals(feature)).to.have.length(0); }); + it('uses the "else" symbolizers when no rules are provided', function() { + var style = new ol.style.Style({ + symbolizers: [ + new ol.style.Stroke({ + color: '#ff0000' + }) + ] + }); + + var feature = new ol.Feature({ + geometry: new ol.geom.LineString([[1, 2], [3, 4]]) + }); + + var literals = style.createLiterals(feature); + expect(literals).to.have.length(1); + expect(literals[0].color).to.be('#ff0000'); + }); + + it('uses the "else" symbolizers when no rules apply', function() { + var style = new ol.style.Style({ + rules: [ + new ol.style.Rule({ + filter: 'name == "match"', + symbolizers: [ + new ol.style.Stroke({ + color: '#ff00ff' + }) + ] + }) + ], + // these are the "else" symbolizers + symbolizers: [ + new ol.style.Stroke({ + color: '#00ff00' + }) + ] + }); + + var feature = new ol.Feature({ + geometry: new ol.geom.LineString([[1, 2], [3, 4]]) + }); + + var literals = style.createLiterals(feature); + expect(literals).to.have.length(1); + expect(literals[0].color).to.be('#00ff00'); + + feature = new ol.Feature({ + name: 'match', + geometry: new ol.geom.LineString([[1, 2], [3, 4]]) + }); + literals = style.createLiterals(feature); + expect(literals).to.have.length(1); + expect(literals[0].color).to.be('#ff00ff'); + }); + }); describe('ol.style.Style.defaults.createLiterals(feature)', function() {