diff --git a/light9/web/light9-music.coffee b/light9/web/light9-music.coffee
--- a/light9/web/light9-music.coffee
+++ b/light9/web/light9-music.coffee
@@ -24,9 +24,8 @@ Polymer
@statusTitle = "GET "+req.url+ " -> " + req.status + " " + req.statusText
setTimeout(@poll.bind(@), 2000)
@poll()
- setInterval(@estimateTimeLoop.bind(@), 50)
+ setInterval(@estimateTimeLoop.bind(@), 30)
-
estimateTimeLoop: ->
if @playing
@t = @remoteT + (Date.now() - @remoteAsOfMs) / 1000
diff --git a/light9/web/timeline-elements.html b/light9/web/timeline-elements.html
--- a/light9/web/timeline-elements.html
+++ b/light9/web/timeline-elements.html
@@ -33,7 +33,11 @@
-
+
timeline editor: song [{{song}}]
diff --git a/light9/web/timeline.coffee b/light9/web/timeline.coffee
--- a/light9/web/timeline.coffee
+++ b/light9/web/timeline.coffee
@@ -9,6 +9,7 @@ Polymer
graph: {type: Object, notify: true}
song: {type: String, notify: true}
songTime: {type: Number, notify: true, observer: '_onSongTime'}
+ songDuration: {type: Number, notify: true, observer: '_onSongDuration'}
songPlaying: {type: Boolean, notify: true}
width: ko.observable(1)
listeners:
@@ -16,19 +17,23 @@ Polymer
_onIronResize: ->
@width(@offsetWidth)
_onSongTime: (t) ->
- @viewState.cursor.t(t) if @viewState
+ @viewState.cursor.t(t)
+ _onSongDuration: (d) ->
+ @viewState.zoomSpec.duration(d)
- attached: ->
- @dia = @$.dia
+ ready: ->
@viewState =
zoomSpec:
- duration: ko.observable(190)
- t1: ko.observable(102)
- t2: ko.observable(161)
+ duration: ko.observable(100)
+ t1: ko.observable(0) # need validation to stay in bounds and not go too close
+ t2: ko.observable(100)
cursor:
- t: ko.observable(105)
+ t: ko.observable(20)
mouse:
pos: ko.observable($V([0,0]))
+
+ attached: ->
+ @dia = @$.dia
ko.computed =>
@debug = ko.toJSON(@viewState)
@@ -66,11 +71,48 @@ Polymer
@viewState.mouse.pos($V([ev.pageX - @root.left, ev.pageY - @root.top]))
@$.dia.setMouse(@viewState.mouse.pos())
+
+ animatedZoom: (newT1, newT2, secs) ->
+ fps = 30
+ oldT1 = @viewState.zoomSpec.t1()
+ oldT2 = @viewState.zoomSpec.t2()
+ lastTime = 0
+ for step in [0..secs * fps]
+ frac = step / (secs * fps)
+ do (frac) =>
+ gotoStep = =>
+ @viewState.zoomSpec.t1((1 - frac) * oldT1 + frac * newT1)
+ @viewState.zoomSpec.t2((1 - frac) * oldT2 + frac * newT2)
+ console.log('to', frac, @viewState.zoomSpec.t1(), @viewState.zoomSpec.t2())
+ delay = frac * secs * 1000
+ setTimeout(gotoStep, delay)
+ lastTime = delay
+ setTimeout(=>
+ @viewState.zoomSpec.t1(newT1)
+ @viewState.zoomSpec.t2(newT2)
+ , lastTime + 10)
+
bindKeys: ->
+
shortcut.add "Ctrl+P", (ev) =>
@$.music.seekPlayOrPause(@zoomInX.invert(@viewState.mouse.pos().e(1)))
+ zoomAnimSec = .2
+ shortcut.add "Ctrl+Escape", =>
+ @animatedZoom(0, @viewState.zoomSpec.duration(), zoomAnimSec)
+ shortcut.add "Shift+Escape", =>
+ @animatedZoom(@songTime - 2, @viewState.zoomSpec.duration(), zoomAnimSec)
+ shortcut.add "Escape", =>
+ zs = @viewState.zoomSpec
+ visSeconds = zs.t2() - zs.t1()
+ margin = visSeconds * .4
+ # buggy: really needs t1/t2 to limit their ranges
+ if @songTime < zs.t1() or @songTime > zs.t2() - visSeconds * .6
+ newCenter = @songTime + margin
+ @animatedZoom(newCenter - visSeconds / 2,
+ newCenter + visSeconds / 2, zoomAnimSec)
+
persistDemo: ->
ctx = @graph.Uri('http://example.com/')
adjs = []