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> |