1 # Copyright 2015 Jason Woofenden
3 # This program is free software: you can redistribute it and/or modify it under
4 # the terms of the GNU General Public License as published by the Free Software
5 # Foundation, either version 3 of the License, or (at your option) any later
8 # This program is distributed in the hope that it will be useful, but WITHOUT
9 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 # You should have received a copy of the GNU General Public License along with
14 # this program. If not, see <http://www.gnu.org/licenses/>.
21 CLICK_FUZ = 10 # this far away from things is close enough to be "clicked on"
22 PROX_MAX = CLICK_FUZ * CLICK_FUZ
39 set_style_class = (args) ->
40 args.el.setAttribute 'class', "#{args.class} #{STYLE_TO_CLASS[args.style]}"
42 # json (compiled to javascript and minified) is ~8% smaller than the resulting xml
43 json_to_svg = (json) ->
44 for tag, attrs of json
45 el = document.createElementNS 'http://www.w3.org/2000/svg', tag
49 el.appendChild json_to_svg child
50 else if k is 'contents'
51 el.appendChild document.createTextNode v
57 # public vars: x, y, width, height, el
60 constructor: (args) ->
66 @width = args.width ? 50
67 @height = args.height ? 34
68 @style = args.style ? STYLE_NORMAL
73 proximity: (xy) -> # return the square of the distance to your visible bits
78 class Control extends Visible
80 class Widget extends Visible
81 #sub-classes are expected to implement all of these:
84 controls: -> # create controls, return them
88 class RectWidget extends Widget
89 constructor: (args) ->
92 @el = json_to_svg rect:
104 return new RectWidget @
105 set_style: (style) ->
107 set_style_class el: @el, class: 'box', style: style
110 @el.setAttribute 'x', @x + 1
111 @el.setAttribute 'y', @y + 1
112 proximity: (xy) -> # return the square of the distance to your visible bits
118 if x > @x - CLICK_FUZ and x < @x + @width + CLICK_FUZ
120 if y < @y + @height / 2
123 new_prox = @y + @height - y
127 if y > @y - CLICK_FUZ and y < @y + @height + CLICK_FUZ
129 if x < @x + @width / 2
132 new_prox = @x + @width - x
136 if in_x and in_y and prox > PROX_MAX
139 controls: -> # create controls, return them
143 # called automatically on domcontentloaded
146 $container = $ '.crayon_mockup'
147 svg = json_to_svg svg: width: width, height: height, viewBox: "0 0 #{width} #{height}"
149 $container.append $svg
150 svg.appendChild json_to_svg filter:
151 id: 'crayon', filterUnits: 'userSpaceOnUse'
152 x: '-5%', y: '-5%', height: '110%', width: '110%'
154 { feTurbulence: baseFrequency: '.3', numOctaves: '2', type: 'fractalNoise' }
155 { feDisplacementMap: scale: '6', xChannelSelector: 'R', in: 'SourceGraphic' }
157 svg.appendChild json_to_svg style:
159 contents: '.box.normal,.box.hover,.box.selected{filter: url(#crayon)}'
161 # create canvas border
162 svg.appendChild json_to_svg rect:
166 height: height - 2 - supply_height
167 class: 'canvas_border'
171 { width: 40, height: 40 }
172 { width: 12, height: 50 }
173 { width: 70, height: 12 }
175 widget = new RectWidget {
178 x: 30 + i * 90 + (70 - args.width) / 2
179 y: (supply_height - args.height) / 2
182 supply[widget.id] = widget
187 editing = {} # has controls
189 drag_from = x: 0, y: 0 # mouse was here at last frame of drag
190 shift_key_down = false
192 deselect_all = (args) ->
193 except = args?.except ? null
194 for id, w of selected
195 w.set_style STYLE_NORMAL
197 closest_widget = (widgets, xy) ->
201 new_prox = w.proximity xy
208 svg_event_to_xy = (e) ->
210 svg_offset = $svg.offset()
212 x: Math.round(e.pageX - svg_offset.left)
213 y: Math.round(e.pageY - svg_offset.top)
217 if dragging # two mousedowns in a row?! it happens
219 xy = svg_event_to_xy e
220 if xy.y < supply_height
221 closest = closest_widget supply, xy
223 closest = closest.clone()
224 on_canvas[closest.id] = closest
226 closest = closest_widget on_canvas, xy
228 unless (shift_key_down or selected[closest.id]?)
229 deselect_all except: closest
230 selected[closest.id] = closest
231 closest.set_style STYLE_DRAGGING
240 for id, w of selected
241 if w.y < supply_height
245 w.set_style STYLE_SELECTED
250 xy = svg_event_to_xy e
252 return if drag_from.x is xy.x and drag_from.y is xy.y
253 rel_x = xy.x - drag_from.x
254 rel_y = xy.y - drag_from.y
256 for id, w of selected
257 w.move x: w.x + rel_x, y: w.y + rel_y
259 hover = closest_widget on_canvas, xy
261 hover = closest_widget supply, xy
262 if hover != prev_hover
265 if selected[prev_hover.id]?
266 prev_hover.set_style STYLE_SELECTED
268 prev_hover.set_style STYLE_NORMAL
270 hover.set_style STYLE_HOVER
273 $svg.mousedown mousedown
275 $svg.mousemove mousemove
276 $(document).on 'keyup keydown', (e) ->
277 shift_key_down = e.shiftKey
279 #($ document).keydown (e) ->