diff --git a/src/ol/feature.js b/src/ol/feature.js index c3c9b66efe..f4d46ac08a 100644 --- a/src/ol/feature.js +++ b/src/ol/feature.js @@ -25,6 +25,24 @@ ol.Feature = function(opt_geometry, opt_values) { goog.inherits(ol.Feature, ol.Object); +/** + * @return {Object} Attributes object. + */ +ol.Feature.prototype.getAttributes = function() { + // TODO: see https://github.com/openlayers/ol3/pull/217 + // var keys = this.getKeys(), + // len = keys.length, + // attributes = {}, + // i, key + // for (var i = 0; i < len; ++ i) { + // key = keys[i]; + // attributes[key] = this.get(key); + // } + // return attributes; + return this; +}; + + /** * @return {ol.geom.Geometry} The geometry (or null if none). */ diff --git a/src/ol/style/line.js b/src/ol/style/line.js index e3bc7352c7..393affc669 100644 --- a/src/ol/style/line.js +++ b/src/ol/style/line.js @@ -1,6 +1,10 @@ +goog.provide('ol.style.Line'); goog.provide('ol.style.LiteralLine'); +goog.require('ol.Expression'); +goog.require('ol.ExpressionLiteral'); goog.require('ol.style.LiteralSymbolizer'); +goog.require('ol.style.Symbolizer'); /** @@ -8,14 +12,14 @@ goog.require('ol.style.LiteralSymbolizer'); * strokeWidth: (number), * opacity: (number)}} */ -ol.style.LiteralLineConfig; +ol.style.LiteralLineOptions; /** * @constructor * @implements {ol.style.LiteralSymbolizer} - * @param {ol.style.LiteralLineConfig} config Symbolizer properties. + * @param {ol.style.LiteralLineOptions} config Symbolizer properties. */ ol.style.LiteralLine = function(config) { @@ -29,3 +33,83 @@ ol.style.LiteralLine = function(config) { this.opacity = config.opacity; }; + + +/** + * @typedef {{strokeStyle: (string|ol.Expression), + * strokeWidth: (number|ol.Expression), + * opacity: (number|ol.Expression)}} + */ +ol.style.LineOptions; + + + +/** + * @constructor + * @implements {ol.style.Symbolizer} + * @param {ol.style.LineOptions} options Symbolizer properties. + */ +ol.style.Line = function(options) { + + /** + * @type {ol.Expression} + * @private + */ + this.strokeStyle_ = !goog.isDef(options.strokeStyle) ? + new ol.ExpressionLiteral(ol.style.LineDefaults.strokeStyle) : + (options.strokeStyle instanceof ol.Expression) ? + options.strokeStyle : new ol.ExpressionLiteral(options.strokeStyle); + + /** + * @type {ol.Expression} + * @private + */ + this.strokeWidth_ = !goog.isDef(options.strokeWidth) ? + new ol.ExpressionLiteral(ol.style.LineDefaults.strokeWidth) : + (options.strokeWidth instanceof ol.Expression) ? + options.strokeWidth : new ol.ExpressionLiteral(options.strokeWidth); + + /** + * @type {ol.Expression} + * @private + */ + this.opacity_ = !goog.isDef(options.opacity) ? + new ol.ExpressionLiteral(ol.style.LineDefaults.opacity) : + (options.opacity instanceof ol.Expression) ? + options.opacity : new ol.ExpressionLiteral(options.opacity); + +}; + + +/** + * @inheritDoc + * @return {ol.style.LiteralLine} Literal line symbolizer. + */ +ol.style.Line.prototype.createLiteral = function(feature) { + var attrs = feature.getAttributes(); + + var strokeStyle = this.strokeStyle_.evaluate(feature, attrs); + goog.asserts.assertString(strokeStyle, 'strokeStyle must be a string'); + + var strokeWidth = this.strokeWidth_.evaluate(feature, attrs); + goog.asserts.assertNumber(strokeWidth, 'strokeWidth must be a number'); + + var opacity = this.opacity_.evaluate(feature, attrs); + goog.asserts.assertNumber(opacity, 'opacity must be a number'); + + return new ol.style.LiteralLine({ + strokeStyle: strokeStyle, + strokeWidth: strokeWidth, + opacity: opacity + }); +}; + + +/** + * @type {ol.style.LiteralLine} + */ +ol.style.LineDefaults = new ol.style.LiteralLine({ + strokeStyle: '#696969', + strokeWidth: 1.5, + opacity: 0.75 +}); diff --git a/src/ol/style/point.js b/src/ol/style/point.js index acbed220c4..faec50af16 100644 --- a/src/ol/style/point.js +++ b/src/ol/style/point.js @@ -1,6 +1,8 @@ goog.provide('ol.style.LiteralPoint'); +goog.provide('ol.style.Point'); goog.require('ol.style.LiteralSymbolizer'); +goog.require('ol.style.Symbolizer'); @@ -9,3 +11,17 @@ goog.require('ol.style.LiteralSymbolizer'); * @implements {ol.style.LiteralSymbolizer} */ ol.style.LiteralPoint = function() {}; + + + +/** + * @constructor + * @implements {ol.style.Symbolizer} + */ +ol.style.Point = function() {}; + + +/** + * @inheritDoc + */ +ol.style.Point.prototype.createLiteral = goog.abstractMethod; diff --git a/src/ol/style/polygon.js b/src/ol/style/polygon.js index 160cdfa310..3ada41fc67 100644 --- a/src/ol/style/polygon.js +++ b/src/ol/style/polygon.js @@ -1,6 +1,10 @@ goog.provide('ol.style.LiteralPolygon'); +goog.provide('ol.style.Polygon'); +goog.require('ol.Expression'); +goog.require('ol.ExpressionLiteral'); goog.require('ol.style.LiteralSymbolizer'); +goog.require('ol.style.Symbolizer'); /** @@ -9,14 +13,14 @@ goog.require('ol.style.LiteralSymbolizer'); * strokeWidth: (number), * opacity: (number)}} */ -ol.style.LiteralPolygonConfig; +ol.style.LiteralPolygonOptions; /** * @constructor * @implements {ol.style.LiteralSymbolizer} - * @param {ol.style.LiteralPolygonConfig} config Symbolizer properties. + * @param {ol.style.LiteralPolygonOptions} config Symbolizer properties. */ ol.style.LiteralPolygon = function(config) { @@ -33,3 +37,98 @@ ol.style.LiteralPolygon = function(config) { this.opacity = config.opacity; }; + + +/** + * @typedef {{fillStyle: (string|ol.Expression), + * strokeStyle: (string|ol.Expression), + * strokeWidth: (number|ol.Expression), + * opacity: (number|ol.Expression)}} + */ +ol.style.PolygonOptions; + + + +/** + * @constructor + * @implements {ol.style.Symbolizer} + * @param {ol.style.PolygonOptions} options Symbolizer properties. + */ +ol.style.Polygon = function(options) { + + /** + * @type {ol.Expression} + * @private + */ + this.fillStyle_ = !goog.isDef(options.fillStyle) ? + new ol.ExpressionLiteral(ol.style.PolygonDefaults.fillStyle) : + (options.fillStyle instanceof ol.Expression) ? + options.fillStyle : new ol.ExpressionLiteral(options.fillStyle); + + /** + * @type {ol.Expression} + * @private + */ + this.strokeStyle_ = !goog.isDef(options.strokeStyle) ? + new ol.ExpressionLiteral(ol.style.PolygonDefaults.strokeStyle) : + (options.strokeStyle instanceof ol.Expression) ? + options.strokeStyle : new ol.ExpressionLiteral(options.strokeStyle); + + /** + * @type {ol.Expression} + * @private + */ + this.strokeWidth_ = !goog.isDef(options.strokeWidth) ? + new ol.ExpressionLiteral(ol.style.PolygonDefaults.strokeWidth) : + (options.strokeWidth instanceof ol.Expression) ? + options.strokeWidth : new ol.ExpressionLiteral(options.strokeWidth); + + /** + * @type {ol.Expression} + * @private + */ + this.opacity_ = !goog.isDef(options.opacity) ? + new ol.ExpressionLiteral(ol.style.PolygonDefaults.opacity) : + (options.opacity instanceof ol.Expression) ? + options.opacity : new ol.ExpressionLiteral(options.opacity); + +}; + + +/** + * @inheritDoc + * @return {ol.style.LiteralPolygon} Literal shape symbolizer. + */ +ol.style.Polygon.prototype.createLiteral = function(feature) { + var attrs = feature.getAttributes(); + + var fillStyle = this.fillStyle_.evaluate(feature, attrs); + goog.asserts.assertString(fillStyle, 'fillStyle must be a string'); + + var strokeStyle = this.strokeStyle_.evaluate(feature, attrs); + goog.asserts.assertString(strokeStyle, 'strokeStyle must be a string'); + + var strokeWidth = this.strokeWidth_.evaluate(feature, attrs); + goog.asserts.assertNumber(strokeWidth, 'strokeWidth must be a number'); + + var opacity = this.opacity_.evaluate(feature, attrs); + goog.asserts.assertNumber(opacity, 'opacity must be a number'); + + return new ol.style.LiteralPolygon({ + fillStyle: fillStyle, + strokeStyle: strokeStyle, + strokeWidth: strokeWidth, + opacity: opacity + }); +}; + + +/** + * @type {ol.style.LiteralPolygon} + */ +ol.style.PolygonDefaults = new ol.style.LiteralPolygon({ + fillStyle: '#ffffff', + strokeStyle: '#696969', + strokeWidth: 1.5, + opacity: 0.75 +}); diff --git a/src/ol/style/shape.js b/src/ol/style/shape.js index e188d8c354..ce07f4bee9 100644 --- a/src/ol/style/shape.js +++ b/src/ol/style/shape.js @@ -1,7 +1,11 @@ goog.provide('ol.style.LiteralShape'); +goog.provide('ol.style.Shape'); goog.provide('ol.style.ShapeType'); +goog.require('ol.Expression'); +goog.require('ol.ExpressionLiteral'); goog.require('ol.style.LiteralPoint'); +goog.require('ol.style.Point'); /** @@ -20,14 +24,14 @@ ol.style.ShapeType = { * strokeWidth: (number), * opacity: (number)}} */ -ol.style.LiteralShapeConfig; +ol.style.LiteralShapeOptions; /** * @constructor * @extends {ol.style.LiteralPoint} - * @param {ol.style.LiteralShapeConfig} config Symbolizer properties. + * @param {ol.style.LiteralShapeOptions} config Symbolizer properties. */ ol.style.LiteralShape = function(config) { @@ -51,3 +55,123 @@ ol.style.LiteralShape = function(config) { }; goog.inherits(ol.style.LiteralShape, ol.style.LiteralPoint); + + +/** + * @typedef {{type: (ol.style.ShapeType), + * size: (number|ol.Expression), + * fillStyle: (string|ol.Expression), + * strokeStyle: (string|ol.Expression), + * strokeWidth: (number|ol.Expression), + * opacity: (number|ol.Expression)}} + */ +ol.style.ShapeOptions; + + + +/** + * @constructor + * @extends {ol.style.Point} + * @param {ol.style.ShapeOptions} options Symbolizer properties. + */ +ol.style.Shape = function(options) { + + /** + * @type {ol.style.ShapeType} + * @private + */ + this.type_ = /** @type {ol.style.ShapeType} */ goog.isDef(options.type) ? + options.type : ol.style.ShapeDefaults.type; + + /** + * @type {ol.Expression} + * @private + */ + this.size_ = !goog.isDef(options.size) ? + new ol.ExpressionLiteral(ol.style.ShapeDefaults.size) : + (options.size instanceof ol.Expression) ? + options.size : new ol.ExpressionLiteral(options.size); + + /** + * @type {ol.Expression} + * @private + */ + this.fillStyle_ = !goog.isDef(options.fillStyle) ? + new ol.ExpressionLiteral(ol.style.ShapeDefaults.fillStyle) : + (options.fillStyle instanceof ol.Expression) ? + options.fillStyle : new ol.ExpressionLiteral(options.fillStyle); + + /** + * @type {ol.Expression} + * @private + */ + this.strokeStyle_ = !goog.isDef(options.strokeStyle) ? + new ol.ExpressionLiteral(ol.style.ShapeDefaults.strokeStyle) : + (options.strokeStyle instanceof ol.Expression) ? + options.strokeStyle : new ol.ExpressionLiteral(options.strokeStyle); + + /** + * @type {ol.Expression} + * @private + */ + this.strokeWidth_ = !goog.isDef(options.strokeWidth) ? + new ol.ExpressionLiteral(ol.style.ShapeDefaults.strokeWidth) : + (options.strokeWidth instanceof ol.Expression) ? + options.strokeWidth : new ol.ExpressionLiteral(options.strokeWidth); + + /** + * @type {ol.Expression} + * @private + */ + this.opacity_ = !goog.isDef(options.opacity) ? + new ol.ExpressionLiteral(ol.style.ShapeDefaults.opacity) : + (options.opacity instanceof ol.Expression) ? + options.opacity : new ol.ExpressionLiteral(options.opacity); + +}; + + +/** + * @inheritDoc + * @return {ol.style.LiteralShape} Literal shape symbolizer. + */ +ol.style.Shape.prototype.createLiteral = function(feature) { + var attrs = feature.getAttributes(); + + var size = this.size_.evaluate(feature, attrs); + goog.asserts.assertNumber(size, 'size must be a number'); + + var fillStyle = this.fillStyle_.evaluate(feature, attrs); + goog.asserts.assertString(fillStyle, 'fillStyle must be a string'); + + var strokeStyle = this.strokeStyle_.evaluate(feature, attrs); + goog.asserts.assertString(strokeStyle, 'strokeStyle must be a string'); + + var strokeWidth = this.strokeWidth_.evaluate(feature, attrs); + goog.asserts.assertNumber(strokeWidth, 'strokeWidth must be a number'); + + var opacity = this.opacity_.evaluate(feature, attrs); + goog.asserts.assertNumber(opacity, 'opacity must be a number'); + + return new ol.style.LiteralShape({ + type: this.type_, + size: size, + fillStyle: fillStyle, + strokeStyle: strokeStyle, + strokeWidth: strokeWidth, + opacity: opacity + }); +}; + + +/** + * @type {ol.style.LiteralShape} + */ +ol.style.ShapeDefaults = new ol.style.LiteralShape({ + type: ol.style.ShapeType.CIRCLE, + size: 5, + fillStyle: '#ffffff', + strokeStyle: '#696969', + strokeWidth: 1.5, + opacity: 0.75 +}); diff --git a/test/spec/ol/style/line.test.js b/test/spec/ol/style/line.test.js new file mode 100644 index 0000000000..c7ffdc177c --- /dev/null +++ b/test/spec/ol/style/line.test.js @@ -0,0 +1,51 @@ +goog.provide('ol.test.style.Line'); + +describe('ol.style.Line', function() { + + describe('constructor', function() { + + it('accepts literal values', function() { + var symbolizer = new ol.style.Line({ + strokeStyle: '#BADA55', + strokeWidth: 3 + }); + expect(symbolizer).toBeA(ol.style.Line); + }); + + it('accepts expressions', function() { + var symbolizer = new ol.style.Line({ + opacity: new ol.Expression('value / 100'), + strokeWidth: ol.Expression('widthAttr') + }); + expect(symbolizer).toBeA(ol.style.Line); + }); + + }); + + describe('#createLiteral()', function() { + + it('evaluates expressions with the given feature', function() { + var symbolizer = new ol.style.Line({ + opacity: new ol.Expression('value / 100'), + strokeWidth: ol.Expression('widthAttr') + }); + + var feature = new ol.Feature(undefined, { + value: 42, + widthAttr: 1.5 + }); + + var literal = symbolizer.createLiteral(feature); + expect(literal).toBeA(ol.style.LiteralLine); + expect(literal.opacity).toBe(42 / 100); + expect(literal.strokeWidth).toBe(1.5); + }); + + }); + +}); + +goog.require('ol.Expression'); +goog.require('ol.Feature'); +goog.require('ol.style.Line'); +goog.require('ol.style.LiteralLine'); diff --git a/test/spec/ol/style/polygon.test.js b/test/spec/ol/style/polygon.test.js new file mode 100644 index 0000000000..52f639a324 --- /dev/null +++ b/test/spec/ol/style/polygon.test.js @@ -0,0 +1,51 @@ +goog.provide('ol.test.style.Polygon'); + +describe('ol.style.Polygon', function() { + + describe('constructor', function() { + + it('accepts literal values', function() { + var symbolizer = new ol.style.Polygon({ + fillStyle: '#BADA55', + strokeWidth: 3 + }); + expect(symbolizer).toBeA(ol.style.Polygon); + }); + + it('accepts expressions', function() { + var symbolizer = new ol.style.Polygon({ + opacity: new ol.Expression('value / 100'), + fillStyle: ol.Expression('fillAttr') + }); + expect(symbolizer).toBeA(ol.style.Polygon); + }); + + }); + + describe('#createLiteral()', function() { + + it('evaluates expressions with the given feature', function() { + var symbolizer = new ol.style.Polygon({ + opacity: new ol.Expression('value / 100'), + fillStyle: new ol.Expression('fillAttr') + }); + + var feature = new ol.Feature(undefined, { + value: 42, + fillAttr: '#ff0000' + }); + + var literal = symbolizer.createLiteral(feature); + expect(literal).toBeA(ol.style.LiteralPolygon); + expect(literal.opacity).toBe(42 / 100); + expect(literal.fillStyle).toBe('#ff0000'); + }); + + }); + +}); + +goog.require('ol.Expression'); +goog.require('ol.Feature'); +goog.require('ol.style.Polygon'); +goog.require('ol.style.LiteralPolygon'); diff --git a/test/spec/ol/style/shape.test.js b/test/spec/ol/style/shape.test.js new file mode 100644 index 0000000000..17835fb047 --- /dev/null +++ b/test/spec/ol/style/shape.test.js @@ -0,0 +1,51 @@ +goog.provide('ol.test.style.Shape'); + +describe('ol.style.Shape', function() { + + describe('constructor', function() { + + it('accepts literal values', function() { + var symbolizer = new ol.style.Shape({ + size: 4, + fillStyle: '#BADA55' + }); + expect(symbolizer).toBeA(ol.style.Shape); + }); + + it('accepts expressions', function() { + var symbolizer = new ol.style.Shape({ + size: new ol.Expression('sizeAttr'), + strokeStyle: ol.Expression('color') + }); + expect(symbolizer).toBeA(ol.style.Shape); + }); + + }); + + describe('#createLiteral()', function() { + + it('evaluates expressions with the given feature', function() { + var symbolizer = new ol.style.Shape({ + size: new ol.Expression('sizeAttr'), + opacity: new ol.Expression('opacityAttr') + }); + + var feature = new ol.Feature(undefined, { + sizeAttr: 42, + opacityAttr: 0.4 + }); + + var literal = symbolizer.createLiteral(feature); + expect(literal).toBeA(ol.style.LiteralShape); + expect(literal.size).toBe(42); + expect(literal.opacity).toBe(0.4); + }); + + }); + +}); + +goog.require('ol.Expression'); +goog.require('ol.Feature'); +goog.require('ol.style.Shape'); +goog.require('ol.style.LiteralShape');