d3_rails 0.0.10 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -12,6 +12,10 @@ handle interactivity, and incorporate smooth transitions and staged animations
12
12
  into your pages. You can use D3 as a visualization framework (like Protovis),
13
13
  or you can use it to build dynamic pages (like jQuery).
14
14
 
15
+ # D3 Version
16
+
17
+ The current release of this gem is using **D3 v=2.5.0**
18
+
15
19
  ### Installation
16
20
 
17
21
  This gem should work out of the box. All you have to do is add the gem to your Gemfile:
@@ -1,3 +1,3 @@
1
1
  module D3Rails
2
- VERSION = "0.0.10"
2
+ VERSION = "0.1.0"
3
3
  end
File without changes
File without changes
@@ -268,6 +268,17 @@ function d3_geom_polygonIntersect(c, d, a, b) {
268
268
  // http://blog.thejit.org/assets/voronoijs/voronoi.js
269
269
  // See lib/jit/LICENSE for details.
270
270
 
271
+ // Notes:
272
+ //
273
+ // This implementation does not clip the returned polygons, so if you want to
274
+ // clip them to a particular shape you will need to do that either in SVG or by
275
+ // post-processing with d3.geom.polygon's clip method.
276
+ //
277
+ // If any vertices are coincident or have NaN positions, the behavior of this
278
+ // method is undefined. Most likely invalid polygons will be returned. You
279
+ // should filter invalid points, and consolidate coincident points, before
280
+ // computing the tessellation.
281
+
271
282
  /**
272
283
  * @param vertices [[x1, y1], [x2, y2], …]
273
284
  * @returns polygons [[[x1, y1], [x2, y2], …], …]
@@ -275,7 +286,6 @@ function d3_geom_polygonIntersect(c, d, a, b) {
275
286
  d3.geom.voronoi = function(vertices) {
276
287
  var polygons = vertices.map(function() { return []; });
277
288
 
278
- // Note: we expect the caller to clip the polygons, if needed.
279
289
  d3_voronoi_tessellate(vertices, function(e) {
280
290
  var s1,
281
291
  s2,
@@ -10,7 +10,7 @@ try {
10
10
  d3_style_setProperty.call(this, name, value + "", priority);
11
11
  };
12
12
  }
13
- d3 = {version: "2.4.6"}; // semver
13
+ d3 = {version: "2.5.0"}; // semver
14
14
  var d3_array = d3_arraySlice; // conversion for NodeLists
15
15
 
16
16
  function d3_arrayCopy(pseudoarray) {
@@ -105,6 +105,42 @@ d3.max = function(array, f) {
105
105
  }
106
106
  return a;
107
107
  };
108
+ d3.extent = function(array, f) {
109
+ var i = -1,
110
+ n = array.length,
111
+ a,
112
+ b,
113
+ c;
114
+ if (arguments.length === 1) {
115
+ while (++i < n && ((a = c = array[i]) == null || a != a)) a = c = undefined;
116
+ while (++i < n) if ((b = array[i]) != null) {
117
+ if (a > b) a = b;
118
+ if (c < b) c = b;
119
+ }
120
+ } else {
121
+ while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined;
122
+ while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
123
+ if (a > b) a = b;
124
+ if (c < b) c = b;
125
+ }
126
+ }
127
+ return [a, c];
128
+ };
129
+ d3.random = {
130
+ normal: function(mean, deviation) {
131
+ if (arguments.length < 2) deviation = 1;
132
+ if (arguments.length < 1) mean = 0;
133
+ return function() {
134
+ var x, y, r;
135
+ do {
136
+ x = Math.random() * 2 - 1;
137
+ y = Math.random() * 2 - 1;
138
+ r = x * x + y * y;
139
+ } while (!r || r > 1);
140
+ return mean + deviation * x * Math.sqrt(-2 * Math.log(r) / r);
141
+ };
142
+ }
143
+ };
108
144
  function d3_number(x) {
109
145
  return x != null && !isNaN(x);
110
146
  }
@@ -438,47 +474,59 @@ d3.ns = {
438
474
  }
439
475
 
440
476
  };
441
- /** @param {...string} types */
442
- d3.dispatch = function(types) {
443
- var dispatch = {},
444
- type;
445
- for (var i = 0, n = arguments.length; i < n; i++) {
446
- type = arguments[i];
447
- dispatch[type] = d3_dispatch(type);
448
- }
477
+ d3.dispatch = function() {
478
+ var dispatch = new d3_dispatch(),
479
+ i = -1,
480
+ n = arguments.length;
481
+ while (++i < n) dispatch[arguments[i]] = d3_dispatch_event();
449
482
  return dispatch;
450
483
  };
451
484
 
452
- function d3_dispatch(type) {
453
- var dispatch = {},
454
- listeners = [];
485
+ function d3_dispatch() {}
455
486
 
456
- dispatch.add = function(listener) {
457
- for (var i = 0; i < listeners.length; i++) {
458
- if (listeners[i].listener == listener) return dispatch; // already registered
459
- }
460
- listeners.push({listener: listener, on: true});
461
- return dispatch;
462
- };
487
+ d3_dispatch.prototype.on = function(type, listener) {
488
+ var i = type.indexOf("."),
489
+ name = "";
463
490
 
464
- dispatch.remove = function(listener) {
465
- for (var i = 0; i < listeners.length; i++) {
466
- var l = listeners[i];
467
- if (l.listener == listener) {
468
- l.on = false;
469
- listeners = listeners.slice(0, i).concat(listeners.slice(i + 1));
470
- break;
471
- }
491
+ // Extract optional namespace, e.g., "click.foo"
492
+ if (i > 0) {
493
+ name = type.substring(i + 1);
494
+ type = type.substring(0, i);
495
+ }
496
+
497
+ this[type].on(name, listener);
498
+ };
499
+
500
+ function d3_dispatch_event() {
501
+ var listeners = [],
502
+ listenerByName = {};
503
+
504
+ function dispatch() {
505
+ var z = listeners, // defensive reference
506
+ i = -1,
507
+ n = z.length,
508
+ l;
509
+ while (++i < n) if ((l = z[i])._on) l.apply(this, arguments);
510
+ }
511
+
512
+ dispatch.on = function(name, listener) {
513
+ var l, i;
514
+
515
+ // remove the old listener, if any
516
+ if (l = listenerByName[name]) {
517
+ l._on = false;
518
+ listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
519
+ delete listenerByName[name];
472
520
  }
473
- return dispatch;
474
- };
475
521
 
476
- dispatch.dispatch = function() {
477
- var ls = listeners; // defensive reference
478
- for (var i = 0, n = ls.length; i < n; i++) {
479
- var l = ls[i];
480
- if (l.on) l.listener.apply(this, arguments);
522
+ // add the new listener, if any
523
+ if (listener) {
524
+ listener._on = true;
525
+ listeners.push(listener);
526
+ listenerByName[name] = listener;
481
527
  }
528
+
529
+ return dispatch;
482
530
  };
483
531
 
484
532
  return dispatch;
@@ -732,6 +780,11 @@ function d3_ease_bounce(t) {
732
780
  : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
733
781
  }
734
782
  d3.event = null;
783
+
784
+ function d3_eventCancel() {
785
+ d3.event.stopPropagation();
786
+ d3.event.preventDefault();
787
+ }
735
788
  d3.interpolate = function(a, b) {
736
789
  var i = d3.interpolators.length, f;
737
790
  while (--i >= 0 && !(f = d3.interpolators[i](a, b)));
@@ -826,6 +879,10 @@ d3.interpolateString = function(a, b) {
826
879
  };
827
880
  };
828
881
 
882
+ d3.interpolateTransform = function(a, b) {
883
+ return d3.interpolateString(d3.transform(a) + "", d3.transform(b) + "");
884
+ };
885
+
829
886
  d3.interpolateRgb = function(a, b) {
830
887
  a = d3.rgb(a);
831
888
  b = d3.rgb(b);
@@ -896,20 +953,19 @@ d3.interpolateObject = function(a, b) {
896
953
  };
897
954
  }
898
955
 
899
- var d3_interpolate_number = /[-+]?(?:\d+\.\d+|\d+\.|\.\d+|\d+)(?:[eE][-]?\d+)?/g,
900
- d3_interpolate_rgb = {background: 1, fill: 1, stroke: 1};
956
+ var d3_interpolate_number = /[-+]?(?:\d*\.?\d+)(?:[eE][-+]?\d+)?/g;
901
957
 
902
958
  function d3_interpolateByName(n) {
903
- return n in d3_interpolate_rgb || /\bcolor\b/.test(n)
904
- ? d3.interpolateRgb
959
+ return n == "transform"
960
+ ? d3.interpolateTransform
905
961
  : d3.interpolate;
906
962
  }
907
963
 
908
964
  d3.interpolators = [
909
965
  d3.interpolateObject,
910
966
  function(a, b) { return (b instanceof Array) && d3.interpolateArray(a, b); },
911
- function(a, b) { return (typeof b === "string") && d3.interpolateString(String(a), b); },
912
- function(a, b) { return (typeof b === "string" ? b in d3_rgb_names || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Rgb || b instanceof d3_Hsl) && d3.interpolateRgb(String(a), b); },
967
+ function(a, b) { return (typeof b === "string") && d3.interpolateString(a + "", b); },
968
+ function(a, b) { return (typeof b === "string" ? b in d3_rgb_names || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Rgb || b instanceof d3_Hsl) && d3.interpolateRgb(a + "", b); },
913
969
  function(a, b) { return (typeof b === "number") && d3.interpolateNumber(+a, b); }
914
970
  ];
915
971
  function d3_uninterpolateNumber(a, b) {
@@ -1871,7 +1927,7 @@ function d3_transition(groups, id, time) {
1871
1927
 
1872
1928
  groups.each = function(type, listener) {
1873
1929
  if (arguments.length < 2) return d3_transition_each.call(groups, type);
1874
- event[type].add(listener);
1930
+ event.on(type, listener);
1875
1931
  return groups;
1876
1932
  };
1877
1933
 
@@ -1897,7 +1953,7 @@ function d3_transition(groups, id, time) {
1897
1953
  }
1898
1954
  }
1899
1955
 
1900
- event.start.dispatch.call(node, d, i);
1956
+ event.start.call(node, d, i);
1901
1957
  if (!tick(elapsed)) d3.timer(tick, 0, time);
1902
1958
  return 1;
1903
1959
  }
@@ -1916,7 +1972,7 @@ function d3_transition(groups, id, time) {
1916
1972
  if (t >= 1) {
1917
1973
  stop();
1918
1974
  d3_transitionInheritId = id;
1919
- event.end.dispatch.call(node, d, i);
1975
+ event.end.call(node, d, i);
1920
1976
  d3_transitionInheritId = 0;
1921
1977
  return 1;
1922
1978
  }
@@ -1939,17 +1995,18 @@ function d3_transitionNull(d, i, a) {
1939
1995
  return a != "" && d3_transitionRemove;
1940
1996
  }
1941
1997
 
1942
- function d3_transitionTween(b) {
1998
+ function d3_transitionTween(name, b) {
1999
+ var interpolate = d3_interpolateByName(name);
1943
2000
 
1944
2001
  function transitionFunction(d, i, a) {
1945
2002
  var v = b.call(this, d, i);
1946
2003
  return v == null
1947
2004
  ? a != "" && d3_transitionRemove
1948
- : a != v && d3.interpolate(a, v);
2005
+ : a != v && interpolate(a, v);
1949
2006
  }
1950
2007
 
1951
2008
  function transitionString(d, i, a) {
1952
- return a != b && d3.interpolate(a, b);
2009
+ return a != b && interpolate(a, b);
1953
2010
  }
1954
2011
 
1955
2012
  return typeof b === "function" ? transitionFunction
@@ -2014,7 +2071,7 @@ d3_transitionPrototype.selectAll = function(selector) {
2014
2071
  return d3_transition(subgroups, this.id, this.time).ease(this.ease());
2015
2072
  };
2016
2073
  d3_transitionPrototype.attr = function(name, value) {
2017
- return this.attrTween(name, d3_transitionTween(value));
2074
+ return this.attrTween(name, d3_transitionTween(name, value));
2018
2075
  };
2019
2076
 
2020
2077
  d3_transitionPrototype.attrTween = function(nameNS, tween) {
@@ -2038,7 +2095,7 @@ d3_transitionPrototype.attrTween = function(nameNS, tween) {
2038
2095
  };
2039
2096
  d3_transitionPrototype.style = function(name, value, priority) {
2040
2097
  if (arguments.length < 3) priority = "";
2041
- return this.styleTween(name, d3_transitionTween(value), priority);
2098
+ return this.styleTween(name, d3_transitionTween(name, value), priority);
2042
2099
  };
2043
2100
 
2044
2101
  d3_transitionPrototype.styleTween = function(name, tween, priority) {
@@ -2191,6 +2248,54 @@ var d3_timer_frame = window.requestAnimationFrame
2191
2248
  || window.oRequestAnimationFrame
2192
2249
  || window.msRequestAnimationFrame
2193
2250
  || function(callback) { setTimeout(callback, 17); };
2251
+ d3.transform = function(string) {
2252
+ d3_transformG.setAttribute("transform", string);
2253
+ return new d3_transform(d3_transformG.transform.baseVal.consolidate().matrix);
2254
+ };
2255
+
2256
+ // Compute x-scale and normalize the first row.
2257
+ // Compute shear and make second row orthogonal to first.
2258
+ // Compute y-scale and normalize the second row.
2259
+ // Finally, compute the rotation.
2260
+ function d3_transform(m) {
2261
+ var r0 = [m.a, m.b],
2262
+ r1 = [m.c, m.d],
2263
+ kx = d3_transformNormalize(r0),
2264
+ kz = d3_transformDot(r0, r1),
2265
+ ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz));
2266
+ this.translate = [m.e, m.f];
2267
+ this.rotate = Math.atan2(m.b, m.a) * d3_transformDegrees;
2268
+ this.scale = [kx, ky || 0];
2269
+ this.skew = ky ? kz / ky * d3_transformDegrees : 0;
2270
+ };
2271
+
2272
+ d3_transform.prototype.toString = function() {
2273
+ return "translate(" + this.translate
2274
+ + ")rotate(" + this.rotate
2275
+ + ")skewX(" + this.skew
2276
+ + ")scale(" + this.scale
2277
+ + ")";
2278
+ };
2279
+
2280
+ function d3_transformDot(a, b) {
2281
+ return a[0] * b[0] + a[1] * b[1];
2282
+ }
2283
+
2284
+ function d3_transformNormalize(a) {
2285
+ var k = Math.sqrt(d3_transformDot(a, a));
2286
+ a[0] /= k;
2287
+ a[1] /= k;
2288
+ return k;
2289
+ }
2290
+
2291
+ function d3_transformCombine(a, b, k) {
2292
+ a[0] += k * b[0];
2293
+ a[1] += k * b[1];
2294
+ return a;
2295
+ }
2296
+
2297
+ var d3_transformG = document.createElementNS(d3.ns.prefix.svg, "g"),
2298
+ d3_transformDegrees = 180 / Math.PI;
2194
2299
  function d3_noop() {}
2195
2300
  d3.scale = {};
2196
2301
 
@@ -2515,6 +2620,10 @@ function d3_scale_ordinal(domain, ranger) {
2515
2620
  return range[((index[x] || (index[x] = domain.push(x))) - 1) % range.length];
2516
2621
  }
2517
2622
 
2623
+ function steps(start, step) {
2624
+ return d3.range(domain.length).map(function(i) { return start + step * i; });
2625
+ }
2626
+
2518
2627
  scale.domain = function(x) {
2519
2628
  if (!arguments.length) return domain;
2520
2629
  domain = [];
@@ -2537,7 +2646,7 @@ function d3_scale_ordinal(domain, ranger) {
2537
2646
  var start = x[0],
2538
2647
  stop = x[1],
2539
2648
  step = (stop - start) / (domain.length - 1 + padding);
2540
- range = domain.length < 2 ? [(start + stop) / 2] : d3.range(start + step * padding / 2, stop + step / 2, step);
2649
+ range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step);
2541
2650
  rangeBand = 0;
2542
2651
  ranger = {t: "rangePoints", x: x, p: padding};
2543
2652
  return scale;
@@ -2548,7 +2657,7 @@ function d3_scale_ordinal(domain, ranger) {
2548
2657
  var start = x[0],
2549
2658
  stop = x[1],
2550
2659
  step = (stop - start) / (domain.length + padding);
2551
- range = d3.range(start + step * padding, stop, step);
2660
+ range = steps(start + step * padding, step);
2552
2661
  rangeBand = step * (1 - padding);
2553
2662
  ranger = {t: "rangeBands", x: x, p: padding};
2554
2663
  return scale;
@@ -2558,9 +2667,8 @@ function d3_scale_ordinal(domain, ranger) {
2558
2667
  if (arguments.length < 2) padding = 0;
2559
2668
  var start = x[0],
2560
2669
  stop = x[1],
2561
- step = Math.floor((stop - start) / (domain.length + padding)),
2562
- err = stop - start - (domain.length - padding) * step;
2563
- range = d3.range(start + Math.round(err / 2), stop, step);
2670
+ step = Math.floor((stop - start) / (domain.length + padding));
2671
+ range = steps(start + Math.round((stop - start - (domain.length - padding) * step) / 2), step);
2564
2672
  rangeBand = Math.round(step * (1 - padding));
2565
2673
  ranger = {t: "rangeRoundBands", x: x, p: padding};
2566
2674
  return scale;
@@ -3529,8 +3637,9 @@ function d3_svg_mousePoint(container, e) {
3529
3637
  point = point.matrixTransform(container.getScreenCTM().inverse());
3530
3638
  return [point.x, point.y];
3531
3639
  };
3532
- d3.svg.touches = function(container) {
3533
- var touches = d3.event.touches;
3640
+ d3.svg.touches = function(container, touches) {
3641
+ if (arguments.length < 2) touches = d3.event.touches;
3642
+
3534
3643
  return touches ? d3_array(touches).map(function(touch) {
3535
3644
  var point = d3_svg_mousePoint(container, touch);
3536
3645
  point.identifier = touch.identifier;
@@ -3820,6 +3929,341 @@ function d3_svg_axisSubdivide(scale, ticks, m) {
3820
3929
  }
3821
3930
  return subticks;
3822
3931
  }
3932
+ d3.svg.brush = function() {
3933
+ var event = d3.dispatch("brushstart", "brush", "brushend"),
3934
+ x, // x-scale, optional
3935
+ y, // y-scale, optional
3936
+ extent = [[0, 0], [0, 0]]; // [x0, y0], [x1, y1]
3937
+
3938
+ function brush(g) {
3939
+ var resizes = x && y ? ["n", "e", "s", "w", "nw", "ne", "se", "sw"]
3940
+ : x ? ["e", "w"]
3941
+ : y ? ["n", "s"]
3942
+ : [];
3943
+
3944
+ g.each(function() {
3945
+ var g = d3.select(this).on("mousedown.brush", down),
3946
+ bg = g.selectAll(".background").data([,]),
3947
+ fg = g.selectAll(".extent").data([,]),
3948
+ tz = g.selectAll(".resize").data(resizes, String),
3949
+ e;
3950
+
3951
+ // An invisible, mouseable area for starting a new brush.
3952
+ bg.enter().append("svg:rect")
3953
+ .attr("class", "background")
3954
+ .style("visibility", "hidden")
3955
+ .style("pointer-events", "all")
3956
+ .style("cursor", "crosshair");
3957
+
3958
+ // The visible brush extent; style this as you like!
3959
+ fg.enter().append("svg:rect")
3960
+ .attr("class", "extent")
3961
+ .style("cursor", "move");
3962
+
3963
+ // More invisible rects for resizing the extent.
3964
+ tz.enter().append("svg:rect")
3965
+ .attr("class", function(d) { return "resize " + d; })
3966
+ .attr("width", 6)
3967
+ .attr("height", 6)
3968
+ .style("visibility", "hidden")
3969
+ .style("pointer-events", brush.empty() ? "none" : "all")
3970
+ .style("cursor", function(d) { return d3_svg_brushCursor[d]; });
3971
+
3972
+ // Remove any superfluous resizers.
3973
+ tz.exit().remove();
3974
+
3975
+ // Initialize the background to fill the defined range.
3976
+ // If the range isn't defined, you can post-process.
3977
+ if (x) {
3978
+ e = d3_scaleExtent(x.range());
3979
+ bg.attr("x", e[0]).attr("width", e[1] - e[0]);
3980
+ d3_svg_brushRedrawX(g, extent);
3981
+ }
3982
+ if (y) {
3983
+ e = d3_scaleExtent(y.range());
3984
+ bg.attr("y", e[0]).attr("height", e[1] - e[0]);
3985
+ d3_svg_brushRedrawY(g, extent);
3986
+ }
3987
+ });
3988
+ }
3989
+
3990
+ function down() {
3991
+ var target = d3.select(d3.event.target);
3992
+
3993
+ // Store some global state for the duration of the brush gesture.
3994
+ d3_svg_brush = brush;
3995
+ d3_svg_brushTarget = this;
3996
+ d3_svg_brushExtent = extent;
3997
+ d3_svg_brushOffset = d3.svg.mouse(d3_svg_brushTarget);
3998
+
3999
+ // If the extent was clicked on, drag rather than brush;
4000
+ // store the offset between the mouse and extent origin instead.
4001
+ if (d3_svg_brushDrag = target.classed("extent")) {
4002
+ d3_svg_brushOffset[0] = extent[0][0] - d3_svg_brushOffset[0];
4003
+ d3_svg_brushOffset[1] = extent[0][1] - d3_svg_brushOffset[1];
4004
+ }
4005
+
4006
+ // If a resizer was clicked on, record which side is to be resized.
4007
+ // Also, set the offset to the opposite side.
4008
+ else if (target.classed("resize")) {
4009
+ d3_svg_brushResize = d3.event.target.__data__;
4010
+ d3_svg_brushOffset[0] = extent[+/w$/.test(d3_svg_brushResize)][0];
4011
+ d3_svg_brushOffset[1] = extent[+/^n/.test(d3_svg_brushResize)][1];
4012
+ }
4013
+
4014
+ // If the ALT key is down when starting a brush, the center is at the mouse.
4015
+ else if (d3.event.altKey) {
4016
+ d3_svg_brushCenter = d3_svg_brushOffset.slice();
4017
+ }
4018
+
4019
+ // Restrict which dimensions are resized.
4020
+ d3_svg_brushX = !/^(n|s)$/.test(d3_svg_brushResize) && x;
4021
+ d3_svg_brushY = !/^(e|w)$/.test(d3_svg_brushResize) && y;
4022
+
4023
+ // Notify listeners.
4024
+ d3_svg_brushDispatch = dispatcher(this, arguments);
4025
+ d3_svg_brushDispatch("brushstart");
4026
+ d3_svg_brushMove();
4027
+ d3_eventCancel();
4028
+ }
4029
+
4030
+ function dispatcher(that, argumentz) {
4031
+ return function(type) {
4032
+ var e = d3.event;
4033
+ try {
4034
+ d3.event = {type: type, target: brush};
4035
+ event[type].apply(that, argumentz);
4036
+ } finally {
4037
+ d3.event = e;
4038
+ }
4039
+ };
4040
+ }
4041
+
4042
+ brush.x = function(z) {
4043
+ if (!arguments.length) return x;
4044
+ x = z;
4045
+ return brush;
4046
+ };
4047
+
4048
+ brush.y = function(z) {
4049
+ if (!arguments.length) return y;
4050
+ y = z;
4051
+ return brush;
4052
+ };
4053
+
4054
+ brush.extent = function(z) {
4055
+ var x0, x1, y0, y1, t;
4056
+
4057
+ // Invert the pixel extent to data-space.
4058
+ if (!arguments.length) {
4059
+ if (x) {
4060
+ x0 = x.invert(extent[0][0]), x1 = x.invert(extent[1][0]);
4061
+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
4062
+ }
4063
+ if (y) {
4064
+ y0 = y.invert(extent[0][1]), y1 = y.invert(extent[1][1]);
4065
+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
4066
+ }
4067
+ return x && y ? [[x0, y0], [x1, y1]] : x ? [x0, x1] : y && [y0, y1];
4068
+ }
4069
+
4070
+ // Scale the data-space extent to pixels.
4071
+ if (x) {
4072
+ x0 = z[0], x1 = z[1];
4073
+ if (y) x0 = x0[0], x1 = x1[0];
4074
+ x0 = x(x0), x1 = x(x1);
4075
+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
4076
+ extent[0][0] = x0, extent[1][0] = x1;
4077
+ }
4078
+ if (y) {
4079
+ y0 = z[0], y1 = z[1];
4080
+ if (x) y0 = y0[1], y1 = y1[1];
4081
+ y0 = y(y0), y1 = y(y1);
4082
+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
4083
+ extent[0][1] = y0, extent[1][1] = y1;
4084
+ }
4085
+
4086
+ return brush;
4087
+ };
4088
+
4089
+ brush.clear = function() {
4090
+ extent[0][0] =
4091
+ extent[0][1] =
4092
+ extent[1][0] =
4093
+ extent[1][1] = 0;
4094
+ return brush;
4095
+ };
4096
+
4097
+ brush.empty = function() {
4098
+ return (x && extent[0][0] === extent[1][0])
4099
+ || (y && extent[0][1] === extent[1][1]);
4100
+ };
4101
+
4102
+ brush.on = function(type, listener) {
4103
+ event.on(type, listener);
4104
+ return brush;
4105
+ };
4106
+
4107
+ d3.select(window)
4108
+ .on("mousemove.brush", d3_svg_brushMove)
4109
+ .on("mouseup.brush", d3_svg_brushUp)
4110
+ .on("keydown.brush", d3_svg_brushKeydown)
4111
+ .on("keyup.brush", d3_svg_brushKeyup);
4112
+
4113
+ return brush;
4114
+ };
4115
+
4116
+ var d3_svg_brush,
4117
+ d3_svg_brushDispatch,
4118
+ d3_svg_brushTarget,
4119
+ d3_svg_brushX,
4120
+ d3_svg_brushY,
4121
+ d3_svg_brushExtent,
4122
+ d3_svg_brushDrag,
4123
+ d3_svg_brushResize,
4124
+ d3_svg_brushCenter,
4125
+ d3_svg_brushOffset;
4126
+
4127
+ function d3_svg_brushRedrawX(g, extent) {
4128
+ g.select(".extent").attr("x", extent[0][0]);
4129
+ g.selectAll(".n,.s,.w,.nw,.sw").attr("x", extent[0][0] - 2);
4130
+ g.selectAll(".e,.ne,.se").attr("x", extent[1][0] - 3);
4131
+ g.selectAll(".extent,.n,.s").attr("width", extent[1][0] - extent[0][0]);
4132
+ }
4133
+
4134
+ function d3_svg_brushRedrawY(g, extent) {
4135
+ g.select(".extent").attr("y", extent[0][1]);
4136
+ g.selectAll(".n,.e,.w,.nw,.ne").attr("y", extent[0][1] - 3);
4137
+ g.selectAll(".s,.se,.sw").attr("y", extent[1][1] - 4);
4138
+ g.selectAll(".extent,.e,.w").attr("height", extent[1][1] - extent[0][1]);
4139
+ }
4140
+
4141
+ function d3_svg_brushKeydown() {
4142
+ if (d3.event.keyCode == 32 && d3_svg_brushTarget && !d3_svg_brushDrag) {
4143
+ d3_svg_brushCenter = null;
4144
+ d3_svg_brushOffset[0] -= d3_svg_brushExtent[1][0];
4145
+ d3_svg_brushOffset[1] -= d3_svg_brushExtent[1][1];
4146
+ d3_svg_brushDrag = 2;
4147
+ d3_eventCancel();
4148
+ }
4149
+ }
4150
+
4151
+ function d3_svg_brushKeyup() {
4152
+ if (d3.event.keyCode == 32 && d3_svg_brushDrag == 2) {
4153
+ d3_svg_brushOffset[0] += d3_svg_brushExtent[1][0];
4154
+ d3_svg_brushOffset[1] += d3_svg_brushExtent[1][1];
4155
+ d3_svg_brushDrag = 0;
4156
+ d3_eventCancel();
4157
+ }
4158
+ }
4159
+
4160
+ function d3_svg_brushMove() {
4161
+ if (d3_svg_brushOffset) {
4162
+ var mouse = d3.svg.mouse(d3_svg_brushTarget),
4163
+ g = d3.select(d3_svg_brushTarget);
4164
+
4165
+ if (!d3_svg_brushDrag) {
4166
+
4167
+ // If needed, determine the center from the current extent.
4168
+ if (d3.event.altKey) {
4169
+ if (!d3_svg_brushCenter) {
4170
+ d3_svg_brushCenter = [
4171
+ (d3_svg_brushExtent[0][0] + d3_svg_brushExtent[1][0]) / 2,
4172
+ (d3_svg_brushExtent[0][1] + d3_svg_brushExtent[1][1]) / 2
4173
+ ];
4174
+ }
4175
+
4176
+ // Update the offset, for when the ALT key is released.
4177
+ d3_svg_brushOffset[0] = d3_svg_brushExtent[+(mouse[0] < d3_svg_brushCenter[0])][0];
4178
+ d3_svg_brushOffset[1] = d3_svg_brushExtent[+(mouse[1] < d3_svg_brushCenter[1])][1];
4179
+ }
4180
+
4181
+ // When the ALT key is released, we clear the center.
4182
+ else d3_svg_brushCenter = null;
4183
+ }
4184
+
4185
+ // Update the brush extent for each dimension.
4186
+ if (d3_svg_brushX) {
4187
+ d3_svg_brushMove1(mouse, d3_svg_brushX, 0);
4188
+ d3_svg_brushRedrawX(g, d3_svg_brushExtent);
4189
+ }
4190
+ if (d3_svg_brushY) {
4191
+ d3_svg_brushMove1(mouse, d3_svg_brushY, 1);
4192
+ d3_svg_brushRedrawY(g, d3_svg_brushExtent);
4193
+ }
4194
+
4195
+ // Notify listeners.
4196
+ d3_svg_brushDispatch("brush");
4197
+ }
4198
+ }
4199
+
4200
+ function d3_svg_brushMove1(mouse, scale, i) {
4201
+ var range = d3_scaleExtent(scale.range()),
4202
+ offset = d3_svg_brushOffset[i],
4203
+ size = d3_svg_brushExtent[1][i] - d3_svg_brushExtent[0][i],
4204
+ min,
4205
+ max;
4206
+
4207
+ // When dragging, reduce the range by the extent size and offset.
4208
+ if (d3_svg_brushDrag) {
4209
+ range[0] -= offset;
4210
+ range[1] -= size + offset;
4211
+ }
4212
+
4213
+ // Clamp the mouse so that the extent fits within the range extent.
4214
+ min = Math.max(range[0], Math.min(range[1], mouse[i]));
4215
+
4216
+ // Compute the new extent bounds.
4217
+ if (d3_svg_brushDrag) {
4218
+ max = (min += offset) + size;
4219
+ } else {
4220
+
4221
+ // If the ALT key is pressed, then preserve the center of the extent.
4222
+ if (d3_svg_brushCenter) offset = Math.max(range[0], Math.min(range[1], 2 * d3_svg_brushCenter[i] - min));
4223
+
4224
+ // Compute the min and max of the offset and mouse.
4225
+ if (offset < min) {
4226
+ max = min;
4227
+ min = offset;
4228
+ } else {
4229
+ max = offset;
4230
+ }
4231
+ }
4232
+
4233
+ // Update the stored bounds.
4234
+ d3_svg_brushExtent[0][i] = min;
4235
+ d3_svg_brushExtent[1][i] = max;
4236
+ }
4237
+
4238
+ function d3_svg_brushUp() {
4239
+ if (d3_svg_brushOffset) {
4240
+ d3_svg_brushMove();
4241
+ d3.select(d3_svg_brushTarget).selectAll(".resize").style("pointer-events", d3_svg_brush.empty() ? "none" : "all");
4242
+ d3_svg_brushDispatch("brushend");
4243
+ d3_svg_brush =
4244
+ d3_svg_brushDispatch =
4245
+ d3_svg_brushTarget =
4246
+ d3_svg_brushX =
4247
+ d3_svg_brushY =
4248
+ d3_svg_brushExtent =
4249
+ d3_svg_brushDrag =
4250
+ d3_svg_brushResize =
4251
+ d3_svg_brushCenter =
4252
+ d3_svg_brushOffset = null;
4253
+ d3_eventCancel();
4254
+ }
4255
+ }
4256
+
4257
+ var d3_svg_brushCursor = {
4258
+ n: "ns-resize",
4259
+ e: "ew-resize",
4260
+ s: "ns-resize",
4261
+ w: "ew-resize",
4262
+ nw: "nwse-resize",
4263
+ ne: "nesw-resize",
4264
+ se: "nwse-resize",
4265
+ sw: "nesw-resize"
4266
+ };
3823
4267
  d3.behavior = {};
3824
4268
  d3.behavior.drag = function() {
3825
4269
  var event = d3.dispatch("drag", "dragstart", "dragend");
@@ -3852,7 +4296,7 @@ d3.behavior.drag = function() {
3852
4296
  }
3853
4297
 
3854
4298
  drag.on = function(type, listener) {
3855
- event[type].add(listener);
4299
+ event.on(type, listener);
3856
4300
  return drag;
3857
4301
  };
3858
4302
 
@@ -3880,7 +4324,7 @@ function d3_behavior_dragDispatch(type) {
3880
4324
 
3881
4325
  try {
3882
4326
  d3.event = {dx: dx, dy: dy};
3883
- d3_behavior_dragEvent[type].dispatch.apply(d3_behavior_dragTarget, d3_behavior_dragArguments);
4327
+ d3_behavior_dragEvent[type].apply(d3_behavior_dragTarget, d3_behavior_dragArguments);
3884
4328
  } finally {
3885
4329
  d3.event = o;
3886
4330
  }
@@ -3888,10 +4332,10 @@ function d3_behavior_dragDispatch(type) {
3888
4332
  o.preventDefault();
3889
4333
  }
3890
4334
 
3891
- function d3_behavior_dragPoint(container) {
3892
- return d3.event.touches
3893
- ? d3.svg.touches(container)[0]
3894
- : d3.svg.mouse(container);
4335
+ function d3_behavior_dragPoint(container, type) {
4336
+ // TODO Track touch points by identifier.
4337
+ var t = d3.event.changedTouches;
4338
+ return t ? d3.svg.touches(container, t)[0] : d3.svg.mouse(container);
3895
4339
  }
3896
4340
 
3897
4341
  function d3_behavior_dragMove() {
@@ -3902,7 +4346,7 @@ function d3_behavior_dragMove() {
3902
4346
  if (!parent) return d3_behavior_dragUp();
3903
4347
 
3904
4348
  d3_behavior_dragDispatch("drag");
3905
- d3_behavior_dragCancel();
4349
+ d3_eventCancel();
3906
4350
  }
3907
4351
 
3908
4352
  function d3_behavior_dragUp() {
@@ -3914,27 +4358,22 @@ function d3_behavior_dragUp() {
3914
4358
  // Also prevent the subsequent click from propagating (e.g., for anchors).
3915
4359
  if (d3_behavior_dragMoved && d3_behavior_dragEventTarget === d3.event.target) {
3916
4360
  d3_behavior_dragStopClick = true;
3917
- d3_behavior_dragCancel();
4361
+ d3_eventCancel();
3918
4362
  }
3919
4363
  }
3920
4364
 
3921
4365
  function d3_behavior_dragClick() {
3922
4366
  if (d3_behavior_dragStopClick && d3_behavior_dragEventTarget === d3.event.target) {
3923
- d3_behavior_dragCancel();
4367
+ d3_eventCancel();
3924
4368
  d3_behavior_dragStopClick = false;
3925
4369
  d3_behavior_dragEventTarget = null;
3926
4370
  }
3927
4371
  }
3928
-
3929
- function d3_behavior_dragCancel() {
3930
- d3.event.stopPropagation();
3931
- d3.event.preventDefault();
3932
- }
3933
4372
  // TODO unbind zoom behavior?
3934
- // TODO unbind listener?
3935
4373
  d3.behavior.zoom = function() {
3936
4374
  var xyz = [0, 0, 0],
3937
- event = d3.dispatch("zoom");
4375
+ event = d3.dispatch("zoom"),
4376
+ extent = d3_behavior_zoomInfiniteExtent;
3938
4377
 
3939
4378
  function zoom() {
3940
4379
  this
@@ -3955,7 +4394,8 @@ d3.behavior.zoom = function() {
3955
4394
  // snapshot the local context for subsequent dispatch
3956
4395
  function start() {
3957
4396
  d3_behavior_zoomXyz = xyz;
3958
- d3_behavior_zoomDispatch = event.zoom.dispatch;
4397
+ d3_behavior_zoomExtent = extent;
4398
+ d3_behavior_zoomDispatch = event.zoom;
3959
4399
  d3_behavior_zoomEventTarget = d3.event.target;
3960
4400
  d3_behavior_zoomTarget = this;
3961
4401
  d3_behavior_zoomArguments = arguments;
@@ -3994,8 +4434,14 @@ d3.behavior.zoom = function() {
3994
4434
  d3_behavior_zoomLast = now;
3995
4435
  }
3996
4436
 
4437
+ zoom.extent = function(x) {
4438
+ if (!arguments.length) return extent;
4439
+ extent = x == null ? d3_behavior_zoomInfiniteExtent : x;
4440
+ return zoom;
4441
+ };
4442
+
3997
4443
  zoom.on = function(type, listener) {
3998
- event[type].add(listener);
4444
+ event.on(type, listener);
3999
4445
  return zoom;
4000
4446
  };
4001
4447
 
@@ -4008,6 +4454,7 @@ var d3_behavior_zoomDiv,
4008
4454
  d3_behavior_zoomLocations = {}, // identifier -> location
4009
4455
  d3_behavior_zoomLast = 0,
4010
4456
  d3_behavior_zoomXyz,
4457
+ d3_behavior_zoomExtent,
4011
4458
  d3_behavior_zoomDispatch,
4012
4459
  d3_behavior_zoomEventTarget,
4013
4460
  d3_behavior_zoomTarget,
@@ -4118,25 +4565,27 @@ function d3_behavior_zoomClick() {
4118
4565
  }
4119
4566
 
4120
4567
  function d3_behavior_zoomTo(z, x0, x1) {
4121
- var K = Math.pow(2, (d3_behavior_zoomXyz[2] = z) - x1[2]),
4122
- x = d3_behavior_zoomXyz[0] = x0[0] - K * x1[0],
4123
- y = d3_behavior_zoomXyz[1] = x0[1] - K * x1[1],
4124
- o = d3.event, // Events can be reentrant (e.g., focus).
4125
- k = Math.pow(2, z);
4568
+ z = d3_behavior_zoomExtentClamp(z, 2);
4569
+ var j = Math.pow(2, d3_behavior_zoomXyz[2]),
4570
+ k = Math.pow(2, z),
4571
+ K = Math.pow(2, (d3_behavior_zoomXyz[2] = z) - x1[2]),
4572
+ x_ = d3_behavior_zoomXyz[0],
4573
+ y_ = d3_behavior_zoomXyz[1],
4574
+ x = d3_behavior_zoomXyz[0] = d3_behavior_zoomExtentClamp((x0[0] - x1[0] * K), 0, k),
4575
+ y = d3_behavior_zoomXyz[1] = d3_behavior_zoomExtentClamp((x0[1] - x1[1] * K), 1, k),
4576
+ o = d3.event; // Events can be reentrant (e.g., focus).
4126
4577
 
4127
4578
  d3.event = {
4128
4579
  scale: k,
4129
4580
  translate: [x, y],
4130
4581
  transform: function(sx, sy) {
4131
- if (sx) transform(sx, x);
4132
- if (sy) transform(sy, y);
4582
+ if (sx) transform(sx, x_, x);
4583
+ if (sy) transform(sy, y_, y);
4133
4584
  }
4134
4585
  };
4135
4586
 
4136
- function transform(scale, o) {
4137
- var domain = scale.__domain || (scale.__domain = scale.domain()),
4138
- range = scale.range().map(function(v) { return (v - o) / k; });
4139
- scale.domain(domain).domain(range.map(scale.invert));
4587
+ function transform(scale, a, b) {
4588
+ scale.domain(scale.range().map(function(v) { return scale.invert(((v - b) * j) / k + a); }));
4140
4589
  }
4141
4590
 
4142
4591
  try {
@@ -4147,4 +4596,20 @@ function d3_behavior_zoomTo(z, x0, x1) {
4147
4596
 
4148
4597
  o.preventDefault();
4149
4598
  }
4599
+
4600
+ var d3_behavior_zoomInfiniteExtent = [
4601
+ [-Infinity, Infinity],
4602
+ [-Infinity, Infinity],
4603
+ [-Infinity, Infinity]
4604
+ ];
4605
+
4606
+ function d3_behavior_zoomExtentClamp(x, i, k) {
4607
+ var range = d3_behavior_zoomExtent[i],
4608
+ r0 = range[0],
4609
+ r1 = range[1];
4610
+ return arguments.length === 3
4611
+ ? Math.max(r1 * (r1 === Infinity ? -Infinity : 1 / k - 1),
4612
+ Math.min(r0 === -Infinity ? Infinity : r0, x / k)) * k
4613
+ : Math.max(r0, Math.min(r1, x));
4614
+ }
4150
4615
  })();
@@ -113,16 +113,19 @@ d3.layout.chord = function() {
113
113
  k = (2 * Math.PI - padding * n) / k;
114
114
 
115
115
  // Compute the start and end angle for each group and subgroup.
116
+ // Note: Opera has a bug reordering object literal properties!
116
117
  x = 0, i = -1; while (++i < n) {
117
118
  x0 = x, j = -1; while (++j < n) {
118
119
  var di = groupIndex[i],
119
120
  dj = subgroupIndex[di][j],
120
- v = matrix[di][dj];
121
+ v = matrix[di][dj],
122
+ a0 = x,
123
+ a1 = x += v * k;
121
124
  subgroups[di + "-" + dj] = {
122
125
  index: di,
123
126
  subindex: dj,
124
- startAngle: x,
125
- endAngle: x += v * k,
127
+ startAngle: a0,
128
+ endAngle: a1,
126
129
  value: v
127
130
  };
128
131
  }
@@ -315,14 +318,14 @@ d3.layout.force = function() {
315
318
  }
316
319
  }
317
320
 
318
- event.tick.dispatch({type: "tick", alpha: alpha});
321
+ event.tick({type: "tick", alpha: alpha});
319
322
 
320
323
  // simulated annealing, basically
321
324
  return (alpha *= .99) < .005;
322
325
  }
323
326
 
324
327
  force.on = function(type, listener) {
325
- event[type].add(listener);
328
+ event.on(type, listener);
326
329
  return force;
327
330
  };
328
331
 
@@ -602,33 +605,31 @@ d3.layout.partition = function() {
602
605
  };
603
606
  d3.layout.pie = function() {
604
607
  var value = Number,
605
- sort = null,
608
+ sort = d3_layout_pieSortByValue,
606
609
  startAngle = 0,
607
610
  endAngle = 2 * Math.PI;
608
611
 
609
612
  function pie(data, i) {
610
613
 
614
+ // Compute the numeric values for each data element.
615
+ var values = data.map(function(d, i) { return +value.call(pie, d, i); });
616
+
611
617
  // Compute the start angle.
612
618
  var a = +(typeof startAngle === "function"
613
619
  ? startAngle.apply(this, arguments)
614
620
  : startAngle);
615
621
 
616
- // Compute the angular range (end - start).
617
- var k = (typeof endAngle === "function"
622
+ // Compute the angular scale factor: from value to radians.
623
+ var k = ((typeof endAngle === "function"
618
624
  ? endAngle.apply(this, arguments)
619
- : endAngle) - startAngle;
625
+ : endAngle) - startAngle)
626
+ / d3.sum(values);
620
627
 
621
628
  // Optionally sort the data.
622
629
  var index = d3.range(data.length);
623
- if (sort != null) index.sort(function(i, j) {
624
- return sort(data[i], data[j]);
625
- });
626
-
627
- // Compute the numeric values for each data element.
628
- var values = data.map(value);
629
-
630
- // Convert k into a scale factor from value to angle, using the sum.
631
- k /= values.reduce(function(p, d) { return p + d; }, 0);
630
+ if (sort != null) index.sort(sort === d3_layout_pieSortByValue
631
+ ? function(i, j) { return values[j] - values[i]; }
632
+ : function(i, j) { return sort(data[i], data[j]); });
632
633
 
633
634
  // Compute the arcs!
634
635
  var arcs = index.map(function(i) {
@@ -695,6 +696,8 @@ d3.layout.pie = function() {
695
696
 
696
697
  return pie;
697
698
  };
699
+
700
+ var d3_layout_pieSortByValue = {};
698
701
  // data is two-dimensional array of x,y; we populate y0
699
702
  d3.layout.stack = function() {
700
703
  var values = Object,
File without changes
File without changes
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: d3_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-10-27 00:00:00.000000000Z
12
+ date: 2011-11-06 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
16
- requirement: &70271918844600 !ruby/object:Gem::Requirement
16
+ requirement: &70232077023480 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.1.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70271918844600
24
+ version_requirements: *70232077023480
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: bundler
27
- requirement: &70271918844080 !ruby/object:Gem::Requirement
27
+ requirement: &70232077022480 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.0.0
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70271918844080
35
+ version_requirements: *70232077022480
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rails
38
- requirement: &70271918843620 !ruby/object:Gem::Requirement
38
+ requirement: &70232077021620 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '3.1'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70271918843620
46
+ version_requirements: *70232077021620
47
47
  description: Gem installation of javascript framework for data visualization, D3
48
48
  email:
49
49
  - han@logicallsat.com
@@ -63,7 +63,6 @@ files:
63
63
  - vendor/assets/javascripts/.DS_Store
64
64
  - vendor/assets/javascripts/LICENSE
65
65
  - vendor/assets/javascripts/colorbrewer.js
66
- - vendor/assets/javascripts/d3-csv.js
67
66
  - vendor/assets/javascripts/d3.chart.js
68
67
  - vendor/assets/javascripts/d3.csv.js
69
68
  - vendor/assets/javascripts/d3.geo.js
@@ -72,6 +71,7 @@ files:
72
71
  - vendor/assets/javascripts/d3.layout.js
73
72
  - vendor/assets/javascripts/d3.min.js
74
73
  - vendor/assets/javascripts/d3.time.js
74
+ - vendor/assets/javascripts/d3_csv.js
75
75
  - vendor/assets/javascripts/d3_rails.js
76
76
  - vendor/assets/javascripts/science.js
77
77
  - vendor/assets/javascripts/science.lin.js