bezier-spline-a.js

total 0
used 0
limit 0
/* --- title: Bezier files: ../point_src/math.js head point pointlist dragging mouse stage dragging stroke ../point_src/keyboard.js ../point_src/split.js ../point_src/curve-extras.js In this example the dirty flag is used for curve tips. */ class MainStage extends Stage { canvas='playspace' mounted(){ this.curve = new PointList( new Point(100, 150, 60, -30) , new Point(200, 340, 60, -30) , new Point(450, 340, 60, -90) , new Point(650, 340, 60, -90) ) this.keyboard.wake() this.myKeys = {} this.handles = [] // this.curve[0].color = '#333' this.curve.each.color = '#444' this.linearDrag = false this.equalDistance = false this.scaleDistance = true this.curve.forEach(p => { let pair = p.split(2, 0, Math.PI * .5) pair[0].recordedDistance = pair[0].distance2D(p) pair[0].relRads = degToRad(calculateAngle360(p, pair[0])) pair[1].recordedDistance = pair[1].distance2D(p) pair[1].relRads = degToRad(calculateAngle360(p, pair[1])) this.handles.push(pair) this.dragging.add(...pair) }) this.dragging.add(...this.curve) } computeHandles(index, owner) { let handles = this.handles[index] handles.forEach(handle => { let radians = owner.radians + handle.relRads let distance = handle.recordedDistance.distance handle.x = owner.x + Math.cos(radians) * distance handle.y = owner.y + Math.sin(radians) * distance }) } constrainHandle(owner, handle) { let radians = owner.radians + handle.relRads let directionX = Math.cos(radians) let directionY = Math.sin(radians) let offsetX = handle.x - owner.x let offsetY = handle.y - owner.y let distance = offsetX * directionX + offsetY * directionY handle.x = owner.x + directionX * distance handle.y = owner.y + directionY * distance return distance } mirrorHandle(owner, handle, distance, scaleDistance=false) { let antipose = handle === owner.pair[0] ? owner.pair[1] : owner.pair[0] let radians = owner.radians + handle.relRads let antiposeDistance = distance if (scaleDistance) { let originalDistance = handle.recordedDistance.distance let ratio = originalDistance == 0 ? 0 : Math.abs(distance) / originalDistance antiposeDistance = antipose.recordedDistance.distance * ratio } antipose.x = owner.x - Math.cos(radians) * antiposeDistance antipose.y = owner.y - Math.sin(radians) * antiposeDistance antipose.recordedDistance = antipose.distance2D(owner) antipose.relRads = degToRad(calculateAngle360(owner, antipose)) antipose.dirty = false } relPolarXY(primaryPoint, controlPoint, distance, spinRads) { /* get xy of the control point, relative to the {X,Y, Rot} of point A, using distance and relative angle. */ // const primaryPoint = { x: 10, y: 10, radians: 1 }; if(distance == undefined){ distance = primaryPoint.distance2D(controlPoint) } const relative = { distance, spinRads }; const totalRads = primaryPoint.radians + relative.spinRads; const dx = distance.x , dy = distance.y; const xRot = dx * Math.cos(totalRads) - dy * Math.sin(totalRads); const yRot = dx * Math.sin(totalRads) + dy * Math.cos(totalRads); return [primaryPoint.x + xRot, primaryPoint.y + yRot] } onKeydown(ev) { console.log('onKeydown', ev) this.myKeys[ev.key] = 1 } onKeyup(ev) { console.log('onKeyup', ev) this.myKeys[ev.key] = 0 } draw(ctx){ this.clear(ctx) this.curve.pen.indicator(ctx, { width: 1 }) /* Iterate each point. If there is a change, recompute the handles*/ this.curve.forEach((p, i) => { if (p.wasDirty) { this.computeHandles(i, p) } }) let altButton = this.myKeys['Control'] == 1 let linearDrag = this.linearDrag let equalDistance = this.equalDistance let scaleDistance = altButton? false: this.scaleDistance /* Iterate all handle pairs, if a handle within the pair is dirty, re-cache its position. */ this.handles.forEach((pair, i) => { let p = this.curve[i] p.pair = pair let dragged = this.dragging.isDragging ? this.dragging.getPoint() : undefined let pairDrag = pair.includes(dragged) pair.forEach(handle => { if (handle.wasDirty && (!pairDrag || handle === dragged)) { let distance if (linearDrag) { distance = this.constrainHandle(p, handle) } else { distance = handle.distance2D(p).distance handle.relRads = degToRad(calculateAngle360(p, handle)) } if (equalDistance || scaleDistance) { this.mirrorHandle(p, handle, distance, scaleDistance && !equalDistance) } handle.recordedDistance = handle.distance2D(p) handle.relRads = degToRad(calculateAngle360(p, handle)) } }) pair.pen.indicator(ctx, { color: p.color, width: 1 }) }) let a = this.curve[0] let b = this.curve[1] let c = this.curve[2] let d = this.curve[3] ctx.moveTo(a.x, a.y) let closeLoop = 0 this.curve.forEach((p, i) => { let n = this.curve[i + 1] if (n == undefined) { if (closeLoop) { n = this.curve[0] } else { return } } ctx.bezierCurveTo( p.pair[0].x, p.pair[0].y, n.pair[1].x, n.pair[1].y, n.x, n.y ) }) // ctx.bezierCurveTo( // a.pair[0].x, a.pair[0].y, // b.pair[1].x, b.pair[1].y, // b.x, b.y // ) // ctx.bezierCurveTo( // b.pair[0].x, b.pair[0].y, // c.pair[1].x, c.pair[1].y, // c.x, c.y // ) // ctx.bezierCurveTo( // c.pair[0].x, c.pair[0].y, // d.pair[1].x, d.pair[1].y, // d.x, d.y // ) ctx.strokeStyle = 'purple' ctx.lineWidth = 3 ctx.stroke() } } ;stage = MainStage.go();
Run
Meta Data
title Bezier
imports ()
files ('../point_src/math.js', 'head', 'point', 'pointlist', 'dragging', 'mouse', 'stage', 'dragging', 'stroke', '../point_src/keyboard.js', '../point_src/split.js', '../point_src/curve-extras.js')
unused_keys ()
unknown_keys ()
filepath_exists True
path bezier-spline-a.js
filepath bezier-spline-a.js
clean_files ('../point_src/math.js', '../point_src/core/head.js', '../point_src/pointpen.js', '../point_src/compass.js', '../point_src/center.js', '../point_src/point-content.js', '../point_src/pointdraw.js', '../point_src/relative-xy.js', '../point_src/pointcast.js', '../point_src/point.js', '../point_src/pointlistdraw.js', '../point_src/pointlistgradient.js', '../point_src/pointlistshape.js', '../point_src/pointlistgenerator.js', '../point_src/unpack.js', '../point_src/pointlist.js', '../point_src/pointlistpen.js', '../point_src/functions/clamp.js', '../point_src/distances.js', '../point_src/protractor.js', '../point_src/text/beta.js', '../point_src/dragging.js', '../point_src/events.js', '../point_src/automouse.js', '../point_src/stage-hooks.js', '../point_src/stage-resize.js', '../point_src/functions/resolve.js', '../point_src/stage.js', '../point_src/setunset.js', '../point_src/stroke.js', '../point_src/keyboard.js', '../point_src/split.js', '../point_src/curve-extras.js')
markdown {'html': '<p>In this example the dirty flag is used for curve tips.</p>', 'content': '---\ntitle: Bezier\nfiles:\n ../point_src/math.js\n head\n point\n pointlist\n dragging\n mouse\n stage\n dragging\n stroke\n ../point_src/keyboard.js\n ../point_src/split.js\n ../point_src/curve-extras.js\n\nIn this example the dirty flag is used for curve tips.'}