+++ /dev/null
-# settings
-width = 800
-height = 600
-supply_height = 96
-CLICK_FUZ = 10 # this far away from things is close enough to be "clicked on"
-PROX_MAX = CLICK_FUZ * CLICK_FUZ
-
-# constants
-STYLE_NORMAL = 0
-STYLE_SELECTED = 1
-STYLE_HOVER = 2
-STYLE_EDITING = 3
-STYLE_DRAGGING = 4
-
-STYLE_TO_CLASS = [
- "normal"
- "selected"
- "hover"
- "editing"
- "dragging"
-]
-
-set_style_class = (args) ->
- args.el.setAttribute 'class', "#{args.class} #{STYLE_TO_CLASS[args.style]}"
-
-# json (compiled to javascript and minified) is ~8% smaller than the resulting xml
-json_to_svg = (json) ->
- for tag, attrs of json
- el = document.createElementNS 'http://www.w3.org/2000/svg', tag
- for k, v of attrs
- if k is 'children'
- for child in v
- el.appendChild json_to_svg child
- else if k is 'contents'
- el.appendChild document.createTextNode v
- else
- el.setAttribute k, v
- return el
-
-next_widget_id = 0
-# public vars: x, y, width, height, el
-class Visible
- # required args: svg
- constructor: (args) ->
- @id = next_widget_id
- next_widget_id += 1
- @svg = args.svg
- @x = args.x ? 1
- @y = args.y ? 1
- @width = args.width ? 50
- @height = args.height ? 34
- @style = args.style ? STYLE_NORMAL
- destruct: ->
- move: (args) ->
- @x = args.x
- @y = args.y
- proximity: (xy) -> # return the square of the distance to your visible bits
- return PROX_MAX + 1
- set_style: (style) ->
- @style = style
-
-class Control extends Visible
-
-class Widget extends Visible
- #sub-classes are expected to implement all of these:
- clone: ->
- return new Widget @
- controls: -> # create controls, return them
- return []
- hide_controls: ->
-
-class RectWidget extends Widget
- constructor: (args) ->
- super args
- @css_class = 'box'
- @el = json_to_svg rect:
- x: @x + 1
- y: @y + 1
- width: @width - 2
- height: @height - 2
- class: 'box normal'
- @svg.appendChild @el
- destruct: ->
- super()
- if @el?
- @svg.removeChild @el
- clone: ->
- return new RectWidget @
- set_style: (style) ->
- super style
- set_style_class el: @el, class: 'box', style: style
- move: (args) ->
- super args
- @el.setAttribute 'x', @x + 1
- @el.setAttribute 'y', @y + 1
- proximity: (xy) -> # return the square of the distance to your visible bits
- x = xy.x
- y = xy.y
- prox = PROX_MAX + 1
- in_x = false
- in_y = false
- if x > @x - CLICK_FUZ and x < @x + @width + CLICK_FUZ
- in_x = true
- if y < @y + @height / 2
- new_prox = @y - y
- else
- new_prox = @y + @height - y
- new_prox *= new_prox
- if new_prox < prox
- prox = new_prox
- if y > @y - CLICK_FUZ and y < @y + @height + CLICK_FUZ
- in_y = true
- if x < @x + @width / 2
- new_prox = @x - x
- else
- new_prox = @x + @width - x
- new_prox *= new_prox
- if new_prox < prox
- prox = new_prox
- if in_x and in_y and prox > PROX_MAX
- prox = PROX_MAX - 1
- return prox
- controls: -> # create controls, return them
- return []
- hide_controls: ->
-
-# called automatically on domcontentloaded
-init = ->
- svg_offset = null
- $container = $ '.crayon_mockup'
- svg = json_to_svg svg: width: width, height: height, viewBox: "0 0 #{width} #{height}"
- $svg = $ svg
- $container.append $svg
- svg.appendChild json_to_svg filter:
- id: 'crayon', filterUnits: 'userSpaceOnUse'
- x: '-5%', y: '-5%', height: '110%', width: '110%'
- children: [
- { feTurbulence: baseFrequency: '.3', numOctaves: '2', type: 'fractalNoise' }
- { feDisplacementMap: scale: '6', xChannelSelector: 'R', in: 'SourceGraphic' }
- ]
- svg.appendChild json_to_svg style:
- type: 'text/css'
- contents: '.box.normal,.box.hover,.box.selected{filter: url(#crayon)}'
-
- # create canvas border
- svg.appendChild json_to_svg rect:
- x: 1
- y: supply_height + 1
- width: width - 2
- height: height - 2 - supply_height
- class: 'canvas_border'
-
- supply = {}
- for args, i in [
- { width: 40, height: 40 }
- { width: 12, height: 50 }
- { width: 70, height: 12 }
- ]
- widget = new RectWidget {
- width: args.width
- height: args.height
- x: 30 + i * 90 + (70 - args.width) / 2
- y: (supply_height - args.height) / 2
- svg: svg
- }
- supply[widget.id] = widget
-
- # editor state
- on_canvas = {}
- selected = {}
- editing = {} # has controls
- dragging = false
- drag_from = x: 0, y: 0 # mouse was here at last frame of drag
- shift_key_down = false
-
- deselect_all = (args) ->
- except = args?.except ? null
- for id, w of selected
- w.set_style STYLE_NORMAL
- delete selected[id]
- closest_widget = (widgets, xy) ->
- prox = PROX_MAX + 1
- closest = null
- for id, w of widgets
- new_prox = w.proximity xy
- if new_prox < prox
- prox = new_prox
- closest = w
- if prox < PROX_MAX
- return closest
- return null
- svg_event_to_xy = (e) ->
- unless svg_offset?
- svg_offset = $svg.offset()
- return {
- x: Math.round(e.pageX - svg_offset.left)
- y: Math.round(e.pageY - svg_offset.top)
- }
- mousedown = (e) ->
- mousemove e
- if dragging # two mousedowns in a row?! it happens
- return mouseup e
- xy = svg_event_to_xy e
- if xy.y < supply_height
- closest = closest_widget supply, xy
- if closest?
- closest = closest.clone()
- on_canvas[closest.id] = closest
- else
- closest = closest_widget on_canvas, xy
- if closest?
- unless (shift_key_down or selected[closest.id]?)
- deselect_all except: closest
- selected[closest.id] = closest
- closest.set_style STYLE_DRAGGING
- dragging = true
- drag_from = xy
- else
- deselect_all()
- return false
- mouseup = (e) ->
- mousemove e
- if dragging
- for id, w of selected
- if w.y < supply_height
- w.destruct()
- delete selected[id]
- else
- w.set_style STYLE_SELECTED
- dragging = false
- return false
- prev_hover = null
- mousemove = (e) ->
- xy = svg_event_to_xy e
- if dragging
- return if drag_from.x is xy.x and drag_from.y is xy.y
- rel_x = xy.x - drag_from.x
- rel_y = xy.y - drag_from.y
- drag_from = xy
- for id, w of selected
- w.move x: w.x + rel_x, y: w.y + rel_y
- else
- hover = closest_widget on_canvas, xy
- unless hover?
- hover = closest_widget supply, xy
- if hover != prev_hover
- if prev_hover?
- # FIXME
- if selected[prev_hover.id]?
- prev_hover.set_style STYLE_SELECTED
- else
- prev_hover.set_style STYLE_NORMAL
- if hover?
- hover.set_style STYLE_HOVER
- prev_hover = hover
- return false
- $svg.mousedown mousedown
- $svg.mouseup mouseup
- $svg.mousemove mousemove
- $(document).on 'keyup keydown', (e) ->
- shift_key_down = e.shiftKey
- return true
- #($ document).keydown (e) ->
-
-$ init