Skip to content

Instantly share code, notes, and snippets.

@queuebit
Last active November 29, 2016 05:28
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 queuebit/99f55f57624b6db17ad7367d776700a3 to your computer and use it in GitHub Desktop.
Save queuebit/99f55f57624b6db17ad7367d776700a3 to your computer and use it in GitHub Desktop.
<DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.dot {
stroke: #000;
}
.overlay {
fill: none;
pointer-events: all;
}
.tracking line {
stroke-dasharray: 5,5;
stroke: red;
}
.tooltip {
position: absolute;
width: 200px;
height: 28px;
pointer-events: none;
}
</style>
<body>
<!-- #hattip - http://bl.ocks.org/mbostock/3902569 -->
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/d3-timer.v1.min.js"></script>
<script>
d3.select("body")
.on("keydown", function () {
if (d3.event.keyCode === 74) {
updatePlayback(-5);
console.log('j - back 5 frames');
} else if (d3.event.keyCode === 75) {
updatePlayback(0);
console.log('k - play/pause');
} else if (d3.event.keyCode === 76) {
updatePlayback(5);
console.log('l - fwd 5 frames');
} else if (d3.event.keyCode === 188) {
updatePlayback(-1);
console.log('< - back 1 frame');
} else if (d3.event.keyCode === 190) {
updatePlayback(1);
console.log('> - fwd 1 frames');
} else if (d3.event.keyCode === 82) {
updatePlayback(-fs.length);
console.log('r - restart');
} else if (d3.event.keyCode === 72) {
console.log('j - back 5 frames');
console.log('l - fwd 5 frames');
console.log('k - play/pause');
console.log('< - back 1 frame');
console.log('> - fwd 1 frames');
console.log('r - restart');
} else {
console.log(d3.event.keyCode);
}
});
var tooltip = d3.select("body").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var tracking = svg.append("g")
.attr("class", "tracking");
var pX = tracking.append("line")
.attr("x1", 0).attr("x2", 0)
.attr("y1", 0).attr("y2", height)
var pY = tracking.append("line")
.attr("x1", 0).attr("x2", width)
.attr("y1", 0).attr("y2", 0)
svg.append("g")
.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() { tracking.style("display", null); })
.on("mouseout", function() {
tracking.style("display", "none");
updateCoords(0,0);
})
.on("mousemove", function() {
var [mx, my] = d3.mouse(this);
updateCoords(mx, my);
})
var data;
var frames;
var fs;
var fi;
var f;
var t;
var dot;
var paused = false;
d3.json("frames.json", function(error, json) {
if (error) return console.warn(error);
frames = json;
fs = Object.keys(frames).sort();
fi = 0;
f = fs[fi];
data = frames[f];
data.forEach(function(d) {
d.x = +d.x;
d.y = +d.y;
});
//x.domain(d3.extent(data, function(d) { return d.x; })).nice();
//y.domain(d3.extent(data, function(d) { return d.y; })).nice();
x.domain([0,300])
y.domain([350,600])
svg.append("text")
.attr("class", "frame")
.attr("x", width - 50)
.attr("y", 40)
.text(f);
svg.append("text")
.attr("class", "coords")
.attr("x", 30)
.attr("y", height - 10)
.text("0, 0");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("class", "label")
.attr("x", width)
.attr("y", -6)
.style("text-anchor", "end")
.text("x");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("class", "label")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("y")
t = d3.interval(updateFrame, 10);
});
function updateFrame(elapsed) {
var svg = d3.select("body > svg");
if (!paused) fi++;
if (fi < 0) {
fi = 0;
} else if (fi >= fs.length) {
t.stop();
return;
}
f = fs[fi];
data = frames[f];
svg.select('text.frame')
.text(f);
dot = svg.selectAll(".dot")
.data(data, function (d) { return d.eid; });
dot.exit().remove();
dot.enter().append("circle")
.attr("class", "dot")
.attr("r", 2)
.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); })
.on("mouseover", function(d) {
tooltip.transition()
.duration(100)
.style("opacity", .9);
tooltip.html(d.eid)
.style("left", (d3.event.pageX + 5) + "px")
.style("top", (d3.event.pageY - 10) + "px");
})
.on("mouseout", function(d) {
tooltip.transition()
.duration(200)
.style("opacity", 0);
});
dot.attr("cx", function(d) { return x(d.x); })
.attr("cy", function(d) { return y(d.y); });
}
function updateCoords(mx, my) {
var svg = d3.select("body > svg");
pX.transition()
.duration(10)
.attr("x1", mx).attr("x2", mx)
pY.transition()
.duration(10)
.attr("y1", my).attr("y2", my)
svg.select('text.coords')
.text(x.invert(mx).toFixed(0) + ", " + y.invert(my).toFixed(0));
}
function updatePlayback(frameDelta) {
if (frameDelta === 0) {
paused = !paused;
} else {
paused = true;
fi += frameDelta;
}
}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment