|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
|
|
.axis--y path { |
|
display: none; |
|
} |
|
|
|
.sites { |
|
fill: none; |
|
stroke-linejoin: round; |
|
stroke-linecap: round; |
|
stroke-width: 1.5px; |
|
} |
|
|
|
.focus text { |
|
text-anchor: middle; |
|
text-shadow: 0 1px 0 #fff, 1px 0 0 #fff, 0 -1px 0 #fff, -1px 0 0 #fff; |
|
} |
|
|
|
.voronoi path { |
|
fill: none; |
|
pointer-events: all; |
|
} |
|
|
|
.voronoi--show path { |
|
stroke: red; |
|
stroke-opacity: 0.2; |
|
} |
|
|
|
#form { |
|
position: absolute; |
|
top: 20px; |
|
right: 30px; |
|
} |
|
|
|
</style> |
|
<svg width="1160" height="600"></svg> |
|
<label id="form" for="show-voronoi"> |
|
Show Voronoi |
|
<input type="checkbox" id="show-voronoi" disabled> |
|
</label> |
|
<script src="https://d3js.org/d3.v4.min.js"></script> |
|
<script> |
|
|
|
var months, |
|
monthKeys, |
|
monthParse = d3.timeParse("%Y-%m"); |
|
var steps, |
|
stepKeys; |
|
|
|
var svg = d3.select("svg"), |
|
margin = {top: 20, right: 30, bottom: 110, left: 40}, |
|
width = svg.attr("width") - margin.left - margin.right, |
|
height = svg.attr("height") - margin.top - margin.bottom, |
|
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); |
|
|
|
var xScale = d3.scaleBand() |
|
.rangeRound([0, width]) |
|
.paddingInner(0.9); |
|
|
|
var yScale = d3.scaleLinear() |
|
.range([height, 0]); |
|
|
|
var zScale = d3.scaleOrdinal(d3.schemeCategory10); |
|
|
|
var voronoi = d3.voronoi() |
|
.x(function(d) { return xScale(d.step); }) |
|
.y(function(d) { return yScale(d.value); }) |
|
.extent([[-margin.left, -margin.top], [width + margin.right, height + margin.bottom]]); |
|
|
|
var line = d3.line() |
|
.x(function(d) { return xScale(d.step); }) |
|
.y(function(d) { return yScale(d.value); }) |
|
.curve(d3.curveMonotoneX); |
|
|
|
d3.csv("datanorth2_fullset.csv", type, function(error, data) { |
|
if (error) throw error; |
|
|
|
xScale.domain(data.columns.slice(1)); |
|
yScale.domain([0, 5500]); |
|
//x.domain(d3.extent(months)); |
|
//y.domain([0, d3.max(data, function(c) { return d3.max(c.values, function(d) { return //d.value; }); })]).nice(); |
|
zScale.domain(data.map(function(d) { return d.origin; })) |
|
|
|
var xAxis = d3.axisBottom(xScale); |
|
|
|
var xAxisDraw = g.append("g") |
|
.attr("class", "axis axis--x") |
|
.attr("transform", "translate(0," + height + ")") |
|
.call(xAxis); |
|
xAxisDraw |
|
// .call(xAxis) |
|
.selectAll("text") |
|
.style("text-anchor", "end") |
|
.attr("dx", "-.8em") |
|
.attr("dy", ".15em") |
|
.attr("transform", function(d) { |
|
return "rotate(-65)" |
|
}); |
|
// g.append("g") |
|
// .attr("class", "axis axis--x") |
|
// .attr("transform", "translate(0," + height + ")") |
|
// .call(d3.axisBottom(xScale)); |
|
|
|
g.append("g") |
|
.attr("class", "axis axis--y") |
|
.call(d3.axisLeft(yScale).ticks(10)) |
|
.append("text") |
|
.attr("x", 4) |
|
.attr("y", 0.5) |
|
.attr("dy", "0.32em") |
|
.style("text-anchor", "start") |
|
.style("fill", "#000") |
|
.style("font-weight", "bold") |
|
.text("Commuters"); |
|
|
|
g.append("g") |
|
.attr("class", "sites") |
|
.selectAll("path") |
|
.data(data) |
|
.enter().append("path") |
|
.attr("d", function(d) { d.line = this; return line(d.values); }) |
|
.style("stroke", function(d) { return zScale(d.origin); }); |
|
|
|
var focus = g.append("g") |
|
.attr("transform", "translate(-100,-100)") |
|
.attr("class", "focus"); |
|
|
|
focus.append("circle") |
|
.attr("r", 3.5); |
|
|
|
focus.append("text") |
|
.attr("y", -10); |
|
|
|
var voronoiGroup = g.append("g") |
|
.attr("class", "voronoi"); |
|
|
|
voronoiGroup.selectAll("path") |
|
.data(voronoi.polygons(d3.merge(data.map(function(d) { return d.values; })))) |
|
.enter().append("path") |
|
.attr("d", function(d) { return d ? "M" + d.join("L") + "Z" : null; }) |
|
.on("mouseover", mouseover) |
|
.on("mouseout", mouseout); |
|
|
|
// data.map(function(d) { return console.log(d)}) |
|
|
|
// console.log(data) |
|
|
|
// console.log(data.map(function(d) { return d.values; })) |
|
|
|
d3.select("#show-voronoi") |
|
.property("disabled", false) |
|
.on("change", function() { voronoiGroup.classed("voronoi--show", this.checked); }); |
|
|
|
function mouseover(d) { |
|
d3.select(d.data.site.line) |
|
.style('stroke-width', 3) |
|
.style('stroke', d3.hsl(zScale(d.data.site.origin)).brighter(1)); |
|
|
|
d.data.site.line.parentNode.appendChild(d.data.site.line); |
|
focus.attr("transform", "translate(" + xScale(d.data.step) + "," + yScale(d.data.value) + ")"); |
|
focus.select("text").text(d.data.site.origin + ': ' + d.data.value); |
|
} |
|
|
|
function mouseout(d) { |
|
d3.select(d.data.site.line) |
|
.style("stroke-width", 1.5) |
|
.style('stroke', zScale(d.data.site.origin)); |
|
focus.attr("transform", "translate(-100,-100)"); |
|
} |
|
}); |
|
|
|
// function type(d, i, columns) { |
|
// if (!months) monthKeys = columns.slice(1), months = monthKeys.map(monthParse); |
|
// var c = {name: d.name.replace(/ (msa|necta div|met necta|met div)$/i, ""), values: |
|
// null}; |
|
// c.values = monthKeys.map(function(k, i) { return {city: c, date: months[i], value: //d[k] / 100}; }); |
|
// return c; |
|
// } |
|
|
|
function type(d, i, columns) { |
|
stepKeys = columns.slice(1); // steps = stepKeys; //.map(); |
|
var c = {origin: d.origin, values: null}; |
|
c.values = stepKeys.map(function(k, i) { return {site: c, step: stepKeys[i], value: d[k]}; }); |
|
return c; |
|
} |
|
|
|
</script> |