Changeset - 46d1c0f0a5ce
[Not reviewed]
default
0 3 0
drewp@bigasterisk.com - 7 years ago 2018-06-08 11:50:13
drewp@bigasterisk.com
attempted redraw fixes, but the real problem is in autodeps
Ignore-this: 96cc361f1951d165131d46b8173b6685
3 files changed with 7 insertions and 2 deletions:
0 comments (0 inline, 0 general)
light9/web/timeline/adjustable.coffee
Show inline comments
 
@@ -65,123 +65,125 @@ class Adjustable
 
    if ev.touches?.length
 
      ev = ev.touches[0]
 

	
 
    # storing root on the object to remember it across calls in case
 
    # you drag outside the editor.
 
    @root = rootElem.getBoundingClientRect() if rootElem
 
    offsetParentPos = $V([ev.pageX - @root.left, ev.pageY - @root.top])
 

	
 
    return offsetParentPos
 

	
 
class window.AdjustableFloatObservable extends Adjustable
 
  constructor: (@config) ->
 
    # config also has:
 
    #   observable -> ko.observable we will read and write
 
    #   getValueForPos(pos) -> what should we set to if the user
 
    #                          moves target to this coord?
 
    super()
 
    @ctor2()
 

	
 
  _getValue: () ->
 
    @config.observable()
 

	
 
  continueDrag: (pos) ->
 
    # pos is vec2 of pixels relative to the drag start.
 
    super(pos)
 
    epos = @_editorCoordinates()
 
    newValue = @config.getValueForPos(epos)
 
    @config.observable(newValue)
 

	
 
  subscribe: (onChange) ->
 
    log('AdjustableFloatObservable subscribe', @config)
 
    ko.computed =>
 
      @config.observable()
 
      onChange()
 

	
 
class window.AdjustableFloatObject extends Adjustable
 
  constructor: (@config) ->
 
    # config also has:
 
    #   graph
 
    #   subj
 
    #   pred
 
    #   ctx
 
    #   getTargetPosForValue(value) -> getTarget result for value
 
    #   getValueForPos
 
    super()
 
    @ctor2()
 
    if not @config.ctx?
 
      throw new Error("missing ctx")
 
    # this seems to not fire enough.
 
    @config.graph.runHandler(@_syncValue.bind(@),
 
                             "adj sync #{@config.subj.value}")
 
                             "adj sync #{@config.subj.value} #{@config.pred.value}")
 

	
 
  _syncValue: () ->
 
    @_currentValue = @config.graph.floatValue(@config.subj, @config.pred)
 
    @_onChange() if @_onChange
 

	
 
  _getValue: () ->
 
    # this is a big speedup- callers use _getValue about 4x as much as
 
    # the graph changes and graph.floatValue is slow
 
    @_currentValue
 

	
 
  getTarget: () ->
 
    @config.getTargetPosForValue(@_getValue())
 

	
 
  subscribe: (onChange) ->
 
    # only works on one subscription at a time
 
    throw new Error('multi subscribe not implemented') if @_onChange
 
    @_onChange = onChange
 

	
 
  continueDrag: (pos) ->
 
    # pos is vec2 of pixels relative to the drag start
 
    super(pos)
 
    newValue = @config.getValueForPos(@_editorCoordinates())
 

	
 
    @config.graph.patchObject(@config.subj, @config.pred,
 
                              @config.graph.LiteralRoundedFloat(newValue),
 
                              @config.ctx)
 
    #@_syncValue()
 

	
 
class window.AdjustableFade extends Adjustable
 
  constructor: (@yForV, @zoomInX, @i0, @i1, @note, offset, ctx) ->
 
    super()
 
    @config = {
 
      getSuggestedTargetOffset: -> offset
 
      getTarget: @getTarget.bind(@)
 
      ctx: ctx
 
    }
 
    @ctor2()
 

	
 
  getTarget: ->
 
    mid = @note.midPoint(@i0, @i1)
 
    $V([@zoomInX(mid.e(1)), @yForV(mid.e(2))])
 

	
 
  _getValue: ->
 
    @note.midPoint(@i0, @i1).e(1)
 

	
 
  continueDrag: (pos) ->
 
    # pos is vec2 of pixels relative to the drag start
 
    super(pos)
 
    graph = @note.graph
 
    U = (x) -> graph.Uri(x)
 

	
 
    goalCenterSec = @zoomInX.invert(@initialTarget.e(1) + pos.e(1))
 

	
 
    diamSec = @note.worldPts[@i1].e(1) - @note.worldPts[@i0].e(1)
 
    newSec0 = goalCenterSec - diamSec / 2
 
    newSec1 = goalCenterSec + diamSec / 2
 

	
 
    originSec = graph.floatValue(@note.uri, U(':originTime'))
 

	
 
    p0 = @_makePatch(graph, @i0, newSec0, originSec, @config.ctx)
 
    p1 = @_makePatch(graph, @i1, newSec1, originSec, @config.ctx)
 

	
 
    graph.applyAndSendPatch(@_addPatches(p0, p1))
 

	
 
  _makePatch: (graph, idx, newSec, originSec, ctx) ->
 
    graph.getObjectPatch(@note.worldPts[idx].uri,
 
                         graph.Uri(':time'),
 
                         graph.LiteralRoundedFloat(newSec - originSec), ctx)
 

	
 
  _addPatches: (p0, p1) ->
 
    {
 
      addQuads: p0.addQuads.concat(p1.addQuads),
 
      delQuads: p0.delQuads.concat(p1.delQuads)
 
    }
 
\ No newline at end of file
light9/web/timeline/adjusters.coffee
Show inline comments
 
@@ -3,116 +3,118 @@ Drawing = window.Drawing
 

	
 
maxDist = 60
 

	
 
coffeeElementSetup(class AdjustersCanvas extends Polymer.mixinBehaviors([Polymer.IronResizableBehavior], Polymer.Element)
 
  @is: 'light9-adjusters-canvas'
 
  @getter_properties:
 
    setAdjuster: {type: Function, notify: true }
 
  @getter_observers: [
 
    'updateAllCoords(adjs)'
 
  ]
 
  constructor: ->
 
    super()
 
    @redraw = _.throttle(@_throttledRedraw.bind(@), 30, {leading: false})
 
    @adjs = {}
 
    @hoveringNear = null
 
    
 
  ready: ->
 
    super.ready()
 
    @addEventListener('iron-resize', @resizeUpdate.bind(@))
 
    @ctx = @$.canvas.getContext('2d')
 
    
 
    @redraw()
 
    @setAdjuster = @_setAdjuster.bind(@)
 

	
 
    # These don't fire; TimelineEditor calls the handlers for us.
 
    @addEventListener('mousedown', @onDown.bind(@))
 
    @addEventListener('mousemove', @onMove.bind(@))
 
    @addEventListener('mouseup', @onUp.bind(@))
 

	
 
  _mousePos: (ev) ->
 
    $V([ev.clientX, ev.clientY - @offsetParent.offsetTop])
 
  
 
  onDown: (ev) ->
 
    if ev.buttons == 1
 
      start = @_mousePos(ev)
 
      adj = @_adjAtPoint(start)
 
      if adj
 
        ev.stopPropagation()
 
        @currentDrag = {start: start, adj: adj}
 
        adj.startDrag()
 

	
 
  onMove: (ev) ->
 
    pos = @_mousePos(ev)
 
    if @currentDrag
 
      @hoveringNear = null
 
      @currentDrag.cur = pos
 
      @currentDrag.adj.continueDrag(
 
        @currentDrag.cur.subtract(@currentDrag.start))
 
      @redraw()
 
    else
 
      near = @_adjAtPoint(pos)
 
      if @hoveringNear != near
 
        @hoveringNear = near
 
        @redraw()
 

	
 
  onUp: (ev) ->
 
    return unless @currentDrag
 
    @currentDrag.adj.endDrag()
 
    @currentDrag = null
 
    
 
  _setAdjuster: (adjId, makeAdjustable) ->
 
    # callers register/unregister the Adjustables they want us to make
 
    # adjuster elements for. Caller invents adjId.  makeAdjustable is
 
    # a function returning the Adjustable or it is null to clear any
 
    # adjusters with this id.
 
    if not @adjs[adjId] or not makeAdjustable?
 
      if not makeAdjustable?
 
      if @adjs[adjId]
 
        delete @adjs[adjId]
 
      else
 
      # this might be able to reuse an existing one a bit
 
        adj = makeAdjustable()
 
        @adjs[adjId] = adj
 
        adj.id = adjId
 

	
 
    @redraw()
 

	
 
    window.debug_adjsCount = Object.keys(@adjs).length
 

	
 
  updateAllCoords: ->
 
    @redraw()
 

	
 
  _adjAtPoint: (pt) ->
 
    nearest = @qt.find(pt.e(1), pt.e(2))
 
    if not nearest? or nearest.distanceFrom(pt) > maxDist
 
      return null
 
    return nearest?.adj
 

	
 
  resizeUpdate: (ev) ->
 
    @$.canvas.width = ev.target.offsetWidth
 
    @$.canvas.height = ev.target.offsetHeight
 
    @canvasCenter = $V([@$.canvas.width / 2, @$.canvas.height / 2])
 
    @redraw()
 

	
 
  _throttledRedraw: () ->
 
    return unless @ctx?
 
    console.time('adjs redraw')
 
    @_layoutCenters()
 
    
 
    @ctx.clearRect(0, 0, @$.canvas.width, @$.canvas.height)
 

	
 
    for adjId, adj of @adjs
 
      ctr = adj.getHandle()
 
      target = adj.getTarget()
 
      if @_isOffScreen(target)
 
        continue
 
      @_drawConnector(ctr, target)
 
      
 
      @_drawAdjuster(adj.getDisplayValue(),
 
                     ctr.e(1) - 20, ctr.e(2) - 10,
 
                     ctr.e(1) + 20, ctr.e(2) + 10,
 
                     adj == @hoveringNear)
 
    console.timeEnd('adjs redraw')
 

	
 
  _layoutCenters: ->
 
    # push Adjustable centers around to avoid overlaps
 
    # Todo: also don't overlap inlineattr boxes
 
    # Todo: don't let their connector lines cross each other
 
    @qt = d3.quadtree([], ((d)->d.e(1)), ((d)->d.e(2)))
light9/web/timeline/timeline.coffee
Show inline comments
 
@@ -493,96 +493,97 @@ class Note
 
    p1 = @worldPts[i1]
 
    p0.x(.5).add(p1.x(.5))
 

	
 
  _planDrawing: ->
 
    U = (x) => @graph.Uri(x)
 
    [pointUris, worldPts] = @getCurvePoints(@uri, U(':strength'))
 
    effect = @graph.uriValue(@uri, U(':effectClass'))
 

	
 
    yForV = @brickLayout.yForVFor(@)
 
    dependOn = [@viewState.zoomSpec.t1(),
 
                @viewState.zoomSpec.t2(),
 
                @viewState.width()]
 
    screenPts = (new PIXI.Point(@viewState.zoomInX(pt.e(1)),
 
                                yForV(pt.e(2))) for pt in worldPts)
 
    return {
 
      yForV: yForV
 
      worldPts: worldPts
 
      screenPts: screenPts
 
      effect: effect
 
      hover: @uri.equals(@selection.hover())
 
      selected: @selection.selected().filter((s) => s.equals(@uri)).length
 
    }
 

	
 
  onRowChange: ->
 
    @clearAdjusters()
 
    @updateSoon()
 

	
 
  redraw: (params) ->
 
    # no observable or graph deps in here
 
    @container.removeChildren()
 
    @graphics = new PIXI.Graphics({nativeLines: false})
 
    @graphics.interactive = true
 
    @container.addChild(@graphics)
 

	
 
    if params.hover
 
      @_traceBorder(params.screenPts, 12, 0x888888)
 
    if params.selected
 
      @_traceBorder(params.screenPts, 6, 0xff2900)
 

	
 
    shape = new PIXI.Polygon(params.screenPts)
 
    @graphics.beginFill(@_noteColor(params.effect), .313)
 
    @graphics.drawShape(shape)
 
    @graphics.endFill()
 

	
 
    @_traceBorder(params.screenPts, 2, 0xffd900)
 

	
 
    @_addMouseBindings()
 
                 
 
                 
 
  update: ->
 
    if not @parentElem.isActiveNote(@uri)
 
      # stale redraw call
 
      return
 

	
 
    if @worldPts
 
      @brickLayout.setNoteSpan(@, @worldPts[0].e(1),
 
                               @worldPts[@worldPts.length - 1].e(1))
 

	
 
    params = @_planDrawing()
 
    @worldPts = params.worldPts
 

	
 
    @redraw(params)
 

	
 
    curveWidthCalc = () => @project.curveWidth(@worldPts)
 
    @_updateAdjusters(params.screenPts, @worldPts, curveWidthCalc,
 
                      params.yForV, @viewState.zoomInX, @song)
 
    @_updateInlineAttrs(params.screenPts, params.yForV)
 
    @parentElem.noteDirty()
 

	
 
  _traceBorder: (screenPts, thick, color) ->
 
    @graphics.lineStyle(thick, color, 1)
 
    @graphics.moveTo(screenPts[0].x, screenPts[0].y)
 
    for p in screenPts.slice(1)
 
      @graphics.lineTo(p.x, p.y)
 

	
 
  _addMouseBindings: () ->
 
    @graphics.on 'mousedown', (ev) =>
 
      @_onMouseDown(ev)
 

	
 
    @graphics.on 'mouseover', =>
 
      if @selection.hover() and @selection.hover().equals(@uri)
 
        # Hovering causes a redraw, which would cause another
 
        # mouseover event.
 
        return
 
      @selection.hover(@uri)
 

	
 
    # mouseout never fires since we rebuild the graphics on mouseover.
 
    @graphics.on 'mousemove', (ev) =>
 
      if @selection.hover() and @selection.hover().equals(@uri) and ev.target != @graphics
 
        @selection.hover(null)
 

	
 
  onUri: ->
 
    @graph.runHandler(@update.bind(@), "note updates #{@uri}")
 

	
 
  patchCouldAffectMe: (patch) ->
 
    if patch and patch.addQuads # sometimes patch is a polymer-sent value. @update is used as a listener too
 
      if patch.addQuads.length == patch.delQuads.length == 1
0 comments (0 inline, 0 general)