topojson-client.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. // https://github.com/topojson/topojson-client v3.1.0 Copyright 2019 Mike Bostock
  2. (function (global, factory) {
  3. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  4. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  5. (global = global || self, factory(global.topojson = global.topojson || {}));
  6. }(this, function (exports) { 'use strict';
  7. function identity(x) {
  8. return x;
  9. }
  10. function transform(transform) {
  11. if (transform == null) return identity;
  12. var x0,
  13. y0,
  14. kx = transform.scale[0],
  15. ky = transform.scale[1],
  16. dx = transform.translate[0],
  17. dy = transform.translate[1];
  18. return function(input, i) {
  19. if (!i) x0 = y0 = 0;
  20. var j = 2, n = input.length, output = new Array(n);
  21. output[0] = (x0 += input[0]) * kx + dx;
  22. output[1] = (y0 += input[1]) * ky + dy;
  23. while (j < n) output[j] = input[j], ++j;
  24. return output;
  25. };
  26. }
  27. function bbox(topology) {
  28. var t = transform(topology.transform), key,
  29. x0 = Infinity, y0 = x0, x1 = -x0, y1 = -x0;
  30. function bboxPoint(p) {
  31. p = t(p);
  32. if (p[0] < x0) x0 = p[0];
  33. if (p[0] > x1) x1 = p[0];
  34. if (p[1] < y0) y0 = p[1];
  35. if (p[1] > y1) y1 = p[1];
  36. }
  37. function bboxGeometry(o) {
  38. switch (o.type) {
  39. case "GeometryCollection": o.geometries.forEach(bboxGeometry); break;
  40. case "Point": bboxPoint(o.coordinates); break;
  41. case "MultiPoint": o.coordinates.forEach(bboxPoint); break;
  42. }
  43. }
  44. topology.arcs.forEach(function(arc) {
  45. var i = -1, n = arc.length, p;
  46. while (++i < n) {
  47. p = t(arc[i], i);
  48. if (p[0] < x0) x0 = p[0];
  49. if (p[0] > x1) x1 = p[0];
  50. if (p[1] < y0) y0 = p[1];
  51. if (p[1] > y1) y1 = p[1];
  52. }
  53. });
  54. for (key in topology.objects) {
  55. bboxGeometry(topology.objects[key]);
  56. }
  57. return [x0, y0, x1, y1];
  58. }
  59. function reverse(array, n) {
  60. var t, j = array.length, i = j - n;
  61. while (i < --j) t = array[i], array[i++] = array[j], array[j] = t;
  62. }
  63. function feature(topology, o) {
  64. if (typeof o === "string") o = topology.objects[o];
  65. return o.type === "GeometryCollection"
  66. ? {type: "FeatureCollection", features: o.geometries.map(function(o) { return feature$1(topology, o); })}
  67. : feature$1(topology, o);
  68. }
  69. function feature$1(topology, o) {
  70. var id = o.id,
  71. bbox = o.bbox,
  72. properties = o.properties == null ? {} : o.properties,
  73. geometry = object(topology, o);
  74. return id == null && bbox == null ? {type: "Feature", properties: properties, geometry: geometry}
  75. : bbox == null ? {type: "Feature", id: id, properties: properties, geometry: geometry}
  76. : {type: "Feature", id: id, bbox: bbox, properties: properties, geometry: geometry};
  77. }
  78. function object(topology, o) {
  79. var transformPoint = transform(topology.transform),
  80. arcs = topology.arcs;
  81. function arc(i, points) {
  82. if (points.length) points.pop();
  83. for (var a = arcs[i < 0 ? ~i : i], k = 0, n = a.length; k < n; ++k) {
  84. points.push(transformPoint(a[k], k));
  85. }
  86. if (i < 0) reverse(points, n);
  87. }
  88. function point(p) {
  89. return transformPoint(p);
  90. }
  91. function line(arcs) {
  92. var points = [];
  93. for (var i = 0, n = arcs.length; i < n; ++i) arc(arcs[i], points);
  94. if (points.length < 2) points.push(points[0]); // This should never happen per the specification.
  95. return points;
  96. }
  97. function ring(arcs) {
  98. var points = line(arcs);
  99. while (points.length < 4) points.push(points[0]); // This may happen if an arc has only two points.
  100. return points;
  101. }
  102. function polygon(arcs) {
  103. return arcs.map(ring);
  104. }
  105. function geometry(o) {
  106. var type = o.type, coordinates;
  107. switch (type) {
  108. case "GeometryCollection": return {type: type, geometries: o.geometries.map(geometry)};
  109. case "Point": coordinates = point(o.coordinates); break;
  110. case "MultiPoint": coordinates = o.coordinates.map(point); break;
  111. case "LineString": coordinates = line(o.arcs); break;
  112. case "MultiLineString": coordinates = o.arcs.map(line); break;
  113. case "Polygon": coordinates = polygon(o.arcs); break;
  114. case "MultiPolygon": coordinates = o.arcs.map(polygon); break;
  115. default: return null;
  116. }
  117. return {type: type, coordinates: coordinates};
  118. }
  119. return geometry(o);
  120. }
  121. function stitch(topology, arcs) {
  122. var stitchedArcs = {},
  123. fragmentByStart = {},
  124. fragmentByEnd = {},
  125. fragments = [],
  126. emptyIndex = -1;
  127. // Stitch empty arcs first, since they may be subsumed by other arcs.
  128. arcs.forEach(function(i, j) {
  129. var arc = topology.arcs[i < 0 ? ~i : i], t;
  130. if (arc.length < 3 && !arc[1][0] && !arc[1][1]) {
  131. t = arcs[++emptyIndex], arcs[emptyIndex] = i, arcs[j] = t;
  132. }
  133. });
  134. arcs.forEach(function(i) {
  135. var e = ends(i),
  136. start = e[0],
  137. end = e[1],
  138. f, g;
  139. if (f = fragmentByEnd[start]) {
  140. delete fragmentByEnd[f.end];
  141. f.push(i);
  142. f.end = end;
  143. if (g = fragmentByStart[end]) {
  144. delete fragmentByStart[g.start];
  145. var fg = g === f ? f : f.concat(g);
  146. fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg;
  147. } else {
  148. fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
  149. }
  150. } else if (f = fragmentByStart[end]) {
  151. delete fragmentByStart[f.start];
  152. f.unshift(i);
  153. f.start = start;
  154. if (g = fragmentByEnd[start]) {
  155. delete fragmentByEnd[g.end];
  156. var gf = g === f ? f : g.concat(f);
  157. fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf;
  158. } else {
  159. fragmentByStart[f.start] = fragmentByEnd[f.end] = f;
  160. }
  161. } else {
  162. f = [i];
  163. fragmentByStart[f.start = start] = fragmentByEnd[f.end = end] = f;
  164. }
  165. });
  166. function ends(i) {
  167. var arc = topology.arcs[i < 0 ? ~i : i], p0 = arc[0], p1;
  168. if (topology.transform) p1 = [0, 0], arc.forEach(function(dp) { p1[0] += dp[0], p1[1] += dp[1]; });
  169. else p1 = arc[arc.length - 1];
  170. return i < 0 ? [p1, p0] : [p0, p1];
  171. }
  172. function flush(fragmentByEnd, fragmentByStart) {
  173. for (var k in fragmentByEnd) {
  174. var f = fragmentByEnd[k];
  175. delete fragmentByStart[f.start];
  176. delete f.start;
  177. delete f.end;
  178. f.forEach(function(i) { stitchedArcs[i < 0 ? ~i : i] = 1; });
  179. fragments.push(f);
  180. }
  181. }
  182. flush(fragmentByEnd, fragmentByStart);
  183. flush(fragmentByStart, fragmentByEnd);
  184. arcs.forEach(function(i) { if (!stitchedArcs[i < 0 ? ~i : i]) fragments.push([i]); });
  185. return fragments;
  186. }
  187. function mesh(topology) {
  188. return object(topology, meshArcs.apply(this, arguments));
  189. }
  190. function meshArcs(topology, object, filter) {
  191. var arcs, i, n;
  192. if (arguments.length > 1) arcs = extractArcs(topology, object, filter);
  193. else for (i = 0, arcs = new Array(n = topology.arcs.length); i < n; ++i) arcs[i] = i;
  194. return {type: "MultiLineString", arcs: stitch(topology, arcs)};
  195. }
  196. function extractArcs(topology, object, filter) {
  197. var arcs = [],
  198. geomsByArc = [],
  199. geom;
  200. function extract0(i) {
  201. var j = i < 0 ? ~i : i;
  202. (geomsByArc[j] || (geomsByArc[j] = [])).push({i: i, g: geom});
  203. }
  204. function extract1(arcs) {
  205. arcs.forEach(extract0);
  206. }
  207. function extract2(arcs) {
  208. arcs.forEach(extract1);
  209. }
  210. function extract3(arcs) {
  211. arcs.forEach(extract2);
  212. }
  213. function geometry(o) {
  214. switch (geom = o, o.type) {
  215. case "GeometryCollection": o.geometries.forEach(geometry); break;
  216. case "LineString": extract1(o.arcs); break;
  217. case "MultiLineString": case "Polygon": extract2(o.arcs); break;
  218. case "MultiPolygon": extract3(o.arcs); break;
  219. }
  220. }
  221. geometry(object);
  222. geomsByArc.forEach(filter == null
  223. ? function(geoms) { arcs.push(geoms[0].i); }
  224. : function(geoms) { if (filter(geoms[0].g, geoms[geoms.length - 1].g)) arcs.push(geoms[0].i); });
  225. return arcs;
  226. }
  227. function planarRingArea(ring) {
  228. var i = -1, n = ring.length, a, b = ring[n - 1], area = 0;
  229. while (++i < n) a = b, b = ring[i], area += a[0] * b[1] - a[1] * b[0];
  230. return Math.abs(area); // Note: doubled area!
  231. }
  232. function merge(topology) {
  233. return object(topology, mergeArcs.apply(this, arguments));
  234. }
  235. function mergeArcs(topology, objects) {
  236. var polygonsByArc = {},
  237. polygons = [],
  238. groups = [];
  239. objects.forEach(geometry);
  240. function geometry(o) {
  241. switch (o.type) {
  242. case "GeometryCollection": o.geometries.forEach(geometry); break;
  243. case "Polygon": extract(o.arcs); break;
  244. case "MultiPolygon": o.arcs.forEach(extract); break;
  245. }
  246. }
  247. function extract(polygon) {
  248. polygon.forEach(function(ring) {
  249. ring.forEach(function(arc) {
  250. (polygonsByArc[arc = arc < 0 ? ~arc : arc] || (polygonsByArc[arc] = [])).push(polygon);
  251. });
  252. });
  253. polygons.push(polygon);
  254. }
  255. function area(ring) {
  256. return planarRingArea(object(topology, {type: "Polygon", arcs: [ring]}).coordinates[0]);
  257. }
  258. polygons.forEach(function(polygon) {
  259. if (!polygon._) {
  260. var group = [],
  261. neighbors = [polygon];
  262. polygon._ = 1;
  263. groups.push(group);
  264. while (polygon = neighbors.pop()) {
  265. group.push(polygon);
  266. polygon.forEach(function(ring) {
  267. ring.forEach(function(arc) {
  268. polygonsByArc[arc < 0 ? ~arc : arc].forEach(function(polygon) {
  269. if (!polygon._) {
  270. polygon._ = 1;
  271. neighbors.push(polygon);
  272. }
  273. });
  274. });
  275. });
  276. }
  277. }
  278. });
  279. polygons.forEach(function(polygon) {
  280. delete polygon._;
  281. });
  282. return {
  283. type: "MultiPolygon",
  284. arcs: groups.map(function(polygons) {
  285. var arcs = [], n;
  286. // Extract the exterior (unique) arcs.
  287. polygons.forEach(function(polygon) {
  288. polygon.forEach(function(ring) {
  289. ring.forEach(function(arc) {
  290. if (polygonsByArc[arc < 0 ? ~arc : arc].length < 2) {
  291. arcs.push(arc);
  292. }
  293. });
  294. });
  295. });
  296. // Stitch the arcs into one or more rings.
  297. arcs = stitch(topology, arcs);
  298. // If more than one ring is returned,
  299. // at most one of these rings can be the exterior;
  300. // choose the one with the greatest absolute area.
  301. if ((n = arcs.length) > 1) {
  302. for (var i = 1, k = area(arcs[0]), ki, t; i < n; ++i) {
  303. if ((ki = area(arcs[i])) > k) {
  304. t = arcs[0], arcs[0] = arcs[i], arcs[i] = t, k = ki;
  305. }
  306. }
  307. }
  308. return arcs;
  309. }).filter(function(arcs) {
  310. return arcs.length > 0;
  311. })
  312. };
  313. }
  314. function bisect(a, x) {
  315. var lo = 0, hi = a.length;
  316. while (lo < hi) {
  317. var mid = lo + hi >>> 1;
  318. if (a[mid] < x) lo = mid + 1;
  319. else hi = mid;
  320. }
  321. return lo;
  322. }
  323. function neighbors(objects) {
  324. var indexesByArc = {}, // arc index -> array of object indexes
  325. neighbors = objects.map(function() { return []; });
  326. function line(arcs, i) {
  327. arcs.forEach(function(a) {
  328. if (a < 0) a = ~a;
  329. var o = indexesByArc[a];
  330. if (o) o.push(i);
  331. else indexesByArc[a] = [i];
  332. });
  333. }
  334. function polygon(arcs, i) {
  335. arcs.forEach(function(arc) { line(arc, i); });
  336. }
  337. function geometry(o, i) {
  338. if (o.type === "GeometryCollection") o.geometries.forEach(function(o) { geometry(o, i); });
  339. else if (o.type in geometryType) geometryType[o.type](o.arcs, i);
  340. }
  341. var geometryType = {
  342. LineString: line,
  343. MultiLineString: polygon,
  344. Polygon: polygon,
  345. MultiPolygon: function(arcs, i) { arcs.forEach(function(arc) { polygon(arc, i); }); }
  346. };
  347. objects.forEach(geometry);
  348. for (var i in indexesByArc) {
  349. for (var indexes = indexesByArc[i], m = indexes.length, j = 0; j < m; ++j) {
  350. for (var k = j + 1; k < m; ++k) {
  351. var ij = indexes[j], ik = indexes[k], n;
  352. if ((n = neighbors[ij])[i = bisect(n, ik)] !== ik) n.splice(i, 0, ik);
  353. if ((n = neighbors[ik])[i = bisect(n, ij)] !== ij) n.splice(i, 0, ij);
  354. }
  355. }
  356. }
  357. return neighbors;
  358. }
  359. function untransform(transform) {
  360. if (transform == null) return identity;
  361. var x0,
  362. y0,
  363. kx = transform.scale[0],
  364. ky = transform.scale[1],
  365. dx = transform.translate[0],
  366. dy = transform.translate[1];
  367. return function(input, i) {
  368. if (!i) x0 = y0 = 0;
  369. var j = 2,
  370. n = input.length,
  371. output = new Array(n),
  372. x1 = Math.round((input[0] - dx) / kx),
  373. y1 = Math.round((input[1] - dy) / ky);
  374. output[0] = x1 - x0, x0 = x1;
  375. output[1] = y1 - y0, y0 = y1;
  376. while (j < n) output[j] = input[j], ++j;
  377. return output;
  378. };
  379. }
  380. function quantize(topology, transform) {
  381. if (topology.transform) throw new Error("already quantized");
  382. if (!transform || !transform.scale) {
  383. if (!((n = Math.floor(transform)) >= 2)) throw new Error("n must be ≥2");
  384. box = topology.bbox || bbox(topology);
  385. var x0 = box[0], y0 = box[1], x1 = box[2], y1 = box[3], n;
  386. transform = {scale: [x1 - x0 ? (x1 - x0) / (n - 1) : 1, y1 - y0 ? (y1 - y0) / (n - 1) : 1], translate: [x0, y0]};
  387. } else {
  388. box = topology.bbox;
  389. }
  390. var t = untransform(transform), box, key, inputs = topology.objects, outputs = {};
  391. function quantizePoint(point) {
  392. return t(point);
  393. }
  394. function quantizeGeometry(input) {
  395. var output;
  396. switch (input.type) {
  397. case "GeometryCollection": output = {type: "GeometryCollection", geometries: input.geometries.map(quantizeGeometry)}; break;
  398. case "Point": output = {type: "Point", coordinates: quantizePoint(input.coordinates)}; break;
  399. case "MultiPoint": output = {type: "MultiPoint", coordinates: input.coordinates.map(quantizePoint)}; break;
  400. default: return input;
  401. }
  402. if (input.id != null) output.id = input.id;
  403. if (input.bbox != null) output.bbox = input.bbox;
  404. if (input.properties != null) output.properties = input.properties;
  405. return output;
  406. }
  407. function quantizeArc(input) {
  408. var i = 0, j = 1, n = input.length, p, output = new Array(n); // pessimistic
  409. output[0] = t(input[0], 0);
  410. while (++i < n) if ((p = t(input[i], i))[0] || p[1]) output[j++] = p; // non-coincident points
  411. if (j === 1) output[j++] = [0, 0]; // an arc must have at least two points
  412. output.length = j;
  413. return output;
  414. }
  415. for (key in inputs) outputs[key] = quantizeGeometry(inputs[key]);
  416. return {
  417. type: "Topology",
  418. bbox: box,
  419. transform: transform,
  420. objects: outputs,
  421. arcs: topology.arcs.map(quantizeArc)
  422. };
  423. }
  424. exports.bbox = bbox;
  425. exports.feature = feature;
  426. exports.merge = merge;
  427. exports.mergeArcs = mergeArcs;
  428. exports.mesh = mesh;
  429. exports.meshArcs = meshArcs;
  430. exports.neighbors = neighbors;
  431. exports.quantize = quantize;
  432. exports.transform = transform;
  433. exports.untransform = untransform;
  434. Object.defineProperty(exports, '__esModule', { value: true });
  435. }));