|
(function() { |
|
'use strict'; |
|
|
|
//************************************************************ |
|
// Set up variables |
|
//************************************************************ |
|
|
|
var data = []; |
|
var items = 9; // data items (used by slider) |
|
|
|
function addData(n) { |
|
for (var i=0; i<=n; i++) { |
|
data.push({value: _.random(10,200), ref: i+1}); |
|
} |
|
} |
|
|
|
var dataReference = []; |
|
|
|
var n = 0, // set initial value |
|
w = 800, // width |
|
h = 200; // height |
|
|
|
var c20 = d3.scale.category20(); |
|
|
|
// add yScale |
|
var yScale = d3.scale.linear() |
|
.domain([0, 200]) |
|
.range([h, 0]); |
|
|
|
|
|
|
|
// ----------------------------- |
|
|
|
function createLines(selection) { |
|
|
|
selection |
|
.append('line') |
|
.attr({ |
|
x1: function(d, i) { return i *20 +10; }, |
|
y1: function(d) { return yScale(d.value); }, |
|
x2: function(d, i) { return i *20 +10; }, |
|
y2: yScale(0), |
|
id: function(d,i) { return 'line-' + i; }, |
|
class: 'line' |
|
}) |
|
.style({ |
|
'stroke-width': 5, |
|
stroke: function(d,i) { |
|
if (i < 10) { |
|
return c20(i); |
|
} else { |
|
var j = i % 20; |
|
return c20(j); |
|
} |
|
} |
|
}) |
|
.on('mouseover', function(d,i) { |
|
// move legend on mouse over |
|
moveLegend('li-' + i); |
|
// update n for the buttons |
|
n = i; |
|
}); |
|
} |
|
|
|
|
|
var svg = d3.select('#chart') |
|
.append('svg') |
|
.attr({ |
|
width: w, |
|
height: h |
|
}); |
|
|
|
|
|
//************************************************************ |
|
// Legend |
|
//************************************************************ |
|
|
|
function renderLegend(data) { |
|
|
|
// create legend |
|
var legend = d3.eesur.legend() |
|
.dataKeys(dataReference); |
|
|
|
// event to update yScale when toggling line series |
|
legend.on('toggleLegend', function(d, i) { |
|
|
|
// console.log('toggleLegend: ' + d, i); |
|
// reference line via it's id |
|
var line = d3.select('#line-' + i); |
|
// reference legend item via it's ID e.g. 'li-0', 'li-1' etc |
|
var liID = 'li-' + i; |
|
|
|
// toggle item in array |
|
if (line.classed('legend-active')) { |
|
|
|
// toggle line |
|
line |
|
.style('opacity', 1) |
|
.classed('legend-active', false); |
|
// toggle legend item |
|
d3.select('#' + liID).style('opacity', 1); |
|
|
|
} else { |
|
|
|
// fade line |
|
line |
|
.style('opacity', 0.2) |
|
.classed('legend-active', true); |
|
// fade legend item |
|
d3.select('#' + liID).style('opacity', 0.2); |
|
} |
|
|
|
}); |
|
|
|
|
|
d3.select('#legend-list') |
|
.call(legend); |
|
} |
|
|
|
|
|
//************************************************************ |
|
// navigation for legend |
|
//************************************************************ |
|
|
|
|
|
var legendNavContainer = d3.select('#legend'); |
|
|
|
function addLegendNav() { |
|
legendNavContainer |
|
.append('button') |
|
.attr({ |
|
class: 'legendNav', |
|
id: 'legendPrev' |
|
}) |
|
.html('‹'); |
|
|
|
legendNavContainer |
|
.append('button') |
|
.attr({ |
|
class: 'legendNav', |
|
id: 'legendNext' |
|
}) |
|
.html('›'); |
|
} |
|
|
|
// controls to navigate back and forward |
|
function legendControls(data, index) { |
|
|
|
var nextBtn = d3.select('#legendNext'); |
|
var prevBtn = d3.select('#legendPrev'); |
|
|
|
d3.select('#legendNext').on('click', function() { |
|
// ensure buttons can't be clicked where there are no items |
|
if (n < data.length-4) { |
|
// ensure buttons are 'visually' active |
|
nextBtn.style('opacity', 1); |
|
prevBtn.style('opacity', 1); |
|
// update value of counter |
|
n++; |
|
// set index to the value of i |
|
index = n; |
|
console.log('value of i NEXT: ' + n); |
|
moveLegend('li-' + index); |
|
} else { |
|
// set n to be value not including the visible legend items |
|
// so that the prev button can be clicked with staggering |
|
n = data.length-4; |
|
// fade button out for user feedback |
|
nextBtn.style('opacity', 0.2); |
|
} |
|
}); |
|
|
|
d3.select('#legendPrev').on('click', function() { |
|
if (n >= 1) { |
|
prevBtn.style('opacity', 1); |
|
nextBtn.style('opacity', 1); |
|
n--; |
|
index = n; |
|
console.log('value of i PREV: ' + n); |
|
moveLegend('li-' + index); |
|
} else { |
|
prevBtn.style('opacity', 0.2); |
|
} |
|
}); |
|
|
|
} |
|
|
|
// offset items in list via their id |
|
function moveLegend(reference) { |
|
|
|
var list = document.getElementById('legend-list'), |
|
targetLi = document.getElementById(reference); // id tag of the <li> element |
|
|
|
list.scrollLeft = (targetLi.offsetLeft - 80); |
|
|
|
console.log(reference + ': ' +targetLi.offsetLeft); |
|
} |
|
|
|
|
|
// ----------------------------- |
|
// render |
|
function render(newDataAmount) { |
|
|
|
// remove old items |
|
d3.selectAll('.line').remove(); |
|
d3.selectAll('.legendNav').remove(); |
|
d3.select('#legend-list').remove(); |
|
|
|
// update data |
|
data = []; |
|
addData(items); |
|
|
|
// give some fake key values to the dummy data |
|
dataReference = data.map(function(d, i) { |
|
return 'bar ' + i; |
|
}); |
|
|
|
// create the lines |
|
var lines = svg.selectAll('line') |
|
.data(data) |
|
.enter() |
|
.call(createLines); |
|
|
|
// create legend |
|
renderLegend(data); |
|
|
|
// only show the controls if needed |
|
if (data.length > 4) { |
|
addLegendNav(); |
|
legendControls(dataReference, 1); |
|
} |
|
} |
|
|
|
|
|
render(items); |
|
|
|
// ----------------------------- |
|
// slider code to change number of data items/lines |
|
// https://github.com/turban/d3.slider |
|
|
|
// ensure slider text is showing current render values |
|
d3.select('#slider-text-items').text(items); |
|
|
|
// update items |
|
d3.select('#slider-items').call(d3.slider().value(items).min(0).max(40).on('slide', function(evt, value) { |
|
items = d3.round(value); // ensure whole number |
|
d3.select('#slider-text-items').text(items + 1); // update the text to show value |
|
|
|
render(items); // update with new amount of items |
|
|
|
})); |
|
|
|
|
|
|
|
})(); |