Merge pull request #870 from ahocevar/vector-api
Give VectorSource the ability to load and parse data
This commit is contained in:
@@ -499,6 +499,20 @@
|
||||
* of `url` when the WMS supports multiple urls for GetMap requests.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ol.source.VectorOptions
|
||||
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
|
||||
* @property {Object|string|undefined} data Data to parse.
|
||||
* @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.ProjectionLike|undefined} projection Projection. EPSG:4326
|
||||
* is assumed if not defined. TODO: Get projection from the parser instead
|
||||
* of assuming EPSG:4326.
|
||||
* @property {string|undefined} url Server url providing the vector data.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} ol.source.VectorSource2Options
|
||||
* @property {Array.<ol.Attribution>|undefined} attributions Attributions.
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
@exportClass ol.layer.Vector ol.layer.VectorLayerOptions
|
||||
|
||||
@exportProperty ol.layer.Vector.prototype.addFeatures
|
||||
@exportProperty ol.layer.Vector.prototype.parseFeatures
|
||||
|
||||
@@ -279,34 +279,26 @@ ol.layer.Vector.prototype.getVectorSource = function() {
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.expr.Expression=} opt_expr Expression for filtering.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getFeatures = function(opt_expr) {
|
||||
return goog.object.getValues(
|
||||
this.featureCache_.getFeaturesObject(opt_expr));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {ol.expr.Expression=} opt_expr Expression for filtering.
|
||||
* @return {Object.<string, ol.Feature>} Features.
|
||||
*/
|
||||
ol.layer.Vector.prototype.getFeaturesObject = function(opt_expr) {
|
||||
return this.featureCache_.getFeaturesObject(opt_expr);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get all features whose bounding box intersects the provided extent.
|
||||
* 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.Projection} projection Target projection.
|
||||
* @param {ol.geom.GeometryType=} opt_type Optional geometry type.
|
||||
* @return {Object.<string, ol.Feature>} Features.
|
||||
* @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,
|
||||
opt_type) {
|
||||
return this.featureCache_.getFeaturesObjectForExtent(extent, opt_type);
|
||||
projection, opt_type, opt_callback) {
|
||||
var source = this.getSource();
|
||||
return source.prepareFeatures(this, extent, projection, opt_callback) ==
|
||||
ol.source.VectorLoadState.LOADING ?
|
||||
null :
|
||||
this.featureCache_.getFeaturesObjectForExtent(extent, opt_type);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -228,9 +228,11 @@ ol.renderer.canvas.VectorLayer.prototype.getFeatureInfoForPixel =
|
||||
* @param {function(Array.<ol.Feature>, ol.layer.Layer)} success Callback for
|
||||
* successful queries. The passed arguments are the resulting features
|
||||
* and the layer.
|
||||
* @param {function()=} opt_error Callback for unsuccessful queries.
|
||||
*/
|
||||
ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel =
|
||||
function(pixel, success) {
|
||||
function(pixel, success, opt_error) {
|
||||
// TODO What do we want to pass to the error callback?
|
||||
var map = this.getMap();
|
||||
var result = [];
|
||||
|
||||
@@ -247,7 +249,15 @@ ol.renderer.canvas.VectorLayer.prototype.getFeaturesForPixel =
|
||||
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);
|
||||
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 candidate, geom, type, symbolBounds, symbolSize, halfWidth, halfHeight,
|
||||
coordinates, j;
|
||||
@@ -446,6 +456,7 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
|
||||
dirty = false,
|
||||
i, type, tileExtent,
|
||||
groups, group, j, numGroups, featuresObject, tileHasFeatures;
|
||||
fetchTileData:
|
||||
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
|
||||
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
|
||||
tileCoord = new ol.TileCoord(0, x, y);
|
||||
@@ -464,7 +475,12 @@ ol.renderer.canvas.VectorLayer.prototype.renderFrame =
|
||||
if (!goog.isDef(featuresToRender[type])) {
|
||||
featuresToRender[type] = {};
|
||||
}
|
||||
featuresObject = layer.getFeaturesObjectForExtent(tileExtent, type);
|
||||
featuresObject = layer.getFeaturesObjectForExtent(tileExtent,
|
||||
projection, type, this.requestMapRenderFrame_);
|
||||
if (goog.isNull(featuresObject)) {
|
||||
deferred = true;
|
||||
break fetchTileData;
|
||||
}
|
||||
tileHasFeatures = tileHasFeatures ||
|
||||
!goog.object.isEmpty(featuresObject);
|
||||
goog.object.extend(featuresToRender[type], featuresObject);
|
||||
|
||||
@@ -1 +1 @@
|
||||
@exportClass ol.source.Vector ol.source.SourceOptions
|
||||
@exportClass ol.source.Vector ol.source.VectorOptions
|
||||
|
||||
@@ -1,15 +1,97 @@
|
||||
goog.provide('ol.source.Vector');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('goog.net.XhrIo');
|
||||
goog.require('ol.proj');
|
||||
goog.require('ol.source.Source');
|
||||
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
ol.source.VectorLoadState = {
|
||||
IDLE: 0,
|
||||
LOADING: 1,
|
||||
LOADED: 2,
|
||||
ERROR: 3
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {ol.source.Source}
|
||||
* @param {ol.source.SourceOptions} options Source options.
|
||||
* @param {ol.source.VectorOptions} options Vector source options.
|
||||
*/
|
||||
ol.source.Vector = function(options) {
|
||||
goog.base(this, 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;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ol.parser.Parser}
|
||||
*/
|
||||
this.parser_ = goog.isDef(options.parser) ? options.parser : null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {string|undefined}
|
||||
*/
|
||||
this.url_ = options.url;
|
||||
|
||||
goog.base(this, {
|
||||
attributions: options.attributions,
|
||||
extent: options.extent,
|
||||
logo: options.logo,
|
||||
projection: goog.isDef(options.projection) ?
|
||||
options.projection : ol.proj.get('EPSG:4326')
|
||||
});
|
||||
};
|
||||
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.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.
|
||||
*/
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
return this.loadState_;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user