Built with blockbuilder.org
forked from mdrobinson's block: Radial Bar Demo - Customer Dim
forked from mdrobinson's block: Radial Bar Demo - Customer Dim
forked from mdrobinson's block: Radial Bar Demo - Customer Dim
license: mit | |
height: 800 | |
border: no | |
scrolling: yes |
Built with blockbuilder.org
forked from mdrobinson's block: Radial Bar Demo - Customer Dim
forked from mdrobinson's block: Radial Bar Demo - Customer Dim
forked from mdrobinson's block: Radial Bar Demo - Customer Dim
name | value | category | |
---|---|---|---|
Price | 18 | Low | |
Health | 87 | High | |
Convenience | 62 | Medium | |
Quality | 95 | High | |
Inspiration | 70 | High |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>Customer Dimensions - Dairy</title> | |
<style> | |
body { | |
font: 12px sans-serif; | |
} | |
svg { | |
margin: 0px auto; | |
display: block; | |
} | |
path.arc { | |
opacity: 0.9; | |
transition: opacity 0.5s; | |
} | |
path.arc:hover { | |
opacity: 0.7; | |
} | |
body span { | |
font-size: 18px; | |
font-weight:bold; | |
} | |
.axis line, .axis circle { | |
stroke: #cccccc; | |
stroke-width: 1px | |
} | |
.axis circle { | |
fill: none; | |
} | |
.r.axis text { | |
text-anchor: end | |
} | |
.tooltip { | |
position: absolute; | |
display: none; | |
background: rgba(0, 0, 0, 0.6); | |
border-radius: 3px; | |
box-shadow: -3px 3px 15px #888; | |
color: white; | |
padding: 6px; | |
} | |
rect.High { | |
fill: green; | |
} | |
rect.Medium { | |
fill: blue; | |
} | |
rect.Low { | |
fill: grey; | |
} | |
</style> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
</head> | |
<body> | |
<span>Dairy Customer Dimensions</span> | |
<script> | |
const width = 960, | |
height = 500, | |
chartRadius = height / 2 - 40; | |
let svg = d3.select('body').append('svg') | |
.attr('width', width) | |
.attr('height', height) | |
.append('g') | |
.attr('transform', 'translate(' + width / 2 + ',' + height / 2 + ')'); | |
let tooltip = d3.select('body').append('div') | |
.attr('class', 'tooltip'); | |
const PI = Math.PI, | |
arcMinRadius = 10, | |
arcPadding = 15, | |
labelPadding = -5, | |
numTicks = 10; | |
d3.csv('custDim.csv', (error, data) => { | |
let scale = d3.scaleLinear() | |
.domain([0, d3.max(data, d => d.value) * 1.1]) | |
.range([0, 2 * PI]); | |
let ticks = scale.ticks(numTicks).slice(0, -1); | |
let keys = data.map((d, i) => d.name); | |
//number of arcs | |
const numArcs = keys.length; | |
const arcWidth = (chartRadius - arcMinRadius - numArcs * arcPadding) / numArcs; | |
let arc = d3.arc() | |
.innerRadius((d, i) => getInnerRadius(i)) | |
.outerRadius((d, i) => getOuterRadius(i)) | |
.startAngle(0) | |
.endAngle((d, i) => scale(d)) | |
let axialAxis = svg.append('g') | |
.attr('class', 'a axis') | |
.selectAll('g') | |
.data(ticks) | |
.enter().append('g') | |
.attr('transform', d => 'rotate(' + (rad2deg(scale(d)) - 90) + ')'); | |
axialAxis.append('line') | |
.attr('x2', chartRadius); | |
axialAxis.append('text') | |
.attr('x', chartRadius + 10) | |
.style('text-anchor', d => (scale(d) >= PI && scale(d) < 2 * PI ? 'end' : null)) | |
.attr('transform', d => 'rotate(' + (90 - rad2deg(scale(d))) + ',' + (chartRadius + 10) + ',0)') | |
.text(d => d); | |
//data arcs | |
let arcs = svg.append('g') | |
.attr('class', 'data') | |
.selectAll('path') | |
.data(data) | |
.enter().append('path') | |
.attr('class', 'arc') | |
.style('fill', getBarColor) | |
let radialAxis = svg.append('g') | |
.attr('class', 'r axis') | |
.selectAll('g') | |
.data(data) | |
.enter().append('g'); | |
radialAxis.append('circle') | |
.attr('r', (d, i) => getOuterRadius(i) + arcPadding); | |
renderLegend(); | |
arcs.transition() | |
.delay((d, i) => i * 200) | |
.duration(1000) | |
.attrTween('d', arcTween); | |
radialAxis.append('text') | |
.attr('x', labelPadding) | |
.attr('y', (d, i) => -getOuterRadius(i) + arcPadding) | |
.style("font-weight", "bold") | |
.text(d => d.name); | |
arcs.on('mousemove', showTooltip) | |
arcs.on('mouseout', hideTooltip) | |
function getBarColor(d){ | |
//debugger; | |
var category = d.category; | |
var color = (category == "High") ? ("green") : ((category == "Medium") ? ("blue") : ("grey")); | |
return color; | |
} | |
function arcTween(d, i) { | |
let interpolate = d3.interpolate(0, d.value); | |
return t => arc(interpolate(t), i); | |
} | |
function showTooltip(d) { | |
tooltip.style('left', (d3.event.pageX + 10) + 'px') | |
.style('top', (d3.event.pageY - 25) + 'px') | |
.style('display', 'inline-block') | |
.html("Dairy " + d.name + " Score: " + d.value); | |
} | |
function hideTooltip() { | |
tooltip.style('display', 'none'); | |
} | |
function rad2deg(angle) { | |
return angle * 180 / PI; | |
} | |
function getInnerRadius(index) { | |
return arcMinRadius + (numArcs - (index + 1)) * (arcWidth + arcPadding); | |
} | |
function getOuterRadius(index) { | |
return getInnerRadius(index) + arcWidth; | |
} | |
function renderLegend() { | |
//var self = this; | |
var svg = d3.select("svg"); | |
var containerWidth = d3.select("svg").clientWidth; | |
// config | |
var legendHeight = 200, | |
colorWidth = 15, | |
x = 875, | |
y = 130, | |
data = [{ | |
cssClass: "High", | |
display: "High" // there is no "really good" maximum | |
}, | |
{ | |
cssClass: "Medium", | |
display: "Medium" | |
}, | |
{ | |
cssClass: "Low", | |
display: "Low" | |
} | |
]; | |
// http://jsbin.com/ubafur/3/edit?js,output | |
svg.select("g.legend1").remove(); // cleanup on previous runs | |
var legend = svg | |
.append("g") | |
.attr("class", "legend1"); | |
legend.selectAll('rect') | |
.data(data) | |
.enter() | |
.append("rect") | |
.attr("x", x) | |
.attr("y", function(d, i) { return y + i * (legendHeight / data.length); }) | |
.attr("width", colorWidth) | |
.attr("height", legendHeight / 3) | |
.attr("class", function(d) { return d.cssClass; }) | |
.attr("stroke", "black") | |
.attr("stroke-width", "1px"); | |
legend.selectAll('text') | |
.data(data) | |
.enter() | |
.append("text") | |
.attr("x", x + colorWidth + 6) | |
.attr("y", function(d, i) { return y + i * (legendHeight / (data.length)) + 40}) | |
//{ return y + i * (legendHeight / (data.length + 1)) + 3; } | |
.attr("pointer-events", "none") | |
.attr("font-size", 12) | |
.attr("font-weight", "bold") | |
.attr("font-family", "Helvetica") | |
.text(function(d) { return d.display }); // TODO - prepend or append units of measure | |
legend | |
.append("text") | |
.attr("x", x) | |
.attr("y", y - 7) | |
.attr("pointer-events", "none") | |
.attr("font-size", 12) | |
.attr("font-family", "Helvetica") | |
.attr("font-weight", "bold") | |
.text("Group"); | |
}; | |
}); | |
</script> | |
</body> | |
</html> |