Last active
January 23, 2023 05:38
-
-
Save msqr/3202712 to your computer and use it in GitHub Desktop.
d3 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
A circular gauge, inspired in part by http://bl.ocks.org/1499279 but with different | |
goals in mind. The approach taken here for rotating the pointer is using a rotational | |
transformation, which is easier to code and animate than redrawing the pointer line | |
as taken in tomerd's gauge. | |
This code is released under the MIT license. | |
Copyright (C) 2012 Matt Magoffin | |
Permission is hereby granted, free of charge, to any person obtaining a | |
copy of this software and associated documentation files (the | |
"Software"), to deal in the Software without restriction, including | |
without limitation the rights to use, copy, modify, merge, publish, | |
distribute, sublicense, and/or sell copies of the Software, and to | |
permit persons to whom the Software is furnished to do so, subject to | |
the following conditions: | |
The above copyright notice and this permission notice shall be included | |
in all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
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> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=320" /> | |
<meta name="apple-mobile-web-app-capable" content="yes" /> | |
<title>Gauge</title> | |
<script type="text/javascript" src="http://d3js.org/d3.v2.min.js"></script> | |
<style> | |
body { | |
font-family: Helvetica, Arial, sans-serif; | |
margin: 32px; | |
} | |
#power-gauge g.arc { | |
fill: steelblue; | |
} | |
#power-gauge g.pointer { | |
fill: #e85116; | |
stroke: #b64011; | |
} | |
#power-gauge g.label text { | |
text-anchor: middle; | |
font-size: 14px; | |
font-weight: bold; | |
fill: #666; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="power-gauge"></div> | |
<script> | |
var gauge = function(container, configuration) { | |
var that = {}; | |
var config = { | |
size : 200, | |
clipWidth : 200, | |
clipHeight : 110, | |
ringInset : 20, | |
ringWidth : 20, | |
pointerWidth : 10, | |
pointerTailLength : 5, | |
pointerHeadLengthPercent : 0.9, | |
minValue : 0, | |
maxValue : 10, | |
minAngle : -90, | |
maxAngle : 90, | |
transitionMs : 750, | |
majorTicks : 5, | |
labelFormat : d3.format(',g'), | |
labelInset : 10, | |
arcColorFn : d3.interpolateHsl(d3.rgb('#e8e2ca'), d3.rgb('#3e6c0a')) | |
}; | |
var range = undefined; | |
var r = undefined; | |
var pointerHeadLength = undefined; | |
var value = 0; | |
var svg = undefined; | |
var arc = undefined; | |
var scale = undefined; | |
var ticks = undefined; | |
var tickData = undefined; | |
var pointer = undefined; | |
var donut = d3.layout.pie(); | |
function deg2rad(deg) { | |
return deg * Math.PI / 180; | |
} | |
function newAngle(d) { | |
var ratio = scale(d); | |
var newAngle = config.minAngle + (ratio * range); | |
return newAngle; | |
} | |
function configure(configuration) { | |
var prop = undefined; | |
for ( prop in configuration ) { | |
config[prop] = configuration[prop]; | |
} | |
range = config.maxAngle - config.minAngle; | |
r = config.size / 2; | |
pointerHeadLength = Math.round(r * config.pointerHeadLengthPercent); | |
// a linear scale that maps domain values to a percent from 0..1 | |
scale = d3.scale.linear() | |
.range([0,1]) | |
.domain([config.minValue, config.maxValue]); | |
ticks = scale.ticks(config.majorTicks); | |
tickData = d3.range(config.majorTicks).map(function() {return 1/config.majorTicks;}); | |
arc = d3.svg.arc() | |
.innerRadius(r - config.ringWidth - config.ringInset) | |
.outerRadius(r - config.ringInset) | |
.startAngle(function(d, i) { | |
var ratio = d * i; | |
return deg2rad(config.minAngle + (ratio * range)); | |
}) | |
.endAngle(function(d, i) { | |
var ratio = d * (i+1); | |
return deg2rad(config.minAngle + (ratio * range)); | |
}); | |
} | |
that.configure = configure; | |
function centerTranslation() { | |
return 'translate('+r +','+ r +')'; | |
} | |
function isRendered() { | |
return (svg !== undefined); | |
} | |
that.isRendered = isRendered; | |
function render(newValue) { | |
svg = d3.select(container) | |
.append('svg:svg') | |
.attr('class', 'gauge') | |
.attr('width', config.clipWidth) | |
.attr('height', config.clipHeight); | |
var centerTx = centerTranslation(); | |
var arcs = svg.append('g') | |
.attr('class', 'arc') | |
.attr('transform', centerTx); | |
arcs.selectAll('path') | |
.data(tickData) | |
.enter().append('path') | |
.attr('fill', function(d, i) { | |
return config.arcColorFn(d * i); | |
}) | |
.attr('d', arc); | |
var lg = svg.append('g') | |
.attr('class', 'label') | |
.attr('transform', centerTx); | |
lg.selectAll('text') | |
.data(ticks) | |
.enter().append('text') | |
.attr('transform', function(d) { | |
var ratio = scale(d); | |
var newAngle = config.minAngle + (ratio * range); | |
return 'rotate(' +newAngle +') translate(0,' +(config.labelInset - r) +')'; | |
}) | |
.text(config.labelFormat); | |
var lineData = [ [config.pointerWidth / 2, 0], | |
[0, -pointerHeadLength], | |
[-(config.pointerWidth / 2), 0], | |
[0, config.pointerTailLength], | |
[config.pointerWidth / 2, 0] ]; | |
var pointerLine = d3.svg.line().interpolate('monotone'); | |
var pg = svg.append('g').data([lineData]) | |
.attr('class', 'pointer') | |
.attr('transform', centerTx); | |
pointer = pg.append('path') | |
.attr('d', pointerLine/*function(d) { return pointerLine(d) +'Z';}*/ ) | |
.attr('transform', 'rotate(' +config.minAngle +')'); | |
update(newValue === undefined ? 0 : newValue); | |
} | |
that.render = render; | |
function update(newValue, newConfiguration) { | |
if ( newConfiguration !== undefined) { | |
configure(newConfiguration); | |
} | |
var ratio = scale(newValue); | |
var newAngle = config.minAngle + (ratio * range); | |
pointer.transition() | |
.duration(config.transitionMs) | |
.ease('elastic') | |
.attr('transform', 'rotate(' +newAngle +')'); | |
} | |
that.update = update; | |
configure(configuration); | |
return that; | |
}; | |
</script> | |
<script> | |
function onDocumentReady() { | |
var powerGauge = gauge('#power-gauge', { | |
size: 300, | |
clipWidth: 300, | |
clipHeight: 300, | |
ringWidth: 60, | |
maxValue: 10, | |
transitionMs: 4000, | |
}); | |
powerGauge.render(); | |
function updateReadings() { | |
// just pump in random data here... | |
powerGauge.update(Math.random() * 10); | |
} | |
// every few seconds update reading values | |
updateReadings(); | |
setInterval(function() { | |
updateReadings(); | |
}, 5 * 1000); | |
} | |
if ( !window.isLoaded ) { | |
window.addEventListener("load", function() { | |
onDocumentReady(); | |
}, false); | |
} else { | |
onDocumentReady(); | |
} | |
</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
This code is released under the MIT license. | |
Copyright (C) 2012 Matt Magoffin | |
Permission is hereby granted, free of charge, to any person obtaining a | |
copy of this software and associated documentation files (the | |
"Software"), to deal in the Software without restriction, including | |
without limitation the rights to use, copy, modify, merge, publish, | |
distribute, sublicense, and/or sell copies of the Software, and to | |
permit persons to whom the Software is furnished to do so, subject to | |
the following conditions: | |
The above copyright notice and this permission notice shall be included | |
in all copies or substantial portions of the Software. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment