diff --git a/externs/olx.js b/externs/olx.js index fa5febf9b1..30bf226baa 100644 --- a/externs/olx.js +++ b/externs/olx.js @@ -1686,7 +1686,11 @@ olx.format.EsriJSONOptions.prototype.geometryName; /** - * @typedef {{geometryName: (string|undefined), + * @typedef {{featureClass: (function((ol.geom.Geometry|Object.)=)| + * function(ol.geom.GeometryType,Array., + * (Array.|Array.>),Object.)| + * undefined), + * geometryName: (string|undefined), * layers: (Array.|undefined), * layerName: (string|undefined)}} * @api @@ -1694,6 +1698,19 @@ olx.format.EsriJSONOptions.prototype.geometryName; olx.format.MVTOptions; +/** + * Class for features returned by {@link ol.format.MVT#readFeatures}. Set to + * {@link ol.Feature} to get full editing and geometry support at the cost of + * decreased rendering performance. The default is {@link ol.render.Feature}, + * which is optimized for rendering and hit detection. + * @type {undefined|function((ol.geom.Geometry|Object.)=)| + * function(ol.geom.GeometryType,Array., + * (Array.|Array.>),Object.)} + * @api + */ +olx.format.MVTOptions.prototype.featureClass; + + /** * Geometry name to use when creating features. Default is 'geometry'. * @type {string|undefined} diff --git a/src/ol/featureloader.js b/src/ol/featureloader.js index cf7a450959..7c6d1c8582 100644 --- a/src/ol/featureloader.js +++ b/src/ol/featureloader.js @@ -7,6 +7,7 @@ goog.require('goog.events'); goog.require('goog.net.EventType'); goog.require('goog.net.XhrIo'); goog.require('goog.net.XhrIo.ResponseType'); +goog.require('ol.TileState'); goog.require('ol.format.FormatType'); goog.require('ol.xml'); @@ -49,7 +50,7 @@ ol.FeatureUrlFunction; * @param {function(this:ol.VectorTile, Array., ol.proj.Projection)|function(this:ol.source.Vector, Array.)} success * Function called with the loaded features and optionally with the data * projection. Called with the vector tile or source as `this`. - * @param {function(this:ol.source.Vector)} failure + * @param {function(this:ol.VectorTile)|function(this:ol.source.Vector)} failure * Function called when loading failed. Called with the vector tile or * source as `this`. * @return {ol.FeatureLoader} The feature loader. diff --git a/src/ol/format/mvtformat.js b/src/ol/format/mvtformat.js index 97936f1585..0b8a07acd2 100644 --- a/src/ol/format/mvtformat.js +++ b/src/ol/format/mvtformat.js @@ -11,6 +11,7 @@ goog.require('ol.format.Feature'); goog.require('ol.format.FormatType'); goog.require('ol.geom.Geometry'); goog.require('ol.geom.GeometryLayout'); +goog.require('ol.geom.GeometryType'); goog.require('ol.geom.LineString'); goog.require('ol.geom.MultiLineString'); goog.require('ol.geom.MultiPoint'); @@ -19,6 +20,7 @@ goog.require('ol.geom.Polygon'); goog.require('ol.proj'); goog.require('ol.proj.Projection'); goog.require('ol.proj.Units'); +goog.require('ol.render.Feature'); @@ -45,6 +47,15 @@ ol.format.MVT = function(opt_options) { units: ol.proj.Units.TILE_PIXELS }); + /** + * @private + * @type {function((ol.geom.Geometry|Object.)=)| + * function(ol.geom.GeometryType,Array., + * (Array.|Array.>),Object.)} + */ + this.featureClass_ = goog.isDef(options.featureClass) ? + options.featureClass : ol.render.Feature; + /** * @private * @type {string} @@ -79,12 +90,15 @@ ol.format.MVT.prototype.getType = function() { /** * @private * @param {Object} rawFeature Raw Mapbox feature. + * @param {string} layer Layer. * @param {olx.format.ReadOptions=} opt_options Read options. * @return {ol.Feature} Feature. */ -ol.format.MVT.prototype.readFeature_ = function(rawFeature, opt_options) { - var feature = new ol.Feature(); +ol.format.MVT.prototype.readFeature_ = function( + rawFeature, layer, opt_options) { + var feature = new this.featureClass_(); var values = rawFeature.properties; + values[this.layerName_] = layer; var geometry = ol.format.Feature.transformWithOptions( ol.format.MVT.readGeometry_(rawFeature), false, this.adaptOptions(opt_options)); @@ -98,18 +112,66 @@ ol.format.MVT.prototype.readFeature_ = function(rawFeature, opt_options) { }; +/** + * @private + * @param {Object} rawFeature Raw Mapbox feature. + * @param {string} layer Layer. + * @return {ol.render.Feature} Feature. + */ +ol.format.MVT.prototype.readRenderFeature_ = function(rawFeature, layer) { + var coords = rawFeature.loadGeometry(); + var end = 0; + var ends = []; + var flatCoordinates = []; + var line, coord; + for (var i = 0, ii = coords.length; i < ii; ++i) { + line = coords[i]; + for (var j = 0, jj = line.length; j < jj; ++j) { + coord = line[j]; + // Non-tilespace coords can be calculated here when a TileGrid and + // TileCoord are known. + flatCoordinates.push(coord.x, coord.y); + } + end += 2 * j; + ends.push(end); + } + + var type = rawFeature.type; + /** @type {ol.geom.GeometryType} */ + var geometryType; + if (type === 1) { + geometryType = coords.length === 1 ? + ol.geom.GeometryType.POINT : ol.geom.GeometryType.MULTI_POINT; + } else if (type === 2) { + if (coords.length === 1) { + geometryType = ol.geom.GeometryType.LINE_STRING; + } else { + geometryType = ol.geom.GeometryType.MULTI_LINE_STRING; + } + } else { + geometryType = ol.geom.GeometryType.POLYGON; + } + + var properties = rawFeature.properties; + properties[this.layerName_] = layer; + + return new this.featureClass_( + geometryType, flatCoordinates, ends, rawFeature.properties); +}; + + /** * @inheritDoc */ ol.format.MVT.prototype.readFeatures = function(source, opt_options) { goog.asserts.assertInstanceof(source, ArrayBuffer); - var layerName = this.layerName_; var layers = this.layers_; var pbf = new ol.ext.pbf(source); var tile = new ol.ext.vectortile.VectorTile(pbf); var features = []; + var featureClass = this.featureClass_; var layer, feature; for (var name in tile.layers) { if (!goog.isNull(layers) && !goog.array.contains(layers, name)) { @@ -118,8 +180,11 @@ ol.format.MVT.prototype.readFeatures = function(source, opt_options) { layer = tile.layers[name]; for (var i = 0, ii = layer.length; i < layer.length; ++i) { - feature = this.readFeature_(layer.feature(i), opt_options); - feature.set(layerName, name); + if (featureClass === ol.render.Feature) { + feature = this.readRenderFeature_(layer.feature(i), name); + } else { + feature = this.readFeature_(layer.feature(i), name, opt_options); + } features.push(feature); } } diff --git a/src/ol/interaction/selectinteraction.js b/src/ol/interaction/selectinteraction.js index 447c18634e..d527dcc248 100644 --- a/src/ol/interaction/selectinteraction.js +++ b/src/ol/interaction/selectinteraction.js @@ -33,9 +33,11 @@ ol.interaction.SelectEventType = { /** - * A function that takes an {@link ol.Feature} and an {@link ol.layer.Layer} - * and returns `true` if the feature may be selected or `false` otherwise. - * @typedef {function(ol.Feature, ol.layer.Layer): boolean} + * A function that takes an {@link ol.Feature} or {@link ol.render.Feature} and + * an {@link ol.layer.Layer} and returns `true` if the feature may be selected + * or `false` otherwise. + * @typedef {function((ol.Feature|ol.render.Feature), ol.layer.Layer): + * boolean} * @api */ ol.interaction.SelectFilterFunction; @@ -273,7 +275,7 @@ ol.interaction.Select.handleEvent = function(mapBrowserEvent) { // the pixel. map.forEachFeatureAtPixel(mapBrowserEvent.pixel, /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @param {ol.layer.Layer} layer Layer. */ function(feature, layer) { @@ -308,7 +310,7 @@ ol.interaction.Select.handleEvent = function(mapBrowserEvent) { // Modify the currently selected feature(s). map.forEachFeatureAtPixel(mapBrowserEvent.pixel, /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @param {ol.layer.Layer} layer Layer. */ function(feature, layer) { diff --git a/src/ol/map.js b/src/ol/map.js index 15fda71a25..91f02c0481 100644 --- a/src/ol/map.js +++ b/src/ol/map.js @@ -594,9 +594,11 @@ ol.Map.prototype.disposeInternal = function() { * callback with each intersecting feature. Layers included in the detection can * be configured through `opt_layerFilter`. * @param {ol.Pixel} pixel Pixel. - * @param {function(this: S, ol.Feature, ol.layer.Layer): T} callback Feature - * callback. The callback will be called with two arguments. The first - * argument is one {@link ol.Feature feature} at the pixel, the second is + * @param {function(this: S, (ol.Feature|ol.render.Feature), + * ol.layer.Layer): T} callback Feature callback. The callback will be + * called with two arguments. The first argument is one + * {@link ol.Feature feature} or + * {@link ol.render.Feature render feature} at the pixel, the second is * the {@link ol.layer.Layer layer} of the feature. To stop detection, * callback functions can return a truthy value. * @param {S=} opt_this Value to use as `this` when executing `callback`. diff --git a/src/ol/render/canvas/canvasimmediate.js b/src/ol/render/canvas/canvasimmediate.js index 2d90610ffe..710c49b416 100644 --- a/src/ol/render/canvas/canvasimmediate.js +++ b/src/ol/render/canvas/canvasimmediate.js @@ -527,8 +527,8 @@ ol.render.canvas.Immediate.prototype.drawGeometryCollectionGeometry = * Render a Point geometry into the canvas. Rendering is immediate and uses * the current style. * - * @param {ol.geom.Point} pointGeometry Point geometry. - * @param {ol.Feature} feature Feature. + * @param {ol.geom.Point|ol.render.Feature} pointGeometry Point geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @api */ ol.render.canvas.Immediate.prototype.drawPointGeometry = @@ -548,8 +548,9 @@ ol.render.canvas.Immediate.prototype.drawPointGeometry = * Render a MultiPoint geometry into the canvas. Rendering is immediate and * uses the current style. * - * @param {ol.geom.MultiPoint} multiPointGeometry MultiPoint geometry. - * @param {ol.Feature} feature Feature. + * @param {ol.geom.MultiPoint|ol.render.Feature} multiPointGeometry MultiPoint + * geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @api */ ol.render.canvas.Immediate.prototype.drawMultiPointGeometry = @@ -569,8 +570,9 @@ ol.render.canvas.Immediate.prototype.drawMultiPointGeometry = * Render a LineString into the canvas. Rendering is immediate and uses * the current style. * - * @param {ol.geom.LineString} lineStringGeometry Line string geometry. - * @param {ol.Feature} feature Feature. + * @param {ol.geom.LineString|ol.render.Feature} lineStringGeometry Line + * string geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @api */ ol.render.canvas.Immediate.prototype.drawLineStringGeometry = @@ -598,9 +600,9 @@ ol.render.canvas.Immediate.prototype.drawLineStringGeometry = * Render a MultiLineString geometry into the canvas. Rendering is immediate * and uses the current style. * - * @param {ol.geom.MultiLineString} multiLineStringGeometry + * @param {ol.geom.MultiLineString|ol.render.Feature} multiLineStringGeometry * MultiLineString geometry. - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @api */ ol.render.canvas.Immediate.prototype.drawMultiLineStringGeometry = @@ -635,8 +637,9 @@ ol.render.canvas.Immediate.prototype.drawMultiLineStringGeometry = * Render a Polygon geometry into the canvas. Rendering is immediate and uses * the current style. * - * @param {ol.geom.Polygon} polygonGeometry Polygon geometry. - * @param {ol.Feature} feature Feature. + * @param {ol.geom.Polygon|ol.render.Feature} polygonGeometry Polygon + * geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @api */ ol.render.canvas.Immediate.prototype.drawPolygonGeometry = @@ -1002,8 +1005,8 @@ ol.render.canvas.Immediate.prototype.setTextStyle = function(textStyle) { * @const * @private * @type {Object.} + * function(this: ol.render.canvas.Immediate, + * (ol.geom.Geometry|ol.render.Feature), Object)>} */ ol.render.canvas.Immediate.GEOMETRY_RENDERERS_ = { 'Point': ol.render.canvas.Immediate.prototype.drawPointGeometry, diff --git a/src/ol/render/canvas/canvasreplay.js b/src/ol/render/canvas/canvasreplay.js index 0e2d7189a9..7b772043c1 100644 --- a/src/ol/render/canvas/canvasreplay.js +++ b/src/ol/render/canvas/canvasreplay.js @@ -202,8 +202,8 @@ ol.render.canvas.Replay.prototype.appendFlatCoordinates = /** * @protected - * @param {ol.geom.Geometry} geometry Geometry. - * @param {ol.Feature} feature Feature. + * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ ol.render.canvas.Replay.prototype.beginGeometry = function(geometry, feature) { this.beginGeometryInstruction1_ = @@ -224,7 +224,8 @@ ol.render.canvas.Replay.prototype.beginGeometry = function(geometry, feature) { * @param {Object.} skippedFeaturesHash Ids of features * to skip. * @param {Array.<*>} instructions Instructions array. - * @param {function(ol.Feature): T|undefined} featureCallback Feature callback. + * @param {function((ol.Feature|ol.render.Feature)): T|undefined} + * featureCallback Feature callback. * @param {ol.Extent=} opt_hitExtent Only check features that intersect this * extent. * @return {T|undefined} Callback result. @@ -256,7 +257,7 @@ ol.render.canvas.Replay.prototype.replay_ = function( var feature, fill, stroke, text, x, y; switch (type) { case ol.render.canvas.Instruction.BEGIN_GEOMETRY: - feature = /** @type {ol.Feature} */ (instruction[1]); + feature = /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]); var featureUid = goog.getUid(feature).toString(); if (skippedFeaturesHash[featureUid] !== undefined || !feature.getGeometry()) { @@ -409,7 +410,7 @@ ol.render.canvas.Replay.prototype.replay_ = function( break; case ol.render.canvas.Instruction.END_GEOMETRY: if (featureCallback !== undefined) { - feature = /** @type {ol.Feature} */ (instruction[1]); + feature = /** @type {ol.Feature|ol.render.Feature} */ (instruction[1]); var result = featureCallback(feature); if (result) { return result; @@ -517,7 +518,8 @@ ol.render.canvas.Replay.prototype.replay = function( * @param {number} viewRotation View rotation. * @param {Object.} skippedFeaturesHash Ids of features * to skip. - * @param {function(ol.Feature): T=} opt_featureCallback Feature callback. + * @param {function((ol.Feature|ol.render.Feature)): T=} opt_featureCallback + * Feature callback. * @param {ol.Extent=} opt_hitExtent Only check features that intersect this * extent. * @return {T|undefined} Callback result. @@ -564,8 +566,8 @@ ol.render.canvas.Replay.prototype.reverseHitDetectionInstructions_ = /** - * @param {ol.geom.Geometry} geometry Geometry. - * @param {ol.Feature} feature Feature. + * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ ol.render.canvas.Replay.prototype.endGeometry = function(geometry, feature) { goog.asserts.assert(this.beginGeometryInstruction1_, @@ -1889,7 +1891,8 @@ ol.render.canvas.ReplayGroup.prototype.finish = function() { * @param {number} rotation Rotation. * @param {Object.} skippedFeaturesHash Ids of features * to skip. - * @param {function(ol.Feature): T} callback Feature callback. + * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature + * callback. * @return {T|undefined} Callback result. * @template T */ @@ -1917,7 +1920,7 @@ ol.render.canvas.ReplayGroup.prototype.forEachFeatureAtCoordinate = function( return this.replayHitDetection_(context, transform, rotation, skippedFeaturesHash, /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @return {?} Callback result. */ function(feature) { @@ -2027,7 +2030,8 @@ ol.render.canvas.ReplayGroup.prototype.replay = function( * @param {number} viewRotation View rotation. * @param {Object.} skippedFeaturesHash Ids of features * to skip. - * @param {function(ol.Feature): T} featureCallback Feature callback. + * @param {function((ol.Feature|ol.render.Feature)): T} featureCallback + * Feature callback. * @param {ol.Extent=} opt_hitExtent Only check features that intersect this * extent. * @return {T|undefined} Callback result. diff --git a/src/ol/render/renderfeature.js b/src/ol/render/renderfeature.js new file mode 100644 index 0000000000..21bc706cd9 --- /dev/null +++ b/src/ol/render/renderfeature.js @@ -0,0 +1,156 @@ +goog.provide('ol.render.Feature'); + + +goog.require('goog.asserts'); +goog.require('goog.functions'); +goog.require('ol.extent'); +goog.require('ol.geom.GeometryType'); + + + +/** + * Lightweight, read-only, {@link ol.Feature} and {@link ol.geom.Geometry} like + * structure, optimized for rendering and styling. Geometry acces through the + * API is limited to getting the type and extent of the geometry. + * + * @constructor + * @param {ol.geom.GeometryType} type Geometry type. + * @param {Array.} flatCoordinates Flat coordinates. + * @param {Array.|Array.>} ends Ends or Endss. + * @param {Object.} properties Properties. + */ +ol.render.Feature = function(type, flatCoordinates, ends, properties) { + + /** + * @private + * @type {ol.Extent|undefined} + */ + this.extent_; + + goog.asserts.assert(type === ol.geom.GeometryType.POINT || + type === ol.geom.GeometryType.MULTI_POINT || + type === ol.geom.GeometryType.LINE_STRING || + type === ol.geom.GeometryType.MULTI_LINE_STRING || + type === ol.geom.GeometryType.POLYGON, + 'Need a Point, MultiPoint, LineString, MultiLineString or Polygon type'); + + /** + * @private + * @type {ol.geom.GeometryType} + */ + this.type_ = type; + + /** + * @private + * @type {Array.} + */ + this.flatCoordinates_ = flatCoordinates; + + /** + * @private + * @type {Array.|Array.>} + */ + this.ends_ = ends; + + /** + * @private + * @type {Object.} + */ + this.properties_ = properties; + +}; + + +/** + * Get a feature property by its key. + * @param {string} key Key + * @return {*} Value for the requested key. + * @api + */ +ol.render.Feature.prototype.get = function(key) { + return this.properties_[key]; +}; + + +/** + * @return {Array.|Array.>} Ends or endss. + */ +ol.render.Feature.prototype.getEnds = function() { + return this.ends_; +}; + + +/** + * Get the extent of this feature's geometry. + * @return {ol.Extent} Extent. + * @api + */ +ol.render.Feature.prototype.getExtent = function() { + if (!goog.isDef(this.extent_)) { + this.extent_ = this.type_ === ol.geom.GeometryType.POINT ? + ol.extent.createOrUpdateFromCoordinate(this.flatCoordinates_) : + ol.extent.createOrUpdateFromFlatCoordinates( + this.flatCoordinates_, 0, this.flatCoordinates_.length, 2); + + } + return this.extent_; +}; + + +/** + * @return {Array.} Flat coordinates. + */ +ol.render.Feature.prototype.getFlatCoordinates = + ol.render.Feature.prototype.getOrientedFlatCoordinates = function() { + return this.flatCoordinates_; +}; + + +/** + * Get the feature for working with its geometry. + * @return {ol.render.Feature} Feature. + * @api + */ +ol.render.Feature.prototype.getGeometry = function() { + return this; +}; + + +/** + * Get the feature properties. + * @return {Object.} Feature properties. + * @api + */ +ol.render.Feature.prototype.getProperties = function() { + return this.properties_; +}; + + +/** + * Get the feature for working with its geometry. + * @return {ol.render.Feature} Feature. + */ +ol.render.Feature.prototype.getSimplifiedGeometry = + ol.render.Feature.prototype.getGeometry; + + +/** + * @return {number} Stride. + */ +ol.render.Feature.prototype.getStride = goog.functions.constant(2); + + +/** + * @return {undefined} + */ +ol.render.Feature.prototype.getStyleFunction = goog.nullFunction; + + +/** + * Get the type of this feature's geometry. + * @return {ol.geom.GeometryType} Geometry type. + * @api + */ +ol.render.Feature.prototype.getType = function() { + return this.type_; +}; diff --git a/src/ol/render/vector.js b/src/ol/render/vector.js index 5c91a013d9..7543740713 100644 --- a/src/ol/render/vector.js +++ b/src/ol/render/vector.js @@ -2,6 +2,7 @@ goog.provide('ol.renderer.vector'); goog.require('goog.asserts'); goog.require('ol.geom.Circle'); +goog.require('ol.geom.Geometry'); goog.require('ol.geom.GeometryCollection'); goog.require('ol.geom.LineString'); goog.require('ol.geom.MultiLineString'); @@ -9,14 +10,15 @@ goog.require('ol.geom.MultiPoint'); goog.require('ol.geom.MultiPolygon'); goog.require('ol.geom.Point'); goog.require('ol.geom.Polygon'); +goog.require('ol.render.Feature'); goog.require('ol.render.IReplayGroup'); goog.require('ol.style.ImageState'); goog.require('ol.style.Style'); /** - * @param {ol.Feature} feature1 Feature 1. - * @param {ol.Feature} feature2 Feature 2. + * @param {ol.Feature|ol.render.Feature} feature1 Feature 1. + * @param {ol.Feature|ol.render.Feature} feature2 Feature 2. * @return {number} Order. */ ol.renderer.vector.defaultOrder = function(feature1, feature2) { @@ -76,7 +78,7 @@ ol.renderer.vector.renderCircleGeometry_ = /** * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @param {ol.style.Style} style Style. * @param {number} squaredTolerance Squared tolerance. * @param {function(this: T, goog.events.Event)} listener Listener function. @@ -113,7 +115,7 @@ ol.renderer.vector.renderFeature = function( /** * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @param {ol.style.Style} style Style. * @param {number} squaredTolerance Squared tolerance. * @private @@ -160,13 +162,15 @@ ol.renderer.vector.renderGeometryCollectionGeometry_ = * @param {ol.render.IReplayGroup} replayGroup Replay group. * @param {ol.geom.Geometry} geometry Geometry. * @param {ol.style.Style} style Style. - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @private */ ol.renderer.vector.renderLineStringGeometry_ = function(replayGroup, geometry, style, feature) { - goog.asserts.assertInstanceof(geometry, ol.geom.LineString, - 'geometry should be an ol.geom.LineString'); + if (geometry instanceof ol.geom.Geometry) { + goog.asserts.assertInstanceof(geometry, ol.geom.LineString, + 'geometry should be an ol.geom.LineString'); + } var strokeStyle = style.getStroke(); if (strokeStyle) { var lineStringReplay = replayGroup.getReplay( @@ -188,13 +192,15 @@ ol.renderer.vector.renderLineStringGeometry_ = * @param {ol.render.IReplayGroup} replayGroup Replay group. * @param {ol.geom.Geometry} geometry Geometry. * @param {ol.style.Style} style Style. - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @private */ ol.renderer.vector.renderMultiLineStringGeometry_ = function(replayGroup, geometry, style, feature) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, - 'geometry should be an ol.geom.MultiLineString'); + if (geometry instanceof ol.geom.Geometry) { + goog.asserts.assertInstanceof(geometry, ol.geom.MultiLineString, + 'geometry should be an ol.geom.MultiLineString'); + } var strokeStyle = style.getStroke(); if (strokeStyle) { var lineStringReplay = replayGroup.getReplay( @@ -249,13 +255,15 @@ ol.renderer.vector.renderMultiPolygonGeometry_ = * @param {ol.render.IReplayGroup} replayGroup Replay group. * @param {ol.geom.Geometry} geometry Geometry. * @param {ol.style.Style} style Style. - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @private */ ol.renderer.vector.renderPointGeometry_ = function(replayGroup, geometry, style, feature) { - goog.asserts.assertInstanceof(geometry, ol.geom.Point, - 'geometry should be an ol.geom.Point'); + if (geometry instanceof ol.geom.Geometry) { + goog.asserts.assertInstanceof(geometry, ol.geom.Point, + 'geometry should be an ol.geom.Point'); + } var imageStyle = style.getImage(); if (imageStyle) { if (imageStyle.getImageState() != ol.style.ImageState.LOADED) { @@ -281,13 +289,15 @@ ol.renderer.vector.renderPointGeometry_ = * @param {ol.render.IReplayGroup} replayGroup Replay group. * @param {ol.geom.Geometry} geometry Geometry. * @param {ol.style.Style} style Style. - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @private */ ol.renderer.vector.renderMultiPointGeometry_ = function(replayGroup, geometry, style, feature) { - goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint, - 'geometry should be an ol.goem.MultiPoint'); + if (geometry instanceof ol.geom.Geometry) { + goog.asserts.assertInstanceof(geometry, ol.geom.MultiPoint, + 'geometry should be an ol.goem.MultiPoint'); + } var imageStyle = style.getImage(); if (imageStyle) { if (imageStyle.getImageState() != ol.style.ImageState.LOADED) { @@ -312,15 +322,17 @@ ol.renderer.vector.renderMultiPointGeometry_ = /** * @param {ol.render.IReplayGroup} replayGroup Replay group. - * @param {ol.geom.Geometry} geometry Geometry. + * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. * @param {ol.style.Style} style Style. - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @private */ ol.renderer.vector.renderPolygonGeometry_ = function(replayGroup, geometry, style, feature) { - goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, - 'geometry should be an ol.geom.Polygon'); + if (geometry instanceof ol.geom.Geometry) { + goog.asserts.assertInstanceof(geometry, ol.geom.Polygon, + 'geometry should be an ol.geom.Polygon or ol.render.Feature'); + } var fillStyle = style.getFill(); var strokeStyle = style.getStroke(); if (fillStyle || strokeStyle) { diff --git a/src/ol/render/vectorcontext.js b/src/ol/render/vectorcontext.js index 5345a592a0..f643c56d5a 100644 --- a/src/ol/render/vectorcontext.js +++ b/src/ol/render/vectorcontext.js @@ -44,25 +44,27 @@ ol.render.VectorContext.prototype.drawGeometryCollectionGeometry = /** - * @param {ol.geom.LineString} lineStringGeometry Line string geometry. - * @param {ol.Feature} feature Feature. + * @param {ol.geom.LineString|ol.render.Feature} lineStringGeometry Line + * string geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ ol.render.VectorContext.prototype.drawLineStringGeometry = goog.abstractMethod; /** - * @param {ol.geom.MultiLineString} multiLineStringGeometry + * @param {ol.geom.MultiLineString|ol.render.Feature} multiLineStringGeometry * MultiLineString geometry. - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ ol.render.VectorContext.prototype.drawMultiLineStringGeometry = goog.abstractMethod; /** - * @param {ol.geom.MultiPoint} multiPointGeometry MultiPoint geometry. - * @param {ol.Feature} feature Feature. + * @param {ol.geom.MultiPoint|ol.render.Feature} multiPointGeometry MultiPoint + * geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ ol.render.VectorContext.prototype.drawMultiPointGeometry = goog.abstractMethod; @@ -76,15 +78,16 @@ ol.render.VectorContext.prototype.drawMultiPolygonGeometry = /** - * @param {ol.geom.Point} pointGeometry Point geometry. - * @param {ol.Feature} feature Feature. + * @param {ol.geom.Point|ol.render.Feature} pointGeometry Point geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ ol.render.VectorContext.prototype.drawPointGeometry = goog.abstractMethod; /** - * @param {ol.geom.Polygon} polygonGeometry Polygon geometry. - * @param {ol.Feature} feature Feature. + * @param {ol.geom.Polygon|ol.render.Feature} polygonGeometry Polygon + * geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ ol.render.VectorContext.prototype.drawPolygonGeometry = goog.abstractMethod; @@ -94,8 +97,8 @@ ol.render.VectorContext.prototype.drawPolygonGeometry = goog.abstractMethod; * @param {number} offset Offset. * @param {number} end End. * @param {number} stride Stride. - * @param {ol.geom.Geometry} geometry Geometry. - * @param {ol.Feature} feature Feature. + * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry. + * @param {ol.Feature|ol.render.Feature} feature Feature. */ ol.render.VectorContext.prototype.drawText = goog.abstractMethod; diff --git a/src/ol/render/webgl/webglimmediate.js b/src/ol/render/webgl/webglimmediate.js index a0f45b0af0..1981e67ef2 100644 --- a/src/ol/render/webgl/webglimmediate.js +++ b/src/ol/render/webgl/webglimmediate.js @@ -294,8 +294,8 @@ ol.render.webgl.Immediate.prototype.setTextStyle = function(textStyle) { * @const * @private * @type {Object.} + * function(this: ol.render.webgl.Immediate, + * (ol.geom.Geometry|ol.render.Feature), Object)>} */ ol.render.webgl.Immediate.GEOMETRY_RENDERERS_ = { 'Point': ol.render.webgl.Immediate.prototype.drawPointGeometry, diff --git a/src/ol/renderer/canvas/canvasimagelayerrenderer.js b/src/ol/renderer/canvas/canvasimagelayerrenderer.js index 22fae30287..9346fbc8f2 100644 --- a/src/ol/renderer/canvas/canvasimagelayerrenderer.js +++ b/src/ol/renderer/canvas/canvasimagelayerrenderer.js @@ -65,7 +65,7 @@ ol.renderer.canvas.ImageLayer.prototype.forEachFeatureAtCoordinate = return source.forEachFeatureAtCoordinate( coordinate, resolution, rotation, skippedFeatureUids, /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @return {?} Callback result. */ function(feature) { diff --git a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js index d0c96994cc..5784df90af 100644 --- a/src/ol/renderer/canvas/canvasvectorlayerrenderer.js +++ b/src/ol/renderer/canvas/canvasvectorlayerrenderer.js @@ -168,7 +168,7 @@ ol.renderer.canvas.VectorLayer.prototype.forEachFeatureAtCoordinate = return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution, rotation, layerState.managed ? frameState.skippedFeatureUids : {}, /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @return {?} Callback result. */ function(feature) { diff --git a/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js b/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js index 76987cf96c..666834497f 100644 --- a/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js +++ b/src/ol/renderer/canvas/canvasvectortilelayerrenderer.js @@ -5,6 +5,7 @@ goog.require('goog.asserts'); goog.require('goog.events'); goog.require('goog.object'); goog.require('goog.vec.Mat4'); +goog.require('ol.Feature'); goog.require('ol.TileRange'); goog.require('ol.TileState'); goog.require('ol.VectorTile'); @@ -193,12 +194,13 @@ ol.renderer.canvas.VectorTileLayer.prototype.createReplayGroup = function(tile, tileResolution, layer.getRenderBuffer(), source.getRightHandedPolygons()); /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @this {ol.renderer.canvas.VectorTileLayer} */ function renderFeature(feature) { var styles; if (goog.isDef(feature.getStyleFunction())) { + goog.asserts.assertInstanceof(feature, ol.Feature, 'Got an ol.Feature'); styles = feature.getStyleFunction().call(feature, resolution); } else if (goog.isDef(layer.getStyleFunction())) { styles = layer.getStyleFunction()(feature, resolution); @@ -273,7 +275,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.forEachFeatureAtCoordinate = tileSpaceCoordinate, resolution, rotation, layerState.managed ? frameState.skippedFeatureUids : {}, /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @return {?} Callback result. */ function(feature) { @@ -413,7 +415,7 @@ ol.renderer.canvas.VectorTileLayer.prototype.prepareFrame = /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @param {number} squaredTolerance Squared tolerance. * @param {Array.} styles Array of styles * @param {ol.render.canvas.ReplayGroup} replayGroup Replay group. diff --git a/src/ol/renderer/dom/domimagelayerrenderer.js b/src/ol/renderer/dom/domimagelayerrenderer.js index 033de8614b..f60702a394 100644 --- a/src/ol/renderer/dom/domimagelayerrenderer.js +++ b/src/ol/renderer/dom/domimagelayerrenderer.js @@ -55,7 +55,7 @@ ol.renderer.dom.ImageLayer.prototype.forEachFeatureAtCoordinate = return source.forEachFeatureAtCoordinate( coordinate, resolution, rotation, skippedFeatureUids, /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @return {?} Callback result. */ function(feature) { diff --git a/src/ol/renderer/dom/domvectorlayerrenderer.js b/src/ol/renderer/dom/domvectorlayerrenderer.js index 3239f82c72..3a221b9376 100644 --- a/src/ol/renderer/dom/domvectorlayerrenderer.js +++ b/src/ol/renderer/dom/domvectorlayerrenderer.js @@ -190,7 +190,7 @@ ol.renderer.dom.VectorLayer.prototype.forEachFeatureAtCoordinate = return this.replayGroup_.forEachFeatureAtCoordinate(coordinate, resolution, rotation, layerState.managed ? frameState.skippedFeatureUids : {}, /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @return {?} Callback result. */ function(feature) { diff --git a/src/ol/renderer/layerrenderer.js b/src/ol/renderer/layerrenderer.js index cd0dba0093..7ab15e54a2 100644 --- a/src/ol/renderer/layerrenderer.js +++ b/src/ol/renderer/layerrenderer.js @@ -42,8 +42,8 @@ goog.inherits(ol.renderer.Layer, ol.Observable); /** * @param {ol.Coordinate} coordinate Coordinate. * @param {olx.FrameState} frameState Frame state. - * @param {function(this: S, ol.Feature, ol.layer.Layer): T} callback Feature - * callback. + * @param {function(this: S, (ol.Feature|ol.render.Feature), ol.layer.Layer): T} + * callback Feature callback. * @param {S} thisArg Value to use as `this` when executing `callback`. * @return {T|undefined} Callback result. * @template S,T diff --git a/src/ol/renderer/maprenderer.js b/src/ol/renderer/maprenderer.js index 7cd56f3c00..de5a49d80d 100644 --- a/src/ol/renderer/maprenderer.js +++ b/src/ol/renderer/maprenderer.js @@ -114,8 +114,8 @@ ol.renderer.Map.expireIconCache_ = function(map, frameState) { /** * @param {ol.Coordinate} coordinate Coordinate. * @param {olx.FrameState} frameState FrameState. - * @param {function(this: S, ol.Feature, ol.layer.Layer): T} callback Feature - * callback. + * @param {function(this: S, (ol.Feature|ol.render.Feature), + * ol.layer.Layer): T} callback Feature callback. * @param {S} thisArg Value to use as `this` when executing `callback`. * @param {function(this: U, ol.layer.Layer): boolean} layerFilter Layer filter * function, only layers which are visible and for which this function @@ -136,7 +136,7 @@ ol.renderer.Map.prototype.forEachFeatureAtCoordinate = var features = {}; /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @return {?} Callback result. */ function forEachFeatureAtCoordinate(feature) { diff --git a/src/ol/renderer/webgl/webglimagelayerrenderer.js b/src/ol/renderer/webgl/webglimagelayerrenderer.js index 8aad156335..dc8d7cc51d 100644 --- a/src/ol/renderer/webgl/webglimagelayerrenderer.js +++ b/src/ol/renderer/webgl/webglimagelayerrenderer.js @@ -85,7 +85,7 @@ ol.renderer.webgl.ImageLayer.prototype.forEachFeatureAtCoordinate = coordinate, resolution, rotation, skippedFeatureUids, /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @return {?} Callback result. */ function(feature) { diff --git a/src/ol/source/imagevectorsource.js b/src/ol/source/imagevectorsource.js index c940996abd..c02a618b50 100644 --- a/src/ol/source/imagevectorsource.js +++ b/src/ol/source/imagevectorsource.js @@ -162,7 +162,7 @@ ol.source.ImageVector.prototype.forEachFeatureAtCoordinate = function( return this.replayGroup_.forEachFeatureAtCoordinate( coordinate, resolution, 0, skippedFeatureUids, /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @return {?} Callback result. */ function(feature) { diff --git a/src/ol/source/source.js b/src/ol/source/source.js index 38261a0e12..84f0c6208e 100644 --- a/src/ol/source/source.js +++ b/src/ol/source/source.js @@ -89,7 +89,8 @@ goog.inherits(ol.source.Source, ol.Object); * @param {number} resolution Resolution. * @param {number} rotation Rotation. * @param {Object.} skippedFeatureUids Skipped feature uids. - * @param {function(ol.Feature): T} callback Feature callback. + * @param {function((ol.Feature|ol.render.Feature)): T} callback Feature + * callback. * @return {T|undefined} Callback result. * @template T */ diff --git a/src/ol/source/tilesource.js b/src/ol/source/tilesource.js index e47afe0d3f..648a77b564 100644 --- a/src/ol/source/tilesource.js +++ b/src/ol/source/tilesource.js @@ -19,6 +19,7 @@ goog.require('ol.tilegrid.TileGrid'); /** * @typedef {{attributions: (Array.|undefined), + * cacheSize: (number|undefined), * extent: (ol.Extent|undefined), * logo: (string|olx.LogoOptions|undefined), * opaque: (boolean|undefined), @@ -77,7 +78,7 @@ ol.source.Tile = function(options) { * @protected * @type {ol.TileCache} */ - this.tileCache = new ol.TileCache(); + this.tileCache = new ol.TileCache(options.cacheSize); /** * @protected diff --git a/src/ol/source/tilevectorsource.js b/src/ol/source/tilevectorsource.js index 902dafb021..1ca9c23522 100644 --- a/src/ol/source/tilevectorsource.js +++ b/src/ol/source/tilevectorsource.js @@ -310,7 +310,8 @@ ol.source.TileVector.prototype.loadFeatures = this.tileLoadFunction_(url, goog.bind(tileSuccess, this)); } else { var loader = ol.featureloader.loadFeaturesXhr(url, - /** @type {ol.format.Feature} */ (this.format_), tileSuccess); + /** @type {ol.format.Feature} */ (this.format_), tileSuccess, + goog.nullFunction); loader.call(this, extent, resolution, projection); } } diff --git a/src/ol/source/urltilesource.js b/src/ol/source/urltilesource.js index ccec07a350..f675aca898 100644 --- a/src/ol/source/urltilesource.js +++ b/src/ol/source/urltilesource.js @@ -11,7 +11,6 @@ goog.require('ol.source.TileEvent'); /** * @typedef {{attributions: (Array.|undefined), - * cacheSize: (number|undefined), * extent: (ol.Extent|undefined), * logo: (string|olx.LogoOptions|undefined), * opaque: (boolean|undefined), @@ -40,6 +39,7 @@ ol.source.UrlTile = function(options) { goog.base(this, { attributions: options.attributions, + cacheSize: options.cacheSize, extent: options.extent, logo: options.logo, opaque: options.opaque, diff --git a/src/ol/source/vectortilesource.js b/src/ol/source/vectortilesource.js index 7fb8524400..4b264bcbff 100644 --- a/src/ol/source/vectortilesource.js +++ b/src/ol/source/vectortilesource.js @@ -24,6 +24,7 @@ ol.source.VectorTile = function(options) { goog.base(this, { attributions: options.attributions, + cacheSize: ol.DEFAULT_TILE_CACHE_HIGH_WATER_MARK / 16, extent: options.extent, logo: options.logo, opaque: options.opaque, @@ -38,10 +39,6 @@ ol.source.VectorTile = function(options) { wrapX: options.wrapX }); - this.assumeRightHandedPolygons_ = - goog.isDef(options.assumeRightHandedPolygons) ? - options.assumeRightHandedPolygons : false; - /** * @private * @type {ol.format.Feature} @@ -60,14 +57,6 @@ ol.source.VectorTile = function(options) { goog.inherits(ol.source.VectorTile, ol.source.UrlTile); -/** - * @return {boolean} Assume right handed polygons. - */ -ol.source.VectorTile.prototype.getRightHandedPolygons = function() { - return this.assumeRightHandedPolygons_; -}; - - /** * @inheritDoc */ diff --git a/src/ol/style/style.js b/src/ol/style/style.js index 3e4c1d46eb..5adb92755e 100644 --- a/src/ol/style/style.js +++ b/src/ol/style/style.js @@ -198,7 +198,8 @@ ol.style.Style.prototype.setZIndex = function(zIndex) { * the view's resolution. The function should return an array of * {@link ol.style.Style}. This way e.g. a vector layer can be styled. * - * @typedef {function(ol.Feature, number): Array.} + * @typedef {function((ol.Feature|ol.render.Feature), number): + * Array.} * @api */ ol.style.StyleFunction; @@ -245,7 +246,7 @@ ol.style.defaultStyle_ = null; /** - * @param {ol.Feature} feature Feature. + * @param {ol.Feature|ol.render.Feature} feature Feature. * @param {number} resolution Resolution. * @return {Array.} Style. */ @@ -354,7 +355,8 @@ ol.style.createDefaultEditingStyles = function() { * A function that takes an {@link ol.Feature} as argument and returns an * {@link ol.geom.Geometry} that will be rendered and styled for the feature. * - * @typedef {function(ol.Feature): (ol.geom.Geometry|undefined)} + * @typedef {function((ol.Feature|ol.render.Feature)): + * (ol.geom.Geometry|ol.render.Feature|undefined)} * @api */ ol.style.GeometryFunction; @@ -362,8 +364,9 @@ ol.style.GeometryFunction; /** * Function that is called with a feature and returns its default geometry. - * @param {ol.Feature} feature Feature to get the geometry for. - * @return {ol.geom.Geometry|undefined} Geometry to render. + * @param {ol.Feature|ol.render.Feature} feature Feature to get the geometry + * for. + * @return {ol.geom.Geometry|ol.render.Feature|undefined} Geometry to render. */ ol.style.defaultGeometryFunction = function(feature) { goog.asserts.assert(feature, 'feature must not be null'); diff --git a/test/spec/ol/format/mvtformat.test.js b/test/spec/ol/format/mvtformat.test.js index 9f77d889ac..2e722746a8 100644 --- a/test/spec/ol/format/mvtformat.test.js +++ b/test/spec/ol/format/mvtformat.test.js @@ -17,6 +17,12 @@ describe('ol.format.MVT', function() { describe('#readFeatures', function() { + it('uses ol.render.Feature as feature class by default', function() { + var format = new ol.format.MVT({layers: ['water']}); + var features = format.readFeatures(data); + expect(features[0]).to.be.a(ol.render.Feature); + }); + it('parses only specified layers', function() { var format = new ol.format.MVT({layers: ['water']}); var features = format.readFeatures(data); @@ -24,7 +30,10 @@ describe('ol.format.MVT', function() { }); it('parses geometries correctly', function() { - var format = new ol.format.MVT({layers: ['poi_label']}); + var format = new ol.format.MVT({ + featureClass: ol.Feature, + layers: ['poi_label'] + }); var pbf = new ol.ext.pbf(data); var tile = new ol.ext.vectortile.VectorTile(pbf); var geometry, rawGeometry; @@ -66,3 +75,4 @@ goog.require('ol.Feature'); goog.require('ol.ext.pbf'); goog.require('ol.ext.vectortile'); goog.require('ol.format.MVT'); +goog.require('ol.render.Feature');