5 CLICK_FUZ = 10 # this far away from things is close enough to be "clicked on"
6 PROX_MAX = CLICK_FUZ * CLICK_FUZ
15 # json (compiled to javascript and minified) is ~8% smaller than the resulting xml
16 json_to_svg = (json) ->
17 for tag, attrs of json
18 el = document.createElementNS 'http://www.w3.org/2000/svg', tag
22 el.appendChild json_to_svg child
28 # public vars: x, y, width, height, el
31 constructor: (args) ->
35 @style = args.style ? STYLE_NORMAL
38 @width = args.width ? 50
39 @height = args.height ? 34
46 proximity: (xy) -> # return the square of the distance to your visible bits
49 return if @style is style
50 if style is STYLE_NORMAL
51 @el.setAttribute 'style', 'filter: url(#crayon)'
53 if @style is STYLE_NORMAL
54 @el.setAttribute 'style', ''
57 @el.setAttribute 'class', "#{@css_class}"
59 @el.setAttribute 'class', "#{@css_class} selected"
61 @el.setAttribute 'class', "#{@css_class} hover"
63 @el.setAttribute 'class', "#{@css_class} dragging"
64 # FIXME when STYLE_EDITING
66 controls: -> # create controls, return them
70 class RectWidget extends Widget
71 constructor: (args) ->
74 @el = json_to_svg rect:
80 style: if @style is STYLE_NORMAL then 'filter: url(#crayon)' else ''
86 return new RectWidget @
89 @el.setAttribute 'x', @x + 1
90 @el.setAttribute 'y', @y + 1
91 proximity: (xy) -> # return the square of the distance to your visible bits
97 if x > @x - CLICK_FUZ and x < @x + @width + CLICK_FUZ
99 if y < @y + @height / 2
102 new_prox = @y + @height - y
106 if y > @y - CLICK_FUZ and y < @y + @height + CLICK_FUZ
108 if x < @x + @width / 2
111 new_prox = @x + @width - x
115 if in_x and in_y and prox > PROX_MAX
118 controls: -> # create controls, return them
122 # called automatically on domcontentloaded
125 $container = $ '.crayon_mockup'
126 svg = json_to_svg svg: width: width, height: height, viewBox: "0 0 #{width} #{height}"
128 $container.append $svg
129 svg.appendChild json_to_svg filter:
130 id: 'crayon', filterUnits: 'userSpaceOnUse'
131 x: '-5%', y: '-5%', height: '110%', width: '110%'
133 { feTurbulence: baseFrequency: '.3', numOctaves: '2', type: 'fractalNoise' }
134 { feDisplacementMap: scale: '6', xChannelSelector: 'R', in: 'SourceGraphic' }
137 # create canvas border
138 svg.appendChild json_to_svg rect:
142 height: height - 2 - supply_height
143 class: 'canvas_border'
146 new RectWidget svg: svg
147 new RectWidget svg: svg, width: 12, height: 50
148 new RectWidget svg: svg, width: 70, height: 12
150 for widget, i in supply
152 x: 30 + i * 90 + (70 - widget.width) / 2
153 y: (supply_height - widget.height) / 2
159 editing = [] # has controls
161 dragging_offset = x: 0, y: 0 # from mouse x,y -> widget x,y
163 deselect_all = (args) ->
164 except = args?.except ? null
170 w.set_style STYLE_NORMAL
175 closest_widget = (widgets, xy) ->
179 new_prox = w.proximity xy
186 svg_event_to_xy = (e) ->
188 svg_offset = $svg.offset()
190 x: Math.round(e.pageX - svg_offset.left)
191 y: Math.round(e.pageY - svg_offset.top)
195 if dragging # two mousedowns in a row?! it happens
197 xy = svg_event_to_xy e
198 if xy.y < supply_height
199 closest = closest_widget supply, xy
201 closest = closest.clone()
202 on_canvas.push closest
204 closest = closest_widget on_canvas, xy
206 deselect_all except: closest
208 closest.set_style STYLE_DRAGGING
210 dragging_offset.x = closest.x - xy.x
211 dragging_offset.y = closest.y - xy.y
219 if w.y < supply_height
222 w.set_style STYLE_SELECTED
227 xy = svg_event_to_xy e
229 xy.x += dragging_offset.x
230 xy.y += dragging_offset.y
233 hover = closest_widget on_canvas, xy
235 hover = closest_widget supply, xy
236 if hover != prev_hover
239 if w.style is STYLE_HOVER and w isnt hover
240 w.set_style STYLE_SELECTED
242 if w.style is STYLE_HOVER and w isnt hover
243 w.set_style STYLE_NORMAL
245 if w.style is STYLE_HOVER and w isnt hover
246 w.set_style STYLE_NORMAL
248 hover.set_style STYLE_HOVER
250 $svg.mousedown mousedown
252 $svg.mousemove mousemove
253 #($ document).keydown (e) ->