|
| 1 | +var values = { |
| 2 | + friction: 0.8, |
| 3 | + timeStep: 0.01, |
| 4 | + amount: 15, |
| 5 | + mass: 2, |
| 6 | + count: 0 |
| 7 | +}; |
| 8 | +values.invMass = 1 / values.mass; |
| 9 | + |
| 10 | +var path, springs; |
| 11 | +var size = view.size * [1.2, 1]; |
| 12 | + |
| 13 | +var Spring = function(a, b, strength, restLength) { |
| 14 | + this.a = a; |
| 15 | + this.b = b; |
| 16 | + this.restLength = restLength || 80; |
| 17 | + this.strength = strength ? strength : 0.55; |
| 18 | + this.mamb = values.invMass * values.invMass; |
| 19 | +}; |
| 20 | + |
| 21 | +Spring.prototype.update = function() { |
| 22 | + var delta = this.b - this.a; |
| 23 | + var dist = delta.length; |
| 24 | + var normDistStrength = (dist - this.restLength) / |
| 25 | + (dist * this.mamb) * this.strength; |
| 26 | + delta.y *= normDistStrength * values.invMass * 0.2; |
| 27 | + if (!this.a.fixed) |
| 28 | + this.a.y += delta.y; |
| 29 | + if (!this.b.fixed) |
| 30 | + this.b.y -= delta.y; |
| 31 | +}; |
| 32 | + |
| 33 | + |
| 34 | +function createPath(strength) { |
| 35 | + var path = new Path({ |
| 36 | + fillColor: 'black' |
| 37 | + }); |
| 38 | + springs = []; |
| 39 | + for (var i = 0; i <= values.amount; i++) { |
| 40 | + var segment = path.add(new Point(i / values.amount, 0.5) * size); |
| 41 | + var point = segment.point; |
| 42 | + if (i == 0 || i == values.amount) |
| 43 | + point.y += size.height; |
| 44 | + point.px = point.x; |
| 45 | + point.py = point.y; |
| 46 | + // The first two and last two points are fixed: |
| 47 | + point.fixed = i < 2 || i > values.amount - 2; |
| 48 | + if (i > 0) { |
| 49 | + var spring = new Spring(segment.previous.point, point, strength); |
| 50 | + springs.push(spring); |
| 51 | + } |
| 52 | + } |
| 53 | + path.position.x -= size.width / 4; |
| 54 | + return path; |
| 55 | +} |
| 56 | + |
| 57 | +function onResize() { |
| 58 | + if (path) |
| 59 | + path.remove(); |
| 60 | + size = view.bounds.size * [2, 1]; |
| 61 | + path = createPath(0.1); |
| 62 | +} |
| 63 | + |
| 64 | +function onMouseMove(event) { |
| 65 | + var location = path.getNearestLocation(event.point); |
| 66 | + var segment = location.segment; |
| 67 | + var point = segment.point; |
| 68 | + |
| 69 | + if (!point.fixed && location.distance < size.height / 4) { |
| 70 | + var y = event.point.y; |
| 71 | + point.y += (y - point.y) / 6; |
| 72 | + if (segment.previous && !segment.previous.fixed) { |
| 73 | + var previous = segment.previous.point; |
| 74 | + previous.y += (y - previous.y) / 24; |
| 75 | + } |
| 76 | + if (segment.next && !segment.next.fixed) { |
| 77 | + var next = segment.next.point; |
| 78 | + next.y += (y - next.y) / 24; |
| 79 | + } |
| 80 | + } |
| 81 | +} |
| 82 | + |
| 83 | +function onFrame(event) { |
| 84 | + updateWave(path); |
| 85 | +} |
| 86 | + |
| 87 | +function updateWave(path) { |
| 88 | + var force = 1 - values.friction * values.timeStep * values.timeStep; |
| 89 | + for (var i = 0, l = path.segments.length; i < l; i++) { |
| 90 | + var point = path.segments[i].point; |
| 91 | + var dy = (point.y - point.py) * force; |
| 92 | + point.py = point.y; |
| 93 | + point.y = Math.max(point.y + dy, 0); |
| 94 | + } |
| 95 | + |
| 96 | + for (var j = 0, l = springs.length; j < l; j++) { |
| 97 | + springs[j].update(); |
| 98 | + } |
| 99 | + path.smooth({ type: 'continuous' }); |
| 100 | +} |
| 101 | + |
| 102 | +function onKeyDown(event) { |
| 103 | + if (event.key == 'space') { |
| 104 | + path.fullySelected = !path.fullySelected; |
| 105 | + path.fillColor = path.fullySelected ? null : 'black'; |
| 106 | + } |
| 107 | +} |
0 commit comments