Changeset - e4825767a4bf
[Not reviewed]
default
0 4 0
Drew Perttula - 9 years ago 2016-06-04 07:43:45
drewp@bigasterisk.com
fixes to RDF adjusters. put graph load in an element.
Ignore-this: dfe48e2553769b4dfe17fc9041798e51
4 files changed with 123 insertions and 81 deletions:
0 comments (0 inline, 0 general)
light9/web/adjustable.coffee
Show inline comments
 
@@ -42,64 +42,71 @@ class Adjustable
 
    newValue = @dragStartValue + pos.e(0) * .1
 
    graph.patchObject(@_subj, @_pred, graph.Literal(newValue), @_ctx)
 

	
 
  endDrag: () ->
 
    0
 

	
 
  _editorCoordinates: () -> # vec2 of mouse relative to <l9-t-editor>
 
    ev = d3.event.sourceEvent
 

	
 
    if ev.target.tagName == "LIGHT9-TIMELINE-EDITOR"
 
      rootElem = ev.target
 
    else
 
      rootElem = ev.target.closest('light9-timeline-editor')
 

	
 
    # 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])
 

	
 
    setMouse(offsetParentPos) # for debugging
 
    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?
 

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

	
 
  _editorCoordinates: () -> # vec2 of mouse relative to <l9-t-editor>
 
    ev = d3.event.sourceEvent
 

	
 
    if ev.target.tagName == "LIGHT9-TIMELINE-EDITOR"
 
      rootElem = ev.target
 
    else
 
      rootElem = ev.target.closest('light9-timeline-editor')
 
    
 
    @root = rootElem.getBoundingClientRect() if rootElem
 
    offsetParentPos = $V([ev.pageX - @root.left, ev.pageY - @root.top])
 

	
 
    setMouse(offsetParentPos)
 
    return offsetParentPos 
 
    
 
  continueDrag: (pos) ->
 
    # pos is vec2 of pixels relative to the drag start.
 

	
 
    epos = @_editorCoordinates()
 
    log('offsetParentPos', epos.elements)
 
    
 
    newValue = @config.getValueForPos(epos)
 
    @config.observable(newValue)
 

	
 
  subscribe: (onChange) ->
 
    ko.computed =>
 
      @config.observable()
 
      onChange()
 

	
 
class window.AdjustableFloatObject extends Adjustable
 
  constructor: (@config) ->
 
    # config has graph, subj, pred, ctx, getSuggestedTargetOffset
 
    # config also has:
 
    #   graph
 
    #   subj
 
    #   pred
 
    #   ctx
 
    #   getTargetTransform(value) -> getTarget result for value
 
    #   getValueForPos
 

	
 
    super(@config)
 

	
 
  _getValue: () -> # for drag math
 
  _getValue: () ->
 
    @config.graph.floatValue(@config.subj, @config.pred)
 

	
 
  getCenter: () ->    
 
    $V([100 + 200 * @_getValue(), 200])
 

	
 
  getTarget: () ->
 
    @config.getTargetTransform(@_getValue())
 
    
 
  subscribe: (onChange) ->
 
    @config.graph.subscribe @config.subj, @config.pred, null, (patch) =>
 
      onChange()
 
    
 
  continueDrag: (pos) ->
 
    # pos is vec2 of pixels relative to the drag start
 
    
 
    newValue = @dragStartValue + pos.e(1) / 200
 
    newValue = @config.getValueForPos(@_editorCoordinates())
 
    @config.graph.patchObject(@config.subj, @config.pred, @config.graph.Literal(newValue), @_ctx)
light9/web/graph.coffee
Show inline comments
 
@@ -62,15 +62,15 @@ class window.SyncedGraph
 
                    
 
  quads: () -> # for debugging
 
    [q.subject, q.predicate, q.object, q.graph] for q in @graph.find()
 

	
 
  applyAndSendPatch: (patch, cb) ->
 
    @applyPatch(patch)
 
    #console.log('patch to server:')
 
    #console.log('  delete:', JSON.stringify(patch.delQuads))
 
    #console.log('  add:', JSON.stringify(patch.addQuads))
 
    console.log('patch to server:')
 
    console.log('  delete:', JSON.stringify(patch.delQuads))
 
    console.log('  add:', JSON.stringify(patch.addQuads))
 
    # post to server
 

	
 
  applyPatch: (patch) ->
 
    # In most cases you want applyAndSendPatch.
 
    # 
 
    # This is the only method that writes to the graph!
light9/web/timeline-elements.html
Show inline comments
 
<link rel="import" href="/lib/polymer/polymer.html">
 
<link rel="import" href="light9-timeline-audio.html">
 
<link rel="import" href="/lib/iron-resizable-behavior/iron-resizable-behavior.html">
 

	
 
<dom-module id="rdfdb-synced-graph">
 
  <template>
 
    <style>
 
     :host { display: none; }
 
    </style>
 
  </template>
 
  <script src="graph.js"></script>
 
  <script>
 
   Polymer({
 
       is: "rdfdb-synced-graph",
 
       properties: {
 
           graph: {type: Object, notify: true}
 
       },
 
       ready: function() {
 
           this.graph = new SyncedGraph('noServerYet', {
 
               '': 'http://light9.bigasterisk.com/',
 
               'xsd': 'http://www.w3.org/2001/XMLSchema#',
 
           });
 
           this.graph.loadTrig(
 
'          @prefix : <http://light9.bigasterisk.com/> .'+
 
'          @prefix dev: <http://light9.bigasterisk.com/device/> .'+
 
'          <http://example.com/> {'+
 
'            :demoResource0 :startTime 1; :endTime 120 .'+
 
'            :demoResource1 :startTime 13; :endTime 16 .'+
 
'            :demoResource2 :startTime 38; :endTime 60 .'+
 
'            :demoResource3 :startTime 56; :endTime 60 .'+
 
'            :demoResource4 :startTime 73; :endTime 74 .'+
 
'            :demoResource5 :startTime 91; :endTime 105 .'+
 
'            :demoResource6 :startTime 110; :endTime 120 .'+
 
'            :demoResource7 :startTime 133; :endTime 140 .'+
 
'          }');
 
       }
 
   });
 
  </script>
 
</dom-module>
 

	
 
<!-- Whole editor- include this on your page.
 
     Most coordinates are relative to this element.
 
   -->
 
<dom-module id="light9-timeline-editor">
 
  <template>
 
    <style>
 
     :host {
 
         background: #444;
 
         display: flex;
 
         flex-direction: column;
 
         position: relative;
 
         border: 1px solid black;
 
         overflow: hidden;
 
     }
 
     light9-timeline-audio {
 
         width: 100%;
 
         height: 30px;
 
     }
 
     light9-timeline-time-zoomed {
 
@@ -30,12 +67,15 @@
 
         position: fixed;
 
         right: 0;
 
         bottom: 0;
 
         }
 
    </style>
 
    <div>
 
      <rdfdb-synced-graph graph="{{graph}}">
 
       
 
      </rdfdb-synced-graph>
 
      timeline editor: song [uri] <button>unlink</button>
 
      <label><input type="checkbox"> follow player song choice</label>
 
    </div>
 
    <!--
 
         Old zoom menu:
 
         See current time .. esc
 
@@ -248,22 +288,12 @@
 
    </style>
 

	
 
    <template is="dom-repeat" items="{{adjs}}">
 
      <light9-timeline-adjuster dia="{{dia}}" adj="{{item}}"></light9-timeline-adjuster>
 
    </template>
 
  </template>
 
  <script>
 
   Polymer({
 
       is: "light9-timeline-adjusters",
 
       properties: {
 
           adjs: { type: Array },
 
           dia: { type: Object }
 
           
 
       }
 
   });
 
  </script>
 
</dom-module>
 

	
 
<!-- Yellow dotted handle that you can adjust to edit something.
 
     Knows an attribute to edit and the true screen location, even if
 
     parent <light9-timeline-adjusters> has offset us a bit to avoid a
 
     text overlap.
 
@@ -299,13 +329,13 @@
 
         padding: 5px;
 

	
 
         cursor: ew-resize;
 
         -webkit-user-select: none;
 
     }
 
     span.empty {
 
         width: 30px;
 
         width: 30px; /* todo: supposed to fill the whole visible section*/
 
         height: 13px;
 
         display: inline-block;
 
         background: rgba(0,0,0,0);
 
     }
 
    </style>
 
    <div id="top" style$="left: [[centerStyle.x]]px; top: [[centerStyle.y]]px">
 
@@ -334,9 +364,8 @@
 
</dom-module>
 

	
 
<script src="/lib/sylvester/sylvester.js"></script>
 
<script src="/lib/d3/build/d3.js"></script>
 
<script src="/lib/N3.js/browser/n3-browser.js"></script>
 
<script src="/lib/knockout/dist/knockout.js"></script>
 
<script src="graph.js"></script>
 
<script src="adjustable.js"></script>
 
<script src="timeline.js"></script>
light9/web/timeline.coffee
Show inline comments
 
log = console.log
 
window.graph = new SyncedGraph('noServerYet', {
 
'': 'http://light9.bigasterisk.com/',
 
'xsd', 'http://www.w3.org/2001/XMLSchema#',
 
  })
 
  
 
window.graph.loadTrig("
 
@prefix : <http://light9.bigasterisk.com/> .
 
@prefix dev: <http://light9.bigasterisk.com/device/> .
 

	
 
<http://example.com/> {
 
  :demoResource :startTime 110; :endTime 120 .
 
}
 
    ")
 

	
 
    
 
      
 
Polymer
 
  is: 'light9-timeline-editor'
 
  behaviors: [ Polymer.IronResizableBehavior ]
 
  properties:
 
    viewState: { type: Object }
 
    debug: {type: String}
 
    graph: {type: Object, notify: true}
 
    
 
  attached: ->
 
    @dia = @$.dia
 
    @viewState =
 
      zoomSpec:
 
        duration: ko.observable(190)
 
@@ -33,50 +19,56 @@ Polymer
 
        t: ko.observable(105)
 

	
 
    ko.computed =>
 
      @debug = ko.toJSON(@viewState)
 

	
 
    ko.computed =>
 
      @fullZoomX = d3.scaleLinear().domain([0, @viewState.zoomSpec.duration()]).range([0, @offsetWidth]) # need to update this if width changes or if duration changes
 
      @zoomInX = d3.scaleLinear().domain([@viewState.zoomSpec.t1(), @viewState.zoomSpec.t2()]).range([0, @offsetWidth]) # need to update this if width changes or if duration changes
 
      # todo: need to trigger this when @offsetWidth changes, too
 
      @fullZoomX = d3.scaleLinear().domain([0, @viewState.zoomSpec.duration()]).range([0, @offsetWidth])
 
      @zoomInX = d3.scaleLinear().domain([@viewState.zoomSpec.t1(), @viewState.zoomSpec.t2()]).range([0, @offsetWidth])
 
      @$.adjusters.updateAllCoords()
 

	
 
    animCursor = () => 
 
      #@viewState.cursor.t = 130 + 20 * Math.sin(Date.now() / 2000)
 
      @viewState.cursor.t = 130 + 20 * Math.sin(Date.now() / 2000)
 
      @$.dia.setCursor(@$.audio.offsetTop, @$.audio.offsetHeight,
 
                       @$.zoomed.$.time.offsetTop,
 
                       @$.zoomed.$.time.offsetHeight,
 
                       @fullZoomX, @zoomInX, @viewState.cursor)
 

	
 
      @viewState.zoomSpec.t1(80 + 10 * Math.sin(Date.now() / 3000))
 
      #@viewState.zoomSpec.t1(80 + 10 * Math.sin(Date.now() / 3000))
 
      
 
    #setInterval(animCursor, 50)
 
    setInterval(animCursor, 50)
 

	
 
    setTimeout(() =>
 
      @adjs = @makeZoomAdjs().concat(@persistDemo())
 
    , 100)
 
    , 500)
 

	
 
  persistDemo: ->
 
    ctx = graph.Uri('http://example.com/')
 
    return [
 
      new AdjustableFloatObject({
 
        graph: graph
 
        subj: graph.Uri(':demoResource')
 
        pred: graph.Uri(':startTime')
 
    ctx = @graph.Uri('http://example.com/')
 
    adjs = []
 
    for n in [0..7]
 
      subj = @graph.Uri(':demoResource'+n)
 
      adjs.push(new AdjustableFloatObject({
 
        graph: @graph
 
        subj: subj
 
        pred: @graph.Uri(':startTime')
 
        ctx: ctx
 
        getTarget: () => $V([200, 300])
 
        getTargetTransform: (value) => $V([@zoomInX(value), 300])
 
        getValueForPos: (pos) => @zoomInX.invert(pos.e(1))
 
        getSuggestedTargetOffset: () => $V([-30, 80])
 
      })
 
      new AdjustableFloatObject({
 
        graph: graph
 
        subj: graph.Uri(':demoResource')
 
        pred: graph.Uri(':endTime')
 
      }))
 
      adjs.push(new AdjustableFloatObject({
 
        graph: @graph
 
        subj: subj
 
        pred: @graph.Uri(':endTime')
 
        ctx: ctx
 
        getTarget: () => $V([300, 300])
 
        getTargetTransform: (value) => $V([@zoomInX(value), 300])
 
        getValueForPos: (pos) => @zoomInX.invert(pos.e(1))
 
        getSuggestedTargetOffset: () => $V([30, 100])
 
      })
 
      ]
 
      }))
 
    return adjs
 

	
 
  makeZoomAdjs: ->
 
    yMid = @$.audio.offsetTop + @$.audio.offsetHeight / 2
 
    dur = @viewState.zoomSpec.duration
 
    
 
    valForPos = (pos) =>
 
@@ -117,12 +109,23 @@ Polymer
 
      getSuggestedTargetOffset: () => $V([0, 0])
 
      getValueForPos: valForPos
 
      })
 
      
 
    return [left, right, pan]
 

	
 

	
 
Polymer
 
  is: "light9-timeline-adjusters"
 
  properties:
 
    adjs: { type: Array },
 
    dia: { type: Object }
 
  updateAllCoords: ->
 
    for elem in @querySelectorAll('light9-timeline-adjuster')
 
      elem.updateDisplay()
 
    
 

	
 
_adjusterSerial = 0
 

	
 
Polymer
 
  is: 'light9-timeline-adjuster'
 
  properties:
 
    adj:
 
@@ -138,13 +141,15 @@ Polymer
 
      type: Object
 
    spanClass:
 
      type: String
 
      value: ''
 

	
 
  onAdj: (adj) ->
 
    @adj.subscribe () =>
 
    @adj.subscribe(@updateDisplay.bind(this))
 

	
 
  updateDisplay: () ->
 
      @spanClass = if @adj.config.emptyBox then 'empty' else ''
 
      @displayValue = @adj.getDisplayValue()
 
      center = @adj.getCenter()
 
      @centerStyle = {x: center.e(1), y: center.e(2)}
 
      @dia?.setAdjusterConnector(@myId, @adj.getCenter(),
 
                                @adj.getTarget())
 
@@ -177,26 +182,21 @@ svgPathFromPoints = (pts) ->
 
  out
 

	
 
Polymer
 
  is: 'light9-timeline-diagram-layer'
 
  properties: {}
 
  ready: ->
 
    @elemById = {}
 
    window.setNote = @setNote.bind(this)
 
    window.setMouse = @setMouse.bind(this)
 
    @cursorPath =
 
      top: @querySelector('#cursor1')
 
      mid: @querySelector('#cursor2')
 
      bot: @querySelector('#cursor3')
 
    @elemById = {}
 

	
 
  setMouse: (pos) ->
 
    elem = @getOrCreateElem('mouse-x', 'mouse', 'path', {style: "fill:none;stroke:#333;stroke-width:0.5;"})
 
    elem.setAttribute('d', svgPathFromPoints([[-999, pos.e(2)], [999, pos.e(2)]]))
 
    elem = @getOrCreateElem('mouse-y', 'mouse', 'path', {style: "fill:none;stroke:#333;stroke-width:0.5;"})
 
    elem.setAttribute('d', svgPathFromPoints([[pos.e(1), -999], [pos.e(1), 999]]))
 
    
 
    elem.setAttribute('d', svgPathFromPoints([[pos.e(1), -999], [pos.e(1), 999]]))   
 

	
 
  getOrCreateElem: (uri, groupId, tag, attrs) ->
 
    elem = @elemById[uri]
 
    if !elem
 
      elem = @elemById[uri] = document.createElementNS("http://www.w3.org/2000/svg", tag)
 
      @$[groupId].appendChild(elem)
 
@@ -213,12 +213,18 @@ Polymer
 
      [x1 * .25 + x2 * .75, y1]
 
      [x2, y2]
 
    ])
 
    elem.setAttribute('d', d)
 

	
 
  setCursor: (y1, h1, y2, h2, fullZoomX, zoomInX, cursor) ->
 
    @cursorPath =
 
      top: @querySelector('#cursor1')
 
      mid: @querySelector('#cursor2')
 
      bot: @querySelector('#cursor3')
 
    return if !@cursorPath.top
 
    
 
    xZoomedOut = fullZoomX(cursor.t)
 
    xZoomedIn = zoomInX(cursor.t)
 
    @cursorPath.top.setAttribute 'd', svgPathFromPoints([
 
      [xZoomedOut, y1]
 
      [xZoomedOut, y1 + h1]
 
    ])
0 comments (0 inline, 0 general)