Built with blockbuilder.org
Last active
January 23, 2018 13:43
-
-
Save cdagli/d43de46aff4313a90005794ab0a30c1d to your computer and use it in GitHub Desktop.
fresh block
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
license: mit |
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> | |
<head> | |
<meta charset="utf-8"> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<style> | |
.bar { | |
fill: steelblue; | |
} | |
.subBar{ | |
fill: steelblue; | |
} | |
.axis text { | |
font: 10px sans-serif; | |
user-select: none; | |
} | |
.axis path, | |
.axis line { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
.x.axis path { | |
display: none; | |
} | |
rect.mover { | |
fill: lightSteelBlue; | |
fill-opacity: .5; | |
} | |
.brush .extent { | |
stroke: #fff; | |
fill-opacity: .125; | |
shape-rendering: crispEdges; | |
} | |
.tooltip { | |
position: absolute; | |
pointer-events: none; | |
padding: 12px; | |
background: white; | |
border: 1px solid gray; | |
border-radius: 4px; | |
} | |
.tooltip-name | |
{ | |
text-align: center; | |
color: steelblue; | |
} | |
.tooltip-value | |
{ | |
text-align: left; | |
margin-top: 5px; | |
} | |
</style> | |
</head> | |
<body> | |
<!DOCTYPE html> | |
<script> | |
var DATA_COUNT = 66; | |
var MAX_LABEL_LENGTH = 10; | |
var MIN_LABEL_LENGTH = 50; | |
var MAX_LABEL_LENGTH_ALLOWED = 27; | |
var MARGIN_MODIFIER_CONSTANT = 4; | |
var BAR_WIDTH = 20; | |
var BAR_PADDING = 5; | |
var data = []; | |
for (var i = 0; i < DATA_COUNT; i++) { | |
var datum = {}; | |
var plusOrMinus = Math.random() < 0.5 ? -1 : 1; | |
datum.name = stringGen(MIN_LABEL_LENGTH, MAX_LABEL_LENGTH); | |
datum.value = Math.floor(Math.random() * 600 * plusOrMinus); | |
data.push(datum); | |
} | |
function stringGen(minLength, maxLength) { | |
var text = ""; | |
var charset = "abcdefghijklmnopqrstuvwxyz0123456789"; | |
for (var i = 0; i < getRandomArbitrary(minLength, 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 maxLabelLength =d3.max(data.map(function(d){ return d.name.length})); | |
var marginModifier = maxLabelLength < MAX_LABEL_LENGTH_ALLOWED ? maxLabelLength : MAX_LABEL_LENGTH_ALLOWED; | |
var margin = { | |
top: 50, | |
right: 30, | |
bottom: 40 + marginModifier * MARGIN_MODIFIER_CONSTANT, | |
left: 80 | |
}; | |
var marginOverview = { | |
top: 50 + marginModifier * MARGIN_MODIFIER_CONSTANT, | |
right: 30, | |
bottom: 0, | |
left: 30 | |
}; | |
var width = 650 - margin.left - margin.right; | |
var heightOverview = 75; | |
var height = 550 - margin.top - margin.bottom; | |
var barWidth = width / data.length; | |
var overviewVisible = true; | |
if (barWidth > BAR_WIDTH) { | |
BAR_WIDTH = barWidth * 90 / 100; | |
BAR_PADDING = barWidth * 10 / 100; | |
overviewVisible = false; | |
} | |
var x = d3.scale.ordinal() | |
.domain(data.map(function(d) { | |
return d.name; | |
})) | |
.range(data.map(function(d, i) { | |
return i * (BAR_WIDTH + BAR_PADDING); | |
})); | |
var y = d3.scale.linear() | |
.domain([d3.min(data, function(d) { | |
return d.value; | |
}), Math.abs(d3.max(data, function(d) { | |
return d.value; | |
}))]) | |
.range([height, 0]).nice(); | |
var xAxis = d3.svg.axis() | |
.scale(x) | |
.orient("bottom") | |
var yAxis = d3.svg.axis() | |
.scale(y) | |
.orient("left"); | |
var svg = d3.select("body") | |
.append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom + heightOverview + marginOverview.top + marginOverview.bottom); | |
var chart = svg.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var defs = chart.append("defs"); | |
defs.append("clipPath").attr('id', 'chart-clip-path').append('rect') | |
.attr('width', width) //Set the width of the clipping area | |
.attr('height', height); // set the height of the clipping area | |
defs.append("clipPath").attr('id', 'x-axis-clip-path').append('rect') | |
.attr('width', width) //Set the width of the clipping area | |
.attr('height', height + margin.bottom); // set the height of the clipping area | |
var barsGroup = chart.append('g'); | |
barsGroup.attr('clip-path', 'url(#chart-clip-path)'); | |
var xAxisGroup = chart.append("g").attr('class', 'x-axis') | |
xAxisGroup.append('g') | |
.attr("class", "x axis") | |
.attr("transform", "translate(" + (BAR_WIDTH + BAR_PADDING) / 2 + "," + height + ")") | |
.call(xAxis) | |
.selectAll("text") | |
.attr("y", 10) | |
.attr("x", -10) | |
.attr("dy", 0) | |
.attr("transform", "rotate(-60)") | |
.style("text-anchor", "end") | |
.text(function (d) { | |
if(d.length > MAX_LABEL_LENGTH_ALLOWED) | |
return d.substring(0,MAX_LABEL_LENGTH_ALLOWED)+'...'; | |
else | |
return d; | |
}); | |
xAxisGroup.attr('clip-path', 'url(#x-axis-clip-path)'); | |
var yAxisGroup = chart.append("g").attr("class", "y axis") | |
yAxisGroup.call(yAxis); | |
var div = d3.select("body") | |
.append("div") | |
.attr("class", "tooltip") | |
.style("opacity", 0); | |
var bars = barsGroup.selectAll(".bar") | |
.data(data) | |
.enter().append("rect") | |
.attr("class", "bar") | |
.attr("x", function(d) { | |
return x(d.name); | |
}) | |
.attr("y", function(d) { | |
return d.value > 0 ? y(d.value) : y(0); | |
}) | |
.attr("height", function(d) { | |
return Math.abs(y(d.value) - y(0)); | |
}) | |
.attr("width", BAR_WIDTH) | |
.on("mouseenter", function(d) { | |
div.style("opacity", .9); | |
div.html('<div class="tooltip-name">' + d.name + '</div><div class="tooltip-value">Value:' + d.value + '</div>') | |
.style("left", (d3.event.pageX + 25) + "px") | |
.style("top", (d3.event.pageY - 25) + "px"); | |
}) | |
.on("mouseleave", function(d) { | |
div.style("opacity", 0); | |
}); | |
var xAxisLabel = chart.append("text") | |
.attr("text-anchor", "middle") // this makes it easy to centre the text as the transform is applied to the anchor | |
.attr("transform", "translate("+ (width/2) +","+(height + marginOverview.top )+")") // centre below axis | |
.text("Name"); | |
var yAxisLabel = chart.append("text") | |
.attr("text-anchor", "middle") // this makes it easy to centre the text as the transform is applied to the anchor | |
.attr("transform", "translate("+ -margin.left / 2 +","+(height/2)+")rotate(-90)") // text is drawn off the screen top left, move down and out and rotate | |
.text("Value"); | |
if (overviewVisible) { | |
var zoom = d3.behavior.zoom().scaleExtent([1, 1]); | |
// var zoomRect = chart.append("rect") | |
// .attr("width", width) | |
// .attr("height", height) | |
// .attr("fill", "none") | |
// .attr("pointer-events", "all") | |
// .call(zoom); | |
var xOverview = d3.scale.ordinal() | |
.domain(data.map(function(d) { | |
return d.name; | |
})) | |
.rangeBands([0, width], BAR_PADDING / BAR_WIDTH, 0); | |
var yOverview = d3.scale.linear().range([heightOverview, 0]); | |
yOverview.domain(y.domain()); | |
var overviewGroup = chart.append('g') | |
.attr('width', width) | |
.attr('height', heightOverview); | |
var subBars = overviewGroup.append('g').selectAll('.subBar') | |
.data(data) | |
subBars.enter().append("rect") | |
.classed('subBar', true) | |
.attr({ | |
height: function(d) { | |
return Math.abs(yOverview(d.value) - yOverview(0)); | |
}, | |
width: function(d) { | |
return xOverview.rangeBand() | |
}, | |
x: function(d) { | |
return xOverview(d.name); | |
}, | |
y: function(d) { | |
return height + marginOverview.top + (d.value > 0 ? yOverview(d.value) : yOverview(0)); | |
} | |
}); | |
var overviewRect = overviewGroup.append('rect') | |
.attr('y', height + marginOverview.top) | |
.attr('width', width) | |
.attr('height', heightOverview) | |
.style("opacity", "0") | |
.style("cursor", "pointer").on("click", click); | |
var selectorWidth = (width / (BAR_WIDTH) * (xOverview.rangeBand())); | |
var selector = chart.append("rect") | |
.attr("class", "mover") | |
.attr("x", 0) | |
.attr("y", height + marginOverview.top) | |
.attr("height", heightOverview) | |
.attr("width", selectorWidth) | |
.attr("pointer-events", "all") | |
.attr("cursor", "ew-resize") | |
.call(d3.behavior.drag().on("drag", drag)); | |
} | |
function click() { | |
var newX = null; | |
var selectorX = null; | |
var customScale = d3.scale.linear().domain([0, width]).range([0, ((BAR_WIDTH + BAR_PADDING) * data.length)]) | |
selectorX = (d3.event.x - marginOverview.left) - selectorWidth / 2; | |
newX = customScale(selectorX); | |
if (selectorX > width - selectorWidth) { | |
newX = customScale(width - selectorWidth); | |
selectorX = width - selectorWidth; | |
} else if (selectorX - (selectorWidth / 2) < 0) { | |
newX = 0; | |
selectorX = 0 | |
} | |
selector.transition().attr("x", selectorX) | |
bars.transition().duration(300).attr("transform", "translate(" + (-newX) + ",0)"); | |
chart.transition().duration(300).select(".x.axis").attr("transform", "translate(" + -(newX - (BAR_WIDTH + BAR_PADDING) / 2) + "," + (height) + ")"); | |
chart.select(".y.axis").call(yAxis); | |
var transformX = (-(d3.event.x - selectorWidth) * ((BAR_WIDTH + BAR_PADDING) * data.length) / width); | |
zoom.translate([-newX, 0]) | |
} | |
// function zoomed() { | |
// var t = zoom.translate(), | |
// tx = t[0], | |
// ty = t[1]; | |
// var xEndValue = x(data[data.length - 1].name) - (width) + (BAR_WIDTH + BAR_PADDING) + BAR_WIDTH / 2; | |
// if (tx <= 0 && tx > -xEndValue) { | |
// bars.attr("transform", "translate(" + d3.event.translate[0] + ",0)"); | |
// chart.select(".x.axis").attr("transform", "translate(" + (d3.event.translate[0] + (BAR_WIDTH + BAR_PADDING) / 2) + "," + (height) + ")"); | |
// chart.select(".y.axis").call(yAxis); | |
// var selectorX = Math.abs(width * tx / ((BAR_WIDTH + BAR_PADDING) * data.length)) | |
// selector.attr("x", selectorX) | |
// } | |
// if (tx < -xEndValue) { | |
// zoom.translate([-xEndValue, ty]) | |
// } | |
// if (tx >= 0) { | |
// zoom.translate([0, ty]) | |
// } | |
// } | |
function drag() { | |
var nx = d3.event.dx; | |
var t = zoom.translate(), | |
tx = t[0], | |
ty = t[1]; | |
var selectorX = parseFloat(selector.attr("x")) + nx | |
var customScale = d3.scale.linear().domain([0, width]).range([0, ((BAR_WIDTH + BAR_PADDING) * data.length)]) | |
var transformX = customScale(selectorX) | |
var xEndValue = customScale(xOverview(data[data.length - 1].name)) - customScale(selectorWidth) + BAR_WIDTH | |
if (transformX < xEndValue && transformX >= 0) { | |
selector.attr("x", selectorX) | |
bars.attr("transform", "translate(" + -transformX + ",0)"); | |
chart.select(".x.axis").attr("transform", "translate(" + (-transformX + (BAR_WIDTH + BAR_PADDING) / 2) + "," + (height) + ")"); | |
chart.select(".y.axis").call(yAxis); | |
zoom.translate([transformX, 0]) | |
} | |
} | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment