Giving vector layers the style they deserve
Now vector layers can have a style. ol.Style instances have an apply method to get the symbolizer literals for a feature. If the layer does not have a style defined, there is also a static applyDefaultStyle function on ol.Style to get the default symbolizer literals for a feature. The vector layer also got a groupFeaturesBySymbolizerLiteral method, which returns an array with features grouped by symbolizer, as needed by the canvas renderer.
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
goog.provide('ol.layer.Vector');
|
goog.provide('ol.layer.Vector');
|
||||||
|
|
||||||
|
goog.require('ol.Feature');
|
||||||
goog.require('ol.layer.Layer');
|
goog.require('ol.layer.Layer');
|
||||||
goog.require('ol.source.Vector');
|
goog.require('ol.source.Vector');
|
||||||
|
goog.require('ol.style.Style');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -12,6 +14,13 @@ goog.require('ol.source.Vector');
|
|||||||
*/
|
*/
|
||||||
ol.layer.Vector = function(layerOptions) {
|
ol.layer.Vector = function(layerOptions) {
|
||||||
goog.base(this, 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);
|
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() {
|
ol.layer.Vector.prototype.getVectorSource = function() {
|
||||||
return /** @type {ol.source.Vector} */ (this.getSource());
|
return /** @type {ol.source.Vector} */ (this.getSource());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array.<ol.Feature>} features Features.
|
||||||
|
* @return {Array.<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;
|
||||||
|
};
|
||||||
|
|||||||
@@ -14,10 +14,6 @@ goog.require('ol.geom.GeometryType');
|
|||||||
goog.require('ol.layer.Vector');
|
goog.require('ol.layer.Vector');
|
||||||
goog.require('ol.renderer.canvas.Layer');
|
goog.require('ol.renderer.canvas.Layer');
|
||||||
goog.require('ol.renderer.canvas.Renderer');
|
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');
|
goog.require('ol.tilegrid.TileGrid');
|
||||||
|
|
||||||
|
|
||||||
@@ -115,31 +111,6 @@ ol.renderer.canvas.VectorLayer = function(mapRenderer, layer) {
|
|||||||
this.dirty_ = false;
|
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
|
* @private
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
@@ -195,7 +166,8 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
|
|||||||
var view2DState = frameState.view2DState,
|
var view2DState = frameState.view2DState,
|
||||||
resolution = view2DState.resolution,
|
resolution = view2DState.resolution,
|
||||||
extent = frameState.extent,
|
extent = frameState.extent,
|
||||||
source = this.getVectorLayer().getVectorSource(),
|
layer = this.getVectorLayer(),
|
||||||
|
source = layer.getVectorSource(),
|
||||||
tileGrid = this.tileGrid_;
|
tileGrid = this.tileGrid_;
|
||||||
|
|
||||||
if (goog.isNull(tileGrid)) {
|
if (goog.isNull(tileGrid)) {
|
||||||
@@ -295,7 +267,8 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
|
|||||||
// render features by geometry type
|
// render features by geometry type
|
||||||
var filters = this.geometryFilters_,
|
var filters = this.geometryFilters_,
|
||||||
numFilters = filters.length,
|
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 (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
||||||
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
||||||
tileCoord = new ol.TileCoord(z, x, 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(
|
features = source.getFeatures(new ol.filter.Logical(
|
||||||
[geomFilter, extentFilter], ol.filter.LogicalOperator.AND));
|
[geomFilter, extentFilter], ol.filter.LogicalOperator.AND));
|
||||||
if (features.length) {
|
if (features.length) {
|
||||||
// TODO: layer.getSymbolizerLiterals(features) or similar
|
groups = layer.groupFeaturesBySymbolizerLiteral(features);
|
||||||
symbolizer = this.symbolizers_[type];
|
numGroups = groups.length;
|
||||||
sketchCanvasRenderer.renderFeaturesByGeometryType(
|
for (j = 0; j < numGroups; ++j) {
|
||||||
type, features, symbolizer);
|
group = groups[j];
|
||||||
|
sketchCanvasRenderer.renderFeaturesByGeometryType(type,
|
||||||
|
group[0], group[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,16 @@ ol.style.LineLiteral = function(config) {
|
|||||||
goog.inherits(ol.style.LineLiteral, ol.style.SymbolizerLiteral);
|
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),
|
* @typedef {{strokeStyle: (string|ol.Expression),
|
||||||
* strokeWidth: (number|ol.Expression),
|
* strokeWidth: (number|ol.Expression),
|
||||||
|
|||||||
@@ -41,6 +41,17 @@ ol.style.PolygonLiteral = function(config) {
|
|||||||
goog.inherits(ol.style.PolygonLiteral, ol.style.SymbolizerLiteral);
|
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),
|
* @typedef {{fillStyle: (string|ol.Expression),
|
||||||
* strokeStyle: (string|ol.Expression),
|
* strokeStyle: (string|ol.Expression),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
goog.provide('ol.style.Rule');
|
goog.provide('ol.style.Rule');
|
||||||
|
|
||||||
|
goog.require('ol.Feature');
|
||||||
goog.require('ol.filter.Filter');
|
goog.require('ol.filter.Filter');
|
||||||
goog.require('ol.style.Symbolizer');
|
goog.require('ol.style.Symbolizer');
|
||||||
|
|
||||||
@@ -32,3 +33,21 @@ ol.style.Rule = function(options) {
|
|||||||
options.symbolizers : [];
|
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.<ol.style.Symbolizer>} Symbolizers.
|
||||||
|
*/
|
||||||
|
ol.style.Rule.prototype.getSymbolizers = function() {
|
||||||
|
return this.symbolizers_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,19 @@ ol.style.ShapeLiteral = function(config) {
|
|||||||
goog.inherits(ol.style.ShapeLiteral, ol.style.PointLiteral);
|
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),
|
* @typedef {{type: (ol.style.ShapeType),
|
||||||
* size: (number|ol.Expression),
|
* size: (number|ol.Expression),
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
goog.provide('ol.style.Style');
|
goog.provide('ol.style.Style');
|
||||||
|
|
||||||
|
goog.require('ol.Feature');
|
||||||
|
goog.require('ol.geom.GeometryType');
|
||||||
goog.require('ol.style.Rule');
|
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 : [];
|
this.rules_ = goog.isDef(options.rules) ? options.rules : [];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ol.Feature} feature Feature.
|
||||||
|
* @return {Array.<ol.style.SymbolizerLiteral>} 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.<ol.style.SymbolizerLiteral>} 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];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -11,6 +11,14 @@ goog.require('ol.Feature');
|
|||||||
ol.style.SymbolizerLiteral = function() {};
|
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
|
* @constructor
|
||||||
|
|||||||
Reference in New Issue
Block a user