X-Git-Url: https://jasonwoof.com/gitweb/?p=crayon_mockup.git;a=blobdiff_plain;f=auto.coffee;h=89dfb86fb41b6b69018983ce0364e85a01662b44;hp=e36132fc7e84050175b7e999bde4a32433b5dd94;hb=af4cde3b88f14635f09f2faf00162b017a2ee7bc;hpb=3fee07a619dd65120b2500e17ce09febd3cc4068 diff --git a/auto.coffee b/auto.coffee index e36132f..89dfb86 100644 --- a/auto.coffee +++ b/auto.coffee @@ -2,6 +2,15 @@ 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 # json (compiled to javascript and minified) is ~8% smaller than the resulting xml json_to_svg = (json) -> @@ -15,38 +24,105 @@ json_to_svg = (json) -> el.setAttribute k, v return el +next_widget_id = 0 # public vars: x, y, width, height, el class Widget + # required args: svg constructor: (args) -> - @x = args?.x ? 1 - @y = args?.y ? 1 - @width = args?.width ? 50 - @height = args?.height ? 34 + @id = next_widget_id + next_widget_id += 1 + @svg = args.svg + @style = args.style ? STYLE_NORMAL + @x = args.x ? 1 + @y = args.y ? 1 + @width = args.width ? 50 + @height = args.height ? 34 + destruct: -> + clone: -> + return new Widget @ 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) -> + return if @style is style + if style is STYLE_NORMAL + @el.setAttribute 'style', 'filter: url(#crayon)' + else + if @style is STYLE_NORMAL + @el.setAttribute 'style', '' + switch style + when STYLE_NORMAL + @el.setAttribute 'class', "#{@css_class}" + when STYLE_SELECTED + @el.setAttribute 'class', "#{@css_class} selected" + when STYLE_HOVER + @el.setAttribute 'class', "#{@css_class} hover" + when STYLE_DRAGGING + @el.setAttribute 'class', "#{@css_class} dragging" + # FIXME when STYLE_EDITING + @style = style + 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: @x + 1 + y: @y + 1 width: @width - 2 height: @height - 2 class: 'box' + style: if @style is STYLE_NORMAL then 'filter: url(#crayon)' else '' + @svg.appendChild @el + destruct: -> + super() + if @el? + @svg.removeChild @el + clone: -> + return new RectWidget @ move: (args) -> super args @el.setAttribute 'x', @x + 1 @el.setAttribute 'y', @y + 1 - clone: -> - return new RectWidget @ + 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 = -> - offset = null - selected = [] - on_canvas = [] - dragging = false + svg_offset = null $container = $ '.crayon_mockup' svg = json_to_svg svg: width: width, height: height, viewBox: "0 0 #{width} #{height}" $svg = $ svg @@ -66,71 +142,117 @@ init = -> width: width - 2 height: height - 2 - supply_height class: 'canvas_border' - - supply = [ - new RectWidget() - new RectWidget width: 12, height: 50 - new RectWidget width: 70, height: 12 + + supply = {} + for args, i in [ + { width: 40, height: 40 } + { width: 12, height: 50 } + { width: 70, height: 12 } ] - for widget, i in supply - widget.move { - x: 30 + i * 90 + (70 - widget.width) / 2 - y: (supply_height - widget.height) / 2 + 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 } - svg.appendChild widget.el - - # todo ask widgets + 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) -> - closest = [10000, null] - for w in widgets - x = w.x + w.width / 2 - xy.x - y = w.y + w.height / 2 - xy.y - dist2 = x * x + y * y - if dist2 < closest[0] - closest = [dist2, w] - if closest[1]? + 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 offset? - offset = $svg.offset() + unless svg_offset? + svg_offset = $svg.offset() return { - x: Math.round(e.pageX - offset.left) - y: Math.round(e.pageY - offset.top) + x: Math.round(e.pageX - svg_offset.left) + y: Math.round(e.pageY - svg_offset.top) } - $svg.mousedown (e) -> + 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 - console.log closest if closest? - closest[1] = closest[1].clone() - svg.appendChild closest[1].el + closest = closest.clone() + on_canvas[closest.id] = closest else closest = closest_widget on_canvas, xy if closest? - selected = [closest[1]] + unless (shift_key_down or selected[closest.id]?) + deselect_all except: closest + selected[closest.id] = closest + closest.set_style STYLE_DRAGGING dragging = true - mousemove e + drag_from = xy + else + deselect_all() return false - $svg.mouseup (e) -> + 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 - if selected[0]? - if selected[0].y > supply_height - on_canvas.push selected[0] - else - svg.removeChild selected[0].el - selected = [] return false + prev_hover = null mousemove = (e) -> + xy = svg_event_to_xy e if dragging - xy = svg_event_to_xy e - xy.x -= selected[0].width / 2 - xy.y -= selected[0].height / 2 - selected[0].move xy + 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