implement pinch to zoom

This commit is contained in:
marlon-erler
2026-08-30 16:15:14 +02:00
parent ea50704f8a
commit 7eb02f07dc
160 changed files with 15806 additions and 61 deletions
+2
View File
@@ -0,0 +1,2 @@
components
build
+27
View File
@@ -0,0 +1,27 @@
1.2.0 / 2015-03-16
==================
* update "emitter" to v1.2.0
* use "component-clone" and "component-type" for browsers support (#5, @cristiandouce)
* update component.json (#4, @pgherveou)
* package: add browserify mappings (#7, @dfcreative)
* package: add "repository" field (#3)
1.1.0 / 2013-05-29
==================
* add Tween#stop(). Closes #2
* fix final update to complete the tween. Closes #1
1.0.0 / 2013-05-27
==================
* pin deps
* add package.json
* add interactive example
0.1.0 / 2012-11-10
==================
* add array tweening support
+16
View File
@@ -0,0 +1,16 @@
build: components index.js
@component build --dev
components: component.json
@component install --dev
clean:
rm -fr build components template.js
tween.js:
@component build --standalone tween \
&& mv build/build.js $@ \
&& rm -fr build
.PHONY: clean tween.js
+78
View File
@@ -0,0 +1,78 @@
# tween
Motion tween component using [ease](https://github.com/component/ease).
## Installation
$ component install component/tween
## Example
```js
var Tween = require('tween');
var raf = require('raf');
var button = document.querySelector('button');
var tween = Tween({ rotate: 0, opacity: 0 })
.ease('out-bounce')
.to({ rotate: 360, opacity: 1 })
.duration(800);
tween.update(function(o){
button.style.opacity = o.opacity;
button.style.webkitTransform = 'rotate(' + (o.rotate | 0) + 'deg)';
});
tween.on('end', function(){
animate = function(){};
});
function animate() {
raf(animate);
tween.update();
}
animate();
```
## API
### Tween(obj:Object|Array)
Initialize a new `Tween` with `obj`.
### Tween#reset()
Reset the tween.
### Tween#to(obj:Object|Array)
Tween to `obj` and reset internal state.
tween.to({ x: 50, y: 100 })
### Tween#duration(ms:Number)
Set duration to `ms` [500].
### Tween#ease(fn:String|Function)
Set easing function to `fn`.
tween.ease('in-out-sine')
### Tween#update(fn:Function)
Set update function to `fn` or
when no argument is given this performs
a "step".
### Tween#stop()
Immediately stop the tween and emit "stop" and end" events. `tween.stopped`
is then marked as `true`.
## License
MIT
+25
View File
@@ -0,0 +1,25 @@
{
"name": "tween",
"repo": "component/tween",
"description": "Motion tween engine using 'ease'",
"version": "1.2.0",
"keywords": [
"tween",
"tweening",
"animation"
],
"dependencies": {
"component/clone": "0.2.2",
"component/ease": "1.0.0",
"component/emitter": "1.2.0",
"component/type": "1.1.0"
},
"development": {
"component/raf": "*",
"component/autoscale-canvas": "*"
},
"license": "MIT",
"scripts": [
"index.js"
]
}
+48
View File
@@ -0,0 +1,48 @@
<style>
canvas {
border: 1px solid #eee;
}
</style>
<script src="../build/build.js"></script>
<canvas width=1000 height=500></canvas>
<script>
var Tween = require('tween');
var raf = require('component-raf');
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var h = 500;
function random(n, f) {
var arr = [];
while (n--) arr.push(Math.random() * f);
return arr;
}
var tween = Tween(random(1000, 50))
.ease('out-bounce')
.to(random(1000, 400))
.duration(800);
tween.update(function(a){
canvas.width = canvas.width;
ctx.fillStyle = '#0070ff';
for (var i = 0; i < a.length; i++) {
ctx.fillRect(i, h - a[i], 1, a[i]);
}
});
tween.on('end', function(){
animate = function(){};
});
function animate() {
raf(animate);
tween.update();
}
animate();
</script>
+64
View File
@@ -0,0 +1,64 @@
<style>
canvas {
border: 1px solid #eee;
}
</style>
<script src="../build/build.js"></script>
<canvas width=500 height=400></canvas>
<script>
var Tween = require('tween');
var raf = require('component-raf');
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var w = canvas.width, h = canvas.height;
var tween = Tween({ x: w/2, y: 20, r: 10, a: .5 })
.ease('out-bounce')
.to({ x: w/2, y: h-8, r: 10, a: .5 })
.duration(2000);
tween.update(function(o){
canvas.width = canvas.width;
ctx.fillStyle = 'red';
ctx.globalAlpha = o.a;
ctx.arc(o.x | 0, o.y | 0, o.r, 0, Math.PI * 2, false);
ctx.fill();
});
var n = 0;
tween.on('end', function(){
switch (n++) {
case 0:
tween
.to({ x: w/2, y: 20, r: 10, a: .5 })
.ease('out-sine')
.duration(500);
break;
case 1:
tween
.to({ x: w/2, y: h/2, r: 10, a: .5 })
.ease('in-out-back')
.duration(800);
break;
case 2:
tween
.to({ x: w/2, y: h/2, r: 80, a: 1 })
.ease('out-bounce')
.duration(1500);
break;
default:
animate = function(){};
}
});
function animate() {
raf(animate);
tween.update();
}
animate();
</script>
+45
View File
@@ -0,0 +1,45 @@
<style>
canvas {
border: 1px solid #eee;
}
</style>
<script src="../build/build.js"></script>
<canvas width=500 height=400></canvas>
<button onclick='tween.stop()'>Stop</button>
<script>
var Tween = require('tween');
var raf = require('component-raf');
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var tween = Tween({ alpha: 0, border: 1, radius: 1 })
.ease('out-bounce')
.to({ alpha: 1, border: 15, radius: 150 })
.duration(1000);
tween.update(function(o){
canvas.width = canvas.width;
ctx.strokeStyle = 'black';
ctx.globalAlpha = o.alpha;
ctx.lineWidth = o.border;
ctx.arc(canvas.width / 2, canvas.height / 2, o.radius, 0, Math.PI * 2, false);
ctx.stroke();
ctx.fill();
});
tween.on('end', function(){
animate = function(){};
});
function animate() {
raf(animate);
tween.update();
}
animate();
</script>
+41
View File
@@ -0,0 +1,41 @@
<style>
body {
padding: 50px;
}
button {
padding: 15px 25px;
}
</style>
<button>Button</button>
<script src="../build/build.js"></script>
<script>
var Tween = require('tween');
var raf = require('component-raf');
var button = document.querySelector('button');
var tween = Tween({ rotate: 0, opacity: 0 })
.ease('out-bounce')
.to({ rotate: 360, opacity: 1 })
.duration(800);
tween.update(function(o){
button.style.opacity = o.opacity;
button.style.webkitTransform = 'rotate(' + (o.rotate | 0) + 'deg)';
});
tween.on('end', function(){
animate = function(){};
});
function animate() {
raf(animate);
tween.update();
}
animate();
</script>
+62
View File
@@ -0,0 +1,62 @@
<style>
canvas {
border: 1px solid #eee;
}
</style>
<script src="../build/build.js"></script>
<canvas width=500 height=400></canvas>
<script>
var Tween = require('tween');
var raf = require('component-raf');
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var w = canvas.width, h = canvas.height;
function Ball(x, y) {
this.moveTo(x, y);
this.rad = 10;
}
Ball.prototype.moveTo = function(x, y){
this.x = x;
this.y = y;
};
Ball.prototype.draw = function(ctx){
ctx.save();
ctx.fillStyle = 'red';
ctx.arc(this.x | 0, this.y | 0, this.rad, 0, Math.PI * 2, false);
ctx.fill();
ctx.restore();
};
var ball = new Ball(100, 100);
ball.draw(ctx);
canvas.onclick = function(e){
console.log('move');
var tween = Tween({ x: ball.x, y: ball.y })
.ease('out-bounce')
.to({ x: e.offsetX, y: e.offsetY })
.duration(1500);
tween.update(function(o){
canvas.width = canvas.width;
ball.moveTo(o.x, o.y);
ball.draw(ctx);
});
function animate() {
raf(animate);
tween.update();
}
animate();
};
</script>
+43
View File
@@ -0,0 +1,43 @@
<style>
canvas {
border: 1px solid #eee;
}
</style>
<script src="../build/build.js"></script>
<canvas width=500 height=400></canvas>
<script>
var Tween = require('tween');
var raf = require('component-raf');
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var tween = Tween({ w: 1, h: 1, border: 1, alpha: 0 })
.ease('out-circ')
.to({ border: 5, w: 150, h: 100, alpha: 1 })
.duration(800);
tween.update(function(o){
canvas.width = canvas.width;
ctx.strokeStyle = 'black';
ctx.globalAlpha = o.alpha;
ctx.lineWidth = o.border;
ctx.rect(canvas.width / 2 - o.w / 2, canvas.height / 2 - o.h / 2, o.w, o.h);
ctx.stroke();
ctx.fill();
});
tween.on('end', function(){
animate = function(){};
});
function animate() {
raf(animate);
tween.update();
}
animate();
</script>
+178
View File
@@ -0,0 +1,178 @@
/**
* Module dependencies.
*/
var Emitter = require('emitter');
var clone = require('clone');
var type = require('type');
var ease = require('ease');
/**
* Expose `Tween`.
*/
module.exports = Tween;
/**
* Initialize a new `Tween` with `obj`.
*
* @param {Object|Array} obj
* @api public
*/
function Tween(obj) {
if (!(this instanceof Tween)) return new Tween(obj);
this._from = obj;
this.ease('linear');
this.duration(500);
}
/**
* Mixin emitter.
*/
Emitter(Tween.prototype);
/**
* Reset the tween.
*
* @api public
*/
Tween.prototype.reset = function(){
this.isArray = 'array' === type(this._from);
this._curr = clone(this._from);
this._done = false;
this._start = Date.now();
return this;
};
/**
* Tween to `obj` and reset internal state.
*
* tween.to({ x: 50, y: 100 })
*
* @param {Object|Array} obj
* @return {Tween} self
* @api public
*/
Tween.prototype.to = function(obj){
this.reset();
this._to = obj;
return this;
};
/**
* Set duration to `ms` [500].
*
* @param {Number} ms
* @return {Tween} self
* @api public
*/
Tween.prototype.duration = function(ms){
this._duration = ms;
return this;
};
/**
* Set easing function to `fn`.
*
* tween.ease('in-out-sine')
*
* @param {String|Function} fn
* @return {Tween}
* @api public
*/
Tween.prototype.ease = function(fn){
fn = 'function' == typeof fn ? fn : ease[fn];
if (!fn) throw new TypeError('invalid easing function');
this._ease = fn;
return this;
};
/**
* Stop the tween and immediately emit "stop" and "end".
*
* @return {Tween}
* @api public
*/
Tween.prototype.stop = function(){
this.stopped = true;
this._done = true;
this.emit('stop');
this.emit('end');
return this;
};
/**
* Perform a step.
*
* @return {Tween} self
* @api private
*/
Tween.prototype.step = function(){
if (this._done) return;
// duration
var duration = this._duration;
var now = Date.now();
var delta = now - this._start;
var done = delta >= duration;
// complete
if (done) {
this._from = this._to;
this._update(this._to);
this._done = true;
this.emit('end');
return this;
}
// tween
var from = this._from;
var to = this._to;
var curr = this._curr;
var fn = this._ease;
var p = (now - this._start) / duration;
var n = fn(p);
// array
if (this.isArray) {
for (var i = 0; i < from.length; ++i) {
curr[i] = from[i] + (to[i] - from[i]) * n;
}
this._update(curr);
return this;
}
// objech
for (var k in from) {
curr[k] = from[k] + (to[k] - from[k]) * n;
}
this._update(curr);
return this;
};
/**
* Set update function to `fn` or
* when no argument is given this performs
* a "step".
*
* @param {Function} fn
* @return {Tween} self
* @api public
*/
Tween.prototype.update = function(fn){
if (0 == arguments.length) return this.step();
this._update = fn;
return this;
};
+63
View File
@@ -0,0 +1,63 @@
1.2.0 / 2014-02-12
==================
* prefix events with `$` to support object prototype method names
1.1.3 / 2014-06-20
==================
* republish for npm
* add LICENSE file
1.1.2 / 2014-02-10
==================
* package: rename to "component-emitter"
* package: update "main" and "component" fields
* Add license to Readme (same format as the other components)
* created .npmignore
* travis stuff
1.1.1 / 2013-12-01
==================
* fix .once adding .on to the listener
* docs: Emitter#off()
* component: add `.repo` prop
1.1.0 / 2013-10-20
==================
* add `.addEventListener()` and `.removeEventListener()` aliases
1.0.1 / 2013-06-27
==================
* add support for legacy ie
1.0.0 / 2013-02-26
==================
* add `.off()` support for removing all listeners
0.0.6 / 2012-10-08
==================
* add `this._callbacks` initialization to prevent funky gotcha
0.0.5 / 2012-09-07
==================
* fix `Emitter.call(this)` usage
0.0.3 / 2012-07-11
==================
* add `.listeners()`
* rename `.has()` to `.hasListeners()`
0.0.2 / 2012-06-28
==================
* fix `.off()` with `.once()`-registered callbacks
+24
View File
@@ -0,0 +1,24 @@
(The MIT License)
Copyright (c) 2014 Component contributors <dev@component.io>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
+74
View File
@@ -0,0 +1,74 @@
# Emitter [![Build Status](https://travis-ci.org/component/emitter.png)](https://travis-ci.org/component/emitter)
Event emitter component.
## Installation
```
$ component install component/emitter
```
## API
### Emitter(obj)
The `Emitter` may also be used as a mixin. For example
a "plain" object may become an emitter, or you may
extend an existing prototype.
As an `Emitter` instance:
```js
var Emitter = require('emitter');
var emitter = new Emitter;
emitter.emit('something');
```
As a mixin:
```js
var Emitter = require('emitter');
var user = { name: 'tobi' };
Emitter(user);
user.emit('im a user');
```
As a prototype mixin:
```js
var Emitter = require('emitter');
Emitter(User.prototype);
```
### Emitter#on(event, fn)
Register an `event` handler `fn`.
### Emitter#once(event, fn)
Register a single-shot `event` handler `fn`,
removed immediately after it is invoked the
first time.
### Emitter#off(event, fn)
* Pass `event` and `fn` to remove a listener.
* Pass `event` to remove all listeners on that event.
* Pass nothing to remove all listeners on all events.
### Emitter#emit(event, ...)
Emit an `event` with variable option args.
### Emitter#listeners(event)
Return an array of callbacks, or an empty array.
### Emitter#hasListeners(event)
Check if this emitter has `event` handlers.
## License
MIT
+161
View File
@@ -0,0 +1,161 @@
/**
* Expose `Emitter`.
*/
module.exports = Emitter;
/**
* Initialize a new `Emitter`.
*
* @api public
*/
function Emitter(obj) {
if (obj) return mixin(obj);
};
/**
* Mixin the emitter properties.
*
* @param {Object} obj
* @return {Object}
* @api private
*/
function mixin(obj) {
for (var key in Emitter.prototype) {
obj[key] = Emitter.prototype[key];
}
return obj;
}
/**
* Listen on the given `event` with `fn`.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.on =
Emitter.prototype.addEventListener = function(event, fn){
this._callbacks = this._callbacks || {};
(this._callbacks['$' + event] = this._callbacks['$' + event] || [])
.push(fn);
return this;
};
/**
* Adds an `event` listener that will be invoked a single
* time then automatically removed.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.once = function(event, fn){
function on() {
this.off(event, on);
fn.apply(this, arguments);
}
on.fn = fn;
this.on(event, on);
return this;
};
/**
* Remove the given callback for `event` or all
* registered callbacks.
*
* @param {String} event
* @param {Function} fn
* @return {Emitter}
* @api public
*/
Emitter.prototype.off =
Emitter.prototype.removeListener =
Emitter.prototype.removeAllListeners =
Emitter.prototype.removeEventListener = function(event, fn){
this._callbacks = this._callbacks || {};
// all
if (0 == arguments.length) {
this._callbacks = {};
return this;
}
// specific event
var callbacks = this._callbacks['$' + event];
if (!callbacks) return this;
// remove all handlers
if (1 == arguments.length) {
delete this._callbacks['$' + event];
return this;
}
// remove specific handler
var cb;
for (var i = 0; i < callbacks.length; i++) {
cb = callbacks[i];
if (cb === fn || cb.fn === fn) {
callbacks.splice(i, 1);
break;
}
}
return this;
};
/**
* Emit `event` with the given args.
*
* @param {String} event
* @param {Mixed} ...
* @return {Emitter}
*/
Emitter.prototype.emit = function(event){
this._callbacks = this._callbacks || {};
var args = [].slice.call(arguments, 1)
, callbacks = this._callbacks['$' + event];
if (callbacks) {
callbacks = callbacks.slice(0);
for (var i = 0, len = callbacks.length; i < len; ++i) {
callbacks[i].apply(this, args);
}
}
return this;
};
/**
* Return array of callbacks for `event`.
*
* @param {String} event
* @return {Array}
* @api public
*/
Emitter.prototype.listeners = function(event){
this._callbacks = this._callbacks || {};
return this._callbacks['$' + event] || [];
};
/**
* Check if this emitter has `event` handlers.
*
* @param {String} event
* @return {Boolean}
* @api public
*/
Emitter.prototype.hasListeners = function(event){
return !! this.listeners(event).length;
};
@@ -0,0 +1,24 @@
{
"name": "component-emitter",
"description": "Event emitter",
"version": "1.2.0",
"license": "MIT",
"devDependencies": {
"mocha": "*",
"should": "*"
},
"component": {
"scripts": {
"emitter/index.js": "index.js"
}
},
"main": "index.js",
"repository": {
"type": "git",
"url": "https://github.com/component/emitter.git"
},
"scripts": {
"test": "make test"
},
"files": ["index.js", "LICENSE"]
}
+32
View File
@@ -0,0 +1,32 @@
{
"name": "component-tween",
"description": "Motion tween engine using 'ease'",
"version": "1.2.0",
"keywords": [
"tween",
"tweening",
"animation"
],
"dependencies": {
"component-clone": "0.2.2",
"component-emitter": "1.2.0",
"component-type": "1.1.0",
"ease-component": "1.0.0"
},
"browser": {
"clone": "component-clone",
"emitter": "component-emitter",
"type": "component-type",
"ease": "ease-component"
},
"license": "MIT",
"component": {
"scripts": {
"tween/index.js": "index.js"
}
},
"repository": {
"type": "git",
"url": "https://github.com/component/tween.git"
}
}