|
readme(document.getElementById("readme")); |
|
|
|
var chartElem = d3.select("body #chart"); |
|
|
|
var yAxisLabel = ["Median Monthly Rent (€)", "Average Monthly Rent (€)", "Number available"]; |
|
var currSym = ['€','€','',], fmt = d3.format(',f'); |
|
var statMetas = [ |
|
[ {n: "MedApt1", d: "1-bed Apt", c: "A"}, |
|
{n: "MedApt2", d: "2-bed Apt", c: "A"}, |
|
{n: "MedApt3", d: "3-bed Apt", c: "A"}, |
|
{n: "MedHse2", d: "2-bed Hse", c: "H"}, |
|
{n: "MedHse3", d: "3-bed Hse", c: "H"} ], |
|
[ {n: "AvgApt1", d: "1-bed Apt", c: "A"}, |
|
{n: "AvgApt2", d: "2-bed Apt", c: "A"}, |
|
{n: "AvgApt3", d: "3-bed Apt", c: "A"}, |
|
{n: "AvgHse2", d: "2-bed Hse", c: "H"}, |
|
{n: "AvgHse3", d: "3-bed Hse", c: "H"} ], |
|
[ {n: "VolApt", d: "Aptment", c: "A"}, |
|
{n: "VolHse", d: "House", c: "H"}, |
|
{n: "VolTot", d: "Total", c: "H"} ]]; |
|
|
|
|
|
//Pop up tip when floating over marker |
|
var dateFmt = d3.time.format("%d-%b-%Y"); |
|
var tip = d3.tip().attr('class', 'd3-tip').offset([ -10, 0 ]).html( |
|
function(d) { |
|
// Include value in tip |
|
var s = "<span class='h'>" + dateFmt(d.date) + ":</span> <span class='v'>" + |
|
currSym[selectedStat] + fmt(d.value) + "</span>"; |
|
return s; |
|
}); |
|
|
|
|
|
var margin = { |
|
top : 20, |
|
right : 80, |
|
bottom : 60, |
|
left : 40 |
|
}, |
|
width = 960 - margin.left - margin.right, |
|
height = 500 - margin.top - margin.bottom; |
|
|
|
// Set the ranges |
|
var x = d3.time.scale().range([0, width]); |
|
var y = d3.scale.linear().range([height, 0]); |
|
|
|
// Define the axes |
|
var xAxis = d3.svg.axis().scale(x) |
|
.orient("bottom").ticks(6).tickFormat(d3.time.format("%d-%b")) |
|
.tickSize(-height, 0, 0); |
|
|
|
var xAxis2 = d3.svg.axis().scale(x) |
|
.orient("bottom").ticks(d3.time.years, 1) |
|
.tickFormat(d3.time.format("%Y")).tickSize(5,0); |
|
|
|
|
|
var yAxis = d3.svg.axis().scale(y) |
|
.orient("left").ticks(5) |
|
.tickSize(-width, 0, 0); |
|
|
|
var color = d3.scale.category10(); |
|
|
|
var sheet = extractGistData(gistData["DaftData.csv"].content); |
|
var allStats = mungeData(sheet); |
|
d3.select("#lastupdate").html(sheet.rowName.replace("X","").replace(/_/g, "-")); |
|
|
|
var selectedStat = parseParamWithDefault('s',['median','average','volume']); |
|
document.selS.selS[selectedStat].checked = true; |
|
doSvg(); |
|
|
|
/** |
|
* Selection changed - remove and redo graph |
|
*/ |
|
function selStat(s) { |
|
selectedStat = s; |
|
d3.select("svg").remove(); |
|
doSvg(); |
|
} |
|
|
|
|
|
function doSvg() { |
|
|
|
var statMeta = statMetas[selectedStat]; |
|
var statNames = statMeta.map(function (d) {return d.n}); |
|
var data = allStats.filter(function (d) {return statNames.indexOf(d.name) > -1;}); |
|
var isApt = function(d) {return statMeta[statNames.indexOf(d)].c=="A";}; |
|
color.domain(statNames); |
|
|
|
// Adds the svg canvas |
|
var svg = chartElem.append("svg") |
|
.attr("width", width + margin.left + margin.right) |
|
.attr("height", height + margin.top + margin.bottom) |
|
.call(tip) |
|
.append("g") |
|
.attr("transform", |
|
"translate(" + margin.left + "," + margin.top + ")"); |
|
|
|
// Scale the range of the data |
|
x.domain([d3.min(data, function(d) { return d3.min(d.values, function(v){return v.date;})}), |
|
d3.max(data, function(d) { return d3.max(d.values, function(v){return v.date;})})]); |
|
y.domain([d3.min(data, function(d) { return d3.min(d.values, function(v){return v.value;})}), |
|
d3.max(data, function(d) { return d3.max(d.values, function(v){return v.value;})})]); |
|
|
|
// Add the X Axis |
|
svg.append("g") |
|
.attr("class", "x axis") |
|
.attr("transform", "translate(0," + height + ")") |
|
.call(xAxis) |
|
.selectAll("text") |
|
.style("text-anchor", "end") |
|
.attr("dx", "1.8em") |
|
.attr("dy", "1.15em") |
|
.attr("transform", "rotate(-0)" ); |
|
|
|
svg.append("g") |
|
.attr("class", "x axis2") |
|
.attr("transform", "translate(0," + (height+25) + ")") |
|
.call(xAxis2); |
|
|
|
// Add the Y Axis |
|
svg.append("g") |
|
.attr("class", "y axis") |
|
.call(yAxis).append("text") |
|
.attr("transform", "rotate(-90)").attr("y", 6).attr("dy", |
|
".71em").style("text-anchor", "end").text(yAxisLabel[selectedStat]); |
|
|
|
// Define the line |
|
var valueline = d3.svg.line() |
|
.x(function(d) { return x(d.date); }) |
|
.y(function(d) { return y(d.value); }); |
|
|
|
var series = svg.selectAll(".series").data(data).enter() |
|
.append("g").attr("class", "series"); |
|
|
|
series.append("path") |
|
.attr("class", "line") |
|
.attr("d", function(d) { return valueline(d.values); }) |
|
.style({stroke: function(d) {return color(d.name);}}); |
|
|
|
series.append("text") |
|
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; }) |
|
.attr("transform", function(d) {return "translate(" + x(d.value.date) + "," + |
|
(y(d.value.value)+(isApt(d.name)? 12 : -12)) + ")"; }) |
|
.attr("x", 6) |
|
.attr("dy", ".35em") |
|
.style({fill: function(d) {return color(d.name);}}) |
|
.text(function(d) { return statMeta[statNames.indexOf(d.name)].d; }); |
|
|
|
series.append("g").selectAll('.marker') |
|
.data(function (d){return d.values}).enter() |
|
.append(function(v) { |
|
var elem; |
|
if (isApt(v.name)) { |
|
elem = document.createElementNS("http://www.w3.org/2000/svg", "circle"); |
|
elem.setAttribute("r", 5); |
|
} else { |
|
elem = document.createElementNS("http://www.w3.org/2000/svg", "rect"); |
|
elem.setAttribute("width", 10); |
|
elem.setAttribute("height", 10); |
|
} |
|
return elem; |
|
}) |
|
.attr("class", "marker") |
|
.style({fill: function(v) {return color(v.name);}}) |
|
.attr("transform", function(v) { return "translate(" + (x(v.date)+(isApt(v.name)?0:-5)) + |
|
"," + (y(v.value)+(isApt(v.name)?0:-5)) + ")"; }) |
|
.on('mouseover', tip.show).on('mouseout', tip.hide);; |
|
|
|
} |
|
|
|
|
|
function mungeData(sheet) { |
|
|
|
// Parse the date / time |
|
var parseDate = d3.time.format("%Y%m%d").parse; |
|
|
|
var values = sheet.colNames.map(function(name) { |
|
return { |
|
name : name, |
|
values : sheet.data.map(function(d) { |
|
return { |
|
name : name, |
|
date : parseDate(d[sheet.rowName]), |
|
value : +d[name].replace(',','') |
|
}; |
|
}) |
|
}; |
|
}); |
|
values.push( |
|
{name: "VolTot", values: sheet.data.map(function(d) { |
|
return { |
|
name: "VolTot", |
|
date : parseDate(d[sheet.rowName]), |
|
value : (+d.VolHse.replace(',','')) + (+d.VolApt.replace(',','')) |
|
};})}); |
|
|
|
|
|
return values; |
|
|
|
} |
|
|