2 d3.horizon = function() {
3 var bands = 1, // between 1 and 5, typically
4 mode = "offset", // or mirror
5 interpolate = "linear", // or basis, monotone, step-before, etc.
12 var color = d3.scale.linear()
14 .range(["#d62728", "#fff", "#1f77b4"]);
16 // For each small multiple…
18 g.each(function(d, i) {
19 var g = d3.select(this),
26 id; // unique id for paths
28 // Compute x- and y-values along with extents.
29 var data = d.map(function(d, i) {
30 var xv = x.call(this, d, i),
31 yv = y.call(this, d, i);
32 if (xv < xMin) xMin = xv;
33 if (xv > xMax) xMax = xv;
34 if (-yv > yMax) yMax = -yv;
35 if (yv > yMax) yMax = yv;
39 // Compute the new x- and y-scales, and transform.
40 var x1 = d3.scale.linear().domain([xMin, xMax]).range([0, w]),
41 y1 = d3.scale.linear().domain([0, yMax]).range([0, h * bands]),
42 t1 = d3_horizonTransform(bands, h, mode);
44 // Retrieve the old scales, if this is an update.
46 x0 = this.__chart__.x;
47 y0 = this.__chart__.y;
48 t0 = this.__chart__.t;
49 id = this.__chart__.id;
57 // We'll use a defs to store the area path and the clip path.
58 var defs = g.selectAll("defs")
61 // The clip path is a simple rect.
62 defs.enter().append("defs").append("clipPath")
63 .attr("id", "d3_horizon_clip" + id)
68 defs.select("rect").transition()
73 // We'll use a container to clip all horizon layers at once.
77 .attr("clip-path", "url(#d3_horizon_clip" + id + ")");
79 // Instantiate each copy of the path with different transforms.
80 var path = g.select("g").selectAll("path")
81 .data(d3.range(-1, -bands - 1, -1).concat(d3.range(1, bands + 1)), Number);
83 var d0 = d3_horizonArea
84 .interpolate(interpolate)
85 .x(function(d) { return x0(d[0]); })
87 .y1(function(d) { return h * bands - y0(d[1]); })
90 var d1 = d3_horizonArea
91 .x(function(d) { return x1(d[0]); })
92 .y1(function(d) { return h * bands - y1(d[1]); })
95 path.enter().append("path")
97 .attr("transform", t0)
102 .style("fill", color)
103 .attr("transform", t1)
106 path.exit().transition()
108 .attr("transform", t1)
112 // Stash the new scales.
113 this.__chart__ = {x: x1, y: y1, t: t1, id: id};
118 horizon.duration = function(x) {
119 if (!arguments.length) return duration;
124 horizon.bands = function(x) {
125 if (!arguments.length) return bands;
127 color.domain([-bands, 0, bands]);
131 horizon.mode = function(x) {
132 if (!arguments.length) return mode;
137 horizon.colors = function(x) {
138 if (!arguments.length) return color.range();
143 horizon.interpolate = function(x) {
144 if (!arguments.length) return interpolate;
145 interpolate = x + "";
149 horizon.x = function(z) {
150 if (!arguments.length) return x;
155 horizon.y = function(z) {
156 if (!arguments.length) return y;
161 horizon.width = function(x) {
162 if (!arguments.length) return w;
167 horizon.height = function(x) {
168 if (!arguments.length) return h;
176 var d3_horizonArea = d3.svg.area(),
179 function d3_horizonX(d) {
183 function d3_horizonY(d) {
187 function d3_horizonTransform(bands, h, mode) {
188 return mode == "offset"
189 ? function(d) { return "translate(0," + (d + (d < 0) - bands) * h + ")"; }
190 : function(d) { return (d < 0 ? "scale(1,-1)" : "") + "translate(0," + (d - bands) * h + ")"; };