Skip to content

Commit 7d5756d

Browse files
committed
Dumping code
0 parents  commit 7d5756d

File tree

6 files changed

+524
-0
lines changed

6 files changed

+524
-0
lines changed

curves.js

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
(function(global) {
2+
3+
function extend(obj) {
4+
for (var i = 1; i < arguments.length; i++) {
5+
var source = arguments[i];
6+
for (var name in source) if (source.hasOwnProperty(name))
7+
obj[name] = source[name];
8+
}
9+
return obj;
10+
}
11+
12+
var EventEmitter = {
13+
on : function(type, handler) {
14+
this._ensureEvent(type);
15+
this._events[type].push(handler);
16+
},
17+
off : function(type, handler) {
18+
if (this._events && this._events[type]) {
19+
this._events[type] = this._events[type].filter(function(h) {
20+
return h !== handler;
21+
});
22+
}
23+
},
24+
emit: function(type) {
25+
var args = Array.prototype.slice.call(arguments, 1);
26+
this._ensureEvent(type);
27+
this._events[type].forEach(function(handler) {
28+
handler.apply(this, args);
29+
});
30+
},
31+
_ensureEvent: function(type) {
32+
if (!this._events) this._events = {};
33+
if (!this._events[type]) this._events[type] = [];
34+
}
35+
};
36+
37+
function Vector2d(x, y) {
38+
this.x = x;
39+
this.y = y;
40+
}
41+
42+
Object.defineProperty(Vector2d.prototype, 'length', {
43+
get : function() { return Math.sqrt(this.x * this.x + this.y * this.y); },
44+
enumerable : true
45+
});
46+
47+
Vector2d.prototype.add = function(v) {
48+
if (v instanceof this.constructor)
49+
return new this.constructor(this.x + v.x, this.y + v.y);
50+
else
51+
return new this.constructor(this.x + v, this.y + v);
52+
};
53+
54+
Vector2d.prototype.sub = function(v) {
55+
if (v instanceof this.constructor)
56+
return this.add(v.neg());
57+
else
58+
return this.add(-v);
59+
};
60+
61+
Vector2d.prototype.neg = function() {
62+
return new this.constructor(-this.x, -this.y);
63+
};
64+
65+
Vector2d.prototype.scale = function(s) {
66+
return new this.constructor(this.x * s, this.y * s);
67+
};
68+
69+
Vector2d.prototype.dot = function(v) {
70+
return this.x * v.x + this.y * v.y;
71+
};
72+
73+
Vector2d.prototype.cross = function(v) {
74+
return this.x * v.y - this.y * v.x;
75+
};
76+
77+
Vector2d.prototype.towards = function(other) {
78+
return other.sub(this).normalize();
79+
};
80+
81+
Vector2d.prototype.normalize = function() {
82+
return this.scale(1 / this.length);
83+
};
84+
85+
Vector2d.random = function(unit) {
86+
var r = Math.random() * Math.PI * 2,
87+
d = unit ? 1 : Math.random();
88+
return new this(
89+
d * Math.cos(r),
90+
d * Math.sin(r)
91+
);
92+
};
93+
94+
Vector2d.randomWithin = function(rectangle) {
95+
return new this(
96+
rectangle.corner.x + Math.random() * rectangle.width,
97+
rectangle.corner.y + Math.random() * rectangle.height
98+
);
99+
};
100+
101+
Vector2d.prototype.rotate = function(r) {
102+
return new this.constructor(
103+
this.x * Math.cos(r) - this.y * Math.sin(r),
104+
this.x * Math.sin(r) + this.y * Math.cos(r)
105+
);
106+
};
107+
108+
Vector2d.prototype.clone = function() {
109+
return new this.constructor(this.x, this.y);
110+
};
111+
112+
function BezierCurve(A, B, C, D) {
113+
this._A = A;
114+
this._B = B;
115+
this._C = C;
116+
this._D = D;
117+
};
118+
119+
extend(BezierCurve.prototype, EventEmitter);
120+
121+
['A', 'B', 'C', 'D'].forEach(function(pt) {
122+
Object.defineProperty(BezierCurve.prototype, pt, {
123+
get: function() { return this['_' + pt]; },
124+
set: function(v) {
125+
this['_' + pt] = v;
126+
this.emit('change', pt);
127+
}
128+
});
129+
});
130+
131+
BezierCurve.prototype.interpolate = function(t) {
132+
var tt = t * t,
133+
ttt = tt * t,
134+
u = 1 - t,
135+
uu = u * u,
136+
uuu = uu * u;
137+
138+
return this.A.scale(uuu).
139+
add(this.B.scale(3 * uu * t)).
140+
add(this.C.scale(3 * u * tt)).
141+
add(this.D.scale(ttt));
142+
};
143+
144+
// Derivative to determine the curve's slope.
145+
BezierCurve.prototype.direction = function(t) {
146+
var tt = t * t,
147+
g = (t - 1) * (t - 1),
148+
h = -3 * tt + 4 * t - 1,
149+
i = 3 * tt - 2 * t,
150+
j = - tt;
151+
152+
return this.A.scale(g).
153+
add(this.B.scale(h)).
154+
add(this.C.scale(i)).
155+
add(this.D.scale(j)).
156+
scale(-3);
157+
};
158+
159+
function AnimationGenerator(options) {
160+
this.options = extend({}, this.constructor.defaults, options || {});
161+
}
162+
163+
AnimationGenerator.defaults = {
164+
segments : 128,
165+
orientAlongPath : false,
166+
maxError : 1,
167+
name : 'CUSTOM_ANIMATION'
168+
};
169+
170+
AnimationGenerator.prototype.generate = function(bezier) {
171+
return this.generateAnimation(this.generatePointList(bezier));
172+
};
173+
174+
AnimationGenerator.prototype.generatePointList = function(bezier) {
175+
var increment = 1 / this.options.segments,
176+
points = [],
177+
i, p, t, d, pa, n, minD, minError = 0, idx;
178+
179+
for (var i = 0; i <= this.options.segments; i++) {
180+
var t = i * increment,
181+
p = bezier.interpolate(t);
182+
p.t = t;
183+
p.dir = bezier.direction(t);
184+
p.angle = -Math.atan2(p.dir.x, p.dir.y) / Math.PI * 180;
185+
points.push(p);
186+
}
187+
188+
// Cull as many points as possible from the generated segments
189+
// while the error is less than the maximum allowed.
190+
do {
191+
if (points.length == 2) break;
192+
193+
idx = null;
194+
minError = Infinity;
195+
196+
for (i = 1; i < points.length - 1; i++) {
197+
n = points[i-1].towards(points[i+1]);
198+
pa = points[i-1].sub(points[i]);
199+
d = pa.sub(n.scale(pa.dot(n))).length;
200+
if (d < minError && d < this.options.maxError) {
201+
minError = d;
202+
idx = i;
203+
}
204+
}
205+
206+
if (idx != null) points.splice(idx, 1);
207+
208+
} while (minError <= this.options.maxError)
209+
210+
return points;
211+
}
212+
213+
AnimationGenerator.prototype.generateAnimation = function(pointList) {
214+
var i, rollingSum = 0, total = 0,
215+
animation = ['@-webkit-keyframes ' + this.options.name + ' {'];
216+
217+
pointList[0].l = 0;
218+
for (i = 1; i < pointList.length; i++) {
219+
total += pointList[i].l = pointList[i].sub(pointList[i-1]).length;
220+
}
221+
222+
for (i = 0; i < pointList.length; i++) {
223+
rollingSum += pointList[i].l;
224+
animation.push(this._generateKeyframe(rollingSum / total, pointList[i]));
225+
}
226+
227+
animation.push('}');
228+
return animation.join('\n');
229+
};
230+
231+
AnimationGenerator.prototype._generateKeyframe = function(position, point) {
232+
var extras = '';
233+
if (this.options.orientAlongPath) {
234+
extras = 'rotate(' + point.angle.toFixed(1) + 'deg)';
235+
}
236+
return ' ' + (position * 100).toFixed(4) + '% { -webkit-transform: translate(' + (point.x.toFixed(1)) + 'px, ' + (point.y.toFixed(1)) + 'px) ' + extras + '; }';
237+
};
238+
239+
// exports
240+
global.Vector2d = Vector2d;
241+
global.BezierCurve = BezierCurve;
242+
global.AnimationGenerator = AnimationGenerator;
243+
244+
})((typeof module != 'undefined' && module.exports) ? module.exports : window);

