in pytheas-core/src/main/resources/js/d3/d3.chart.js [558:669]
function horizon(g) {
g.each(function(d, i) {
var g = d3.select(this),
n = 2 * bands + 1,
xMin = Infinity,
xMax = -Infinity,
yMax = -Infinity,
x0, // old x-scale
y0, // old y-scale
id; // unique id for paths
// Compute x- and y-values along with extents.
var data = d.map(function(d, i) {
var xv = x.call(this, d, i),
yv = y.call(this, d, i);
if (xv < xMin) xMin = xv;
if (xv > xMax) xMax = xv;
if (-yv > yMax) yMax = -yv;
if (yv > yMax) yMax = yv;
return [xv, yv];
});
// Compute the new x- and y-scales.
var x1 = d3.scale.linear().domain([xMin, xMax]).range([0, w]),
y1 = d3.scale.linear().domain([0, yMax]).range([0, h * bands]);
// Retrieve the old scales, if this is an update.
if (this.__chart__) {
x0 = this.__chart__.x;
y0 = this.__chart__.y;
id = this.__chart__.id;
} else {
x0 = d3.scale.linear().domain([0, Infinity]).range(x1.range());
y0 = d3.scale.linear().domain([0, Infinity]).range(y1.range());
id = ++d3_chart_horizonId;
}
// We'll use a defs to store the area path and the clip path.
var defs = g.selectAll("defs")
.data([data]);
var defsEnter = defs.enter().append("svg:defs");
// The clip path is a simple rect.
defsEnter.append("svg:clipPath")
.attr("id", "d3_chart_horizon_clip" + id)
.append("svg:rect")
.attr("width", w)
.attr("height", h);
defs.select("rect").transition()
.duration(duration)
.attr("width", w)
.attr("height", h);
// The area path is rendered with our resuable d3.svg.area.
defsEnter.append("svg:path")
.attr("id", "d3_chart_horizon_path" + id)
.attr("d", d3_chart_horizonArea
.interpolate(interpolate)
.x(function(d) { return x0(d[0]); })
.y0(h * bands)
.y1(function(d) { return h * bands - y0(d[1]); }))
.transition()
.duration(duration)
.attr("d", d3_chart_horizonArea
.x(function(d) { return x1(d[0]); })
.y1(function(d) { return h * bands - y1(d[1]); }));
defs.select("path").transition()
.duration(duration)
.attr("d", d3_chart_horizonArea);
// We'll use a container to clip all horizon layers at once.
g.selectAll("g")
.data([null])
.enter().append("svg:g")
.attr("clip-path", "url(#d3_chart_horizon_clip" + id + ")");
// Define the transform function based on the mode.
var transform = mode == "offset"
? function(d) { return "translate(0," + (d + (d < 0) - bands) * h + ")"; }
: function(d) { return (d < 0 ? "scale(1,-1)" : "") + "translate(0," + (d - bands) * h + ")"; };
// Instantiate each copy of the path with different transforms.
var u = g.select("g").selectAll("use")
.data(d3.range(-1, -bands - 1, -1).concat(d3.range(1, bands + 1)), Number);
// TODO don't fudge the enter transition
u.enter().append("svg:use")
.attr("xlink:href", "#d3_chart_horizon_path" + id)
.attr("transform", function(d) { return transform(d + (d > 0 ? 1 : -1)); })
.style("fill", color)
.transition()
.duration(duration)
.attr("transform", transform);
u.transition()
.duration(duration)
.attr("transform", transform)
.style("fill", color);
u.exit().transition()
.duration(duration)
.attr("transform", transform)
.remove();
// Stash the new scales.
this.__chart__ = {x: x1, y: y1, id: id};
});
d3.timer.flush();
}