function Line () { Module.call(this, 'line', 'Drawing lines. Tween expects something in the `$&$>>$&$` format.') this.ports.step = new Port(this, 'step', false, true, 0, 100, 'The tween line index.') this.ports.thickness = new Port(this, 'thickness', true, true, 1, 100, 'The tween line thickness.') this.methods.stroke = new Method('stroke', 'x1,y1&x2,y2', 'Stroke positions.', function (q) { ronin.line.stroke_multi(q) }) this.methods.tween = new Method('tween', 'tween:$&$>>$&$ step->thickness', 'Stroke lines between strokes.', function (q) { var from = q.from var to = q.to ronin.line.ports.step.write(0) while (ronin.line.ports.step.value < ronin.line.ports.step.max) { var progress = ronin.line.ports.step.value / parseFloat(ronin.line.ports.step.max) var new_positions = tween_positions(from, to, progress) ronin.line.stroke_multi(new_positions) ronin.line.ports.step.write(ronin.line.ports.step.value + 1) } }) this.preview = function (q) { // TODO // console.log(q); } this.stroke_multi = function (coordinates) { var from = coordinates[0] for (pos_id in coordinates) { var pos = coordinates[pos_id] ronin.line.stroke(from, pos) from = pos } } this.stroke = function (from, to, ctx = ronin.cursor.target.context()) { ctx.beginPath() ctx.globalCompositeOperation = 'source-over' ctx.moveTo((from.x * 2), (from.y * 2)) ctx.lineTo((to.x * 2), (to.y * 2)) ctx.lineCap = 'round' ctx.lineWidth = clamp(ronin.line.ports.thickness.value, 1, 200) * 0.1 ctx.strokeStyle = '#000' ctx.stroke() ctx.closePath() } function clamp (v, min, max) { return v < min ? min : v > max ? max : v } function tween_positions (froms, tos, progress) { var a = [] for (pos_id in froms) { var from = froms[pos_id] var to = tos[pos_id] a.push(tween_position(from, to, progress)) } return a } function tween_position (from, to, progress) { var offset = { x: to.x - from.x, y: to.y - from.y } return { x: from.x + offset.x * progress, y: from.y + offset.y * progress } } }