source: main/trunk/model-sites-dev/von-sparql/js/paper/examples/Paperjs.org/Tadpoles.html@ 28914

Last change on this file since 28914 was 28914, checked in by ak19, 10 years ago

Supporting javascript libraries and bespoke code written by Steffan to support the von-sparql user interface

File size: 8.9 KB
Line 
1<!DOCTYPE html>
2<html>
3<head>
4 <meta charset="UTF-8">
5 <title>Tadpoles</title>
6 <link rel="stylesheet" href="../css/style.css">
7 <script type="text/javascript" src="../../dist/paper.js"></script>
8 <script type="text/paperscript" canvas="canvas">
9 // Adapted from Flocking Processing example by Daniel Schiffman:
10 // http://processing.org/learning/topics/flocking.html
11
12 var Boid = Base.extend({
13 initialize: function(position, maxSpeed, maxForce) {
14 var strength = Math.random() * 0.5;
15 this.acceleration = new Point();
16 this.vector = Point.random() * 2 - 1;
17 this.position = position.clone();
18 this.radius = 30;
19 this.maxSpeed = maxSpeed + strength;
20 this.maxForce = maxForce + strength;
21 this.points = [];
22 for (var i = 0, l = strength * 10 + 10; i < l; i++) {
23 this.points.push(new Point());
24 }
25 this.count = 0;
26 this.lastAngle = 0;
27 this.distances = [];
28 this.createItems();
29 },
30
31 run: function(boids) {
32 this.lastLoc = this.position.clone();
33 if (!groupTogether) {
34 this.flock(boids);
35 } else {
36 this.align(boids);
37 }
38 this.borders();
39 this.update();
40 this.calculateTail();
41 this.updateItems();
42 },
43
44 calculateTail: function() {
45 var points = this.points;
46 var speed = this.vector.length;
47 var pieceLength = 5 + speed * 0.3;
48 var point = points[0] = this.position.clone();
49 var lastVector = this.vector.clone();
50 for (var i = 1, l = points.length; i < l; i++) {
51 this.count += speed * 15;
52 var vector = point - points[i];
53 var rotated = lastVector.rotate(90);
54 rotated.length = Math.sin((this.count + i * 3) * 0.003);
55 lastVector.length = -pieceLength;
56 point += lastVector;
57 points[i] = point + rotated;
58 lastVector = vector;
59 }
60 },
61
62 createItems: function() {
63 this.head = (project.symbols[0]
64 ? project.symbols[0]
65 : new Symbol(new Path.Ellipse({
66 from: [0, 0],
67 to: [13, 8],
68 fillColor: 'white'
69 }))).place();
70 this.path = new Path({
71 strokeColor: 'white',
72 strokeWidth: 2,
73 strokeCap: 'round'
74 });
75 this.shortPath = new Path({
76 strokeColor: 'white',
77 strokeWidth: 4,
78 strokeCap: 'round'
79 });
80 },
81
82 updateItems: function() {
83 this.path.segments = this.points;
84 this.shortPath.segments = this.points.slice(0, 3);
85
86 this.head.position = this.position;
87 var angle = this.vector.angle;
88 this.head.rotate(angle - this.lastAngle);
89 this.lastAngle = angle;
90 },
91
92 // We accumulate a new acceleration each time based on three rules
93 flock: function(boids) {
94 this.calculateDistances(boids);
95 var separation = this.separate(boids) * 3;
96 var alignment = this.align(boids);
97 var cohesion = this.cohesion(boids);
98 this.acceleration += separation + alignment + cohesion;
99 },
100
101 calculateDistances: function(boids) {
102 for (var i = 0, l = boids.length; i < l; i++) {
103 var other = boids[i];
104 this.distances[i] = other.position.getDistance(this.position, true);
105 }
106 },
107
108 update: function() {
109 // Update velocity
110 this.vector += this.acceleration;
111 // Limit speed (vector#limit?)
112 this.vector.length = Math.min(this.maxSpeed, this.vector.length);
113 this.position += this.vector;
114 // Reset acceleration to 0 each cycle
115 this.acceleration = new Point();
116 },
117
118 seek: function(target) {
119 this.acceleration += this.steer(target, false);
120 },
121
122 arrive: function(target) {
123 this.acceleration += this.steer(target, true);
124 },
125
126 borders: function() {
127 var vector = new Point();
128 var position = this.position;
129 var radius = this.radius;
130 var size = view.size;
131 if (position.x < -radius) vector.x = size.width + radius;
132 if (position.y < -radius) vector.y = size.height + radius;
133 if (position.x > size.width + radius) vector.x = -size.width -radius;
134 if (position.y > size.height + radius) vector.y = -size.height -radius;
135 if (!vector.isZero()) {
136 this.position += vector;
137 var points = this.points;
138 for (var i = 0, l = points.length; i < l; i++) {
139 points[i] += vector;
140 }
141 }
142 },
143
144 // A method that calculates a steering vector towards a target
145 // Takes a second argument, if true, it slows down as it approaches
146 // the target
147 steer: function(target, slowdown) {
148 var steer,
149 desired = target - this.position;
150 var distance = desired.length;
151 // Two options for desired vector magnitude
152 // (1 -- based on distance, 2 -- maxSpeed)
153 if (slowdown && distance < 100) {
154 // This damping is somewhat arbitrary:
155 desired.length = this.maxSpeed * (distance * 0.001);
156 } else {
157 desired.length = this.maxSpeed;
158 }
159 steer = desired - this.vector;
160 steer.length = Math.min(this.maxForce, steer.length);
161 return steer;
162 },
163
164 separate: function(boids) {
165 var desiredSeperation = 3600;
166 var steer = new Point();
167 var count = 0;
168 // For every boid in the system, check if it's too close
169 for (var i = 0, l = boids.length; i < l; i++) {
170 var distance = this.distances[i];
171 if (distance > 0 && distance < desiredSeperation) {
172 // Calculate vector pointing away from neighbor
173 var delta = this.position - boids[i].position;
174 delta.length = 1 / distance;
175 steer += delta;
176 count++;
177 }
178 }
179 // Average -- divide by how many
180 if (count > 0)
181 steer /= count;
182 if (!steer.isZero()) {
183 // Implement Reynolds: Steering = Desired - Velocity
184 steer.length = this.maxSpeed;
185 steer -= this.vector;
186 steer.length = Math.min(steer.length, this.maxForce);
187 }
188 return steer;
189 },
190
191 // Alignment
192 // For every nearby boid in the system, calculate the average velocity
193 align: function(boids) {
194 var neighborDist = 25;
195 var steer = new Point();
196 var count = 0;
197 for (var i = 0, l = boids.length; i < l; i++) {
198 var distance = this.distances[i];
199 if (distance > 0 && distance < neighborDist) {
200 steer += boids[i].vector;
201 count++;
202 }
203 }
204
205 if (count > 0)
206 steer /= count;
207 if (!steer.isZero()) {
208 // Implement Reynolds: Steering = Desired - Velocity
209 steer.length = this.maxSpeed;
210 steer -= this.vector;
211 steer.length = Math.min(steer.length, this.maxForce);
212 }
213 return steer;
214 },
215
216 // Cohesion
217 // For the average location (i.e. center) of all nearby boids,
218 // calculate steering vector towards that location
219 cohesion: function(boids) {
220 var neighborDist = 10000;
221 var sum = new Point(0, 0);
222 var count = 0;
223 for (var i = 0, l = boids.length; i < l; i++) {
224 var distance = this.distances[i];
225 if (distance > 0 && distance < neighborDist) {
226 sum += boids[i].position; // Add location
227 count++;
228 }
229 }
230 if (count > 0) {
231 sum /= count;
232 // Steer towards the location
233 return this.steer(sum, false);
234 }
235 return sum;
236 }
237 });
238
239 var heartPath = Project.importJSON('["Path",{"pathData":"M514.69629,624.70313c-7.10205,-27.02441 -17.2373,-52.39453 -30.40576,-76.10059c-13.17383,-23.70703 -38.65137,-60.52246 -76.44434,-110.45801c-27.71631,-36.64355 -44.78174,-59.89355 -51.19189,-69.74414c-10.5376,-16.02979 -18.15527,-30.74951 -22.84717,-44.14893c-4.69727,-13.39893 -7.04297,-26.97021 -7.04297,-40.71289c0,-25.42432 8.47119,-46.72559 25.42383,-63.90381c16.94775,-17.17871 37.90527,-25.76758 62.87354,-25.76758c25.19287,0 47.06885,8.93262 65.62158,26.79834c13.96826,13.28662 25.30615,33.10059 34.01318,59.4375c7.55859,-25.88037 18.20898,-45.57666 31.95215,-59.09424c19.00879,-18.32178 40.99707,-27.48535 65.96484,-27.48535c24.7373,0 45.69531,8.53564 62.87305,25.5957c17.17871,17.06592 25.76855,37.39551 25.76855,60.98389c0,20.61377 -5.04102,42.08691 -15.11719,64.41895c-10.08203,22.33203 -29.54687,51.59521 -58.40723,87.78271c-37.56738,47.41211 -64.93457,86.35352 -82.11328,116.8125c-13.51758,24.0498 -23.82422,49.24902 -30.9209,75.58594z","strokeWidth":2,"strokeCap":"round"}]');
240 var pathLength = heartPath.length;
241
242 var boids = [];
243 var groupTogether = false;
244
245 // Add the boids:
246 for (var i = 0; i < 30; i++) {
247 var position = Point.random() * view.size;
248 boids.push(new Boid(position, 10, 0.05));
249 }
250
251
252 function onFrame(event) {
253 for (var i = 0, l = boids.length; i < l; i++) {
254 if (groupTogether) {
255 var length = ((i + event.count / 30) % l) / l * pathLength;
256 var point = heartPath.getPointAt(length);
257 if (point)
258 boids[i].arrive(point);
259 }
260 boids[i].run(boids);
261 }
262 }
263
264 // Reposition the heart path whenever the window is resized:
265 function onResize(event) {
266 heartPath.fitBounds(view.bounds);
267 heartPath.scale(0.8);
268 pathLength = heartPath.length;
269 }
270
271 function onMouseDown(event) {
272 groupTogether = !groupTogether;
273 }
274
275 function onKeyDown(event) {
276 if (event.key == 'space') {
277 var layer = project.activeLayer;
278 layer.selected = !layer.selected;
279 return false;
280 }
281 }
282 </script>
283 <style>
284 body {
285 background: black;
286 }
287 </style>
288</head>
289<body>
290 <canvas id="canvas" resize></canvas>
291</body>
292</html>
Note: See TracBrowser for help on using the repository browser.