Changeset - b4633fb9bccf
[Not reviewed]
default
0 2 0
Drew Perttula - 7 years ago 2018-05-07 00:38:56
drewp@bigasterisk.com
extract Project class with the larger graph-only methods
Ignore-this: e0d79e45fb053d8b7e228b6eb5687eba
2 files changed with 97 insertions and 89 deletions:
0 comments (0 inline, 0 general)
light9/web/timeline/timeline-elements.html
Show inline comments
 
@@ -62,12 +62,13 @@
 
      <light9-timeline-audio id="audio"
 
                             graph="{{graph}}"
 
                             show="{{show}}"
 
                             song="{{song}}"></light9-timeline-audio>
 
      <light9-timeline-time-zoomed id="zoomed"
 
                                   graph="{{graph}}"
 
                                   project="{{project}}"
 
                                   selection="{{selection}}"
 
                                   dia="{{dia}}"
 
                                   set-adjuster="{{setAdjuster}}"
 
                                   song="{{song}}"
 
                                   show="{{show}}"
 
                                   zoom="{{viewState.zoomSpec}}"
light9/web/timeline/timeline.coffee
Show inline comments
 
log = console.log
 
RDF = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
 
Drawing = window.Drawing
 
ROW_COUNT = 7
 

	
 
class Project
 
  constructor: (@graph) ->
 

	
 
  makeEffect: (uri) ->
 
    U = (x) => @graph.Uri(x)
 
    effect = U(uri + '/effect')
 
    quad = (s, p, o) => {subject: s, predicate: p, object: o, graph: effect}
 
    
 
    quads = [
 
      quad(effect, U('rdf:type'), U(':Effect')),
 
      quad(effect, U(':copiedFrom'), uri),
 
      quad(effect, U('rdfs:label'), @graph.Literal(uri.replace(/.*capture\//, ''))),
 
      quad(effect, U(':publishAttr'), U(':strength')),
 
      ]
 

	
 
    fromSettings = @graph.objects(uri, U(':setting'))
 

	
 
    toSettings = @graph.nextNumberedResources(effect + '_set', fromSettings.length)
 
      
 
    for fs in fromSettings
 
      ts = toSettings.pop()
 
      # full copies of these since I may have to delete captures
 
      quads.push(quad(effect, U(':setting'), ts))
 
      quads.push(quad(ts, U(':device'), @graph.uriValue(fs, U(':device'))))
 
      quads.push(quad(ts, U(':deviceAttr'), @graph.uriValue(fs, U(':deviceAttr'))))
 
      try
 
        quads.push(quad(ts, U(':value'), @graph.uriValue(fs, U(':value'))))
 
      catch
 
        quads.push(quad(ts, U(':scaledValue'), @graph.uriValue(fs, U(':scaledValue'))))
 

	
 
    @graph.applyAndSendPatch({delQuads: [], addQuads: quads})
 
    return effect
 

	
 
  makeNewNote: (effect, dropTime, desiredWidthT) ->
 
    U = (x) => @graph.Uri(x)
 
    quad = (s, p, o) => {subject: s, predicate: p, object: o, graph: @song}
 
      
 
    newNote = @graph.nextNumberedResource("#{@song}/n")
 
    newCurve = @graph.nextNumberedResource("#{newNote}c")
 
    points = @graph.nextNumberedResources("#{newCurve}p", 4)
 

	
 
    curveQuads = [
 
        quad(@song, U(':note'), newNote)
 
        quad(newNote, RDF + 'type', U(':Note'))
 
        quad(newNote, U(':originTime'), @graph.LiteralRoundedFloat(dropTime))
 
        quad(newNote, U(':effectClass'), effect)
 
        quad(newNote, U(':curve'), newCurve)
 
        quad(newCurve, RDF + 'type', U(':Curve'))
 
        quad(newCurve, U(':attr'), U(':strength'))
 
      ]        
 
    pointQuads = []
 

	
 
   
 
    
 
    for i in [0...4]
 
      pt = points[i]
 
      pointQuads.push(quad(newCurve, U(':point'), pt))
 
      pointQuads.push(quad(pt, U(':time'), @graph.LiteralRoundedFloat(i/3 * desiredWidthT)))
 
      pointQuads.push(quad(pt, U(':value'), @graph.LiteralRoundedFloat(i == 1 or i == 2)))
 

	
 
    patch = {
 
      delQuads: []
 
      addQuads: curveQuads.concat(pointQuads)
 
      }
 
    @graph.applyAndSendPatch(patch)
 
    
 
  getCurvePoints: (curve, xOffset) ->
 
    worldPts = []
 
    uris = @graph.objects(curve, @graph.Uri(':point'))
 
    for pt in uris
 
      v = $V([xOffset + @graph.floatValue(pt, @graph.Uri(':time')),
 
              @graph.floatValue(pt, @graph.Uri(':value'))])
 
      v.uri = pt
 
      worldPts.push(v)
 
    worldPts.sort((a,b) -> a.e(1) > b.e(1))
 
    return [uris, worldPts]
 

	
 
  curveWidth: (worldPts) ->
 
    tMin = @graph.floatValue(worldPts[0].uri, @graph.Uri(':time'))
 
    tMax = @graph.floatValue(worldPts[3].uri, @graph.Uri(':time'))
 
    tMax - tMin
 
      
 
  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 TimelineEditor extends Polymer.Element
 
  @is: 'light9-timeline-editor'
 
  @behaviors: [ Polymer.IronResizableBehavior ]
 
  @properties:
 
    viewState: { type: Object }
 
    debug: {type: String}
 
@@ -54,13 +141,14 @@ class TimelineEditor extends Polymer.Ele
 
      cursor:
 
        t: ko.observable(20)
 
      mouse:
 
        pos: ko.observable($V([0,0]))
 
    @fullZoomX = d3.scaleLinear()
 
    @zoomInX = d3.scaleLinear()
 
    #@setAdjuster = @$.adjustersCanvas.setAdjuster.bind(@$.adjustersCanvas)
 
    @setAdjuster = (adjId, makeAdjustable) =>
 
      @$.adjustersCanvas.setAdjuster(adjId, makeAdjustable)
 

	
 
    setInterval(@updateDebugSummary.bind(@), 100)
 

	
 
    #if anchor == loadtest
 
    #  add note and delete it repeatedly
 
    #  disconnect the graph, make many notes, drag a point over many steps, measure lag somewhere
 
@@ -209,13 +297,13 @@ class TimelineEditor extends Polymer.Ele
 
        @animatedZoom(newCenter - visSeconds / 2,
 
                      newCenter + visSeconds / 2, zoomAnimSec)
 
    shortcut.add "L", =>
 
      @$.adjustersCanvas.updateAllCoords()
 
    shortcut.add 'Delete', =>
 
      for note in @selection.selected()
 
        deleteNote(@graph, @song, note, @selection)
 
        @project.deleteNote(@song, note, @selection)
 

	
 
  makeZoomAdjs: ->
 
    yMid = => @$.audio.offsetTop + @$.audio.offsetHeight / 2
 
    dur = @viewState.zoomSpec.duration
 
    
 
    valForPos = (pos) =>
 
@@ -264,25 +352,26 @@ customElements.define(TimelineEditor.is,
 
# the brick layout. update only changing adjusters.
 
class TimeZoomed extends Polymer.Element
 
  @is: 'light9-timeline-time-zoomed'
 
  @behaviors: [ Polymer.IronResizableBehavior ]
 
  @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 }
 
  @observers: [
 
    'onGraph(graph, dia, setAdjuster, song, zoomInX)'
 
  ]
 
  @listeners: {'iron-resize': 'update'}
 
  update: ->
 
    @renderer.resize(@clientWidth, @clientHeight)
 
    @renderer.render(@stage);
 
    @renderer.render(@stage)
 

	
 
  onZoom: ->
 
    updateZoomFlattened = ->
 
      log('updateZoomFlattened')
 
      @zoomFlattened = ko.toJS(@zoom)
 
    ko.computed(updateZoomFlattened.bind(@))
 
@@ -311,12 +400,13 @@ class TimeZoomed extends Polymer.Element
 
     
 
     @stage.addChild(graphics);
 
     @renderer.render(@stage);
 

	
 
     # iron-resize should be doing this but it never fires
 
     setInterval(@update.bind(@), 1000)
 
    
 
  onGraph: ->
 
    U = (x) => @graph.Uri(x)
 
    log('assign rows',@song)
 

	
 
    for uri in _.sortBy(@graph.objects(@song, U(':note')), 'uri')
 
      #should only make new ones
 
@@ -332,85 +422,24 @@ class TimeZoomed extends Polymer.Element
 

	
 
    # we could probably accept some initial overrides right on the
 
    # effect uri, maybe as query params
 

	
 
    if not @graph.contains(effect, RDF + 'type', U(':Effect'))
 
      if @graph.contains(effect, RDF + 'type', U(':LightSample'))
 
        effect = @makeEffect(effect)
 
        effect = @project.makeEffect(effect)
 
      else
 
        log("drop #{effect} is not an effect")
 
        return
 

	
 
    dropTime = @zoomInX.invert(pos.e(1))
 
    @makeNewNote(effect, dropTime)
 

	
 
  makeEffect: (uri) ->
 
    U = (x) => @graph.Uri(x)
 
    effect = U(uri + '/effect')
 
    quad = (s, p, o) => {subject: s, predicate: p, object: o, graph: effect}
 
    
 
    quads = [
 
      quad(effect, U('rdf:type'), U(':Effect')),
 
      quad(effect, U(':copiedFrom'), uri),
 
      quad(effect, U('rdfs:label'), @graph.Literal(uri.replace(/.*capture\//, ''))),
 
      quad(effect, U(':publishAttr'), U(':strength')),
 
      ]
 

	
 
    fromSettings = @graph.objects(uri, U(':setting'))
 

	
 
    toSettings = @graph.nextNumberedResources(effect + '_set', fromSettings.length)
 
      
 
    for fs in fromSettings
 
      ts = toSettings.pop()
 
      # full copies of these since I may have to delete captures
 
      quads.push(quad(effect, U(':setting'), ts))
 
      quads.push(quad(ts, U(':device'), @graph.uriValue(fs, U(':device'))))
 
      quads.push(quad(ts, U(':deviceAttr'), @graph.uriValue(fs, U(':deviceAttr'))))
 
      try
 
        quads.push(quad(ts, U(':value'), @graph.uriValue(fs, U(':value'))))
 
      catch
 
        quads.push(quad(ts, U(':scaledValue'), @graph.uriValue(fs, U(':scaledValue'))))
 

	
 
    @graph.applyAndSendPatch({delQuads: [], addQuads: quads})
 
    return effect
 
        
 
  makeNewNote: (effect, dropTime) ->
 
    U = (x) => @graph.Uri(x)
 
    quad = (s, p, o) => {subject: s, predicate: p, object: o, graph: @song}
 
      
 
    newNote = @graph.nextNumberedResource("#{@song}/n")
 
    newCurve = @graph.nextNumberedResource("#{newNote}c")
 
    points = @graph.nextNumberedResources("#{newCurve}p", 4)
 

	
 
    curveQuads = [
 
        quad(@song, U(':note'), newNote)
 
        quad(newNote, RDF + 'type', U(':Note'))
 
        quad(newNote, U(':originTime'), @graph.LiteralRoundedFloat(dropTime))
 
        quad(newNote, U(':effectClass'), effect)
 
        quad(newNote, U(':curve'), newCurve)
 
        quad(newCurve, RDF + 'type', U(':Curve'))
 
        quad(newCurve, U(':attr'), U(':strength'))
 
      ]        
 
    pointQuads = []
 

	
 
    desiredWidthX = @offsetWidth * .3
 
    desiredWidthT = @zoomInX.invert(desiredWidthX) - @zoomInX.invert(0)
 
    desiredWidthT = Math.min(desiredWidthT, @zoom.duration() - dropTime)
 
    
 
    for i in [0...4]
 
      pt = points[i]
 
      pointQuads.push(quad(newCurve, U(':point'), pt))
 
      pointQuads.push(quad(pt, U(':time'), @graph.LiteralRoundedFloat(i/3 * desiredWidthT)))
 
      pointQuads.push(quad(pt, U(':value'), @graph.LiteralRoundedFloat(i == 1 or i == 2)))
 

	
 
    patch = {
 
      delQuads: []
 
      addQuads: curveQuads.concat(pointQuads)
 
      }
 
    @graph.applyAndSendPatch(patch)
 

	
 
    @project.makeNewNote(effect, dropTime, desiredWidthT)
 
        
 
customElements.define(TimeZoomed.is, TimeZoomed)
 

	
 
class TimeAxis extends Polymer.Element
 
  @is: "light9-timeline-time-axis",
 
  # for now since it's just one line calling dia,
 
  # light9-timeline-editor does our drawing work.
 
@@ -552,28 +581,12 @@ class Note
 
      display: if rightX - leftX > w then 'block' else 'none'
 
      }
 
    if wasHidden and @inlineRect.display != 'none'
 
      @async =>
 
        @querySelector('light9-timeline-note-inline-attrs')?.displayed()
 
    
 
  _getCurvePoints: (curve, xOffset) ->
 
    worldPts = []
 
    uris = @graph.objects(curve, @graph.Uri(':point'))
 
    for pt in uris
 
      v = $V([xOffset + @graph.floatValue(pt, @graph.Uri(':time')),
 
              @graph.floatValue(pt, @graph.Uri(':value'))])
 
      v.uri = pt
 
      worldPts.push(v)
 
    worldPts.sort((a,b) -> a.e(1) > b.e(1))
 
    return [uris, worldPts]
 

	
 
  _curveWidth: (worldPts) ->
 
    tMin = @graph.floatValue(worldPts[0].uri, @graph.Uri(':time'))
 
    tMax = @graph.floatValue(worldPts[3].uri, @graph.Uri(':time'))
 
    tMax - tMin
 
    
 
  _makeCurvePointAdjusters: (yForV, worldPts, ctx) ->
 
    for pointNum in [0...worldPts.length]
 
      @_makePointAdjuster(yForV, worldPts, pointNum, ctx)
 

	
 
  _makePointAdjuster: (yForV, worldPts, pointNum, ctx) ->
 
    U = (x) => @graph.Uri(x)
 
@@ -633,18 +646,12 @@ class Note
 
  _suggestedOffset: (pt) ->
 
    if pt.e(2) > .5
 
      $V([0, 30])
 
    else
 
      $V([0, -30])
 
    
 
    
 
deleteNote = (graph, 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 DiagramLayer extends Polymer.Element
 
  # note boxes. 
 
  @is: 'light9-timeline-diagram-layer'
 
  @properties: {
0 comments (0 inline, 0 general)