Skip to content

Instantly share code, notes, and snippets.

@bcowgill
Last active February 7, 2016 12:47
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 bcowgill/f246703b2443ae62081e to your computer and use it in GitHub Desktop.
Save bcowgill/f246703b2443ae62081e to your computer and use it in GitHub Desktop.
Weight Chart
var svg, view, xscale, yscale, yheight, data, max, Target, points, seriesDelay,
WIDTH = 1024,
HEIGHT = 768,
MARGINW = 10,
MARGINH = 10,
LABELH = 32,
TARGET_SIZE = MARGINW * 0.75,
DELAY = 300,
DURATION = 1000,
OFFSCREEN = 2,
DATA = [{
started: "2016-01-01",
who: "brent",
color: "blue",
border: "limegreen",
textColor: "white",
target: -2.2 * 7,
weight: [192, 193, 189.8, 188.8, 190, 186.8]
}, {
who: "velda",
color: "pink",
border: "red",
textColor: "red",
target: 105,
weight: [111.8, 111, 110.4, 109.6, 109.2, 108.8]
}];
Target = [{
who: DATA[0].who,
color: DATA[0].color,
goalColor: DATA[0].color,
currentWeight: DATA[0].weight[DATA[0].weight.length - 1],
weight: DATA[0].weight[0] + DATA[0].target },
{
who: DATA[1].who,
color: DATA[1].color,
goalColor: DATA[1].color,
currentWeight: DATA[1].weight[DATA[1].weight.length - 1],
weight: DATA[1].target
}];
function setGoalColor(targetData)
{
targetData.goalColor = targetData.currentWeight > targetData.weight ? "red" : "#00ff00";
}
setGoalColor(Target[0]);
setGoalColor(Target[1]);
function exit(d3Sel) {
d3Sel.transition().duration(DURATION)
.attr("opacity", 0)
.each("end", function () {
d3.select(this).remove();
});
}
svg = d3.select("body")
.append("svg")
.attr({
"width": WIDTH + 2 * MARGINW,
"height": HEIGHT + 2 * MARGINH
});
view = svg.append("svg:g")
.classed("transform", true)
.attr("transform", "translate(" + MARGINW + " " + MARGINH + ")");
view.append("svg:rect")
.classed("background", true)
.attr({
"x": 0,
"y": 0,
"width": WIDTH,
"height": HEIGHT,
"fill": "black",
"stroke": "none",
"stroke-width": 0,
"opacity": 0.1
});
max = d3.max([d3.max(DATA[0].weight), d3.max(DATA[1].weight)]);
points = d3.max([DATA[0].weight.length, DATA[1].weight.length]);
console.log("max", max);
console.log("points", points);
seriesDelay = DELAY * points / 2;
xscale = d3.scale.ordinal().domain(d3.range(points)).rangeRoundBands([0, WIDTH], 0.1);
console.log("X0", xscale(0));
console.log("X1", xscale(1));
console.log("w", xscale.rangeBand());
yscale = d3.scale.linear().domain([0, max]).range([HEIGHT, 0]);
yheight = d3.scale.linear().domain([0, max]).range([0, HEIGHT]);
console.log("Ymin", yscale(0));
console.log("Ymax", yscale(max));
function targetPath(x, y) {
return "M" + x + " " + y + " l" + TARGET_SIZE / 2 + " -" + TARGET_SIZE / 2 + " l0 " + TARGET_SIZE + " z";
}
function renderData(data, delay) {
var update = view.selectAll("rect.weight." + data.who).data(data.weight);
update.enter().append("svg:rect").classed("weight", true).classed(data.who, true)
.attr({
"x": -xscale(OFFSCREEN),
"y": yscale(max),
"width": xscale.rangeBand(),
"height": yheight(max),
"opacity": 0.3,
"fill": "salmon",
"stroke": "salmon",
"stroke-width": 0.5
});
update.transition()
.duration(DURATION)
.delay(function (datum, idx) {
return delay + idx * DELAY;
})
.ease("elastic", 1, 1.5)
.attr({
"x": function (datum, idx) {
return xscale(idx);
},
"y": function (datum) {
return yscale(datum);
},
"width": xscale.rangeBand(),
"height": function (datum) {
return yheight(datum);
},
"opacity": 1,
"fill": data.color,
"stroke": data.border,
"stroke-width": 0.5
});
exit(update.exit());
update = view.selectAll("text.label." + data.who).data(data.weight);
update.enter().append("svg:text").classed("label", true).classed(data.who, true).attr({
"x": -xscale(OFFSCREEN) + xscale.rangeBand() / 2,
"y": yscale(max) + LABELH,
"opacity": 1,
"fill": "black",
"stroke": "black",
"stroke-width": 0.5,
"font-size": LABELH + "px"
})
.text(function (datum) {
return datum;
});
update.transition()
.duration(DURATION)
.delay(function (datum, idx) {
return delay + idx * DELAY;
})
.ease("elastic", 1, 1.5)
.attr({
"x": function (datum, idx) {
return xscale(idx) + xscale.rangeBand() / 2;
},
"y": function (datum) {
return yscale(datum) + LABELH;
},
"opacity": 1,
"fill": data.textColor,
"stroke": data.textColor,
"stroke-width": 0.5,
"font-size": LABELH + "px"
});
exit(update.exit());
}
function renderTargets(Target) {
console.dir(Target);
var targetX = WIDTH, update = view.selectAll('path.target').data(Target);
update.enter().append("svg:path")
.classed("target", true)
.attr({
"d": targetPath(targetX, yscale(0)),
"opacity": 0.3,
"fill": "salmon",
"stroke": "salmon",
"stroke-width": 0.5
})
.each(function (datum) {
d3.select(this).classed(datum.who, true);
});
update.transition()
.duration(DELAY * points + DURATION)
.delay(function (datum, idx) {
return idx * seriesDelay;
})
.ease("elastic", 1, 1.5)
.attr({
"d": function (datum) {
return targetPath(targetX, yscale(datum.weight));
},
"opacity": 1,
"fill": function (datum) { return datum.goalColor; },
"stroke": function (datum) { return datum.color; },
"stroke-width": 0.5
});
exit(update.exit());
}
renderData(DATA[0], 0);
renderData(DATA[1], seriesDelay);
renderTargets(Target);
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
body {
background: black;
}
svg {
border: 1px solid black;
}
text.label {
font-family: sans;
text-anchor: middle;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment