Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

fixing conflict

  • Loading branch information...
commit 75d335d282ac6ea7cfb012b42cc5c68b76d60504 2 parents 4ea3efc + 06e1a98
Zachary Johnson authored
17 .project
... ... @@ -0,0 +1,17 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<projectDescription>
  3 + <name>hexbin-js</name>
  4 + <comment></comment>
  5 + <projects>
  6 + </projects>
  7 + <buildSpec>
  8 + <buildCommand>
  9 + <name>com.aptana.ide.core.unifiedBuilder</name>
  10 + <arguments>
  11 + </arguments>
  12 + </buildCommand>
  13 + </buildSpec>
  14 + <natures>
  15 + <nature>com.aptana.projects.webnature</nature>
  16 + </natures>
  17 +</projectDescription>
0  README
No changes.
1  data/json/139309.json
1 addition, 0 deletions not shown
2,005 data/json/crime-data-2000.json
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
2,005 data/json/crime-data-downtown
2,005 additions, 0 deletions not shown
2,005 data/json/crime-data-downtown.json
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
4,005 data/json/crime-data.json
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
1  data/json/starbucks_on_earth.json
1 addition, 0 deletions not shown
1  index.html
... ... @@ -1 +1,2 @@
  1 +
1 2 cacaw
692 lib/d3.geo.js
... ... @@ -0,0 +1,692 @@
  1 +(function(){d3.geo = {};
  2 +// TODO clip input coordinates on opposite hemisphere
  3 +d3.geo.azimuthal = function() {
  4 + var mode = "orthographic", // or stereographic
  5 + origin,
  6 + scale = 200,
  7 + translate = [480, 250],
  8 + x0,
  9 + y0,
  10 + cy0,
  11 + sy0;
  12 +
  13 + function azimuthal(coordinates) {
  14 + var x1 = coordinates[0] * d3_radians - x0,
  15 + y1 = coordinates[1] * d3_radians,
  16 + cx1 = Math.cos(x1),
  17 + sx1 = Math.sin(x1),
  18 + cy1 = Math.cos(y1),
  19 + sy1 = Math.sin(y1),
  20 + k = mode === "stereographic" ? 1 / (1 + sy0 * sy1 + cy0 * cy1 * cx1) : 1,
  21 + x = k * cy1 * sx1,
  22 + y = k * (sy0 * cy1 * cx1 - cy0 * sy1);
  23 + return [
  24 + scale * x + translate[0],
  25 + scale * y + translate[1]
  26 + ];
  27 + }
  28 +
  29 + azimuthal.invert = function(coordinates) {
  30 + var x = (coordinates[0] - translate[0]) / scale,
  31 + y = (coordinates[1] - translate[1]) / scale,
  32 + p = Math.sqrt(x * x + y * y),
  33 + c = mode === "stereographic" ? 2 * Math.atan(p) : Math.asin(p),
  34 + sc = Math.sin(c),
  35 + cc = Math.cos(c);
  36 + return [
  37 + (x0 + Math.atan2(x * sc, p * cy0 * cc + y * sy0 * sc)) / d3_radians,
  38 + Math.asin(cc * sy0 - (y * sc * cy0) / p) / d3_radians
  39 + ];
  40 + };
  41 +
  42 + azimuthal.mode = function(x) {
  43 + if (!arguments.length) return mode;
  44 + mode = x + "";
  45 + return azimuthal;
  46 + };
  47 +
  48 + azimuthal.origin = function(x) {
  49 + if (!arguments.length) return origin;
  50 + origin = x;
  51 + x0 = origin[0] * d3_radians;
  52 + y0 = origin[1] * d3_radians;
  53 + cy0 = Math.cos(y0);
  54 + sy0 = Math.sin(y0);
  55 + return azimuthal;
  56 + };
  57 +
  58 + azimuthal.scale = function(x) {
  59 + if (!arguments.length) return scale;
  60 + scale = +x;
  61 + return azimuthal;
  62 + };
  63 +
  64 + azimuthal.translate = function(x) {
  65 + if (!arguments.length) return translate;
  66 + translate = [+x[0], +x[1]];
  67 + return azimuthal;
  68 + };
  69 +
  70 + return azimuthal.origin([0, 0]);
  71 +};
  72 +// Derived from Tom Carden's Albers implementation for Protovis.
  73 +// http://gist.github.com/476238
  74 +// http://mathworld.wolfram.com/AlbersEqual-AreaConicProjection.html
  75 +
  76 +d3.geo.albers = function() {
  77 + var origin = [-98, 38],
  78 + parallels = [29.5, 45.5],
  79 + scale = 1000,
  80 + translate = [480, 250],
  81 + lng0, // d3_radians * origin[0]
  82 + n,
  83 + C,
  84 + p0;
  85 +
  86 + function albers(coordinates) {
  87 + var t = n * (d3_radians * coordinates[0] - lng0),
  88 + p = Math.sqrt(C - 2 * n * Math.sin(d3_radians * coordinates[1])) / n;
  89 + return [
  90 + scale * p * Math.sin(t) + translate[0],
  91 + scale * (p * Math.cos(t) - p0) + translate[1]
  92 + ];
  93 + }
  94 +
  95 + albers.invert = function(coordinates) {
  96 + var x = (coordinates[0] - translate[0]) / scale,
  97 + y = (coordinates[1] - translate[1]) / scale,
  98 + p0y = p0 + y,
  99 + t = Math.atan2(x, p0y),
  100 + p = Math.sqrt(x * x + p0y * p0y);
  101 + return [
  102 + (lng0 + t / n) / d3_radians,
  103 + Math.asin((C - p * p * n * n) / (2 * n)) / d3_radians
  104 + ];
  105 + };
  106 +
  107 + function reload() {
  108 + var phi1 = d3_radians * parallels[0],
  109 + phi2 = d3_radians * parallels[1],
  110 + lat0 = d3_radians * origin[1],
  111 + s = Math.sin(phi1),
  112 + c = Math.cos(phi1);
  113 + lng0 = d3_radians * origin[0];
  114 + n = .5 * (s + Math.sin(phi2));
  115 + C = c * c + 2 * n * s;
  116 + p0 = Math.sqrt(C - 2 * n * Math.sin(lat0)) / n;
  117 + return albers;
  118 + }
  119 +
  120 + albers.origin = function(x) {
  121 + if (!arguments.length) return origin;
  122 + origin = [+x[0], +x[1]];
  123 + return reload();
  124 + };
  125 +
  126 + albers.parallels = function(x) {
  127 + if (!arguments.length) return parallels;
  128 + parallels = [+x[0], +x[1]];
  129 + return reload();
  130 + };
  131 +
  132 + albers.scale = function(x) {
  133 + if (!arguments.length) return scale;
  134 + scale = +x;
  135 + return albers;
  136 + };
  137 +
  138 + albers.translate = function(x) {
  139 + if (!arguments.length) return translate;
  140 + translate = [+x[0], +x[1]];
  141 + return albers;
  142 + };
  143 +
  144 + return reload();
  145 +};
  146 +
  147 +// A composite projection for the United States, 960x500. The set of standard
  148 +// parallels for each region comes from USGS, which is published here:
  149 +// http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers
  150 +// TODO allow the composite projection to be rescaled?
  151 +d3.geo.albersUsa = function() {
  152 + var lower48 = d3.geo.albers();
  153 +
  154 + var alaska = d3.geo.albers()
  155 + .origin([-160, 60])
  156 + .parallels([55, 65]);
  157 +
  158 + var hawaii = d3.geo.albers()
  159 + .origin([-160, 20])
  160 + .parallels([8, 18]);
  161 +
  162 + var puertoRico = d3.geo.albers()
  163 + .origin([-60, 10])
  164 + .parallels([8, 18]);
  165 +
  166 + function albersUsa(coordinates) {
  167 + var lon = coordinates[0],
  168 + lat = coordinates[1];
  169 + return (lat > 50 ? alaska
  170 + : lon < -140 ? hawaii
  171 + : lat < 21 ? puertoRico
  172 + : lower48)(coordinates);
  173 + }
  174 +
  175 + albersUsa.scale = function(x) {
  176 + if (!arguments.length) return lower48.scale();
  177 + lower48.scale(x);
  178 + alaska.scale(x * .6);
  179 + hawaii.scale(x);
  180 + puertoRico.scale(x * 1.5);
  181 + return albersUsa.translate(lower48.translate());
  182 + };
  183 +
  184 + albersUsa.translate = function(x) {
  185 + if (!arguments.length) return lower48.translate();
  186 + var dz = lower48.scale() / 1000,
  187 + dx = x[0],
  188 + dy = x[1];
  189 + lower48.translate(x);
  190 + alaska.translate([dx - 400 * dz, dy + 170 * dz]);
  191 + hawaii.translate([dx - 190 * dz, dy + 200 * dz]);
  192 + puertoRico.translate([dx + 580 * dz, dy + 430 * dz]);
  193 + return albersUsa;
  194 + };
  195 +
  196 + return albersUsa.scale(lower48.scale());
  197 +};
  198 +
  199 +var d3_radians = Math.PI / 180;
  200 +d3.geo.mercator = function() {
  201 + var scale = 500,
  202 + translate = [480, 250];
  203 +
  204 + function mercator(coordinates) {
  205 + var x = coordinates[0] / 360,
  206 + y = -(Math.log(Math.tan(Math.PI / 4 + coordinates[1] * d3_radians / 2)) / d3_radians) / 360;
  207 + return [
  208 + scale * x + translate[0],
  209 + scale * Math.max(-.5, Math.min(.5, y)) + translate[1]
  210 + ];
  211 + }
  212 +
  213 + mercator.invert = function(coordinates) {
  214 + var x = (coordinates[0] - translate[0]) / scale,
  215 + y = (coordinates[1] - translate[1]) / scale;
  216 + return [
  217 + 360 * x,
  218 + 2 * Math.atan(Math.exp(-360 * y * d3_radians)) / d3_radians - 90
  219 + ];
  220 + };
  221 +
  222 + mercator.scale = function(x) {
  223 + if (!arguments.length) return scale;
  224 + scale = +x;
  225 + return mercator;
  226 + };
  227 +
  228 + mercator.translate = function(x) {
  229 + if (!arguments.length) return translate;
  230 + translate = [+x[0], +x[1]];
  231 + return mercator;
  232 + };
  233 +
  234 + return mercator;
  235 +};
  236 +/**
  237 + * Returns a function that, given a GeoJSON object (e.g., a feature), returns
  238 + * the corresponding SVG path. The function can be customized by overriding the
  239 + * projection. Point features are mapped to circles with a default radius of
  240 + * 4.5px; the radius can be specified either as a constant or a function that
  241 + * is evaluated per object.
  242 + */
  243 +d3.geo.path = function() {
  244 + var pointRadius = 4.5,
  245 + pointCircle = d3_path_circle(pointRadius),
  246 + projection = d3.geo.albersUsa();
  247 +
  248 + function path(d, i) {
  249 + if (typeof pointRadius === "function") {
  250 + pointCircle = d3_path_circle(pointRadius.apply(this, arguments));
  251 + }
  252 + return d3_geo_pathType(pathTypes, d);
  253 + }
  254 +
  255 + function project(coordinates) {
  256 + return projection(coordinates).join(",");
  257 + }
  258 +
  259 + var pathTypes = {
  260 +
  261 + FeatureCollection: function(f) {
  262 + var path = [],
  263 + features = f.features,
  264 + i = -1, // features.index
  265 + n = features.length;
  266 + while (++i < n) path.push(d3_geo_pathType(pathTypes, features[i].geometry));
  267 + return path.join("");
  268 + },
  269 +
  270 + Feature: function(f) {
  271 + return d3_geo_pathType(pathTypes, f.geometry);
  272 + },
  273 +
  274 + Point: function(o) {
  275 + return "M" + project(o.coordinates) + pointCircle;
  276 + },
  277 +
  278 + MultiPoint: function(o) {
  279 + var path = [],
  280 + coordinates = o.coordinates,
  281 + i = -1, // coordinates.index
  282 + n = coordinates.length;
  283 + while (++i < n) path.push("M", project(coordinates[i]), pointCircle);
  284 + return path.join("");
  285 + },
  286 +
  287 + LineString: function(o) {
  288 + var path = ["M"],
  289 + coordinates = o.coordinates,
  290 + i = -1, // coordinates.index
  291 + n = coordinates.length;
  292 + while (++i < n) path.push(project(coordinates[i]), "L");
  293 + path.pop();
  294 + return path.join("");
  295 + },
  296 +
  297 + MultiLineString: function(o) {
  298 + var path = [],
  299 + coordinates = o.coordinates,
  300 + i = -1, // coordinates.index
  301 + n = coordinates.length,
  302 + subcoordinates, // coordinates[i]
  303 + j, // subcoordinates.index
  304 + m; // subcoordinates.length
  305 + while (++i < n) {
  306 + subcoordinates = coordinates[i];
  307 + j = -1;
  308 + m = subcoordinates.length;
  309 + path.push("M");
  310 + while (++j < m) path.push(project(subcoordinates[j]), "L");
  311 + path.pop();
  312 + }
  313 + return path.join("");
  314 + },
  315 +
  316 + Polygon: function(o) {
  317 + var path = [],
  318 + coordinates = o.coordinates,
  319 + i = -1, // coordinates.index
  320 + n = coordinates.length,
  321 + subcoordinates, // coordinates[i]
  322 + j, // subcoordinates.index
  323 + m; // subcoordinates.length
  324 + while (++i < n) {
  325 + subcoordinates = coordinates[i];
  326 + j = -1;
  327 + m = subcoordinates.length;
  328 + path.push("M");
  329 + while (++j < m) path.push(project(subcoordinates[j]), "L");
  330 + path[path.length - 1] = "Z";
  331 + }
  332 + return path.join("");
  333 + },
  334 +
  335 + MultiPolygon: function(o) {
  336 + var path = [],
  337 + coordinates = o.coordinates,
  338 + i = -1, // coordinates index
  339 + n = coordinates.length,
  340 + subcoordinates, // coordinates[i]
  341 + j, // subcoordinates index
  342 + m, // subcoordinates.length
  343 + subsubcoordinates, // subcoordinates[j]
  344 + k, // subsubcoordinates index
  345 + p; // subsubcoordinates.length
  346 + while (++i < n) {
  347 + subcoordinates = coordinates[i];
  348 + j = -1;
  349 + m = subcoordinates.length;
  350 + while (++j < m) {
  351 + subsubcoordinates = subcoordinates[j];
  352 + k = -1;
  353 + p = subsubcoordinates.length - 1;
  354 + path.push("M");
  355 + while (++k < p) path.push(project(subsubcoordinates[k]), "L");
  356 + path[path.length - 1] = "Z";
  357 + }
  358 + }
  359 + return path.join("");
  360 + },
  361 +
  362 + GeometryCollection: function(o) {
  363 + var path = [],
  364 + geometries = o.geometries,
  365 + i = -1, // geometries index
  366 + n = geometries.length;
  367 + while (++i < n) path.push(d3_geo_pathType(pathTypes, geometries[i]));
  368 + return path.join("");
  369 + }
  370 +
  371 + };
  372 +
  373 + var areaTypes = {
  374 +
  375 + FeatureCollection: function(f) {
  376 + var area = 0,
  377 + features = f.features,
  378 + i = -1, // features.index
  379 + n = features.length;
  380 + while (++i < n) area += d3_geo_pathType(areaTypes, features[i]);
  381 + return area;
  382 + },
  383 +
  384 + Feature: function(f) {
  385 + return d3_geo_pathType(areaTypes, f.geometry);
  386 + },
  387 +
  388 + Point: d3_geo_pathZero,
  389 + MultiPoint: d3_geo_pathZero,
  390 + LineString: d3_geo_pathZero,
  391 + MultiLineString: d3_geo_pathZero,
  392 +
  393 + Polygon: function(o) {
  394 + return polygonArea(o.coordinates);
  395 + },
  396 +
  397 + MultiPolygon: function(o) {
  398 + var sum = 0,
  399 + coordinates = o.coordinates,
  400 + i = -1, // coordinates index
  401 + n = coordinates.length;
  402 + while (++i < n) sum += polygonArea(coordinates[i]);
  403 + return sum;
  404 + },
  405 +
  406 + GeometryCollection: function(o) {
  407 + var sum = 0,
  408 + geometries = o.geometries,
  409 + i = -1, // geometries index
  410 + n = geometries.length;
  411 + while (++i < n) sum += d3_geo_pathType(areaTypes, geometries[i]);
  412 + return sum;
  413 + }
  414 +
  415 + };
  416 +
  417 + function polygonArea(coordinates) {
  418 + var sum = area(coordinates[0]), // exterior ring
  419 + i = 0, // coordinates.index
  420 + n = coordinates.length;
  421 + while (++i < n) sum -= area(coordinates[i]); // holes
  422 + return sum;
  423 + }
  424 +
  425 + function polygonCentroid(coordinates) {
  426 + var polygon = d3.geom.polygon(coordinates[0].map(projection)), // exterior ring
  427 + centroid = polygon.centroid(1),
  428 + x = centroid[0],
  429 + y = centroid[1],
  430 + z = Math.abs(polygon.area()),
  431 + i = 0, // coordinates index
  432 + n = coordinates.length;
  433 + while (++i < n) {
  434 + polygon = d3.geom.polygon(coordinates[i].map(projection)); // holes
  435 + centroid = polygon.centroid(1);
  436 + x -= centroid[0];
  437 + y -= centroid[1];
  438 + z -= Math.abs(polygon.area());
  439 + }
  440 + return [x, y, 6 * z]; // weighted centroid
  441 + }
  442 +
  443 + var centroidTypes = {
  444 +
  445 + // TODO FeatureCollection
  446 + // TODO Point
  447 + // TODO MultiPoint
  448 + // TODO LineString
  449 + // TODO MultiLineString
  450 + // TODO GeometryCollection
  451 +
  452 + Feature: function(f) {
  453 + return d3_geo_pathType(centroidTypes, f.geometry);
  454 + },
  455 +
  456 + Polygon: function(o) {
  457 + var centroid = polygonCentroid(o.coordinates);
  458 + return [centroid[0] / centroid[2], centroid[1] / centroid[2]];
  459 + },
  460 +
  461 + MultiPolygon: function(o) {
  462 + var area = 0,
  463 + coordinates = o.coordinates,
  464 + centroid,
  465 + x = 0,
  466 + y = 0,
  467 + z = 0,
  468 + i = -1, // coordinates index
  469 + n = coordinates.length;
  470 + while (++i < n) {
  471 + centroid = polygonCentroid(coordinates[i]);
  472 + x += centroid[0];
  473 + y += centroid[1];
  474 + z += centroid[2];
  475 + }
  476 + return [x / z, y / z];
  477 + }
  478 +
  479 + };
  480 +
  481 +
  482 + function area(coordinates) {
  483 + return Math.abs(d3.geom.polygon(coordinates.map(projection)).area());
  484 + }
  485 +
  486 + path.projection = function(x) {
  487 + projection = x;
  488 + return path;
  489 + };
  490 +
  491 + path.area = function(d) {
  492 + return d3_geo_pathType(areaTypes, d);
  493 + };
  494 +
  495 + path.centroid = function(d) {
  496 + return d3_geo_pathType(centroidTypes, d);
  497 + };
  498 +
  499 + path.pointRadius = function(x) {
  500 + if (typeof x === "function") pointRadius = x;
  501 + else {
  502 + pointRadius = +x;
  503 + pointCircle = d3_path_circle(pointRadius);
  504 + }
  505 + return path;
  506 + };
  507 +
  508 + return path;
  509 +};
  510 +
  511 +function d3_path_circle(radius) {
  512 + return "m0," + radius
  513 + + "a" + radius + "," + radius + " 0 1,1 0," + (-2 * radius)
  514 + + "a" + radius + "," + radius + " 0 1,1 0," + (+2 * radius)
  515 + + "z";
  516 +}
  517 +
  518 +function d3_geo_pathZero() {
  519 + return 0;
  520 +}
  521 +
  522 +function d3_geo_pathType(types, o) {
  523 + return o && o.type in types ? types[o.type](o) : "";
  524 +}
  525 +/**
  526 + * Given a GeoJSON object, returns the corresponding bounding box. The bounding
  527 + * box is represented by a two-dimensional array: [[left, bottom], [right,
  528 + * top]], where left is the minimum longitude, bottom is the minimum latitude,
  529 + * right is maximum longitude, and top is the maximum latitude.
  530 + */
  531 +d3.geo.bounds = function(feature) {
  532 + var left = Infinity,
  533 + bottom = Infinity,
  534 + right = -Infinity,
  535 + top = -Infinity;
  536 + d3_geo_bounds(feature, function(x, y) {
  537 + if (x < left) left = x;
  538 + if (x > right) right = x;
  539 + if (y < bottom) bottom = y;
  540 + if (y > top) top = y;
  541 + });
  542 + return [[left, bottom], [right, top]];
  543 +};
  544 +
  545 +function d3_geo_bounds(o, f) {
  546 + if (o.type in d3_geo_boundsTypes) d3_geo_boundsTypes[o.type](o, f);
  547 +}
  548 +
  549 +var d3_geo_boundsTypes = {
  550 + Feature: d3_geo_boundsFeature,
  551 + FeatureCollection: d3_geo_boundsFeatureCollection,
  552 + LineString: d3_geo_boundsLineString,
  553 + MultiLineString: d3_geo_boundsMultiLineString,
  554 + MultiPoint: d3_geo_boundsLineString,
  555 + MultiPolygon: d3_geo_boundsMultiPolygon,
  556 + Point: d3_geo_boundsPoint,
  557 + Polygon: d3_geo_boundsPolygon
  558 +};
  559 +
  560 +function d3_geo_boundsFeature(o, f) {
  561 + d3_geo_bounds(o.geometry, f);
  562 +}
  563 +
  564 +function d3_geo_boundsFeatureCollection(o, f) {
  565 + for (var a = o.features, i = 0, n = a.length; i < n; i++) {
  566 + d3_geo_bounds(a[i].geometry, f);
  567 + }
  568 +}
  569 +
  570 +function d3_geo_boundsLineString(o, f) {
  571 + for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) {
  572 + f.apply(null, a[i]);
  573 + }
  574 +}
  575 +
  576 +function d3_geo_boundsMultiLineString(o, f) {
  577 + for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) {
  578 + for (var b = a[i], j = 0, m = b.length; j < m; j++) {
  579 + f.apply(null, b[j]);
  580 + }
  581 + }
  582 +}
  583 +
  584 +function d3_geo_boundsMultiPolygon(o, f) {
  585 + for (var a = o.coordinates, i = 0, n = a.length; i < n; i++) {
  586 + for (var b = a[i][0], j = 0, m = b.length; j < m; j++) {
  587 + f.apply(null, b[j]);
  588 + }
  589 + }
  590 +}
  591 +
  592 +function d3_geo_boundsPoint(o, f) {
  593 + f.apply(null, o.coordinates);
  594 +}
  595 +
  596 +function d3_geo_boundsPolygon(o, f) {
  597 + for (var a = o.coordinates[0], i = 0, n = a.length; i < n; i++) {
  598 + f.apply(null, a[i]);
  599 + }
  600 +}
  601 +// From http://williams.best.vwh.net/avform.htm#Intermediate
  602 +d3.geo.greatCircle = function() {
  603 + var source = d3_geo_greatCircleSource,
  604 + target = d3_geo_greatCircleTarget,
  605 + n = 100,
  606 + radius = 6371; // Mean radius of Earth, in km.
  607 + // TODO: breakAtDateLine?
  608 +
  609 + function greatCircle(d, i) {
  610 + var from = source.call(this, d, i),
  611 + to = target.call(this, d, i),
  612 + x0 = from[0] * d3_radians,
  613 + y0 = from[1] * d3_radians,
  614 + x1 = to[0] * d3_radians,
  615 + y1 = to[1] * d3_radians,
  616 + cx0 = Math.cos(x0), sx0 = Math.sin(x0),
  617 + cy0 = Math.cos(y0), sy0 = Math.sin(y0),
  618 + cx1 = Math.cos(x1), sx1 = Math.sin(x1),
  619 + cy1 = Math.cos(y1), sy1 = Math.sin(y1),
  620 + d = Math.acos(sy0 * sy1 + cy0 * cy1 * Math.cos(x1 - x0)),
  621 + sd = Math.sin(d),
  622 + f = d / (n - 1),
  623 + e = -f,
  624 + path = [],
  625 + i = -1;
  626 +
  627 + while (++i < n) {
  628 + e += f;
  629 + var A = Math.sin(d - e) / sd,
  630 + B = Math.sin(e) / sd,
  631 + x = A * cy0 * cx0 + B * cy1 * cx1,
  632 + y = A * cy0 * sx0 + B * cy1 * sx1,
  633 + z = A * sy0 + B * sy1;
  634 + path[i] = [
  635 + Math.atan2(y, x) / d3_radians,
  636 + Math.atan2(z, Math.sqrt(x * x + y * y)) / d3_radians
  637 + ];
  638 + }
  639 +
  640 + return path;
  641 + }
  642 +
  643 + greatCircle.source = function(x) {
  644 + if (!arguments.length) return source;
  645 + source = x;
  646 + return greatCircle;
  647 + };
  648 +
  649 + greatCircle.target = function(x) {
  650 + if (!arguments.length) return target;
  651 + target = x;
  652 + return greatCircle;
  653 + };
  654 +
  655 + greatCircle.n = function(x) {
  656 + if (!arguments.length) return n;
  657 + n = +x;
  658 + return greatCircle;
  659 + };
  660 +
  661 + greatCircle.radius = function(x) {
  662 + if (!arguments.length) return radius;
  663 + radius = +x;
  664 + return greatCircle;
  665 + };
  666 +
  667 + // Haversine formula for great-circle distance.
  668 + greatCircle.distance = function(d, i) {
  669 + var from = source.call(this, d, i),
  670 + to = target.call(this, d, i),
  671 + x0 = from[0] * d3_radians,
  672 + y0 = from[1] * d3_radians,
  673 + x1 = to[0] * d3_radians,
  674 + y1 = to[1] * d3_radians,
  675 + sy = Math.sin((y1 - y0) / 2),
  676 + sx = Math.sin((x1 - x0) / 2),
  677 + a = sy * sy + Math.cos(y0) * Math.cos(y1) * sx * sx;
  678 +
  679 + return radius * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  680 + };
  681 +
  682 + return greatCircle;
  683 +};
  684 +
  685 +function d3_geo_greatCircleSource(d) {
  686 + return d.source;
  687 +}
  688 +
  689 +function d3_geo_greatCircleTarget(d) {
  690 + return d.target;
  691 +}
  692 +})();
3,592 lib/d3.js
... ... @@ -0,0 +1,3592 @@
  1 +(function(){d3 = {version: "1.29.1"}; // semver
  2 +if (!Date.now) Date.now = function() {
  3 + return +new Date;
  4 +};
  5 +if (!Object.create) Object.create = function(o) {
  6 + /** @constructor */ function f() {}
  7 + f.prototype = o;
  8 + return new f;
  9 +};
  10 +var d3_array = d3_arraySlice; // conversion for NodeLists
  11 +
  12 +function d3_arrayCopy(psuedoarray) {
  13 + var i = -1, n = psuedoarray.length, array = [];
  14 + while (++i < n) array.push(psuedoarray[i]);
  15 + return array;
  16 +}
  17 +
  18 +function d3_arraySlice(psuedoarray) {
  19 + return Array.prototype.slice.call(psuedoarray);
  20 +}
  21 +
  22 +try {
  23 + d3_array(document.documentElement.childNodes)[0].nodeType;
  24 +} catch(e) {
  25 + d3_array = d3_arrayCopy;
  26 +}
  27 +d3.functor = function(v) {
  28 + return typeof v === "function" ? v : function() { return v; };
  29 +};
  30 +// A getter-setter method that preserves the appropriate `this` context.
  31 +d3.rebind = function(object, method) {
  32 + return function() {
  33 + var x = method.apply(object, arguments);
  34 + return arguments.length ? object : x;
  35 + };
  36 +};
  37 +d3.ascending = function(a, b) {
  38 + return a < b ? -1 : a > b ? 1 : 0;
  39 +};
  40 +d3.descending = function(a, b) {
  41 + return b < a ? -1 : b > a ? 1 : 0;
  42 +};
  43 +d3.min = function(array, f) {
  44 + var i = -1,
  45 + n = array.length,
  46 + a,
  47 + b;
  48 + if (arguments.length === 1) {
  49 + while (++i < n && ((a = array[i]) == null || a != a)) a = undefined;
  50 + while (++i < n) if ((b = array[i]) != null && a > b) a = b;
  51 + } else {
  52 + while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;
  53 + while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
  54 + }
  55 + return a;
  56 +};
  57 +d3.max = function(array, f) {
  58 + var i = -1,
  59 + n = array.length,
  60 + a,
  61 + b;
  62 + if (arguments.length === 1) {
  63 + while (++i < n && ((a = array[i]) == null || a != a)) a = undefined;
  64 + while (++i < n) if ((b = array[i]) != null && b > a) a = b;
  65 + } else {
  66 + while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;
  67 + while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;
  68 + }
  69 + return a;
  70 +};
  71 +d3.sum = function(array, f) {
  72 + var s = 0,
  73 + n = array.length,
  74 + a,
  75 + i = -1;
  76 +
  77 + if (arguments.length === 1) {
  78 + while (++i < n) if (!isNaN(a = +array[i])) s += a;
  79 + } else {
  80 + while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a;
  81 + }
  82 +
  83 + return s;
  84 +};
  85 +// R-7 per <http://en.wikipedia.org/wiki/Quantile>
  86 +d3.quantile = function(values, p) {
  87 + var H = (values.length - 1) * p + 1,
  88 + h = Math.floor(H),
  89 + v = values[h - 1],
  90 + e = H - h;
  91 + return e ? v + e * (values[h] - v) : v;
  92 +};
  93 +d3.zip = function() {
  94 + if (!(n = arguments.length)) return [];
  95 + for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m;) {
  96 + for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n;) {
  97 + zip[j] = arguments[j][i];
  98 + }
  99 + }
  100 + return zips;
  101 +};
  102 +
  103 +function d3_zipLength(d) {
  104 + return d.length;
  105 +}
  106 +// Locate the insertion point for x in a to maintain sorted order. The
  107 +// arguments lo and hi may be used to specify a subset of the array which should
  108 +// be considered; by default the entire array is used. If x is already present
  109 +// in a, the insertion point will be before (to the left of) any existing
  110 +// entries. The return value is suitable for use as the first argument to
  111 +// `array.splice` assuming that a is already sorted.
  112 +//
  113 +// The returned insertion point i partitions the array a into two halves so that
  114 +// all v < x for v in a[lo:i] for the left side and all v >= x for v in a[i:hi]
  115 +// for the right side.
  116 +d3.bisectLeft = function(a, x, lo, hi) {
  117 + if (arguments.length < 3) lo = 0;
  118 + if (arguments.length < 4) hi = a.length;
  119 + while (lo < hi) {
  120 + var mid = (lo + hi) >> 1;
  121 + if (a[mid] < x) lo = mid + 1;
  122 + else hi = mid;
  123 + }
  124 + return lo;
  125 +};
  126 +
  127 +// Similar to bisectLeft, but returns an insertion point which comes after (to
  128 +// the right of) any existing entries of x in a.
  129 +//
  130 +// The returned insertion point i partitions the array into two halves so that
  131 +// all v <= x for v in a[lo:i] for the left side and all v > x for v in a[i:hi]
  132 +// for the right side.
  133 +d3.bisect =
  134 +d3.bisectRight = function(a, x, lo, hi) {
  135 + if (arguments.length < 3) lo = 0;
  136 + if (arguments.length < 4) hi = a.length;
  137 + while (lo < hi) {
  138 + var mid = (lo + hi) >> 1;
  139 + if (x < a[mid]) hi = mid;
  140 + else lo = mid + 1;
  141 + }
  142 + return lo;
  143 +};
  144 +d3.first = function(array, f) {
  145 + var i = 0,
  146 + n = array.length,
  147 + a = array[0],
  148 + b;
  149 + if (arguments.length === 1) f = d3.ascending;
  150 + while (++i < n) {
  151 + if (f.call(array, a, b = array[i]) > 0) {
  152 + a = b;
  153 + }
  154 + }
  155 + return a;
  156 +};
  157 +d3.last = function(array, f) {
  158 + var i = 0,
  159 + n = array.length,
  160 + a = array[0],
  161 + b;
  162 + if (arguments.length === 1) f = d3.ascending;
  163 + while (++i < n) {
  164 + if (f.call(array, a, b = array[i]) <= 0) {
  165 + a = b;
  166 + }
  167 + }
  168 + return a;
  169 +};
  170 +d3.nest = function() {
  171 + var nest = {},
  172 + keys = [],
  173 + sortKeys = [],
  174 + sortValues,
  175 + rollup;
  176 +
  177 + function map(array, depth) {
  178 + if (depth >= keys.length) return rollup
  179 + ? rollup.call(nest, array) : (sortValues
  180 + ? array.sort(sortValues)
  181 + : array);
  182 +
  183 + var i = -1,
  184 + n = array.length,
  185 + key = keys[depth++],
  186 + keyValue,
  187 + object,
  188 + o = {};
  189 +
  190 + while (++i < n) {
  191 + if ((keyValue = key(object = array[i])) in o) {
  192 + o[keyValue].push(object);
  193 + } else {
  194 + o[keyValue] = [object];
  195 + }
  196 + }
  197 +
  198 + for (keyValue in o) {
  199 + o[keyValue] = map(o[keyValue], depth);
  200 + }
  201 +
  202 + return o;
  203 + }
  204 +
  205 + function entries(map, depth) {
  206 + if (depth >= keys.length) return map;
  207 +
  208 + var a = [],
  209 + sortKey = sortKeys[depth++],
  210 + key;
  211 +
  212 + for (key in map) {
  213 + a.push({key: key, values: entries(map[key], depth)});
  214 + }
  215 +
  216 + if (sortKey) a.sort(function(a, b) {
  217 + return sortKey(a.key, b.key);
  218 + });
  219 +
  220 + return a;
  221 + }
  222 +
  223 + nest.map = function(array) {
  224 + return map(array, 0);
  225 + };
  226 +
  227 + nest.entries = function(array) {
  228 + return entries(map(array, 0), 0);
  229 + };
  230 +
  231 + nest.key = function(d) {
  232 + keys.push(d);
  233 + return nest;
  234 + };
  235 +
  236 + // Specifies the order for the most-recently specified key.
  237 + // Note: only applies to entries. Map keys are unordered!
  238 + nest.sortKeys = function(order) {
  239 + sortKeys[keys.length - 1] = order;
  240 + return nest;
  241 + };
  242 +
  243 + // Specifies the order for leaf values.
  244 + // Applies to both maps and entries array.
  245 + nest.sortValues = function(order) {
  246 + sortValues = order;
  247 + return nest;
  248 + };
  249 +
  250 + nest.rollup = function(f) {
  251 + rollup = f;
  252 + return nest;
  253 + };
  254 +
  255 + return nest;
  256 +};
  257 +d3.keys = function(map) {
  258 + var keys = [];
  259 + for (var key in map) keys.push(key);
  260 + return keys;
  261 +};
  262 +d3.values = function(map) {
  263 + var values = [];
  264 + for (var key in map) values.push(map[key]);
  265 + return values;
  266 +};
  267 +d3.entries = function(map) {
  268 + var entries = [];
  269 + for (var key in map) entries.push({key: key, value: map[key]});
  270 + return entries;
  271 +};
  272 +d3.permute = function(array, indexes) {
  273 + var permutes = [],
  274 + i = -1,
  275 + n = indexes.length;
  276 + while (++i < n) permutes[i] = array[indexes[i]];
  277 + return permutes;
  278 +};
  279 +d3.merge = function(arrays) {
  280 + return Array.prototype.concat.apply([], arrays);
  281 +};
  282 +d3.split = function(array, f) {
  283 + var arrays = [],
  284 + values = [],
  285 + value,
  286 + i = -1,
  287 + n = array.length;
  288 + if (arguments.length < 2) f = d3_splitter;
  289 + while (++i < n) {
  290 + if (f.call(values, value = array[i], i)) {
  291 + values = [];
  292 + } else {
  293 + if (!values.length) arrays.push(values);
  294 + values.push(value);
  295 + }
  296 + }
  297 + return arrays;
  298 +};
  299 +
  300 +function d3_splitter(d) {
  301 + return d == null;
  302 +}
  303 +function d3_collapse(s) {
  304 + return s.replace(/(^\s+)|(\s+$)/g, "").replace(/\s+/g, " ");
  305 +}
  306 +//
  307 +// Note: assigning to the arguments array simultaneously changes the value of
  308 +// the corresponding argument!
  309 +//
  310 +// TODO The `this` argument probably shouldn't be the first argument to the
  311 +// callback, anyway, since it's redundant. However, that will require a major
  312 +// version bump due to backwards compatibility, so I'm not changing it right
  313 +// away.
  314 +//
  315 +function d3_call(callback) {
  316 + callback.apply(this, (arguments[0] = this, arguments));
  317 + return this;
  318 +}
  319 +/**
  320 + * @param {number} start
  321 + * @param {number=} stop
  322 + * @param {number=} step
  323 + */
  324 +d3.range = function(start, stop, step) {
  325 + if (arguments.length === 1) { stop = start; start = 0; }
  326 + if (step == null) step = 1;
  327 + if ((stop - start) / step == Infinity) throw new Error("infinite range");
  328 + var range = [],
  329 + i = -1,
  330 + j;
  331 + if (step < 0) while ((j = start + step * ++i) > stop) range.push(j);
  332 + else while ((j = start + step * ++i) < stop) range.push(j);
  333 + return range;
  334 +};
  335 +d3.requote = function(s) {
  336 + return s.replace(d3_requote_re, "\\$&");
  337 +};
  338 +
  339 +var d3_requote_re = /[\\\^\$\*\+\?\[\]\(\)\.\{\}]/g;
  340 +d3.round = function(x, n) {
  341 + return n
  342 + ? Math.round(x * Math.pow(10, n)) * Math.pow(10, -n)
  343 + : Math.round(x);
  344 +};
  345 +d3.xhr = function(url, mime, callback) {
  346 + var req = new XMLHttpRequest;
  347 + if (arguments.length < 3) callback = mime;
  348 + else if (mime && req.overrideMimeType) req.overrideMimeType(mime);
  349 + req.open("GET", url, true);
  350 + req.onreadystatechange = function() {
  351 + if (req.readyState === 4) callback(req.status < 300 ? req : null);
  352 + };
  353 + req.send(null);
  354 +};
  355 +d3.text = function(url, mime, callback) {
  356 + function ready(req) {
  357 + callback(req && req.responseText);
  358 + }
  359 + if (arguments.length < 3) {
  360 + callback = mime;
  361 + mime = null;
  362 + }
  363 + d3.xhr(url, mime, ready);
  364 +};
  365 +d3.json = function(url, callback) {
  366 + d3.text(url, "application/json", function(text) {
  367 + callback(text ? JSON.parse(text) : null);
  368 + });
  369 +};
  370 +d3.html = function(url, callback) {
  371 + d3.text(url, "text/html", function(text) {
  372 + if (text != null) { // Treat empty string as valid HTML.
  373 + var range = document.createRange();
  374 + range.selectNode(document.body);
  375 + text = range.createContextualFragment(text);
  376 + }
  377 + callback(text);
  378 + });
  379 +};
  380 +d3.xml = function(url, mime, callback) {
  381 + function ready(req) {
  382 + callback(req && req.responseXML);
  383 + }
  384 + if (arguments.length < 3) {
  385 + callback = mime;
  386 + mime = null;
  387 + }
  388 + d3.xhr(url, mime, ready);
  389 +};
  390 +d3.ns = {
  391 +
  392 + prefix: {
  393 + svg: "http://www.w3.org/2000/svg",
  394 + xhtml: "http://www.w3.org/1999/xhtml",
  395 + xlink: "http://www.w3.org/1999/xlink",
  396 + xml: "http://www.w3.org/XML/1998/namespace",
  397 + xmlns: "http://www.w3.org/2000/xmlns/"
  398 + },
  399 +
  400 + qualify: function(name) {
  401 + var i = name.indexOf(":");
  402 + return i < 0 ? name : {
  403 + space: d3.ns.prefix[name.substring(0, i)],
  404 + local: name.substring(i + 1)
  405 + };
  406 + }
  407 +
  408 +};
  409 +/** @param {...string} types */
  410 +d3.dispatch = function(types) {
  411 + var dispatch = {},
  412 + type;
  413 + for (var i = 0, n = arguments.length; i < n; i++) {
  414 + type = arguments[i];
  415 + dispatch[type] = d3_dispatch(type);
  416 + }
  417 + return dispatch;
  418 +};
  419 +
  420 +function d3_dispatch(type) {
  421 + var dispatch = {},
  422 + listeners = [];
  423 +
  424 + dispatch.add = function(listener) {
  425 + for (var i = 0; i < listeners.length; i++) {
  426 + if (listeners[i].listener == listener) return dispatch; // already registered
  427 + }
  428 + listeners.push({listener: listener, on: true});
  429 + return dispatch;
  430 + };
  431 +
  432 + dispatch.remove = function(listener) {
  433 + for (var i = 0; i < listeners.length; i++) {
  434 + var l = listeners[i];
  435 + if (l.listener == listener) {
  436 + l.on = false;
  437 + listeners = listeners.slice(0, i).concat(listeners.slice(i + 1));
  438 + break;
  439 + }
  440 + }
  441 + return dispatch;
  442 + };
  443 +
  444 + dispatch.dispatch = function() {
  445 + var ls = listeners; // defensive reference
  446 + for (var i = 0, n = ls.length; i < n; i++) {
  447 + var l = ls[i];
  448 + if (l.on) l.listener.apply(this, arguments);
  449 + }
  450 + };
  451 +
  452 + return dispatch;
  453 +};
  454 +// TODO align
  455 +d3.format = function(specifier) {
  456 + var match = d3_format_re.exec(specifier),
  457 + fill = match[1] || " ",
  458 + sign = match[3] || "",
  459 + zfill = match[5],
  460 + width = +match[6],
  461 + comma = match[7],
  462 + precision = match[8],
  463 + type = match[9],
  464 + percentage = false,
  465 + integer = false;
  466 +
  467 + if (precision) precision = precision.substring(1);
  468 +
  469 + if (zfill) {
  470 + fill = "0"; // TODO align = "=";
  471 + if (comma) width -= Math.floor((width - 1) / 4);
  472 + }
  473 +
  474 + switch (type) {
  475 + case "n": comma = true; type = "g"; break;
  476 + case "%": percentage = true; type = "f"; break;
  477 + case "p": percentage = true; type = "r"; break;
  478 + case "d": integer = true; precision = "0"; break;
  479 + }
  480 +
  481 + type = d3_format_types[type] || d3_format_typeDefault;
  482 +
  483 + return function(value) {
  484 + var number = percentage ? value * 100 : +value,
  485 + negative = (number < 0) && (number = -number) ? "\u2212" : sign;
  486 +
  487 + // Return the empty string for floats formatted as ints.
  488 + if (integer && (number % 1)) return "";
  489 +
  490 + // Convert the input value to the desired precision.
  491 + value = type(number, precision);
  492 +
  493 + // If the fill character is 0, the sign and group is applied after the fill.
  494 + if (zfill) {
  495 + var length = value.length + negative.length;
  496 + if (length < width) value = new Array(width - length + 1).join(fill) + value;
  497 + if (comma) value = d3_format_group(value);
  498 + value = negative + value;
  499 + }
  500 +
  501 + // Otherwise (e.g., space-filling), the sign and group is applied before.
  502 + else {
  503 + if (comma) value = d3_format_group(value);
  504 + value = negative + value;
  505 + var length = value.length;
  506 + if (length < width) value = new Array(width - length + 1).join(fill) + value;
  507 + }
  508 + if (percentage) value += "%";
  509 +
  510 + return value;
  511 + };
  512 +};
  513 +
  514 +// [[fill]align][sign][#][0][width][,][.precision][type]
  515 +var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/;
  516 +
  517 +var d3_format_types = {
  518 + g: function(x, p) { return x.toPrecision(p); },
  519 + e: function(x, p) { return x.toExponential(p); },