// ***************************************** // reusable slopegraph chart // ***************************************** (function() { 'use strict'; d3.eesur.slopegraph = function module() { // input vars for getter setters var w = 600, h = 800, margin = {top: 40, bottom: 40, left: 100, right: 100}, strokeColour = 'black', // key data values start for left(axis) and end for right(axis) keyValueStart = '', keyValueEnd = '', // key value (used for ref/titles) keyName = '', format = d3.format(''); var dispatch = d3.dispatch('_hover'); function exports(_selection) { _selection.each(function(data) { // format/clean data data.forEach(function(d) { d[keyValueStart] = +d[keyValueStart]; d[keyValueEnd] = +d[keyValueEnd]; }); // get max value(s) for y scale var keyValueStartMax = d3.max(data, function (d) { return d[keyValueStart]; } ); var keyValueEndMax = d3.max(data, function (d) { return d[keyValueEnd]; } ); // use same scale for both sides var yScale = d3.scale.linear() .domain([0, d3.max([keyValueStartMax, keyValueEndMax])]) .range([h - margin.top, margin.bottom]); var svg = d3.select(this).append('svg') .attr({ width: w, height: h }); var lines = svg.selectAll('line') .data(data); lines.enter().append('line') .attr({ x1: margin.left, x2: w - margin.right, y1: function(d) { return yScale(d[keyValueStart]); }, y2: function(d) { return yScale(d[keyValueEnd]); }, stroke: strokeColour, 'stroke-width': 1, class: function (d, i) { return 's-line elm ' + 'sel-' + i; } }) .on('mouseover', dispatch._hover); var rightLabels = svg.selectAll('.labels') .data(data); rightLabels.enter().append('text') .attr({ class: function (d, i) { return 'r-labels elm ' + 'sel-' + i; }, x: w - margin.right + 3, y: function(d) { return yScale(d[keyValueEnd]) + 4; }, }) .text(function (d) { return d[keyName] + ' ' + format(d[keyValueEnd]); }) .style('text-anchor','start') .on('mouseover', dispatch._hover); var leftLabels = svg.selectAll('.left-labels') .data(data); leftLabels.enter().append('text') .attr({ class: function (d, i) { return 'l-labels elm ' + 'sel-' + i; }, x: margin.left - 3, y: function(d) { return yScale(d[keyValueStart]) + 4; } }) .text(function (d) { return d[keyName] + ' ' + format(d[keyValueStart]); }) .style('text-anchor','end') .on('mouseover', dispatch._hover); var leftTitle = svg.append('text') .attr({ class: 's-title', x: margin.left - 3, y: margin.top/2 }) .text(keyValueStart + ' ↓') .style('text-anchor','end'); var rightTitle = svg.append('text') .attr({ class: 's-title', x: w - margin.right + 3, y: margin.top/2 }) .text('↓ ' + keyValueEnd) .style('text-anchor','start'); }); } // getter/setters for overrides exports.w = function(value) { if (!arguments.length) return w; w = value; return this; }; exports.h = function(value) { if (!arguments.length) return h; h = value; return this; }; exports.margin = function(value) { if (!arguments.length) return margin; margin = value; return this; }; exports.strokeColour = function(value) { if (!arguments.length) return strokeColour; strokeColour = value; return this; }; exports.keyValueStart = function(value) { if (!arguments.length) return keyValueStart; keyValueStart = value; return this; }; exports.keyValueEnd = function(value) { if (!arguments.length) return keyValueEnd; keyValueEnd = value; return this; }; exports.keyName = function(value) { if (!arguments.length) return keyName; keyName = value; return this; }; exports.format = function(value) { if (!arguments.length) return format; format = value; return this; }; d3.rebind(exports, dispatch, 'on'); return exports; }; }());