Files @ 2ce77421c0b7
Branch filter:

Location: light9/web/paint/paint-elements.coffee - annotation

drewp@bigasterisk.com
put a big time display on ascoltami
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
4556eebe5d73
log = debug('paint')
debug.enable('paint')

class Painting
  constructor: (@svg) ->
    @strokes = []

  setSize: (@size) ->

  startStroke: (pos, color) ->
    stroke = new Stroke(pos, color, @size)
    stroke.appendElem(@svg)
    @strokes.push(stroke)
    return stroke

  hover: (pos) ->
    @clear()
    s = @startStroke(pos, '#ffffff', @size)
    r = .02
    steps = 5
    for ang in [0..steps]
      ang = 6.28 * ang / steps
      s.move([pos[0] + r * Math.sin(ang), pos[1] + 1.5 * r * Math.cos(ang)])

  getDoc: ->
    {strokes: @strokes}

  clear: ->
    s.removeElem() for s in @strokes
    @strokes = []

class Stroke
  constructor: (pos, @color, @size) ->
    @path = document.createElementNS('http://www.w3.org/2000/svg', 'path')
    @path.setAttributeNS(null, 'd', "M #{pos[0]*@size[0]} #{pos[1]*@size[1]}")
    @pts = [pos]
    @lastPos = pos

  appendElem: (parent) ->
    parent.appendChild(@path)

  removeElem: ->
    @path.remove()
    
  move: (pos) ->
    if Math.hypot(pos[0] - @lastPos[0], pos[1] - @lastPos[1]) < .02
      return
    @path.attributes.d.value += " L #{pos[0]*@size[0]} #{pos[1]*@size[1]}"
    @pts.push(pos)
    @lastPos = pos

  finish: () ->

Polymer
  is: "light9-paint-canvas"
  behaviors: [ Polymer.IronResizableBehavior ]
  listeners: 'iron-resize': 'onResize'
  properties: {
    bg: { type: String },
    tool: { type: String, value: 'hover' },
    painting: { type: Object } # output
  }
  ready: ->
    @painting = new Painting(@$.paint)
    @onResize()
    @$.paint.addEventListener('mousedown', @onDown.bind(@))
    @$.paint.addEventListener('mousemove', @onMove.bind(@))
    @$.paint.addEventListener('mouseup', @onUp.bind(@))
    @$.paint.addEventListener('touchstart', @onDown.bind(@))
    @$.paint.addEventListener('touchmove', @onMove.bind(@))
    @$.paint.addEventListener('touchend', @onUp.bind(@))

    @hover = _.throttle((ev) =>
          @painting.hover(@evPos(ev))
          @scopeSubtree(@$.paint)
          @fire('paintingChanged', @painting)
        , 100)

  evPos: (ev) ->
    px = (if ev.touches?.length? then [Math.round(ev.touches[0].clientX),
                                       Math.round(ev.touches[0].clientY)] else [ev.x, ev.y])
    return [px[0] / @size[0], px[1] / @size[1]]

  onClear: () ->
    @painting.clear()
    @fire('paintingChanged', @painting)
    
  onDown: (ev) ->
    switch @tool
      when "hover"
        @onMove(ev)
      when "paint"
        # if it's on an existing one, do selection
        @currentStroke = @painting.startStroke(@evPos(ev), '#aaaaaa')
    @scopeSubtree(@$.paint)

  onMove: (ev) ->
    switch @tool
      when "hover"
        @hover(ev)

      when "paint"
        # ..or move selection
        return unless @currentStroke
        @currentStroke.move(@evPos(ev))

  onUp: (ev) ->
    return unless @currentStroke
    @currentStroke.finish()
    @currentStroke = null
    
    @notifyPath('painting.strokes.length') # not working
    @fire('paintingChanged', @painting)

  onResize: (ev) ->
    @size = [@$.parent.offsetWidth, @$.parent.offsetHeight]
    @$.paint.attributes.viewBox.value = "0 0 #{@size[0]} #{@size[1]}"
    @painting.setSize(@size)


Polymer
  is: "light9-simulation"
  properties: {
    graph: { type: Object }
    layers: { type: Object }
    solution: { type: Object }
  }
  listeners: [
    "onLayers(layers)"
  ]
  ready: ->
    null
  onLayers: (layers) ->
    log('upd', layers)


Polymer
  is: "light9-device-settings",
  properties: {
    graph: { type: Object }
    subj: {type: String, notify: true},
    label: {type: String, notify: true},
    attrs: {type: Array, notify: true},
  },
  observers: [
    'onSubj(graph, subj)'
  ]
  ready: ->
    @label = "aura2"
    @attrs = [
        {attr: 'rx', val: .03},
        {attr: 'color', val: '#ffe897'},
    ]
  onSubj: (graph, @subj) ->
    graph.runHandler(@loadAttrs.bind(@), "loadAttrs #{@subj}")
  loadAttrs: ->
    U = (x) => @graph.Uri(x)
    @attrs = []
    for s in @graph.objects(U(@subj), U(':setting'))
      attr = @graph.uriValue(s, U(':deviceAttr'))
      attrLabel = @graph.stringValue(attr, U('rdfs:label'))
      @attrs.push({attr: attrLabel, val: @settingValue(s)})
    @attrs = _.sortBy(@attrs, 'attr')

  settingValue: (s) ->
    U = (x) => @graph.Uri(x)
    for pred in [U(':value'), U(':scaledValue')]
      try
        return @graph.stringValue(s, pred)
      catch
        null
      try
        return @graph.floatValue(s, pred)
      catch
        null
    throw new Error("no value for #{s}")
    
Polymer
  is: "light9-paint"
  properties: {
    painting: { type: Object }
    client: { type: Object }
    graph: { type: Object }
  }

  ready: () ->
    # couldn't make it work to bind to painting's notifyPath events
    @$.canvas.addEventListener('paintingChanged', @paintingChanged.bind(@))
    @$.solve.addEventListener('response', @onSolve.bind(@))

    @clientSendThrottled = _.throttle(@client.send.bind(@client), 60)
    @bestMatchPending = false
    
  paintingChanged: (ev) ->
    U = (x) => @graph.Uri(x)

    @painting = ev.detail
    @$.solve.body = JSON.stringify(@painting.getDoc())
    #@$.solve.generateRequest()

    @$.bestMatches.body = JSON.stringify({
      painting: @painting.getDoc(),
      devices: [
        U('dev:aura1'), U('dev:aura2'), U('dev:aura3'), U('dev:aura4'), U('dev:aura5'),
        U('dev:q1'), U('dev:q2'), U('dev:q3'),
        ]})

    send = =>
      @$.bestMatches.generateRequest().completes.then (r) =>
        @clientSendThrottled(r.response.settings)
        if @bestMatchPending
          @bestMatchPending = false
          send()
    
    if @$.bestMatches.loading
      @bestMatchPending = true
    else
      send()

  onSolve: (response) ->
    U = (x) => @graph.Uri(x)

    sample = @$.solve.lastResponse.bestMatch.uri
    settingsList = []
    for s in @graph.objects(sample, U(':setting'))
      try
        v = @graph.floatValue(s, U(':value'))
      catch
        v = @graph.stringValue(s, U(':scaledValue'))
      row = [@graph.uriValue(s, U(':device')), @graph.uriValue(s, U(':deviceAttr')), v]
      settingsList.push(row)
    @client.send(settingsList)