Built with blockbuilder.org
forked from tomshanley's block: Horizon bar chart
forked from tomshanley's block: Horizon bar chart v2 (variable bands)
license: mit |
Built with blockbuilder.org
forked from tomshanley's block: Horizon bar chart
forked from tomshanley's block: Horizon bar chart v2 (variable bands)
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
body { | |
font-family: sans-serif; | |
margin: 0; | |
top: 0; | |
right: 0; | |
bottom: 0; | |
left: 0; | |
} | |
rect, | |
line { | |
shape-rendering: crispEdges | |
} | |
</style> | |
</head> | |
<body> | |
<div> | |
<p>Choose number of bands: | |
<select> | |
<option value="1">1</option> | |
<option value="2">2</option> | |
<option value="3">3</option> | |
<option value="4">4</option> | |
<option value="5">5</option> | |
<option value="10">10</option> | |
</select> | |
</p> | |
</div> | |
<div id="horizon"> | |
<h2>Horizon bar chart</h2> | |
</div> | |
<script> | |
const minY = 0; | |
const maxY = 100; | |
var numberOfBands = 4; | |
var bandWidth = (maxY - minY)/(numberOfBands); | |
const height = 80; | |
const width = 800; | |
const margin = { "top": 10, "bottom": 10, "left": 50, "right": 10, }; | |
//used Draw My Data http://www.robertgrantstats.co.uk/drawmydata.html | |
const data = [9.5433, 4.5433, 4.5433, 6.0817, 8.7743, 10.6971, 22.2356, 34.5433, 37.2356, 37.6202, 37.2356, 35.6971, 34.5433, 38.3894, 43.3894, 47.6202, 52.2356, 55.3125, 59.1587, 59.9279, 58.3894, 56.851, 56.0817, 59.5433, 61.851, 64.9279, 67.6202, 69.9279, 69.9279, 68.004, 67.2356, 65.3125, 62.2356, 60.3125, 58.3894, 57.2356, 47.6202, 39.9279, 1.0817, 2.6202, 13.0048, 12.6202, 61.4663, 61.0817, 69.9279, 77.2356, 85.3125, 82.6202, 91.0817, 88.774, 77.6202, 66.0817, 64.5433, 54.5433, 45.3125, 46.4663, 49.9279, 40.6971, 37.6202, 36.0817, 35.3125, 39.5433, 38.774, 57.6202, 50.3125, 16.851, 17.6202, 18.774, 23.774, 58.774, 48.0048, 46.4663, 50.3125]; | |
const barWidth = width / data.length - 1; | |
const xScale = d3.scaleLinear() | |
.domain([0, data.length]) | |
.range([0, width]); | |
var yScaleBar = d3.scaleLinear() | |
.domain([0, maxY]) | |
.range([height, 0]); | |
var colour = d3.scaleLinear() | |
//.domain(d3.extent(data, function (d) { return d })) | |
.domain([0,100]) | |
.range(["yellow", "darkgreen"]); | |
var select = d3.select("select"); | |
select.property("value", numberOfBands); | |
select.on("change", function(d){ | |
var selectedBand = d3.select("select").property("value"); | |
selectedBand = +selectedBand; | |
numberOfBands = selectedBand | |
bandWidth = (maxY - minY)/(numberOfBands); | |
removeExisting(); | |
drawHorizon(data); | |
drawLegend(); | |
}); | |
drawHorizon(data); | |
drawLegend(); | |
function removeExisting() { | |
d3.selectAll("svg").remove(); | |
}; | |
function drawHorizon(data) { | |
let yScale = d3.scaleLinear() | |
.domain([0, bandWidth]) | |
.range([height, 0]); | |
let yAxis = d3.axisLeft(yScale); | |
let svg = d3.select("#horizon").append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
let g = svg.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
let axisG = g.append("g") | |
.call(yAxis) | |
axisG.selectAll("text") | |
.text(function (d) { return "..." + d }); | |
axisG.select(".domain").remove(); | |
let bars = g.selectAll(".bars") | |
.data(data) | |
.enter() | |
.append("g") | |
.attr("transform", function (d, i) { | |
return "translate(" + xScale(i) + ",0)"; | |
}) | |
let backgroundBars = bars.append("rect") | |
.attr("width", barWidth) | |
.attr("height", height) | |
.style("fill", function (d) { | |
return d < bandWidth ? "white" : colour(band(d, bandWidth)); | |
}); | |
let foregroundBars = bars.append("rect") | |
.attr("y", function (d) { | |
let thisHeight = barHeight(d, bandWidth); | |
return yScale(thisHeight); | |
}) | |
.attr("width", barWidth) | |
.attr("height", function (d) { | |
let thisHeight = barHeight(d, bandWidth); | |
return height - yScale(thisHeight); | |
}) | |
.style("fill", function (d) { | |
let thisBand = band(d, bandWidth) + bandWidth; | |
return colour(thisBand); | |
}); | |
/*var caps = bars.append("line") | |
.attr("x1", 0) | |
.attr("x2", barWidth) | |
.attr("y1", function(d){ | |
let thisHeight = barHeight(d, bandWidth); | |
return yScale(thisHeight); | |
}) | |
.attr("y2", function(d){ | |
let thisHeight = barHeight(d, bandWidth); | |
return yScale(thisHeight); | |
}) | |
.style("stroke", "white")*/ | |
}; | |
function drawLegend() { | |
let legendWidth = 25; | |
let legendHeight = legendWidth * numberOfBands; | |
const legendMargin = {"top": 10, "bottom": 10, "left": 25, "right": 150 }; | |
let legend = d3.select("body").append("svg") | |
.attr("width", legendWidth + legendMargin.left + legendMargin.right) | |
.attr("height", legendMargin.top + legendHeight + legendMargin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + legendMargin.left + "," + legendMargin.top + ")"); | |
let legendData = []; | |
let i = 0; | |
for (i; i < numberOfBands; i++) { | |
let datum = (i * bandWidth) + bandWidth; | |
legendData.push(datum) | |
}; | |
console.log(legendData); | |
let legendItems = legend.selectAll("g") | |
.data(legendData) | |
.enter() | |
.append("g") | |
.attr("transform", function(d, j) { | |
return "translate(0," + (j * legendWidth) + ")" | |
}); | |
legendItems.append("rect") | |
.attr("width", legendWidth) | |
.attr("height", legendWidth) | |
.style("fill", function(d) { return colour(d); }) | |
.style("stroke", "white"); | |
legendItems.append("text") | |
.text(function(d){ | |
return (d - bandWidth) + " - " + d; | |
}) | |
.attr("x", legendWidth + 5) | |
.attr("y", legendWidth/2 + 5) | |
}; | |
function band(n, bandWidth) { | |
return Math.floor(n / bandWidth) * bandWidth; | |
}; | |
function barHeight(n, bandWidth) { | |
return n - band(n, bandWidth); | |
}; | |
</script> | |
</body> |