Testing legend with scroll for an overtly long legend. Test has simple fade out of lines on click of legend item, and moves the legend on roll over of bar lines. Use the slider to increase/decrease the lines and keys in legend.
Created
June 19, 2015 13:28
-
-
Save eesur/008ec2fc3d587e883e02 to your computer and use it in GitHub Desktop.
d3 | legend scroll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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 | |
})); | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="utf-8"> | |
<title>d3 legend | scrollable legend</title> | |
<meta name="author" content="Sundar Singh | eesur.com"> | |
<link rel="stylesheet" type="text/css" href="https://rawgit.com/turban/d3.slider/master/d3.slider.css"> | |
<link rel="stylesheet" href="main.css"> | |
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> | |
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.9.3/lodash.min.js"></script> | |
</head> | |
<body> | |
<header> | |
<p>Crazy test for when legend has to many items for viewport. Next and Prev buttons will only show if over four items/lines</p> | |
<p>Number of items: <span id="slider-text-items">9</span></p> | |
<div id="slider-items"></div> | |
</header> | |
<section id="container"> | |
<section id="chart"></section> | |
<aside id="legend"></aside> | |
</section> | |
<script src="https://rawgit.com/turban/d3.slider/master/d3.slider.js"></script> | |
<script src="legend_component.js" charset="utf-8"></script> | |
<script src="d3_code_legend.js" charset="utf-8"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
'use strict'; | |
d3.eesur = {}; // namespace | |
d3.eesur.legend = function() { | |
var container = 'legend', // ID of DIV container | |
list = 'legend-list', // ID for UL | |
dataKeys = []; // array of key values from JSON data | |
var dispatch = d3.dispatch('toggleLegend'); | |
var c20 = d3.scale.category20(); | |
var legend = function() { | |
// ensure container is visible | |
d3.select('#' + container).transition().duration(1000).style('opacity', 1); | |
var legend = d3.select('#' + container + ' ul'); | |
// create legend container if doesn't exist | |
if (legend.empty()) { | |
legend = d3.select('#' + container) | |
.attr('class', 'legend_wrap'); | |
legend | |
.append('ul') | |
.attr('id', list); | |
// add the legend items | |
var legendList = d3.select('#' + list) | |
.selectAll('li') | |
.data(dataKeys); | |
legendList | |
.enter() | |
.append('li') | |
.attr('class', 'legend-item') | |
.attr('id', function(d, i) { | |
return 'li-' + i; | |
}) | |
.on('click', function(d,i) { | |
return dispatch.toggleLegend(d, i); | |
}); | |
legendList.append('span') | |
.attr('class', 'legend-line') | |
.style('color', function(d,i) { return c20(i); }) | |
.html('— '); | |
legendList.append('span') | |
.attr('class', 'legend-title') | |
.style('color', '#7AC143;') | |
.html(function(d, i) { return dataKeys[i]; }); | |
} | |
}; | |
legend.container = function(value) { | |
if (!arguments.length) return container; | |
container = value; | |
return this; | |
}; | |
legend.list = function(value) { | |
if (!arguments.length) return list; | |
list = value; | |
return this; | |
}; | |
legend.dataKeys = function(value) { | |
if (!arguments.length) return dataKeys; | |
dataKeys = value; | |
return this; | |
}; | |
d3.rebind(legend, dispatch, 'on'); | |
return legend; | |
}; | |
}()); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@import url(http://fonts.googleapis.com/css?family=Source+Code+Pro:400,600); | |
html, body { | |
height: 100%; | |
} | |
body { | |
font-family: "Source Code Pro", Consolas, monaco, monospace; | |
line-height: 1.5; | |
font-weight: 400; | |
background-color: #130C0E; | |
color: #7AC143; | |
padding: 10px; | |
} | |
p { | |
max-width: 600px; | |
} | |
button { | |
font-family: "Source Code Pro", Consolas, monaco, monospace; | |
font-size: 14px; | |
background: #130C0E; | |
color: #FDBB30; | |
border: none; | |
outline:none; | |
padding: 4px 8px; | |
letter-spacing: 1px; | |
} | |
button:hover { | |
color: #EE3124; | |
} | |
#container { | |
text-align: center; | |
white-space: nowrap; | |
width: 800px; | |
margin: 0 auto; | |
margin-top: 20px; | |
} | |
#chart { | |
height: 200px; | |
margin-bottom: 40px; | |
} | |
.legendNav { | |
font-size: 24px; | |
display: inline-block; | |
} | |
.legendNav:hover { | |
font-weight: bold; | |
} | |
#legendPrev { | |
position: absolute; | |
left: 20px; | |
top: -10px; | |
} | |
#legendNext { | |
position: absolute; | |
right: 20px; | |
top: -10px; | |
} | |
.legend-group{ | |
display: inline-block; | |
width: 100px; | |
} | |
#legend { | |
position: relative; | |
padding-top: 5px; | |
font-size: 13px; | |
bottom: 5px; | |
text-align: left; | |
padding: 0px; | |
} | |
#legend ul { | |
list-style: none; | |
text-align: center; | |
height: 24px; | |
padding-left: 0; | |
min-width: 300px; | |
max-width: 640px; | |
margin: 0 auto; | |
overflow: hidden; | |
} | |
#legend li { | |
padding-right: 0; | |
cursor: pointer; | |
font-size: 13px; | |
display: inline-block; | |
width: 160px; | |
overflow: hidden; | |
letter-spacing: 1px; | |
} | |
#legend li span { | |
padding: 2px 4px; | |
pointer-events: none; | |
} | |
.legend-line { | |
margin-left: 8px; | |
vertical-align: right; | |
font-size: 14px; | |
line-height: 13px; | |
} | |
#slider-items, #slider-rows { | |
margin: 10px 0; | |
max-width: 300px; | |
} | |
.d3-slider { | |
border: 1px solid #7AC143; | |
} | |
.d3-slider-handle { | |
border: none; | |
background: #7AC143; | |
} | |
.d3-slider-handle:hover { | |
border: 1px solid #7AC143; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment