Changeset - 68681c2cbbc1
[Not reviewed]
default
0 3 0
Drew Perttula - 7 years ago 2018-05-11 09:54:05
drewp@bigasterisk.com
extract viewState, pass it to other elements
Ignore-this: 776252bdb90b590a380666b14b6c7818
3 files changed with 74 insertions and 64 deletions:
0 comments (0 inline, 0 general)
light9/web/timeline/cursor_canvas.coffee
Show inline comments
 
@@ -17,16 +17,16 @@ Polymer
 

	
 
  setMouse: (pos) ->
 
    @mouseX = pos.e(1)
 
    @mouseY = pos.e(2)
 
    @redraw()
 

	
 
  setCursor: (y1, h1, y2, h2, fullZoomX, zoomInX, cursor) ->
 
  setCursor: (y1, h1, y2, h2, viewState) ->
 
    
 
    xZoomedOut = fullZoomX(cursor.t())
 
    xZoomedIn = zoomInX(cursor.t())
 
    xZoomedOut = viewState.fullZoomX(viewState.latestMouseTime())
 
    xZoomedIn = viewState.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])
light9/web/timeline/timeline-elements.html
Show inline comments
 
@@ -68,14 +68,13 @@
 
                                   project="{{project}}"
 
                                   selection="{{selection}}"
 
                                   dia="{{dia}}"
 
                                   set-adjuster="{{setAdjuster}}"
 
                                   song="{{song}}"
 
                                   show="{{show}}"
 
                                   zoom="{{viewState.zoomSpec}}"
 
                                   zoom-in-x="{{zoomInX}}">
 
                                   view-state="{{viewState}}">
 
      </light9-timeline-time-zoomed>
 
      <light9-timeline-diagram-layer id="dia" selection="{{selection}}"></light9-timeline-diagram-layer>
 
      <light9-adjusters-canvas id="adjustersCanvas" set-adjuster="{{setAdjuster}}">
 
      </light9-adjusters-canvas>
 
      <light9-cursor-canvas id="cursorCanvas"></light9-cursor-canvas>
 
    </div>
light9/web/timeline/timeline.coffee
Show inline comments
 
@@ -88,13 +88,67 @@ class Project
 
      
 
  deleteNote: (song, note, selection) ->
 
    patch = {delQuads: [{subject: song, predicate: graph.Uri(':note'), object: note, graph: song}], addQuads: []}
 
    @graph.applyAndSendPatch(patch)
 
    if note in selection.selected()
 
      selection.selected(_.without(selection.selected(), note))
 
  
 

	
 
class ViewState
 
  constructor: () ->
 
    # caller updates all these observables
 
    @width = ko.observable(500)
 
    @zoomSpec =
 
      duration: ko.observable(100) # current song duration
 
      t1: ko.observable(0)
 
      t2: ko.observable(100)
 
    @cursor =
 
      t: ko.observable(20)
 
    @mouse =
 
      pos: ko.observable($V([0,0]))
 
      
 
    @fullZoomX = d3.scaleLinear()
 
    @zoomInX = d3.scaleLinear()
 

	
 
    ko.computed(@zoomOrLayoutChanged.bind(@))    
 
    
 
  zoomOrLayoutChanged: () ->
 
    log('zoomOrLayoutChanged')
 
    # not for cursor updates
 

	
 
    window.debug_zoomOrLayoutChangedCount++
 

	
 
    if @zoomSpec.t1() < 0
 
      @zoomSpec.t1(0)
 
    if @zoomSpec.duration() and @zoomSpec.t2() > @zoomSpec.duration()
 
      @zoomSpec.t2(@zoomSpec.duration())
 

	
 
    @fullZoomX.domain([0, @zoomSpec.duration()])
 
    @fullZoomX.range([0, @width()])
 

	
 
    # had trouble making notes update when this changes
 
    zoomInX = d3.scaleLinear()
 
    zoomInX.domain([@zoomSpec.t1(), @zoomSpec.t2()])
 
    zoomInX.range([0, @width()])
 
    @zoomInX = zoomInX
 
    
 
  latestMouseTime: ->
 
    @zoomInX.invert(@mouse.pos().e(1))
 

	
 
  onMouseWheel: (deltaY) ->
 
    zs = @zoomSpec
 

	
 
    center = @latestMouseTime()
 
    left = center - zs.t1()
 
    right = zs.t2() - center
 
    scale = Math.pow(1.005, deltaY)
 

	
 
    zs.t1(center - left * scale)
 
    zs.t2(center + right * scale)
 
    log('view to', ko.toJSON(@))
 

	
 
    
 
class TimelineEditor extends Polymer.Element
 
  @is: 'light9-timeline-editor'
 
  @behaviors: [ Polymer.IronResizableBehavior ]
 
  @properties:
 
    viewState: { type: Object }
 
    debug: {type: String}
 