curves.min.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

images/box.png

1.51 KB
Loading

index.html

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8"/>
5+
<title>CSS3 Beziér curve animation generator</title>
6+
<style>
7+
* { padding: 0; margin: 0; box-sizing: border-box; }
8+
html, body { height: 100%; }
9+
html, input, select { font: normal 12px Tahoma;}
10+
#container, #container canvas { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
11+
#container .node {
12+
position: absolute; width: 10px; height: 10px;
13+
border-radius: 10px;
14+
background: green;
15+
border: 1px solid rgba(0,0,0,0.5);
16+
box-shadow: 1px 1px 2px rgba(0,0,0,0.5);
17+
cursor: pointer;
18+
}
19+
#container .node span { position: relative; top: 10px; }
20+
#container input { width: 5em; }
21+
#container .params { position: fixed; top: 0; left: 0; z-index: 10; border-image: url(images/box.png) 10 10 10 10 fill repeat; border-width: 10px; }
22+
#container textarea { font: normal 11px Consolas; width: 38em; height: 25em; padding: 0.8em; }
23+
#animatable { width: 64px; height: 64px; position: absolute; left: 50%; top: 50%; margin-left: -32px; margin-top: -32px; pointer-events: none; background: url(images/box.png) center no-repeat; display: none; z-index: 11;}
24+
</style>
25+
</head>
26+
<body>
27+
<div id="container">
28+
<canvas></canvas>
29+
<div class="params">
30+
<table>
31+
<tr>
32+
<th>A</th>
33+
<td><input name="Ax"/></td>
34+
<td><input name="Ay"/></td>
35+
<th>B</th>
36+
<td><input name="Bx"/></td>
37+
<td><input name="By"/></td>
38+
</tr>
39+
<tr>
40+
<th>C</th>
41+
<td><input name="Cx"/></td>
42+
<td><input name="Cy"/></td>
43+
<th>D</th>
44+
<td><input name="Dx"/></td>
45+
<td><input name="Dy"/></td>
46+
</tr>
47+
</table>
48+
<table>
49+
<tr>
50+
<th>Animation length</th>
51+
<td><input name="anim_length" value="1"/> s</td>
52+
</tr>
53+
<tr>
54+
<th>Easing</th>
55+
<td>
56+
<select name="easing">
57+
<option value="linear">linear</option>
58+
<option value="ease-in">ease in</option>
59+
<option value="ease-out">ease out</option>
60+
<option value="ease-in-out">ease in-out</option>
61+
</select>
62+
</td>
63+
</tr>
64+
<tr>
65+
<th/>
66+
<td><button data-action="run">Run animation</button></td>
67+
</tr>
68+
</table>
69+
70+
<textarea class="generated"></textarea>
71+
</div>
72+
<div id="animatable"></div>
73+
</div>
74+
<script src="http://code.jquery.com/jquery-1.11.2.min.js"></script>
75+
<script src="http://code.jquery.com/jquery-migrate-1.2.1.min.js"></script>
76+
<script src="http://code.jquery.com/ui/1.9.0/jquery-ui.min.js"></script>
77+
<script src="curves.js"></script>
78+
<script src="ui.js"></script>
79+
<script src="main.js"></script>
80+
</body>
81+
</html>

0 commit comments

Comments
 (0)