d3.time.clock()
clock.speed([speed])
clock.extent([extent])
clock.init()
clock.run()
clock.pause()
clock.seek
d3.svg.dial()
dial.clock([clock])
d3.time.clock = function () { | |
return d3_time_clock(0, 1, null); | |
}; | |
function d3_time_clock(t, speed, interval) { | |
var dispatch = d3.dispatch('tick', 'run', 'pause', 'complete'); | |
function clock() {} | |
clock.speed = function(x) { | |
if (!arguments.length) return speed; | |
speed = x; | |
return clock; | |
}; | |
// Tie to a scale instead, with default linear? | |
clock.extent = function(x) { | |
if (!arguments.length) return extent; | |
extent = x; | |
return clock; | |
}; | |
clock.run = function() { | |
interval = window.setInterval(function() { | |
dispatch.tick(++t); | |
if (t >= extent) { | |
clock.pause(); | |
dispatch.complete(); | |
} | |
}, 1000 / speed); | |
dispatch.run(); | |
return clock; | |
}; | |
clock.pause = function() { | |
window.clearInterval(interval); | |
interval = null; | |
dispatch.pause(); | |
return clock; | |
}; | |
clock.init = function() { | |
dispatch.tick(t = 0); | |
return clock; | |
}; | |
clock.seek = function(dt) { | |
t += Math.round(dt * speed); | |
if (t >= extent) { | |
clock.pause(); | |
dispatch.complete(); | |
} | |
t = Math.max(0, Math.min(extent, t)); | |
dispatch.tick(t); | |
return clock; | |
}; | |
return d3.rebind(clock, dispatch, 'on'); | |
} | |
d3.svg.dial = function() { | |
var clock = d3.time.clock(), | |
state = null; | |
function pop(x) { | |
x.attr('transform', 'scale(0)') | |
.transition() | |
.ease('elastic') | |
.attr('transform', 'scale(1)'); | |
} | |
function dial(g) { | |
g.each(function() { | |
var g = d3.select(this); | |
g.call(d3.behavior.drag() | |
.origin(function() { return { x: 0, y: 0}; }) | |
.on('drag', function() { | |
console.log(d3.event) | |
clock.pause(); | |
clock.seek(Math.floor(d3.event.dx / 5)); | |
}) | |
); | |
g.style('cursor', 'e-resize'); | |
g.append('circle') | |
.attr('r', 42) | |
.attr('fill', '#f6f6f6'); | |
g.append('path') | |
.attr('fill', '#cccccc') | |
.attr('class', 'arc'); | |
var btn = g.append('g') | |
.attr('class', 'btn') | |
.attr('transform', 'translate(0, 22)') | |
.style('cursor', 'pointer') | |
.on('click', function() { | |
switch (state) { | |
case 'running': | |
clock.pause(); | |
break; | |
case 'paused': | |
clock.run(); | |
break; | |
case 'complete': | |
clock.init().run(); | |
break; | |
} | |
}); | |
btn.append('rect') | |
.attr('width', 12) | |
.attr('height', 12) | |
.style('fill', 'transparent') | |
.attr('transform', 'translate(-6,-6)'); | |
var btn_d = { | |
pause: 'M-5 -6V6H-1V-6H-5M5 -6V6H1V-6H5', | |
play: 'M-4 -7V7L7 0Z', | |
replay: 'M1 -7L7 -3L1 1V-2A4 4 0 1 0 4 1H 6A6 6 0 1 1 1 -5Z' | |
}; | |
var path = btn.append('path').attr('d', btn_d.play); | |
clock.on('run.dial', function() { | |
state = 'running'; | |
path.attr('d', btn_d.pause).call(pop); | |
}); | |
clock.on('pause.dial', function() { | |
if (state == 'paused') return; | |
state = 'paused'; | |
path.attr('d', btn_d.play).call(pop); | |
}); | |
clock.on('complete.dial', function() { | |
state = 'complete'; | |
path.attr('d', btn_d.replay).call(pop); | |
}); | |
clock.on('tick.dial', function(t) { | |
g.select('path') | |
.datum(t) | |
.attr('d', d3.svg.arc() | |
.outerRadius(42) | |
.innerRadius(0) | |
.startAngle(0) | |
.endAngle(function(d) { | |
return 2 * Math.PI * d / clock.extent(); | |
}) | |
); | |
}); | |
}); | |
} | |
dial.clock = function(x) { | |
if (!arguments.length) return clock; | |
clock = x; | |
return dial; | |
}; | |
return dial; | |
}; |