Merge pull request #1282 from tschaub/vector-source
Vector layer/source refactor.
This commit is contained in:
@@ -18,7 +18,7 @@ var raster = new ol.layer.Tile({
|
||||
});
|
||||
|
||||
var vector = new ol.layer.Vector({
|
||||
source: new ol.source.Vector({parser: null}),
|
||||
source: new ol.source.Vector(),
|
||||
style: new ol.style.Style({
|
||||
rules: [
|
||||
new ol.style.Rule({
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.Map');
|
||||
goog.require('ol.Overlay');
|
||||
goog.require('ol.OverlayPositioning');
|
||||
goog.require('ol.RendererHint');
|
||||
goog.require('ol.View2D');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.layer.Tile');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.parser.GeoJSON');
|
||||
goog.require('ol.source.TileJSON');
|
||||
goog.require('ol.source.Vector');
|
||||
goog.require('ol.style.Icon');
|
||||
@@ -18,22 +19,6 @@ var raster = new ol.layer.Tile({
|
||||
})
|
||||
});
|
||||
|
||||
var data = {
|
||||
type: 'FeatureCollection',
|
||||
features: [{
|
||||
type: 'Feature',
|
||||
properties: {
|
||||
name: 'Null Island',
|
||||
population: 4000,
|
||||
rainfall: 500
|
||||
},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [0, 0]
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
var style = new ol.style.Style({
|
||||
symbolizers: [
|
||||
new ol.style.Icon({
|
||||
@@ -45,8 +30,14 @@ var style = new ol.style.Style({
|
||||
|
||||
var vector = new ol.layer.Vector({
|
||||
source: new ol.source.Vector({
|
||||
parser: new ol.parser.GeoJSON(),
|
||||
data: data
|
||||
features: [
|
||||
new ol.Feature({
|
||||
name: 'Null Island',
|
||||
population: 4000,
|
||||
rainfall: 500,
|
||||
geometry: new ol.geom.Point([0, 0])
|
||||
})
|
||||
]
|
||||
}),
|
||||
style: style
|
||||
});
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.Map');
|
||||
goog.require('ol.RendererHint');
|
||||
goog.require('ol.View2D');
|
||||
goog.require('ol.control');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.parser.GeoJSON');
|
||||
goog.require('ol.proj');
|
||||
goog.require('ol.source.Vector');
|
||||
goog.require('ol.style.Fill');
|
||||
goog.require('ol.style.Rule');
|
||||
@@ -62,108 +63,60 @@ var style = new ol.style.Style({rules: [
|
||||
var vector = new ol.layer.Vector({
|
||||
style: style,
|
||||
source: new ol.source.Vector({
|
||||
data: {
|
||||
'type': 'FeatureCollection',
|
||||
'features': [{
|
||||
'type': 'Feature',
|
||||
'properties': {
|
||||
'color': '#BADA55',
|
||||
'where': 'inner'
|
||||
},
|
||||
'geometry': {
|
||||
'type': 'LineString',
|
||||
'coordinates': [[-10000000, -10000000], [10000000, 10000000]]
|
||||
}
|
||||
}, {
|
||||
'type': 'Feature',
|
||||
'properties': {
|
||||
'color': '#BADA55',
|
||||
'where': 'inner'
|
||||
},
|
||||
'geometry': {
|
||||
'type': 'LineString',
|
||||
'coordinates': [[-10000000, 10000000], [10000000, -10000000]]
|
||||
}
|
||||
}, {
|
||||
'type': 'Feature',
|
||||
'properties': {
|
||||
'color': '#013',
|
||||
'where': 'outer'
|
||||
},
|
||||
'geometry': {
|
||||
'type': 'LineString',
|
||||
'coordinates': [[-10000000, -10000000], [-10000000, 10000000]]
|
||||
}
|
||||
}, {
|
||||
'type': 'Feature',
|
||||
'properties': {
|
||||
'color': '#013',
|
||||
'where': 'outer'
|
||||
},
|
||||
'geometry': {
|
||||
'type': 'LineString',
|
||||
'coordinates': [[-10000000, 10000000], [10000000, 10000000]]
|
||||
}
|
||||
}, {
|
||||
'type': 'Feature',
|
||||
'properties': {
|
||||
'color': '#013',
|
||||
'where': 'outer'
|
||||
},
|
||||
'geometry': {
|
||||
'type': 'LineString',
|
||||
'coordinates': [[10000000, 10000000], [10000000, -10000000]]
|
||||
}
|
||||
}, {
|
||||
'type': 'Feature',
|
||||
'properties': {
|
||||
'color': '#013',
|
||||
'where': 'outer'
|
||||
},
|
||||
'geometry': {
|
||||
'type': 'LineString',
|
||||
'coordinates': [[10000000, -10000000], [-10000000, -10000000]]
|
||||
}
|
||||
}, {
|
||||
'type': 'Feature',
|
||||
'properties': {
|
||||
'label': 'South'
|
||||
},
|
||||
'geometry': {
|
||||
'type': 'Point',
|
||||
'coordinates': [0, -6000000]
|
||||
}
|
||||
}, {
|
||||
'type': 'Feature',
|
||||
'properties': {
|
||||
'label': 'West'
|
||||
},
|
||||
'geometry': {
|
||||
'type': 'Point',
|
||||
'coordinates': [-6000000, 0]
|
||||
}
|
||||
}, {
|
||||
'type': 'Feature',
|
||||
'properties': {
|
||||
'label': 'North'
|
||||
},
|
||||
'geometry': {
|
||||
'type': 'Point',
|
||||
'coordinates': [0, 6000000]
|
||||
}
|
||||
}, {
|
||||
'type': 'Feature',
|
||||
'properties': {
|
||||
'label': 'East'
|
||||
},
|
||||
'geometry': {
|
||||
'type': 'Point',
|
||||
'coordinates': [6000000, 0]
|
||||
}
|
||||
}]
|
||||
},
|
||||
parser: new ol.parser.GeoJSON(),
|
||||
projection: ol.proj.get('EPSG:3857')
|
||||
features: [
|
||||
new ol.Feature({
|
||||
color: '#BADA55',
|
||||
where: 'inner',
|
||||
geometry: new ol.geom.LineString(
|
||||
[[-10000000, -10000000], [10000000, 10000000]])
|
||||
}),
|
||||
new ol.Feature({
|
||||
color: '#BADA55',
|
||||
where: 'inner',
|
||||
geometry: new ol.geom.LineString(
|
||||
[[-10000000, 10000000], [10000000, -10000000]])
|
||||
}),
|
||||
new ol.Feature({
|
||||
color: '#013',
|
||||
where: 'outer',
|
||||
geometry: new ol.geom.LineString(
|
||||
[[-10000000, -10000000], [-10000000, 10000000]])
|
||||
}),
|
||||
new ol.Feature({
|
||||
color: '#013',
|
||||
where: 'outer',
|
||||
geometry: new ol.geom.LineString(
|
||||
[[-10000000, 10000000], [10000000, 10000000]])
|
||||
}),
|
||||
new ol.Feature({
|
||||
color: '#013',
|
||||
where: 'outer',
|
||||
geometry: new ol.geom.LineString(
|
||||
[[10000000, 10000000], [10000000, -10000000]])
|
||||
}),
|
||||
new ol.Feature({
|
||||
color: '#013',
|
||||
where: 'outer',
|
||||
geometry: new ol.geom.LineString(
|
||||
[[10000000, -10000000], [-10000000, -10000000]])
|
||||
}),
|
||||
new ol.Feature({
|
||||
label: 'South',
|
||||
geometry: new ol.geom.Point([0, -6000000])
|
||||
}),
|
||||
new ol.Feature({
|
||||
label: 'West',
|
||||
geometry: new ol.geom.Point([-6000000, 0])
|
||||
}),
|
||||
new ol.Feature({
|
||||
label: 'North',
|
||||
geometry: new ol.geom.Point([0, 6000000])
|
||||
}),
|
||||
new ol.Feature({
|
||||
label: 'East',
|
||||
geometry: new ol.geom.Point([6000000, 0])
|
||||
})
|
||||
]
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
@@ -718,16 +718,19 @@
|
||||
/**
|
||||
* @typedef {Object} ol.source.VectorOptions
|
||||
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
|
||||
* @property {Object|string|undefined} data Data to parse.
|
||||
* @property {Array.<ol.Feature>|undefined} features Any features to be added
|
||||
* to the source. Providing features is an alternative to providing
|
||||
* `url` and `parser` options.
|
||||
* @property {ol.Extent|undefined} extent Extent.
|
||||
* @property {string|undefined} logo Logo.
|
||||
* @property {ol.parser.Parser} parser Parser instance to parse data
|
||||
* provided as `data` or fetched from `url`.
|
||||
* @property {ol.parser.Parser|undefined} parser Parser instance to parse data
|
||||
* fetched from `url`.
|
||||
* @property {ol.proj.ProjectionLike|undefined} projection Projection. Usually the
|
||||
* projection is provided by the parser, so this only needs to be set if
|
||||
* the parser does not know the SRS (e.g. in some GML flavors), or if the
|
||||
* projection determined by the parser needs to be overridden.
|
||||
* @property {string|undefined} url Server url providing the vector data.
|
||||
* @property {string|undefined} url Server url providing the vector data. If
|
||||
* provided, the `parser` option must also be supplied.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
goog.provide('ol.Feature');
|
||||
goog.provide('ol.FeatureEvent');
|
||||
goog.provide('ol.FeatureEventType');
|
||||
goog.provide('ol.FeatureRenderIntent');
|
||||
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.Event');
|
||||
@@ -8,7 +9,6 @@ goog.require('goog.events.EventType');
|
||||
goog.require('ol.Object');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.geom.GeometryEvent');
|
||||
goog.require('ol.layer.VectorLayerRenderIntent');
|
||||
|
||||
|
||||
|
||||
@@ -51,10 +51,10 @@ ol.Feature = function(opt_values) {
|
||||
|
||||
/**
|
||||
* The render intent for this feature.
|
||||
* @type {ol.layer.VectorLayerRenderIntent|string}
|
||||
* @type {ol.FeatureRenderIntent|string}
|
||||
* @private
|
||||
*/
|
||||
this.renderIntent_ = ol.layer.VectorLayerRenderIntent.DEFAULT;
|
||||
this.renderIntent_ = ol.FeatureRenderIntent.DEFAULT;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.style.Symbolizer>}
|
||||
@@ -247,6 +247,18 @@ ol.Feature.prototype.setSymbolizers = function(symbolizers) {
|
||||
ol.Feature.DEFAULT_GEOMETRY = 'geometry';
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.FeatureRenderIntent = {
|
||||
DEFAULT: 'default',
|
||||
FUTURE: 'future',
|
||||
HIDDEN: 'hidden',
|
||||
SELECTED: 'selected',
|
||||
TEMPORARY: 'temporary'
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
|
||||
@@ -4,6 +4,7 @@ goog.require('goog.asserts');
|
||||
|
||||
goog.require('ol.Coordinate');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.FeatureRenderIntent');
|
||||
goog.require('ol.Map');
|
||||
goog.require('ol.MapBrowserEvent');
|
||||
goog.require('ol.MapBrowserEvent.EventType');
|
||||
@@ -16,7 +17,6 @@ goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.interaction.Interaction');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.layer.VectorLayerRenderIntent');
|
||||
goog.require('ol.source.Vector');
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ ol.interaction.Draw.prototype.setMap = function(map) {
|
||||
if (!goog.isNull(map)) {
|
||||
if (goog.isNull(this.sketchLayer_)) {
|
||||
var layer = new ol.layer.Vector({
|
||||
source: new ol.source.Vector({parser: null}),
|
||||
source: new ol.source.Vector(),
|
||||
style: this.layer_.getStyle()
|
||||
});
|
||||
layer.setTemporary(true);
|
||||
@@ -233,7 +233,7 @@ ol.interaction.Draw.prototype.startDrawing_ = function(event) {
|
||||
var start = event.getCoordinate();
|
||||
this.finishCoordinate_ = start;
|
||||
var sketchFeature = new ol.Feature();
|
||||
sketchFeature.setRenderIntent(ol.layer.VectorLayerRenderIntent.SELECTED);
|
||||
sketchFeature.setRenderIntent(ol.FeatureRenderIntent.SELECTED);
|
||||
var features = [sketchFeature];
|
||||
var geometry;
|
||||
if (this.mode_ === ol.interaction.DrawMode.POINT) {
|
||||
@@ -242,7 +242,7 @@ ol.interaction.Draw.prototype.startDrawing_ = function(event) {
|
||||
var sketchPoint = new ol.Feature({
|
||||
geom: new ol.geom.Point(start.slice())
|
||||
});
|
||||
sketchPoint.setRenderIntent(ol.layer.VectorLayerRenderIntent.TEMPORARY);
|
||||
sketchPoint.setRenderIntent(ol.FeatureRenderIntent.TEMPORARY);
|
||||
this.sketchPoint_ = sketchPoint;
|
||||
features.push(sketchPoint);
|
||||
|
||||
@@ -256,7 +256,7 @@ ol.interaction.Draw.prototype.startDrawing_ = function(event) {
|
||||
sketchFeature.setGeometry(geometry);
|
||||
this.sketchFeature_ = sketchFeature;
|
||||
|
||||
this.sketchLayer_.addFeatures(features);
|
||||
this.sketchLayer_.getVectorSource().addFeatures(features);
|
||||
};
|
||||
|
||||
|
||||
@@ -325,7 +325,7 @@ ol.interaction.Draw.prototype.addToDrawing_ = function(event) {
|
||||
ol.interaction.Draw.prototype.finishDrawing_ = function(event) {
|
||||
var sketchFeature = this.abortDrawing_();
|
||||
goog.asserts.assert(!goog.isNull(sketchFeature));
|
||||
sketchFeature.setRenderIntent(ol.layer.VectorLayerRenderIntent.DEFAULT);
|
||||
sketchFeature.setRenderIntent(ol.FeatureRenderIntent.DEFAULT);
|
||||
var geometry = sketchFeature.getGeometry();
|
||||
var coordinates = geometry.getCoordinates();
|
||||
if (this.mode_ === ol.interaction.DrawMode.LINESTRING) {
|
||||
@@ -344,7 +344,7 @@ ol.interaction.Draw.prototype.finishDrawing_ = function(event) {
|
||||
} else if (this.type_ === ol.geom.GeometryType.MULTIPOLYGON) {
|
||||
sketchFeature.setGeometry(new ol.geom.MultiPolygon([coordinates]));
|
||||
}
|
||||
this.layer_.addFeatures([sketchFeature]);
|
||||
this.layer_.getVectorSource().addFeatures([sketchFeature]);
|
||||
};
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@ ol.interaction.Draw.prototype.abortDrawing_ = function() {
|
||||
features.push(this.sketchPoint_);
|
||||
this.sketchPoint_ = null;
|
||||
}
|
||||
this.sketchLayer_.removeFeatures(features);
|
||||
this.sketchLayer_.getVectorSource().removeFeatures(features);
|
||||
}
|
||||
return sketchFeature;
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ goog.require('goog.events');
|
||||
goog.require('goog.functions');
|
||||
goog.require('ol.CollectionEventType');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.FeatureRenderIntent');
|
||||
goog.require('ol.MapBrowserEvent.EventType');
|
||||
goog.require('ol.ViewHint');
|
||||
goog.require('ol.coordinate');
|
||||
@@ -18,9 +19,8 @@ goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.interaction.Drag');
|
||||
goog.require('ol.layer.Layer');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.layer.VectorEventType');
|
||||
goog.require('ol.layer.VectorLayerRenderIntent');
|
||||
goog.require('ol.source.Vector');
|
||||
goog.require('ol.source.VectorEventType');
|
||||
goog.require('ol.structs.RBush');
|
||||
|
||||
|
||||
@@ -59,6 +59,13 @@ ol.interaction.Modify = function(opt_options) {
|
||||
*/
|
||||
this.layerFilter_ = layerFilter;
|
||||
|
||||
/**
|
||||
* Layer lookup. Keys source id to layer.
|
||||
* @type {Object.<number, ol.layer.Vector>}
|
||||
* @private
|
||||
*/
|
||||
this.layerLookup_ = null;
|
||||
|
||||
/**
|
||||
* Temporary sketch layer.
|
||||
* @type {ol.layer.Vector}
|
||||
@@ -121,12 +128,13 @@ ol.interaction.Modify.prototype.setMap = function(map) {
|
||||
}
|
||||
|
||||
if (!goog.isNull(map)) {
|
||||
this.layerLookup_ = {};
|
||||
if (goog.isNull(this.rBush_)) {
|
||||
this.rBush_ = new ol.structs.RBush();
|
||||
}
|
||||
if (goog.isNull(this.sketchLayer_)) {
|
||||
var sketchLayer = new ol.layer.Vector({
|
||||
source: new ol.source.Vector({parser: null})
|
||||
source: new ol.source.Vector()
|
||||
});
|
||||
this.sketchLayer_ = sketchLayer;
|
||||
sketchLayer.setTemporary(true);
|
||||
@@ -141,6 +149,7 @@ ol.interaction.Modify.prototype.setMap = function(map) {
|
||||
false, this);
|
||||
} else {
|
||||
// removing from a map, clean up
|
||||
this.layerLookup_ = null;
|
||||
this.rBush_ = null;
|
||||
this.sketchLayer_ = null;
|
||||
}
|
||||
@@ -168,9 +177,11 @@ ol.interaction.Modify.prototype.handleLayerAdded_ = function(evt) {
|
||||
ol.interaction.Modify.prototype.addLayer_ = function(layer) {
|
||||
if (this.layerFilter_(layer) && layer instanceof ol.layer.Vector &&
|
||||
!layer.getTemporary()) {
|
||||
this.addIndex_(layer.getFeatures(ol.layer.Vector.selectedFeaturesFilter),
|
||||
var source = layer.getVectorSource();
|
||||
this.layerLookup_[goog.getUid(source)] = layer;
|
||||
this.addIndex_(source.getFeatures(ol.layer.Vector.selectedFeaturesFilter),
|
||||
layer);
|
||||
goog.events.listen(layer, ol.layer.VectorEventType.INTENTCHANGE,
|
||||
goog.events.listen(source, ol.source.VectorEventType.INTENTCHANGE,
|
||||
this.handleIntentChange_, false, this);
|
||||
}
|
||||
};
|
||||
@@ -195,9 +206,11 @@ ol.interaction.Modify.prototype.handleLayerRemoved_ = function(evt) {
|
||||
ol.interaction.Modify.prototype.removeLayer_ = function(layer) {
|
||||
if (this.layerFilter_(layer) && layer instanceof ol.layer.Vector &&
|
||||
!layer.getTemporary()) {
|
||||
var source = layer.getVectorSource();
|
||||
delete this.layerLookup_[goog.getUid(source)];
|
||||
this.removeIndex_(
|
||||
layer.getFeatures(ol.layer.Vector.selectedFeaturesFilter));
|
||||
goog.events.unlisten(layer, ol.layer.VectorEventType.INTENTCHANGE,
|
||||
source.getFeatures(ol.layer.Vector.selectedFeaturesFilter));
|
||||
goog.events.unlisten(source, ol.source.VectorEventType.INTENTCHANGE,
|
||||
this.handleIntentChange_, false, this);
|
||||
}
|
||||
};
|
||||
@@ -248,17 +261,19 @@ ol.interaction.Modify.prototype.removeIndex_ = function(features) {
|
||||
|
||||
/**
|
||||
* Listen for feature additions.
|
||||
* @param {ol.layer.VectorEvent} evt Event object.
|
||||
* @param {ol.source.VectorEvent} evt Event object.
|
||||
* @private
|
||||
*/
|
||||
ol.interaction.Modify.prototype.handleIntentChange_ = function(evt) {
|
||||
var layer = evt.target;
|
||||
var source = evt.target;
|
||||
goog.asserts.assertInstanceof(source, ol.source.Vector);
|
||||
var layer = this.layerLookup_[goog.getUid(source)];
|
||||
goog.asserts.assertInstanceof(layer, ol.layer.Vector);
|
||||
var features = evt.features;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
var feature = features[i];
|
||||
var renderIntent = feature.getRenderIntent();
|
||||
if (renderIntent == ol.layer.VectorLayerRenderIntent.SELECTED) {
|
||||
if (renderIntent == ol.FeatureRenderIntent.SELECTED) {
|
||||
this.addIndex_([feature], layer);
|
||||
} else {
|
||||
this.removeIndex_([feature]);
|
||||
@@ -322,7 +337,7 @@ ol.interaction.Modify.prototype.createOrUpdateVertexFeature_ =
|
||||
if (goog.isNull(vertexFeature)) {
|
||||
vertexFeature = new ol.Feature({g: new ol.geom.Point(coordinates)});
|
||||
this.vertexFeature_ = vertexFeature;
|
||||
this.sketchLayer_.addFeatures([vertexFeature]);
|
||||
this.sketchLayer_.getVectorSource().addFeatures([vertexFeature]);
|
||||
} else {
|
||||
var geometry = vertexFeature.getGeometry();
|
||||
geometry.setCoordinates(coordinates);
|
||||
@@ -341,7 +356,7 @@ ol.interaction.Modify.prototype.handleDragStart = function(evt) {
|
||||
this.dragSegments_ = [];
|
||||
var vertexFeature = this.vertexFeature_;
|
||||
if (!goog.isNull(vertexFeature) && vertexFeature.getRenderIntent() !=
|
||||
ol.layer.VectorLayerRenderIntent.HIDDEN) {
|
||||
ol.FeatureRenderIntent.HIDDEN) {
|
||||
var renderIntent = vertexFeature.getRenderIntent();
|
||||
var insertVertices = [];
|
||||
var vertex = vertexFeature.getGeometry().getCoordinates();
|
||||
@@ -360,7 +375,7 @@ ol.interaction.Modify.prototype.handleDragStart = function(evt) {
|
||||
original.setSymbolizers(feature.getSymbolizers());
|
||||
feature.setOriginal(original);
|
||||
}
|
||||
if (renderIntent == ol.layer.VectorLayerRenderIntent.TEMPORARY) {
|
||||
if (renderIntent == ol.FeatureRenderIntent.TEMPORARY) {
|
||||
if (ol.coordinate.equals(segment[0], vertex)) {
|
||||
dragSegments.push([node, 0]);
|
||||
} else if (ol.coordinate.equals(segment[1], vertex)) {
|
||||
@@ -455,7 +470,7 @@ ol.interaction.Modify.prototype.handleMouseMove_ = function(evt) {
|
||||
var vertexFeature = this.vertexFeature_;
|
||||
var rBush = this.rBush_;
|
||||
var nodes = rBush.getAllInExtent(box);
|
||||
var renderIntent = ol.layer.VectorLayerRenderIntent.HIDDEN;
|
||||
var renderIntent = ol.FeatureRenderIntent.HIDDEN;
|
||||
if (nodes.length > 0) {
|
||||
nodes.sort(sortByDistance);
|
||||
var node = nodes[0];
|
||||
@@ -469,10 +484,10 @@ ol.interaction.Modify.prototype.handleMouseMove_ = function(evt) {
|
||||
var squaredDist1 = ol.coordinate.squaredDistance(vertexPixel, pixel1);
|
||||
var squaredDist2 = ol.coordinate.squaredDistance(vertexPixel, pixel2);
|
||||
var dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
|
||||
renderIntent = ol.layer.VectorLayerRenderIntent.FUTURE;
|
||||
renderIntent = ol.FeatureRenderIntent.FUTURE;
|
||||
if (dist <= 10) {
|
||||
vertex = squaredDist1 > squaredDist2 ? segment[1] : segment[0];
|
||||
renderIntent = ol.layer.VectorLayerRenderIntent.TEMPORARY;
|
||||
renderIntent = ol.FeatureRenderIntent.TEMPORARY;
|
||||
}
|
||||
vertexFeature = this.createOrUpdateVertexFeature_(node.style, vertex);
|
||||
this.modifiable_ = true;
|
||||
|
||||
@@ -3,11 +3,11 @@ goog.provide('ol.interaction.Select');
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.FeatureRenderIntent');
|
||||
goog.require('ol.events.ConditionType');
|
||||
goog.require('ol.events.condition');
|
||||
goog.require('ol.interaction.Interaction');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.layer.VectorLayerRenderIntent');
|
||||
|
||||
|
||||
|
||||
@@ -97,21 +97,21 @@ ol.interaction.Select.prototype.select =
|
||||
}
|
||||
|
||||
var featuresToSelect = featuresByLayer[i];
|
||||
var selectedFeatures = layer.getFeatures(
|
||||
var selectedFeatures = layer.getVectorSource().getFeatures(
|
||||
ol.layer.Vector.selectedFeaturesFilter);
|
||||
if (clear) {
|
||||
for (var j = selectedFeatures.length - 1; j >= 0; --j) {
|
||||
selectedFeatures[j].setRenderIntent(
|
||||
ol.layer.VectorLayerRenderIntent.DEFAULT);
|
||||
ol.FeatureRenderIntent.DEFAULT);
|
||||
}
|
||||
}
|
||||
for (var j = featuresToSelect.length - 1; j >= 0; --j) {
|
||||
var feature = featuresToSelect[j];
|
||||
// TODO: Make toggle configurable
|
||||
feature.setRenderIntent(feature.getRenderIntent() ==
|
||||
ol.layer.VectorLayerRenderIntent.SELECTED ?
|
||||
ol.layer.VectorLayerRenderIntent.DEFAULT :
|
||||
ol.layer.VectorLayerRenderIntent.SELECTED);
|
||||
ol.FeatureRenderIntent.SELECTED ?
|
||||
ol.FeatureRenderIntent.DEFAULT :
|
||||
ol.FeatureRenderIntent.SELECTED);
|
||||
}
|
||||
// TODO: Dispatch an event with selectedFeatures and unselectedFeatures
|
||||
}
|
||||
|
||||
@@ -1,126 +1,14 @@
|
||||
goog.provide('ol.layer.Vector');
|
||||
goog.provide('ol.layer.VectorEventType');
|
||||
|
||||
goog.require('goog.array');
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.Event');
|
||||
goog.require('goog.object');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.FeatureEventType');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.FeatureRenderIntent');
|
||||
goog.require('ol.layer.Layer');
|
||||
goog.require('ol.layer.VectorLayerRenderIntent');
|
||||
goog.require('ol.proj');
|
||||
goog.require('ol.source.Vector');
|
||||
goog.require('ol.structs.RTree');
|
||||
goog.require('ol.source.VectorEventType');
|
||||
goog.require('ol.style');
|
||||
goog.require('ol.style.Style');
|
||||
goog.require('ol.style.TextLiteral');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
ol.layer.FeatureCache = function() {
|
||||
|
||||
/**
|
||||
* @type {Object.<string, ol.Feature>}
|
||||
* @private
|
||||
*/
|
||||
this.idLookup_;
|
||||
|
||||
/**
|
||||
* @type {ol.structs.RTree}
|
||||
* @private
|
||||
*/
|
||||
this.rTree_;
|
||||
|
||||
this.clear();
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clear the cache.
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.clear = function() {
|
||||
this.idLookup_ = {};
|
||||
this.rTree_ = new ol.structs.RTree();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add a feature to the cache.
|
||||
* @param {ol.Feature} feature Feature to be cached.
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.add = function(feature) {
|
||||
var id = goog.getUid(feature).toString(),
|
||||
geometry = feature.getGeometry();
|
||||
|
||||
this.idLookup_[id] = feature;
|
||||
|
||||
// index by bounding box
|
||||
if (!goog.isNull(geometry)) {
|
||||
this.rTree_.insert(geometry.getBounds(), feature);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Object.<string, ol.Feature>} Object of features, keyed by id.
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.getFeaturesObject = function() {
|
||||
return this.idLookup_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get all features whose bounding box intersects the provided extent.
|
||||
*
|
||||
* @param {ol.Extent} extent Bounding extent.
|
||||
* @return {Object.<string, ol.Feature>} Features.
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.getFeaturesObjectForExtent = function(extent) {
|
||||
return this.rTree_.searchReturningObject(extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get features by ids.
|
||||
* @param {Array.<string>} ids Array of (internal) identifiers.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
* @private
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.getFeaturesByIds_ = function(ids) {
|
||||
var len = ids.length,
|
||||
features = new Array(len),
|
||||
i;
|
||||
for (i = 0; i < len; ++i) {
|
||||
features[i] = this.idLookup_[ids[i]];
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove a feature from the cache.
|
||||
* @param {ol.Feature} feature Feature.
|
||||
* @param {ol.Extent=} opt_extent Optional extent (used when the current feature
|
||||
* extent is different than the one in the index).
|
||||
*/
|
||||
ol.layer.FeatureCache.prototype.remove = function(feature, opt_extent) {
|
||||
var id = goog.getUid(feature).toString(),
|
||||
geometry = feature.getGeometry();
|
||||
|
||||
delete this.idLookup_[id];
|
||||
// index by bounding box
|
||||
if (!goog.isNull(geometry)) {
|
||||
var extent = goog.isDef(opt_extent) ? opt_extent : geometry.getBounds();
|
||||
this.rTree_.remove(extent, feature);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -132,19 +20,15 @@ ol.layer.FeatureCache.prototype.remove = function(feature, opt_extent) {
|
||||
*/
|
||||
ol.layer.Vector = function(options) {
|
||||
|
||||
goog.base(this, /** @type {ol.layer.LayerOptions} */ (options));
|
||||
var baseOptions = /** @type {ol.layer.VectorLayerOptions} */
|
||||
(goog.object.clone(options));
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.style.Style}
|
||||
*/
|
||||
this.style_ = goog.isDef(options.style) ? options.style : null;
|
||||
|
||||
/**
|
||||
* @type {ol.layer.FeatureCache}
|
||||
* @private
|
||||
*/
|
||||
this.featureCache_ = new ol.layer.FeatureCache();
|
||||
delete baseOptions.style;
|
||||
|
||||
/**
|
||||
* @type {function(Array.<ol.Feature>):string}
|
||||
@@ -152,6 +36,7 @@ ol.layer.Vector = function(options) {
|
||||
*/
|
||||
this.transformFeatureInfo_ = goog.isDef(options.transformFeatureInfo) ?
|
||||
options.transformFeatureInfo : ol.layer.Vector.uidTransformFeatureInfo;
|
||||
delete baseOptions.transformFeatureInfo;
|
||||
|
||||
/**
|
||||
* True if this is a temporary layer.
|
||||
@@ -160,83 +45,11 @@ ol.layer.Vector = function(options) {
|
||||
*/
|
||||
this.temporary_ = false;
|
||||
|
||||
goog.base(this, /** @type {ol.layer.LayerOptions} */ (baseOptions));
|
||||
};
|
||||
goog.inherits(ol.layer.Vector, ol.layer.Layer);
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.Feature>} features Array of features.
|
||||
*/
|
||||
ol.layer.Vector.prototype.addFeatures = function(features) {
|
||||
var extent = ol.extent.createEmpty(),
|
||||
feature, geometry;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
this.featureCache_.add(feature);
|
||||
geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
ol.extent.extend(extent, geometry.getBounds());
|
||||
}
|
||||
goog.events.listen(feature, ol.FeatureEventType.CHANGE,
|
||||
this.handleFeatureChange_, false, this);
|
||||
goog.events.listen(feature, ol.FeatureEventType.INTENTCHANGE,
|
||||
this.handleIntentChange_, false, this);
|
||||
}
|
||||
this.dispatchEvent(new ol.layer.VectorEvent(ol.layer.VectorEventType.ADD,
|
||||
features, [extent]));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listener for feature change events.
|
||||
* @param {ol.FeatureEvent} evt The feature change event.
|
||||
* @private
|
||||
*/
|
||||
ol.layer.Vector.prototype.handleFeatureChange_ = function(evt) {
|
||||
goog.asserts.assertInstanceof(evt.target, ol.Feature);
|
||||
var feature = /** @type {ol.Feature} */ (evt.target);
|
||||
var extents = [];
|
||||
if (!goog.isNull(evt.oldExtent)) {
|
||||
extents.push(evt.oldExtent);
|
||||
}
|
||||
var geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
this.featureCache_.remove(feature, evt.oldExtent);
|
||||
this.featureCache_.add(feature);
|
||||
extents.push(geometry.getBounds());
|
||||
}
|
||||
this.dispatchEvent(new ol.layer.VectorEvent(ol.layer.VectorEventType.CHANGE,
|
||||
[feature], extents));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listener for render intent change events of features.
|
||||
* @param {ol.FeatureEvent} evt The feature intent change event.
|
||||
* @private
|
||||
*/
|
||||
ol.layer.Vector.prototype.handleIntentChange_ = function(evt) {
|
||||
goog.asserts.assertInstanceof(evt.target, ol.Feature);
|
||||
var feature = /** @type {ol.Feature} */ (evt.target);
|
||||
var geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
this.dispatchEvent(new ol.layer.VectorEvent(
|
||||
ol.layer.VectorEventType.INTENTCHANGE, [feature],
|
||||
[geometry.getBounds()]));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove all features from the layer.
|
||||
*/
|
||||
ol.layer.Vector.prototype.clear = function() {
|
||||
this.featureCache_.clear();
|
||||
this.dispatchEvent(
|
||||
new ol.layer.VectorEvent(ol.layer.VectorEventType.REMOVE, [], []));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {boolean} Whether this layer is temporary.
|
||||
*/
|
||||
@@ -267,165 +80,10 @@ ol.layer.Vector.prototype.getStyle = function() {
|
||||
*/
|
||||
ol.layer.Vector.prototype.setStyle = function(style) {
|
||||
this.style_ = style;
|
||||
this.dispatchEvent(
|
||||
new ol.layer.VectorEvent(ol.layer.VectorEventType.CHANGE, [], []));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of features that match a filter. This will not fetch data,
|
||||
* it only considers features that are loaded already.
|
||||
* @param {(function(ol.Feature):boolean)=} opt_filter Filter function.
|
||||
* @return {Array.<ol.Feature>} Features that match the filter, or all features
|
||||
* if no filter was provided.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getFeatures = function(opt_filter) {
|
||||
var result;
|
||||
var features = this.featureCache_.getFeaturesObject();
|
||||
if (goog.isDef(opt_filter)) {
|
||||
result = [];
|
||||
for (var f in features) {
|
||||
if (opt_filter(features[f]) === true) {
|
||||
result.push(features[f]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = goog.object.getValues(features);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get all features whose bounding box intersects the provided extent. This
|
||||
* method is intended for being called by the renderer. When null is returned,
|
||||
* the renderer should not waste time rendering, and `opt_callback` is
|
||||
* usually a function that requests a renderFrame, which will be called as soon
|
||||
* as the data for `extent` is available.
|
||||
*
|
||||
* @param {ol.Extent} extent Bounding extent.
|
||||
* @param {ol.proj.Projection} projection Target projection.
|
||||
* @param {Function=} opt_callback Callback to call when data is parsed.
|
||||
* @return {Object.<string, ol.Feature>} Features or null if source is loading
|
||||
* data for `extent`.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getFeaturesObjectForExtent = function(extent,
|
||||
projection, opt_callback) {
|
||||
var source = this.getSource();
|
||||
return source.prepareFeatures(this, extent, projection, opt_callback) ==
|
||||
ol.source.VectorLoadState.LOADING ?
|
||||
null :
|
||||
this.featureCache_.getFeaturesObjectForExtent(extent);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Object.<string, ol.Feature>} features Features.
|
||||
* @param {number} resolution Map resolution.
|
||||
* @return {Array.<Array>} symbolizers for features. Each array in this array
|
||||
* contains 3 items: an array of features, the symbolizer literal, and
|
||||
* an array with optional additional data for each feature.
|
||||
*/
|
||||
ol.layer.Vector.prototype.groupFeaturesBySymbolizerLiteral =
|
||||
function(features, resolution) {
|
||||
var uniqueLiterals = {},
|
||||
featuresBySymbolizer = [],
|
||||
style = this.style_,
|
||||
i, j, l, feature, symbolizers, literals, numLiterals, literal,
|
||||
uniqueLiteral, key, item;
|
||||
for (i in features) {
|
||||
feature = features[i];
|
||||
// feature level symbolizers take precedence
|
||||
symbolizers = feature.getSymbolizers();
|
||||
if (!goog.isNull(symbolizers)) {
|
||||
literals = ol.style.Style.createLiterals(symbolizers, feature);
|
||||
} else {
|
||||
// layer style second
|
||||
if (goog.isNull(style)) {
|
||||
style = ol.style.getDefault();
|
||||
}
|
||||
literals = style.createLiterals(feature, resolution);
|
||||
}
|
||||
numLiterals = literals.length;
|
||||
for (j = 0; j < numLiterals; ++j) {
|
||||
literal = literals[j];
|
||||
for (l in uniqueLiterals) {
|
||||
uniqueLiteral = featuresBySymbolizer[uniqueLiterals[l]][1];
|
||||
if (literal.equals(uniqueLiteral)) {
|
||||
literal = uniqueLiteral;
|
||||
break;
|
||||
}
|
||||
}
|
||||
key = goog.getUid(literal);
|
||||
if (!goog.object.containsKey(uniqueLiterals, key)) {
|
||||
uniqueLiterals[key] = featuresBySymbolizer.length;
|
||||
featuresBySymbolizer.push([
|
||||
/** @type {Array.<ol.Feature>} */ ([]),
|
||||
/** @type {ol.style.Literal} */ (literal),
|
||||
/** @type {Array} */ ([])
|
||||
]);
|
||||
}
|
||||
item = featuresBySymbolizer[uniqueLiterals[key]];
|
||||
item[0].push(feature);
|
||||
if (literal instanceof ol.style.TextLiteral) {
|
||||
item[2].push(literals[j].text);
|
||||
}
|
||||
}
|
||||
}
|
||||
featuresBySymbolizer.sort(this.sortByZIndex_);
|
||||
return featuresBySymbolizer;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Object|Element|Document|string} data Feature data.
|
||||
* @param {ol.parser.Parser} parser Feature parser.
|
||||
* @param {ol.proj.Projection} projection This sucks. The layer should be a
|
||||
* view in one projection.
|
||||
*/
|
||||
ol.layer.Vector.prototype.parseFeatures = function(data, parser, projection) {
|
||||
|
||||
var addFeatures = function(data) {
|
||||
var features = data.features;
|
||||
var sourceProjection = this.getSource().getProjection();
|
||||
if (goog.isNull(sourceProjection)) {
|
||||
sourceProjection = data.metadata.projection;
|
||||
}
|
||||
var transform = ol.proj.getTransform(sourceProjection, projection);
|
||||
var geometry = null;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
geometry = features[i].getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
geometry.transform(transform);
|
||||
}
|
||||
}
|
||||
this.addFeatures(features);
|
||||
};
|
||||
|
||||
var result;
|
||||
if (goog.isString(data)) {
|
||||
if (goog.isFunction(parser.readFeaturesFromStringAsync)) {
|
||||
parser.readFeaturesFromStringAsync(data, goog.bind(addFeatures, this));
|
||||
} else {
|
||||
goog.asserts.assert(
|
||||
goog.isFunction(parser.readFeaturesFromString),
|
||||
'Expected parser with a readFeaturesFromString method.');
|
||||
result = parser.readFeaturesFromString(data);
|
||||
addFeatures.call(this, result);
|
||||
}
|
||||
} else if (goog.isObject(data)) {
|
||||
if (goog.isFunction(parser.readFeaturesFromObjectAsync)) {
|
||||
parser.readFeaturesFromObjectAsync(data, goog.bind(addFeatures, this));
|
||||
} else {
|
||||
goog.asserts.assert(
|
||||
goog.isFunction(parser.readFeaturesFromObject),
|
||||
'Expected parser with a readFeaturesFromObject method.');
|
||||
result = parser.readFeaturesFromObject(data);
|
||||
addFeatures.call(this, result);
|
||||
}
|
||||
} else {
|
||||
// TODO: parse more data types
|
||||
throw new Error('Data type not supported: ' + data);
|
||||
var source = this.getVectorSource();
|
||||
if (source) {
|
||||
source.dispatchEvent(
|
||||
new ol.source.VectorEvent(ol.source.VectorEventType.CHANGE, [], []));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -438,30 +96,6 @@ ol.layer.Vector.prototype.getTransformFeatureInfo = function() {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove features from the layer.
|
||||
* @param {Array.<ol.Feature>} features Features to remove.
|
||||
*/
|
||||
ol.layer.Vector.prototype.removeFeatures = function(features) {
|
||||
var extent = ol.extent.createEmpty(),
|
||||
feature, geometry;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
this.featureCache_.remove(feature);
|
||||
geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
ol.extent.extend(extent, geometry.getBounds());
|
||||
}
|
||||
goog.events.unlisten(feature, ol.FeatureEventType.CHANGE,
|
||||
this.handleFeatureChange_, false, this);
|
||||
goog.events.unlisten(feature, ol.FeatureEventType.INTENTCHANGE,
|
||||
this.handleIntentChange_, false, this);
|
||||
}
|
||||
this.dispatchEvent(new ol.layer.VectorEvent(ol.layer.VectorEventType.REMOVE,
|
||||
features, [extent]));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {boolean} temporary Whether this layer is temporary.
|
||||
*/
|
||||
@@ -470,18 +104,6 @@ ol.layer.Vector.prototype.setTemporary = function(temporary) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sort function for `groupFeaturesBySymbolizerLiteral`.
|
||||
* @private
|
||||
* @param {Array} a 1st item for the sort comparison.
|
||||
* @param {Array} b 2nd item for the sort comparison.
|
||||
* @return {number} Comparison result.
|
||||
*/
|
||||
ol.layer.Vector.prototype.sortByZIndex_ = function(a, b) {
|
||||
return a[1].zIndex - b[1].zIndex;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Array.<ol.Feature>} features Features.
|
||||
* @return {string} Feature info.
|
||||
@@ -498,42 +120,5 @@ ol.layer.Vector.uidTransformFeatureInfo = function(features) {
|
||||
* @return {boolean} Whether the feature is selected.
|
||||
*/
|
||||
ol.layer.Vector.selectedFeaturesFilter = function(feature) {
|
||||
return feature.getRenderIntent() == ol.layer.VectorLayerRenderIntent.SELECTED;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {goog.events.Event}
|
||||
* @param {string} type Event type.
|
||||
* @param {Array.<ol.Feature>} features Features associated with the event.
|
||||
* @param {Array.<ol.Extent>} extents Any extents associated with the event.
|
||||
*/
|
||||
ol.layer.VectorEvent = function(type, features, extents) {
|
||||
|
||||
goog.base(this, type);
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.Feature>}
|
||||
*/
|
||||
this.features = features;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.Extent>}
|
||||
*/
|
||||
this.extents = extents;
|
||||
|
||||
};
|
||||
goog.inherits(ol.layer.VectorEvent, goog.events.Event);
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.layer.VectorEventType = {
|
||||
ADD: 'featureadd',
|
||||
CHANGE: 'featurechange',
|
||||
INTENTCHANGE: 'featureintentchange',
|
||||
REMOVE: 'featureremove'
|
||||
return feature.getRenderIntent() == ol.FeatureRenderIntent.SELECTED;
|
||||
};
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
goog.provide('ol.layer.VectorLayerRenderIntent');
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.layer.VectorLayerRenderIntent = {
|
||||
DEFAULT: 'default',
|
||||
FUTURE: 'future',
|
||||
HIDDEN: 'hidden',
|
||||
SELECTED: 'selected',
|
||||
TEMPORARY: 'temporary'
|
||||
};
|
||||
@@ -1,11 +1,13 @@
|
||||
goog.provide('ol.renderer.canvas.VectorLayer');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.async.nextTick');
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.dom.TagName');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.object');
|
||||
goog.require('goog.vec.Mat4');
|
||||
goog.require('ol.FeatureRenderIntent');
|
||||
goog.require('ol.Pixel');
|
||||
goog.require('ol.TileCache');
|
||||
goog.require('ol.TileCoord');
|
||||
@@ -14,10 +16,10 @@ goog.require('ol.ViewHint');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.layer.VectorEventType');
|
||||
goog.require('ol.layer.VectorLayerRenderIntent');
|
||||
goog.require('ol.renderer.canvas.Layer');
|
||||
goog.require('ol.renderer.canvas.Vector');
|
||||
goog.require('ol.source.VectorEventType');
|
||||
goog.require('ol.style');
|
||||
goog.require('ol.tilegrid.TileGrid');
|
||||
|
||||
|
||||
@@ -88,13 +90,16 @@ ol.renderer.canvas.VectorLayer = function(mapRenderer, layer) {
|
||||
*/
|
||||
this.tileCache_ = new ol.TileCache(
|
||||
ol.renderer.canvas.VectorLayer.TILECACHE_SIZE);
|
||||
goog.events.listen(layer, [
|
||||
ol.layer.VectorEventType.ADD,
|
||||
ol.layer.VectorEventType.CHANGE,
|
||||
ol.layer.VectorEventType.REMOVE,
|
||||
ol.layer.VectorEventType.INTENTCHANGE
|
||||
|
||||
var source = layer.getSource();
|
||||
goog.events.listen(source, [
|
||||
ol.source.VectorEventType.LOAD,
|
||||
ol.source.VectorEventType.ADD,
|
||||
ol.source.VectorEventType.CHANGE,
|
||||
ol.source.VectorEventType.REMOVE,
|
||||
ol.source.VectorEventType.INTENTCHANGE
|
||||
],
|
||||
this.handleLayerChange_, false, this);
|
||||
this.handleSourceChange_, false, this);
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -243,12 +248,13 @@ ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel =
|
||||
function(pixel, success, opt_error) {
|
||||
// TODO What do we want to pass to the error callback?
|
||||
var map = this.getMap();
|
||||
var result = [];
|
||||
var features = [];
|
||||
|
||||
var layer = this.getLayer();
|
||||
var source = this.getVectorLayer().getSource();
|
||||
var location = map.getCoordinateFromPixel(pixel);
|
||||
var tileCoord = this.tileGrid_.getTileCoordForCoordAndZ(location, 0);
|
||||
var key = tileCoord.toString();
|
||||
|
||||
if (this.tileCache_.containsKey(key)) {
|
||||
var cachedTile = this.tileCache_.get(key);
|
||||
var symbolSizes = cachedTile[1];
|
||||
@@ -258,24 +264,15 @@ ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel =
|
||||
var halfMaxHeight = maxSymbolSize[1] / 2;
|
||||
var locationMin = [location[0] - halfMaxWidth, location[1] - halfMaxHeight];
|
||||
var locationMax = [location[0] + halfMaxWidth, location[1] + halfMaxHeight];
|
||||
var locationBbox = ol.extent.boundingExtent([locationMin, locationMax]);
|
||||
var candidates = layer.getFeaturesObjectForExtent(locationBbox,
|
||||
map.getView().getView2D().getProjection());
|
||||
if (goog.isNull(candidates)) {
|
||||
// data is not loaded
|
||||
if (goog.isDef(opt_error)) {
|
||||
goog.global.setTimeout(function() { opt_error(); }, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
var extent = ol.extent.boundingExtent([locationMin, locationMax]);
|
||||
var projection = map.getView().getView2D().getProjection();
|
||||
|
||||
var candidate, geom, type, symbolBounds, symbolSize, symbolOffset,
|
||||
halfWidth, halfHeight, uid, coordinates, j;
|
||||
for (var id in candidates) {
|
||||
candidate = candidates[id];
|
||||
if (candidate.getRenderIntent() ==
|
||||
ol.layer.VectorLayerRenderIntent.HIDDEN) {
|
||||
continue;
|
||||
source.forEachFeatureInExtent(extent, projection, function(candidate) {
|
||||
var geom, type, symbolBounds, symbolSize, symbolOffset,
|
||||
halfWidth, halfHeight, uid, coordinates, j;
|
||||
|
||||
if (candidate.getRenderIntent() == ol.FeatureRenderIntent.HIDDEN) {
|
||||
return;
|
||||
}
|
||||
geom = candidate.getGeometry();
|
||||
type = geom.getType();
|
||||
@@ -300,34 +297,38 @@ ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel =
|
||||
}
|
||||
for (j = coordinates.length - 1; j >= 0; --j) {
|
||||
if (ol.extent.containsCoordinate(symbolBounds, coordinates[j])) {
|
||||
result.push(candidate);
|
||||
features.push(candidate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (goog.isFunction(geom.containsCoordinate)) {
|
||||
// For polygons, check if the pixel location is inside the polygon
|
||||
if (geom.containsCoordinate(location)) {
|
||||
result.push(candidate);
|
||||
features.push(candidate);
|
||||
}
|
||||
} else if (goog.isFunction(geom.distanceFromCoordinate)) {
|
||||
// For lines, check if the distance to the pixel location is
|
||||
// within the rendered line width
|
||||
if (2 * geom.distanceFromCoordinate(location) <=
|
||||
symbolSizes[goog.getUid(candidate)][0]) {
|
||||
result.push(candidate);
|
||||
features.push(candidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
goog.global.setTimeout(function() { success(result, layer); }, 0);
|
||||
var layer = this.getLayer();
|
||||
goog.async.nextTick(function() {
|
||||
success(features, layer);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.layer.VectorEvent} event Vector layer event.
|
||||
* @param {ol.source.VectorEvent} event Vector layer event.
|
||||
* @private
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer.prototype.handleLayerChange_ = function(event) {
|
||||
ol.renderer.canvas.VectorLayer.prototype.handleSourceChange_ = function(event) {
|
||||
if (goog.isDef(this.renderedResolution_)) {
|
||||
this.expireTiles_(event.extents);
|
||||
}
|
||||
@@ -348,7 +349,6 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
|
||||
resolution = view2DState.resolution,
|
||||
projection = view2DState.projection,
|
||||
extent = frameState.extent,
|
||||
layer = this.getVectorLayer(),
|
||||
tileGrid = this.tileGrid_,
|
||||
tileSize = [512, 512],
|
||||
idle = !frameState.viewHints[ol.ViewHint.ANIMATING] &&
|
||||
@@ -424,6 +424,15 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
|
||||
this.tileArchetype_.height = tileSize[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Let the source to know what data extent we want loaded. As there may
|
||||
* already be features loaded, we continue with rendering after this request.
|
||||
* If this results in loading new features, a new rendering will be triggered.
|
||||
*/
|
||||
var layer = this.getVectorLayer();
|
||||
var source = layer.getVectorSource();
|
||||
source.load(tileRangeExtent, projection);
|
||||
|
||||
/**
|
||||
* Prepare the sketch canvas. This covers the currently visible tile range
|
||||
* and will have rendered all newly visible features.
|
||||
@@ -469,10 +478,9 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
|
||||
// TODO make gutter configurable?
|
||||
var tileGutter = 15 * tileResolution;
|
||||
var tile, tileCoord, key, x, y, i, type;
|
||||
var deferred = false;
|
||||
var dirty = false;
|
||||
var tileExtent, groups, group, j, numGroups, featuresObject, tileHasFeatures;
|
||||
fetchTileData:
|
||||
var tileExtent, featuresObject, tileHasFeatures;
|
||||
|
||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
||||
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
||||
tileCoord = new ol.TileCoord(0, x, y);
|
||||
@@ -486,15 +494,11 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
|
||||
tileExtent[1] -= tileGutter;
|
||||
tileExtent[3] += tileGutter;
|
||||
tileHasFeatures = false;
|
||||
featuresObject = layer.getFeaturesObjectForExtent(tileExtent,
|
||||
projection, this.requestMapRenderFrame_);
|
||||
if (goog.isNull(featuresObject)) {
|
||||
deferred = true;
|
||||
break fetchTileData;
|
||||
}
|
||||
tileHasFeatures = tileHasFeatures ||
|
||||
!goog.object.isEmpty(featuresObject);
|
||||
goog.object.extend(featuresToRender, featuresObject);
|
||||
source.forEachFeatureInExtent(
|
||||
tileExtent, projection, function(feature) {
|
||||
featuresToRender[goog.getUid(feature)] = feature;
|
||||
tileHasFeatures = true;
|
||||
});
|
||||
if (tileHasFeatures) {
|
||||
tilesOnSketchCanvas[key] = tileCoord;
|
||||
}
|
||||
@@ -505,10 +509,16 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
|
||||
}
|
||||
this.dirty_ = dirty;
|
||||
|
||||
groups = layer.groupFeaturesBySymbolizerLiteral(featuresToRender,
|
||||
tileResolution);
|
||||
numGroups = groups.length;
|
||||
for (j = 0; j < numGroups; ++j) {
|
||||
var style = layer.getStyle();
|
||||
if (goog.isNull(style)) {
|
||||
style = ol.style.getDefault();
|
||||
}
|
||||
var groups = style.groupFeaturesBySymbolizerLiteral(
|
||||
featuresToRender, tileResolution);
|
||||
var numGroups = groups.length;
|
||||
var deferred = false;
|
||||
var group;
|
||||
for (var j = 0; j < numGroups; ++j) {
|
||||
group = groups[j];
|
||||
deferred = sketchCanvasRenderer.renderFeatures(group[0], group[1],
|
||||
group[2]);
|
||||
|
||||
@@ -8,6 +8,7 @@ goog.require('goog.events');
|
||||
goog.require('goog.events.EventType');
|
||||
goog.require('goog.vec.Mat4');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.FeatureRenderIntent');
|
||||
goog.require('ol.geom.AbstractCollection');
|
||||
goog.require('ol.geom.Geometry');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
@@ -17,7 +18,6 @@ goog.require('ol.geom.MultiPoint');
|
||||
goog.require('ol.geom.MultiPolygon');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.layer.VectorLayerRenderIntent');
|
||||
goog.require('ol.style.IconLiteral');
|
||||
goog.require('ol.style.LineLiteral');
|
||||
goog.require('ol.style.Literal');
|
||||
@@ -160,7 +160,7 @@ ol.renderer.canvas.Vector.prototype.renderLineStringFeatures_ =
|
||||
context.beginPath();
|
||||
for (i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
if (feature.getRenderIntent() == ol.layer.VectorLayerRenderIntent.HIDDEN) {
|
||||
if (feature.getRenderIntent() == ol.FeatureRenderIntent.HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
id = goog.getUid(feature);
|
||||
@@ -249,7 +249,7 @@ ol.renderer.canvas.Vector.prototype.renderPointFeatures_ =
|
||||
context.globalAlpha = alpha;
|
||||
for (i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
if (feature.getRenderIntent() == ol.layer.VectorLayerRenderIntent.HIDDEN) {
|
||||
if (feature.getRenderIntent() == ol.FeatureRenderIntent.HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
id = goog.getUid(feature);
|
||||
@@ -325,7 +325,7 @@ ol.renderer.canvas.Vector.prototype.renderText_ =
|
||||
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
if (feature.getRenderIntent() == ol.layer.VectorLayerRenderIntent.HIDDEN) {
|
||||
if (feature.getRenderIntent() == ol.FeatureRenderIntent.HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
vecs = ol.renderer.canvas.Vector.getLabelVectors(
|
||||
@@ -393,7 +393,7 @@ ol.renderer.canvas.Vector.prototype.renderPolygonFeatures_ =
|
||||
context.beginPath();
|
||||
for (i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
if (feature.getRenderIntent() == ol.layer.VectorLayerRenderIntent.HIDDEN) {
|
||||
if (feature.getRenderIntent() == ol.FeatureRenderIntent.HIDDEN) {
|
||||
continue;
|
||||
}
|
||||
geometry = feature.getGeometry();
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
@exportClass ol.source.Vector ol.source.VectorOptions
|
||||
@exportProperty ol.source.Vector.prototype.addFeatures
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
goog.provide('ol.source.FeatureCache');
|
||||
goog.provide('ol.source.Vector');
|
||||
goog.provide('ol.source.VectorEventType');
|
||||
goog.provide('ol.source.VectorLoadState');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.async.nextTick');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.events.Event');
|
||||
goog.require('goog.net.XhrIo');
|
||||
goog.require('goog.object');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.FeatureEventType');
|
||||
goog.require('ol.extent');
|
||||
goog.require('ol.proj');
|
||||
goog.require('ol.source.Source');
|
||||
goog.require('ol.structs.RTree');
|
||||
|
||||
|
||||
/**
|
||||
@@ -20,22 +32,18 @@ ol.source.VectorLoadState = {
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.source.Source}
|
||||
* @param {ol.source.VectorOptions} options Vector source options.
|
||||
* @param {ol.source.VectorOptions=} opt_options Vector source options.
|
||||
* @todo stability experimental
|
||||
*/
|
||||
ol.source.Vector = function(options) {
|
||||
ol.source.Vector = function(opt_options) {
|
||||
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Object|string}
|
||||
*/
|
||||
this.data_ = goog.isDef(options.data) ? options.data : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.source.VectorLoadState}
|
||||
*/
|
||||
this.loadState_ = ol.source.VectorLoadState.IDLE;
|
||||
goog.base(this, {
|
||||
attributions: options.attributions,
|
||||
extent: options.extent,
|
||||
logo: options.logo,
|
||||
projection: options.projection
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -49,48 +57,377 @@ ol.source.Vector = function(options) {
|
||||
*/
|
||||
this.url_ = options.url;
|
||||
|
||||
goog.base(this, {
|
||||
attributions: options.attributions,
|
||||
extent: options.extent,
|
||||
logo: options.logo,
|
||||
projection: options.projection
|
||||
});
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.source.VectorLoadState}
|
||||
*/
|
||||
this.loadState_ = goog.isDef(this.url_) ?
|
||||
ol.source.VectorLoadState.IDLE : ol.source.VectorLoadState.LOADED;
|
||||
|
||||
/**
|
||||
* @type {ol.source.FeatureCache}
|
||||
* @private
|
||||
*/
|
||||
this.featureCache_ = new ol.source.FeatureCache();
|
||||
|
||||
// add any user provided features
|
||||
if (goog.isDef(options.features)) {
|
||||
this.addFeatures(options.features);
|
||||
}
|
||||
|
||||
};
|
||||
goog.inherits(ol.source.Vector, ol.source.Source);
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.layer.Vector} layer Layer that parses the data.
|
||||
* @param {ol.Extent} extent Extent that needs to be fetched.
|
||||
* @param {ol.proj.Projection} projection Projection of the view.
|
||||
* @param {function()=} opt_callback Callback which is called when features are
|
||||
* parsed after loading.
|
||||
* @return {ol.source.VectorLoadState} The current load state.
|
||||
* Request for new features to be loaded.
|
||||
* @param {ol.Extent} extent Desired extent.
|
||||
* @param {ol.proj.Projection} projection Desired projection.
|
||||
* @return {boolean} New features will be loaded.
|
||||
*/
|
||||
ol.source.Vector.prototype.prepareFeatures = function(layer, extent, projection,
|
||||
opt_callback) {
|
||||
// TODO: Implement strategies. BBOX aware strategies will need the extent.
|
||||
if (goog.isDef(this.url_) &&
|
||||
this.loadState_ == ol.source.VectorLoadState.IDLE) {
|
||||
ol.source.Vector.prototype.load = function(extent, projection) {
|
||||
var requested = false;
|
||||
if (this.loadState_ === ol.source.VectorLoadState.IDLE) {
|
||||
goog.asserts.assertString(this.url_);
|
||||
this.loadState_ = ol.source.VectorLoadState.LOADING;
|
||||
goog.net.XhrIo.send(this.url_, goog.bind(function(event) {
|
||||
var xhr = event.target;
|
||||
if (xhr.isSuccess()) {
|
||||
// TODO: Get source projection from data if supported by parser.
|
||||
layer.parseFeatures(xhr.getResponseText(), this.parser_, projection);
|
||||
this.loadState_ = ol.source.VectorLoadState.LOADED;
|
||||
if (goog.isDef(opt_callback)) {
|
||||
opt_callback();
|
||||
}
|
||||
// parsing may be asynchronous, so we don't set load state here
|
||||
this.parseFeaturesString_(xhr.getResponseText(), projection);
|
||||
} else {
|
||||
// TODO: Error handling.
|
||||
this.loadState_ = ol.source.VectorLoadState.ERROR;
|
||||
}
|
||||
}, this));
|
||||
} else if (!goog.isNull(this.data_)) {
|
||||
layer.parseFeatures(this.data_, this.parser_, projection);
|
||||
this.data_ = null;
|
||||
this.loadState_ = ol.source.VectorLoadState.LOADED;
|
||||
requested = true;
|
||||
}
|
||||
return requested;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse features from a string.
|
||||
* @param {string} data Feature data.
|
||||
* @param {ol.proj.Projection} projection The target projection.
|
||||
* @private
|
||||
*/
|
||||
ol.source.Vector.prototype.parseFeaturesString_ = function(data, projection) {
|
||||
if (goog.isFunction(this.parser_.readFeaturesFromStringAsync)) {
|
||||
this.parser_.readFeaturesFromStringAsync(data, goog.bind(function(result) {
|
||||
this.handleReadResult_(result, projection);
|
||||
}, this));
|
||||
} else {
|
||||
goog.asserts.assert(
|
||||
goog.isFunction(this.parser_.readFeaturesFromString),
|
||||
'Expected parser with a readFeaturesFromString method.');
|
||||
this.handleReadResult_(
|
||||
this.parser_.readFeaturesFromString(data), projection);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle the read result from a parser.
|
||||
* TODO: make parsers accept a target projection (see #1287)
|
||||
* @param {ol.parser.ReadFeaturesResult} result Read features result.
|
||||
* @param {ol.proj.Projection} projection The desired projection.
|
||||
* @private
|
||||
*/
|
||||
ol.source.Vector.prototype.handleReadResult_ = function(result, projection) {
|
||||
var features = result.features;
|
||||
var sourceProjection = this.getProjection();
|
||||
if (goog.isNull(sourceProjection)) {
|
||||
sourceProjection = result.metadata.projection;
|
||||
}
|
||||
var transform = ol.proj.getTransform(sourceProjection, projection);
|
||||
var extent = ol.extent.createEmpty();
|
||||
var geometry = null;
|
||||
var feature;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
geometry.transform(transform);
|
||||
ol.extent.extend(extent, geometry.getBounds());
|
||||
}
|
||||
this.loadFeature_(feature);
|
||||
}
|
||||
this.loadState_ = ol.source.VectorLoadState.LOADED;
|
||||
// called in the next tick to normalize load event for sync/async parsing
|
||||
goog.async.nextTick(function() {
|
||||
this.dispatchEvent(new ol.source.VectorEvent(ol.source.VectorEventType.LOAD,
|
||||
features, [extent]));
|
||||
}, this);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Load a feature.
|
||||
* @param {ol.Feature} feature Feature to load.
|
||||
* @private
|
||||
*/
|
||||
ol.source.Vector.prototype.loadFeature_ = function(feature) {
|
||||
goog.events.listen(feature, ol.FeatureEventType.CHANGE,
|
||||
this.handleFeatureChange_, false, this);
|
||||
goog.events.listen(feature, ol.FeatureEventType.INTENTCHANGE,
|
||||
this.handleIntentChange_, false, this);
|
||||
this.featureCache_.add(feature);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add newly created features to the source.
|
||||
* @param {Array.<ol.Feature>} features Array of features.
|
||||
*/
|
||||
ol.source.Vector.prototype.addFeatures = function(features) {
|
||||
var extent = ol.extent.createEmpty(),
|
||||
feature, geometry;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
this.loadFeature_(feature);
|
||||
geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
ol.extent.extend(extent, geometry.getBounds());
|
||||
}
|
||||
}
|
||||
this.dispatchEvent(new ol.source.VectorEvent(ol.source.VectorEventType.ADD,
|
||||
features, [extent]));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of features that match a filter. This will not fetch data,
|
||||
* it only considers features that are loaded already.
|
||||
* @param {(function(ol.Feature):boolean)=} opt_filter Filter function.
|
||||
* @return {Array.<ol.Feature>} Features that match the filter, or all features
|
||||
* if no filter was provided.
|
||||
*/
|
||||
ol.source.Vector.prototype.getFeatures = function(opt_filter) {
|
||||
var result;
|
||||
var features = this.featureCache_.getFeaturesObject();
|
||||
if (goog.isDef(opt_filter)) {
|
||||
result = [];
|
||||
for (var f in features) {
|
||||
if (opt_filter(features[f]) === true) {
|
||||
result.push(features[f]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = goog.object.getValues(features);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get all features whose bounding box intersects the provided extent. This
|
||||
* method is intended for being called by the renderer.
|
||||
*
|
||||
* @param {ol.Extent} extent Bounding extent.
|
||||
* @param {ol.proj.Projection} projection Target projection.
|
||||
* @param {function(this: T, ol.Feature)} callback Callback called with each
|
||||
* feature.
|
||||
* @param {T=} opt_thisArg The object to be used as the value of 'this' for
|
||||
* the callback.
|
||||
* @template T
|
||||
*/
|
||||
ol.source.Vector.prototype.forEachFeatureInExtent = function(extent,
|
||||
projection, callback, opt_thisArg) {
|
||||
// TODO: transform if requested project is different than loaded projection
|
||||
this.featureCache_.forEach(extent, callback, opt_thisArg);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listener for feature change events.
|
||||
* @param {ol.FeatureEvent} evt The feature change event.
|
||||
* @private
|
||||
*/
|
||||
ol.source.Vector.prototype.handleFeatureChange_ = function(evt) {
|
||||
goog.asserts.assertInstanceof(evt.target, ol.Feature);
|
||||
var feature = /** @type {ol.Feature} */ (evt.target);
|
||||
var extents = [];
|
||||
if (!goog.isNull(evt.oldExtent)) {
|
||||
extents.push(evt.oldExtent);
|
||||
}
|
||||
var geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
this.featureCache_.remove(feature, evt.oldExtent);
|
||||
this.featureCache_.add(feature);
|
||||
extents.push(geometry.getBounds());
|
||||
}
|
||||
this.dispatchEvent(new ol.source.VectorEvent(ol.source.VectorEventType.CHANGE,
|
||||
[feature], extents));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Listener for render intent change events of features.
|
||||
* @param {ol.FeatureEvent} evt The feature intent change event.
|
||||
* @private
|
||||
*/
|
||||
ol.source.Vector.prototype.handleIntentChange_ = function(evt) {
|
||||
goog.asserts.assertInstanceof(evt.target, ol.Feature);
|
||||
var feature = /** @type {ol.Feature} */ (evt.target);
|
||||
var geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
this.dispatchEvent(new ol.source.VectorEvent(
|
||||
ol.source.VectorEventType.INTENTCHANGE, [feature],
|
||||
[geometry.getBounds()]));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove features from the layer.
|
||||
* @param {Array.<ol.Feature>} features Features to remove.
|
||||
*/
|
||||
ol.source.Vector.prototype.removeFeatures = function(features) {
|
||||
var extent = ol.extent.createEmpty(),
|
||||
feature, geometry;
|
||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||
feature = features[i];
|
||||
this.featureCache_.remove(feature);
|
||||
geometry = feature.getGeometry();
|
||||
if (!goog.isNull(geometry)) {
|
||||
ol.extent.extend(extent, geometry.getBounds());
|
||||
}
|
||||
goog.events.unlisten(feature, ol.FeatureEventType.CHANGE,
|
||||
this.handleFeatureChange_, false, this);
|
||||
goog.events.unlisten(feature, ol.FeatureEventType.INTENTCHANGE,
|
||||
this.handleIntentChange_, false, this);
|
||||
}
|
||||
this.dispatchEvent(new ol.source.VectorEvent(ol.source.VectorEventType.REMOVE,
|
||||
features, [extent]));
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {goog.events.Event}
|
||||
* @param {string} type Event type.
|
||||
* @param {Array.<ol.Feature>} features Features associated with the event.
|
||||
* @param {Array.<ol.Extent>} extents Any extents associated with the event.
|
||||
*/
|
||||
ol.source.VectorEvent = function(type, features, extents) {
|
||||
|
||||
goog.base(this, type);
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.Feature>}
|
||||
*/
|
||||
this.features = features;
|
||||
|
||||
/**
|
||||
* @type {Array.<ol.Extent>}
|
||||
*/
|
||||
this.extents = extents;
|
||||
|
||||
};
|
||||
goog.inherits(ol.source.VectorEvent, goog.events.Event);
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
ol.source.VectorEventType = {
|
||||
LOAD: 'featureload',
|
||||
ADD: 'featureadd',
|
||||
CHANGE: 'featurechange',
|
||||
INTENTCHANGE: 'featureintentchange',
|
||||
REMOVE: 'featureremove'
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
ol.source.FeatureCache = function() {
|
||||
|
||||
/**
|
||||
* @type {Object.<string, ol.Feature>}
|
||||
* @private
|
||||
*/
|
||||
this.idLookup_;
|
||||
|
||||
/**
|
||||
* @type {ol.structs.RTree}
|
||||
* @private
|
||||
*/
|
||||
this.rTree_;
|
||||
|
||||
this.clear();
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Clear the cache.
|
||||
*/
|
||||
ol.source.FeatureCache.prototype.clear = function() {
|
||||
this.idLookup_ = {};
|
||||
this.rTree_ = new ol.structs.RTree();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add a feature to the cache.
|
||||
* @param {ol.Feature} feature Feature to be cached.
|
||||
*/
|
||||
ol.source.FeatureCache.prototype.add = function(feature) {
|
||||
var id = goog.getUid(feature).toString(),
|
||||
geometry = feature.getGeometry();
|
||||
|
||||
this.idLookup_[id] = feature;
|
||||
|
||||
// index by bounding box
|
||||
if (!goog.isNull(geometry)) {
|
||||
this.rTree_.insert(geometry.getBounds(), feature);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return {Object.<string, ol.Feature>} Object of features, keyed by id.
|
||||
*/
|
||||
ol.source.FeatureCache.prototype.getFeaturesObject = function() {
|
||||
return this.idLookup_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Operate on each feature whose bounding box intersects the provided extent.
|
||||
*
|
||||
* @param {ol.Extent} extent Bounding extent.
|
||||
* @param {function(this: T, ol.Feature)} callback Callback called with each
|
||||
* feature.
|
||||
* @param {T=} opt_thisArg The object to be used as the value of 'this' for
|
||||
* the callback.
|
||||
* @template T
|
||||
*/
|
||||
ol.source.FeatureCache.prototype.forEach =
|
||||
function(extent, callback, opt_thisArg) {
|
||||
this.rTree_.forEach(
|
||||
extent, /** @type {function(Object)} */ (callback), opt_thisArg);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove a feature from the cache.
|
||||
* @param {ol.Feature} feature Feature.
|
||||
* @param {ol.Extent=} opt_extent Optional extent (used when the current feature
|
||||
* extent is different than the one in the index).
|
||||
*/
|
||||
ol.source.FeatureCache.prototype.remove = function(feature, opt_extent) {
|
||||
var id = goog.getUid(feature).toString(),
|
||||
geometry = feature.getGeometry();
|
||||
|
||||
delete this.idLookup_[id];
|
||||
// index by bounding box
|
||||
if (!goog.isNull(geometry)) {
|
||||
var extent = goog.isDef(opt_extent) ? opt_extent : geometry.getBounds();
|
||||
this.rTree_.remove(extent, feature);
|
||||
}
|
||||
return this.loadState_;
|
||||
};
|
||||
|
||||
@@ -499,8 +499,7 @@ ol.structs.RTree.prototype.removeSubtree_ = function(rect, obj, root) {
|
||||
ol.structs.RTree.recalculateExtent_(tree);
|
||||
workingObject.target = undefined;
|
||||
if (tree.nodes.length < this.minWidth_) { // Underflow
|
||||
workingObject.nodes = /** @type {Array} */
|
||||
(this.searchSubtree_(tree, true, [], tree));
|
||||
workingObject.nodes = this.searchSubtree_(tree, true, [], tree);
|
||||
}
|
||||
break;
|
||||
} else if (goog.isDef(lTree.nodes)) {
|
||||
@@ -528,15 +527,13 @@ ol.structs.RTree.prototype.removeSubtree_ = function(rect, obj, root) {
|
||||
workingObject.nodes.length = 0;
|
||||
if (hitStack.length === 0 && tree.nodes.length <= 1) {
|
||||
// Underflow..on root!
|
||||
workingObject.nodes = /** @type {Array} */
|
||||
(this.searchSubtree_(tree, true, workingObject.nodes, tree));
|
||||
this.searchSubtree_(tree, true, workingObject.nodes, tree);
|
||||
tree.nodes.length = 0;
|
||||
hitStack.push(tree);
|
||||
countStack.push(1);
|
||||
} else if (hitStack.length > 0 && tree.nodes.length < this.minWidth_) {
|
||||
// Underflow..AGAIN!
|
||||
workingObject.nodes = /** @type {Array} */
|
||||
(this.searchSubtree_(tree, true, workingObject.nodes, tree));
|
||||
this.searchSubtree_(tree, true, workingObject.nodes, tree);
|
||||
tree.nodes.length = 0;
|
||||
} else {
|
||||
workingObject.nodes = undefined; // Just start resizing
|
||||
@@ -562,24 +559,24 @@ ol.structs.RTree.prototype.removeSubtree_ = function(rect, obj, root) {
|
||||
*/
|
||||
ol.structs.RTree.prototype.search = function(extent, opt_type) {
|
||||
var rect = /** @type {ol.structs.RTreeNode} */ ({extent: extent});
|
||||
return /** @type {Array} */ (
|
||||
this.searchSubtree_(rect, false, [], this.rootTree_, opt_type));
|
||||
return this.searchSubtree_(rect, false, [], this.rootTree_, opt_type);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Non-recursive search function
|
||||
* Search in the given extent and call the callback with each result.
|
||||
*
|
||||
* @param {ol.Extent} extent Extent.
|
||||
* @param {string|number=} opt_type Optional type of the objects we want to
|
||||
* find.
|
||||
* @return {Object} Result. Keys are UIDs of the values.
|
||||
* @param {ol.Extent} extent Extent to search.
|
||||
* @param {function(this: T, Object)} callback Callback called with each result.
|
||||
* @param {T=} opt_thisArg The object to be used as the value of 'this' for
|
||||
* the callback.
|
||||
* @this {ol.structs.RTree}
|
||||
* @template T
|
||||
*/
|
||||
ol.structs.RTree.prototype.searchReturningObject = function(extent, opt_type) {
|
||||
ol.structs.RTree.prototype.forEach = function(extent, callback, opt_thisArg) {
|
||||
var rect = /** @type {ol.structs.RTreeNode} */ ({extent: extent});
|
||||
return /** @type {Object} */ (
|
||||
this.searchSubtree_(rect, false, [], this.rootTree_, opt_type, true));
|
||||
this.searchSubtree_(
|
||||
rect, false, [], this.rootTree_, undefined, callback, opt_thisArg);
|
||||
};
|
||||
|
||||
|
||||
@@ -588,17 +585,19 @@ ol.structs.RTree.prototype.searchReturningObject = function(extent, opt_type) {
|
||||
*
|
||||
* @param {ol.structs.RTreeNode} rect Rectangle.
|
||||
* @param {boolean} returnNode Do we return nodes?
|
||||
* @param {Array|Object} result Result.
|
||||
* @param {Array} result Result.
|
||||
* @param {ol.structs.RTreeNode} root Root.
|
||||
* @param {string|number=} opt_type Optional type to search for.
|
||||
* @param {boolean=} opt_resultAsObject If set, result will be an object keyed
|
||||
* by UID.
|
||||
* @param {function(this: T, Object)=} opt_callback Callback called with each
|
||||
* result.
|
||||
* @param {T=} opt_thisArg The object to be used as the value of 'this' for
|
||||
* the callback.
|
||||
* @private
|
||||
* @return {Array|Object} Result.
|
||||
* @template T
|
||||
* @return {Array} Result.
|
||||
*/
|
||||
ol.structs.RTree.prototype.searchSubtree_ = function(
|
||||
rect, returnNode, result, root, opt_type, opt_resultAsObject) {
|
||||
var resultObject = {};
|
||||
rect, returnNode, result, root, opt_type, opt_callback, opt_thisArg) {
|
||||
var hitStack = []; // Contains the elements that overlap
|
||||
|
||||
if (!ol.extent.intersects(rect.extent, root.extent)) {
|
||||
@@ -621,8 +620,8 @@ ol.structs.RTree.prototype.searchSubtree_ = function(
|
||||
// walk all the way in to the leaf to know that we don't need it
|
||||
if (!goog.isDef(opt_type) || lTree.type == opt_type) {
|
||||
var obj = lTree.leaf;
|
||||
if (goog.isDef(opt_resultAsObject)) {
|
||||
resultObject[goog.getUid(obj).toString()] = obj;
|
||||
if (goog.isDef(opt_callback)) {
|
||||
opt_callback.call(opt_thisArg, obj);
|
||||
} else {
|
||||
result.push(obj);
|
||||
}
|
||||
@@ -635,9 +634,5 @@ ol.structs.RTree.prototype.searchSubtree_ = function(
|
||||
}
|
||||
} while (hitStack.length > 0);
|
||||
|
||||
if (goog.isDef(opt_resultAsObject)) {
|
||||
return resultObject;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@ goog.require('ol.style.Rule');
|
||||
goog.require('ol.style.Shape');
|
||||
goog.require('ol.style.Stroke');
|
||||
goog.require('ol.style.Symbolizer');
|
||||
goog.require('ol.style.TextLiteral');
|
||||
|
||||
|
||||
|
||||
@@ -82,6 +83,71 @@ ol.style.Style.prototype.createLiterals = function(feature, resolution) {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {Object.<string, ol.Feature>} features Features.
|
||||
* @param {number} resolution Map resolution.
|
||||
* @return {Array.<Array>} symbolizers for features. Each array in this array
|
||||
* contains 3 items: an array of features, the symbolizer literal, and
|
||||
* an array with optional additional data for each feature.
|
||||
*/
|
||||
ol.style.Style.prototype.groupFeaturesBySymbolizerLiteral =
|
||||
function(features, resolution) {
|
||||
var uniqueLiterals = {},
|
||||
featuresBySymbolizer = [],
|
||||
i, j, l, feature, symbolizers, literals, numLiterals, literal,
|
||||
uniqueLiteral, key, item;
|
||||
for (i in features) {
|
||||
feature = features[i];
|
||||
// feature level symbolizers take precedence
|
||||
symbolizers = feature.getSymbolizers();
|
||||
if (!goog.isNull(symbolizers)) {
|
||||
literals = ol.style.Style.createLiterals(symbolizers, feature);
|
||||
} else {
|
||||
literals = this.createLiterals(feature, resolution);
|
||||
}
|
||||
numLiterals = literals.length;
|
||||
for (j = 0; j < numLiterals; ++j) {
|
||||
literal = literals[j];
|
||||
for (l in uniqueLiterals) {
|
||||
uniqueLiteral = featuresBySymbolizer[uniqueLiterals[l]][1];
|
||||
if (literal.equals(uniqueLiteral)) {
|
||||
literal = uniqueLiteral;
|
||||
break;
|
||||
}
|
||||
}
|
||||
key = goog.getUid(literal);
|
||||
if (!goog.object.containsKey(uniqueLiterals, key)) {
|
||||
uniqueLiterals[key] = featuresBySymbolizer.length;
|
||||
featuresBySymbolizer.push([
|
||||
/** @type {Array.<ol.Feature>} */ ([]),
|
||||
/** @type {ol.style.Literal} */ (literal),
|
||||
/** @type {Array} */ ([])
|
||||
]);
|
||||
}
|
||||
item = featuresBySymbolizer[uniqueLiterals[key]];
|
||||
item[0].push(feature);
|
||||
if (literal instanceof ol.style.TextLiteral) {
|
||||
item[2].push(literals[j].text);
|
||||
}
|
||||
}
|
||||
}
|
||||
featuresBySymbolizer.sort(this.sortByZIndex_);
|
||||
return featuresBySymbolizer;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sort function for `groupFeaturesBySymbolizerLiteral`.
|
||||
* @private
|
||||
* @param {Array} a 1st item for the sort comparison.
|
||||
* @param {Array} b 2nd item for the sort comparison.
|
||||
* @return {number} Comparison result.
|
||||
*/
|
||||
ol.style.Style.prototype.sortByZIndex_ = function(a, b) {
|
||||
return a[1].zIndex - b[1].zIndex;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The default style.
|
||||
* @type {ol.style.Style}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
goog.provide('ol.test.interaction.Draw');
|
||||
|
||||
describe('ol.interaction.Draw', function() {
|
||||
var target, map, vector;
|
||||
var target, map, source, layer;
|
||||
|
||||
var width = 360;
|
||||
var height = 180;
|
||||
@@ -15,11 +15,12 @@ describe('ol.interaction.Draw', function() {
|
||||
style.width = width + 'px';
|
||||
style.height = height + 'px';
|
||||
document.body.appendChild(target);
|
||||
vector = new ol.layer.Vector({source: new ol.source.Vector({})});
|
||||
source = new ol.source.Vector();
|
||||
layer = new ol.layer.Vector({source: source});
|
||||
map = new ol.Map({
|
||||
target: target,
|
||||
renderer: ol.RendererHint.CANVAS,
|
||||
layers: [vector],
|
||||
layers: [layer],
|
||||
view: new ol.View2D({
|
||||
projection: 'EPSG:4326',
|
||||
center: [0, 0],
|
||||
@@ -56,7 +57,7 @@ describe('ol.interaction.Draw', function() {
|
||||
|
||||
it('creates a new interaction', function() {
|
||||
var draw = new ol.interaction.Draw({
|
||||
layer: vector,
|
||||
layer: layer,
|
||||
type: ol.geom.GeometryType.POINT
|
||||
});
|
||||
expect(draw).to.be.a(ol.interaction.Draw);
|
||||
@@ -69,7 +70,7 @@ describe('ol.interaction.Draw', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
map.addInteraction(new ol.interaction.Draw({
|
||||
layer: vector,
|
||||
layer: layer,
|
||||
type: ol.geom.GeometryType.POINT
|
||||
}));
|
||||
});
|
||||
@@ -79,7 +80,7 @@ describe('ol.interaction.Draw', function() {
|
||||
simulateEvent('mousedown', 10, 20);
|
||||
simulateEvent('mouseup', 10, 20);
|
||||
simulateEvent('click', 10, 20);
|
||||
var features = vector.getFeatures();
|
||||
var features = source.getFeatures();
|
||||
expect(features).to.have.length(1);
|
||||
var geometry = features[0].getGeometry();
|
||||
expect(geometry).to.be.a(ol.geom.Point);
|
||||
@@ -92,7 +93,7 @@ describe('ol.interaction.Draw', function() {
|
||||
simulateEvent('mousemove', 15, 20);
|
||||
simulateEvent('mouseup', 15, 20);
|
||||
simulateEvent('click', 15, 20);
|
||||
var features = vector.getFeatures();
|
||||
var features = source.getFeatures();
|
||||
expect(features).to.have.length(0);
|
||||
});
|
||||
|
||||
@@ -102,7 +103,7 @@ describe('ol.interaction.Draw', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
map.addInteraction(new ol.interaction.Draw({
|
||||
layer: vector,
|
||||
layer: layer,
|
||||
type: ol.geom.GeometryType.MULTIPOINT
|
||||
}));
|
||||
});
|
||||
@@ -112,7 +113,7 @@ describe('ol.interaction.Draw', function() {
|
||||
simulateEvent('mousedown', 30, 15);
|
||||
simulateEvent('mouseup', 30, 15);
|
||||
simulateEvent('click', 30, 15);
|
||||
var features = vector.getFeatures();
|
||||
var features = source.getFeatures();
|
||||
expect(features).to.have.length(1);
|
||||
var geometry = features[0].getGeometry();
|
||||
expect(geometry).to.be.a(ol.geom.MultiPoint);
|
||||
@@ -125,7 +126,7 @@ describe('ol.interaction.Draw', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
map.addInteraction(new ol.interaction.Draw({
|
||||
layer: vector,
|
||||
layer: layer,
|
||||
type: ol.geom.GeometryType.LINESTRING
|
||||
}));
|
||||
});
|
||||
@@ -148,7 +149,7 @@ describe('ol.interaction.Draw', function() {
|
||||
simulateEvent('mouseup', 30, 20);
|
||||
simulateEvent('click', 30, 20);
|
||||
|
||||
var features = vector.getFeatures();
|
||||
var features = source.getFeatures();
|
||||
expect(features).to.have.length(1);
|
||||
var geometry = features[0].getGeometry();
|
||||
expect(geometry).to.be.a(ol.geom.LineString);
|
||||
@@ -181,7 +182,7 @@ describe('ol.interaction.Draw', function() {
|
||||
simulateEvent('mouseup', 30, 20);
|
||||
simulateEvent('click', 30, 20);
|
||||
|
||||
var features = vector.getFeatures();
|
||||
var features = source.getFeatures();
|
||||
expect(features).to.have.length(1);
|
||||
var geometry = features[0].getGeometry();
|
||||
expect(geometry).to.be.a(ol.geom.LineString);
|
||||
@@ -194,7 +195,7 @@ describe('ol.interaction.Draw', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
map.addInteraction(new ol.interaction.Draw({
|
||||
layer: vector,
|
||||
layer: layer,
|
||||
type: ol.geom.GeometryType.MULTILINESTRING
|
||||
}));
|
||||
});
|
||||
@@ -217,7 +218,7 @@ describe('ol.interaction.Draw', function() {
|
||||
simulateEvent('mouseup', 30, 20);
|
||||
simulateEvent('click', 30, 20);
|
||||
|
||||
var features = vector.getFeatures();
|
||||
var features = source.getFeatures();
|
||||
expect(features).to.have.length(1);
|
||||
var geometry = features[0].getGeometry();
|
||||
expect(geometry).to.be.a(ol.geom.MultiLineString);
|
||||
@@ -230,7 +231,7 @@ describe('ol.interaction.Draw', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
map.addInteraction(new ol.interaction.Draw({
|
||||
layer: vector,
|
||||
layer: layer,
|
||||
type: ol.geom.GeometryType.POLYGON
|
||||
}));
|
||||
});
|
||||
@@ -260,7 +261,7 @@ describe('ol.interaction.Draw', function() {
|
||||
simulateEvent('mouseup', 10, 20);
|
||||
simulateEvent('click', 10, 20);
|
||||
|
||||
var features = vector.getFeatures();
|
||||
var features = source.getFeatures();
|
||||
expect(features).to.have.length(1);
|
||||
var geometry = features[0].getGeometry();
|
||||
expect(geometry).to.be.a(ol.geom.Polygon);
|
||||
@@ -277,7 +278,7 @@ describe('ol.interaction.Draw', function() {
|
||||
|
||||
beforeEach(function() {
|
||||
map.addInteraction(new ol.interaction.Draw({
|
||||
layer: vector,
|
||||
layer: layer,
|
||||
type: ol.geom.GeometryType.MULTIPOLYGON
|
||||
}));
|
||||
});
|
||||
@@ -307,7 +308,7 @@ describe('ol.interaction.Draw', function() {
|
||||
simulateEvent('mouseup', 10, 20);
|
||||
simulateEvent('click', 10, 20);
|
||||
|
||||
var features = vector.getFeatures();
|
||||
var features = source.getFeatures();
|
||||
expect(features).to.have.length(1);
|
||||
var geometry = features[0].getGeometry();
|
||||
expect(geometry).to.be.a(ol.geom.MultiPolygon);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
goog.provide('ol.test.interaction.Select');
|
||||
|
||||
describe('ol.interaction.Select', function() {
|
||||
var map, target, select, vector, features;
|
||||
var map, target, select, source, vector, features;
|
||||
|
||||
beforeEach(function() {
|
||||
target = document.createElement('div');
|
||||
@@ -11,24 +11,19 @@ describe('ol.interaction.Select', function() {
|
||||
map = new ol.Map({
|
||||
target: target
|
||||
});
|
||||
features = ol.parser.GeoJSON.read(JSON.stringify({
|
||||
'type': 'FeatureCollection',
|
||||
'features': [{
|
||||
'type': 'Feature',
|
||||
'geometry': {
|
||||
'type': 'Point',
|
||||
'coordinates': [-1, 1]
|
||||
}
|
||||
}, {
|
||||
'type': 'Feature',
|
||||
'geometry': {
|
||||
'type': 'Point',
|
||||
'coordinates': [1, -1]
|
||||
}
|
||||
}]
|
||||
}));
|
||||
vector = new ol.layer.Vector({source: new ol.source.Vector({})});
|
||||
vector.addFeatures(features);
|
||||
|
||||
features = [
|
||||
new ol.Feature({
|
||||
geometry: new ol.geom.Point([-1, 1])
|
||||
}),
|
||||
new ol.Feature({
|
||||
geometry: new ol.geom.Point([1, -1])
|
||||
})
|
||||
];
|
||||
|
||||
source = new ol.source.Vector({});
|
||||
source.addFeatures(features);
|
||||
vector = new ol.layer.Vector({source: source});
|
||||
select = new ol.interaction.Select({
|
||||
layers: [vector]
|
||||
});
|
||||
@@ -52,21 +47,21 @@ describe('ol.interaction.Select', function() {
|
||||
|
||||
it('toggles selection of features', function() {
|
||||
select.select(map, [features], [vector]);
|
||||
expect(vector.getFeatures(selectedFeaturesFilter).length).to.be(2);
|
||||
expect(source.getFeatures(selectedFeaturesFilter).length).to.be(2);
|
||||
select.select(map, [features], [vector]);
|
||||
expect(vector.getFeatures(selectedFeaturesFilter).length).to.be(0);
|
||||
expect(source.getFeatures(selectedFeaturesFilter).length).to.be(0);
|
||||
});
|
||||
|
||||
it('can append features to an existing selection', function() {
|
||||
select.select(map, [[features[0]]], [vector], true);
|
||||
select.select(map, [[features[1]]], [vector]);
|
||||
expect(vector.getFeatures(selectedFeaturesFilter).length).to.be(2);
|
||||
expect(source.getFeatures(selectedFeaturesFilter).length).to.be(2);
|
||||
});
|
||||
|
||||
it('can clear a selection before selecting new features', function() {
|
||||
select.select(map, [[features[0]]], [vector], true);
|
||||
select.select(map, [[features[1]]], [vector], true);
|
||||
expect(vector.getFeatures(selectedFeaturesFilter).length).to.be(1);
|
||||
expect(source.getFeatures(selectedFeaturesFilter).length).to.be(1);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -74,8 +69,9 @@ describe('ol.interaction.Select', function() {
|
||||
});
|
||||
|
||||
goog.require('goog.dispose');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.Map');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.interaction.Select');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.parser.GeoJSON');
|
||||
goog.require('ol.source.Vector');
|
||||
|
||||
@@ -2,177 +2,15 @@ goog.provide('ol.test.layer.Vector');
|
||||
|
||||
describe('ol.layer.Vector', function() {
|
||||
|
||||
describe('#addFeatures()', function() {
|
||||
describe('constructor', function() {
|
||||
|
||||
it('creates a new layer', function() {
|
||||
|
||||
it('allows adding features', function() {
|
||||
var layer = new ol.layer.Vector({
|
||||
source: new ol.source.Vector({})
|
||||
source: new ol.source.Vector()
|
||||
});
|
||||
layer.addFeatures([new ol.Feature(), new ol.Feature()]);
|
||||
expect(goog.object.getCount(layer.featureCache_.getFeaturesObject()))
|
||||
.to.eql(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ol.layer.FeatureCache#getFeaturesObject()', function() {
|
||||
|
||||
var layer, features;
|
||||
|
||||
beforeEach(function() {
|
||||
features = [
|
||||
new ol.Feature({
|
||||
g: new ol.geom.Point([16.0, 48.0])
|
||||
}),
|
||||
new ol.Feature({
|
||||
g: new ol.geom.LineString([[17.0, 49.0], [17.1, 49.1]])
|
||||
})
|
||||
];
|
||||
layer = new ol.layer.Vector({
|
||||
source: new ol.source.Vector({})
|
||||
});
|
||||
layer.addFeatures(features);
|
||||
});
|
||||
|
||||
it('returns the features in an object', function() {
|
||||
var featuresObject = layer.featureCache_.getFeaturesObject();
|
||||
expect(goog.object.getCount(featuresObject)).to.eql(features.length);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#groupFeaturesBySymbolizerLiteral()', function() {
|
||||
|
||||
var layer = new ol.layer.Vector({
|
||||
source: new ol.source.Vector({
|
||||
projection: ol.proj.get('EPSG:4326')
|
||||
}),
|
||||
style: new ol.style.Style({
|
||||
rules: [
|
||||
new ol.style.Rule({
|
||||
symbolizers: [
|
||||
new ol.style.Stroke({
|
||||
width: 2,
|
||||
color: ol.expr.parse('colorProperty'),
|
||||
opacity: 1
|
||||
})
|
||||
]
|
||||
})
|
||||
]
|
||||
})
|
||||
});
|
||||
var features;
|
||||
|
||||
it('groups equal symbolizers', function() {
|
||||
features = [
|
||||
new ol.Feature({
|
||||
g: new ol.geom.LineString([[-10, -10], [10, 10]]),
|
||||
colorProperty: '#BADA55'
|
||||
}),
|
||||
new ol.Feature({
|
||||
g: new ol.geom.LineString([[-10, 10], [10, -10]]),
|
||||
colorProperty: '#013'
|
||||
}),
|
||||
new ol.Feature({
|
||||
g: new ol.geom.LineString([[10, -10], [-10, -10]]),
|
||||
colorProperty: '#013'
|
||||
})
|
||||
];
|
||||
|
||||
var groups = layer.groupFeaturesBySymbolizerLiteral(features, 1);
|
||||
expect(groups.length).to.be(2);
|
||||
expect(groups[0][0].length).to.be(1);
|
||||
expect(groups[0][1].color).to.be('#BADA55');
|
||||
expect(groups[1][0].length).to.be(2);
|
||||
expect(groups[1][1].color).to.be('#013');
|
||||
});
|
||||
|
||||
it('groups equal symbolizers also when defined on features', function() {
|
||||
var symbolizer = new ol.style.Stroke({
|
||||
width: 3,
|
||||
color: ol.expr.parse('colorProperty'),
|
||||
opacity: 1
|
||||
});
|
||||
var anotherSymbolizer = new ol.style.Stroke({
|
||||
width: 3,
|
||||
color: '#BADA55',
|
||||
opacity: 1
|
||||
});
|
||||
var featureWithSymbolizers = new ol.Feature({
|
||||
g: new ol.geom.LineString([[-10, -10], [-10, 10]]),
|
||||
colorProperty: '#BADA55'
|
||||
});
|
||||
featureWithSymbolizers.setSymbolizers([symbolizer]);
|
||||
var anotherFeatureWithSymbolizers = new ol.Feature({
|
||||
g: new ol.geom.LineString([[-10, 10], [-10, -10]])
|
||||
});
|
||||
anotherFeatureWithSymbolizers.setSymbolizers([anotherSymbolizer]);
|
||||
features.push(featureWithSymbolizers, anotherFeatureWithSymbolizers);
|
||||
|
||||
var groups = layer.groupFeaturesBySymbolizerLiteral(features, 1);
|
||||
expect(groups).to.have.length(3);
|
||||
expect(groups[2][0].length).to.be(2);
|
||||
expect(groups[2][1].width).to.be(3);
|
||||
|
||||
});
|
||||
|
||||
it('sorts groups by zIndex', function() {
|
||||
var symbolizer = new ol.style.Stroke({
|
||||
width: 3,
|
||||
color: '#BADA55',
|
||||
opacity: 1,
|
||||
zIndex: 1
|
||||
});
|
||||
var anotherSymbolizer = new ol.style.Stroke({
|
||||
width: 3,
|
||||
color: '#BADA55',
|
||||
opacity: 1
|
||||
});
|
||||
var featureWithSymbolizers = new ol.Feature({
|
||||
g: new ol.geom.LineString([[-10, -10], [-10, 10]])
|
||||
});
|
||||
featureWithSymbolizers.setSymbolizers([symbolizer]);
|
||||
var anotherFeatureWithSymbolizers = new ol.Feature({
|
||||
g: new ol.geom.LineString([[-10, 10], [-10, -10]])
|
||||
});
|
||||
anotherFeatureWithSymbolizers.setSymbolizers([anotherSymbolizer]);
|
||||
features = [featureWithSymbolizers, anotherFeatureWithSymbolizers];
|
||||
|
||||
var groups = layer.groupFeaturesBySymbolizerLiteral(features, 1);
|
||||
expect(groups).to.have.length(2);
|
||||
expect(groups[0][1].zIndex).to.be(0);
|
||||
expect(groups[1][1].zIndex).to.be(1);
|
||||
});
|
||||
|
||||
goog.dispose(layer);
|
||||
|
||||
});
|
||||
|
||||
describe('ol.layer.VectorEvent', function() {
|
||||
|
||||
var layer, features;
|
||||
|
||||
beforeEach(function() {
|
||||
features = [
|
||||
new ol.Feature({
|
||||
g: new ol.geom.Point([16.0, 48.0])
|
||||
}),
|
||||
new ol.Feature({
|
||||
g: new ol.geom.LineString([[17.0, 49.0], [17.1, 49.1]])
|
||||
})
|
||||
];
|
||||
layer = new ol.layer.Vector({
|
||||
source: new ol.source.Vector({})
|
||||
});
|
||||
layer.addFeatures(features);
|
||||
});
|
||||
|
||||
it('dispatches events on feature change', function(done) {
|
||||
layer.on('featurechange', function(evt) {
|
||||
expect(evt.features[0]).to.be(features[0]);
|
||||
expect(evt.extents[0]).to.eql(features[0].getGeometry().getBounds());
|
||||
done();
|
||||
});
|
||||
features[0].set('foo', 'bar');
|
||||
expect(layer).to.be.a(ol.layer.Vector);
|
||||
expect(layer).to.be.a(ol.layer.Layer);
|
||||
|
||||
});
|
||||
|
||||
@@ -180,15 +18,6 @@ describe('ol.layer.Vector', function() {
|
||||
|
||||
});
|
||||
|
||||
goog.require('goog.dispose');
|
||||
goog.require('goog.object');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.expr');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.proj');
|
||||
goog.require('ol.layer.Layer');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.source.Vector');
|
||||
goog.require('ol.style.Rule');
|
||||
goog.require('ol.style.Stroke');
|
||||
goog.require('ol.style.Style');
|
||||
|
||||
@@ -3,85 +3,334 @@ goog.provide('ol.test.source.Vector');
|
||||
|
||||
describe('ol.source.Vector', function() {
|
||||
|
||||
var url = 'spec/ol/source/vectorsource/single-feature.json';
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates an instance', function() {
|
||||
var source = new ol.source.Vector({});
|
||||
var source = new ol.source.Vector();
|
||||
expect(source).to.be.a(ol.source.Vector);
|
||||
expect(source).to.be.a(ol.source.Source);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#prepareFeatures', function() {
|
||||
it('loads and parses data from a file', function(done) {
|
||||
it('accepts features', function() {
|
||||
var features = [new ol.Feature()];
|
||||
var source = new ol.source.Vector({
|
||||
url: 'spec/ol/parser/geojson/countries.geojson',
|
||||
features: features
|
||||
});
|
||||
expect(source).to.be.a(ol.source.Vector);
|
||||
expect(source.getFeatures()).to.eql(features);
|
||||
});
|
||||
|
||||
it('accepts url and parser', function() {
|
||||
var source = new ol.source.Vector({
|
||||
url: url,
|
||||
parser: new ol.parser.GeoJSON()
|
||||
});
|
||||
var layer = new ol.layer.Vector({
|
||||
source: source
|
||||
expect(source).to.be.a(ol.source.Vector);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#load()', function() {
|
||||
it('triggers loading of features', function() {
|
||||
var source = new ol.source.Vector({
|
||||
url: url,
|
||||
parser: new ol.parser.GeoJSON()
|
||||
});
|
||||
source.prepareFeatures(layer, [-180, -90, 180, 90],
|
||||
ol.proj.get('EPSG:4326'),
|
||||
function() {
|
||||
expect(source.loadState_).to.be(ol.source.VectorLoadState.IDLE);
|
||||
var triggered = source.load([-1, -1, 1, 1], ol.proj.get('EPSG:4326'));
|
||||
expect(triggered).to.be(true);
|
||||
expect(source.loadState_).to.be(ol.source.VectorLoadState.LOADING);
|
||||
});
|
||||
|
||||
it('returns false when already loading', function() {
|
||||
var source = new ol.source.Vector({
|
||||
url: url,
|
||||
parser: new ol.parser.GeoJSON()
|
||||
});
|
||||
source.load([-1, -1, 1, 1], ol.proj.get('EPSG:4326'));
|
||||
// second call with same extent
|
||||
var triggered = source.load([-1, -1, 1, 1], ol.proj.get('EPSG:4326'));
|
||||
expect(triggered).to.be(false);
|
||||
expect(source.loadState_).to.be(ol.source.VectorLoadState.LOADING);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#addFeatures()', function() {
|
||||
|
||||
it('allows adding features', function() {
|
||||
var source = new ol.source.Vector();
|
||||
var features = [new ol.Feature()];
|
||||
source.addFeatures(features);
|
||||
expect(source.getFeatures()).to.eql(features);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#getFeatures()', function() {
|
||||
|
||||
it('gets features cached on the source', function() {
|
||||
var source = new ol.source.Vector({
|
||||
features: [new ol.Feature()]
|
||||
});
|
||||
source.addFeatures([new ol.Feature()]);
|
||||
|
||||
var features = source.getFeatures();
|
||||
expect(features).to.be.an('array');
|
||||
expect(features).to.have.length(2);
|
||||
});
|
||||
|
||||
it('accepts a filter function', function() {
|
||||
var features = [
|
||||
new ol.Feature({name: 'a'}),
|
||||
new ol.Feature({name: 'b'}),
|
||||
new ol.Feature({name: 'c'}),
|
||||
new ol.Feature({name: 'd'})
|
||||
];
|
||||
var source = new ol.source.Vector({features: features});
|
||||
|
||||
var results = source.getFeatures(function(feature) {
|
||||
return feature.get('name') > 'b';
|
||||
});
|
||||
|
||||
expect(results).to.be.an('array');
|
||||
expect(results).to.have.length(2);
|
||||
expect(results).to.contain(features[2]);
|
||||
expect(results).to.contain(features[3]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#removeFeatures()', function() {
|
||||
|
||||
it('removes cached features', function() {
|
||||
var features = [new ol.Feature(), new ol.Feature()];
|
||||
var source = new ol.source.Vector({features: features});
|
||||
|
||||
expect(source.getFeatures()).to.have.length(2);
|
||||
source.removeFeatures(features);
|
||||
expect(source.getFeatures()).to.have.length(0);
|
||||
});
|
||||
|
||||
it('removes cached features', function() {
|
||||
var features = [new ol.Feature(), new ol.Feature()];
|
||||
var source = new ol.source.Vector({features: features});
|
||||
|
||||
expect(source.getFeatures()).to.have.length(2);
|
||||
source.removeFeatures([features[0]]);
|
||||
expect(source.getFeatures()).to.eql([features[1]]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#forEachFeatureInExtent()', function() {
|
||||
|
||||
var features = [
|
||||
new ol.Feature({geom: new ol.geom.Point([-100, 50])}),
|
||||
new ol.Feature({geom: new ol.geom.Point([100, 50])}),
|
||||
new ol.Feature({geom: new ol.geom.Point([100, -50])}),
|
||||
new ol.Feature({geom: new ol.geom.Point([-100, -50])})
|
||||
];
|
||||
var source = new ol.source.Vector({features: features});
|
||||
var gg = ol.proj.get('EPSG:4326');
|
||||
|
||||
it('calls callback with each feature in the extent', function() {
|
||||
var callback = sinon.spy();
|
||||
source.forEachFeatureInExtent([-180, -90, 180, 90], gg, callback);
|
||||
expect(callback.callCount).to.be(4);
|
||||
expect(callback.calledWith(sinon.match.same(features[0]))).to.be(true);
|
||||
expect(callback.calledWith(sinon.match.same(features[1]))).to.be(true);
|
||||
expect(callback.calledWith(sinon.match.same(features[2]))).to.be(true);
|
||||
expect(callback.calledWith(sinon.match.same(features[3]))).to.be(true);
|
||||
});
|
||||
|
||||
it('accepts a this argument', function() {
|
||||
var callback = sinon.spy();
|
||||
var thisArg = {};
|
||||
source.forEachFeatureInExtent(
|
||||
[-180, -90, 180, 90], gg, callback, thisArg);
|
||||
expect(callback.calledOn(thisArg)).to.be(true);
|
||||
});
|
||||
|
||||
it('works with a subset of features', function() {
|
||||
var callback = sinon.spy();
|
||||
source.forEachFeatureInExtent([-100, -50, -100, 50], gg, callback);
|
||||
expect(callback.callCount).to.be(2);
|
||||
expect(callback.calledWith(sinon.match.same(features[0]))).to.be(true);
|
||||
expect(callback.calledWith(sinon.match.same(features[3]))).to.be(true);
|
||||
});
|
||||
|
||||
it('works with no features', function() {
|
||||
var callback = sinon.spy();
|
||||
source.forEachFeatureInExtent([-110, -50, -110, -50], gg, callback);
|
||||
expect(callback.called).to.be(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('featureload event', function() {
|
||||
|
||||
var gg = ol.proj.get('EPSG:4326');
|
||||
var world = [-180, -90, 180, 90];
|
||||
|
||||
it('is dispatched after features load', function(done) {
|
||||
var source = new ol.source.Vector({
|
||||
url: url,
|
||||
parser: new ol.parser.GeoJSON()
|
||||
});
|
||||
expect(source.loadState_).to.be(ol.source.VectorLoadState.IDLE);
|
||||
var triggered = source.load(world, gg);
|
||||
expect(triggered).to.be(true);
|
||||
expect(source.loadState_).to.be(ol.source.VectorLoadState.LOADING);
|
||||
goog.events.listen(source, ol.source.VectorEventType.LOAD,
|
||||
function(evt) {
|
||||
var features = evt.features;
|
||||
expect(features).to.be.an('array');
|
||||
expect(features).to.have.length(1);
|
||||
expect(features[0]).to.be.an(ol.Feature);
|
||||
|
||||
var extents = evt.extents;
|
||||
expect(extents).to.be.an('array');
|
||||
expect(extents).to.have.length(1);
|
||||
expect(extents[0]).to.be.eql([1, 2, 1, 2]);
|
||||
|
||||
expect(source.loadState_).to.be(ol.source.VectorLoadState.LOADED);
|
||||
expect(goog.object.getCount(
|
||||
layer.featureCache_.getFeaturesObject())).to.be(179);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('parses inline data', function() {
|
||||
var source = new ol.source.Vector({
|
||||
data: {
|
||||
'type': 'FeatureCollection',
|
||||
'features': [{
|
||||
'type': 'Feature',
|
||||
'geometry': {
|
||||
'type': 'Point',
|
||||
'coordinates': [0, -6000000]
|
||||
}
|
||||
}, {
|
||||
'type': 'Feature',
|
||||
'geometry': {
|
||||
'type': 'Point',
|
||||
'coordinates': [-6000000, 0]
|
||||
}
|
||||
}, {
|
||||
'type': 'Feature',
|
||||
'geometry': {
|
||||
'type': 'Point',
|
||||
'coordinates': [0, 6000000]
|
||||
}
|
||||
}, {
|
||||
'type': 'Feature',
|
||||
'geometry': {
|
||||
'type': 'Point',
|
||||
'coordinates': [6000000, 0]
|
||||
}
|
||||
}]
|
||||
},
|
||||
parser: new ol.parser.GeoJSON(),
|
||||
projection: ol.proj.get('EPSG:4326')
|
||||
});
|
||||
var layer = new ol.layer.Vector({
|
||||
source: source
|
||||
});
|
||||
source.prepareFeatures(layer, [-180, -90, 180, 90],
|
||||
ol.proj.get('EPSG:4326'),
|
||||
function() {
|
||||
expect(source.loadState_).to.be(ol.source.VectorLoadState.LOADED);
|
||||
expect(goog.object.getCount(
|
||||
layer.featureCache_.getFeaturesObject())).to.be(4);
|
||||
});
|
||||
|
||||
describe('featureadd event', function() {
|
||||
|
||||
it('is dispatched after features are added', function(done) {
|
||||
var source = new ol.source.Vector();
|
||||
var features = [
|
||||
new ol.Feature({g: new ol.geom.Point([10, 5])}),
|
||||
new ol.Feature({g: new ol.geom.Point([-10, -5])})
|
||||
];
|
||||
|
||||
goog.events.listen(source, ol.source.VectorEventType.ADD,
|
||||
function(evt) {
|
||||
var features = evt.features;
|
||||
expect(features).to.be.an('array');
|
||||
expect(features).to.have.length(2);
|
||||
expect(features).to.contain(features[0]);
|
||||
expect(features).to.contain(features[1]);
|
||||
|
||||
var extents = evt.extents;
|
||||
expect(extents).to.be.an('array');
|
||||
expect(extents).to.have.length(1);
|
||||
expect(extents[0]).to.be.eql([-10, -5, 10, 5]);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
source.addFeatures(features);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('featureremove event', function() {
|
||||
|
||||
it('is dispatched after features are removed', function(done) {
|
||||
var features = [
|
||||
new ol.Feature({g: new ol.geom.Point([10, 5])}),
|
||||
new ol.Feature({g: new ol.geom.Point([-10, -5])})
|
||||
];
|
||||
var source = new ol.source.Vector({features: features});
|
||||
|
||||
goog.events.listen(source, ol.source.VectorEventType.REMOVE,
|
||||
function(evt) {
|
||||
var features = evt.features;
|
||||
expect(features).to.be.an('array');
|
||||
expect(features).to.have.length(2);
|
||||
expect(features).to.contain(features[0]);
|
||||
expect(features).to.contain(features[1]);
|
||||
|
||||
var extents = evt.extents;
|
||||
expect(extents).to.be.an('array');
|
||||
expect(extents).to.have.length(1);
|
||||
expect(extents[0]).to.be.eql([-10, -5, 10, 5]);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
source.removeFeatures(features);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('featurechange event', function() {
|
||||
|
||||
var source, features;
|
||||
|
||||
beforeEach(function() {
|
||||
features = [
|
||||
new ol.Feature({
|
||||
g: new ol.geom.Point([16.0, 48.0])
|
||||
}),
|
||||
new ol.Feature({
|
||||
g: new ol.geom.LineString([[17.0, 49.0], [17.1, 49.1]])
|
||||
})
|
||||
];
|
||||
source = new ol.source.Vector();
|
||||
source.addFeatures(features);
|
||||
});
|
||||
|
||||
it('is dispatched on attribute changes', function(done) {
|
||||
goog.events.listen(source, ol.source.VectorEventType.CHANGE,
|
||||
function(evt) {
|
||||
var expected = features[0];
|
||||
expect(evt.features[0]).to.be(expected);
|
||||
expect(evt.extents[0]).to.eql(expected.getGeometry().getBounds());
|
||||
done();
|
||||
|
||||
});
|
||||
|
||||
features[0].set('foo', 'bar');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.source.FeatureCache', function() {
|
||||
|
||||
describe('#getFeaturesObject()', function() {
|
||||
var source, features;
|
||||
|
||||
beforeEach(function() {
|
||||
features = [
|
||||
new ol.Feature({
|
||||
g: new ol.geom.Point([16.0, 48.0])
|
||||
}),
|
||||
new ol.Feature({
|
||||
g: new ol.geom.LineString([[17.0, 49.0], [17.1, 49.1]])
|
||||
})
|
||||
];
|
||||
source = new ol.source.Vector();
|
||||
source.addFeatures(features);
|
||||
});
|
||||
|
||||
it('returns the features in an object', function() {
|
||||
var featuresObject = source.featureCache_.getFeaturesObject();
|
||||
expect(goog.object.getCount(featuresObject)).to.eql(features.length);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
goog.require('goog.dispose');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.object');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.parser.GeoJSON');
|
||||
goog.require('ol.proj');
|
||||
goog.require('ol.source.FeatureCache');
|
||||
goog.require('ol.source.Source');
|
||||
goog.require('ol.source.Vector');
|
||||
goog.require('ol.source.VectorEventType');
|
||||
goog.require('ol.source.VectorLoadState');
|
||||
|
||||
16
test/spec/ol/source/vectorsource/single-feature.json
Normal file
16
test/spec/ol/source/vectorsource/single-feature.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "point_1",
|
||||
"geometry": {
|
||||
"coordinates": [1, 2],
|
||||
"type": "Point"
|
||||
},
|
||||
"properties": {
|
||||
"name": "point"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -109,11 +109,38 @@ describe('ol.structs.RTree', function() {
|
||||
expect(result.length).to.be(3);
|
||||
});
|
||||
|
||||
it('can return objects instead of arrays', function() {
|
||||
var obj = {foo: 'bar'};
|
||||
rTree.insert([5, 5, 5, 5], obj);
|
||||
var result = rTree.searchReturningObject([4, 4, 6, 6]);
|
||||
expect(result[goog.getUid(obj)]).to.equal(obj);
|
||||
});
|
||||
|
||||
describe('#forEach()', function() {
|
||||
var tree;
|
||||
beforeEach(function() {
|
||||
tree = new ol.structs.RTree();
|
||||
});
|
||||
|
||||
it('calls a callback for each result in the search extent', function() {
|
||||
var one = {};
|
||||
tree.insert([4.5, 4.5, 5, 5], one);
|
||||
|
||||
var two = {};
|
||||
tree.insert([5, 5, 5.5, 5.5], two);
|
||||
|
||||
var callback = sinon.spy();
|
||||
tree.forEach([4, 4, 6, 6], callback);
|
||||
expect(callback.callCount).to.be(2);
|
||||
expect(callback.calledWith(one)).to.be(true);
|
||||
expect(callback.calledWith(two)).to.be(true);
|
||||
});
|
||||
|
||||
it('accepts a this argument', function() {
|
||||
var obj = {};
|
||||
tree.insert([5, 5, 5, 5], obj);
|
||||
|
||||
var callback = sinon.spy();
|
||||
var thisArg = {};
|
||||
tree.forEach([4, 4, 6, 6], callback, thisArg);
|
||||
expect(callback.callCount).to.be(1);
|
||||
expect(callback.calledWith(obj)).to.be(true);
|
||||
expect(callback.calledOn(thisArg)).to.be(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -122,6 +122,102 @@ describe('ol.style.Style', function() {
|
||||
|
||||
});
|
||||
|
||||
describe('#groupFeaturesBySymbolizerLiteral()', function() {
|
||||
|
||||
var style = new ol.style.Style({
|
||||
symbolizers: [
|
||||
new ol.style.Stroke({
|
||||
width: 2,
|
||||
color: ol.expr.parse('colorProperty'),
|
||||
opacity: 1
|
||||
})
|
||||
]
|
||||
});
|
||||
var features;
|
||||
|
||||
it('groups equal symbolizers', function() {
|
||||
features = [
|
||||
new ol.Feature({
|
||||
g: new ol.geom.LineString([[-10, -10], [10, 10]]),
|
||||
colorProperty: '#BADA55'
|
||||
}),
|
||||
new ol.Feature({
|
||||
g: new ol.geom.LineString([[-10, 10], [10, -10]]),
|
||||
colorProperty: '#013'
|
||||
}),
|
||||
new ol.Feature({
|
||||
g: new ol.geom.LineString([[10, -10], [-10, -10]]),
|
||||
colorProperty: '#013'
|
||||
})
|
||||
];
|
||||
|
||||
var groups = style.groupFeaturesBySymbolizerLiteral(features, 1);
|
||||
expect(groups.length).to.be(2);
|
||||
expect(groups[0][0].length).to.be(1);
|
||||
expect(groups[0][1].color).to.be('#BADA55');
|
||||
expect(groups[1][0].length).to.be(2);
|
||||
expect(groups[1][1].color).to.be('#013');
|
||||
});
|
||||
|
||||
it('groups equal symbolizers also when defined on features', function() {
|
||||
var symbolizer = new ol.style.Stroke({
|
||||
width: 3,
|
||||
color: ol.expr.parse('colorProperty'),
|
||||
opacity: 1
|
||||
});
|
||||
var anotherSymbolizer = new ol.style.Stroke({
|
||||
width: 3,
|
||||
color: '#BADA55',
|
||||
opacity: 1
|
||||
});
|
||||
var featureWithSymbolizers = new ol.Feature({
|
||||
g: new ol.geom.LineString([[-10, -10], [-10, 10]]),
|
||||
colorProperty: '#BADA55'
|
||||
});
|
||||
featureWithSymbolizers.setSymbolizers([symbolizer]);
|
||||
var anotherFeatureWithSymbolizers = new ol.Feature({
|
||||
g: new ol.geom.LineString([[-10, 10], [-10, -10]])
|
||||
});
|
||||
anotherFeatureWithSymbolizers.setSymbolizers([anotherSymbolizer]);
|
||||
features.push(featureWithSymbolizers, anotherFeatureWithSymbolizers);
|
||||
|
||||
var groups = style.groupFeaturesBySymbolizerLiteral(features, 1);
|
||||
expect(groups).to.have.length(3);
|
||||
expect(groups[2][0].length).to.be(2);
|
||||
expect(groups[2][1].width).to.be(3);
|
||||
|
||||
});
|
||||
|
||||
it('sorts groups by zIndex', function() {
|
||||
var symbolizer = new ol.style.Stroke({
|
||||
width: 3,
|
||||
color: '#BADA55',
|
||||
opacity: 1,
|
||||
zIndex: 1
|
||||
});
|
||||
var anotherSymbolizer = new ol.style.Stroke({
|
||||
width: 3,
|
||||
color: '#BADA55',
|
||||
opacity: 1
|
||||
});
|
||||
var featureWithSymbolizers = new ol.Feature({
|
||||
g: new ol.geom.LineString([[-10, -10], [-10, 10]])
|
||||
});
|
||||
featureWithSymbolizers.setSymbolizers([symbolizer]);
|
||||
var anotherFeatureWithSymbolizers = new ol.Feature({
|
||||
g: new ol.geom.LineString([[-10, 10], [-10, -10]])
|
||||
});
|
||||
anotherFeatureWithSymbolizers.setSymbolizers([anotherSymbolizer]);
|
||||
features = [featureWithSymbolizers, anotherFeatureWithSymbolizers];
|
||||
|
||||
var groups = style.groupFeaturesBySymbolizerLiteral(features, 1);
|
||||
expect(groups).to.have.length(2);
|
||||
expect(groups[0][1].zIndex).to.be(0);
|
||||
expect(groups[1][1].zIndex).to.be(1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('ol.style.getDefault()', function() {
|
||||
var style = ol.style.getDefault();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user