Built with blockbuilder.org
forked from GitNoise's block: donut chart
license: mit |
Built with blockbuilder.org
forked from GitNoise's block: donut chart
<!DOCTYPE html> | |
<head> | |
<meta charset="utf-8"> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script src="//d3js.org/d3-scale-chromatic.v0.3.min.js"></script> | |
<style> | |
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; } | |
svg { | |
} | |
path { | |
stroke: black; | |
} | |
.rim { | |
fill: none; | |
stroke: #000000; | |
stroke-width: 1; | |
stroke-opacity: 0.2; | |
} | |
rect { | |
fill: #000000; | |
fill-opacity: 0.05; | |
stroke: #000000; | |
stroke-opacity: 0.4; | |
stroke-width: 0.5 | |
} | |
line { | |
stroke: #000000; | |
stroke-opacity: 0.5; | |
stroke-dasharray: 10; | |
} | |
.connector { | |
stroke-dasharray: 0; | |
stroke-width: 1; | |
} | |
.dot { | |
r: 4; | |
} | |
.label { | |
position: absolute; | |
font-family: verdana; | |
font-size: 9px; | |
font-weight: bold; | |
text-transform: uppercase; | |
background: rgba(255, 255, 255, 0.6); | |
color: #222222; | |
} | |
path { | |
stroke: none; | |
} | |
</style> | |
</head> | |
<body> | |
<script> | |
var length = 400, | |
circleRadius = 175, | |
iconRadius = 15; | |
function randVal() { | |
const min = - circleRadius/1.66; | |
const max = + circleRadius*1.2; | |
const result = Math.floor(Math.random() * max) + min; | |
return result; | |
} | |
const colorScale = d3.scaleOrdinal(["#FE96BD","#E4A9E0","#B8BEF6","#83D2FA","#55E2EB","#55ECCD","#81F2A6","#B7F382","#EFEE6A" ]); | |
var data = [ | |
{ value: 100 / 9, x: randVal(), y: randVal(), color: colorScale(0) }, | |
{ value: 100 / 9, x: randVal(), y: randVal(), color: colorScale(1)}, | |
{ value: 100 / 9, x: randVal(), y: randVal(), color: colorScale(2)}, | |
{ value: 100 / 9, x: randVal(), y: randVal(), color: colorScale(3)}, | |
{ value: 100 / 9, x: randVal(), y: randVal(), color: colorScale(4)}, | |
{ value: 100 / 9, x: randVal(), y: randVal(), color: colorScale(5)}, | |
{ value: 100 / 9, x: randVal(), y: randVal(), color: colorScale(6)}, | |
{ value: 100 / 9, x: randVal(), y: randVal(), color: colorScale(7)}, | |
{ value: 100 / 9, x: randVal(), y: randVal(), color: colorScale(8)}, | |
]; | |
var pie = d3.pie() | |
.value(function(d) { return d.value; }) | |
.sort(null); | |
var arc = d3.arc() | |
.innerRadius(circleRadius) | |
.outerRadius(circleRadius) | |
.startAngle(d => d.startAngle) | |
.endAngle(d => d.endAngle); | |
var svg = d3.select("body").append("svg") | |
.attr("width", length) | |
.attr("height", length); | |
svg.append("circle") | |
.classed("rim", true) | |
.attr("cx", length/2) | |
.attr("cy", length/2) | |
.attr("r", circleRadius - iconRadius - 4) | |
svg.append("circle") | |
.classed("rim", true) | |
.attr("cx", length/2) | |
.attr("cy", length/2) | |
.attr("r", circleRadius + iconRadius + 4) | |
// chart area | |
svg.append("rect") | |
.attr("x", length/2 - circleRadius/1.66) | |
.attr("y", length/2 - circleRadius/1.66) | |
.attr("width", circleRadius * 1.2) | |
.attr("height", circleRadius * 1.2); | |
// chart crosshair | |
const lineVertical = svg.append("line") | |
.attr("x1", length/2 - circleRadius/1.66) | |
.attr("x2", length/2 + circleRadius/1.66) | |
.attr("y1", length/2) | |
.attr("y2", length/2) | |
const lineHorizontal = svg.append("line") | |
.attr("x2", length/2) | |
.attr("x1", length/2) | |
.attr("y1", length/2 - circleRadius/1.66) | |
.attr("y2", length/2 + circleRadius/1.66) | |
// chart data | |
var slice = svg.append("g") | |
.attr("transform", "translate(" + length/2 + "," + length / 2 + ")") | |
.attr("class", "field") | |
.selectAll(".slice") | |
.data(pie(data)) | |
.enter() | |
.append("g") | |
.classed("slice", true) | |
slice | |
.append("path") | |
.attr("class", "slice path path--background") | |
.attr("d", arc ) | |
d3.selectAll('.slice').each(function(d) { | |
const thisSelect = d3.select(this); | |
const c = arc.centroid(d), | |
x = c[0], | |
y = c[1]; | |
thisSelect.append("line") | |
.classed("connector", true) | |
.attr("x1", x) | |
.attr("y1", y) | |
.attr("x2", d => d.data.x) | |
.attr("y2", d => d.data.y) | |
.style("stroke", d => d.data.color) | |
thisSelect | |
.append("circle") | |
.attr("cx", x) | |
.attr("cy", y) | |
.attr("r", d => iconRadius) | |
.style("fill", d => d.data.color) | |
thisSelect.append("circle") | |
.classed("dot", true) | |
.attr("cx", d => d.data.x) | |
.attr("cy", d => d.data.y) | |
.attr("r", 3) | |
.style("fill", d => d.data.color) | |
}); | |
// labels | |
let compensationBCR = undefined; | |
const margin = 4; | |
const progressive = d3.select("body") | |
.append("div") | |
.classed("label", true) | |
.html("Mer progressiv") | |
compensationBCR = progressive.node().getBoundingClientRect(); | |
progressive | |
.attr("style", | |
`top:${length/2 - circleRadius/1.66 - compensationBCR.height - margin}px; | |
left:${length/2 - compensationBCR.width/2}px`) | |
const conservative = d3.select("body") | |
.append("div") | |
.classed("label", true) | |
.html("Mer konservativ"); | |
compensationBCR = conservative.node().getBoundingClientRect(); | |
conservative | |
.attr("style", | |
`top:${length/2 + circleRadius/1.66 + margin}px; | |
left:${length/2 - compensationBCR.width/2}px`) | |
const left = d3.select("body") | |
.append("div") | |
.classed("label", true) | |
.html("Mer<br/>vänster") | |
compensationBCR = left.node().getBoundingClientRect(); | |
left | |
.attr("style", | |
`top:${length/2 - compensationBCR.height/2}px; | |
left:${length/2 - circleRadius/1.66 - compensationBCR.width - margin}px`) | |
const right = d3.select("body") | |
.append("div") | |
.classed("label", true) | |
.html("Mer<br/>höger") | |
compensationBCR = right.node().getBoundingClientRect(); | |
right | |
.attr("style", | |
`top:${length/2 - compensationBCR.height/2}px; | |
left:${length/2 + circleRadius/1.66 + margin}px`) | |
</script> | |
</body> |