Built with blockbuilder.org
forked from cdagli's block: Scroll Bar Chart
license: mit |
Built with blockbuilder.org
forked from cdagli's block: Scroll Bar Chart
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
svg { | |
font: 10px sans-serif; | |
} | |
.bar { | |
fill: steelblue; | |
clip-path: url(#clip); | |
} | |
.subBar { | |
fill: gray; | |
opacity: 0.5; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.brush .extent { | |
stroke: #fff; | |
fill: steelblue; | |
fill-opacity: .25; | |
shape-rendering: crispEdges; | |
} | |
rect.mover { | |
stroke: red; | |
stroke-opacity: .1; | |
fill: lightSteelBlue; | |
fill-opacity: .5; | |
} | |
</style> | |
<body> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script> | |
var DATA_COUNT = 50; | |
var MAX_LABEL_LENGTH = 30; | |
var data = []; | |
for (var i = 0; i < DATA_COUNT; i++) { | |
var datum = {}; | |
datum.label = stringGen(MAX_LABEL_LENGTH) | |
datum.value = Math.floor(Math.random() * 600); | |
data.push(datum); | |
} | |
function stringGen(maxLength) { | |
var text = ""; | |
var charset = "abcdefghijklmnopqrstuvwxyz0123456789"; | |
for( var i=0; i < getRandomArbitrary(1, maxLength) ; i++ ) { | |
text += charset.charAt(Math.floor(Math.random() * charset.length)); | |
} | |
return text; | |
} | |
function getRandomArbitrary(min, max) { | |
return Math.round(Math.random() * (max - min) + min); | |
} | |
var margin = {top: 20, right: 10, bottom: 20, left: 40}; | |
var marginOverview = {top: 30, right: 10, bottom: 20, left: 40}; | |
var selectorHeight = 40; | |
var width = 600 - margin.left - margin.right; | |
var height = 400 - margin.top - margin.bottom - selectorHeight; | |
var heightOverview = 80 - marginOverview.top - marginOverview.bottom; | |
var maxLength = d3.max(data.map(function(d){ return d.label.length})) | |
var barWidth = maxLength * 7; | |
var numBars = Math.round(width/barWidth); | |
var isScrollDisplayed = barWidth * data.length > width; | |
console.log(isScrollDisplayed) | |
var xscale = d3.scale.ordinal() | |
.domain(data.slice(0,numBars).map(function (d) { return d.label; })) | |
.rangeBands([0, width], .2); | |
var yscale = d3.scale.linear() | |
.domain([0, d3.max(data, function (d) { return d.value; })]) | |
.range([height, 0]); | |
var xAxis = d3.svg.axis().scale(xscale).orient("bottom"); | |
var yAxis = d3.svg.axis().scale(yscale).orient("left"); | |
var svg = d3.select("body").append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom + selectorHeight); | |
var diagram = svg.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
diagram.append("g") | |
.attr("class", "x axis") | |
.attr("transform", "translate(0, " + height + ")") | |
.call(xAxis); | |
diagram.append("g") | |
.attr("class", "y axis") | |
.call(yAxis); | |
var bars = diagram.append("g"); | |
bars.selectAll("rect") | |
.data(data.slice(0, numBars), function (d) {return d.label; }) | |
.enter().append("rect") | |
.attr("class", "bar") | |
.attr("x", function (d) { return xscale(d.label); }) | |
.attr("y", function (d) { return yscale(d.value); }) | |
.attr("width", xscale.rangeBand()) | |
.attr("height", function (d) { return height - yscale(d.value); }); | |
if (isScrollDisplayed) | |
{ | |
var xOverview = d3.scale.ordinal() | |
.domain(data.map(function (d) { return d.label; })) | |
.rangeBands([0, width], .2); | |
yOverview = d3.scale.linear().range([heightOverview, 0]); | |
yOverview.domain(yscale.domain()); | |
var subBars = diagram.selectAll('.subBar') | |
.data(data) | |
subBars.enter().append("rect") | |
.classed('subBar', true) | |
.attr({ | |
height: function(d) { | |
return heightOverview - yOverview(d.value); | |
}, | |
width: function(d) { | |
return xOverview.rangeBand() | |
}, | |
x: function(d) { | |
return xOverview(d.label); | |
}, | |
y: function(d) { | |
return height + heightOverview + yOverview(d.value) | |
} | |
}) | |
var displayed = d3.scale.quantize() | |
.domain([0, width]) | |
.range(d3.range(data.length)); | |
diagram.append("rect") | |
.attr("transform", "translate(0, " + (height + margin.bottom) + ")") | |
.attr("class", "mover") | |
.attr("x", 0) | |
.attr("y", 0) | |
.attr("height", selectorHeight) | |
.attr("width", Math.round(parseFloat(numBars * width)/data.length)) | |
.attr("pointer-events", "all") | |
.attr("cursor", "ew-resize") | |
.call(d3.behavior.drag().on("drag", display)); | |
} | |
function display () { | |
var x = parseInt(d3.select(this).attr("x")), | |
nx = x + d3.event.dx, | |
w = parseInt(d3.select(this).attr("width")), | |
f, nf, new_data, rects; | |
if ( nx < 0 || nx + w > width ) return; | |
d3.select(this).attr("x", nx); | |
f = displayed(x); | |
nf = displayed(nx); | |
if ( f === nf ) return; | |
new_data = data.slice(nf, nf + numBars); | |
xscale.domain(new_data.map(function (d) { return d.label; })); | |
diagram.select(".x.axis").call(xAxis); | |
rects = bars.selectAll("rect") | |
.data(new_data, function (d) {return d.label; }); | |
rects.attr("x", function (d) { return xscale(d.label); }); | |
// rects.attr("transform", function(d) { return "translate(" + xscale(d.label) + ",0)"; }) | |
rects.enter().append("rect") | |
.attr("class", "bar") | |
.attr("x", function (d) { return xscale(d.label); }) | |
.attr("y", function (d) { return yscale(d.value); }) | |
.attr("width", xscale.rangeBand()) | |
.attr("height", function (d) { return height - yscale(d.value); }); | |
rects.exit().remove(); | |
}; | |
</script> |