Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
akira-cn committed Jul 9, 2019
1 parent b5a812d commit b696e1b
Show file tree
Hide file tree
Showing 15 changed files with 446 additions and 25 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Sprite Template
# Sprite Gesture

The standard project template.
SpriteJS Gesture extension based on [winter-gestures](https://github.com/wintercn/gesture).
67 changes: 67 additions & 0 deletions examples/dual.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
html, body {
width:100%;height:100%;margin:0;
}
html,body {
margin: 0 0 0 0;
padding: 0 0 0 0;
width:100%;
height:100%;
overflow:hidden;
}
body {
-webkit-user-select: none;
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-touch-callout: none;
-webkit-text-size-adjust: none;
}
</style>
<script type="text/javascript">
// 关闭选择
document.addEventListener('selectstart', (e) => { e.preventDefault() });
// 避免鼠标变成文本选择形状
document.addEventListener('mousedown', (e) => { e.preventDefault() });
// 避免上下滚屏
document.addEventListener('touchmove', (e) => { e.preventDefault() }, {passive: false});
// 避免双击缩放
document.addEventListener('touchstart', (e) => { e.preventDefault() }, {passive: false});
</script>
</head>
<body>
<script src="https://unpkg.com/spritejs/dist/spritejs.js"></script>
<script src="/js/sprite-extend-gesture.js"></script>
<div id="container"></div>
<script>
const imgUrl = 'https://s5.ssl.qhres.com/static/ec9f373a383d7664.svg';
const {Scene, Sprite, Gesture} = spritejs;
const paper = new Scene('#container', {viewport: [400, 400]});

const sprite = new Sprite(imgUrl);
sprite.attr({
bgcolor: '#fff',
pos: [0, 0],
size: [400, 400],
borderRadius: '200',
});

paper.layer().appendChild(sprite);
Gesture.subscribe(sprite);
sprite.on('dual', (event) => {
if(event.type === 'dual') {
console.log(sprite.attr('transform'));
sprite.attr('transform', [event.transform[0][0], event.transform[1][0],
event.transform[0][1], event.transform[1][1],
event.transform[0][2], event.transform[1][2]]);
//sprite.attr("transform", {rotate: event.rotate / Math.PI * 180});
}
});
</script>
</body>
</html>
15 changes: 0 additions & 15 deletions examples/test.html

This file was deleted.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
{
"name": "sprite-template",
"name": "@spritejs/gesture",
"version": "0.0.1",
"description": "The standard project template.",
"description": "Recogonize gestures on mobile phones.",
"main": "index.js",
"scripts": {
"start": "webpack-dev-server --env.server=examples --watch-poll",
"compile": "webpack --env.production=true",
"lint": "eslint src --fix",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
Expand Down
44 changes: 44 additions & 0 deletions src/gesture.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import SpriteTouchListener from './gesture/SpriteTouchListener';
import DualRecogonizer from './gesture/DualRecogonizer';
import FlickRecogonizer from './gesture/FlickRecogonizer';
import PanRecogonizer from './gesture/PanRecogonizer';
import PressRecogonizer from './gesture/PressRecogonizer';
import TapRecogonizer from './gesture/TapRecogonizer';

export default function install({use, utils, registerNodeType, BaseSprite}) {
const Gesture = {
subscribe(target) {
if(target.__gestureHandlers) return false;
new SpriteTouchListener(target, [
new DualRecogonizer((event) => {
target.dispatchEvent(event.type, event, true, true);
}),
new FlickRecogonizer((event) => {
target.dispatchEvent(event.type, event, true, true);
}),
new PanRecogonizer((event) => {
target.dispatchEvent(event.type, event, true, true);
}),
new PressRecogonizer((event) => {
target.dispatchEvent(event.type, event, true, true);
}),
new TapRecogonizer((event) => {
target.dispatchEvent(event.type, event, true, true);
}),
]);
return true;
},
unsubscribe(target) {
if(target.__gestureHandlers) {
const {start, move, end, cancel} = target.__gestureHandlers;
target.off('touchstart', start);
target.off('touchmove', move);
target.off('touchend', end);
target.off('touchcancel', cancel);
return true;
}
return false;
},
};
return {Gesture};
}
63 changes: 63 additions & 0 deletions src/gesture/DualRecogonizer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import Recogonizer from './Recogonizer.js';


export default class DualRecogonizer extends Recogonizer {
start(pointer, pointers) {
if(pointers.size > 2) {
this.emit('dualcancel', {pointer, pointers});
}
if(pointers.size == 2) {
const i = pointers.values();
const p1 = i.next().value;
const p2 = i.next().value;
// console.log(p1);

this.startPoints = {p1: Object.assign({}, p1), p2: Object.assign({}, p2)};
this.emit('dualstart', {pointer, pointers});
}
}

move(pointer, pointers) {
if(pointers.size == 2) {
const {p1, p2} = this.startPoints;
const p3 = pointers.get(p1.identifier);
const p4 = pointers.get(p2.identifier);

const scale = Math.sqrt(Math.pow(p3.x - p4.x, 2) + Math.pow(p3.y - p4.y, 2))
/ Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
// console.log(p1,p2,p3,p4);

const rotate = Math.atan2(p4.y - p3.y, p4.x - p3.x) - Math.atan2(p2.y - p1.y, p2.x - p1.x);


// scale = 1;
// rotate = 0;

const translate = {
x: p3.x - scale * p1.x * Math.cos(rotate) + scale * p1.y * Math.sin(rotate),
y: p3.y - scale * p1.y * Math.cos(rotate) - scale * p1.x * Math.sin(rotate),
};
// console.log("**************")
// console.log(calc(p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y).matrix);
const transform = [
[scale * Math.cos(rotate), -scale * Math.sin(rotate), translate.x],
[scale * Math.sin(rotate), scale * Math.cos(rotate), translate.y],
[0, 0, 1],
];
// console.log(transform);
this.emit('dual', {pointer, pointers, scale, rotate, translate, transform});
}
}

end(pointer, pointers) {
if(pointers.size == 1) {
this.emit('dualend', {pointer, pointers});
}
}

cancel(pointer, pointers) {
if(pointers.size == 1) {
this.emit('dualcancel', {pointer, pointers});
}
}
}
55 changes: 55 additions & 0 deletions src/gesture/FlickRecogonizer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import Recogonizer from './Recogonizer.js';

export default class FlickRecogonizer extends Recogonizer {
start(pointer) {
pointer.recordCount = 1;
pointer.recordStart = {
t: Date.now(),
x: pointer.startX,
y: pointer.startY,
next: null,
};
pointer.recordEnd = pointer.recordStart;
pointer.v = 0;
pointer.vx = 0;
pointer.vy = 0;
}

move(pointer) {
const t = Date.now();
const record = {
t,
x: pointer.x,
y: pointer.y,
next: null,
};
pointer.recordEnd.next = record;
pointer.recordEnd = record;
pointer.recordCount++;

while(t - pointer.recordStart.t > 30 && pointer.recordCount > 3) {
pointer.recordCount--;
pointer.recordStart = pointer.recordStart.next;
}

const r1 = pointer.recordStart;
const r2 = pointer.recordEnd;

pointer.v = Math.sqrt((r1.x - r2.x) ** 2 + (r1.y - r2.y) ** 2) / (r2.t - r1.t);
pointer.vx = (r2.x - r1.x) / (r2.t - r1.t);
pointer.vy = (r2.y - r1.y) / (r2.t - r1.t);
//
// document.body.innerHTML = `x: ${r1.x - r2.x}, y: ${r1.y - r2.y}, v: ${pointer.v}`;
}

end(pointer) {
if(pointer.v > Number(this.DPR)) {
pointer.isFlick = true;
this.emit('flick', pointer);
}
}

cancel(pointer) {

}
}
6 changes: 6 additions & 0 deletions src/gesture/Listener.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default class Listener {
constructor(recogonizers) {
this.pointers = new Map();
this.recogonizers = [...recogonizers];
}
}
27 changes: 27 additions & 0 deletions src/gesture/PanRecogonizer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Recogonizer from './Recogonizer.js';

export default class PanRecogonizer extends Recogonizer {
start(pointer) {
pointer.isPanning = false;
}

move(pointer) {
const dx = pointer.x - pointer.startX,
dy = pointer.y - pointer.startY;

if(Math.sqrt(dx * dx + dy * dy) > 10 * this.DPR && !pointer.isPanning) {
pointer.isPanning = true;
this.emit('panstart', pointer);
}

if(pointer.isPanning) this.emit('pan', pointer);
}

end(pointer) {
if(pointer.isPanning) this.emit('panend', pointer);
}

cancel(pointer) {
if(pointer.isPanning) this.emit('pancancel', pointer);
}
}
48 changes: 48 additions & 0 deletions src/gesture/PressRecogonizer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import Recogonizer from './Recogonizer.js';

export default class PressRecogonizer extends Recogonizer {
start(pointer) {
pointer.pressHandler = setTimeout(() => {
pointer.isPressing = true;
this.emit('pressstart', pointer);
pointer.pressHandler = null;
}, 500);
}

move(pointer) {
const dx = pointer.x - pointer.startX,
dy = pointer.y - pointer.startY;
if(Math.sqrt(dx * dx + dy * dy) > 10 * this.DPR) {
if(pointer.isPressing) {
pointer.isPressing = false;
this.emit('presscancel', pointer);
}
if(pointer.pressHandler) {
clearTimeout(pointer.pressHandler);
pointer.pressHandler = null;
}
}
}

end(pointer) {
if(pointer.isPressing) {
pointer.isPressing = false;
this.emit('pressend', pointer);
}
if(pointer.pressHandler) {
clearTimeout(pointer.pressHandler);
pointer.pressHandler = null;
}
}

cancel(pointer) {
if(pointer.isPressing) {
pointer.isPressing = false;
this.emit('presscancel', pointer);
}
if(pointer.pressHandler) {
clearTimeout(pointer.pressHandler);
pointer.pressHandler = null;
}
}
}
30 changes: 30 additions & 0 deletions src/gesture/Recogonizer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export default class Recogonizer {
constructor(consumer, DPR = 1) {
this.consumer = consumer;
this.DPR = DPR;
}

emit(name, props) {
const event = Object.create(props, {
type: {value: name},
});
if(this.consumer && this.consumer.handle) Promise.resolve().then(() => this.consumer.handle(event));
if(this.consumer && typeof this.consumer === 'function') Promise.resolve().then(() => this.consumer.call(null, event));
}

start(pointer) {

}

move(pointer) {

}

end(pointer) {

}

cancel(pointer) {

}
}
Loading

0 comments on commit b696e1b

Please sign in to comment.