Merge pull request #844 from tschaub/topojson
Parser for reading TopoJSON topologies.
This commit is contained in:
1
build.py
1
build.py
@@ -312,6 +312,7 @@ def examples_star_json(name, match):
|
||||
'../externs/bingmaps.js',
|
||||
'../externs/bootstrap.js',
|
||||
'../externs/geojson.js',
|
||||
'../externs/topojson.js',
|
||||
'../externs/oli.js',
|
||||
'../externs/proj4js.js',
|
||||
'../externs/tilejson.js',
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
"//json.js",
|
||||
"../externs/bingmaps.js",
|
||||
"../externs/geojson.js",
|
||||
"../externs/topojson.js",
|
||||
"../externs/oli.js",
|
||||
"../externs/proj4js.js",
|
||||
"../externs/tilejson.js"
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"../build/src/external/externs/types.js",
|
||||
"../externs/bingmaps.js",
|
||||
"../externs/geojson.js",
|
||||
"../externs/topojson.js",
|
||||
"../externs/oli.js",
|
||||
"../externs/proj4js.js",
|
||||
"../externs/tilejson.js"
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
"//json.js",
|
||||
"../externs/bingmaps.js",
|
||||
"../externs/geojson.js",
|
||||
"../externs/topojson.js",
|
||||
"../externs/oli.js",
|
||||
"../externs/proj4js.js",
|
||||
"../externs/tilejson.js"
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"//json.js",
|
||||
"../externs/bingmaps.js",
|
||||
"../externs/geojson.js",
|
||||
"../externs/topojson.js",
|
||||
"../externs/oli.js",
|
||||
"../externs/proj4js.js",
|
||||
"../externs/tilejson.js"
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"../build/src/external/externs/types.js",
|
||||
"../externs/bingmaps.js",
|
||||
"../externs/geojson.js",
|
||||
"../externs/topojson.js",
|
||||
"../externs/oli.js",
|
||||
"../externs/proj4js.js",
|
||||
"../externs/tilejson.js"
|
||||
|
||||
1
examples/data/topojson/world-110m.json
Normal file
1
examples/data/topojson/world-110m.json
Normal file
File diff suppressed because one or more lines are too long
56
examples/topojson.html
Normal file
56
examples/topojson.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="chrome=1">
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
|
||||
<link rel="stylesheet" href="../resources/bootstrap/css/bootstrap.min.css" type="text/css">
|
||||
<link rel="stylesheet" href="../resources/layout.css" type="text/css">
|
||||
<link rel="stylesheet" href="../resources/bootstrap/css/bootstrap-responsive.min.css" type="text/css">
|
||||
<title>TopoJSON Example</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="./">OpenLayers 3 Examples</a>
|
||||
<ul class="nav pull-right">
|
||||
<li><iframe class="github-watch-button" src="http://ghbtns.com/github-btn.html?user=openlayers&repo=ol3&type=watch&count=true"
|
||||
allowtransparency="true" frameborder="0" scrolling="0" height="20" width="90"></iframe></li>
|
||||
<li><a href="https://twitter.com/share" class="twitter-share-button" data-count="none" data-hashtags="openlayers"> </a></li>
|
||||
<li><div class="g-plusone-wrapper"><div class="g-plusone" data-size="medium" data-annotation="none"></div></div></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
<div id="map" class="map"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span8">
|
||||
<h4 id="title">TopoJSON example</h4>
|
||||
<p id="shortdesc">Demonstrates rendering of features from a TopoJSON topology.</p>
|
||||
<div id="docs">
|
||||
<p>See the <a href="topojson.js" target="_blank">topojson.js source</a> to see how this is done.</p>
|
||||
</div>
|
||||
<div id="tags">vector, topojson, style</div>
|
||||
</div>
|
||||
<div id="info" class="span4"> </div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script src="loader.js?id=topojson" type="text/javascript"></script>
|
||||
<script src="../resources/social-links.js" type="text/javascript"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
47
examples/topojson.js
Normal file
47
examples/topojson.js
Normal file
@@ -0,0 +1,47 @@
|
||||
goog.require('ol.Map');
|
||||
goog.require('ol.RendererHint');
|
||||
goog.require('ol.View2D');
|
||||
goog.require('ol.layer.TileLayer');
|
||||
goog.require('ol.layer.Vector');
|
||||
goog.require('ol.parser.TopoJSON');
|
||||
goog.require('ol.source.TileJSON');
|
||||
goog.require('ol.source.Vector');
|
||||
goog.require('ol.style.Polygon');
|
||||
goog.require('ol.style.Rule');
|
||||
goog.require('ol.style.Style');
|
||||
|
||||
|
||||
var raster = new ol.layer.TileLayer({
|
||||
source: new ol.source.TileJSON({
|
||||
url: 'http://api.tiles.mapbox.com/v3/mapbox.world-dark.jsonp'
|
||||
})
|
||||
});
|
||||
|
||||
var vector = new ol.layer.Vector({
|
||||
source: new ol.source.Vector({
|
||||
url: 'data/topojson/world-110m.json',
|
||||
parser: new ol.parser.TopoJSON()
|
||||
}),
|
||||
style: new ol.style.Style({rules: [
|
||||
new ol.style.Rule({
|
||||
symbolizers: [
|
||||
new ol.style.Polygon({
|
||||
strokeColor: '#FFF',
|
||||
fillColor: '#BADA55',
|
||||
strokeWidth: 1.5,
|
||||
opacity: 0.5
|
||||
})
|
||||
]
|
||||
})
|
||||
]})
|
||||
});
|
||||
|
||||
var map = new ol.Map({
|
||||
layers: [raster, vector],
|
||||
renderer: ol.RendererHint.CANVAS,
|
||||
target: 'map',
|
||||
view: new ol.View2D({
|
||||
center: [0, 0],
|
||||
zoom: 1
|
||||
})
|
||||
});
|
||||
172
externs/topojson.js
Normal file
172
externs/topojson.js
Normal file
@@ -0,0 +1,172 @@
|
||||
|
||||
/**
|
||||
* @fileoverview Externs for TopoJSON.
|
||||
* @see https://github.com/mbostock/topojson/wiki/Specification
|
||||
* @externs
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
var TopoJSONTopology = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
TopoJSONTopology.prototype.type;
|
||||
|
||||
|
||||
/**
|
||||
* @type {TopoJSONTransform}
|
||||
*/
|
||||
TopoJSONTopology.prototype.transform;
|
||||
|
||||
|
||||
/**
|
||||
* @type {Object.<string, (TopoJSONGeometry|TopoJSONGeometryCollection)>}
|
||||
*/
|
||||
TopoJSONTopology.prototype.objects;
|
||||
|
||||
|
||||
/**
|
||||
* @type {!Array.<Array.<Array.<number>>>}
|
||||
*/
|
||||
TopoJSONTopology.prototype.arcs;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
var TopoJSONTransform = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @type {!Array.<number>}
|
||||
*/
|
||||
TopoJSONTransform.prototype.scale;
|
||||
|
||||
|
||||
/**
|
||||
* @type {!Array.<number>}
|
||||
*/
|
||||
TopoJSONTransform.prototype.translate;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
var TopoJSONGeometry = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
TopoJSONGeometry.prototype.type;
|
||||
|
||||
|
||||
/**
|
||||
* @type {string|number|undefined}
|
||||
*/
|
||||
TopoJSONGeometry.prototype.id;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
var TopoJSONGeometryCollection = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @type {Array.<TopoJSONGeometry>}
|
||||
*/
|
||||
TopoJSONGeometryCollection.prototype.geometries;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {TopoJSONGeometry}
|
||||
*/
|
||||
var TopoJSONPoint = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @type {!Array.<number>}
|
||||
*/
|
||||
TopoJSONPoint.prototype.coordinates;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {TopoJSONGeometry}
|
||||
*/
|
||||
var TopoJSONLineString = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @type {!Array.<number>}
|
||||
*/
|
||||
TopoJSONLineString.prototype.arcs;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {TopoJSONGeometry}
|
||||
*/
|
||||
var TopoJSONPolygon = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @type {!Array.<Array.<number>>}
|
||||
*/
|
||||
TopoJSONPolygon.prototype.arcs;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {TopoJSONGeometry}
|
||||
*/
|
||||
var TopoJSONMultiPoint = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @type {!Array.<Array.<number>>}
|
||||
*/
|
||||
TopoJSONMultiPoint.prototype.coordinates;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {TopoJSONGeometry}
|
||||
*/
|
||||
var TopoJSONMultiLineString = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @type {!Array.<Array.<number>>}
|
||||
*/
|
||||
TopoJSONMultiLineString.prototype.arcs;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends {TopoJSONGeometry}
|
||||
*/
|
||||
var TopoJSONMultiPolygon = function() {};
|
||||
|
||||
|
||||
/**
|
||||
* @type {!Array.<Array.<Array.<number>>>}
|
||||
*/
|
||||
TopoJSONMultiPolygon.prototype.arcs;
|
||||
4
src/ol/parser/topojson.exports
Normal file
4
src/ol/parser/topojson.exports
Normal file
@@ -0,0 +1,4 @@
|
||||
@exportSymbol ol.parser.TopoJSON
|
||||
|
||||
@exportProperty ol.parser.TopoJSON.prototype.read
|
||||
@exportProperty ol.parser.TopoJSON.read
|
||||
439
src/ol/parser/topojson.js
Normal file
439
src/ol/parser/topojson.js
Normal file
@@ -0,0 +1,439 @@
|
||||
goog.provide('ol.parser.TopoJSON');
|
||||
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.geom.GeometryType');
|
||||
goog.require('ol.geom.LineString');
|
||||
goog.require('ol.geom.MultiLineString');
|
||||
goog.require('ol.geom.MultiPoint');
|
||||
goog.require('ol.geom.MultiPolygon');
|
||||
goog.require('ol.geom.Point');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.geom.Vertex');
|
||||
goog.require('ol.geom.VertexArray');
|
||||
goog.require('ol.parser.Parser');
|
||||
goog.require('ol.parser.ReadFeaturesOptions');
|
||||
goog.require('ol.parser.StringFeatureParser');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @implements {ol.parser.StringFeatureParser}
|
||||
* @extends {ol.parser.Parser}
|
||||
*/
|
||||
ol.parser.TopoJSON = function() {
|
||||
|
||||
/**
|
||||
* Common feature for all shared vertex creation.
|
||||
* // TODO: make feature optional in shared vertex callback
|
||||
*
|
||||
* @type {ol.Feature}
|
||||
* @private
|
||||
*/
|
||||
this.feature_ = new ol.Feature();
|
||||
|
||||
};
|
||||
goog.inherits(ol.parser.TopoJSON, ol.parser.Parser);
|
||||
goog.addSingletonGetter(ol.parser.TopoJSON);
|
||||
|
||||
|
||||
/**
|
||||
* Concatenate arcs into a coordinate array.
|
||||
* @param {Array.<number>} indices Indices of arcs to concatenate. Negative
|
||||
* values indicate arcs need to be reversed.
|
||||
* @param {Array.<ol.geom.VertexArray>} arcs Arcs (already transformed).
|
||||
* @return {ol.geom.VertexArray} Coordinate array.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.concatenateArcs_ = function(indices, arcs) {
|
||||
var coordinates = [];
|
||||
var index, arc;
|
||||
for (var i = 0, ii = indices.length; i < ii; ++i) {
|
||||
index = indices[i];
|
||||
if (i > 0) {
|
||||
// splicing together arcs, discard last point
|
||||
coordinates.pop();
|
||||
}
|
||||
if (index >= 0) {
|
||||
// forward arc
|
||||
arc = arcs[index];
|
||||
} else {
|
||||
// reverse arc
|
||||
arc = arcs[~index].slice().reverse();
|
||||
}
|
||||
coordinates.push.apply(coordinates, arc);
|
||||
}
|
||||
return coordinates;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse a TopoJSON string.
|
||||
* @param {string} str TopoJSON string.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.read = function(str) {
|
||||
var topology = /** @type {TopoJSONTopology} */ (JSON.parse(str));
|
||||
return this.readFeaturesFromObject(topology);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create features from a TopoJSON topology string.
|
||||
*
|
||||
* @param {string} str TopoJSON topology string.
|
||||
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readFeaturesFromString =
|
||||
function(str, opt_options) {
|
||||
var topology = /** @type {TopoJSONTopology} */ (JSON.parse(str));
|
||||
if (topology.type !== 'Topology') {
|
||||
throw new Error('Not a "Topology" type object');
|
||||
}
|
||||
return this.readFeaturesFromTopology_(topology, opt_options);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create features from a TopoJSON topology object.
|
||||
*
|
||||
* @param {TopoJSONTopology} topology TopoJSON topology object.
|
||||
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readFeaturesFromObject =
|
||||
function(topology, opt_options) {
|
||||
if (topology.type !== 'Topology') {
|
||||
throw new Error('Not a "Topology" type object');
|
||||
}
|
||||
return this.readFeaturesFromTopology_(topology, opt_options);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a feature from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONGeometry} object TopoJSON geometry object.
|
||||
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
|
||||
* @return {ol.Feature} Feature.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readFeatureFromGeometry_ = function(object, arcs,
|
||||
scale, translate, opt_options) {
|
||||
var geometry;
|
||||
var type = object.type;
|
||||
if (type === 'Point') {
|
||||
geometry = this.readPoint_(/** @type {TopoJSONPoint} */ (object), scale,
|
||||
translate, opt_options);
|
||||
} else if (type === 'LineString') {
|
||||
geometry = this.readLineString_(/** @type {TopoJSONLineString} */ (object),
|
||||
arcs, opt_options);
|
||||
} else if (type === 'Polygon') {
|
||||
geometry = this.readPolygon_(/** @type {TopoJSONPolygon} */ (object), arcs,
|
||||
opt_options);
|
||||
} else if (type === 'MultiPoint') {
|
||||
geometry = this.readMultiPoint_(/** @type {TopoJSONMultiPoint} */ (object),
|
||||
scale, translate, opt_options);
|
||||
} else if (type === 'MultiLineString') {
|
||||
geometry = this.readMultiLineString_(
|
||||
/** @type {TopoJSONMultiLineString} */(object), arcs, opt_options);
|
||||
} else if (type === 'MultiPolygon') {
|
||||
geometry = this.readMultiPolygon_(
|
||||
/** @type {TopoJSONMultiPolygon} */ (object), arcs, opt_options);
|
||||
} else {
|
||||
throw new Error('Unsupported geometry type: ' + type);
|
||||
}
|
||||
var feature = new ol.Feature();
|
||||
feature.setGeometry(geometry);
|
||||
if (goog.isDef(object.id)) {
|
||||
feature.setFeatureId(String(object.id));
|
||||
}
|
||||
return feature;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create features from a TopoJSON GeometryCollection object.
|
||||
*
|
||||
* @param {TopoJSONGeometryCollection} collection TopoJSON GeometryCollection
|
||||
* object.
|
||||
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readFeaturesFromGeometryCollection_ = function(
|
||||
collection, arcs, scale, translate, opt_options) {
|
||||
var geometries = collection.geometries;
|
||||
var num = geometries.length;
|
||||
var features = new Array(num);
|
||||
for (var i = 0; i < num; ++i) {
|
||||
features[i] = this.readFeatureFromGeometry_(geometries[i], arcs, scale,
|
||||
translate, opt_options);
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @param {TopoJSONTopology} topology TopoJSON object.
|
||||
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
|
||||
* @return {Array.<ol.Feature>} Parsed features.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readFeaturesFromTopology_ = function(
|
||||
topology, opt_options) {
|
||||
var transform = topology.transform;
|
||||
var scale = transform.scale;
|
||||
var translate = transform.translate;
|
||||
var arcs = topology.arcs;
|
||||
this.transformArcs_(arcs, scale, translate);
|
||||
var objects = topology.objects;
|
||||
var features = [];
|
||||
for (var key in objects) {
|
||||
if (objects[key].type === 'GeometryCollection') {
|
||||
features.push.apply(features, this.readFeaturesFromGeometryCollection_(
|
||||
/** @type {TopoJSONGeometryCollection} */ (objects[key]),
|
||||
arcs, scale, translate, opt_options));
|
||||
} else {
|
||||
features.push(this.readFeatureFromGeometry_(
|
||||
/** @type {TopoJSONGeometry} */ (objects[key]),
|
||||
arcs, scale, translate, opt_options));
|
||||
}
|
||||
}
|
||||
return features;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a linestring from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONLineString} object TopoJSON object.
|
||||
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
|
||||
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
|
||||
* @return {ol.geom.LineString} Geometry.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readLineString_ = function(object, arcs,
|
||||
opt_options) {
|
||||
var coordinates = this.concatenateArcs_(object.arcs, arcs);
|
||||
// TODO: make feature optional in callback
|
||||
var callback = opt_options && opt_options.callback;
|
||||
var sharedVertices;
|
||||
if (callback) {
|
||||
sharedVertices = callback(this.feature_, ol.geom.GeometryType.LINESTRING);
|
||||
}
|
||||
return new ol.geom.LineString(coordinates, sharedVertices);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a multi-linestring from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONMultiLineString} object TopoJSON object.
|
||||
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
|
||||
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
|
||||
* @return {ol.geom.MultiLineString} Geometry.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readMultiLineString_ = function(object, arcs,
|
||||
opt_options) {
|
||||
var array = object.arcs; // I'm out of good names
|
||||
var num = array.length;
|
||||
var coordinates = new Array(num);
|
||||
for (var i = 0; i < num; ++i) {
|
||||
coordinates[i] = this.concatenateArcs_(array[i], arcs);
|
||||
}
|
||||
// TODO: make feature optional in callback
|
||||
var callback = opt_options && opt_options.callback;
|
||||
var sharedVertices;
|
||||
if (callback) {
|
||||
sharedVertices = callback(this.feature_,
|
||||
ol.geom.GeometryType.MULTILINESTRING);
|
||||
}
|
||||
return new ol.geom.MultiLineString(coordinates, sharedVertices);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a multi-point from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONMultiPoint} object TopoJSON object.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
|
||||
* @return {ol.geom.MultiPoint} Geometry.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readMultiPoint_ = function(object, scale,
|
||||
translate, opt_options) {
|
||||
var coordinates = object.coordinates;
|
||||
for (var i = 0, ii = coordinates.length; i < ii; ++i) {
|
||||
this.transformVertex_(coordinates[i], scale, translate);
|
||||
}
|
||||
// TODO: make feature optional in callback
|
||||
var callback = opt_options && opt_options.callback;
|
||||
var sharedVertices;
|
||||
if (callback) {
|
||||
sharedVertices = callback(this.feature_, ol.geom.GeometryType.MULTIPOINT);
|
||||
}
|
||||
return new ol.geom.MultiPoint(coordinates, sharedVertices);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a multi-polygon from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONMultiPolygon} object TopoJSON object.
|
||||
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
|
||||
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
|
||||
* @return {ol.geom.MultiPolygon} Geometry.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readMultiPolygon_ = function(object, arcs,
|
||||
opt_options) {
|
||||
var array = object.arcs;
|
||||
var numPolys = array.length;
|
||||
var coordinates = new Array(numPolys);
|
||||
var polyArray, numRings, ringCoords, j;
|
||||
for (var i = 0; i < numPolys; ++i) {
|
||||
// for each polygon
|
||||
polyArray = array[i];
|
||||
numRings = polyArray.length;
|
||||
ringCoords = new Array(numRings);
|
||||
for (j = 0; j < numRings; ++j) {
|
||||
// for each ring
|
||||
ringCoords[j] = this.concatenateArcs_(polyArray[j], arcs);
|
||||
}
|
||||
coordinates[i] = ringCoords;
|
||||
}
|
||||
// TODO: make feature optional in callback
|
||||
var callback = opt_options && opt_options.callback;
|
||||
var sharedVertices;
|
||||
if (callback) {
|
||||
sharedVertices = callback(this.feature_, ol.geom.GeometryType.MULTIPOLYGON);
|
||||
}
|
||||
return new ol.geom.MultiPolygon(coordinates, sharedVertices);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a point from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONPoint} object TopoJSON object.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
|
||||
* @return {ol.geom.Point} Geometry.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readPoint_ = function(object, scale, translate,
|
||||
opt_options) {
|
||||
var coordinates = object.coordinates;
|
||||
this.transformVertex_(coordinates, scale, translate);
|
||||
// TODO: make feature optional in callback
|
||||
var callback = opt_options && opt_options.callback;
|
||||
var sharedVertices;
|
||||
if (callback) {
|
||||
sharedVertices = callback(this.feature_, ol.geom.GeometryType.POINT);
|
||||
}
|
||||
return new ol.geom.Point(coordinates, sharedVertices);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a polygon from a TopoJSON geometry object.
|
||||
*
|
||||
* @param {TopoJSONPolygon} object TopoJSON object.
|
||||
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
|
||||
* @param {ol.parser.ReadFeaturesOptions=} opt_options Reader options.
|
||||
* @return {ol.geom.Polygon} Geometry.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.readPolygon_ = function(object, arcs,
|
||||
opt_options) {
|
||||
var array = object.arcs; // I'm out of good names
|
||||
var num = array.length;
|
||||
var coordinates = new Array(num);
|
||||
for (var i = 0; i < num; ++i) {
|
||||
coordinates[i] = this.concatenateArcs_(array[i], arcs);
|
||||
}
|
||||
// TODO: make feature optional in callback
|
||||
var callback = opt_options && opt_options.callback;
|
||||
var sharedVertices;
|
||||
if (callback) {
|
||||
sharedVertices = callback(this.feature_, ol.geom.GeometryType.POLYGON);
|
||||
}
|
||||
return new ol.geom.Polygon(coordinates, sharedVertices);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Apply a linear transform to array of arcs. The provided array of arcs is
|
||||
* modified in place.
|
||||
*
|
||||
* @param {Array.<ol.geom.VertexArray>} arcs Array of arcs.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.transformArcs_ = function(arcs, scale, translate) {
|
||||
for (var i = 0, ii = arcs.length; i < ii; ++i) {
|
||||
this.transformArc_(arcs[i], scale, translate);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Apply a linear transform to an arc. The provided arc is modified in place.
|
||||
*
|
||||
* @param {ol.geom.VertexArray} arc Arc.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.transformArc_ = function(arc, scale, translate) {
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
var vertex;
|
||||
for (var i = 0, ii = arc.length; i < ii; ++i) {
|
||||
vertex = arc[i];
|
||||
x += vertex[0];
|
||||
y += vertex[1];
|
||||
vertex[0] = x;
|
||||
vertex[1] = y;
|
||||
this.transformVertex_(vertex, scale, translate);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Apply a linear transform to a vertex. The provided vertex is modified in
|
||||
* place.
|
||||
*
|
||||
* @param {ol.geom.Vertex} vertex Vertex.
|
||||
* @param {Array.<number>} scale Scale for each dimension.
|
||||
* @param {Array.<number>} translate Translation for each dimension.
|
||||
* @private
|
||||
*/
|
||||
ol.parser.TopoJSON.prototype.transformVertex_ = function(vertex, scale,
|
||||
translate) {
|
||||
vertex[0] = vertex[0] * scale[0] + translate[0];
|
||||
vertex[1] = vertex[1] * scale[1] + translate[1];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Parse a TopoJSON string.
|
||||
* @param {string} str TopoJSON string.
|
||||
* @return {Array.<ol.Feature>} Array of features.
|
||||
*/
|
||||
ol.parser.TopoJSON.read = function(str) {
|
||||
return ol.parser.TopoJSON.getInstance().read(str);
|
||||
};
|
||||
118
test/spec/ol/parser/topojson.test.js
Normal file
118
test/spec/ol/parser/topojson.test.js
Normal file
@@ -0,0 +1,118 @@
|
||||
goog.provide('ol.test.parser.TopoJSON');
|
||||
|
||||
var aruba = {
|
||||
type: 'Topology',
|
||||
transform: {
|
||||
scale: [0.036003600360036005, 0.017361589674592462],
|
||||
translate: [-180, -89.99892578124998]
|
||||
},
|
||||
objects: {
|
||||
aruba: {
|
||||
type: 'Polygon',
|
||||
arcs: [[0]],
|
||||
id: 533
|
||||
}
|
||||
},
|
||||
arcs: [
|
||||
[[3058, 5901], [0, -2], [-2, 1], [-1, 3], [-2, 3], [0, 3], [1, 1], [1, -3],
|
||||
[2, -5], [1, -1]]
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
describe('ol.parser.TopoJSON', function() {
|
||||
|
||||
var parser;
|
||||
before(function() {
|
||||
parser = new ol.parser.TopoJSON();
|
||||
});
|
||||
|
||||
describe('constructor', function() {
|
||||
it('creates a new parser', function() {
|
||||
expect(parser).to.be.a(ol.parser.Parser);
|
||||
expect(parser).to.be.a(ol.parser.TopoJSON);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#readFeaturesFromTopology_()', function() {
|
||||
|
||||
it('creates an array of features from a topology', function() {
|
||||
var features = parser.readFeaturesFromTopology_(aruba);
|
||||
expect(features).to.have.length(1);
|
||||
|
||||
var feature = features[0];
|
||||
expect(feature).to.be.a(ol.Feature);
|
||||
|
||||
var geometry = feature.getGeometry();
|
||||
expect(geometry).to.be.a(ol.geom.Polygon);
|
||||
|
||||
expect(geometry.getBounds()).to.eql([
|
||||
-70.08100810081008,
|
||||
-69.9009900990099,
|
||||
12.417091709170947,
|
||||
12.608069195591469
|
||||
]);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#readFeaturesFromString()', function() {
|
||||
|
||||
it('parses world-110m.geojson with shared vertices', function(done) {
|
||||
afterLoadText('spec/ol/parser/topojson/world-110m.json', function(text) {
|
||||
|
||||
var pointVertices = new ol.geom.SharedVertices();
|
||||
var lineVertices = new ol.geom.SharedVertices();
|
||||
var polygonVertices = new ol.geom.SharedVertices();
|
||||
|
||||
var lookup = {
|
||||
'point': pointVertices,
|
||||
'linestring': lineVertices,
|
||||
'polygon': polygonVertices,
|
||||
'multipoint': pointVertices,
|
||||
'multilinstring': lineVertices,
|
||||
'multipolygon': polygonVertices
|
||||
};
|
||||
|
||||
var callback = function(feature, type) {
|
||||
return lookup[type];
|
||||
};
|
||||
|
||||
var result = parser.readFeaturesFromString(text, {callback: callback});
|
||||
expect(result.length).to.be(178);
|
||||
|
||||
expect(pointVertices.coordinates.length).to.be(0);
|
||||
expect(lineVertices.coordinates.length).to.be(0);
|
||||
expect(polygonVertices.coordinates.length).to.be(31400);
|
||||
|
||||
var first = result[0];
|
||||
expect(first).to.be.a(ol.Feature);
|
||||
var firstGeom = first.getGeometry();
|
||||
expect(firstGeom).to.be.a(ol.geom.MultiPolygon);
|
||||
expect(firstGeom.getBounds()).to.eql([
|
||||
-180, 180, -85.60903777459777, 83.64513000000002
|
||||
]);
|
||||
|
||||
var last = result[177];
|
||||
expect(last).to.be.a(ol.Feature);
|
||||
var lastGeom = last.getGeometry();
|
||||
expect(lastGeom).to.be.a(ol.geom.Polygon);
|
||||
expect(lastGeom.getBounds()).to.eql([
|
||||
25.26325263252633, 32.848528485284874,
|
||||
-22.271802279310577, -15.50833810039586
|
||||
]);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
goog.require('ol.Feature');
|
||||
goog.require('ol.geom.MultiPolygon');
|
||||
goog.require('ol.geom.Polygon');
|
||||
goog.require('ol.geom.SharedVertices');
|
||||
goog.require('ol.parser.Parser');
|
||||
goog.require('ol.parser.TopoJSON');
|
||||
1
test/spec/ol/parser/topojson/world-110m.json
Normal file
1
test/spec/ol/parser/topojson/world-110m.json
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user