Merge pull request #844 from tschaub/topojson
Parser for reading TopoJSON topologies.
This commit is contained in:
@@ -312,6 +312,7 @@ def examples_star_json(name, match):
|
|||||||
'../externs/bingmaps.js',
|
'../externs/bingmaps.js',
|
||||||
'../externs/bootstrap.js',
|
'../externs/bootstrap.js',
|
||||||
'../externs/geojson.js',
|
'../externs/geojson.js',
|
||||||
|
'../externs/topojson.js',
|
||||||
'../externs/oli.js',
|
'../externs/oli.js',
|
||||||
'../externs/proj4js.js',
|
'../externs/proj4js.js',
|
||||||
'../externs/tilejson.js',
|
'../externs/tilejson.js',
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
"//json.js",
|
"//json.js",
|
||||||
"../externs/bingmaps.js",
|
"../externs/bingmaps.js",
|
||||||
"../externs/geojson.js",
|
"../externs/geojson.js",
|
||||||
|
"../externs/topojson.js",
|
||||||
"../externs/oli.js",
|
"../externs/oli.js",
|
||||||
"../externs/proj4js.js",
|
"../externs/proj4js.js",
|
||||||
"../externs/tilejson.js"
|
"../externs/tilejson.js"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"../build/src/external/externs/types.js",
|
"../build/src/external/externs/types.js",
|
||||||
"../externs/bingmaps.js",
|
"../externs/bingmaps.js",
|
||||||
"../externs/geojson.js",
|
"../externs/geojson.js",
|
||||||
|
"../externs/topojson.js",
|
||||||
"../externs/oli.js",
|
"../externs/oli.js",
|
||||||
"../externs/proj4js.js",
|
"../externs/proj4js.js",
|
||||||
"../externs/tilejson.js"
|
"../externs/tilejson.js"
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"//json.js",
|
"//json.js",
|
||||||
"../externs/bingmaps.js",
|
"../externs/bingmaps.js",
|
||||||
"../externs/geojson.js",
|
"../externs/geojson.js",
|
||||||
|
"../externs/topojson.js",
|
||||||
"../externs/oli.js",
|
"../externs/oli.js",
|
||||||
"../externs/proj4js.js",
|
"../externs/proj4js.js",
|
||||||
"../externs/tilejson.js"
|
"../externs/tilejson.js"
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
"//json.js",
|
"//json.js",
|
||||||
"../externs/bingmaps.js",
|
"../externs/bingmaps.js",
|
||||||
"../externs/geojson.js",
|
"../externs/geojson.js",
|
||||||
|
"../externs/topojson.js",
|
||||||
"../externs/oli.js",
|
"../externs/oli.js",
|
||||||
"../externs/proj4js.js",
|
"../externs/proj4js.js",
|
||||||
"../externs/tilejson.js"
|
"../externs/tilejson.js"
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
"../build/src/external/externs/types.js",
|
"../build/src/external/externs/types.js",
|
||||||
"../externs/bingmaps.js",
|
"../externs/bingmaps.js",
|
||||||
"../externs/geojson.js",
|
"../externs/geojson.js",
|
||||||
|
"../externs/topojson.js",
|
||||||
"../externs/oli.js",
|
"../externs/oli.js",
|
||||||
"../externs/proj4js.js",
|
"../externs/proj4js.js",
|
||||||
"../externs/tilejson.js"
|
"../externs/tilejson.js"
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -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>
|
||||||
@@ -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
|
||||||
|
})
|
||||||
|
});
|
||||||
@@ -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;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
@exportSymbol ol.parser.TopoJSON
|
||||||
|
|
||||||
|
@exportProperty ol.parser.TopoJSON.prototype.read
|
||||||
|
@exportProperty ol.parser.TopoJSON.read
|
||||||
@@ -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);
|
||||||
|
};
|
||||||
@@ -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');
|
||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user