Skip to content

Instantly share code, notes, and snippets.

@TheMcMurder
Last active December 23, 2015 19:39
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 TheMcMurder/6684357 to your computer and use it in GitHub Desktop.
Save TheMcMurder/6684357 to your computer and use it in GitHub Desktop.
double rotation

This is something I created just for fun using d3js. It serves no actual purpose.

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script>
<script>
var graphic_config = {
arc_width: 20,
max: 90,
inner_radius: 60,
best: "min",
title_font_size: 27,
color_scheme: ["#D9EBFD","#73B0D7","#31689B"],
transition_duration: 3500,
fade_delay: 200,
start: Date.now(),
speed: .005,
timer_interval: 4000
}
// wedding colors
// color_scheme: ["#E6600D","#F2A310","#768534"],
var width = 600,
height = 600,
τ = 2 * Math.PI; // http://tauday.com/tau-manifesto
var tau = τ;
var data = [ [.5], [.10], [.5], [.1], [.7], [.10], [.5], [.1], [.7] ];
// An arc function with all values bound except the endAngle. So, to compute an
// SVG path string for a given angle, we pass an object with an endAngle
// property to the `arc` function, and it will return the corresponding string.
var fill = graphic_config.color_scheme
console.log (fill)
var arc = d3.svg.arc()
// Create the SVG container, and apply a transform such that the origin is the
// center of the canvas. This way, we don't need to position arcs individually.
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
var arcGroup = svg.append("g")
// Add the foreground arc in orange, currently showing 12.7%.
// var foreground = svg.append("path")
// .datum({endAngle: .127 * τ})
// .style("fill", "orange")
// .attr("d", arc);
var modified_inner = graphic_config.inner_radius
for (var i = 0; i < data.length; i++){
data[i].innerRadius = modified_inner
data[i].outerRadius = modified_inner + graphic_config.arc_width
modified_inner += graphic_config.arc_width + 5
data[i].startAngle = (Math.random() * tau)
data[i].endAngle = (Math.random() * tau)
}
console.log(data)
var drawnArcs = arcGroup.selectAll("path")
.data(data)
.enter().append("path")
.style("fill", function(d, i){
return fill[i%fill.length]
})
.each(function (d){
console.log(d)
})
.attr("d", arc)
.attr("class", function(d,i){return "arc" + i})
var arc0 = arcGroup.select(".arc0")
var arc1 = arcGroup.select(".arc1")
var arc2 = arcGroup.select(".arc2")
var arc3 = arcGroup.select(".arc3")
var arc4 = arcGroup.select(".arc4")
var arc5 = arcGroup.select(".arc5")
var arc6 = arcGroup.select(".arc6")
var arc7 = arcGroup.select(".arc7")
var arc8 = arcGroup.select(".arc8")
// Every so often, start a transition to a new random angle. Use transition.call
// (identical to selection.call) so that we can encapsulate the logic for
// tweening the arc in a separate function below.
setInterval(function() {
arc0.transition()
.duration(graphic_config.transition_duration)
.call(arcTween, Math.random() * τ);
arc1.transition()
.duration(graphic_config.transition_duration)
.call(arcTween, Math.random() * τ);
arc2.transition()
.duration(graphic_config.transition_duration)
.call(arcTween, Math.random() * τ);
arc3.transition()
.duration(graphic_config.transition_duration)
.call(arcTween, Math.random() * τ);
arc4.transition()
.duration(graphic_config.transition_duration)
.call(arcTween, Math.random() * τ);
arc5.transition()
.duration(graphic_config.transition_duration)
.call(arcTween, Math.random() * τ);
arc6.transition()
.duration(graphic_config.transition_duration)
.call(arcTween, Math.random() * τ);
arc7.transition()
.duration(graphic_config.transition_duration)
.call(arcTween, Math.random() * τ);
arc8.transition()
.duration(graphic_config.transition_duration)
.call(arcTween, Math.random() * τ);
}, graphic_config.timer_interval);
// Creates a tween on the specified transition's "d" attribute, transitioning
// any selected arcs from their current angle to the specified new angle.
function arcTween(transition, newAngle) {
// The function passed to attrTween is invoked for each selected element when
// the transition starts, and for each element returns the interpolator to use
// over the course of transition. This function is thus responsible for
// determining the starting angle of the transition (which is pulled from the
// element's bound datum, d.endAngle), and the ending angle (simply the
// newAngle argument to the enclosing function).
transition.attrTween("d", function(d) {
// To interpolate between the two angles, we use the default d3.interpolate.
// (Internally, this maps to d3.interpolateNumber, since both of the
// arguments to d3.interpolate are numbers.) The returned function takes a
// single argument t and returns a number between the starting angle and the
// ending angle. When t = 0, it returns d.endAngle; when t = 1, it returns
// newAngle; and for 0 < t < 1 it returns an angle in-between.
var interpolate = d3.interpolate(d.endAngle, newAngle);
var interpolate2 = d3.interpolate(d.startAngle, Math.random() * tau)
// The return value of the attrTween is also a function: the function that
// we want to run for each tick of the transition. Because we used
// attrTween("d"), the return value of this last function will be set to the
// "d" attribute at every tick. (It's also possible to use transition.tween
// to run arbitrary code for every tick, say if you want to set multiple
// attributes from a single function.) The argument t ranges from 0, at the
// start of the transition, to 1, at the end.
return function(t) {
// Calculate the current arc angle based on the transition time, t. Since
// the t for the transition and the t for the interpolate both range from
// 0 to 1, we can pass t directly to the interpolator.
//
// Note that the interpolated angle is written into the element's bound
// data object! This is important: it means that if the transition were
// interrupted, the data bound to the element would still be consistent
// with its appearance. Whenever we start a new arc transition, the
// correct starting angle can be inferred from the data.
d.endAngle = interpolate(t);
d.startAngle = interpolate2(t)
// Lastly, compute the arc path given the updated data! In effect, this
// transition uses data-space interpolation: the data is interpolated
// (that is, the end angle) rather than the path string itself.
// Interpolating the angles in polar coordinates, rather than the raw path
// string, produces valid intermediate arcs during the transition.
return arc(d);
};
});
}
d3.timer(function() {
var angle = (Date.now() - graphic_config.start) * graphic_config.speed,
transform = function(d) { return "rotate(" + angle + ")"; };
arcGroup.selectAll("path").attr("transform", transform);
arcGroup.attr("transform", transform); // frame of reference
});
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment