Mercurial > hg > dml-open-vis
comparison src/DML/VendorAssetsBundle/Resources/assets/vega/2.2.6/topojson.js @ 0:493bcb69166c
added public content
author | Daniel Wolff |
---|---|
date | Tue, 09 Feb 2016 20:54:02 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:493bcb69166c |
---|---|
1 !function() { | |
2 var topojson = { | |
3 version: "1.6.19", | |
4 mesh: function(topology) { return object(topology, meshArcs.apply(this, arguments)); }, | |
5 meshArcs: meshArcs, | |
6 merge: function(topology) { return object(topology, mergeArcs.apply(this, arguments)); }, | |
7 mergeArcs: mergeArcs, | |
8 feature: featureOrCollection, | |
9 neighbors: neighbors, | |
10 presimplify: presimplify | |
11 }; | |
12 | |
13 function stitchArcs(topology, arcs) { | |
14 var stitchedArcs = {}, | |
15 fragmentByStart = {}, | |
16 fragmentByEnd = {}, | |
17 fragments = [], | |
18 emptyIndex = -1; | |
19 | |
20 // Stitch empty arcs first, since they may be subsumed by other arcs. | |
21 arcs.forEach(function(i, j) { | |
22 var arc = topology.arcs[i < 0 ? ~i : i], t; | |
23 if (arc.length < 3 && !arc[1][0] && !arc[1][1]) { | |
24 t = arcs[++emptyIndex], arcs[emptyIndex] = i, arcs[j] = t; | |
25 } | |
26 }); | |
27 | |
28 arcs.forEach(function(i) { | |
29 var e = ends(i), | |
30 start = e[0], | |
31 end = e[1], | |
32 f, g; | |
33 | |
34 if (f = fragmentByEnd[start]) { | |
35 delete fragmentByEnd[f.end]; | |
36 f.push(i); | |
37 f.end = end; | |
38 if (g = fragmentByStart[end]) { | |
39 delete fragmentByStart[g.start]; | |
40 var fg = g === f ? f : f.concat(g); | |
41 fragmentByStart[fg.start = f.start] = fragmentByEnd[fg.end = g.end] = fg; | |
42 } else { | |
43 fragmentByStart[f.start] = fragmentByEnd[f.end] = f; | |
44 } | |
45 } else if (f = fragmentByStart[end]) { | |
46 delete fragmentByStart[f.start]; | |
47 f.unshift(i); | |
48 f.start = start; | |
49 if (g = fragmentByEnd[start]) { | |
50 delete fragmentByEnd[g.end]; | |
51 var gf = g === f ? f : g.concat(f); | |
52 fragmentByStart[gf.start = g.start] = fragmentByEnd[gf.end = f.end] = gf; | |
53 } else { | |
54 fragmentByStart[f.start] = fragmentByEnd[f.end] = f; | |
55 } | |
56 } else { | |
57 f = [i]; | |
58 fragmentByStart[f.start = start] = fragmentByEnd[f.end = end] = f; | |
59 } | |
60 }); | |
61 | |
62 function ends(i) { | |
63 var arc = topology.arcs[i < 0 ? ~i : i], p0 = arc[0], p1; | |
64 if (topology.transform) p1 = [0, 0], arc.forEach(function(dp) { p1[0] += dp[0], p1[1] += dp[1]; }); | |
65 else p1 = arc[arc.length - 1]; | |
66 return i < 0 ? [p1, p0] : [p0, p1]; | |
67 } | |
68 | |
69 function flush(fragmentByEnd, fragmentByStart) { | |
70 for (var k in fragmentByEnd) { | |
71 var f = fragmentByEnd[k]; | |
72 delete fragmentByStart[f.start]; | |
73 delete f.start; | |
74 delete f.end; | |
75 f.forEach(function(i) { stitchedArcs[i < 0 ? ~i : i] = 1; }); | |
76 fragments.push(f); | |
77 } | |
78 } | |
79 | |
80 flush(fragmentByEnd, fragmentByStart); | |
81 flush(fragmentByStart, fragmentByEnd); | |
82 arcs.forEach(function(i) { if (!stitchedArcs[i < 0 ? ~i : i]) fragments.push([i]); }); | |
83 | |
84 return fragments; | |
85 } | |
86 | |
87 function meshArcs(topology, o, filter) { | |
88 var arcs = []; | |
89 | |
90 if (arguments.length > 1) { | |
91 var geomsByArc = [], | |
92 geom; | |
93 | |
94 function arc(i) { | |
95 var j = i < 0 ? ~i : i; | |
96 (geomsByArc[j] || (geomsByArc[j] = [])).push({i: i, g: geom}); | |
97 } | |
98 | |
99 function line(arcs) { | |
100 arcs.forEach(arc); | |
101 } | |
102 | |
103 function polygon(arcs) { | |
104 arcs.forEach(line); | |
105 } | |
106 | |
107 function geometry(o) { | |
108 if (o.type === "GeometryCollection") o.geometries.forEach(geometry); | |
109 else if (o.type in geometryType) geom = o, geometryType[o.type](o.arcs); | |
110 } | |
111 | |
112 var geometryType = { | |
113 LineString: line, | |
114 MultiLineString: polygon, | |
115 Polygon: polygon, | |
116 MultiPolygon: function(arcs) { arcs.forEach(polygon); } | |
117 }; | |
118 | |
119 geometry(o); | |
120 | |
121 geomsByArc.forEach(arguments.length < 3 | |
122 ? function(geoms) { arcs.push(geoms[0].i); } | |
123 : function(geoms) { if (filter(geoms[0].g, geoms[geoms.length - 1].g)) arcs.push(geoms[0].i); }); | |
124 } else { | |
125 for (var i = 0, n = topology.arcs.length; i < n; ++i) arcs.push(i); | |
126 } | |
127 | |
128 return {type: "MultiLineString", arcs: stitchArcs(topology, arcs)}; | |
129 } | |
130 | |
131 function mergeArcs(topology, objects) { | |
132 var polygonsByArc = {}, | |
133 polygons = [], | |
134 components = []; | |
135 | |
136 objects.forEach(function(o) { | |
137 if (o.type === "Polygon") register(o.arcs); | |
138 else if (o.type === "MultiPolygon") o.arcs.forEach(register); | |
139 }); | |
140 | |
141 function register(polygon) { | |
142 polygon.forEach(function(ring) { | |
143 ring.forEach(function(arc) { | |
144 (polygonsByArc[arc = arc < 0 ? ~arc : arc] || (polygonsByArc[arc] = [])).push(polygon); | |
145 }); | |
146 }); | |
147 polygons.push(polygon); | |
148 } | |
149 | |
150 function exterior(ring) { | |
151 return cartesianRingArea(object(topology, {type: "Polygon", arcs: [ring]}).coordinates[0]) > 0; // TODO allow spherical? | |
152 } | |
153 | |
154 polygons.forEach(function(polygon) { | |
155 if (!polygon._) { | |
156 var component = [], | |
157 neighbors = [polygon]; | |
158 polygon._ = 1; | |
159 components.push(component); | |
160 while (polygon = neighbors.pop()) { | |
161 component.push(polygon); | |
162 polygon.forEach(function(ring) { | |
163 ring.forEach(function(arc) { | |
164 polygonsByArc[arc < 0 ? ~arc : arc].forEach(function(polygon) { | |
165 if (!polygon._) { | |
166 polygon._ = 1; | |
167 neighbors.push(polygon); | |
168 } | |
169 }); | |
170 }); | |
171 }); | |
172 } | |
173 } | |
174 }); | |
175 | |
176 polygons.forEach(function(polygon) { | |
177 delete polygon._; | |
178 }); | |
179 | |
180 return { | |
181 type: "MultiPolygon", | |
182 arcs: components.map(function(polygons) { | |
183 var arcs = []; | |
184 | |
185 // Extract the exterior (unique) arcs. | |
186 polygons.forEach(function(polygon) { | |
187 polygon.forEach(function(ring) { | |
188 ring.forEach(function(arc) { | |
189 if (polygonsByArc[arc < 0 ? ~arc : arc].length < 2) { | |
190 arcs.push(arc); | |
191 } | |
192 }); | |
193 }); | |
194 }); | |
195 | |
196 // Stitch the arcs into one or more rings. | |
197 arcs = stitchArcs(topology, arcs); | |
198 | |
199 // If more than one ring is returned, | |
200 // at most one of these rings can be the exterior; | |
201 // this exterior ring has the same winding order | |
202 // as any exterior ring in the original polygons. | |
203 if ((n = arcs.length) > 1) { | |
204 var sgn = exterior(polygons[0][0]); | |
205 for (var i = 0, t; i < n; ++i) { | |
206 if (sgn === exterior(arcs[i])) { | |
207 t = arcs[0], arcs[0] = arcs[i], arcs[i] = t; | |
208 break; | |
209 } | |
210 } | |
211 } | |
212 | |
213 return arcs; | |
214 }) | |
215 }; | |
216 } | |
217 | |
218 function featureOrCollection(topology, o) { | |
219 return o.type === "GeometryCollection" ? { | |
220 type: "FeatureCollection", | |
221 features: o.geometries.map(function(o) { return feature(topology, o); }) | |
222 } : feature(topology, o); | |
223 } | |
224 | |
225 function feature(topology, o) { | |
226 var f = { | |
227 type: "Feature", | |
228 id: o.id, | |
229 properties: o.properties || {}, | |
230 geometry: object(topology, o) | |
231 }; | |
232 if (o.id == null) delete f.id; | |
233 return f; | |
234 } | |
235 | |
236 function object(topology, o) { | |
237 var absolute = transformAbsolute(topology.transform), | |
238 arcs = topology.arcs; | |
239 | |
240 function arc(i, points) { | |
241 if (points.length) points.pop(); | |
242 for (var a = arcs[i < 0 ? ~i : i], k = 0, n = a.length, p; k < n; ++k) { | |
243 points.push(p = a[k].slice()); | |
244 absolute(p, k); | |
245 } | |
246 if (i < 0) reverse(points, n); | |
247 } | |
248 | |
249 function point(p) { | |
250 p = p.slice(); | |
251 absolute(p, 0); | |
252 return p; | |
253 } | |
254 | |
255 function line(arcs) { | |
256 var points = []; | |
257 for (var i = 0, n = arcs.length; i < n; ++i) arc(arcs[i], points); | |
258 if (points.length < 2) points.push(points[0].slice()); | |
259 return points; | |
260 } | |
261 | |
262 function ring(arcs) { | |
263 var points = line(arcs); | |
264 while (points.length < 4) points.push(points[0].slice()); | |
265 return points; | |
266 } | |
267 | |
268 function polygon(arcs) { | |
269 return arcs.map(ring); | |
270 } | |
271 | |
272 function geometry(o) { | |
273 var t = o.type; | |
274 return t === "GeometryCollection" ? {type: t, geometries: o.geometries.map(geometry)} | |
275 : t in geometryType ? {type: t, coordinates: geometryType[t](o)} | |
276 : null; | |
277 } | |
278 | |
279 var geometryType = { | |
280 Point: function(o) { return point(o.coordinates); }, | |
281 MultiPoint: function(o) { return o.coordinates.map(point); }, | |
282 LineString: function(o) { return line(o.arcs); }, | |
283 MultiLineString: function(o) { return o.arcs.map(line); }, | |
284 Polygon: function(o) { return polygon(o.arcs); }, | |
285 MultiPolygon: function(o) { return o.arcs.map(polygon); } | |
286 }; | |
287 | |
288 return geometry(o); | |
289 } | |
290 | |
291 function reverse(array, n) { | |
292 var t, j = array.length, i = j - n; while (i < --j) t = array[i], array[i++] = array[j], array[j] = t; | |
293 } | |
294 | |
295 function bisect(a, x) { | |
296 var lo = 0, hi = a.length; | |
297 while (lo < hi) { | |
298 var mid = lo + hi >>> 1; | |
299 if (a[mid] < x) lo = mid + 1; | |
300 else hi = mid; | |
301 } | |
302 return lo; | |
303 } | |
304 | |
305 function neighbors(objects) { | |
306 var indexesByArc = {}, // arc index -> array of object indexes | |
307 neighbors = objects.map(function() { return []; }); | |
308 | |
309 function line(arcs, i) { | |
310 arcs.forEach(function(a) { | |
311 if (a < 0) a = ~a; | |
312 var o = indexesByArc[a]; | |
313 if (o) o.push(i); | |
314 else indexesByArc[a] = [i]; | |
315 }); | |
316 } | |
317 | |
318 function polygon(arcs, i) { | |
319 arcs.forEach(function(arc) { line(arc, i); }); | |
320 } | |
321 | |
322 function geometry(o, i) { | |
323 if (o.type === "GeometryCollection") o.geometries.forEach(function(o) { geometry(o, i); }); | |
324 else if (o.type in geometryType) geometryType[o.type](o.arcs, i); | |
325 } | |
326 | |
327 var geometryType = { | |
328 LineString: line, | |
329 MultiLineString: polygon, | |
330 Polygon: polygon, | |
331 MultiPolygon: function(arcs, i) { arcs.forEach(function(arc) { polygon(arc, i); }); } | |
332 }; | |
333 | |
334 objects.forEach(geometry); | |
335 | |
336 for (var i in indexesByArc) { | |
337 for (var indexes = indexesByArc[i], m = indexes.length, j = 0; j < m; ++j) { | |
338 for (var k = j + 1; k < m; ++k) { | |
339 var ij = indexes[j], ik = indexes[k], n; | |
340 if ((n = neighbors[ij])[i = bisect(n, ik)] !== ik) n.splice(i, 0, ik); | |
341 if ((n = neighbors[ik])[i = bisect(n, ij)] !== ij) n.splice(i, 0, ij); | |
342 } | |
343 } | |
344 } | |
345 | |
346 return neighbors; | |
347 } | |
348 | |
349 function presimplify(topology, triangleArea) { | |
350 var absolute = transformAbsolute(topology.transform), | |
351 relative = transformRelative(topology.transform), | |
352 heap = minAreaHeap(); | |
353 | |
354 if (!triangleArea) triangleArea = cartesianTriangleArea; | |
355 | |
356 topology.arcs.forEach(function(arc) { | |
357 var triangles = [], | |
358 maxArea = 0, | |
359 triangle; | |
360 | |
361 // To store each point’s effective area, we create a new array rather than | |
362 // extending the passed-in point to workaround a Chrome/V8 bug (getting | |
363 // stuck in smi mode). For midpoints, the initial effective area of | |
364 // Infinity will be computed in the next step. | |
365 for (var i = 0, n = arc.length, p; i < n; ++i) { | |
366 p = arc[i]; | |
367 absolute(arc[i] = [p[0], p[1], Infinity], i); | |
368 } | |
369 | |
370 for (var i = 1, n = arc.length - 1; i < n; ++i) { | |
371 triangle = arc.slice(i - 1, i + 2); | |
372 triangle[1][2] = triangleArea(triangle); | |
373 triangles.push(triangle); | |
374 heap.push(triangle); | |
375 } | |
376 | |
377 for (var i = 0, n = triangles.length; i < n; ++i) { | |
378 triangle = triangles[i]; | |
379 triangle.previous = triangles[i - 1]; | |
380 triangle.next = triangles[i + 1]; | |
381 } | |
382 | |
383 while (triangle = heap.pop()) { | |
384 var previous = triangle.previous, | |
385 next = triangle.next; | |
386 | |
387 // If the area of the current point is less than that of the previous point | |
388 // to be eliminated, use the latter's area instead. This ensures that the | |
389 // current point cannot be eliminated without eliminating previously- | |
390 // eliminated points. | |
391 if (triangle[1][2] < maxArea) triangle[1][2] = maxArea; | |
392 else maxArea = triangle[1][2]; | |
393 | |
394 if (previous) { | |
395 previous.next = next; | |
396 previous[2] = triangle[2]; | |
397 update(previous); | |
398 } | |
399 | |
400 if (next) { | |
401 next.previous = previous; | |
402 next[0] = triangle[0]; | |
403 update(next); | |
404 } | |
405 } | |
406 | |
407 arc.forEach(relative); | |
408 }); | |
409 | |
410 function update(triangle) { | |
411 heap.remove(triangle); | |
412 triangle[1][2] = triangleArea(triangle); | |
413 heap.push(triangle); | |
414 } | |
415 | |
416 return topology; | |
417 }; | |
418 | |
419 function cartesianRingArea(ring) { | |
420 var i = -1, | |
421 n = ring.length, | |
422 a, | |
423 b = ring[n - 1], | |
424 area = 0; | |
425 | |
426 while (++i < n) { | |
427 a = b; | |
428 b = ring[i]; | |
429 area += a[0] * b[1] - a[1] * b[0]; | |
430 } | |
431 | |
432 return area * .5; | |
433 } | |
434 | |
435 function cartesianTriangleArea(triangle) { | |
436 var a = triangle[0], b = triangle[1], c = triangle[2]; | |
437 return Math.abs((a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1])); | |
438 } | |
439 | |
440 function compareArea(a, b) { | |
441 return a[1][2] - b[1][2]; | |
442 } | |
443 | |
444 function minAreaHeap() { | |
445 var heap = {}, | |
446 array = [], | |
447 size = 0; | |
448 | |
449 heap.push = function(object) { | |
450 up(array[object._ = size] = object, size++); | |
451 return size; | |
452 }; | |
453 | |
454 heap.pop = function() { | |
455 if (size <= 0) return; | |
456 var removed = array[0], object; | |
457 if (--size > 0) object = array[size], down(array[object._ = 0] = object, 0); | |
458 return removed; | |
459 }; | |
460 | |
461 heap.remove = function(removed) { | |
462 var i = removed._, object; | |
463 if (array[i] !== removed) return; // invalid request | |
464 if (i !== --size) object = array[size], (compareArea(object, removed) < 0 ? up : down)(array[object._ = i] = object, i); | |
465 return i; | |
466 }; | |
467 | |
468 function up(object, i) { | |
469 while (i > 0) { | |
470 var j = ((i + 1) >> 1) - 1, | |
471 parent = array[j]; | |
472 if (compareArea(object, parent) >= 0) break; | |
473 array[parent._ = i] = parent; | |
474 array[object._ = i = j] = object; | |
475 } | |
476 } | |
477 | |
478 function down(object, i) { | |
479 while (true) { | |
480 var r = (i + 1) << 1, | |
481 l = r - 1, | |
482 j = i, | |
483 child = array[j]; | |
484 if (l < size && compareArea(array[l], child) < 0) child = array[j = l]; | |
485 if (r < size && compareArea(array[r], child) < 0) child = array[j = r]; | |
486 if (j === i) break; | |
487 array[child._ = i] = child; | |
488 array[object._ = i = j] = object; | |
489 } | |
490 } | |
491 | |
492 return heap; | |
493 } | |
494 | |
495 function transformAbsolute(transform) { | |
496 if (!transform) return noop; | |
497 var x0, | |
498 y0, | |
499 kx = transform.scale[0], | |
500 ky = transform.scale[1], | |
501 dx = transform.translate[0], | |
502 dy = transform.translate[1]; | |
503 return function(point, i) { | |
504 if (!i) x0 = y0 = 0; | |
505 point[0] = (x0 += point[0]) * kx + dx; | |
506 point[1] = (y0 += point[1]) * ky + dy; | |
507 }; | |
508 } | |
509 | |
510 function transformRelative(transform) { | |
511 if (!transform) return noop; | |
512 var x0, | |
513 y0, | |
514 kx = transform.scale[0], | |
515 ky = transform.scale[1], | |
516 dx = transform.translate[0], | |
517 dy = transform.translate[1]; | |
518 return function(point, i) { | |
519 if (!i) x0 = y0 = 0; | |
520 var x1 = (point[0] - dx) / kx | 0, | |
521 y1 = (point[1] - dy) / ky | 0; | |
522 point[0] = x1 - x0; | |
523 point[1] = y1 - y0; | |
524 x0 = x1; | |
525 y0 = y1; | |
526 }; | |
527 } | |
528 | |
529 function noop() {} | |
530 | |
531 if (typeof define === "function" && define.amd) define(topojson); | |
532 else if (typeof module === "object" && module.exports) module.exports = topojson; | |
533 else this.topojson = topojson; | |
534 }(); |