Skip to content

Instantly share code, notes, and snippets.

@ajfarkas
Last active August 29, 2015 14:19
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 ajfarkas/5f366fb9fe5eb4a5d9f6 to your computer and use it in GitHub Desktop.
Save ajfarkas/5f366fb9fe5eb4a5d9f6 to your computer and use it in GitHub Desktop.
Rotating D3 Axis Labels with Slider

Move the slider to choose the angle of the x-axis labels.

<!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