index.html
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<style>
svg {
width: 960px;
height: 500px;
border: 1px solid gray;
}
.table {
width: 960px;
height: 500px;
overflow: scroll;
}
.axis {
font-size: 10px;
}
.axis path {
fill: none;
stroke: #000000;
}
.axis .tick line {
stroke: #000;
}
</style>
</head>
<body>
<svg></svg>
<div id="display"></div>
<script src="//d3js.org/d3.v3.js"></script>
<script src="table.js"></script>
<script src="scatter.js"></script>
<script src="brush.js"></script>
<script src="histogram.js"></script>
<script>
var display = d3.select("#display");
d3.json("pics.json", function(err, pics) {
var data = pics.data.children;
data.forEach(function(d) {
d.data.created *= 1000;
})
console.log(data);
var display = d3.select("#display")
var tdiv = display.append("div").classed("table", true)
var table = d3.chart.table()
table.data(data)
table(tdiv);
var svg = d3.select("svg")
var sgroup = svg.append("g")
.attr("transform", "translate(50, 0)")
var scatter = d3.chart.scatter()
scatter.data(data)
scatter(sgroup)
var hgroup = svg.append("g")
.attr("transform", "translate(450, 0)")
var histogram = d3.chart.histogram()
histogram.data(data)
histogram(hgroup)
var bgroup = svg.append("g")
.attr("transform", "translate(100, 430)")
var brush = d3.chart.brush()
brush
.data(data)
.width(800)
brush(bgroup)
brush.on("filter", function(filtered) {
console.log("filtered", filtered);
scatter.data(filtered);
scatter.update();
table.data(filtered)
table.update();
histogram.data(filtered)
histogram.update();
})
table.on("hover", function(hovered) {
scatter.highlight(hovered)
brush.highlight(hovered)
})
scatter.on("hover", function(hovered) {
table.highlight(hovered)
brush.highlight(hovered)
})
histogram.on("hover", function(hovered) {
table.highlight(hovered)
scatter.highlight(hovered)
brush.highlight(hovered)
})
})
</script>
</body>
</html>
brush.js
if(!d3.chart) d3.chart = {};
d3.chart.brush = function() {
var g;
var data;
var width = 600;
var height = 30;
var dispatch = d3.dispatch(chart, "filter");
function chart(container) {
g = container;
var extent = d3.extent(data, function(d) {
return d.data.created
})
var scale = d3.time.scale()
.domain(extent)
.range([0, width])
var brush = d3.svg.brush()
brush.x(scale)
brush(g)
g.selectAll("rect").attr("height", height)
g.selectAll(".background")
.style({fill: "#4B9E9E", visibility: "visible"})
g.selectAll(".extent")
.style({fill: "#78C5C5", visibility: "visible"})
g.selectAll(".resize rect")
.style({fill: "#276C86", visibility: "visible"})
var rects = g.selectAll("rect.events")
.data(data)
rects.enter()
.append("rect").classed("events", true)
rects.attr({
x: function(d) { return scale(d.data.created);},
y: 0,
width: 1,
height: height
}).style("pointer-events", "none")
rects.exit().remove()
brush.on("brushend", function() {
var ext = brush.extent()
var filtered = data.filter(function(d) {
return (d.data.created > ext[0] && d.data.created < ext[1])
})
g.selectAll("rect.events")
.style("stroke", "")
g.selectAll("rect.events")
.data(filtered, function(d) { return d.data.id })
.style({
stroke: "#fff"
})
dispatch.filter(filtered)
})
var axis = d3.svg.axis()
.scale(scale)
.orient("bottom")
.tickValues([new Date(extent[0]), new Date(extent[0] + (extent[1] - extent[0])/2) , new Date(extent[1])])
.tickFormat(d3.time.format("%x %H:%M"))
var agroup = g.append("g")
agroup.attr("transform", "translate(" + [0, height] + ")")
axis(agroup)
agroup.selectAll("path")
.style({ fill: "none", stroke: "#000"})
agroup.selectAll("line")
.style({ stroke: "#000"})
}
chart.highlight = function(data) {
var rects = g.selectAll("rect.events")
.style("stroke", "")
.style("stroke-width", "")
rects.data(data, function(d) { return d.data.id })
.style("stroke", "orange")
.style("stroke-width", 3)
}
chart.data = function(value) {
if(!arguments.length) return data;
data = value;
return chart;
}
chart.width = function(value) {
if(!arguments.length) return width;
width = value;
return chart;
}
chart.height = function(value) {
if(!arguments.length) return height;
height = value;
return chart;
}
return d3.rebind(chart, dispatch, "on");
}
histogram.js
if(!d3.chart) d3.chart = {};
d3.chart.histogram = function() {
var g;
var data;
var width = 400;
var height = 400;
var cx = 10;
var numberBins = 5;
var dispatch = d3.dispatch(chart, "hover");
function chart(container) {
g = container;
update();
}
chart.update = update;
function update() {
var hist = d3.layout.histogram()
.value(function(d) { return d.data.score })
.range([0, d3.max(data, function(d){ return d.data.score }) ])
.bins(numberBins);
var layout = hist(data);
var maxLength = d3.max(layout, function(d) { return d.length });
var widthScale = d3.scale.linear()
.domain([0, maxLength])
.range([0, width])
var yScale = d3.scale.ordinal()
.domain(d3.range(numberBins))
.rangeBands([height, 0], 0.1)
var colorScale = d3.scale.category20();
var rects = g.selectAll("rect")
.data(layout)
rects.enter().append("rect")
rects
.transition()
.attr({
y: function(d,i) {
return yScale(i)
},
x: 50,
height: yScale.rangeBand(),
width: function(d,i) {
return widthScale(d.length)
},
fill: function(d, i) { return colorScale(i) }
})
rects.exit().transition().remove();
rects.on("mouseover", function(d) {
d3.select(this).style("fill", "orange")
console.log("hist over", d)
dispatch.hover(d)
})
rects.on("mouseout", function(d) {
d3.select(this).style("fill", "")
dispatch.hover([])
})
}
chart.data = function(value) {
if(!arguments.length) return data;
data = value;
return chart;
}
chart.width = function(value) {
if(!arguments.length) return width;
width = value;
return chart;
}
chart.height = function(value) {
if(!arguments.length) return height;
height = value;
return chart;
}
return d3.rebind(chart, dispatch, "on");
}
scatter.js
if(!d3.chart) d3.chart = {};
d3.chart.scatter = function() {
var g;
var data;
var width = 400;
var height = 400;
var cx = 10;
var numberBins = 5;
var dispatch = d3.dispatch(chart, "hover");
function chart(container) {
g = container;
g.append("g")
.classed("xaxis", true)
g.append("g")
.classed("yaxis", true)
update();
}
chart.update = update;
function update() {
var maxCreated = d3.max(data, function(d) { return d.data.created });
var minCreated = d3.min(data, function(d) { return d.data.created });
var maxScore = d3.max(data, function(d) { return d.data.score })
var colorScale = d3.scale.category20();
var createdScale = d3.time.scale()
.domain([minCreated, maxCreated])
.range([cx, width])
var commentScale = d3.scale.linear()
.domain(d3.extent(data, function(d) { return d.data.num_comments }))
.range([3, 15])
var yScale = d3.scale.linear()
.domain([0, maxScore])
.range([height, cx])
var xAxis = d3.svg.axis()
.scale(createdScale)
.ticks(3)
.tickFormat(d3.time.format("%x %H:%M"))
var yAxis = d3.svg.axis()
.scale(yScale)
.ticks(3)
.orient("left")
var xg = g.select(".xaxis")
.classed("axis", true)
.attr("transform", "translate(" + [0,height] + ")")
.transition()
.call(xAxis)
var yg = g.select(".yaxis")
.classed("axis", true)
.classed("yaxis", true)
.attr("transform", "translate(" + [cx - 5,0] + ")")
.transition()
.call(yAxis)
var circles = g.selectAll("circle")
.data(data, function(d) { return d.data.id })
circles.enter()
.append("circle")
circles
.transition()
.attr({
cx: function(d,i) { return createdScale(d.data.created) },
cy: function(d,i) { return yScale(d.data.score) },
r: function(d) { return commentScale(d.data.num_comments)}
})
circles.exit().remove()
circles.on("mouseover", function(d) {
d3.select(this).style("stroke", "black")
dispatch.hover([d])
})
circles.on("mouseout", function(d) {
d3.select(this).style("stroke", "")
dispatch.hover([])
})
var hist = d3.layout.histogram()
.value(function(d) { return d.data.score })
.range([0, d3.max(data, function(d){ return d.data.score }) ])
.bins(numberBins);
var layout = hist(data);
for(var i = 0; i < layout.length; i++) {
var bin = layout[i];
g.selectAll("circle")
.data(bin, function(d) { return d.data.id })
.style("fill", function() { return colorScale(i) })
}
}
chart.highlight = function(data) {
var circles = g.selectAll("circle")
.style("stroke", "")
circles.data(data, function(d) { return d.data.id })
.style("stroke", "orange")
.style("stroke-width", 3)
}
chart.data = function(value) {
if(!arguments.length) return data;
data = value;
return chart;
}
chart.width = function(value) {
if(!arguments.length) return width;
width = value;
return chart;
}
chart.height = function(value) {
if(!arguments.length) return height;
height = value;
return chart;
}
return d3.rebind(chart, dispatch, "on");
}
table.js
if(!d3.chart) d3.chart = {};
d3.chart.table = function() {
var div;
var data;
var width;
var dispatch = d3.dispatch(chart, "hover");
function chart(container) {
div = container;
var table = container.append("table")
update();
}
chart.update = update;
function update() {
var table = div.select("table")
var rows = table.selectAll("tr.row")
.data(data, function(d) { return d.data.id })
console.log("table data", data)
rows.exit().remove();
var rowsEnter = rows.enter()
.append("tr").classed("row", true)
rowsEnter.append("td")
.text(function(d) { return d.data.score })
rowsEnter.append("td")
.append("a")
.attr({
href: function(d) { return d.data.url }
})
.append("img")
.attr({
src: function(d) { return d.data.thumbnail }
})
rowsEnter.append("td")
.append("a")
.attr({
href: function(d) { return d.data.url }
}).text(function(d) { return d.data.title })
rowsEnter.append("td")
.text(function(d) { return d.data.ups })
rowsEnter.append("td")
.text(function(d) { return d.data.downs })
rowsEnter.on("mouseover", function(d) {
d3.select(this).style("background-color", "orange")
dispatch.hover([d])
})
rowsEnter.on("mouseout", function(d) {
d3.select(this).style("background-color", "")
dispatch.hover([])
})
}
chart.highlight = function(data) {
var trs = div.selectAll("tr")
.style("background-color", "")
trs.data(data, function(d) { return d.data.id })
.style("background-color", "orange")
}
chart.data = function(value) {
if(!arguments.length) return data;
data = value;
return chart;
}
chart.width = function(value) {
if(!arguments.length) return width;
width = value;
return chart;
}
return d3.rebind(chart, dispatch, "on");
}