From d0d397f98f43c7adce06ed97228a874497f8ecc1 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Sun, 20 Jan 2013 21:23:19 +0100 Subject: [PATCH] Tiled vector source This source has features and provides tiles with the feature geometries rendered, using the feature symbolizers. Needs more work because it is still very unefficient, because it renders all feature geometries to all tiles, and uses a collection of features, which we do not have yet. --- src/ol/source/tiledvectorsource.js | 205 +++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 src/ol/source/tiledvectorsource.js diff --git a/src/ol/source/tiledvectorsource.js b/src/ol/source/tiledvectorsource.js new file mode 100644 index 0000000000..a9a9fda49f --- /dev/null +++ b/src/ol/source/tiledvectorsource.js @@ -0,0 +1,205 @@ +goog.provide('ol.source.TiledVector'); +goog.provide('ol.source.TiledVectorOptions'); + + +goog.require('goog.array'); +goog.require('goog.object'); +goog.require('ol.Projection'); +goog.require('ol.source.TileSource'); +goog.require('ol.tilegrid.TileGrid'); + + +/** + * @typedef {{features: (ol.Collection|undefined), + * extent: (ol.Extent|undefined), + * projection: (ol.Projection|undefined), + * tileGrid: (ol.tilegrid.TileGrid|undefined)}} + */ +ol.source.TiledVectorOptions; + + + +/** + * @constructor + * @extends {ol.Tile} + * @param {ol.TileCoord} tileCoord Tile coordinate. + * @param {ol.tilegrid.TileGrid} tileGrid Tile grid. + * @private + */ +ol.VectorTile_ = function(tileCoord, tileGrid) { + + goog.base(this, tileCoord); + + this.state = ol.TileState.LOADING; + + /** + * @private + * @type {!goog.vec.Mat4.Number} + */ + this.transform_ = goog.vec.Mat4.createNumber(); + + /** + * @private + * @type {Object.} + * FIXME needs to be cleared when the data changes + */ + this.canvasByContext_ = {}; + + /** + * @private + * @type {ol.renderer.canvas.Renderer} + * FIXME Use a shared renderer and cut out tiles; keep track of rendered items + */ + this.renderer_ = this.createRenderer_(tileGrid); + +}; +goog.inherits(ol.VectorTile_, ol.Tile); + + +/** + * @private + * @param {ol.TileGrid} tileGrid tileGrid. + * @return {ol.renderer.canvas.Renderer} The renderer for this tile. + */ +ol.VectorTile_.prototype.createRenderer_ = function(tileGrid) { + var tileSize = tileGrid.getTileSize(); + var canvas = /** @type {HTMLCanvasElement} */ + (goog.dom.createElement(goog.dom.TagName.CANVAS)); + canvas.width = tileSize.width; + canvas.height = tileSize.height; + + var transform = this.transform_; + var origin = tileGrid.getExtent_.getTopLeft(); + var resolution = tileGrid.getResolution(); + goog.vec.Mat4.makeIdentity(transform); + goog.vec.Mat4.scale(transform, resolution, resolution, 1); + goog.vec.Mat4.translate(transform, + origin.x / resolution, -origin.y / resolution, 0); + + this.canvasByContext_[key] = canvas; + + return ol.renderer.canvas.Renderer(canvas, transform); +}; + + +/** + * @param {Array.} geometries Geometries for this tile. + * @param {Array.} symbolizers Symbolizers for the + * geometries, in the same order. + */ +ol.VectorTile_.prototype.setContent = function(geometries, symbolizers) { + this.state = ol.TileState.LOADED; + + var uniqueSymbolizers = []; + goog.array.removeDuplicates(symbolizers, uniqueSymbolizers); + + var geometriesBySymbolizer = goog.array.bucket(geometries, function(e, i) { + var index = goog.array.indexOf(uniqueSymbolizers, symbolizers[i]); + return index === -1 ? undefined : index; + }); + + var buckets, + renderer = this.renderer_, + type = {line: 'line', point: 'point', polygon: 'polygon'}; + function sortByGeometryType(geometry) { + if (geometry instanceof ol.geom.LineString) { + return type['line']; + } else if (geometry instanceof ol.geom.Point) { + return type['point']; + } else if (geometry instanceof ol.geom.Polygon) { + return type['polygon']; + } + } + for (var i = 0, ii = uniqueSymbolizers.length; i < ii; ++i) { + buckets = ol.array.bucket(geometriesBySymbolizer[i], sortByGeometryType); + renderer.renderLineStrings(buckets[type['line']], uniqueSymbolizers[i]); + renderer.renderPoints(buckets[type['point']], uniqueSymbolizers[i]); + renderer.renderPolygons(buckets[type['polygon']], uniqueSymbolizers[i]); + } +}; + + +/** + * @inheritDoc + */ +ol.VectorTile_.prototype.getImage = function(opt_context) { + var key = goog.isDef(opt_context) ? goog.getUid(opt_context) : -1; + if (key in this.canvasByContext_) { + return this.canvasByContext_[key]; + } else { + + return canvas; + + } +}; + + + +/** + * @constructor + * @extends {ol.source.TileSource} + * @param {ol.source.TiledVectorOptions} options options. + */ +ol.source.TiledVector = function(options) { + + /** + * @type {ol.Collection} + * @private + */ + this.features_ = goog.isDef(options.features) ? + options.features : new ol.Collection(); + + /** + * @private + * @type {Object.} + * FIXME will need to expire elements from this cache + * FIXME will need to invalidate tiles when data changes + */ + this.tileCache_ = {}; + + var projection = ol.Projection.createProjection( + options.projection, 'EPSG:3857'); + + goog.base(this, { + extent: goog.isDef(options.extent) ? + options.extent : projection.getExtent(), + projection: projection, + tileGrid: goog.isDef(options.tileGrid) ? + options.tileGrid : ol.tilegrid.createForProjection(projection) + }); + +}; +goog.inherits(ol.source.TiledVector, ol.source.TileSource); + + +/** + * @return {ol.Collection} This layer's features. + */ +ol.source.TiledVector.prototype.getFeatures = function() { + return this.features_; +}; + + +/** + * @inheritDoc + */ +ol.source.TiledVector.prototype.getTile = function(tileCoord) { + var extent = this.tileGrid.getTileCoordExtent(tileCoord); + var key = tileCoord.toString(); + if (goog.object.containsKey(this.tileCache_, key)) { + return this.tileCache_[key]; + } else { + var tile = new ol.VectorTile_(tileCoord, this.tileGrid), + geometries = [], + symbolizers = []; + // FIXME only pass geometries for tile extent + this.features_.forEach(function(feature) { + geometries.push(feature.getGeometry()); + symbolizers.push(feature.getSymbolizer()); + }); + tile.setContent(geometries, symbolizers); + + this.tileCache_[key] = tile; + return tile; + } +};