diff --git a/src/ol/layer/vectorlayer.js b/src/ol/layer/vectorlayer.js
index 6ef234f60d..38b7367a22 100644
--- a/src/ol/layer/vectorlayer.js
+++ b/src/ol/layer/vectorlayer.js
@@ -1,7 +1,9 @@
goog.provide('ol.layer.Vector');
+goog.require('ol.Feature');
goog.require('ol.layer.Layer');
goog.require('ol.source.Vector');
+goog.require('ol.style.Style');
@@ -12,6 +14,13 @@ goog.require('ol.source.Vector');
*/
ol.layer.Vector = function(layerOptions) {
goog.base(this, layerOptions);
+
+ /**
+ * @private
+ * @type {ol.style.Style}
+ */
+ this.style_ = goog.isDef(layerOptions.style) ? layerOptions.style : null;
+
};
goog.inherits(ol.layer.Vector, ol.layer.Layer);
@@ -22,3 +31,38 @@ goog.inherits(ol.layer.Vector, ol.layer.Layer);
ol.layer.Vector.prototype.getVectorSource = function() {
return /** @type {ol.source.Vector} */ (this.getSource());
};
+
+
+/**
+ * @param {Array.
} features Features.
+ * @return {Array.} symbolizers for features.
+ */
+ol.layer.Vector.prototype.groupFeaturesBySymbolizerLiteral =
+ function(features) {
+ var uniqueLiterals = {},
+ featuresBySymbolizer = [],
+ style = this.style_,
+ feature, literals, literal, key;
+ for (var i = 0, ii = features.length; i < ii; ++i) {
+ feature = features[i];
+ literals = goog.isNull(style) ?
+ ol.style.Style.applyDefaultStyle(feature) :
+ style.apply(feature);
+ for (var j = 0, jj = literals.length; j < jj; ++j) {
+ literal = literals[j];
+ for (var l in uniqueLiterals) {
+ if (literal.equals(uniqueLiterals[l])) {
+ literal = uniqueLiterals[l];
+ break;
+ }
+ }
+ key = goog.getUid(literal);
+ if (!goog.object.containsKey(uniqueLiterals, key)) {
+ uniqueLiterals[key] = featuresBySymbolizer.length;
+ featuresBySymbolizer.push([[], literal]);
+ }
+ featuresBySymbolizer[uniqueLiterals[key]][0].push(feature);
+ }
+ }
+ return featuresBySymbolizer;
+};
diff --git a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js
index 5efe58ade3..38a82edfb7 100644
--- a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js
+++ b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js
@@ -14,10 +14,6 @@ goog.require('ol.geom.GeometryType');
goog.require('ol.layer.Vector');
goog.require('ol.renderer.canvas.Layer');
goog.require('ol.renderer.canvas.Renderer');
-goog.require('ol.style.LineLiteral');
-goog.require('ol.style.PolygonLiteral');
-goog.require('ol.style.ShapeLiteral');
-goog.require('ol.style.ShapeType');
goog.require('ol.tilegrid.TileGrid');
@@ -115,31 +111,6 @@ ol.renderer.canvas.VectorLayer = function(mapRenderer, layer) {
this.dirty_ = false;
- // TODO: implement layer.setStyle(style) where style is a set of rules
- // and a rule has a filter and array of symbolizers
- var symbolizers = {};
- symbolizers[ol.geom.GeometryType.POINT] = new ol.style.ShapeLiteral({
- type: ol.style.ShapeType.CIRCLE,
- size: 10,
- fillStyle: '#ffcc99',
- strokeStyle: '#ff9933',
- strokeWidth: 2,
- opacity: 0.75
- });
- symbolizers[ol.geom.GeometryType.LINESTRING] = new ol.style.LineLiteral({
- strokeStyle: '#ff9933',
- strokeWidth: 2,
- opacity: 1
- });
- symbolizers[ol.geom.GeometryType.POLYGON] = new ol.style.PolygonLiteral({
- fillStyle: '#ffcc99',
- strokeStyle: '#ff9933',
- strokeWidth: 2,
- opacity: 0.5
- });
- // TODO: remove this
- this.symbolizers_ = symbolizers;
-
/**
* @private
* @type {boolean}
@@ -195,7 +166,8 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
var view2DState = frameState.view2DState,
resolution = view2DState.resolution,
extent = frameState.extent,
- source = this.getVectorLayer().getVectorSource(),
+ layer = this.getVectorLayer(),
+ source = layer.getVectorSource(),
tileGrid = this.tileGrid_;
if (goog.isNull(tileGrid)) {
@@ -295,7 +267,8 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
// render features by geometry type
var filters = this.geometryFilters_,
numFilters = filters.length,
- i, geomFilter, extentFilter, type, features, symbolizer;
+ i, geomFilter, extentFilter, type, features,
+ groups, group, j, numGroups;
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tileCoord = new ol.TileCoord(z, x, y);
@@ -312,10 +285,13 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
features = source.getFeatures(new ol.filter.Logical(
[geomFilter, extentFilter], ol.filter.LogicalOperator.AND));
if (features.length) {
- // TODO: layer.getSymbolizerLiterals(features) or similar
- symbolizer = this.symbolizers_[type];
- sketchCanvasRenderer.renderFeaturesByGeometryType(
- type, features, symbolizer);
+ groups = layer.groupFeaturesBySymbolizerLiteral(features);
+ numGroups = groups.length;
+ for (j = 0; j < numGroups; ++j) {
+ group = groups[j];
+ sketchCanvasRenderer.renderFeaturesByGeometryType(type,
+ group[0], group[1]);
+ }
}
}
}
diff --git a/src/ol/style/line.js b/src/ol/style/line.js
index 3b0c6cd1cf..7d8519067f 100644
--- a/src/ol/style/line.js
+++ b/src/ol/style/line.js
@@ -37,6 +37,16 @@ ol.style.LineLiteral = function(config) {
goog.inherits(ol.style.LineLiteral, ol.style.SymbolizerLiteral);
+/**
+ * @inheritDoc
+ */
+ol.style.LineLiteral.prototype.equals = function(lineLiteral) {
+ return this.strokeStyle == lineLiteral.strokeStyle &&
+ this.strokeWidth == lineLiteral.strokeWidth &&
+ this.opacity == lineLiteral.opacity;
+};
+
+
/**
* @typedef {{strokeStyle: (string|ol.Expression),
* strokeWidth: (number|ol.Expression),
diff --git a/src/ol/style/polygon.js b/src/ol/style/polygon.js
index fe67bf677c..5886ccf474 100644
--- a/src/ol/style/polygon.js
+++ b/src/ol/style/polygon.js
@@ -41,6 +41,17 @@ ol.style.PolygonLiteral = function(config) {
goog.inherits(ol.style.PolygonLiteral, ol.style.SymbolizerLiteral);
+/**
+ * @inheritDoc
+ */
+ol.style.PolygonLiteral.prototype.equals = function(polygonLiteral) {
+ return this.fillStyle == polygonLiteral.fillStyle &&
+ this.strokeStyle == polygonLiteral.strokeStyle &&
+ this.strokeWidth == polygonLiteral.strokeWidth &&
+ this.opacity == polygonLiteral.opacity;
+};
+
+
/**
* @typedef {{fillStyle: (string|ol.Expression),
* strokeStyle: (string|ol.Expression),
diff --git a/src/ol/style/rule.js b/src/ol/style/rule.js
index 90e7ae8b00..14b054a3d3 100644
--- a/src/ol/style/rule.js
+++ b/src/ol/style/rule.js
@@ -1,5 +1,6 @@
goog.provide('ol.style.Rule');
+goog.require('ol.Feature');
goog.require('ol.filter.Filter');
goog.require('ol.style.Symbolizer');
@@ -32,3 +33,21 @@ ol.style.Rule = function(options) {
options.symbolizers : [];
};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @return {boolean} Does the rule apply to the feature?
+ */
+ol.style.Rule.prototype.applies = function(feature) {
+ return goog.isNull(this.filter_) ? true : this.filter_.applies(feature);
+};
+
+
+/**
+ * @return {Array.} Symbolizers.
+ */
+ol.style.Rule.prototype.getSymbolizers = function() {
+ return this.symbolizers_;
+};
+
diff --git a/src/ol/style/shape.js b/src/ol/style/shape.js
index e3007f5205..92c407c452 100644
--- a/src/ol/style/shape.js
+++ b/src/ol/style/shape.js
@@ -57,6 +57,19 @@ ol.style.ShapeLiteral = function(config) {
goog.inherits(ol.style.ShapeLiteral, ol.style.PointLiteral);
+/**
+ * @inheritDoc
+ */
+ol.style.ShapeLiteral.prototype.equals = function(shapeLiteral) {
+ return this.type == shapeLiteral.type &&
+ this.size == shapeLiteral.size &&
+ this.fillStyle == shapeLiteral.fillStyle &&
+ this.strokeStyle == shapeLiteral.strokeStyle &&
+ this.strokeWidth == shapeLiteral.strokeWidth &&
+ this.opacity == shapeLiteral.opacity;
+};
+
+
/**
* @typedef {{type: (ol.style.ShapeType),
* size: (number|ol.Expression),
diff --git a/src/ol/style/style.js b/src/ol/style/style.js
index 536c8dac6c..86271dcaf9 100644
--- a/src/ol/style/style.js
+++ b/src/ol/style/style.js
@@ -1,6 +1,9 @@
goog.provide('ol.style.Style');
+goog.require('ol.Feature');
+goog.require('ol.geom.GeometryType');
goog.require('ol.style.Rule');
+goog.require('ol.style.SymbolizerLiteral');
/**
@@ -23,3 +26,46 @@ ol.style.Style = function(options) {
this.rules_ = goog.isDef(options.rules) ? options.rules : [];
};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @return {Array.} Symbolizer literals for the
+ * feature.
+ */
+ol.style.Style.prototype.apply = function(feature) {
+ var rules = this.rules_,
+ literals = [],
+ rule, symbolizers;
+ 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));
+ }
+ }
+ }
+ return literals;
+};
+
+
+/**
+ * @param {ol.Feature} feature Feature.
+ * @return {Array.} Default symbolizer literals for
+ * the feature.
+ */
+ol.style.Style.applyDefaultStyle = function(feature) {
+ var type = feature.getGeometry().getType();
+ if (type === ol.geom.GeometryType.POINT ||
+ type === ol.geom.GeometryType.MULTIPOINT) {
+ return [ol.style.ShapeDefaults];
+ } else if (type === ol.geom.GeometryType.LINESTRING ||
+ type === ol.geom.GeometryType.MULTILINESTRING) {
+ return [ol.style.LineDefaults];
+ } else if (type === ol.geom.GeometryType.LINEARRING ||
+ type === ol.geom.GeometryType.POLYGON ||
+ type === ol.geom.GeometryType.MULTIPOLYGON) {
+ return [ol.style.PolygonDefaults];
+ }
+};
diff --git a/src/ol/style/symbolizer.js b/src/ol/style/symbolizer.js
index 72bda71e16..36bec5fbdc 100644
--- a/src/ol/style/symbolizer.js
+++ b/src/ol/style/symbolizer.js
@@ -11,6 +11,14 @@ goog.require('ol.Feature');
ol.style.SymbolizerLiteral = function() {};
+/**
+ * @param {ol.style.SymbolizerLiteral} symbolizerLiteral Symbolizer literal to
+ * compare to.
+ * @return {boolean} Is the passed symbolizer literal equal to this instance?
+ */
+ol.style.SymbolizerLiteral.prototype.equals = goog.abstractMethod;
+
+
/**
* @constructor