@@ -105,14 +159,12 @@ class TimelineEditor extends Polymer.Ele
 
    followPlayerSong: {type: Boolean, notify: true, value: true}
 
    song: {type: String, notify: true}
 
    show: {value: 'http://light9.bigasterisk.com/show/dance2017'}
 
    songTime: {type: Number, notify: true, observer: '_onSongTime'}
 
    songDuration: {type: Number, notify: true, observer: '_onSongDuration'}
 
    songPlaying: {type: Boolean, notify: true}
 
    fullZoomX: {type: Object, notify: true}
 
    zoomInX: {type: Object, notify: true}
 
    selection: {type: Object, notify: true}
 
  width: ko.observable(1)
 
  @listeners:
 
    'iron-resize': '_onIronResize'
 
  @observers: [
 
    'setSong(playerSong, followPlayerSong)',
 
@@ -127,24 +179,14 @@ class TimelineEditor extends Polymer.Ele
 

	
 
    @selection = {hover: ko.observable(null), selected: ko.observable([])}
 

	
 
    window.debug_zoomOrLayoutChangedCount = 0
 
    window.debug_adjUpdateDisplay = 0
 
    
 
    @viewState =
 
      zoomSpec:
 
        duration: ko.observable(100) # current song duration
 
        t1: ko.observable(0) # need validation to stay in bounds and not go too close
 
        t2: ko.observable(100)
 
      cursor:
 
        t: ko.observable(20)
 
      mouse:
 
        pos: ko.observable($V([0,0]))
 
    @viewState = new ViewState()
 
    window.viewState = @viewState
 
    @fullZoomX = d3.scaleLinear()
 
    @zoomInX = d3.scaleLinear()
 
    @setAdjuster = (adjId, makeAdjustable) =>
 
      ac = @$.adjustersCanvas
 
      setTimeout((()=>ac.setAdjuster(adjId, makeAdjustable)),10)
 

	
 
    setTimeout =>
 
      ko.computed(@zoomOrLayoutChanged.bind(@))
 
@@ -191,47 +233,31 @@ class TimelineEditor extends Polymer.Ele
 
     #{elemCount('light9-timeline-graph-row')} rows,
 
     #{window.debug_adjsCount} adjuster items registered,
 
     #{window.debug_adjUpdateDisplay} adjuster updateDisplay calls,
 
    "
 

	
 
  zoomOrLayoutChanged: ->
 
    log('zoomOrLayoutChanged')
 
    # not for cursor updates
 

	
 
  
 
    vs = @viewState
 
    
 
    if vs.zoomSpec.t1() < 0
 
      vs.zoomSpec.t1(0)
 
    if vs.zoomSpec.duration() and vs.zoomSpec.t2() > vs.zoomSpec.duration()
 
      vs.zoomSpec.t2(vs.zoomSpec.duration())
 

	
 
    window.debug_zoomOrLayoutChangedCount++
 
    @fullZoomX.domain([0, vs.zoomSpec.duration()])
 
    @fullZoomX.range([0, @width()])
 

	
 
    # had trouble making notes update when this changes
 
    zoomInX = d3.scaleLinear()
 
    zoomInX.domain([vs.zoomSpec.t1(), vs.zoomSpec.t2()])
 
    zoomInX.range([0, @width()])
 
    @zoomInX = zoomInX
 

	
 
  
 
    # todo: these run a lot of work purely for a time change
 
    if @$.zoomed?.$?.audio?
 
      @dia.setTimeAxis(@width(), @$.zoomed.$.audio.offsetTop, @zoomInX)
 
      @dia.setTimeAxis(@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,
 
                              @$.zoomed.$.time.offsetHeight,
 
                              @fullZoomX, @zoomInX, @viewState.cursor)
 
                              @viewState)
 
    
 
  trackMouse: ->
 
    # not just for show- we use the mouse pos sometimes
 
    for evName in ['mousemove', 'touchmove']
 
      @addEventListener evName, (ev) =>
 
        ev.preventDefault()
 
@@ -251,27 +277,17 @@ class TimelineEditor extends Polymer.Ele
 
    now = Date.now()
 
    if (!@$.vidrefLastSent? || @$.vidrefLastSent < now - 200) && !@songPlaying
 
      @$.vidrefTime.body = {t: @latestMouseTime(), source: 'timeline'}
 
      @$.vidrefTime.generateRequest()
 
      @$.vidrefLastSent = now
 

	
 
  latestMouseTime: ->
 
    @zoomInX.invert(@viewState.mouse.pos().e(1))
 
  
 

	
 
  bindWheelZoom: (elem) ->
 
    elem.addEventListener 'mousewheel', (ev) =>
 
      zs = @viewState.zoomSpec
 

	
 
      center = @latestMouseTime()
 
      left = center - zs.t1()
 
      right = zs.t2() - center
 
      scale = Math.pow(1.005, ev.deltaY)
 

	
 
      zs.t1(center - left * scale)
 
      zs.t2(center + right * scale)
 
      log('view to', ko.toJSON(@viewState))
 
      @viewState.onMouseWheel(ev.deltaY)
 

	
 
  forwardMouseEventsToAdjustersCanvas: ->
 
    ac = @$.adjustersCanvas
 
    @addEventListener('mousedown', ac.onDown.bind(ac))
 
    @addEventListener('mousemove', ac.onMove.bind(ac))
 
    @addEventListener('mouseup', ac.onUp.bind(ac))
 
