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"
+ -> return "M#{@x - 5} #{@y - 5}h6l-2 2 4 4 2 -2v6h-6l2-2-4-4-2 2z"
+ -> 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"
+ -> return "M#{@x + 5} #{@y - 5}v6l-2-2-4 4 2 2h-6v-6l2 2 4-4-2-2z"
+ -> 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"
]
+shape_node_move = -> "M#{@x} #{@y - 9}l-2.5 4.5h2v2.404a2.156 2.156 0 0 0-1.596 1.596h-2.404v-2l-4.5 2.5 4.5 2.5v-2h2.404a2.156 2.156 0 0 0 1.596 1.596v2.404h-2l2.5 4.5 2.5-4.5h-2v-2.404a2.156 2.156 0 0 0 1.596-1.596h2.404v2l4.5-2.5-4.5-2.5v2h-2.404a2.156 2.156 0 0 0-1.596-1.596v-2.404h2l-2.5-4.5z"
next_widget_id = 0
# public vars: x, y, width, height, el
}
return @controls
+class PolylineWidget extends Widget
+ constructor: (args) ->
+ super args
+ @css_class = 'polyline'
+ @nodes = []
+ for n in args.nodes
+ @nodes.push x: n.x, y: n.y
+ @el = json_to_svg path:
+ d: @my_path_d()
+ class: 'polyline normal'
+ @svg.appendChild @el
+ destruct: ->
+ super()
+ if @el?
+ @svg.removeChild @el
+ clone: ->
+ return new PolylineWidget @
+ my_path_d: ->
+ ret = ''
+ for n in @nodes
+ if ret is ''
+ ret += 'M'
+ else
+ ret += 'L'
+ ret += n.x + @x
+ ret += ' '
+ ret += n.y + @y
+ return ret
+ set_state: (state) ->
+ super state
+ @update_class()
+ move: (args) ->
+ super args
+ @el.setAttribute 'd', @my_path_d()
+ @reposition_controls()
+ proximity: (xy) -> # return the square of the distance to your visible bits
+ prox = PROX_TOO_FAR
+ for n, i in @nodes
+ dx = @x + n.x - xy.x
+ dy = @y + n.y - xy.y
+ p = dx * dx + dy * dy
+ if p < prox
+ prox = p
+ if i > 0
+ l1x = @x + @nodes[i-1].x
+ l1y = @y + @nodes[i-1].y
+ l2x = @x + @nodes[i].x
+ l2y = @y + @nodes[i].y
+ ldx = l2x - l1x
+ ldy = l2y - l1y
+ if ldx is 0 # vertical line
+ if (xy.y < l1y) is (xy.y < l2y)
+ continue
+ dx = l1x - xy.x
+ p = dx * dx
+ else if ldy is 0 # horizontal line
+ if (xy.x < l1x) is (xy.x < l2x)
+ continue
+ dy = l1y - xy.y
+ p = dy * dy
+ else # slanty line
+ # https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
+ a = ldy
+ b = -1 * ldx
+ c = l2x * l1y - l2y * l1x
+ y_on_line = (a * (a * xy.y - b * xy.x) - b * c) / (a * a + b * b)
+ if (y_on_line < l1y) is (y_on_line < l2y)
+ continue
+ p = (a * xy.x + b * xy.y + c) / Math.sqrt(a * a + b * b)
+ p *= p
+
+ if p < prox
+ prox = p
+ return prox
+ resize: (wh) ->
+ # FIXME (apply to more than just 2nd node)
+ @nodes[1].x = wh.w
+ @nodes[1].y = wh.h
+ @width = wh.w
+ @height = wh.h
+ @el.setAttribute 'd', @my_path_d()
+ @reposition_controls()
+ return
+ node_dragger: (i) ->
+ if i is 0
+ return (dxy) =>
+ for i in [1...@nodes.length]
+ @nodes[i].x -= dxy.x
+ @nodes[i].y -= dxy.y
+ @move x: @x + dxy.x, y: @y + dxy.y
+ return (dxy) =>
+ @nodes[i].x += dxy.x
+ @nodes[i].y += dxy.y
+ @el.setAttribute 'd', @my_path_d()
+ @reposition_controls()
+ reposition_controls: ->
+ if @controls.length > 1
+ positions = @control_positions()
+ for i in [0...positions.length]
+ @controls[i].move x: positions[i].x, y: positions[i].y
+ return
+ control_positions: ->
+ ret = []
+ for n in @nodes
+ ret.push x: @x + n.x, y: @y + n.y
+ return ret
+ make_controls: (args) -> # create controls, return them
+ console.log 'make line controls'
+ if @controls.length > 0
+ if console?.log?
+ console.log "warning: re-adding controls"
+ @kill_controls()
+ 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: @node_dragger i
+ shape: shape_node_move
+ }
+ return @controls
+
# called automatically on domcontentloaded
init = ->
svg_offset = null
]
svg.appendChild json_to_svg style:
type: 'text/css'
- contents: '.box.normal{filter: url(#crayon)}'
+ contents: '.box.normal,.polyline.normal{filter: url(#crayon)}'
# create canvas border
svg.appendChild json_to_svg rect:
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
+ supply_count = 0
+ supply_add = (type, args) ->
+ args.x ?= 0
+ args.y ?= 0
+ args.x += 30 + supply_count * 90
+ args.y += (supply_height - 50) / 2
+ args.svg = svg
+ w = new type args
+ supply[w.id] = w
+ supply_count += 1
+ supply_add RectWidget, width: 50, height: 50
+ supply_add PolylineWidget, y: 25, nodes: [{x: 0, y: 0}, {x: 50, y: 0}]
+ supply_add PolylineWidget, x: 25, nodes: [{x: 0, y: 0}, {x: 0, y: 50}]
+ supply_add PolylineWidget, x: 10, nodes: [{x: 0, y: 0}, {x: 15, y: 50}, {x: 30, y: 0}]
+ supply_add PolylineWidget, x: 0, nodes: [{x: 0, y: 50}, {x: 17, y: 0}, {x: 33, y: 50}, {x: 50, y: 0}]
# editor state
controls_layer = { all: {}, selected: {} }