el.setAttribute k, v
return el
+resizer_nw = (widget) ->
+ return (dxy) ->
+ widget.resize w: widget.width - dxy.x, h: widget.height - dxy.y
+ widget.move x: widget.x + dxy.x, y: widget.y + dxy.y
+resizer_n = (widget) ->
+ return (dxy) ->
+ widget.resize w: widget.width, h: widget.height - dxy.y
+ widget.move x: widget.x, y: widget.y + dxy.y
+resizer_ne = (widget) ->
+ return (dxy) ->
+ widget.resize w: widget.width + dxy.x, h: widget.height - dxy.y
+ widget.move x: widget.x, y: widget.y + dxy.y
+resizer_e = (widget) ->
+ return (dxy) ->
+ widget.resize w: widget.width + dxy.x, h: widget.height
+resizer_se = (widget) ->
+ return (dxy) ->
+ widget.resize w: widget.width + dxy.x, h: widget.height + dxy.y
+resizer_s = (widget) ->
+ return (dxy) ->
+ widget.resize w: widget.width, h: widget.height + dxy.y
+resizer_sw = (widget) ->
+ return (dxy) ->
+ widget.resize w: widget.width - dxy.x, h: widget.height + dxy.y
+ widget.move x: widget.x + dxy.x, y: widget.y
+resizer_w = (widget) ->
+ return (dxy) ->
+ widget.resize w: widget.width - dxy.x, h: widget.height
+ widget.move x: widget.x + dxy.x, y: widget.y
+resizers = [
+ resizer_nw
+ resizer_n
+ resizer_ne
+ resizer_e
+ resizer_se
+ resizer_s
+ resizer_sw
+ resizer_w
+]
+resizer_shapes = [
+ (xy) -> return "M#{@x - 5} #{@y - 5}h6l-2 2 4 4 2 -2v6h-6l2-2-4-4-2 2z"
+ (xy) -> return "M #{@x},#{@y - 7} l 4,4 -2.5,0 0,5 2.5,0 -4,4 -4,-4 2.5,0 0,-5 -2.5,0 z"
+ (xy) -> return "M#{@x + 5} #{@y - 5}v6l-2-2-4 4 2 2h-6v-6l2 2 4-4-2-2z"
+ (xy) -> return "M #{@x - 7},#{@y} l 4,-4 0,2.5 5,0 0,-2.5 4,4 -4,4 0,-2.5 -5,0 0,2.5 z"
+]
+
next_widget_id = 0
# public vars: x, y, width, height, el
class Visible
dx = xy.x - @x
dy = xy.y - @y
return dx * dx + dy * dy
-
-class ControlPoint extends Control
+class ControlPath extends Control
constructor: (args) ->
super args
@css_class = 'control_point'
- @el = json_to_svg circle:
- cx: @x + 1
- cy: @y + 1
- r: 6
+ @make_path = args.shape
+ @el = json_to_svg path:
+ d: @make_path()
class: 'control_point normal'
@svg.appendChild @el
destruct: ->
@svg.removeChild @el
move: (args) ->
super args
- @el.setAttribute 'cx', @x
- @el.setAttribute 'cy', @y
+ @el.setAttribute 'd', @make_path()
class Widget extends Visible
#sub-classes are expected to implement all of these:
make_controls: -> # create controls, return them
return []
kill_controls: ->
- console.log 'kill_controls'
for c in @controls
c.destruct()
@controls = []
super args
@el.setAttribute 'x', @x + 1
@el.setAttribute 'y', @y + 1
+ @reposition_controls()
proximity: (xy) -> # return the square of the distance to your visible bits
x = xy.x
y = xy.y
prox = PROX_MAX - 1
return prox
resize: (wh) ->
+ dw = wh.w - @width
+ dh = wh.h - @height
@width = wh.w
- @el.setAttribute 'width', @width
+ @el.setAttribute 'width', @width - 2
@height = wh.h
- @el.setAttribute 'height', @height
+ @el.setAttribute 'height', @height - 2
+ @reposition_controls()
+ reposition_controls: ->
if @controls.length > 1
- @controls[1].move x: @x + @width, y: @y + @height
+ positions = @control_positions()
+ for i in [0...positions.length]
+ @controls[i].move x: positions[i].x, y: positions[i].y
+ control_positions: ->
+ gap = 7
+ mgap = 9
+ w2p = Math.floor(@width / 2) + 0.5
+ h2p = Math.floor(@height / 2) + 0.5
+ return [
+ { x: @x - gap, y: @y - gap }
+ { x: @x + w2p, y: @y - mgap }
+ { x: @x + @width + gap, y: @y - gap }
+ { x: @x + @width + mgap, y: @y + h2p }
+ { x: @x + @width + gap, y: @y + @height + gap }
+ { x: @x + w2p, y: @y + @height + mgap }
+ { x: @x - gap, y: @y + @height + gap }
+ { x: @x - mgap, y: @y + h2p }
+ ]
make_controls: (args) -> # create controls, return them
- console.log 'make_controls'
if @controls.length > 0
- console.log "warning: re-adding controls"
+ if console?.log?
+ console.log "warning: re-adding controls"
@kill_controls()
- w = @
- @controls = [
- new ControlPoint svg: @svg, x: @x, y: @y, done: args.done, drag: (dxy) ->
- w.resize w: w.width - dxy.x, h: w.height - dxy.y
- w.move x: w.x + dxy.x, y: w.y + dxy.y
- new ControlPoint svg: @svg, x: @x + @width, y: @y + @height, done: args.done, drag: (dxy) ->
- w.resize w: w.width + dxy.x, h: w.height + dxy.y
- ]
+ positions = @control_positions()
+ for i in [0...positions.length]
+ @controls.push new ControlPath {
+ svg: @svg
+ x: positions[i].x
+ y: positions[i].y
+ done: args.done
+ drag: resizers[i] @
+ shape: resizer_shapes[i % resizer_shapes.length]
+ }
return @controls
# called automatically on domcontentloaded
dragging = true
drag_layer = hit.layer
drag_from = xy
- console.log hit
else
deselect_all widget_layer
return