Last active
May 23, 2020 23:12
-
-
Save pjsier/0cd4e2eb3819e50cffea7b70a8c2cd24 to your computer and use it in GitHub Desktop.
Simple Responsive Gauge
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> | |
<html> | |
<head> | |
<title>Simple Gauge Visualization</title> | |
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" /> | |
<meta charset='utf-8' /> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
text { | |
font-family: "Verdana", sans-serif; | |
} | |
#chart { | |
max-width: 500px; | |
} | |
</style> | |
</head> | |
<body> | |
<button id="random">Random Number</button> | |
<div id="chart"></div> | |
<script src="script.js"></script> | |
<script> | |
function randNumberBounds(min, max) { | |
min = Math.ceil(min); | |
max = Math.floor(max); | |
return Math.floor(Math.random() * (max - min)) + min; | |
} | |
(function() { | |
var gauge = gaugeChart() | |
.width(260) | |
.height(200) | |
.innerRadius(50) | |
.outerRadius(80); | |
d3.select("#chart").datum([randNumberBounds(0, 100)]).call(gauge); | |
function resize() { | |
var gWidth = Math.min(d3.select("#chart").node().offsetWidth, 260); | |
gauge.width(gWidth).innerRadius(gWidth / 4).outerRadius((gWidth / 4) + 40); | |
d3.select("#chart").call(gauge); | |
} | |
resize(); | |
window.addEventListener("resize", resize); | |
var button = document.getElementById("random"); | |
button.addEventListener("click", function() { | |
d3.select("#chart").datum([randNumberBounds(0, 100)]).call(gauge); | |
}); | |
})() | |
</script> | |
</body> | |
</html> |
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
// Based on reusable chart pattern from https://bost.ocks.org/mike/chart/ | |
function gaugeChart() { | |
var margin = {top: 0, right: 65, bottom: 10, left: 65}, | |
width = 250, | |
height = 150, | |
arcMin = -Math.PI/2, | |
arcMax = Math.PI/2, | |
innerRadius = 60, | |
outerRadius = 80, | |
dataDomain = [0, 50, 100], | |
labelPad = 10, | |
dataValue = function(d) { return +d; }, | |
colorScale = d3.scaleLinear(), | |
arcScale = d3.scaleLinear(), | |
colorOptions = ["#d7191c", "#efef5d", "#1a9641"], | |
arc = d3.arc(); | |
function chart(selection) { | |
selection.each(function(data) { | |
// Convert data to standard representation greedily; | |
// this is needed for nondeterministic accessors. | |
data = data.map(function(d, i) { return dataValue(d); }); | |
arcScale = d3.scaleLinear().domain(dataDomain).range([arcMin, 0, arcMax]); | |
colorScale = d3.scaleLinear().domain(dataDomain).range(colorOptions); | |
arc = d3.arc().innerRadius(innerRadius) | |
.outerRadius(outerRadius) | |
.startAngle(arcMin); | |
// Select the svg element, if it exists. | |
var svg = d3.select(this).selectAll("svg").data([data]); | |
// Otherwise, create the skeletal chart. | |
var gEnter = svg.enter().append("svg").append("g"); | |
var arcGEnter = gEnter.append("g").attr("class", "arc"); | |
arcGEnter.append("path").attr("class", "bg-arc"); | |
arcGEnter.append("path").attr("class", "data-arc") | |
.datum({endAngle: arcMin, startAngle: arcMin, score: dataDomain[0]}) | |
.attr("d", arc) | |
.style("fill", colorScale(dataDomain[0])) | |
.each(function(d) { this._current = d; }); | |
arcGEnter.append("text").attr("class", "arc-label"); | |
arcGEnter.selectAll(".lines").data(arcScale.ticks(5).map(function(d) { | |
return { score: d }; | |
})).enter() | |
.append("path") | |
.attr("class", "lines"); | |
arcGEnter.selectAll(".ticks").data(arcScale.ticks(5)) | |
.enter().append("text") | |
.attr("class", "ticks"); | |
// Update the outer dimensions. | |
var svg = selection.select("svg"); | |
svg.attr("width", width).attr("height", height); | |
// Update the inner dimensions. | |
var g = svg.select("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
var arcG = svg.select("g.arc") | |
.attr("transform", "translate(" + | |
((width - margin.left - margin.right) / 2) + "," + | |
((height * (2 / 3)) + ")")); | |
svg.select("g.arc .bg-arc") | |
.datum({endAngle: arcMax}) | |
.style("fill", "#ddd") | |
.attr("d", arc); | |
// https://bl.ocks.org/mbostock/1346410 | |
function arcTween(a) { | |
var i = d3.interpolate(this._current, a); | |
this._current = i(0); | |
return function(t) { | |
return arc(i(t)); | |
}; | |
} | |
var dataArc = svg.select("g.arc .data-arc") | |
.datum({score: data[0], startAngle: arcMin, endAngle: arcScale(data[0])}) | |
.transition() | |
.duration(750) | |
.style("fill", function(d) { return colorScale(d.score); }) | |
.style("opacity", function(d) { return d.score < dataDomain[0] ? 0 : 1; }) | |
.attrTween("d", arcTween); | |
var arcBox = svg.select("g.arc .bg-arc").node().getBBox(); | |
svg.select("text.arc-label") | |
.datum({score: data[0]}) | |
.attr("x", (arcBox.width/2)+arcBox.x) | |
.attr("y", -15) | |
.style("alignment-baseline", "central") | |
.style("text-anchor", "middle") | |
.style("font-size", "30px") | |
.text(function(d) { return d3.format(".1f")(d.score); }); | |
var markerLine = d3.radialLine() | |
.angle(function(d) { return arcScale(d); }) | |
.radius(function(d, i) { | |
return innerRadius + ((i % 2) * ((outerRadius - innerRadius))); | |
}); | |
arcG.selectAll(".lines") | |
.attr("d", function(d) { return markerLine([d.score, d.score]); }) | |
.style("fill", "none") | |
.style("stroke-width", 2.5) | |
.style("stroke", "#fff"); | |
arcG.selectAll(".ticks") | |
.style("font-size", "12px") | |
.style("text-anchor", "middle") | |
.attr("x", function(d) { return Math.cos(arcScale(d) + arcMin) * (outerRadius + labelPad); }) | |
.attr("y", function(d) { | |
var yVal = Math.sin(arcScale(d) + arcMin) * (outerRadius + labelPad); | |
return yVal < -1 ? yVal : -7; | |
}).text(function(d) { return d; }); | |
}); | |
} | |
chart.margin = function(_) { | |
if (!arguments.length) return margin; | |
margin = _; | |
return chart; | |
}; | |
chart.width = function(_) { | |
if (!arguments.length) return width; | |
width = _; | |
return chart; | |
}; | |
chart.height = function(_) { | |
if (!arguments.length) return height; | |
height = _; | |
return chart; | |
}; | |
chart.innerRadius = function(_) { | |
if (!arguments.length) return innerRadius; | |
innerRadius = _; | |
return chart; | |
}; | |
chart.outerRadius = function(_) { | |
if (!arguments.length) return outerRadius; | |
outerRadius = _; | |
return chart; | |
}; | |
chart.dataDomain = function(_) { | |
if (!arguments.length) return dataDomain; | |
dataDomain = _; | |
return chart; | |
}; | |
chart.colorOptions = function(_) { | |
if (!arguments.length) return colorOptions; | |
colorOptions = _; | |
return chart; | |
}; | |
chart.labelPad = function(_) { | |
if (!arguments.length) return labelPad; | |
labelPad = _; | |
return chart; | |
}; | |
return chart; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment