Skip to content

Instantly share code, notes, and snippets.

@mforando
Last active October 1, 2019 20:24
Show Gist options
  • Save mforando/0bf4f4f848d9ad51970a0687429782b3 to your computer and use it in GitHub Desktop.
Save mforando/0bf4f4f848d9ad51970a0687429782b3 to your computer and use it in GitHub Desktop.
Polar Labeling Logic
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
var width = 500;
var height = 500;
// Feel free to change or delete any of the code you see in this editor!
var svg = d3.select("body").append("svg")
.attr("width", 500)
.attr("height", 500)
.style("overflow","visible")
var chart = svg.append("g")
.attr("transform","translate(250,250)")
var mainCircle = chart.append("circle")
.attr("r",width/4)
.attr("fill","white")
.attr("stroke","black")
var randAngles = d3.range(10).map(function(d){
return {"angle":Math.random()*Math.PI - Math.PI/2}
})
var scaleBand = d3.scaleBand()
.domain(randAngles
.sort(function(a,b){return d3.ascending(a.angle,b.angle)})
.map(function(d,i){return i}))
.range([-height/2 + 20,height/2 - 20])
var radiusInner = width/4;
var radiusOuterMin = width/4 + 15;
var radiusOuterMax = width/2;
var radiusScale = d3.scaleLinear()
.range([radiusOuterMin,radiusOuterMax,radiusOuterMin])
.domain([0,Math.PI,Math.PI*2])
var circles = chart.selectAll(".randcircles")
.data(randAngles)
circles.enter()
.append("circle")
.attr("r",3)
.attr("cx",function(d){return Math.cos(d.angle)*radiusInner})
.attr("cy",function(d){return Math.sin(d.angle)*radiusInner})
var lbls = chart.selectAll(".randcircles")
.data(randAngles)
lbls.enter()
.append("text")
.text(function(d){return d3.format('0.2f')(d.angle)})
.attr("x",300)
.attr("y",function(d,i){return scaleBand(i)})
var polyLineData = randAngles.map(function(d,i){
//figure out the current angle.
var curAngle = d.angle;
//figure out the slope for the current angle.
var slope = (Math.sin(d.angle)*radiusInner)/(Math.cos(d.angle)*radiusInner);
//y = mx + b;
// intercept = 0 so
// y = mx;
// y/m = x;
//solve for the intersection between the desired y-position
// the equation for the label's line is just the Y value desired (constant)
var desiredY = scaleBand(i);
var xVal = desiredY/slope;
var yVal = desiredY;
//adjust the second point if its in the wrong direction.
if(xVal<Math.cos(d.angle)*radiusInner || xVal > 300){
xVal = 250;
yVal = Math.sin(d.angle)*radiusInner;
}
return [[Math.cos(d.angle)*radiusInner,Math.sin(d.angle)*radiusInner],
[xVal,yVal],
[300,desiredY]]
})
var paths = chart.selectAll("polyline")
.data(polyLineData)
paths.enter()
.append("polyline")
.attr("points",function(d){return d})
.attr("stroke","black")
.attr("fill","none")
console.log(polyLineData)
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment