Introduce ol.format.MVT
This commit is contained in:
@@ -1685,6 +1685,40 @@ olx.format.EsriJSONOptions;
|
|||||||
olx.format.EsriJSONOptions.prototype.geometryName;
|
olx.format.EsriJSONOptions.prototype.geometryName;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef {{geometryName: (string|undefined),
|
||||||
|
* layers: (Array.<string>|undefined),
|
||||||
|
* layerName: (string|undefined)}}
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
olx.format.MVTOptions;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Geometry name to use when creating features. Default is 'geometry'.
|
||||||
|
* @type {string|undefined}
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
olx.format.MVTOptions.prototype.geometryName;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the feature attribute that holds the layer name. Default is 'layer'.
|
||||||
|
* @type {string|undefined}
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
olx.format.MVTOptions.prototype.layerName;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Layers to read features from. If not provided, features will be read from all
|
||||||
|
* layers.
|
||||||
|
* @type {Array.<string>|undefined}
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
olx.format.MVTOptions.prototype.layers;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{factor: (number|undefined),
|
* @typedef {{factor: (number|undefined),
|
||||||
* geometryLayout: (ol.geom.GeometryLayout|undefined)}}
|
* geometryLayout: (ol.geom.GeometryLayout|undefined)}}
|
||||||
|
|||||||
@@ -38,9 +38,11 @@
|
|||||||
"metalsmith": "1.6.0",
|
"metalsmith": "1.6.0",
|
||||||
"metalsmith-templates": "0.7.0",
|
"metalsmith-templates": "0.7.0",
|
||||||
"nomnom": "1.8.0",
|
"nomnom": "1.8.0",
|
||||||
|
"pbf": "1.3.5",
|
||||||
"pixelworks": "1.0.0",
|
"pixelworks": "1.0.0",
|
||||||
"rbush": "1.3.5",
|
"rbush": "1.3.5",
|
||||||
"temp": "0.8.1",
|
"temp": "0.8.1",
|
||||||
|
"vector-tile": "1.1.3",
|
||||||
"walk": "2.3.4"
|
"walk": "2.3.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -64,6 +66,8 @@
|
|||||||
},
|
},
|
||||||
"ext": [
|
"ext": [
|
||||||
"rbush",
|
"rbush",
|
||||||
{"module": "pixelworks", "browserify": true}
|
{"module": "pbf", "browserify": true},
|
||||||
|
{"module": "pixelworks", "browserify": true},
|
||||||
|
{"module": "vector-tile", "name": "vectortile", "browserify": true}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,10 @@ ol.featureloader.loadFeaturesXhr = function(url, format, success) {
|
|||||||
*/
|
*/
|
||||||
function(extent, resolution, projection) {
|
function(extent, resolution, projection) {
|
||||||
var xhrIo = new goog.net.XhrIo();
|
var xhrIo = new goog.net.XhrIo();
|
||||||
xhrIo.setResponseType(goog.net.XhrIo.ResponseType.TEXT);
|
xhrIo.setResponseType(
|
||||||
|
format.getType() == ol.format.FormatType.ARRAY_BUFFER ?
|
||||||
|
goog.net.XhrIo.ResponseType.ARRAY_BUFFER :
|
||||||
|
goog.net.XhrIo.ResponseType.TEXT);
|
||||||
goog.events.listen(xhrIo, goog.net.EventType.COMPLETE,
|
goog.events.listen(xhrIo, goog.net.EventType.COMPLETE,
|
||||||
/**
|
/**
|
||||||
* @param {Event} event Event.
|
* @param {Event} event Event.
|
||||||
@@ -87,6 +90,8 @@ ol.featureloader.loadFeaturesXhr = function(url, format, success) {
|
|||||||
if (!source) {
|
if (!source) {
|
||||||
source = ol.xml.parse(xhrIo.getResponseText());
|
source = ol.xml.parse(xhrIo.getResponseText());
|
||||||
}
|
}
|
||||||
|
} else if (type == ol.format.FormatType.ARRAY_BUFFER) {
|
||||||
|
source = xhrIo.getResponse();
|
||||||
} else {
|
} else {
|
||||||
goog.asserts.fail('unexpected format type');
|
goog.asserts.fail('unexpected format type');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ ol.format.Feature.prototype.readFeature = goog.abstractMethod;
|
|||||||
/**
|
/**
|
||||||
* Read all features from a source.
|
* Read all features from a source.
|
||||||
*
|
*
|
||||||
* @param {Document|Node|Object|string} source Source.
|
* @param {Document|Node|ArrayBuffer|Object|string} source Source.
|
||||||
* @param {olx.format.ReadOptions=} opt_options Read options.
|
* @param {olx.format.ReadOptions=} opt_options Read options.
|
||||||
* @return {Array.<ol.Feature>} Features.
|
* @return {Array.<ol.Feature>} Features.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ goog.provide('ol.format.FormatType');
|
|||||||
* @enum {string}
|
* @enum {string}
|
||||||
*/
|
*/
|
||||||
ol.format.FormatType = {
|
ol.format.FormatType = {
|
||||||
|
ARRAY_BUFFER: 'arraybuffer',
|
||||||
JSON: 'json',
|
JSON: 'json',
|
||||||
TEXT: 'text',
|
TEXT: 'text',
|
||||||
XML: 'xml'
|
XML: 'xml'
|
||||||
|
|||||||
196
src/ol/format/mvtformat.js
Normal file
196
src/ol/format/mvtformat.js
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
//FIXME Implement projection handling
|
||||||
|
|
||||||
|
goog.provide('ol.format.MVT');
|
||||||
|
|
||||||
|
goog.require('goog.array');
|
||||||
|
goog.require('goog.asserts');
|
||||||
|
goog.require('ol.Feature');
|
||||||
|
goog.require('ol.ext.pbf');
|
||||||
|
goog.require('ol.ext.vectortile');
|
||||||
|
goog.require('ol.format.Feature');
|
||||||
|
goog.require('ol.format.FormatType');
|
||||||
|
goog.require('ol.geom.Geometry');
|
||||||
|
goog.require('ol.geom.GeometryLayout');
|
||||||
|
goog.require('ol.geom.LineString');
|
||||||
|
goog.require('ol.geom.MultiLineString');
|
||||||
|
goog.require('ol.geom.MultiPoint');
|
||||||
|
goog.require('ol.geom.Point');
|
||||||
|
goog.require('ol.geom.Polygon');
|
||||||
|
goog.require('ol.proj');
|
||||||
|
goog.require('ol.proj.Projection');
|
||||||
|
goog.require('ol.proj.Units');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @classdesc
|
||||||
|
* Feature format for reading data in the Mapbox MVT format.
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
* @extends {ol.format.Feature}
|
||||||
|
* @param {olx.format.MVTOptions=} opt_options Options.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
ol.format.MVT = function(opt_options) {
|
||||||
|
|
||||||
|
goog.base(this);
|
||||||
|
|
||||||
|
var options = goog.isDef(opt_options) ? opt_options : {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {ol.proj.Projection}
|
||||||
|
*/
|
||||||
|
this.defaultDataProjection = new ol.proj.Projection({
|
||||||
|
code: 'EPSG:3857',
|
||||||
|
units: ol.proj.Units.TILE_PIXELS
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.geometryName_ = goog.isDef(options.geometryName) ?
|
||||||
|
options.geometryName : 'geometry';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.layerName_ = goog.isDef(options.layerName) ? options.layerName : 'layer';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @type {Array.<string>}
|
||||||
|
*/
|
||||||
|
this.layers_ = goog.isDef(options.layers) ? options.layers : null;
|
||||||
|
|
||||||
|
};
|
||||||
|
goog.inherits(ol.format.MVT, ol.format.Feature);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
ol.format.MVT.prototype.getType = function() {
|
||||||
|
return ol.format.FormatType.ARRAY_BUFFER;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {Object} rawFeature Raw Mapbox feature.
|
||||||
|
* @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();
|
||||||
|
var values = rawFeature.properties;
|
||||||
|
var geometry = ol.format.Feature.transformWithOptions(
|
||||||
|
ol.format.MVT.readGeometry_(rawFeature), false,
|
||||||
|
this.adaptOptions(opt_options));
|
||||||
|
if (!goog.isNull(geometry)) {
|
||||||
|
goog.asserts.assertInstanceof(geometry, ol.geom.Geometry);
|
||||||
|
values[this.geometryName_] = geometry;
|
||||||
|
}
|
||||||
|
feature.setProperties(rawFeature.properties);
|
||||||
|
feature.setGeometryName(this.geometryName_);
|
||||||
|
return feature;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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 layer, feature;
|
||||||
|
for (var name in tile.layers) {
|
||||||
|
if (!goog.isNull(layers) && !goog.array.contains(layers, name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
features.push(feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return features;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
ol.format.MVT.prototype.readProjection = function(source) {
|
||||||
|
return this.defaultDataProjection;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the layers that features will be read from.
|
||||||
|
* @param {Array.<string>} layers Layers.
|
||||||
|
* @api
|
||||||
|
*/
|
||||||
|
ol.format.MVT.prototype.setLayers = function(layers) {
|
||||||
|
this.layers_ = layers;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
* @param {Object} rawFeature Raw Mapbox feature.
|
||||||
|
* @return {ol.geom.Geometry} Geometry.
|
||||||
|
*/
|
||||||
|
ol.format.MVT.readGeometry_ = function(rawFeature) {
|
||||||
|
var type = rawFeature.type;
|
||||||
|
if (type === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 geom;
|
||||||
|
if (type === 1) {
|
||||||
|
geom = coords.length === 1 ?
|
||||||
|
new ol.geom.Point(null) : new ol.geom.MultiPoint(null);
|
||||||
|
} else if (type === 2) {
|
||||||
|
if (coords.length === 1) {
|
||||||
|
geom = new ol.geom.LineString(null);
|
||||||
|
} else {
|
||||||
|
geom = new ol.geom.MultiLineString(null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
geom = new ol.geom.Polygon(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
geom.setFlatCoordinates(ol.geom.GeometryLayout.XY, flatCoordinates,
|
||||||
|
ends);
|
||||||
|
|
||||||
|
return geom;
|
||||||
|
};
|
||||||
BIN
test/spec/ol/data/14-8938-5680.vector.pbf
Normal file
BIN
test/spec/ol/data/14-8938-5680.vector.pbf
Normal file
Binary file not shown.
68
test/spec/ol/format/mvtformat.test.js
Normal file
68
test/spec/ol/format/mvtformat.test.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
goog.provide('ol.test.format.MVT');
|
||||||
|
|
||||||
|
|
||||||
|
describe('ol.format.MVT', function() {
|
||||||
|
|
||||||
|
var data;
|
||||||
|
beforeEach(function(done) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', 'spec/ol/data/14-8938-5680.vector.pbf');
|
||||||
|
xhr.responseType = 'arraybuffer';
|
||||||
|
xhr.onload = function() {
|
||||||
|
data = xhr.response;
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
xhr.send();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#readFeatures', function() {
|
||||||
|
|
||||||
|
it('parses only specified layers', function() {
|
||||||
|
var format = new ol.format.MVT({layers: ['water']});
|
||||||
|
var features = format.readFeatures(data);
|
||||||
|
expect(features.length).to.be(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('parses geometries correctly', function() {
|
||||||
|
var format = new ol.format.MVT({layers: ['poi_label']});
|
||||||
|
var pbf = new ol.ext.pbf(data);
|
||||||
|
var tile = new ol.ext.vectortile.VectorTile(pbf);
|
||||||
|
var geometry, rawGeometry;
|
||||||
|
|
||||||
|
rawGeometry = tile.layers['poi_label'].feature(0).loadGeometry();
|
||||||
|
geometry = format.readFeatures(data)[0]
|
||||||
|
.getGeometry();
|
||||||
|
expect(geometry.getType()).to.be('Point');
|
||||||
|
expect(geometry.getCoordinates())
|
||||||
|
.to.eql([rawGeometry[0][0].x, rawGeometry[0][0].y]);
|
||||||
|
|
||||||
|
rawGeometry = tile.layers['water'].feature(0).loadGeometry();
|
||||||
|
format.setLayers(['water']);
|
||||||
|
geometry = format.readFeatures(data)[0]
|
||||||
|
.getGeometry();
|
||||||
|
expect(geometry.getType()).to.be('Polygon');
|
||||||
|
expect(rawGeometry[0].length)
|
||||||
|
.to.equal(geometry.getCoordinates()[0].length);
|
||||||
|
expect(geometry.getCoordinates()[0][0])
|
||||||
|
.to.eql([rawGeometry[0][0].x, rawGeometry[0][0].y]);
|
||||||
|
|
||||||
|
rawGeometry = tile.layers['barrier_line'].feature(0).loadGeometry();
|
||||||
|
format.setLayers(['barrier_line']);
|
||||||
|
geometry = format.readFeatures(data)[0]
|
||||||
|
.getGeometry();
|
||||||
|
expect(geometry.getType()).to.be('MultiLineString');
|
||||||
|
expect(rawGeometry[1].length)
|
||||||
|
.to.equal(geometry.getCoordinates()[1].length);
|
||||||
|
expect(geometry.getCoordinates()[1][0])
|
||||||
|
.to.eql([rawGeometry[1][0].x, rawGeometry[1][0].y]);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
goog.require('ol.Feature');
|
||||||
|
goog.require('ol.ext.pbf');
|
||||||
|
goog.require('ol.ext.vectortile');
|
||||||
|
goog.require('ol.format.MVT');
|
||||||
Reference in New Issue
Block a user