Move the slider to choose the angle of the x-axis labels.
Last active
August 29, 2015 14:19
-
-
Save ajfarkas/5f366fb9fe5eb4a5d9f6 to your computer and use it in GitHub Desktop.
Rotating D3 Axis Labels with Slider
This file contains hidden or 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> | |
<meta charset="utf-8"> | |
<style> | |
.scale { | |
position: absolute; | |
top: 202px; | |
left: 20px; | |
width: 840px; | |
height: 8px; | |
box-shadow: inset 0px 0px 1px 19px white, inset 0px 0 0 19px black; | |
background-color: #f2f2f2; | |
padding: 20px 40px; | |
} | |
.slider { | |
position: absolute; | |
top: 14px; | |
left: 21px; | |
width: 20px; | |
height: 20px; | |
background-color: white; | |
outline: 1px solid #999; | |
box-shadow: 0px 1px 1px 0px black; | |
} | |
svg { | |
-webkit-user-select: none; | |
-moz-user-select: none; | |
-ms-user-select: none; | |
} | |
.axis text { | |
font: 11px sans-serif; | |
} | |
.axis line, | |
.axis path { | |
fill: none; | |
stroke: #000; | |
shape-rendering: crispEdges; | |
} | |
</style> | |
<body> | |
<div class="scale"> | |
<div class="slider" draggable="false"></div> | |
</div> | |
</body> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script> | |
var margin = {top: 250, right: 40, bottom: 250, left: 40}, | |
width = 960 - margin.left - margin.right, | |
height = 500 - margin.top - margin.bottom | |
var x = d3.scale.linear() | |
.domain([-90, 90]) | |
.range([0, width]) | |
var xAxis = d3.svg.axis() | |
.ticks(19) | |
.scale(x) | |
var svg = d3.select("body").append("svg") | |
.attr("width", width + margin.left + margin.right) | |
.attr("height", height + margin.top + margin.bottom) | |
.append("g") | |
.attr("transform", "translate(" + margin.left + "," + margin.top + ")") | |
svg.append("g") | |
.attr("class", "x axis") | |
.call(xAxis) | |
var rotateXLabels = function(deg) { | |
var axis = d3.select('.x').selectAll('text') | |
var rotateLabel = function() { | |
var d3Label = d3.select(this), | |
sign = Math.sign(deg) | |
// get coordinates and dimensions of this | |
bBox = this.getBBox(), | |
width = bBox.width, | |
height = bBox.height, | |
bx = d3Label.attr('data-bx') || bBox.x, | |
by = d3Label.attr('data-by') || bBox.y, | |
// convert to radians | |
rad = Math.abs(deg) * Math.PI/180, | |
anchor = 'middle' | |
/* move along non-hypoteneuse sides of triangle created by connecting | |
** top right corner of rotated label with top center of original. | |
*/ | |
if (sign === -1) { | |
var | |
dy = Math.sin(rad) * width/2, | |
shift = Math.sqrt(Math.pow(width,2) + Math.pow(width/2,2) - Math.pow(width,2) * Math.cos(rad) ), | |
dx = - Math.sqrt(Math.pow(shift,2) - Math.pow(dy,2)) | |
} | |
/* move along non-hypoteneuse sides of triangle created by extending | |
** left side of rotated label to meet in right angle with line | |
** extended from top center of original. | |
*/ | |
else if (sign === 1) { | |
var | |
dy = - Math.cos(Math.PI/2 - rad) * width/2, | |
dx = Math.sin(Math.PI/2 - rad) * width/2 | |
} | |
// don't move. But reset the anchor. | |
else { | |
var | |
dy = height/2, | |
dx = 0 | |
anchor = 'start' | |
} | |
d3Label | |
.attr('transform', 'rotate('+deg+' '+bx+' '+by+')') | |
.attr('x', 0) | |
// add padding | |
.attr('y', 16.1) | |
.attr('dx', dx + 4 * sign) | |
.attr('dy', dy - height/2) | |
.attr('text-anchor', anchor) | |
.attr('data-bx', bx) | |
.attr('data-by', by) | |
} | |
// rotate each member of x-axis | |
axis.each(rotateLabel) | |
} | |
!function slider() { | |
var scale = d3.select('.scale'), | |
slide = d3.select('.slider'), | |
pos = parseInt(slide.style('left')), | |
posMin = pos, | |
posMax = parseInt(scale.style('width')) + pos + slide.node().clientWidth, | |
range = posMax - posMin, | |
degrees | |
scale.on('mousedown', function() { | |
// check if mouse is on slider handle | |
var onSlider = d3.event.target === slide.node() ? true : false | |
slide.on('mouseenter', function() { onSlider = true }) | |
slide.on('mouseexit', function() { onSlider = false }) | |
// move slider | |
scale.on('mousemove', function() { | |
// find mouse position | |
pos = d3.event.pageX - 40 | |
// keep within range | |
if (pos < posMin || pos > posMax) { | |
slide.style('left', pos < posMin ? posMin : posMax) | |
degrees = pos < posMin ? -90 : 90 | |
} | |
// set position | |
else if (onSlider) { | |
slide.style('left', pos + 'px') | |
degrees = (pos - posMin) * 180/range - 90 | |
} | |
rotateXLabels(degrees) | |
}) | |
}) | |
// cleanup listeners | |
d3.select('body').on('mouseup', function() { | |
scale.on('mousemove', null) | |
slide.on('mouseenter', null) | |
slide.on('mouseexit', null) | |
}) | |
}() | |
rotateXLabels(-90) | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment