topojson.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. /**
  2. @license
  3. topojson - https://github.com/mbostock/topojson
  4. Copyright (c) 2012, Michael Bostock
  5. All rights reserved.
  6. Redistribution and use in source and binary forms, with or without
  7. modification, are permitted provided that the following conditions are met:
  8. * Redistributions of source code must retain the above copyright notice, this
  9. list of conditions and the following disclaimer.
  10. * Redistributions in binary form must reproduce the above copyright notice,
  11. this list of conditions and the following disclaimer in the documentation
  12. and/or other materials provided with the distribution.
  13. * The name Michael Bostock may not be used to endorse or promote products
  14. derived from this software without specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
  19. INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  20. BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  22. OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  23. NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  24. EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. !function() {
  27. var topojson = {
  28. version: "1.6.18",
  29. mesh: function(topology) { return object(topology, meshArcs.apply(this, arguments)); },
  30. meshArcs: meshArcs,
  31. merge: function(topology) { return object(topology, mergeArcs.apply(this, arguments)); },
  32. mergeArcs: mergeArcs,
  33. feature: featureOrCollection,
  34. neighbors: neighbors,
  35. presimplify: presimplify
  36. };
  37. function stitchArcs(topology, arcs) {
  38. var stitchedArcs = {},
  39. fragmentByStart = {},
  40. fragmentByEnd = {},
  41. fragments = [],
  42. emptyIndex = -1;
  43. // Stitch empty arcs first, since they may be subsumed by other arcs.
  44. arcs.forEach(function(i, j) {
  45. var arc = topology.arcs[i < 0 ? ~i : i], t;
  46. if (arc.length < 3 && !arc[1][0] && !arc[1][1]) {
  47. t = arcs[++emptyIndex], arcs[emptyIndex] = i, arcs[j] = t;
  48. }
  49. });
  50. arcs.forEach(function(i) {
  51. var e = ends(i),
  52. start = e[0],
  53. end = e[1],
  54. f, g;
  55. if (f = fragmentByEnd[start]) {
  56. delete fragmentByEnd[f.end];
  57. f.push(i);
  58. f.end = end;
  59. if (g = fragmentByStart[end]) {
  60. delete fragmentByStart[g.start];
  61. var fg = g === f ? f : f.concat(g);
  62. fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg;
  63. } else {
  64. fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
  65. }
  66. } else if (f = fragmentByStart[end]) {
  67. delete fragmentByStart[f.start];
  68. f.unshift(i);
  69. f.start = start;
  70. if (g = fragmentByEnd[start]) {
  71. delete fragmentByEnd[g.end];
  72. var gf = g === f ? f : g.concat(f);
  73. fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf;
  74. } else {
  75. fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
  76. }
  77. } else {
  78. f = [i];
  79. fragmentByStart[f.start = start] = fragmentByEnd[f.end = end] = f;
  80. }
  81. });
  82. function ends(i) {
  83. var arc = topology.arcs[i < 0 ? ~i : i], p0 = arc[0], p1;
  84. if (topology.transform) p1 = [0, 0], arc.forEach(function(dp) { p1[0] += dp[0], p1[1] += dp[1]; });
  85. else p1 = arc[arc.length - 1];
  86. return i < 0 ? [p1, p0] : [p0, p1];
  87. }
  88. function flush(fragmentByEnd, fragmentByStart) {
  89. for (var k in fragmentByEnd) {
  90. var f = fragmentByEnd[k];
  91. delete fragmentByStart[f.start];
  92. delete f.start;
  93. delete f.end;
  94. f.forEach(function(i) { stitchedArcs[i < 0 ? ~i : i] = 1; });
  95. fragments.push(f);
  96. }
  97. }
  98. flush(fragmentByEnd, fragmentByStart);
  99. flush(fragmentByStart, fragmentByEnd);
  100. arcs.forEach(function(i) { if (!stitchedArcs[i < 0 ? ~i : i]) fragments.push([i]); });
  101. return fragments;
  102. }
  103. function meshArcs(topology, o, filter) {
  104. var arcs = [];
  105. if (arguments.length > 1) {
  106. var geomsByArc = [],
  107. geom;
  108. function arc(i) {
  109. var j = i < 0 ? ~i : i;
  110. (geomsByArc[j] || (geomsByArc[j] = [])).push({i: i, g: geom});
  111. }
  112. function line(arcs) {
  113. arcs.forEach(arc);
  114. }
  115. function polygon(arcs) {
  116. arcs.forEach(line);
  117. }
  118. function geometry(o) {
  119. if (o.type === "GeometryCollection") o.geometries.forEach(geometry);
  120. else if (o.type in geometryType) geom = o, geometryType[o.type](o.arcs);
  121. }
  122. var geometryType = {
  123. LineString: line,
  124. MultiLineString: polygon,
  125. Polygon: polygon,
  126. MultiPolygon: function(arcs) { arcs.forEach(polygon); }
  127. };
  128. geometry(o);
  129. geomsByArc.forEach(arguments.length < 3
  130. ? function(geoms) { arcs.push(geoms[0].i); }
  131. : function(geoms) { if (filter(geoms[0].g, geoms[geoms.length - 1].g)) arcs.push(geoms[0].i); });
  132. } else {
  133. for (var i = 0, n = topology.arcs.length; i < n; ++i) arcs.push(i);
  134. }
  135. return {type: "MultiLineString", arcs: stitchArcs(topology, arcs)};
  136. }
  137. function mergeArcs(topology, objects) {
  138. var polygonsByArc = {},
  139. polygons = [],
  140. components = [];
  141. objects.forEach(function(o) {
  142. if (o.type === "Polygon") register(o.arcs);
  143. else if (o.type === "MultiPolygon") o.arcs.forEach(register);
  144. });
  145. function register(polygon) {
  146. polygon.forEach(function(ring) {
  147. ring.forEach(function(arc) {
  148. (polygonsByArc[arc = arc < 0 ? ~arc : arc] || (polygonsByArc[arc] = [])).push(polygon);
  149. });
  150. });
  151. polygons.push(polygon);
  152. }
  153. function exterior(ring) {
  154. return cartesianRingArea(object(topology, {type: "Polygon", arcs: [ring]}).coordinates[0]) > 0; // TODO allow spherical?
  155. }
  156. polygons.forEach(function(polygon) {
  157. if (!polygon._) {
  158. var component = [],
  159. neighbors = [polygon];
  160. polygon._ = 1;
  161. components.push(component);
  162. while (polygon = neighbors.pop()) {
  163. component.push(polygon);
  164. polygon.forEach(function(ring) {
  165. ring.forEach(function(arc) {
  166. polygonsByArc[arc < 0 ? ~arc : arc].forEach(function(polygon) {
  167. if (!polygon._) {
  168. polygon._ = 1;
  169. neighbors.push(polygon);
  170. }
  171. });
  172. });
  173. });
  174. }
  175. }
  176. });
  177. polygons.forEach(function(polygon) {
  178. delete polygon._;
  179. });
  180. return {
  181. type: "MultiPolygon",
  182. arcs: components.map(function(polygons) {
  183. var arcs = [];
  184. // Extract the exterior (unique) arcs.
  185. polygons.forEach(function(polygon) {
  186. polygon.forEach(function(ring) {
  187. ring.forEach(function(arc) {
  188. if (polygonsByArc[arc < 0 ? ~arc : arc].length < 2) {
  189. arcs.push(arc);
  190. }
  191. });
  192. });
  193. });
  194. // Stitch the arcs into one or more rings.
  195. arcs = stitchArcs(topology, arcs);
  196. // If more than one ring is returned,
  197. // at most one of these rings can be the exterior;
  198. // this exterior ring has the same winding order
  199. // as any exterior ring in the original polygons.
  200. if ((n = arcs.length) > 1) {
  201. var sgn = exterior(polygons[0][0]);
  202. for (var i = 0, t; i < n; ++i) {
  203. if (sgn === exterior(arcs[i])) {
  204. t = arcs[0], arcs[0] = arcs[i], arcs[i] = t;
  205. break;
  206. }
  207. }
  208. }
  209. return arcs;
  210. })
  211. };
  212. }
  213. function featureOrCollection(topology, o) {
  214. return o.type === "GeometryCollection" ? {
  215. type: "FeatureCollection",
  216. features: o.geometries.map(function(o) { return feature(topology, o); })
  217. } : feature(topology, o);
  218. }
  219. function feature(topology, o) {
  220. var f = {
  221. type: "Feature",
  222. id: o.id,
  223. properties: o.properties || {},
  224. geometry: object(topology, o)
  225. };
  226. if (o.id == null) delete f.id;
  227. return f;
  228. }
  229. function object(topology, o) {
  230. var absolute = transformAbsolute(topology.transform),
  231. arcs = topology.arcs;
  232. function arc(i, points) {
  233. if (points.length) points.pop();
  234. for (var a = arcs[i < 0 ? ~i : i], k = 0, n = a.length, p; k < n; ++k) {
  235. points.push(p = a[k].slice());
  236. absolute(p, k);
  237. }
  238. if (i < 0) reverse(points, n);
  239. }
  240. function point(p) {
  241. p = p.slice();
  242. absolute(p, 0);
  243. return p;
  244. }
  245. function line(arcs) {
  246. var points = [];
  247. for (var i = 0, n = arcs.length; i < n; ++i) arc(arcs[i], points);
  248. if (points.length < 2) points.push(points[0].slice());
  249. return points;
  250. }
  251. function ring(arcs) {
  252. var points = line(arcs);
  253. while (points.length < 4) points.push(points[0].slice());
  254. return points;
  255. }
  256. function polygon(arcs) {
  257. return arcs.map(ring);
  258. }
  259. function geometry(o) {
  260. var t = o.type;
  261. return t === "GeometryCollection" ? {type: t, geometries: o.geometries.map(geometry)}
  262. : t in geometryType ? {type: t, coordinates: geometryType[t](o)}
  263. : null;
  264. }
  265. var geometryType = {
  266. Point: function(o) { return point(o.coordinates); },
  267. MultiPoint: function(o) { return o.coordinates.map(point); },
  268. LineString: function(o) { return line(o.arcs); },
  269. MultiLineString: function(o) { return o.arcs.map(line); },
  270. Polygon: function(o) { return polygon(o.arcs); },
  271. MultiPolygon: function(o) { return o.arcs.map(polygon); }
  272. };
  273. return geometry(o);
  274. }
  275. function reverse(array, n) {
  276. var t, j = array.length, i = j - n; while (i < --j) t = array[i], array[i++] = array[j], array[j] = t;
  277. }
  278. function bisect(a, x) {
  279. var lo = 0, hi = a.length;
  280. while (lo < hi) {
  281. var mid = lo + hi >>> 1;
  282. if (a[mid] < x) lo = mid + 1;
  283. else hi = mid;
  284. }
  285. return lo;
  286. }
  287. function neighbors(objects) {
  288. var indexesByArc = {}, // arc index -> array of object indexes
  289. neighbors = objects.map(function() { return []; });
  290. function line(arcs, i) {
  291. arcs.forEach(function(a) {
  292. if (a < 0) a = ~a;
  293. var o = indexesByArc[a];
  294. if (o) o.push(i);
  295. else indexesByArc[a] = [i];
  296. });
  297. }
  298. function polygon(arcs, i) {
  299. arcs.forEach(function(arc) { line(arc, i); });
  300. }
  301. function geometry(o, i) {
  302. if (o.type === "GeometryCollection") o.geometries.forEach(function(o) { geometry(o, i); });
  303. else if (o.type in geometryType) geometryType[o.type](o.arcs, i);
  304. }
  305. var geometryType = {
  306. LineString: line,
  307. MultiLineString: polygon,
  308. Polygon: polygon,
  309. MultiPolygon: function(arcs, i) { arcs.forEach(function(arc) { polygon(arc, i); }); }
  310. };
  311. objects.forEach(geometry);
  312. for (var i in indexesByArc) {
  313. for (var indexes = indexesByArc[i], m = indexes.length, j = 0; j < m; ++j) {
  314. for (var k = j + 1; k < m; ++k) {
  315. var ij = indexes[j], ik = indexes[k], n;
  316. if ((n = neighbors[ij])[i = bisect(n, ik)] !== ik) n.splice(i, 0, ik);
  317. if ((n = neighbors[ik])[i = bisect(n, ij)] !== ij) n.splice(i, 0, ij);
  318. }
  319. }
  320. }
  321. return neighbors;
  322. }
  323. function presimplify(topology, triangleArea) {
  324. var absolute = transformAbsolute(topology.transform),
  325. relative = transformRelative(topology.transform),
  326. heap = minAreaHeap();
  327. if (!triangleArea) triangleArea = cartesianTriangleArea;
  328. topology.arcs.forEach(function(arc) {
  329. var triangles = [],
  330. maxArea = 0,
  331. triangle;
  332. // To store each point’s effective area, we create a new array rather than
  333. // extending the passed-in point to workaround a Chrome/V8 bug (getting
  334. // stuck in smi mode). For midpoints, the initial effective area of
  335. // Infinity will be computed in the next step.
  336. for (var i = 0, n = arc.length, p; i < n; ++i) {
  337. p = arc[i];
  338. absolute(arc[i] = [p[0], p[1], Infinity], i);
  339. }
  340. for (var i = 1, n = arc.length - 1; i < n; ++i) {
  341. triangle = arc.slice(i - 1, i + 2);
  342. triangle[1][2] = triangleArea(triangle);
  343. triangles.push(triangle);
  344. heap.push(triangle);
  345. }
  346. for (var i = 0, n = triangles.length; i < n; ++i) {
  347. triangle = triangles[i];
  348. triangle.previous = triangles[i - 1];
  349. triangle.next = triangles[i + 1];
  350. }
  351. while (triangle = heap.pop()) {
  352. var previous = triangle.previous,
  353. next = triangle.next;
  354. // If the area of the current point is less than that of the previous point
  355. // to be eliminated, use the latter's area instead. This ensures that the
  356. // current point cannot be eliminated without eliminating previously-
  357. // eliminated points.
  358. if (triangle[1][2] < maxArea) triangle[1][2] = maxArea;
  359. else maxArea = triangle[1][2];
  360. if (previous) {
  361. previous.next = next;
  362. previous[2] = triangle[2];
  363. update(previous);
  364. }
  365. if (next) {
  366. next.previous = previous;
  367. next[0] = triangle[0];
  368. update(next);
  369. }
  370. }
  371. arc.forEach(relative);
  372. });
  373. function update(triangle) {
  374. heap.remove(triangle);
  375. triangle[1][2] = triangleArea(triangle);
  376. heap.push(triangle);
  377. }
  378. return topology;
  379. };
  380. function cartesianRingArea(ring) {
  381. var i = -1,
  382. n = ring.length,
  383. a,
  384. b = ring[n - 1],
  385. area = 0;
  386. while (++i < n) {
  387. a = b;
  388. b = ring[i];
  389. area += a[0] * b[1] - a[1] * b[0];
  390. }
  391. return area * .5;
  392. }
  393. function cartesianTriangleArea(triangle) {
  394. var a = triangle[0], b = triangle[1], c = triangle[2];
  395. return Math.abs((a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]));
  396. }
  397. function compareArea(a, b) {
  398. return a[1][2] - b[1][2];
  399. }
  400. function minAreaHeap() {
  401. var heap = {},
  402. array = [],
  403. size = 0;
  404. heap.push = function(object) {
  405. up(array[object._ = size] = object, size++);
  406. return size;
  407. };
  408. heap.pop = function() {
  409. if (size <= 0) return;
  410. var removed = array[0], object;
  411. if (--size > 0) object = array[size], down(array[object._ = 0] = object, 0);
  412. return removed;
  413. };
  414. heap.remove = function(removed) {
  415. var i = removed._, object;
  416. if (array[i] !== removed) return; // invalid request
  417. if (i !== --size) object = array[size], (compareArea(object, removed) < 0 ? up : down)(array[object._ = i] = object, i);
  418. return i;
  419. };
  420. function up(object, i) {
  421. while (i > 0) {
  422. var j = ((i + 1) >> 1) - 1,
  423. parent = array[j];
  424. if (compareArea(object, parent) >= 0) break;
  425. array[parent._ = i] = parent;
  426. array[object._ = i = j] = object;
  427. }
  428. }
  429. function down(object, i) {
  430. while (true) {
  431. var r = (i + 1) << 1,
  432. l = r - 1,
  433. j = i,
  434. child = array[j];
  435. if (l < size && compareArea(array[l], child) < 0) child = array[j = l];
  436. if (r < size && compareArea(array[r], child) < 0) child = array[j = r];
  437. if (j === i) break;
  438. array[child._ = i] = child;
  439. array[object._ = i = j] = object;
  440. }
  441. }
  442. return heap;
  443. }
  444. function transformAbsolute(transform) {
  445. if (!transform) return noop;
  446. var x0,
  447. y0,
  448. kx = transform.scale[0],
  449. ky = transform.scale[1],
  450. dx = transform.translate[0],
  451. dy = transform.translate[1];
  452. return function(point, i) {
  453. if (!i) x0 = y0 = 0;
  454. point[0] = (x0 += point[0]) * kx + dx;
  455. point[1] = (y0 += point[1]) * ky + dy;
  456. };
  457. }
  458. function transformRelative(transform) {
  459. if (!transform) return noop;
  460. var x0,
  461. y0,
  462. kx = transform.scale[0],
  463. ky = transform.scale[1],
  464. dx = transform.translate[0],
  465. dy = transform.translate[1];
  466. return function(point, i) {
  467. if (!i) x0 = y0 = 0;
  468. var x1 = (point[0] - dx) / kx | 0,
  469. y1 = (point[1] - dy) / ky | 0;
  470. point[0] = x1 - x0;
  471. point[1] = y1 - y0;
  472. x0 = x1;
  473. y0 = y1;
  474. };
  475. }
  476. function noop() {}
  477. if (typeof define === "function" && define.amd) define(topojson);
  478. else if (typeof module === "object" && module.exports) module.exports = topojson;
  479. else this.topojson = topojson;
  480. }();