diff --git a/light9/web/timeline/cursor_canvas.coffee b/light9/web/timeline/cursor_canvas.coffee
--- a/light9/web/timeline/cursor_canvas.coffee
+++ b/light9/web/timeline/cursor_canvas.coffee
@@ -3,41 +3,42 @@ Polymer
is: 'light9-cursor-canvas'
behaviors: [ Polymer.IronResizableBehavior ]
listeners: 'iron-resize': 'update'
-
+ properties:
+ viewState: { type: Object, notify: true, observer: "onViewState" }
ready: ->
@mouseX = 0
@mouseY = 0
@cursorPath = null
@ctx = @$.canvas.getContext('2d')
+ onViewState: ->
+ ko.computed(@redrawCursor.bind(@))
+
update: (ev) ->
@$.canvas.width = ev.target.offsetWidth
@$.canvas.height = ev.target.offsetHeight
@redraw()
- setMouse: (pos) ->
- @mouseX = pos.e(1)
- @mouseY = pos.e(2)
- @redraw()
-
- setCursor: (y1, h1, y2, h2, viewState) ->
-
- xZoomedOut = viewState.fullZoomX(viewState.latestMouseTime())
- xZoomedIn = viewState.mouse.pos().e(1)
+ redrawCursor: ->
+ vs = @viewState
+ dependOn = [vs.zoomSpec.t1(), vs.zoomSpec.t2()]
+ xZoomedOut = vs.fullZoomX(vs.latestMouseTime())
+ xZoomedIn = vs.mouse.pos().e(1)
@cursorPath = {
- top0: $V([xZoomedOut, y1])
- top1: $V([xZoomedOut, y1 + h1])
- mid0: $V([xZoomedIn + 2, y2 + h2])
- mid1: $V([xZoomedIn - 2, y2 + h2])
- mid2: $V([xZoomedOut - 1, y1 + h1])
- mid3: $V([xZoomedOut + 1, y1 + h1])
- bot0: $V([xZoomedIn, y2 + h2])
+ top0: $V([xZoomedOut, vs.audioY()])
+ top1: $V([xZoomedOut, vs.audioY() + vs.audioH()])
+ mid0: $V([xZoomedIn + 2, vs.zoomedTimeY() + vs.zoomedTimeH()])
+ mid1: $V([xZoomedIn - 2, vs.zoomedTimeY() + vs.zoomedTimeH()])
+ mid2: $V([xZoomedOut - 1, vs.audioY() + vs.audioH()])
+ mid3: $V([xZoomedOut + 1, vs.audioY() + vs.audioH()])
+ bot0: $V([xZoomedIn, vs.zoomedTimeY() + vs.zoomedTimeH()])
bot1: $V([xZoomedIn, @offsetParent.offsetHeight])
}
@redraw()
redraw: ->
+ return unless @ctx
@ctx.clearRect(0, 0, @$.canvas.width, @$.canvas.height)
@ctx.strokeStyle = '#fff'
diff --git a/light9/web/timeline/timeline-elements.html b/light9/web/timeline/timeline-elements.html
--- a/light9/web/timeline/timeline-elements.html
+++ b/light9/web/timeline/timeline-elements.html
@@ -76,7 +76,7 @@
-
+
diff --git a/light9/web/timeline/timeline.coffee b/light9/web/timeline/timeline.coffee
--- a/light9/web/timeline/timeline.coffee
+++ b/light9/web/timeline/timeline.coffee
@@ -95,7 +95,6 @@ class Project
class ViewState
constructor: () ->
# caller updates all these observables
- @width = ko.observable(500)
@zoomSpec =
duration: ko.observable(100) # current song duration
t1: ko.observable(0)
@@ -104,22 +103,27 @@ class ViewState
t: ko.observable(20) # songTime
@mouse =
pos: ko.observable($V([0,0]))
+ @width = ko.observable(500)
+ @audioY = ko.observable(0)
+ @audioH = ko.observable(0)
+ @zoomedTimeY = ko.observable(0)
+ @zoomedTimeH = ko.observable(0)
@fullZoomX = d3.scaleLinear()
@zoomInX = d3.scaleLinear()
- ko.computed(@zoomOrLayoutChanged.bind(@))
+ @zoomAnimSec = .1
+
+ ko.computed(@maintainZoomLimitsAndScales.bind(@))
setWidth: (w) ->
@width(w)
- @zoomOrLayoutChanged() # before other handleers run
+ @maintainZoomLimitsAndScales() # before other handlers run
- zoomOrLayoutChanged: () ->
- log('zoomOrLayoutChanged')
+ maintainZoomLimitsAndScales: () ->
+ log('maintainZoomLimitsAndScales')
# not for cursor updates
- window.debug_zoomOrLayoutChangedCount++
-
if @zoomSpec.t1() < 0
@zoomSpec.t1(0)
if @zoomSpec.duration() and @zoomSpec.t2() > @zoomSpec.duration()
@@ -130,7 +134,6 @@ class ViewState
@zoomInX.domain([@zoomSpec.t1(), @zoomSpec.t2()])
@zoomInX.range([0, @width()])
- log('update zoomInX')
latestMouseTime: ->
@zoomInX.invert(@mouse.pos().e(1))
@@ -147,7 +150,19 @@ class ViewState
zs.t2(center + right * scale)
log('view to', ko.toJSON(@))
-
+ frameCursor: ->
+ zs = @zoomSpec
+ visSeconds = zs.t2() - zs.t1()
+ margin = visSeconds * .4
+ # buggy: really needs t1/t2 to limit their ranges
+ if @cursor.t() < zs.t1() or @cursor.t() > zs.t2() - visSeconds * .6
+ newCenter = @cursor.t() + margin
+ @animatedZoom(newCenter - visSeconds / 2,
+ newCenter + visSeconds / 2, @zoomAnimSec)
+ frameToEnd: ->
+ @animatedZoom(@cursor.t() - 2, @zoomSpec.duration(), @zoomAnimSec)
+ frameAll: ->
+ @animatedZoom(0, @zoomSpec.duration(), @zoomAnimSec)
animatedZoom: (newT1, newT2, secs) ->
fps = 30
oldT1 = @zoomSpec.t1()
@@ -209,7 +224,6 @@ class TimelineEditor extends Polymer.mix
ko.computed(@zoomOrLayoutChanged.bind(@))
setTimeout =>
- ko.computed(@songTimeChanged.bind(@))
@trackMouse()
@bindKeys()
@@ -228,7 +242,7 @@ class TimelineEditor extends Polymer.mix
, 500
@addEventListener('iron-resize', @_onIronResize.bind(@))
- @_onIronResize()
+ setTimeout(@_onIronResize.bind(@), 1000) # when children are packed
#if anchor == loadtest
# add note and delete it repeatedly
@@ -236,8 +250,12 @@ class TimelineEditor extends Polymer.mix
_onIronResize: ->
@viewState.setWidth(@offsetWidth)
-
- log('changed width')
+ @viewState.audioY(@$.audio.offsetTop)
+ @viewState.audioH(@$.audio.offsetHeight)
+ @viewState.zoomedTimeY(@$.zoomed.$.time.offsetTop) if @$.zoomed?.$?.time?
+ @viewState.zoomedTimeH(30) #@$.zoomed.$.time.offsetHeight)
+
+ log('editor resized')
_onSongTime: (t) ->
@viewState.cursor.t(t)
_onSongDuration: (d) ->
@@ -260,9 +278,8 @@ class TimelineEditor extends Polymer.mix
"
zoomOrLayoutChanged: ->
-
vs = @viewState
-
+ vs.width()
# todo: these run a lot of work purely for a time change
if @$.zoomed?.$?.audio?
@@ -270,17 +287,6 @@ class TimelineEditor extends Polymer.mix
#@dia.setTimeAxis(vs.width(), @$.zoomed.$.audio.offsetTop, vs.zoomInX)
@$.adjustersCanvas.updateAllCoords()
- # cursor needs update when layout changes, but I don't want
- # zoom/layout to depend on the playback time
- setTimeout(@songTimeChanged.bind(@), 1)
-
- songTimeChanged: ->
- return unless @$.zoomed?.$?.time?
- @$.cursorCanvas.setCursor(@$.audio.offsetTop, @$.audio.offsetHeight,
- @$.zoomed.$.time.offsetTop,
- 30,#@$.zoomed.$.time.offsetHeight,
- @viewState)
-
trackMouse: ->
# not just for show- we use the mouse pos sometimes
for evName in ['mousemove', 'touchmove']
@@ -294,7 +300,6 @@ class TimelineEditor extends Polymer.mix
root = @$.cursorCanvas.getBoundingClientRect()
@viewState.mouse.pos($V([ev.pageX - root.left, ev.pageY - root.top]))
- @$.cursorCanvas.setMouse(@viewState.mouse.pos())
# should be controlled by a checkbox next to follow-player-song-choice
@sendMouseToVidref() unless window.location.hash.match(/novidref/)
@@ -305,8 +310,6 @@ class TimelineEditor extends Polymer.mix
@$.vidrefTime.generateRequest()
@$.vidrefLastSent = now
-
-
bindWheelZoom: (elem) ->
elem.addEventListener 'mousewheel', (ev) =>
@viewState.onMouseWheel(ev.deltaY)
@@ -320,21 +323,9 @@ class TimelineEditor extends Polymer.mix
bindKeys: ->
shortcut.add "Ctrl+P", (ev) =>
@$.music.seekPlayOrPause(@latestMouseTime())
-
- zoomAnimSec = .1
- shortcut.add "Ctrl+Escape", =>
- @viewState.animatedZoom(0, @viewState.zoomSpec.duration(), zoomAnimSec)
- shortcut.add "Shift+Escape", =>
- @viewState.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
- @viewState.animatedZoom(newCenter - visSeconds / 2,
- newCenter + visSeconds / 2, zoomAnimSec)
+ shortcut.add "Ctrl+Escape", => @viewState.frameAll()
+ shortcut.add "Shift+Escape", => @viewState.frameToEnd()
+ shortcut.add "Escape", => @viewState.frameCursor()
shortcut.add "L", =>
@$.adjustersCanvas.updateAllCoords()
shortcut.add 'Delete', =>
@@ -343,7 +334,6 @@ class TimelineEditor extends Polymer.mix
makeZoomAdjs: ->
yMid = => @$.audio.offsetTop + @$.audio.offsetHeight / 2
- dur = @viewState.zoomSpec.duration
valForPos = (pos) =>
x = pos.e(1)