Mutable symbolizer properties for style functions

This change adds setters for symbolizer properties. In addition, it
introduces a mutable flag on all styles. By default, this is set to
true. ol.style.createStyleFunction sets it to false for all static
styles.

The new setters assert that the mutable flag is true, so whenever an
application tries to set a symbolizer property on a style that was
assigned to a vector layer or feature overlay, the assertion will fail.
This commit is contained in:
Andreas Hocevar
2014-09-03 16:57:50 -06:00
parent 2470f21b4c
commit a50f6d7a2f
9 changed files with 448 additions and 28 deletions

View File

@@ -11,16 +11,7 @@ goog.require('ol.style.Style');
goog.require('ol.style.Text');
var styleCache = {};
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({
var style = new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(255, 255, 255, 0.6)'
}),
@@ -30,7 +21,6 @@ var vectorLayer = new ol.layer.Vector({
}),
text: new ol.style.Text({
font: '12px Calibri,sans-serif',
text: text,
fill: new ol.style.Fill({
color: '#000'
}),
@@ -39,9 +29,16 @@ var vectorLayer = new ol.layer.Vector({
width: 3
})
})
})];
}
return styleCache[text];
});
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) {
style.getText().setText(resolution < 5000 ? feature.get('name') : '');
return styles;
}
});

View File

@@ -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
*/

View File

@@ -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;
};

View File

@@ -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`.

View File

@@ -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.<number>} 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;
};

View File

@@ -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;

View File

@@ -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;
};

View File

@@ -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);
});

View File

@@ -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');