Skip to content

Instantly share code, notes, and snippets.

@enjalot
Created May 16, 2014 06:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save enjalot/de713c5d78463d41e09c to your computer and use it in GitHub Desktop.
Save enjalot/de713c5d78463d41e09c to your computer and use it in GitHub Desktop.
simple horizon++
{"description":"simple horizon++","endpoint":"","display":"svg","public":true,"require":[],"fileconfigs":{"inlet.js":{"default":true,"vim":false,"emacs":false,"fontSize":12},"horizon.js":{"default":true,"vim":false,"emacs":false,"fontSize":12}},"fullscreen":false,"play":false,"loop":false,"restart":false,"autoinit":true,"pause":true,"loop_type":"pingpong","bv":false,"nclones":15,"clone_opacity":0.4,"duration":3000,"ease":"linear","dt":0.01,"ajax-caching":true}
(function() {
d3.horizon = function() {
var bands = 1, // between 1 and 5, typically
mode = "offset", // or mirror
interpolate = "linear", // or basis, monotone, step-before, etc.
x = d3_horizonX,
y = d3_horizonY,
width = 960,
height = 40;
var color = d3.scale.linear()
.domain([-1, 0, 1])
.range(["#d62728", "#fff", "#1f77b4"]);
// For each small multiple…
function horizon(g) {
g.each(function(d) {
var g = d3.select(this),
xMin = Infinity,
xMax = -Infinity,
yMax = -Infinity,
x0, // old x-scale
y0, // old y-scale
t0,
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, and transform.
var x1 = d3.scale.linear().domain([xMin, xMax]).range([0, width]),
y1 = d3.scale.linear().domain([0, yMax]).range([0, height * bands]),
t1 = d3_horizonTransform(bands, height, mode);
// Retrieve the old scales, if this is an update.
if (this.__chart__) {
x0 = this.__chart__.x;
y0 = this.__chart__.y;
t0 = this.__chart__.t;
id = this.__chart__.id;
} else {
x0 = x1.copy();
y0 = y1.copy();
t0 = t1;
id = ++d3_horizonId;
}
// We'll use a defs to store the area path and the clip path.
var defs = g.selectAll("defs")
.data([null]);
// The clip path is a simple rect.
defs.enter().append("defs").append("clipPath")
.attr("id", "d3_horizon_clip" + id)
.append("rect")
.attr("width", width)
.attr("height", height);
d3.transition(defs.select("rect"))
.attr("width", width)
.attr("height", height);
// We'll use a container to clip all horizon layers at once.
g.selectAll("g")
.data([null])
.enter().append("g")
.attr("clip-path", "url(#d3_horizon_clip" + id + ")");
// Instantiate each copy of the path with different transforms.
var path = g.select("g").selectAll("path")
.data(d3.range(-1, -bands - 1, -1).concat(d3.range(1, bands + 1)), Number);
var d0 = d3_horizonArea
.interpolate(interpolate)
.x(function(d) { return x0(d[0]); })
.y0(height * bands)
.y1(function(d) { return height * bands - y0(d[1]); })
(data);
var d1 = d3_horizonArea
.x(function(d) { return x1(d[0]); })
.y1(function(d) { return height * bands - y1(d[1]); })
(data);
path.enter().append("path")
.style("fill", color)
.attr("transform", t0)
.attr("d", d0);
d3.transition(path)
.style("fill", color)
.attr("transform", t1)
.attr("d", d1);
d3.transition(path.exit())
.attr("transform", t1)
.attr("d", d1)
.remove();
// Stash the new scales.
this.__chart__ = {x: x1, y: y1, t: t1, id: id};
});
}
horizon.bands = function(_) {
if (!arguments.length) return bands;
bands = +_;
color.domain([-bands, 0, bands]);
return horizon;
};
horizon.mode = function(_) {
if (!arguments.length) return mode;
mode = _ + "";
return horizon;
};
horizon.colors = function(_) {
if (!arguments.length) return color.range();
color.range(_);
return horizon;
};
horizon.interpolate = function(_) {
if (!arguments.length) return interpolate;
interpolate = _ + "";
return horizon;
};
horizon.x = function(_) {
if (!arguments.length) return x;
x = _;
return horizon;
};
horizon.y = function(_) {
if (!arguments.length) return y;
y = _;
return horizon;
};
horizon.width = function(_) {
if (!arguments.length) return width;
width = +_;
return horizon;
};
horizon.height = function(_) {
if (!arguments.length) return height;
height = +_;
return horizon;
};
horizon.colors = function(_) {
if (!arguments.length) return color.range();
color.range(_);
return horizon;
};
return horizon;
};
var d3_horizonArea = d3.svg.area(),
d3_horizonId = 0;
function d3_horizonX(d) { return d[0]; }
function d3_horizonY(d) { return d[1]; }
function d3_horizonTransform(bands, h, mode) {
return 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 + ")"; };
}
})();
// change the second number to affect the values.
// the first number is used for the x-axis, it should be numbers in order
// play with j to see what happens when you skip x values
var j = 0
var data = [
[3,2],
[4,3],
[5,4],
[6, 10],
[7,20],
[8,33],
[9,5],
[10+j,6],
[11+j,7],
[12+j,14],
[13+j,12],
[14+j,22],
[15+j,13],
[16+j,14]
];
var colors = ["#d727a5", "#ffffff", "#1eb268"];
var width = 400;
var height = 200;
var svg = d3.select("svg");
var chart = d3.horizon()
.width(width)
.height(height)
.bands(8)
.height(height)
.mode("mirror")
.interpolate("step-after")
//.colors(colors);
var g = svg.append("g")
.attr("transform", "translate(" + [ 51, 50 ] +")")
g.append("rect")
.attr({
x: -1,
y: -1,
width: width + 2,
height: height + 2
})
g.datum(data);
chart(g);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment