├── README.md ├── gears.png ├── index.css ├── index.html ├── notes.txt ├── paper.js ├── paper_animation.pjs ├── paper_circle.pjs ├── paper_gears.html ├── paper_gears.pjs ├── paper_interaction.pjs ├── processing.js ├── processing_animation.java ├── processing_circle.java ├── processing_gears.html ├── processing_gears.java ├── processing_interaction.java ├── raphael-min.js ├── raphael_animation.js ├── raphael_circle.js ├── raphael_gears.html ├── raphael_gears.js └── raphael_interaction.js /README.md: -------------------------------------------------------------------------------- 1 | 3 Gears 2 | ================================================== 3 | 4 | The project is the sample code to an article comparing [PaperJS](http://paperjs.org/), [Processing.js](http://processingjs.org/), and [Raphaël](http://raphaeljs.com). It shows a simple drawing, animation, and interaction example in each and then combines it all in a complex animation of gears. 5 | 6 | 7 | [Paper vs. Processing vs. Raphaël](http://zgrossbart.github.io/3gears) 8 | -------------------------------------------------------------------------------- /gears.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zgrossbart/3gears/c5b9f3b5cff9cef0354061991577527671a0be1a/gears.png -------------------------------------------------------------------------------- /index.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #fff; 3 | color: #000; 4 | font-size: 18px; 5 | line-height: 24px; 6 | font-family: "ff-basic-gothic-web-pro", Verdana,Arial,Sans-serif; 7 | } 8 | 9 | a { 10 | text-decoration: none; 11 | 12 | } 13 | 14 | a:hover { 15 | text-decoration: underline; 16 | } 17 | 18 | a.sourceLink { 19 | position: relative; 20 | top: -24px; 21 | left: 30px; 22 | font-size: 12px; 23 | } 24 | 25 | h2 { 26 | text-align: center; 27 | } 28 | 29 | .canvas { 30 | border-radius: 12px; 31 | border: thin solid lightgray; 32 | width: 200px; 33 | height: 200px; 34 | margin: 0 auto; 35 | display: block; 36 | margin-top: 18px; 37 | } 38 | 39 | #main { 40 | position: relative; 41 | width: 960px; 42 | margin: 0 auto; 43 | height: 1200px; 44 | } 45 | 46 | #main > div { 47 | padding: 10px; 48 | overflow: hidden; 49 | } 50 | 51 | #headers { 52 | position: absolute; 53 | left: 0px; 54 | width: 220px; 55 | top: 28px; 56 | } 57 | 58 | #paper { 59 | position: absolute; 60 | left: 240px; 61 | width: 240px; 62 | top: 28px; 63 | } 64 | 65 | #processing { 66 | position: absolute; 67 | left: 480px; 68 | width: 240px; 69 | top: 28px; 70 | } 71 | 72 | #raphael { 73 | position: absolute; 74 | left: 720px; 75 | width: 240px; 76 | top: 28px; 77 | } 78 | 79 | pre { 80 | font-size: 12px; 81 | line-height: 14px; 82 | } 83 | 84 | #paperGears { 85 | background: transparent url('gears.png') no-repeat scroll 0 0; 86 | } 87 | 88 | #processingGears { 89 | background: transparent url('gears.png') no-repeat scroll -250px 0; 90 | } 91 | 92 | #raphaelGears { 93 | background: transparent url('gears.png') no-repeat scroll -500px 0; 94 | } 95 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Paper vs. Processing vs. Raphaël 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 35 | 36 | 43 | 44 | 45 |
46 |
47 |

48 | Web-Drawing Throwdown: Paper.js Vs. Processing.js Vs. Raphael 49 |

50 | 51 |

52 | Compare the code for Paper, Processing, and Raphaël. We'll start by drawing a simple circle. 53 |

54 | 55 |

56 | Each framework creates animated drawings. Click the squares to make them spin. 57 |

58 | 59 |

60 | 61 | The frameworks also handle interactions. Click or touch a square to change its color. 62 |

63 | 64 |

65 | Now we'll put it all together with more complex shapes and create gears. Click the images to watch the gears run. 66 |

67 |
68 |
69 |

Paper

70 | 71 | view source 72 | 73 | 74 | view source 75 | 76 | 77 | view source 78 | 79 | 80 |
81 | 82 |
83 |

Processing

84 | 85 | view source 86 | 87 | 88 | view source 89 | 90 | 91 | view source 92 | 93 | 94 |
95 | 96 |
97 |

Raphaël

98 |
99 | view source 100 | 101 |
102 | view source 103 | 104 |
105 | view source 106 | 107 | 108 | 109 |

110 | by Zack Grossbart 111 |

112 |
113 |
114 | 115 | Fork me on GitHub 116 | 117 | 118 | -------------------------------------------------------------------------------- /notes.txt: -------------------------------------------------------------------------------- 1 | http://coding.smashingmagazine.com/2011/10/04/quick-look-math-animations-javascript/ 2 | -------------------------------------------------------------------------------- /paper_animation.pjs: -------------------------------------------------------------------------------- 1 | var r; 2 | 3 | function init() { 4 | var c = new Path.Circle(new Point(100, 100), 10); 5 | c.fillColor = '#ee2a33'; 6 | 7 | var point = new Point(60, 60); 8 | var size = new Size(80, 80); 9 | var rectangle = new Rectangle(point, size); 10 | r = new Path.Rectangle(rectangle); 11 | r.strokeColor = '#ee2a33'; 12 | r.strokeWidth = 2; 13 | r.rotate(20); 14 | } 15 | 16 | function onMouseUp(event) { 17 | main.paperAnimationStopped = !main.paperAnimationStopped; 18 | } 19 | 20 | function onFrame(event) { 21 | if (!main.paperAnimationStopped) { 22 | r.rotate(3); 23 | } 24 | } 25 | 26 | 27 | init(); 28 | -------------------------------------------------------------------------------- /paper_circle.pjs: -------------------------------------------------------------------------------- 1 | var circle = new Path.Circle(new Point(100, 100), 10); 2 | circle.fillColor = '#ee2a33'; 3 | -------------------------------------------------------------------------------- /paper_gears.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PaperJS Gears 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 25 | 26 | 27 | Fork me on GitHub 28 | 29 | 30 |

Gears in PaperJS

31 | 32 | Paper vs. Processing vs. Raphaël 33 | 34 | 35 | -------------------------------------------------------------------------------- /paper_gears.pjs: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright 2011 Zack Grossbart 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | ******************************************************************************/ 18 | 19 | var speed = 0.75; 20 | var scale = 15; 21 | var toothSize = 28; 22 | var clockwise = false; 23 | 24 | var width = 960; 25 | var height = 650; 26 | var started = true; 27 | 28 | var gears = []; 29 | 30 | 31 | /** 32 | * This function initializes our script. 33 | */ 34 | function init() { 35 | 36 | var p = new Point(width / 6, (height / 3) + 30); 37 | var redGear = new Gear(); 38 | redGear.create(p, 15, '#ee2a33', speed, !clockwise); // red gear 39 | gears.push(redGear); 40 | 41 | g = addGear(p, redGear, 4, '#00aeef', speed, 100); // blue gear 42 | 43 | g = addGear(g.point, g.gear, 41, '#52b755', g.speed, 52); // green gear 44 | g = addGear(g.point, g.gear, 6, '#d03c3a', g.speed, 324); // dark red gear 45 | g = addGear(g.point, g.gear, 9, '#F00FF0', g.speed, 30); // light purple gear 46 | g = addGear(g.point, g.gear, 4, '#fec01e', g.speed, 298); // yellow gear 47 | g = addGear(g.point, g.gear, 21, '#e0cb61', g.speed, 248); // beige gear 48 | g = addGear(g.point, g.gear, 11, '#f69c9f', g.speed, 210); // pink gear 49 | g = addGear(g.point, g.gear, 8, '#157d6b', g.speed, 124); // dark green gear 50 | //g = addGear(g.point, g.gear, 8, '#ee5b32', g.speed, 322); // orange gear 51 | 52 | 53 | } 54 | 55 | function Gear() { 56 | this.angle = 0.0; 57 | this.group = new Group(); 58 | 59 | this.create = function(/*Point*/ p, /*int*/ teeth, /*color*/ c, /*int*/ speed, /*boolean*/ clockwise) { 60 | this.speed = speed; 61 | this.clockwise = clockwise; 62 | 63 | var d = teeth * scale; 64 | 65 | var outerCircle = new Path.Circle(p, d / 2); 66 | outerCircle.fillColor = c; 67 | 68 | var innerCircle = new Path.Circle(p, d / 8); 69 | innerCircle.fillColor = 'white'; 70 | 71 | this.group.addChild(this.drawTeeth((d / 2) - 5, d / scale, c, p)); 72 | } 73 | 74 | this.drawTeeth = function(/*int*/ d, /*int*/ plots, /*color*/ c, /*Point*/ p) { 75 | var increase = Math.PI * 2 / plots; 76 | var angle = 0; 77 | 78 | var teeth = new Group(); 79 | this.pos = p; 80 | 81 | var symbol = new Symbol(this.createTooth(c)); 82 | 83 | for (var i = 0; i < plots; i++) { 84 | var t = 2 * Math.PI * i / plots; 85 | var x = Math.round((d + (toothSize / 2)) * Math.cos(t)); 86 | var y = Math.round((d + (toothSize / 2)) * Math.sin(t)); 87 | 88 | var placed = symbol.place(new Point(p.x + x, p.y + y)); 89 | 90 | // 1 radian = 57.2957795 degrees 91 | placed.rotate(((180 / Math.PI) * angle) + 90); 92 | teeth.addChild(placed); 93 | angle += increase; 94 | } 95 | 96 | this.teethCount = plots; 97 | 98 | return teeth; 99 | } 100 | 101 | this.createTooth = function(/*color*/ c) { 102 | var path = new Path(); 103 | path.add(new Point(-(toothSize / 4) + 2, -(toothSize / 2))); // upper left 104 | path.add(new Point((toothSize / 4) - 2, -(toothSize / 2))); // upper right 105 | 106 | // Curve down to the bottom right point 107 | var throughPoint = new Point(new Point((toothSize / 4), -(toothSize / 2) + 4)); 108 | var toPoint = new Point((toothSize / 2), (toothSize / 2)); 109 | path.arcTo(throughPoint, toPoint); 110 | 111 | path.add(new Point(-(toothSize / 2), (toothSize / 2))); // bottom left 112 | 113 | // Curve up to the top left point 114 | throughPoint = new Point(new Point(new Point(-(toothSize / 4) , -(toothSize / 2) + 4))); 115 | toPoint = new Point(-(toothSize / 4) + 2, -(toothSize / 2)); 116 | path.arcTo(throughPoint, toPoint); 117 | path.closePath(); 118 | path.fillColor = c; 119 | 120 | return path; 121 | } 122 | 123 | this.getPoint = function() { 124 | return this.pos; 125 | } 126 | 127 | this.getToothCount = function() { 128 | return this.teethCount; 129 | } 130 | 131 | this.rot = function(/*int*/ angle) { 132 | this.group.rotate(angle); 133 | this.angle += angle; 134 | } 135 | 136 | this.getRot = function() { 137 | return this.angle; 138 | } 139 | 140 | this.spin = function() { 141 | if (this.clockwise) { 142 | this.group.rotate(this.speed); 143 | } else { 144 | this.group.rotate(-this.speed); 145 | } 146 | } 147 | } 148 | 149 | /** 150 | * This function helps us with debugging. We can stop and start 151 | * the animation whenever the user clicks the mouse. 152 | */ 153 | function onMouseUp(event) { 154 | started = !started; 155 | } 156 | 157 | function addGear(/*Point*/ p, /*Gear*/ gear1, /*int*/ g2, /*color*/ color, /*int*/ speed, /*int*/ angle) { 158 | var r1 = (gear1.getToothCount() * scale) / 2; 159 | var r2 = (g2 * scale) / 2; 160 | 161 | var p2 = new Point(p.x + ((r1 + r2 + (toothSize - 2)) * Math.cos((angle / 180) * Math.PI)), 162 | p.y + ((r1 + r2 + (toothSize - 2)) * Math.sin((angle / 180) * Math.PI))); 163 | 164 | var gear2 = new Gear(); 165 | gear2.create(p2, g2, color, speed * (gear1.getToothCount() / g2), clockwise); 166 | gears.push(gear2); 167 | 168 | /* 169 | * Now we need to rotate the gears so they match up 170 | */ 171 | var wedge = 360 / gear1.getToothCount(); 172 | var tooth = Math.floor((angle - gear1.getRot()) / wedge); 173 | var t = 2 * Math.PI * tooth / gear1.getToothCount(); 174 | var x = Math.round((r1 + (toothSize / 1.85)) * Math.cos(t)); 175 | var y = Math.round((r1 + (toothSize / 1.85)) * Math.sin(t)); 176 | 177 | var rad = gear1.getRot() * (Math.PI / 180); 178 | var x1 = (Math.cos(rad) * x) - (Math.sin(rad) * y); 179 | var y1 = (Math.cos(rad) * y) + (Math.sin(rad) * x); 180 | x = x1; 181 | y = y1; 182 | 183 | var pa1 = new Point(gear1.getPoint().x + x, gear1.getPoint().y + y); 184 | 185 | t = 2 * Math.PI * 0.5 / gear2.getToothCount(); 186 | x = Math.round((r2) * Math.cos(t)); 187 | y = Math.round((r2) * Math.sin(t)); 188 | var pad = new Point(gear2.getPoint().x + x, gear2.getPoint().y + y); 189 | 190 | var pa2 = gear2.getPoint(); 191 | var v = pa1 - pa2; 192 | var v2 = pad - pa2; 193 | 194 | gear2.rot(v.angle - v2.angle); 195 | 196 | clockwise = !clockwise; 197 | return { 198 | 'point': p2, 199 | 'speed': speed * (gear1.getToothCount() / g2), 200 | 'gear': gear2 201 | }; 202 | } 203 | 204 | /** 205 | * This function is called with each frame of the animation. 206 | */ 207 | function onFrame(event) { 208 | if (started) { 209 | for (var i = 0; i < gears.length; i++) { 210 | gears[i].spin(); 211 | } 212 | } 213 | } 214 | 215 | init(); 216 | -------------------------------------------------------------------------------- /paper_interaction.pjs: -------------------------------------------------------------------------------- 1 | var hitOptions = { 2 | fill: true, 3 | tolerance: 5 4 | }; 5 | 6 | function init() { 7 | var point = new Point(60, 60); 8 | var size = new Size(80, 80); 9 | var rectangle = new Rectangle(point, size); 10 | r = new Path.Rectangle(rectangle); 11 | r.fillColor = '#ee2a33'; 12 | } 13 | 14 | function onMouseUp(event) { 15 | var hitResult = project.hitTest(event.point, hitOptions); 16 | 17 | if (hitResult && hitResult.item) { 18 | if (hitResult.item.clicked) { 19 | hitResult.item.fillColor = '#ee2a33'; 20 | } else { 21 | hitResult.item.fillColor = '#f00ff0'; 22 | } 23 | 24 | hitResult.item.clicked = !hitResult.item.clicked; 25 | } 26 | } 27 | 28 | init(); 29 | -------------------------------------------------------------------------------- /processing_animation.java: -------------------------------------------------------------------------------- 1 | //40 degrees = 0.698131701 radians 2 | float angle = 0.698131701; 3 | 4 | void setup() { 5 | size(200, 200); 6 | smooth(); 7 | frameRate(30); 8 | main.processingAnimationStopped = false; 9 | draw(); 10 | main.processingAnimationStopped = true; 11 | } 12 | 13 | void draw() { 14 | if (main.processingAnimationStopped) { 15 | return; 16 | } 17 | 18 | background(#ffffff); 19 | translate(100, 100); 20 | fill(#52b755); 21 | noStroke(); 22 | ellipse(0, 0, 20, 20); 23 | 24 | rotate(angle); 25 | angle += 0.1; 26 | noFill(); 27 | stroke(#52b755); 28 | strokeWeight(2); 29 | rect(-40, -40, 80, 80); 30 | 31 | } 32 | 33 | void mousePressed() { 34 | main.processingAnimationStopped = !main.processingAnimationStopped; 35 | } 36 | -------------------------------------------------------------------------------- /processing_circle.java: -------------------------------------------------------------------------------- 1 | void setup() { 2 | size(200, 200); 3 | smooth(); 4 | } 5 | 6 | void draw() { 7 | background(#ffffff); 8 | translate(100, 100); 9 | fill(#52b755); 10 | noStroke(); 11 | ellipse(0, 0, 20, 20); 12 | } 13 | -------------------------------------------------------------------------------- /processing_gears.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ProcessingJS Gears 6 | 7 | 8 | 9 | 10 | 11 | 22 | 23 | 24 | 25 | Fork me on GitHub 26 | 27 | 28 |

Gears in Processing.js

29 | 30 | Paper vs. Processing vs. Raphaël 31 | 32 | 33 | -------------------------------------------------------------------------------- /processing_gears.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright 2011 Zack Grossbart 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | ******************************************************************************/ 18 | 19 | boolean stopped = false; 20 | boolean clockwise = false; 21 | float angle1 = 0.0; 22 | float angle2 = 0.0; 23 | 24 | ArrayList gears = new ArrayList(); 25 | int toothSize = 30; 26 | 27 | void setup() { 28 | size(960, 650); 29 | smooth(); 30 | 31 | int speed = 0.02; 32 | 33 | int x = width / 6; 34 | int y = (height / 3) + 30; 35 | 36 | Gear redGear = new Gear(x, y, speed, 0, #ee2a33, 15, true); // red gear 37 | gears.add(redGear); 38 | 39 | HashMap map = addGear(x, y, redGear, 9, #00aeef, speed, 30); // blue gear 40 | map = addGear(map.get('x'), map.get('y'), map.get('gear'), 11, #52b755, map.get('speed'), 125); // green gear 41 | map = addGear(map.get('x'), map.get('y'), map.get('gear'), 38, #d03c3a, map.get('speed'), 25); // dark red gear 42 | map = addGear(map.get('x'), map.get('y'), map.get('gear'), 4, #ac6a13, map.get('speed'), 318); // light brown gear 43 | map = addGear(map.get('x'), map.get('y'), map.get('gear'), 7, #F00FF0, map.get('speed'), 281); // light purple gear 44 | map = addGear(map.get('x'), map.get('y'), map.get('gear'), 8, #f8b724, map.get('speed'), 257); // yellow gear 45 | map = addGear(map.get('x'), map.get('y'), map.get('gear'), 16, #e0cb61, map.get('speed'), 188); // beige gear 46 | map = addGear(map.get('x'), map.get('y'), map.get('gear'), 4, #f69c9f, map.get('speed'), 201); // pink gear 47 | map = addGear(map.get('x'), map.get('y'), map.get('gear'), 7, #825f84, map.get('speed'), 175); // pink gear 48 | 49 | frameRate(30); 50 | //drawX(); 51 | } 52 | 53 | void draw() { 54 | if (stopped) { 55 | return; 56 | } 57 | 58 | background(236); 59 | for (int i = 0; i < gears.size(); i++) { 60 | gears.get(i).drawGear(); 61 | } 62 | } 63 | 64 | HashMap addGear(int x, int y, Gear gear1, int g2, color c, int speed, int angle) { 65 | float r1 = (gear1.getToothCount() * 15) / 2; 66 | float r2 = (g2 * 15) / 2; 67 | 68 | int x2 = x + ((r1 + r2 + (toothSize - 2)) * Math.cos((angle / 180) * Math.PI)); 69 | int y2 = y + ((r1 + r2 + (toothSize - 2)) * Math.sin((angle / 180) * Math.PI)); 70 | 71 | Gear gear2 = new Gear(x2, y2, speed * (gear1.getToothCount() / g2), 0, c, g2, clockwise); 72 | gears.add(gear2); 73 | 74 | /* 75 | * Now we need to rotate the gears so they match up 76 | */ 77 | float wedge = 360 / gear1.getToothCount(); 78 | int tooth = Math.floor((angle - gear1.getRot()) / wedge); 79 | double t = 2 * Math.PI * tooth / gear1.getToothCount(); 80 | int x = (int) Math.round((r1 + (toothSize / 1.85)) * Math.cos(t)); 81 | int y = (int) Math.round((r1 + (toothSize / 1.85)) * Math.sin(t)); 82 | 83 | double rad = gear1.getRot() * (Math.PI / 180); 84 | int x1 = (Math.cos(rad) * x) - (Math.sin(rad) * y); 85 | int y1 = (Math.cos(rad) * y) + (Math.sin(rad) * x); 86 | x = x1; 87 | y = y1; 88 | 89 | int pa1x = gear1.getX() + x; 90 | int pa1y = gear1.getY() + y; 91 | 92 | t = 2 * Math.PI * 0.5 / gear2.getToothCount(); 93 | x = Math.round((r2) * Math.cos(t)); 94 | y = Math.round((r2) * Math.sin(t)); 95 | int padx = gear2.getX() + x; 96 | int pady = gear2.getY() + y; 97 | 98 | PVector v1 = new PVector(pa1x - gear2.getX(), 99 | pa1y - gear2.getY()); 100 | PVector v2 = new PVector(padx - gear2.getX(), 101 | pady - gear2.getY()); 102 | 103 | gear2.rot(PVector.angleBetween(v1, v2)); 104 | 105 | clockwise = !clockwise; 106 | 107 | HashMap map = new HashMap(); 108 | map.put('x', x2); 109 | map.put('y', y2); 110 | map.put('speed', speed * (gear1.getToothCount() / g2)); 111 | map.put('gear', gear2); 112 | 113 | return map; 114 | } 115 | 116 | 117 | class Gear { 118 | int m_x; 119 | int m_y; 120 | color m_c; 121 | float m_speed; 122 | int m_angle; 123 | int m_teeth; 124 | boolean m_clockwise; 125 | 126 | Gear(int x, int y, float speed, int angle, color c, int teeth, boolean clockwise) { 127 | m_x = x; 128 | m_y = y; 129 | m_speed = speed; 130 | m_angle = angle; 131 | m_c = c; 132 | m_teeth = teeth; 133 | m_clockwise = clockwise; 134 | } 135 | 136 | void drawGear() { 137 | spin(); 138 | pushMatrix(); 139 | translate(m_x, m_y); 140 | 141 | rotate(m_angle); 142 | noStroke(); 143 | 144 | int d = m_teeth * 15; 145 | 146 | /* 147 | The gear circle 148 | */ 149 | fill(m_c); 150 | ellipse(0, 0, d, d); 151 | 152 | /* 153 | The inner gap 154 | */ 155 | fill(); 156 | ellipse(0, 0, d / 4, d / 4); 157 | 158 | drawTeeth((d / 2) - 5, m_teeth, m_c); 159 | 160 | popMatrix(); 161 | } 162 | 163 | void rot(int angle) { 164 | m_angle -= angle; 165 | } 166 | 167 | int getRot() { 168 | return (180 / Math.PI) * m_angle; 169 | } 170 | 171 | void spin() { 172 | if (m_clockwise) { 173 | m_angle += m_speed; 174 | } else { 175 | m_angle -= m_speed; 176 | } 177 | } 178 | 179 | void drawTeeth(int d, int plots) { 180 | float increase = Math.PI * 2 / plots; 181 | float angle = 0; 182 | float x = 0; 183 | float y = 0; 184 | 185 | pushMatrix(); 186 | 187 | for (var i = 0; i < plots; i++ ) { 188 | pushMatrix(); 189 | double t = 2 * Math.PI * i / plots; 190 | int x = (int) Math.round((d + (toothSize / 2)) * Math.cos(t)); 191 | int y = (int) Math.round((d + (toothSize / 2)) * Math.sin(t)); 192 | 193 | translate(x, y); 194 | 195 | fill(m_c); 196 | rotate(angle - 55); 197 | 198 | beginShape(); 199 | vertex(-(toothSize / 4) + 2, -(toothSize / 2)); // upper left 200 | vertex((toothSize / 4) - 6, -(toothSize / 2)); // upper right 201 | vertex(toothSize / 4, -(toothSize / 2) + 8); // upper right bump 202 | vertex(toothSize / 2, toothSize / 2); // bottom right 203 | vertex(-(toothSize / 2), toothSize / 2); // bottom left 204 | vertex(-(toothSize / 2) + 4, -(toothSize / 2) + 8); // upper left bump 205 | endShape(); 206 | angle += increase; 207 | 208 | //fill(255, 255, 0); 209 | //ellipse(0, 0, 10, 10); 210 | popMatrix(); 211 | } 212 | popMatrix(); 213 | } 214 | 215 | int getX() { 216 | return m_x; 217 | } 218 | 219 | int getY() { 220 | return m_y; 221 | } 222 | 223 | int getToothCount() { 224 | return m_teeth; 225 | } 226 | } 227 | 228 | void mousePressed() { 229 | stopped = !stopped; 230 | } 231 | -------------------------------------------------------------------------------- /processing_interaction.java: -------------------------------------------------------------------------------- 1 | float bx; 2 | float by; 3 | int bs = 20; 4 | boolean clicked = false; 5 | 6 | void setup() { 7 | size(200, 200); 8 | bx = width/2.0; 9 | by = height/2.0; 10 | noStroke(); 11 | fill(#52b755); 12 | frameRate(10); 13 | } 14 | 15 | void draw() { 16 | background(#ffffff); 17 | 18 | translate(100, 100); 19 | rect(-40, -40, 80, 80); 20 | } 21 | 22 | void mousePressed() { 23 | 24 | // Test if the cursor is over the box 25 | if (mouseX > bx-bs && mouseX < bx+bs && 26 | mouseY > by-bs && mouseY < by+bs) { 27 | if (clicked) { 28 | fill(#52b755); 29 | } else { 30 | fill(#f00ff0); 31 | } 32 | clicked = !clicked; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /raphael-min.js: -------------------------------------------------------------------------------- 1 | // ┌─────────────────────────────────────────────────────────────────────┐ \\ 2 | // │ Raphaël 2.0.1 - JavaScript Vector Library │ \\ 3 | // ├─────────────────────────────────────────────────────────────────────┤ \\ 4 | // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ 5 | // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ 6 | // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ 7 | // └─────────────────────────────────────────────────────────────────────┘ \\ 8 | (function(a){var b="0.4.0",c="hasOwnProperty",d=/[\.\/]/,e="*",f=function(){},g=function(a,b){return a-b},h,i,j={n:{}},k=function(a,b){var c=j,d=i,e=Array.prototype.slice.call(arguments,2),f=k.listeners(a),l=0,m=!1,n,o=[],p={},q=[],r=[];h=a,i=0;for(var s=0,t=f.length;sf*b.top){e=b.percents[y],p=b.percents[y-1]||0,t=t/b.top*(e-p),o=b.percents[y+1],j=b.anim[e];break}f&&d.attr(b.anim[b.percents[y]])}if(!!j){if(!k){for(var A in j)if(j[g](A))if(U[g](A)||d.paper.customAttributes[g](A)){u[A]=d.attr(A),u[A]==null&&(u[A]=T[A]),v[A]=j[A];switch(U[A]){case C:w[A]=(v[A]-u[A])/t;break;case"colour":u[A]=a.getRGB(u[A]);var B=a.getRGB(v[A]);w[A]={r:(B.r-u[A].r)/t,g:(B.g-u[A].g)/t,b:(B.b-u[A].b)/t};break;case"path":var D=bG(u[A],v[A]),E=D[1];u[A]=D[0],w[A]=[];for(y=0,z=u[A].length;yd)return d;while(cf?c=e:d=e,e=(d-c)/2+c}return e}function n(a,b){var c=o(a,b);return((l*c+k)*c+j)*c}function m(a){return((i*a+h)*a+g)*a}var g=3*b,h=3*(d-b)-g,i=1-g-h,j=3*c,k=3*(e-c)-j,l=1-j-k;return n(a,1/(200*f))}function cd(){return this.x+q+this.y+q+this.width+" × "+this.height}function cc(){return this.x+q+this.y}function bQ(a,b,c,d,e,f){a!=null?(this.a=+a,this.b=+b,this.c=+c,this.d=+d,this.e=+e,this.f=+f):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0)}function bw(a){var b=[];for(var c=0,d=a.length;d-2>c;c+=2){var e=[{x:+a[c],y:+a[c+1]},{x:+a[c],y:+a[c+1]},{x:+a[c+2],y:+a[c+3]},{x:+a[c+4],y:+a[c+5]}];d-4==c?(e[0]={x:+a[c-2],y:+a[c-1]},e[3]=e[2]):c&&(e[0]={x:+a[c-2],y:+a[c-1]}),b.push(["C",(-e[0].x+6*e[1].x+e[2].x)/6,(-e[0].y+6*e[1].y+e[2].y)/6,(e[1].x+6*e[2].x-e[3].x)/6,(e[1].y+6*e[2].y-e[3].y)/6,e[2].x,e[2].y])}return b}function bv(){return this.hex}function bt(a,b,c){function d(){var e=Array.prototype.slice.call(arguments,0),f=e.join("␀"),h=d.cache=d.cache||{},i=d.count=d.count||[];if(h[g](f)){bs(i,f);return c?c(h[f]):h[f]}i.length>=1e3&&delete h[i.shift()],i.push(f),h[f]=a[m](b,e);return c?c(h[f]):h[f]}return d}function bs(a,b){for(var c=0,d=a.length;c',bk=bj.firstChild,bk.style.behavior="url(#default#VML)";if(!bk||typeof bk.adj!="object")return a.type=p;bj=null}a.svg=!(a.vml=a.type=="VML"),a._Paper=j,a.fn=k=j.prototype=a.prototype,a._id=0,a._oid=0,a.is=function(a,b){b=v.call(b);if(b=="finite")return!M[g](+a);if(b=="array")return a instanceof Array;return b=="null"&&a===null||b==typeof a&&a!==null||b=="object"&&a===Object(a)||b=="array"&&Array.isArray&&Array.isArray(a)||H.call(a).slice(8,-1).toLowerCase()==b},a.angle=function(b,c,d,e,f,g){if(f==null){var h=b-d,i=c-e;if(!h&&!i)return 0;return(180+w.atan2(-i,-h)*180/B+360)%360}return a.angle(b,c,f,g)-a.angle(d,e,f,g)},a.rad=function(a){return a%360*B/180},a.deg=function(a){return a*180/B%360},a.snapTo=function(b,c,d){d=a.is(d,"finite")?d:10;if(a.is(b,E)){var e=b.length;while(e--)if(z(b[e]-c)<=d)return b[e]}else{b=+b;var f=c%b;if(fb-d)return c-f+b}return c};var bl=a.createUUID=function(a,b){return function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(a,b).toUpperCase()}}(/[xy]/g,function(a){var b=w.random()*16|0,c=a=="x"?b:b&3|8;return c.toString(16)});a.setWindow=function(b){eve("setWindow",a,h.win,b),h.win=b,h.doc=h.win.document,a._engine.initWin&&a._engine.initWin(h.win)};var bm=function(b){if(a.vml){var c=/^\s+|\s+$/g,d;try{var e=new ActiveXObject("htmlfile");e.write(""),e.close(),d=e.body}catch(f){d=createPopup().document.body}var g=d.createTextRange();bm=bt(function(a){try{d.style.color=r(a).replace(c,p);var b=g.queryCommandValue("ForeColor");b=(b&255)<<16|b&65280|(b&16711680)>>>16;return"#"+("000000"+b.toString(16)).slice(-6)}catch(e){return"none"}})}else{var i=h.doc.createElement("i");i.title="Raphaël Colour Picker",i.style.display="none",h.doc.body.appendChild(i),bm=bt(function(a){i.style.color=a;return h.doc.defaultView.getComputedStyle(i,p).getPropertyValue("color")})}return bm(b)},bn=function(){return"hsb("+[this.h,this.s,this.b]+")"},bo=function(){return"hsl("+[this.h,this.s,this.l]+")"},bp=function(){return this.hex},bq=function(b,c,d){c==null&&a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b&&(d=b.b,c=b.g,b=b.r);if(c==null&&a.is(b,D)){var e=a.getRGB(b);b=e.r,c=e.g,d=e.b}if(b>1||c>1||d>1)b/=255,c/=255,d/=255;return[b,c,d]},br=function(b,c,d,e){b*=255,c*=255,d*=255;var f={r:b,g:c,b:d,hex:a.rgb(b,c,d),toString:bp};a.is(e,"finite")&&(f.opacity=e);return f};a.color=function(b){var c;a.is(b,"object")&&"h"in b&&"s"in b&&"b"in b?(c=a.hsb2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):a.is(b,"object")&&"h"in b&&"s"in b&&"l"in b?(c=a.hsl2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):(a.is(b,"string")&&(b=a.getRGB(b)),a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b?(c=a.rgb2hsl(b),b.h=c.h,b.s=c.s,b.l=c.l,c=a.rgb2hsb(b),b.v=c.b):(b={hex:"none"},b.r=b.g=b.b=b.h=b.s=b.v=b.l=-1)),b.toString=bp;return b},a.hsb2rgb=function(a,b,c,d){this.is(a,"object")&&"h"in a&&"s"in a&&"b"in a&&(c=a.b,b=a.s,a=a.h,d=a.o),a*=360;var e,f,g,h,i;a=a%360/60,i=c*b,h=i*(1-z(a%2-1)),e=f=g=c-i,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return br(e,f,g,d)},a.hsl2rgb=function(a,b,c,d){this.is(a,"object")&&"h"in a&&"s"in a&&"l"in a&&(c=a.l,b=a.s,a=a.h);if(a>1||b>1||c>1)a/=360,b/=100,c/=100;a*=360;var e,f,g,h,i;a=a%360/60,i=2*b*(c<.5?c:1-c),h=i*(1-z(a%2-1)),e=f=g=c-i/2,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return br(e,f,g,d)},a.rgb2hsb=function(a,b,c){c=bq(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;f=x(a,b,c),g=f-y(a,b,c),d=g==0?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=(d+360)%6*60/360,e=g==0?0:g/f;return{h:d,s:e,b:f,toString:bn}},a.rgb2hsl=function(a,b,c){c=bq(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;g=x(a,b,c),h=y(a,b,c),i=g-h,d=i==0?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=(d+360)%6*60/360,f=(g+h)/2,e=i==0?0:f<.5?i/(2*f):i/(2-2*f);return{h:d,s:e,l:f,toString:bo}},a._path2string=function(){return this.join(",").replace(X,"$1")};var bu=a._preload=function(a,b){var c=h.doc.createElement("img");c.style.cssText="position:absolute;left:-9999em;top:-9999em",c.onload=function(){b.call(this),this.onload=null,h.doc.body.removeChild(this)},c.onerror=function(){h.doc.body.removeChild(this)},h.doc.body.appendChild(c),c.src=a};a.getRGB=bt(function(b){if(!b||!!((b=r(b)).indexOf("-")+1))return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:bv};if(b=="none")return{r:-1,g:-1,b:-1,hex:"none",toString:bv};!W[g](b.toLowerCase().substring(0,2))&&b.charAt()!="#"&&(b=bm(b));var c,d,e,f,h,i,j,k=b.match(L);if(k){k[2]&&(f=R(k[2].substring(5),16),e=R(k[2].substring(3,5),16),d=R(k[2].substring(1,3),16)),k[3]&&(f=R((i=k[3].charAt(3))+i,16),e=R((i=k[3].charAt(2))+i,16),d=R((i=k[3].charAt(1))+i,16)),k[4]&&(j=k[4][s](V),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),k[1].toLowerCase().slice(0,4)=="rgba"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100));if(k[5]){j=k[5][s](V),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsba"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsb2rgb(d,e,f,h)}if(k[6]){j=k[6][s](V),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsla"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsl2rgb(d,e,f,h)}k={r:d,g:e,b:f,toString:bv},k.hex="#"+(16777216|f|e<<8|d<<16).toString(16).slice(1),a.is(h,"finite")&&(k.opacity=h);return k}return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:bv}},a),a.hsb=bt(function(b,c,d){return a.hsb2rgb(b,c,d).hex}),a.hsl=bt(function(b,c,d){return a.hsl2rgb(b,c,d).hex}),a.rgb=bt(function(a,b,c){return"#"+(16777216|c|b<<8|a<<16).toString(16).slice(1)}),a.getColor=function(a){var b=this.getColor.start=this.getColor.start||{h:0,s:1,b:a||.75},c=this.hsb2rgb(b.h,b.s,b.b);b.h+=.075,b.h>1&&(b.h=0,b.s-=.2,b.s<=0&&(this.getColor.start={h:0,s:1,b:b.b}));return c.hex},a.getColor.reset=function(){delete this.start},a.parsePathString=bt(function(b){if(!b)return null;var c={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},d=[];a.is(b,E)&&a.is(b[0],E)&&(d=by(b)),d.length||r(b).replace(Y,function(a,b,e){var f=[],g=b.toLowerCase();e.replace($,function(a,b){b&&f.push(+b)}),g=="m"&&f.length>2&&(d.push([b][n](f.splice(0,2))),g="l",b=b=="m"?"l":"L");if(g=="r")d.push([b][n](f));else while(f.length>=c[g]){d.push([b][n](f.splice(0,c[g])));if(!c[g])break}}),d.toString=a._path2string;return d}),a.parseTransformString=bt(function(b){if(!b)return null;var c={r:3,s:4,t:2,m:6},d=[];a.is(b,E)&&a.is(b[0],E)&&(d=by(b)),d.length||r(b).replace(Z,function(a,b,c){var e=[],f=v.call(b);c.replace($,function(a,b){b&&e.push(+b)}),d.push([b][n](e))}),d.toString=a._path2string;return d}),a.findDotsAtSegment=function(a,b,c,d,e,f,g,h,i){var j=1-i,k=A(j,3),l=A(j,2),m=i*i,n=m*i,o=k*a+l*3*i*c+j*3*i*i*e+n*g,p=k*b+l*3*i*d+j*3*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,x=j*e+i*g,y=j*f+i*h,z=90-w.atan2(q-s,r-t)*180/B;(q>s||r1&&(v=w.sqrt(v),c=v*c,d=v*d);var x=c*c,y=d*d,A=(f==g?-1:1)*w.sqrt(z((x*y-x*u*u-y*t*t)/(x*u*u+y*t*t))),C=A*c*u/d+(a+h)/2,D=A*-d*t/c+(b+i)/2,E=w.asin(((b-D)/d).toFixed(9)),F=w.asin(((i-D)/d).toFixed(9));E=aF&&(E=E-B*2),!g&&F>E&&(F=F-B*2)}else E=j[0],F=j[1],C=j[2],D=j[3];var G=F-E;if(z(G)>k){var H=F,I=h,J=i;F=E+k*(g&&F>E?1:-1),h=C+c*w.cos(F),i=D+d*w.sin(F),m=bD(h,i,c,d,e,0,g,I,J,[F,H,C,D])}G=F-E;var K=w.cos(E),L=w.sin(E),M=w.cos(F),N=w.sin(F),O=w.tan(G/4),P=4/3*c*O,Q=4/3*d*O,R=[a,b],S=[a+P*L,b-Q*K],T=[h+P*N,i-Q*M],U=[h,i];S[0]=2*R[0]-S[0],S[1]=2*R[1]-S[1];if(j)return[S,T,U][n](m);m=[S,T,U][n](m).join()[s](",");var V=[];for(var W=0,X=m.length;W"1e12"&&(l=.5),z(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bE(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bE(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y)),i=f-2*d+b-(h-2*f+d),j=2*(d-b)-2*(f-d),k=b-d,l=(-j+w.sqrt(j*j-4*i*k))/2/i,n=(-j-w.sqrt(j*j-4*i*k))/2/i,z(l)>"1e12"&&(l=.5),z(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bE(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bE(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y));return{min:{x:y[m](0,p),y:y[m](0,o)},max:{x:x[m](0,p),y:x[m](0,o)}}}),bG=a._path2curve=bt(function(a,b){var c=bA(a),d=b&&bA(b),e={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},f={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},g=function(a,b){var c,d;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null);switch(a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"][n](bD[m](0,[b.x,b.y][n](a.slice(1))));break;case"S":c=b.x+(b.x-(b.bx||b.x)),d=b.y+(b.y-(b.by||b.y)),a=["C",c,d][n](a.slice(1));break;case"T":b.qx=b.x+(b.x-(b.qx||b.x)),b.qy=b.y+(b.y-(b.qy||b.y)),a=["C"][n](bC(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"][n](bC(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"][n](bB(b.x,b.y,a[1],a[2]));break;case"H":a=["C"][n](bB(b.x,b.y,a[1],b.y));break;case"V":a=["C"][n](bB(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"][n](bB(b.x,b.y,b.X,b.Y))}return a},h=function(a,b){if(a[b].length>7){a[b].shift();var e=a[b];while(e.length)a.splice(b++,0,["C"][n](e.splice(0,6)));a.splice(b,1),k=x(c.length,d&&d.length||0)}},i=function(a,b,e,f,g){a&&b&&a[g][0]=="M"&&b[g][0]!="M"&&(b.splice(g,0,["M",f.x,f.y]),e.bx=0,e.by=0,e.x=a[g][1],e.y=a[g][2],k=x(c.length,d&&d.length||0))};for(var j=0,k=x(c.length,d&&d.length||0);j=j)return p;o=p}if(j==null)return k},cg=function(b,c){return function(d,e,f){d=bG(d);var g,h,i,j,k="",l={},m,n=0;for(var o=0,p=d.length;oe){if(c&&!l.start){m=cf(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n),k+=["C"+m.start.x,m.start.y,m.m.x,m.m.y,m.x,m.y];if(f)return k;l.start=k,k=["M"+m.x,m.y+"C"+m.n.x,m.n.y,m.end.x,m.end.y,i[5],i[6]].join(),n+=j,g=+i[5],h=+i[6];continue}if(!b&&!c){m=cf(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n);return{x:m.x,y:m.y,alpha:m.alpha}}}n+=j,g=+i[5],h=+i[6]}k+=i.shift()+i}l.end=k,m=b?n:c?l:a.findDotsAtSegment(g,h,i[0],i[1],i[2],i[3],i[4],i[5],1),m.alpha&&(m={x:m.x,y:m.y,alpha:m.alpha});return m}},ch=cg(1),ci=cg(),cj=cg(0,1);a.getTotalLength=ch,a.getPointAtLength=ci,a.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return cj(a,b).end;var d=cj(a,c,1);return b?cj(d,b).end:d},b$.getTotalLength=function(){if(this.type=="path"){if(this.node.getTotalLength)return this.node.getTotalLength();return ch(this.attrs.path)}},b$.getPointAtLength=function(a){if(this.type=="path")return ci(this.attrs.path,a)},b$.getSubpath=function(b,c){if(this.type=="path")return a.getSubpath(this.attrs.path,b,c)};var ck=a.easing_formulas={linear:function(a){return a},"<":function(a){return A(a,1.7)},">":function(a){return A(a,.48)},"<>":function(a){var b=.48-a/1.04,c=w.sqrt(.1734+b*b),d=c-b,e=A(z(d),1/3)*(d<0?-1:1),f=-c-b,g=A(z(f),1/3)*(f<0?-1:1),h=e+g+.5;return(1-h)*3*h*h+h*h*h},backIn:function(a){var b=1.70158;return a*a*((b+1)*a-b)},backOut:function(a){a=a-1;var b=1.70158;return a*a*((b+1)*a+b)+1},elastic:function(a){if(a==!!a)return a;return A(2,-10*a)*w.sin((a-.075)*2*B/.3)+1},bounce:function(a){var b=7.5625,c=2.75,d;a<1/c?d=b*a*a:a<2/c?(a-=1.5/c,d=b*a*a+.75):a<2.5/c?(a-=2.25/c,d=b*a*a+.9375):(a-=2.625/c,d=b*a*a+.984375);return d}};ck.easeIn=ck["ease-in"]=ck["<"],ck.easeOut=ck["ease-out"]=ck[">"],ck.easeInOut=ck["ease-in-out"]=ck["<>"],ck["back-in"]=ck.backIn,ck["back-out"]=ck.backOut;var cl=[],cm=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){setTimeout(a,16)},cn=function(){var b=+(new Date),c=0;for(;c1&&!d.next){for(s in k)k[g](s)&&(r[s]=d.totalOrigin[s]);d.el.attr(r),cr(d.anim,d.el,d.anim.percents[0],null,d.totalOrigin,d.repeat-1)}d.next&&!d.stop&&cr(d.anim,d.el,d.next,null,d.totalOrigin,d.repeat)}}a.svg&&m&&m.paper&&m.paper.safari(),cl.length&&cm(cn)},co=function(a){return a>255?255:a<0?0:a};b$.animateWith=function(b,c,d,e,f,g){var h=d?a.animation(d,e,f,g):c,i=b.status(c);return this.animate(h).status(h,i*c.ms/h.ms)},b$.onAnimation=function(a){a?eve.on("anim.frame."+this.id,a):eve.unbind("anim.frame."+this.id);return this},cq.prototype.delay=function(a){var b=new cq(this.anim,this.ms);b.times=this.times,b.del=+a||0;return b},cq.prototype.repeat=function(a){var b=new cq(this.anim,this.ms);b.del=this.del,b.times=w.floor(x(a,0))||1;return b},a.animation=function(b,c,d,e){if(b instanceof cq)return b;if(a.is(d,"function")||!d)e=e||d||null,d=null;b=Object(b),c=+c||0;var f={},h,i;for(i in b)b[g](i)&&Q(i)!=i&&Q(i)+"%"!=i&&(h=!0,f[i]=b[i]);if(!h)return new cq(b,c);d&&(f.easing=d),e&&(f.callback=e);return new cq({100:f},c)},b$.animate=function(b,c,d,e){var f=this;if(f.removed){e&&e.call(f);return f}var g=b instanceof cq?b:a.animation(b,c,d,e);cr(g,f,g.percents[0],null,f.attr());return f},b$.setTime=function(a,b){a&&b!=null&&this.status(a,y(b,a.ms)/a.ms);return this},b$.status=function(a,b){var c=[],d=0,e,f;if(b!=null){cr(a,this,-1,y(b,1));return this}e=cl.length;for(;d.5)*2-1;i(m-.5,2)+i(n-.5,2)>.25&&(n=f.sqrt(.25-i(m-.5,2))*e+.5)&&n!=.5&&(n=n.toFixed(5)-1e-5*e)}return l}),e=e.split(/\s*\-\s*/);if(j=="linear"){var t=e.shift();t=-d(t);if(isNaN(t))return null;var u=[0,0,f.cos(a.rad(t)),f.sin(a.rad(t))],v=1/(g(h(u[2]),h(u[3]))||1);u[2]*=v,u[3]*=v,u[2]<0&&(u[0]=-u[2],u[2]=0),u[3]<0&&(u[1]=-u[3],u[3]=0)}var w=a._parseDots(e);if(!w)return null;k=k.replace(/[\(\)\s,\xb0#]/g,"_"),b.gradient&&k!=b.gradient.id&&(p.defs.removeChild(b.gradient),delete b.gradient);if(!b.gradient){s=q(j+"Gradient",{id:k}),b.gradient=s,q(s,j=="radial"?{fx:m,fy:n}:{x1:u[0],y1:u[1],x2:u[2],y2:u[3],gradientTransform:b.matrix.invert()}),p.defs.appendChild(s);for(var x=0,y=w.length;x1?G.opacity/100:G.opacity});case"stroke":G=a.getRGB(p),i.setAttribute(o,G.hex),o=="stroke"&&G[b]("opacity")&&q(i,{"stroke-opacity":G.opacity>1?G.opacity/100:G.opacity}),o=="stroke"&&d._.arrows&&("startString"in d._.arrows&&t(d,d._.arrows.startString),"endString"in d._.arrows&&t(d,d._.arrows.endString,1));break;case"gradient":(d.type=="circle"||d.type=="ellipse"||c(p).charAt()!="r")&&r(d,p);break;case"opacity":k.gradient&&!k[b]("stroke-opacity")&&q(i,{"stroke-opacity":p>1?p/100:p});case"fill-opacity":if(k.gradient){H=a._g.doc.getElementById(i.getAttribute("fill").replace(/^url\(#|\)$/g,l)),H&&(I=H.getElementsByTagName("stop"),q(I[I.length-1],{"stop-opacity":p}));break};default:o=="font-size"&&(p=e(p,10)+"px");var J=o.replace(/(\-.)/g,function(a){return a.substring(1).toUpperCase()});i.style[J]=p,d._.dirty=1,i.setAttribute(o,p)}}y(d,f),i.style.visibility=m},x=1.2,y=function(d,f){if(d.type=="text"&&!!(f[b]("text")||f[b]("font")||f[b]("font-size")||f[b]("x")||f[b]("y"))){var g=d.attrs,h=d.node,i=h.firstChild?e(a._g.doc.defaultView.getComputedStyle(h.firstChild,l).getPropertyValue("font-size"),10):10;if(f[b]("text")){g.text=f.text;while(h.firstChild)h.removeChild(h.firstChild);var j=c(f.text).split("\n"),k=[],m;for(var n=0,o=j.length;n"));var $=X.getBoundingClientRect();t.W=m.w=($.right-$.left)/Y,t.H=m.h=($.bottom-$.top)/Y,t.X=m.x,t.Y=m.y+t.H/2,("x"in i||"y"in i)&&(t.path.v=a.format("m{0},{1}l{2},{1}",f(m.x*u),f(m.y*u),f(m.x*u)+1));var _=["x","y","text","font","font-family","font-weight","font-style","font-size"];for(var ba=0,bb=_.length;ba.25&&(c=e.sqrt(.25-i(b-.5,2))*((c>.5)*2-1)+.5),m=b+n+c);return o}),f=f.split(/\s*\-\s*/);if(l=="linear"){var p=f.shift();p=-d(p);if(isNaN(p))return null}var q=a._parseDots(f);if(!q)return null;b=b.shape||b.node;if(q.length){b.removeChild(g),g.on=!0,g.method="none",g.color=q[0].color,g.color2=q[q.length-1].color;var r=[];for(var s=0,t=q.length;s')}}catch(c){F=function(a){return b.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}},a._engine.initWin(a._g.win),a._engine.create=function(){var b=a._getContainer.apply(0,arguments),c=b.container,d=b.height,e,f=b.width,g=b.x,h=b.y;if(!c)throw new Error("VML container not found.");var i=new a._Paper,j=i.canvas=a._g.doc.createElement("div"),k=j.style;g=g||0,h=h||0,f=f||512,d=d||342,i.width=f,i.height=d,f==+f&&(f+="px"),d==+d&&(d+="px"),i.coordsize=u*1e3+n+u*1e3,i.coordorigin="0 0",i.span=a._g.doc.createElement("span"),i.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;",j.appendChild(i.span),k.cssText=a.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",f,d),c==1?(a._g.doc.body.appendChild(j),k.left=g+"px",k.top=h+"px",k.position="absolute"):c.firstChild?c.insertBefore(j,c.firstChild):c.appendChild(j),i.renderfix=function(){};return i},a.prototype.clear=function(){a.eve("clear",this),this.canvas.innerHTML=o,this.span=a._g.doc.createElement("span"),this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",this.canvas.appendChild(this.span),this.bottom=this.top=null},a.prototype.remove=function(){a.eve("remove",this),this.canvas.parentNode.removeChild(this.canvas);for(var b in this)this[b]=typeof this[b]=="function"?a._removedFactory(b):null;return!0};var G=a.st;for(var H in E)E[b](H)&&!G[b](H)&&(G[H]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(H))}(window.Raphael) -------------------------------------------------------------------------------- /raphael_animation.js: -------------------------------------------------------------------------------- 1 | Raphael('raphaelAnimation', 200, 200, function () { 2 | var paper = this, 3 | anim; 4 | 5 | var c = paper.circle(100, 100, 10); 6 | c.attr({ 7 | fill: '#00aeef', 8 | stroke: 'none' 9 | }); 10 | 11 | var r = paper.rect(60, 60, 80, 80); 12 | r.attr({ 13 | 'stroke-width': 2, 14 | stroke: '#00aeef', 15 | fill: "#000", 16 | "fill-opacity": 0 17 | }); 18 | r.click(function () { 19 | if (anim) { 20 | r.stop(); 21 | } else { 22 | r.animate(a); 23 | } 24 | anim = !anim; 25 | }); 26 | 27 | r.rotate(60); 28 | 29 | var a = Raphael.animation({transform: "...r360"}, 3000).repeat(Infinity); 30 | 31 | }); 32 | -------------------------------------------------------------------------------- /raphael_circle.js: -------------------------------------------------------------------------------- 1 | Raphael('raphaelCircle', 200, 200, function () { 2 | this.circle(100, 100, 10).attr({ 3 | fill: '#00aeef', 4 | stroke: 'none' 5 | }); 6 | }); -------------------------------------------------------------------------------- /raphael_gears.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Raphaël Gears 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 24 | 25 | 26 | 27 | 28 | Fork me on GitHub 29 | 30 |
31 | 32 |

Gears in Raphaël

33 | 34 | Paper vs. Processing vs. Raphaël 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /raphael_gears.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * 3 | * Copyright 2011 Zack Grossbart 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | ******************************************************************************/ 18 | 19 | var scale = 15; 20 | var toothSize = 28; 21 | var clockwise = false; 22 | 23 | 24 | g = { 25 | stopped: false, 26 | create: function(/*Point*/ p, /*int*/ teeth, /*string*/ c, /*int*/ speed, /*boolean*/ clockwise) { 27 | 28 | g.speed = speed; 29 | g.clockwise = clockwise; 30 | 31 | var d = teeth * scale; 32 | 33 | var outerCircle = g.paper.circle(p.x, p.y, d / 2); 34 | outerCircle.attr({ 35 | fill: c, 36 | stroke: c 37 | }); 38 | outerCircle.click(function() { 39 | g.stopped = !g.stopped; 40 | }); 41 | 42 | var innerCircle = g.paper.circle(p.x, p.y, d / 8); 43 | innerCircle.attr({ 44 | fill: 'white', 45 | stroke: 'white' 46 | }); 47 | innerCircle.click(function() { 48 | g.stopped = !g.stopped; 49 | }); 50 | 51 | var st = g.drawTeeth((d / 2) - 5, d / scale, c, p), 52 | an = Raphael.animation({transform: (clockwise ? "r360," : "r-360,") + [p.x, p.y]}, speed); 53 | 54 | var path = ""; 55 | for (var i = 0, ii = st.length; i < ii; i++) { 56 | path += Raphael.mapPath(st[i].attr("path"), st[i].matrix); 57 | } 58 | st.remove(); 59 | st = g.paper.path(path).attr({ 60 | stroke: "none", 61 | fill: c 62 | }); 63 | 64 | st.animate(an.repeat(Infinity)); 65 | }, 66 | 67 | drawTeeth: function(/*int*/ d, /*int*/ plots, /*color*/ c, /*Point*/ p) { 68 | var increase = 360 / plots; 69 | var angle = 0; 70 | 71 | var st = g.paper.set(); 72 | 73 | for (var i = 0; i < plots; i++) { 74 | var tooth = g.createTooth(c); 75 | tooth.transform("t" + [p.x, p.y - (d + (toothSize / 2))] + "R" + [angle, p.x, p.y]); 76 | st.push(tooth); 77 | angle += increase; 78 | } 79 | 80 | return st; 81 | }, 82 | 83 | createTooth: function(/*color*/ c) { 84 | var t2 = toothSize / 2; 85 | var path = 'M ' + (-t2 / 2 + 2) + ' ' + (-t2) + // upper left 86 | 'L ' + (t2 / 2 - 6) + ' ' + (-t2) + // upper right 87 | 'L ' + (t2 / 2) + ' ' + (-t2 + 8) + // upper right bump 88 | 'L ' + t2 + ' ' + t2 + // bottom right 89 | 'L ' + (-t2) + ' ' + t2 + // bottom left 90 | 'L ' + (-t2 + 4) + ' ' + (-t2 + 8); // upper left bump 91 | path += ' z'; 92 | 93 | return g.paper.path(path).attr({ 94 | fill: c, 95 | stroke: "none" 96 | }); 97 | } 98 | }; 99 | 100 | window.onload = function () { 101 | g.paper = Raphael('canvas', 960, 650); 102 | 103 | var back = g.paper.rect(0, 0, 960, 650); 104 | back.attr({ 105 | fill: '#ececec', 106 | stroke: 'none' 107 | }); 108 | 109 | back.click(function() { 110 | g.stopped = !g.stopped; 111 | }); 112 | 113 | var speed = 15000; 114 | 115 | g.create({ 116 | 'x': 150, 117 | 'y': 150 118 | }, 15, '#00aeef', speed, !clockwise); 119 | 120 | g.create({ 121 | 'x': 295, 122 | 'y': 285 123 | }, 8, '#ee5b32', speed * (8 / 15), clockwise); 124 | 125 | g.create({ 126 | 'x': 172, 127 | 'y': 587 128 | }, 32, '#F00FF0', speed * (17 / 8), !clockwise); 129 | 130 | g.create({ 131 | 'x': 565, 132 | 'y': 425 133 | }, 21, '#fec01e', speed * (23.5 / 17), clockwise); 134 | 135 | g.create({ 136 | 'x': 615, 137 | 'y': 165 138 | }, 11, '#157d6b', speed * (8 / 11), !clockwise); 139 | 140 | }; 141 | -------------------------------------------------------------------------------- /raphael_interaction.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function() { 2 | var paper = Raphael('raphaelInteraction', 200, 200); 3 | var r = paper.rect(60, 60, 80, 80); 4 | r.attr({ 5 | 'fill': '#00aeef', 6 | 'stroke': '#00aeef' 7 | }); 8 | 9 | var clicked = false; 10 | 11 | r.click(function() { 12 | if (clicked) { 13 | r.attr({ 14 | 'fill': '#00aeef', 15 | 'stroke': '#00aeef' 16 | }); 17 | } else { 18 | r.attr({ 19 | 'fill': '#f00ff0', 20 | 'stroke': '#f00ff0' 21 | }); 22 | } 23 | clicked = !clicked; 24 | }); 25 | }); 26 | --------------------------------------------------------------------------------