Skip to content

Instantly share code, notes, and snippets.

@albertsun
Created January 29, 2015 18:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save albertsun/90339d1b64cd9b4ae203 to your computer and use it in GitHub Desktop.
Save albertsun/90339d1b64cd9b4ae203 to your computer and use it in GitHub Desktop.
Drawing partial circles with area proportional to a value (good!) or angle proportional to a value (misleading!)
(function() {
var circleSegment = {};
var degreesToRadians = function(deg) {
return deg*Math.PI*2/360;
};
// takes an angle in radians
// returns 0-1 the proportion of a circle's area
// that a segment bounded by arc of that angle fills
// (allowing segment to range in size to the full circle)
var angleToProportion = function(radians) {
return (radians-Math.sin(radians))/(2*Math.PI);
};
var calc_table = [];
for (var i=1;i<=360;i++) {
calc_table.push(angleToProportion(degreesToRadians(i)));
}
// takes a 0-1 proportion of area
// returns the angle of arc in radians that defines a circle segment
// filling that proportion of the circle
// accurate to within 1/360th of a circle (1°)
var proportionToAngle = function(proportion) {
proportion = proportion % (2*Math.PI);
var curr = calc_table[0];
for (var i=0;i<360;i++) {
if (calc_table[i] > proportion) {
return degreesToRadians(Math.abs( calc_table[i-1]-proportion ) < Math.abs( calc_table[i]-proportion ) ? i : i+1);
}
}
return degreesToRadians(calc_table.length);
};
circleSegment.angleToProportion = angleToProportion;
circleSegment.proportionToAngle = proportionToAngle;
if (typeof define === 'function' && define.amd) {
define([], function() {
return circleSegment;
});
} else {
this.circleSegment = circleSegment;
}
}).call(this);
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: relative;
}
svg {
display: inline-block;
margin: 3px;
}
svg circle,
svg path {
stroke-width: 0;
opacity: 1;
}
svg .proportional {
fill: #2ca02c;
}
svg .naive {
fill: #d62728;
}
</style>
<body>
<div>
<svg width="360" height="40">
<circle r="20" cx="20" cy="20" class="proportional" /><text y="20" x="45">Area Proportional</text>
<circle r="20" cx="200" cy="20" class="naive" /><text y="20" x="225">Angle Proportional</text>
</svg>
</div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="circle-segment.js"></script>
<script>
function partialCircle(radius, radians) {
// var radians = circleSegment.proportionToAngle(proportion);
var rotation = (((1*Math.PI)-radians)/2)+radians;
var dimension = 2 * radius,
points = 50;
var angle = d3.scale.linear()
.domain([0, points-1])
.range([0-rotation, radians-rotation]);
var line = d3.svg.line.radial()
.interpolate("basis")
.tension(0)
.radius(radius)
.angle(function(d, i) { return angle(i); });
return line(d3.range(points));
}
var pct = d3.format("%");
// var radians = circleSegment.proportionToAngle(proportion);
d3.range(1,101).forEach(function(i) {
var radius = 20;
var height = radius*2,
width = (radius*4)+100;
var svg = d3.select("body").append("svg");
svg.attr("width", width)
.attr("height", height);
var radians = circleSegment.proportionToAngle(i/100); // proportional to area
var radiansNaive = 2*Math.PI*i/100; // proportional to angle
svg.append("path")
.classed("proportional", true)
.attr("d", partialCircle(radius, radians))
.attr("transform", function(d) { return "translate("+radius+","+radius+")"; });
svg.append("path")
.classed("naive", true)
.attr("d", partialCircle(radius, radiansNaive))
.attr("transform", function(d) { return "translate("+(3*radius)+","+radius+")"; });
svg.append("text").attr("y",radius).attr("x",radius*4).text(pct(i/100));
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment