diff --git a/examples/vector-layer.js b/examples/vector-layer.js index daf0d3ca75..25f70d6cde 100644 --- a/examples/vector-layer.js +++ b/examples/vector-layer.js @@ -11,37 +11,34 @@ goog.require('ol.style.Style'); goog.require('ol.style.Text'); -var styleCache = {}; +var style = new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.6)' + }), + stroke: new ol.style.Stroke({ + color: '#319FD3', + width: 1 + }), + text: new ol.style.Text({ + font: '12px Calibri,sans-serif', + fill: new ol.style.Fill({ + color: '#000' + }), + stroke: new ol.style.Stroke({ + color: '#fff', + width: 3 + }) + }) +}); +var styles = [style]; var vectorLayer = new ol.layer.Vector({ source: new ol.source.GeoJSON({ projection: 'EPSG:3857', url: 'data/geojson/countries.geojson' }), style: function(feature, resolution) { - var text = resolution < 5000 ? feature.get('name') : ''; - if (!styleCache[text]) { - styleCache[text] = [new ol.style.Style({ - fill: new ol.style.Fill({ - color: 'rgba(255, 255, 255, 0.6)' - }), - stroke: new ol.style.Stroke({ - color: '#319FD3', - width: 1 - }), - text: new ol.style.Text({ - font: '12px Calibri,sans-serif', - text: text, - fill: new ol.style.Fill({ - color: '#000' - }), - stroke: new ol.style.Stroke({ - color: '#fff', - width: 3 - }) - }) - })]; - } - return styleCache[text]; + style.getText().setText(resolution < 5000 ? feature.get('name') : ''); + return styles; } }); diff --git a/src/ol/style/circlestyle.js b/src/ol/style/circlestyle.js index 7f9c268541..e531716ec6 100644 --- a/src/ol/style/circlestyle.js +++ b/src/ol/style/circlestyle.js @@ -172,6 +172,21 @@ ol.style.Circle.prototype.getStroke = function() { }; +/** + * @protected + * @param {boolean} mutable Mutable. + */ +ol.style.Circle.prototype.setMutable = function(mutable) { + if (!goog.isNull(this.stroke_)) { + this.stroke_.setMutable(mutable); + } + if (!goog.isNull(this.fill_)) { + this.fill_.setMutable(mutable); + } + goog.base(this, 'setMutable', mutable); +}; + + /** * @inheritDoc */ diff --git a/src/ol/style/fillstyle.js b/src/ol/style/fillstyle.js index edfad11ae4..6b566deb96 100644 --- a/src/ol/style/fillstyle.js +++ b/src/ol/style/fillstyle.js @@ -1,6 +1,6 @@ goog.provide('ol.style.Fill'); -goog.require('ol.color'); +goog.require('goog.asserts'); @@ -21,6 +21,13 @@ ol.style.Fill = function(opt_options) { * @type {ol.Color|string} */ this.color_ = goog.isDef(options.color) ? options.color : null; + + /** + * @private + * @type {boolean} + */ + this.mutable_ = true; + }; @@ -31,3 +38,21 @@ ol.style.Fill = function(opt_options) { ol.style.Fill.prototype.getColor = function() { return this.color_; }; + + +/** + * @param {ol.Color|string} color Color. + * @api + */ +ol.style.Fill.prototype.setColor = function(color) { + goog.asserts.assert(this.mutable_); + this.color_ = color; +}; + + +/** + * @param {boolean} mutable Mutable. + */ +ol.style.Fill.prototype.setMutable = function(mutable) { + this.mutable_ = mutable; +}; diff --git a/src/ol/style/imagestyle.js b/src/ol/style/imagestyle.js index e5d8bce527..e4db519d23 100644 --- a/src/ol/style/imagestyle.js +++ b/src/ol/style/imagestyle.js @@ -1,6 +1,8 @@ goog.provide('ol.style.Image'); goog.provide('ol.style.ImageState'); +goog.require('goog.asserts'); + /** * @enum {number} @@ -63,6 +65,12 @@ ol.style.Image = function(options) { */ this.snapToPixel_ = options.snapToPixel; + /** + * @private + * @type {boolean} + */ + this.mutable_ = true; + }; @@ -150,6 +158,61 @@ ol.style.Image.prototype.getOrigin = goog.abstractMethod; ol.style.Image.prototype.getSize = goog.abstractMethod; +/** + * @param {number} opacity Opacity. + */ +ol.style.Image.prototype.setOpacity = function(opacity) { + goog.asserts.assert(this.mutable_); + this.opacity_ = opacity; +}; + + +/** + * @param {boolean} rotateWithView Rotate with map. + */ +ol.style.Image.prototype.setRotateWithView = function(rotateWithView) { + goog.asserts.assert(this.mutable_); + this.rotateWithView_ = rotateWithView; +}; + + +/** + * @param {number} rotation Rotation. + * @api + */ +ol.style.Image.prototype.setRotation = function(rotation) { + goog.asserts.assert(this.mutable_); + this.rotation_ = rotation; +}; + + +/** + * @param {number} scale Scale. + * @api + */ +ol.style.Image.prototype.setScale = function(scale) { + goog.asserts.assert(this.mutable_); + this.scale_ = scale; +}; + + +/** + * @param {boolean} snapToPixel Snap to pixel? + */ +ol.style.Image.prototype.setSnapToPixel = function(snapToPixel) { + goog.asserts.assert(this.mutable_); + this.snapToPixel_ = snapToPixel; +}; + + +/** + * @param {boolean} mutable Mutable. + */ +ol.style.Image.prototype.setMutable = function(mutable) { + this.mutable_ = mutable; +}; + + /** * @param {function(this: T, goog.events.Event)} listener Listener function. * @param {T} thisArg Value to use as `this` when executing `listener`. diff --git a/src/ol/style/strokestyle.js b/src/ol/style/strokestyle.js index c5d2e90c91..6e487f974e 100644 --- a/src/ol/style/strokestyle.js +++ b/src/ol/style/strokestyle.js @@ -1,6 +1,6 @@ goog.provide('ol.style.Stroke'); -goog.require('ol.color'); +goog.require('goog.asserts'); @@ -54,6 +54,13 @@ ol.style.Stroke = function(opt_options) { * @type {number|undefined} */ this.width_ = options.width; + + /** + * @private + * @type {boolean} + */ + this.mutable_ = true; + }; @@ -109,3 +116,71 @@ ol.style.Stroke.prototype.getMiterLimit = function() { ol.style.Stroke.prototype.getWidth = function() { return this.width_; }; + + +/** + * @param {ol.Color|string} color Color. + * @api + */ +ol.style.Stroke.prototype.setColor = function(color) { + goog.asserts.assert(this.mutable_); + this.color_ = color; +}; + + +/** + * @param {string|undefined} lineCap Line cap. + * @api + */ +ol.style.Stroke.prototype.setLineCap = function(lineCap) { + goog.asserts.assert(this.mutable_); + this.lineCap_ = lineCap; +}; + + +/** + * @param {Array.} lineDash Line dash. + * @api + */ +ol.style.Stroke.prototype.setLineDash = function(lineDash) { + goog.asserts.assert(this.mutable_); + this.lineDash_ = lineDash; +}; + + +/** + * @param {string|undefined} lineJoin Line join. + * @api + */ +ol.style.Stroke.prototype.setLineJoin = function(lineJoin) { + goog.asserts.assert(this.mutable_); + this.lineJoin_ = lineJoin; +}; + + +/** + * @param {number|undefined} miterLimit Miter limit. + * @api + */ +ol.style.Stroke.prototype.setMiterLimit = function(miterLimit) { + goog.asserts.assert(this.mutable_); + this.miterLimit_ = miterLimit; +}; + + +/** + * @param {number|undefined} width Width. + * @api + */ +ol.style.Stroke.prototype.setWidth = function(width) { + goog.asserts.assert(this.mutable_); + this.width_ = width; +}; + + +/** + * @param {boolean} mutable Mutable. + */ +ol.style.Stroke.prototype.setMutable = function(mutable) { + this.mutable_ = mutable; +}; diff --git a/src/ol/style/style.js b/src/ol/style/style.js index 031b9b59bc..527ca0d3d4 100644 --- a/src/ol/style/style.js +++ b/src/ol/style/style.js @@ -52,6 +52,11 @@ ol.style.Style = function(opt_options) { */ this.zIndex_ = options.zIndex; + /** + * @private + * @type {boolean} + */ + this.mutable_ = true; }; @@ -100,6 +105,36 @@ ol.style.Style.prototype.getZIndex = function() { }; +/** + * @param {number|undefined} zIndex ZIndex. + * @api + */ +ol.style.Style.prototype.setZIndex = function(zIndex) { + goog.asserts.assert(this.mutable_); + this.zIndex_ = zIndex; +}; + + +/** + * @param {boolean} mutable Mutable. + */ +ol.style.Style.prototype.setMutable = function(mutable) { + if (!goog.isNull(this.fill_)) { + this.fill_.setMutable(mutable); + } + if (!goog.isNull(this.image_)) { + this.image_.setMutable(mutable); + } + if (!goog.isNull(this.stroke_)) { + this.stroke_.setMutable(mutable); + } + if (!goog.isNull(this.text_)) { + this.text_.setMutable(mutable); + } + this.mutable_ = mutable; +}; + + /** * A function that takes an {@link ol.Feature} and a `{number}` representing * the view's resolution. The function should return an array of @@ -138,6 +173,9 @@ ol.style.createStyleFunction = function(obj) { goog.asserts.assertInstanceof(obj, ol.style.Style); styles = [obj]; } + for (var i = styles.length - 1; i >= 0; --i) { + styles[i].setMutable(false); + } styleFunction = goog.functions.constant(styles); } return styleFunction; diff --git a/src/ol/style/textstyle.js b/src/ol/style/textstyle.js index 0ea5e73550..e2b8d6474d 100644 --- a/src/ol/style/textstyle.js +++ b/src/ol/style/textstyle.js @@ -1,5 +1,7 @@ goog.provide('ol.style.Text'); +goog.require('goog.asserts'); + /** @@ -73,6 +75,13 @@ ol.style.Text = function(opt_options) { * @type {number} */ this.offsetY_ = goog.isDef(options.offsetY) ? options.offsetY : 0; + + /** + * @private + * @type {boolean} + */ + this.mutable_ = true; + }; @@ -162,3 +171,115 @@ ol.style.Text.prototype.getTextAlign = function() { ol.style.Text.prototype.getTextBaseline = function() { return this.textBaseline_; }; + + +/** + * @param {string|undefined} font Font. + * @api + */ +ol.style.Text.prototype.setFont = function(font) { + goog.asserts.assert(this.mutable_); + this.font_ = font; +}; + + +/** + * @param {number} offsetX Horizontal text offset. + */ +ol.style.Text.prototype.setOffsetX = function(offsetX) { + goog.asserts.assert(this.mutable_); + this.offsetX_ = offsetX; +}; + + +/** + * @param {number} offsetY Vertical text offset. + */ +ol.style.Text.prototype.setOffsetY = function(offsetY) { + goog.asserts.assert(this.mutable_); + this.offsetY_ = offsetY; +}; + + +/** + * @param {ol.style.Fill} fill Fill style. + * @api + */ +ol.style.Text.prototype.setFill = function(fill) { + goog.asserts.assert(this.mutable_); + this.fill_ = fill; +}; + + +/** + * @param {number|undefined} rotation Rotation. + * @api + */ +ol.style.Text.prototype.setRotation = function(rotation) { + goog.asserts.assert(this.mutable_); + this.rotation_ = rotation; +}; + + +/** + * @param {number|undefined} scale Scale. + * @api + */ +ol.style.Text.prototype.setScale = function(scale) { + goog.asserts.assert(this.mutable_); + this.scale_ = scale; +}; + + +/** + * @param {ol.style.Stroke} stroke Stroke style. + * @api + */ +ol.style.Text.prototype.setStroke = function(stroke) { + goog.asserts.assert(this.mutable_); + this.stroke_ = stroke; +}; + + +/** + * @param {string|undefined} text Text. + * @api + */ +ol.style.Text.prototype.setText = function(text) { + goog.asserts.assert(this.mutable_); + this.text_ = text; +}; + + +/** + * @param {string|undefined} textAlign Text align. + * @api + */ +ol.style.Text.prototype.setTextAlign = function(textAlign) { + goog.asserts.assert(this.mutable_); + this.textAlign_ = textAlign; +}; + + +/** + * @param {string|undefined} textBaseline Text baseline. + * @api + */ +ol.style.Text.prototype.setTextBaseline = function(textBaseline) { + goog.asserts.assert(this.mutable_); + this.textBaseline_ = textBaseline; +}; + + +/** + * @param {boolean} mutable Mutable. + */ +ol.style.Text.prototype.setMutable = function(mutable) { + if (!goog.isNull(this.stroke_)) { + this.stroke_.setMutable(mutable); + } + if (!goog.isNull(this.fill_)) { + this.fill_.setMutable(mutable); + } + this.mutable_ = mutable; +}; diff --git a/test/spec/ol/featureoverlay.test.js b/test/spec/ol/featureoverlay.test.js index 47aa06189a..71f8bfc2d0 100644 --- a/test/spec/ol/featureoverlay.test.js +++ b/test/spec/ol/featureoverlay.test.js @@ -16,11 +16,12 @@ describe('ol.FeatureOverlay', function() { expect(featureOverlay.getFeatures().getLength()).to.be(1); }); - it('takes a style', function() { + it('takes a style and makes it immutable', function() { var style = [new ol.style.Style()]; var featureOverlay = new ol.FeatureOverlay({ style: [new ol.style.Style()] }); + style[0].setMutable(false); expect(featureOverlay.getStyle()).to.eql(style); expect(featureOverlay.getStyleFunction()()).to.eql(style); }); diff --git a/test/spec/ol/style.test.js b/test/spec/ol/style.test.js index 17eae20b5e..25710157a4 100644 --- a/test/spec/ol/style.test.js +++ b/test/spec/ol/style.test.js @@ -1,5 +1,55 @@ goog.provide('ol.test.style.Style'); +describe('ol.style.Style', function() { + + describe('#setMutable', function() { + + it('recursively sets the mutable flag', function() { + var style = new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.6)' + }), + stroke: new ol.style.Stroke({ + color: '#319FD3', + width: 1 + }), + text: new ol.style.Text({ + font: '12px Calibri,sans-serif', + fill: new ol.style.Fill({ + color: '#000' + }), + stroke: new ol.style.Stroke({ + color: '#fff', + width: 3 + }) + }) + }); + + expect(function() { + style.setZIndex(1); + }).to.not.throwException(); + + expect(style.mutable_).to.be(true); + expect(style.getFill().mutable_).to.be(true); + expect(style.getStroke().mutable_).to.be(true); + expect(style.getText().mutable_).to.be(true); + expect(style.getText().getStroke().mutable_).to.be(true); + + style.setMutable(false); + + expect(function() { + style.setZIndex(); + }).to.throwException(); + + expect(style.mutable_).to.be(false); + expect(style.getFill().mutable_).to.be(false); + expect(style.getStroke().mutable_).to.be(false); + expect(style.getText().mutable_).to.be(false); + expect(style.getText().getStroke().mutable_).to.be(false); + }); + }); +}); + describe('ol.style.createStyleFunction()', function() { var style = new ol.style.Style(); @@ -27,6 +77,41 @@ describe('ol.style.createStyleFunction()', function() { }).to.throwException(); }); + it('makes styles immutable', function() { + var style = new ol.style.Style({ + fill: new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.6)' + }), + stroke: new ol.style.Stroke({ + color: '#319FD3', + width: 1 + }), + text: new ol.style.Text({ + font: '12px Calibri,sans-serif', + fill: new ol.style.Fill({ + color: '#000' + }), + stroke: new ol.style.Stroke({ + color: '#fff', + width: 3 + }) + }) + }); + + expect(function() { + style.getFill().setColor('white'); + }).to.not.throwException(); + + ol.style.createStyleFunction(style); + + expect(function() { + style.getFill().setColor('black'); + }).to.throwException(); + + }); }); +goog.require('ol.style.Fill'); +goog.require('ol.style.Stroke'); goog.require('ol.style.Style'); +goog.require('ol.style.Text');