@@ -373,36 +389,34 @@ class TimeZoomed extends Polymer.Element
 
  @properties:
 
    graph: { type: Object, notify: true }
 
    project: { type: Object }
 
    selection: { type: Object, notify: true }
 
    dia: { type: Object, notify: true }
 
    song: { type: String, notify: true }
 
    zoomInX: { type: Object, notify: true }
 
    zoom: { type: Object, notify: true, observer: 'onZoom' } # viewState.zoomSpec
 
    zoomFlattened: { type: Object, notify: true }
 
    viewState: { type: Object, notify: true }
 
  @observers: [
 
    'onGraph(graph, setAdjuster, song, zoomInX, project)'
 
    'onGraph(graph, setAdjuster, song, viewState, project)',
 
    'onZoom(viewState)',
 
  ]
 
  @listeners: {'iron-resize': 'update'}
 
  update: ->
 
    @renderer.resize(@clientWidth, @clientHeight)
 
    @renderer.render(@stage)
 

	
 
  onZoom: ->
 
    updateZoomFlattened = ->
 
      log('updateZoomFlattened')
 
      @zoomFlattened = ko.toJS(@zoom)
 
      @zoomFlattened = ko.toJS(@viewState.zoomSpec)
 
    ko.computed(updateZoomFlattened.bind(@))
 

	
 
  constructor: ->
 
    super()
 
    @stage = new PIXI.Container()
 
    
 
    @renderer = PIXI.autoDetectRenderer({
 
         backgroundColor: 0xff6060,
 
  
 
    })
 
     
 
  connectedCallback: ->
 
    super.connectedCallback()
 
     
 
    @$.rows.appendChild(@renderer.view);
 
@@ -418,40 +432,37 @@ class TimeZoomed extends Polymer.Element
 
    log('assign rows',@song, 'graph has', @graph.quads().length)
 
    graphics = new PIXI.Graphics({nativeLines: true})
 

	
 
    for uri in _.sortBy(@graph.objects(@song, U(':note')), 'uri')
 
      #should only make new ones
 
      # 
 
      child = new Note(@graph, @selection, @dia, uri, @setAdjuster, @song, @zoomInX)
 
      child = new Note(@graph, @selection, @dia, uri, @setAdjuster, @song, @viewState.zoomInX)
 
      originTime = @graph.floatValue(uri, U(':originTime'))
 
      effect = @graph.uriValue(uri, U(':effectClass'))
 
      for curve in @graph.objects(uri, U(':curve'))
 
        if @graph.uriValue(curve, U(':attr')).equals(U(':strength'))
 

	
 
          [@pointUris, @worldPts] = @project.getCurvePoints(curve, originTime)
 
          curveWidthCalc = () => @_curveWidth(@worldPts)
 

	
 
          h = 150 #@offsetHeight
 
          screenPts = ($V([@zoomInX(pt.e(1)), @offsetTop + (1 - pt.e(2)) * h]) for pt in @worldPts)
 
          screenPts = ($V([@viewState.zoomInX(pt.e(1)), @offsetTop + (1 - pt.e(2)) * h]) for pt in @worldPts)
 
          graphics.beginFill(0xFF3300);
 
          graphics.lineStyle(4, 0xffd900, 1)
 

	
 
          graphics.moveTo(screenPts[0].e(1), screenPts[0].e(2))
 
          for p in screenPts.slice(1)
 
            graphics.lineTo(p.e(1), p.e(2))
 
         graphics.endFill()
 
    
 
     @rows = []#(new NoteRow(@graph, @dia, @song, @zoomInX, @noteUris, i, @selection) for i in [0...ROW_COUNT])
 

	
 

	
 

	
 
     @stage.children.splice(0)
 
     @stage.addChild(graphics)
 
     @renderer.render(@stage)
 
    
 

	
 
  onDrop: (effect, pos) ->
 
    U = (x) => @graph.Uri(x)
 

	
 
    return unless effect and effect.match(/^http/)
 

	
 
    # we could probably accept some initial overrides right on the
 
@@ -461,16 +472,16 @@ class TimeZoomed extends Polymer.Element
 
      if @graph.contains(effect, RDF + 'type', U(':LightSample'))
 
        effect = @project.makeEffect(effect)
 
      else
 
        log("drop #{effect} is not an effect")
 
        return
 

	
 
    dropTime = @zoomInX.invert(pos.e(1))
 
    dropTime = @viewState.zoomInX.invert(pos.e(1))
 

	
 
    desiredWidthX = @offsetWidth * .3
 
    desiredWidthT = @zoomInX.invert(desiredWidthX) - @zoomInX.invert(0)
 
    desiredWidthT = @viewState.zoomInX.invert(desiredWidthX) - @viewState.zoomInX.invert(0)
 
    desiredWidthT = Math.min(desiredWidthT, @zoom.duration() - dropTime)
 
    @project.makeNewNote(effect, dropTime, desiredWidthT)
 
        
 
customElements.define(TimeZoomed.is, TimeZoomed)
 

	
 
class TimeAxis extends Polymer.Element
0 comments (0 inline, 0 general)