├── .babelrc
├── .gitignore
├── LICENSE
├── README.md
├── alloy_crop
└── README.md
├── alloy_finger.js
├── asset
├── a.html
├── alloy_paper.js
├── cover.jpg
├── image_loaded.js
├── loading.gif
├── test.png
├── test2.png
├── test3.png
├── to.js
├── transform.js
└── yes.png
├── example
├── canvas
│ └── index.html
├── destroy
│ └── index.html
├── on_off
│ └── index.html
├── picture
│ └── index.html
├── simple
│ └── index.html
├── tap_state
│ └── index.html
└── test
│ └── index.html
├── index.html
├── package.json
├── react
└── AlloyFinger.jsx
└── transformjs
├── README.md
└── transform.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", {
4 | "targets": {
5 | "browsers": ["last 2 versions", "> 5%"],
6 | "ios": 7,
7 | "android": 4,
8 | "node": 6,
9 | "ie": 11
10 | },
11 | "include": [],
12 | "exclude": [
13 | "transform-async-to-generator"
14 | ],
15 | "uglify": true,
16 | "useBuiltIns": true,
17 | "loose": false,
18 | "debug": false
19 | }],
20 | "react"
21 | ],
22 | "plugins": [
23 | "add-module-exports",
24 | "transform-es2015-modules-commonjs",
25 | "fast-async",
26 | "transform-function-bind",
27 | "transform-class-properties",
28 | "transform-object-rest-spread",
29 | "transform-decorators"
30 | ]
31 | }
32 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | dist/
3 | .DS_Store
4 | npm-debug.log
5 | .idea/
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 腾讯 AlloyTeam
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Preview
2 |
3 | You can touch this → [http://alloyteam.github.io/AlloyFinger/](http://alloyteam.github.io/AlloyFinger/)
4 |
5 | # Install
6 |
7 | You can install it via npm:
8 |
9 | ```html
10 | npm install alloyfinger
11 | ```
12 |
13 | # Usage
14 |
15 | ```js
16 | var af = new AlloyFinger(element, {
17 | touchStart: function () { },
18 | touchMove: function () { },
19 | touchEnd: function () { },
20 | touchCancel: function () { },
21 | multipointStart: function () { },
22 | multipointEnd: function () { },
23 | tap: function () { },
24 | doubleTap: function () { },
25 | longTap: function () { },
26 | singleTap: function () { },
27 | rotate: function (evt) {
28 | console.log(evt.angle);
29 | },
30 | pinch: function (evt) {
31 | console.log(evt.zoom);
32 | },
33 | pressMove: function (evt) {
34 | console.log(evt.deltaX);
35 | console.log(evt.deltaY);
36 | },
37 | swipe: function (evt) {
38 | console.log("swipe" + evt.direction);
39 | }
40 | });
41 |
42 | /**
43 | * this method can also add or remove the event handler
44 | */
45 | var onTap = function() {};
46 |
47 | af.on('tap', onTap);
48 | af.on('touchStart', function() {});
49 |
50 | af.off('tap', onTap);
51 |
52 | /**
53 | * this method can destroy the instance
54 | */
55 | af = af.destroy();
56 | ```
57 |
58 | ### Omi Version:
59 |
60 |
61 | ```js
62 | import { render, tag, WeElement } from 'omi'
63 | import 'omi-finger'
64 |
65 | @tag('my-app')
66 | class MyApp extends WeElement {
67 | install() {
68 | this.data.wording = 'Tap or Swipe Me!'
69 | }
70 |
71 | handleTap = (evt) => {
72 | this.data.wording += '\r\nTap'
73 | this.update()
74 | }
75 |
76 | handleSwipe = (evt) => {
77 | this.data.wording += '\r\nSwipe-' + evt.direction
78 | this.update()
79 | }
80 |
81 | render() {
82 | return (
83 |
84 |
85 |
86 | {this.data.wording}
87 |
88 |
89 |
90 | )
91 | }
92 |
93 | css() {
94 | return `.touchArea{
95 | background-color: green;
96 | width: 200px;
97 | min-height: 200px;
98 | text-align: center;
99 | color:white;
100 | height:auto;
101 | white-space: pre-line;
102 | }`
103 | }
104 | }
105 |
106 | render(, 'body')
107 | ```
108 |
109 | * [omi-finger](https://github.com/Tencent/omi/tree/master/packages/omi-finger)
110 | * [css3transform](https://github.com/Tencent/omi/tree/master/packages/omi-transform)
111 |
112 | # Others
113 |
114 | * [AlloyCrop](https://github.com/AlloyTeam/AlloyCrop)
115 |
116 |
117 | # License
118 | This content is released under the [MIT](http://opensource.org/licenses/MIT) License.
119 |
--------------------------------------------------------------------------------
/alloy_crop/README.md:
--------------------------------------------------------------------------------
1 | # 项目新地址
2 |
3 | New Address -> [https://github.com/AlloyTeam/AlloyCrop](https://github.com/AlloyTeam/AlloyCrop)
4 |
--------------------------------------------------------------------------------
/alloy_finger.js:
--------------------------------------------------------------------------------
1 | /* AlloyFinger v0.1.15
2 | * By dntzhang
3 | * Github: https://github.com/AlloyTeam/AlloyFinger
4 | */
5 | ; (function () {
6 | function getLen(v) {
7 | return Math.sqrt(v.x * v.x + v.y * v.y);
8 | }
9 |
10 | function dot(v1, v2) {
11 | return v1.x * v2.x + v1.y * v2.y;
12 | }
13 |
14 | function getAngle(v1, v2) {
15 | var mr = getLen(v1) * getLen(v2);
16 | if (mr === 0) return 0;
17 | var r = dot(v1, v2) / mr;
18 | if (r > 1) r = 1;
19 | return Math.acos(r);
20 | }
21 |
22 | function cross(v1, v2) {
23 | return v1.x * v2.y - v2.x * v1.y;
24 | }
25 |
26 | function getRotateAngle(v1, v2) {
27 | var angle = getAngle(v1, v2);
28 | if (cross(v1, v2) > 0) {
29 | angle *= -1;
30 | }
31 |
32 | return angle * 180 / Math.PI;
33 | }
34 |
35 | var HandlerAdmin = function(el) {
36 | this.handlers = [];
37 | this.el = el;
38 | };
39 |
40 | HandlerAdmin.prototype.add = function(handler) {
41 | this.handlers.push(handler);
42 | }
43 |
44 | HandlerAdmin.prototype.del = function(handler) {
45 | if(!handler) this.handlers = [];
46 |
47 | for(var i=this.handlers.length; i>=0; i--) {
48 | if(this.handlers[i] === handler) {
49 | this.handlers.splice(i, 1);
50 | }
51 | }
52 | }
53 |
54 | HandlerAdmin.prototype.dispatch = function() {
55 | for(var i=0,len=this.handlers.length; i 0 && this.delta <= 250 && Math.abs(this.preTapPosition.x - this.x1) < 30 && Math.abs(this.preTapPosition.y - this.y1) < 30);
129 | if (this.isDoubleTap) clearTimeout(this.singleTapTimeout);
130 | }
131 | this.preTapPosition.x = this.x1;
132 | this.preTapPosition.y = this.y1;
133 | this.last = this.now;
134 | var preV = this.preV,
135 | len = evt.touches.length;
136 | if (len > 1) {
137 | this._cancelLongTap();
138 | this._cancelSingleTap();
139 | var v = { x: evt.touches[1].pageX - this.x1, y: evt.touches[1].pageY - this.y1 };
140 | preV.x = v.x;
141 | preV.y = v.y;
142 | this.pinchStartLen = getLen(preV);
143 | this.multipointStart.dispatch(evt, this.element);
144 | }
145 | this._preventTap = false;
146 | this.longTapTimeout = setTimeout(function () {
147 | this.longTap.dispatch(evt, this.element);
148 | this._preventTap = true;
149 | }.bind(this), 750);
150 | },
151 | move: function (evt) {
152 | if (!evt.touches) return;
153 | var preV = this.preV,
154 | len = evt.touches.length,
155 | currentX = evt.touches[0].pageX,
156 | currentY = evt.touches[0].pageY;
157 | this.isDoubleTap = false;
158 | if (len > 1) {
159 | var sCurrentX = evt.touches[1].pageX,
160 | sCurrentY = evt.touches[1].pageY
161 | var v = { x: evt.touches[1].pageX - currentX, y: evt.touches[1].pageY - currentY };
162 |
163 | if (preV.x !== null) {
164 | if (this.pinchStartLen > 0) {
165 | evt.zoom = getLen(v) / this.pinchStartLen;
166 | this.pinch.dispatch(evt, this.element);
167 | }
168 |
169 | evt.angle = getRotateAngle(v, preV);
170 | this.rotate.dispatch(evt, this.element);
171 | }
172 | preV.x = v.x;
173 | preV.y = v.y;
174 |
175 | if (this.x2 !== null && this.sx2 !== null) {
176 | evt.deltaX = (currentX - this.x2 + sCurrentX - this.sx2) / 2;
177 | evt.deltaY = (currentY - this.y2 + sCurrentY - this.sy2) / 2;
178 | } else {
179 | evt.deltaX = 0;
180 | evt.deltaY = 0;
181 | }
182 | this.twoFingerPressMove.dispatch(evt, this.element);
183 |
184 | this.sx2 = sCurrentX;
185 | this.sy2 = sCurrentY;
186 | } else {
187 | if (this.x2 !== null) {
188 | evt.deltaX = currentX - this.x2;
189 | evt.deltaY = currentY - this.y2;
190 |
191 | //move事件中添加对当前触摸点到初始触摸点的判断,
192 | //如果曾经大于过某个距离(比如10),就认为是移动到某个地方又移回来,应该不再触发tap事件才对。
193 | var movedX = Math.abs(this.x1 - this.x2),
194 | movedY = Math.abs(this.y1 - this.y2);
195 |
196 | if(movedX > 10 || movedY > 10){
197 | this._preventTap = true;
198 | }
199 |
200 | } else {
201 | evt.deltaX = 0;
202 | evt.deltaY = 0;
203 | }
204 |
205 |
206 | this.pressMove.dispatch(evt, this.element);
207 | }
208 |
209 | this.touchMove.dispatch(evt, this.element);
210 |
211 | this._cancelLongTap();
212 | this.x2 = currentX;
213 | this.y2 = currentY;
214 |
215 | if (len > 1) {
216 | evt.preventDefault();
217 | }
218 | },
219 | end: function (evt) {
220 | if (!evt.changedTouches) return;
221 | this._cancelLongTap();
222 | var self = this;
223 | if (evt.touches.length < 2) {
224 | this.multipointEnd.dispatch(evt, this.element);
225 | this.sx2 = this.sy2 = null;
226 | }
227 |
228 | //swipe
229 | if ((this.x2 && Math.abs(this.x1 - this.x2) > 30) ||
230 | (this.y2 && Math.abs(this.y1 - this.y2) > 30)) {
231 | evt.direction = this._swipeDirection(this.x1, this.x2, this.y1, this.y2);
232 | this.swipeTimeout = setTimeout(function () {
233 | self.swipe.dispatch(evt, self.element);
234 |
235 | }, 0)
236 | } else {
237 | this.tapTimeout = setTimeout(function () {
238 | if(!self._preventTap){
239 | self.tap.dispatch(evt, self.element);
240 | }
241 | // trigger double tap immediately
242 | if (self.isDoubleTap) {
243 | self.doubleTap.dispatch(evt, self.element);
244 | self.isDoubleTap = false;
245 | }
246 | }, 0)
247 |
248 | if (!self.isDoubleTap) {
249 | self.singleTapTimeout = setTimeout(function () {
250 | self.singleTap.dispatch(evt, self.element);
251 | }, 250);
252 | }
253 | }
254 |
255 | this.touchEnd.dispatch(evt, this.element);
256 |
257 | this.preV.x = 0;
258 | this.preV.y = 0;
259 | this.zoom = 1;
260 | this.pinchStartLen = null;
261 | this.x1 = this.x2 = this.y1 = this.y2 = null;
262 | },
263 | cancelAll: function () {
264 | this._preventTap = true
265 | clearTimeout(this.singleTapTimeout);
266 | clearTimeout(this.tapTimeout);
267 | clearTimeout(this.longTapTimeout);
268 | clearTimeout(this.swipeTimeout);
269 | },
270 | cancel: function (evt) {
271 | this.cancelAll()
272 | this.touchCancel.dispatch(evt, this.element);
273 | },
274 | _cancelLongTap: function () {
275 | clearTimeout(this.longTapTimeout);
276 | },
277 | _cancelSingleTap: function () {
278 | clearTimeout(this.singleTapTimeout);
279 | },
280 | _swipeDirection: function (x1, x2, y1, y2) {
281 | return Math.abs(x1 - x2) >= Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
282 | },
283 |
284 | on: function(evt, handler) {
285 | if(this[evt]) {
286 | this[evt].add(handler);
287 | }
288 | },
289 |
290 | off: function(evt, handler) {
291 | if(this[evt]) {
292 | this[evt].del(handler);
293 | }
294 | },
295 |
296 | destroy: function() {
297 | if(this.singleTapTimeout) clearTimeout(this.singleTapTimeout);
298 | if(this.tapTimeout) clearTimeout(this.tapTimeout);
299 | if(this.longTapTimeout) clearTimeout(this.longTapTimeout);
300 | if(this.swipeTimeout) clearTimeout(this.swipeTimeout);
301 |
302 | this.element.removeEventListener("touchstart", this.start);
303 | this.element.removeEventListener("touchmove", this.move);
304 | this.element.removeEventListener("touchend", this.end);
305 | this.element.removeEventListener("touchcancel", this.cancel);
306 |
307 | this.rotate.del();
308 | this.touchStart.del();
309 | this.multipointStart.del();
310 | this.multipointEnd.del();
311 | this.pinch.del();
312 | this.swipe.del();
313 | this.tap.del();
314 | this.doubleTap.del();
315 | this.longTap.del();
316 | this.singleTap.del();
317 | this.pressMove.del();
318 | this.twoFingerPressMove.del()
319 | this.touchMove.del();
320 | this.touchEnd.del();
321 | this.touchCancel.del();
322 |
323 | this.preV = this.pinchStartLen = this.zoom = this.isDoubleTap = this.delta = this.last = this.now = this.tapTimeout = this.singleTapTimeout = this.longTapTimeout = this.swipeTimeout = this.x1 = this.x2 = this.y1 = this.y2 = this.preTapPosition = this.rotate = this.touchStart = this.multipointStart = this.multipointEnd = this.pinch = this.swipe = this.tap = this.doubleTap = this.longTap = this.singleTap = this.pressMove = this.touchMove = this.touchEnd = this.touchCancel = this.twoFingerPressMove = null;
324 |
325 | window.removeEventListener('scroll', this._cancelAllHandler);
326 | return null;
327 | }
328 | };
329 |
330 | if (typeof module !== 'undefined' && typeof exports === 'object') {
331 | module.exports = AlloyFinger;
332 | } else {
333 | window.AlloyFinger = AlloyFinger;
334 | }
335 | })();
336 |
--------------------------------------------------------------------------------
/asset/a.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
10 |
11 |
12 |
13 |
14 |
15 | transformjs
16 |
17 |
18 |
19 | transformjs
20 |
21 |
22 |
23 | transformjs
24 |
25 |
26 |
27 | transformjs
28 |
29 |
30 |
31 | transformjs
32 |
33 |
34 |
35 | transformjs
36 |
37 |
38 |
39 | transformjs
40 |
41 |
42 |
43 | transformjs
44 |
45 |
46 |
47 | transformjs
48 |
49 |
50 | transformjs
51 |
52 |
53 |
54 |
105 |
106 |
--------------------------------------------------------------------------------
/asset/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlloyTeam/AlloyFinger/38f2062e65d311db4d51457f06bc0ec77d66f664/asset/cover.jpg
--------------------------------------------------------------------------------
/asset/image_loaded.js:
--------------------------------------------------------------------------------
1 | function imageLoaded(selector,onload){
2 | var img=new Image() ;
3 | var dom=document.querySelector(selector);
4 | img.onload=function(){
5 | //real_width,real_height
6 | onload.call(dom,this.width,this.height);
7 | img.onload=null;
8 | img=null;
9 | };
10 | img.src=dom.getAttribute("src");
11 | }
--------------------------------------------------------------------------------
/asset/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlloyTeam/AlloyFinger/38f2062e65d311db4d51457f06bc0ec77d66f664/asset/loading.gif
--------------------------------------------------------------------------------
/asset/test.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlloyTeam/AlloyFinger/38f2062e65d311db4d51457f06bc0ec77d66f664/asset/test.png
--------------------------------------------------------------------------------
/asset/test2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlloyTeam/AlloyFinger/38f2062e65d311db4d51457f06bc0ec77d66f664/asset/test2.png
--------------------------------------------------------------------------------
/asset/test3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlloyTeam/AlloyFinger/38f2062e65d311db4d51457f06bc0ec77d66f664/asset/test3.png
--------------------------------------------------------------------------------
/asset/to.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlloyTeam/AlloyFinger/38f2062e65d311db4d51457f06bc0ec77d66f664/asset/to.js
--------------------------------------------------------------------------------
/asset/transform.js:
--------------------------------------------------------------------------------
1 | /* transformjs
2 | * By dntzhang
3 | */
4 | ;(function () {
5 |
6 | var Matrix3D = function (n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44) {
7 | this.elements =window.Float32Array ? new Float32Array(16) : [];
8 | var te = this.elements;
9 | te[0] = (n11 !== undefined) ? n11 : 1; te[4] = n12 || 0; te[8] = n13 || 0; te[12] = n14 || 0;
10 | te[1] = n21 || 0; te[5] = (n22 !== undefined) ? n22 : 1; te[9] = n23 || 0; te[13] = n24 || 0;
11 | te[2] = n31 || 0; te[6] = n32 || 0; te[10] = (n33 !== undefined) ? n33 : 1; te[14] = n34 || 0;
12 | te[3] = n41 || 0; te[7] = n42 || 0; te[11] = n43 || 0; te[15] = (n44 !== undefined) ? n44 : 1;
13 | };
14 |
15 | Matrix3D.DEG_TO_RAD = Math.PI / 180;
16 |
17 | Matrix3D.prototype = {
18 | set: function (n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44) {
19 | var te = this.elements;
20 | te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14;
21 | te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24;
22 | te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34;
23 | te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44;
24 | return this;
25 | },
26 | identity: function () {
27 | this.set(
28 | 1, 0, 0, 0,
29 | 0, 1, 0, 0,
30 | 0, 0, 1, 0,
31 | 0, 0, 0, 1
32 | );
33 | return this;
34 | },
35 | multiplyMatrices: function (a, be) {
36 |
37 | var ae = a.elements;
38 | var te = this.elements;
39 | var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12];
40 | var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13];
41 | var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14];
42 | var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15];
43 |
44 | var b11 = be[0], b12 = be[1], b13 = be[2], b14 = be[3];
45 | var b21 = be[4], b22 = be[5], b23 = be[6], b24 = be[7];
46 | var b31 = be[8], b32 = be[9], b33 = be[10], b34 = be[11];
47 | var b41 = be[12], b42 = be[13], b43 = be[14], b44 = be[15];
48 |
49 | te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
50 | te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
51 | te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
52 | te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
53 |
54 | te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
55 | te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
56 | te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
57 | te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
58 |
59 | te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
60 | te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
61 | te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
62 | te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
63 |
64 | te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
65 | te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
66 | te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
67 | te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
68 |
69 | return this;
70 |
71 | },
72 | // 解决角度为90的整数倍导致Math.cos得到极小的数,其实是0。导致不渲染
73 | _rounded: function(value,i){
74 | i= Math.pow(10, i || 15);
75 | // default
76 | return Math.round(value*i)/i;
77 | },
78 | appendTransform: function (x, y, z, scaleX, scaleY, scaleZ, rotateX, rotateY, rotateZ,skewX,skewY, originX, originY, originZ) {
79 |
80 | var rx = rotateX * Matrix3D.DEG_TO_RAD;
81 | var cosx =this._rounded( Math.cos(rx));
82 | var sinx = this._rounded(Math.sin(rx));
83 | var ry = rotateY * Matrix3D.DEG_TO_RAD;
84 | var cosy =this._rounded( Math.cos(ry));
85 | var siny = this._rounded(Math.sin(ry));
86 | var rz = rotateZ * Matrix3D.DEG_TO_RAD;
87 | var cosz =this._rounded( Math.cos(rz * -1));
88 | var sinz =this._rounded( Math.sin(rz * -1));
89 |
90 | this.multiplyMatrices(this, [
91 | 1, 0, 0, x,
92 | 0, cosx, sinx, y,
93 | 0, -sinx, cosx, z,
94 | 0, 0, 0, 1
95 | ]);
96 |
97 | this.multiplyMatrices(this, [
98 | cosy, 0, siny, 0,
99 | 0, 1, 0, 0,
100 | -siny, 0, cosy, 0,
101 | 0, 0, 0, 1
102 | ]);
103 |
104 | this.multiplyMatrices(this,[
105 | cosz * scaleX, sinz * scaleY, 0, 0,
106 | -sinz * scaleX, cosz * scaleY, 0, 0,
107 | 0, 0, 1 * scaleZ, 0,
108 | 0, 0, 0, 1
109 | ]);
110 |
111 | if(skewX||skewY){
112 | this.multiplyMatrices(this,[
113 | this._rounded(Math.cos(skewX* Matrix3D.DEG_TO_RAD)), this._rounded( Math.sin(skewX* Matrix3D.DEG_TO_RAD)), 0, 0,
114 | -1*this._rounded(Math.sin(skewY* Matrix3D.DEG_TO_RAD)), this._rounded( Math.cos(skewY* Matrix3D.DEG_TO_RAD)), 0, 0,
115 | 0, 0, 1, 0,
116 | 0, 0, 0, 1
117 | ]);
118 | }
119 |
120 | if (originX || originY || originZ) {
121 | this.elements[12] -= originX * this.elements[0] + originY * this.elements[4] + originZ * this.elements[8];
122 | this.elements[13] -= originX * this.elements[1] + originY * this.elements[5] + originZ * this.elements[9];
123 | this.elements[14] -= originX * this.elements[2] + originY * this.elements[6] + originZ * this.elements[10];
124 | }
125 | return this;
126 | }
127 | };
128 |
129 | function observe(target, props, callback) {
130 | for (var i = 0, len = props.length; i < len; i++) {
131 | var prop = props[i];
132 | watch(target, prop, callback);
133 | }
134 | }
135 |
136 | function watch(target, prop, callback) {
137 | Object.defineProperty(target, prop, {
138 | get: function () {
139 | return this["__" + prop];
140 | },
141 | set: function (value) {
142 | if (value !== this["__" + prop]) {
143 | this["__" + prop] = value;
144 | callback();
145 | }
146 |
147 | }
148 | });
149 | }
150 |
151 | window.Transform = function (element) {
152 |
153 | observe(
154 | element,
155 | ["translateX", "translateY", "translateZ", "scaleX", "scaleY", "scaleZ" , "rotateX", "rotateY", "rotateZ","skewX","skewY", "originX", "originY", "originZ"],
156 | function () {
157 | var mtx = element.matrix3D.identity().appendTransform( element.translateX, element.translateY, element.translateZ, element.scaleX, element.scaleY, element.scaleZ, element.rotateX, element.rotateY, element.rotateZ,element.skewX,element.skewY, element.originX, element.originY, element.originZ);
158 | element.style.transform = element.style.msTransform = element.style.OTransform = element.style.MozTransform = element.style.webkitTransform = "perspective("+element.perspective+"px) matrix3d(" + Array.prototype.slice.call(mtx.elements).join(",") + ")";
159 | });
160 |
161 | observe(
162 | element,
163 | [ "perspective"],
164 | function () {
165 | element.style.transform = element.style.msTransform = element.style.OTransform = element.style.MozTransform = element.style.webkitTransform = "perspective("+element.perspective+"px) matrix3d(" + Array.prototype.slice.call(element.matrix3D.elements).join(",") + ")";
166 | });
167 |
168 | element.matrix3D = new Matrix3D();
169 | element.perspective = 500;
170 | element.scaleX = element.scaleY = element.scaleZ = 1;
171 | //由于image自带了x\y\z,所有加上translate前缀
172 | element.translateX = element.translateY = element.translateZ = element.rotateX = element.rotateY = element.rotateZ =element.skewX=element.skewY= element.originX = element.originY = element.originZ = 0;
173 | }
174 | })();
--------------------------------------------------------------------------------
/asset/yes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AlloyTeam/AlloyFinger/38f2062e65d311db4d51457f06bc0ec77d66f664/asset/yes.png
--------------------------------------------------------------------------------
/example/canvas/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Canvas+AlloyFinger
6 |
7 |
30 |
31 |
32 | Fork me on Github
33 |
34 |
35 |
36 |
37 |
116 |
117 |
--------------------------------------------------------------------------------
/example/destroy/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Event Test
5 |
6 |
14 |
15 |
16 | Touch Me
17 |
18 |
19 |
20 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/example/on_off/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Event Test
5 |
6 |
14 |
15 |
16 | Touch Me
17 |
18 |
19 |
20 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/example/picture/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AlloyFinger
5 |
6 |
29 |
30 |
31 | Fork me on Github
32 |
33 |
34 |
35 |
36 |
38 |

39 |
40 |
41 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/example/simple/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
29 |
30 |
31 | Fork me on Github
32 |
33 |
34 |
35 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/example/tap_state/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Tap State
5 |
6 |
39 |
40 |
41 | Fork me on Github
42 | Tap Me
43 |
44 |
45 |
46 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/example/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Event Test
5 |
6 |
14 |
15 |
16 | Touch Me
17 |
18 |
19 |
20 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | AlloyFinger
6 |
7 |
169 |
170 |
171 | Fork me on Github
172 |
173 |
174 |
pinch
175 |
176 |

177 |
178 |
rotate
179 |
180 |

181 |
182 |
pinch+rotate
183 |
184 |

185 |
186 |
pressMove
187 |
188 |

189 |
190 |
doubleTap
191 |
192 |

193 |
194 |
swipe
195 |
207 |
longTap
208 |
209 |
210 |

211 |
212 |

213 |
214 |
215 |
216 |
217 |
tap
218 |
219 |
220 |

221 |
222 |

223 |
224 |
225 |
226 |
227 |
230 |
231 |
232 |
233 |
374 |
375 |
376 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "alloyfinger",
3 | "version": "0.1.15",
4 | "description": "super tiny size multi-touch gestures library for the web. ",
5 | "main": "alloy_finger.js",
6 | "directories": {
7 | "example": "example"
8 | },
9 | "scripts": {
10 | "prepare": "npm run build",
11 | "build": "if [ -d dist ]; then rm -r dist; fi; npm run build:react",
12 | "build:react": "babel react --out-dir dist/react --source-map",
13 | "test": "echo \"Error: no test specified\" && exit 1"
14 | },
15 | "devDependencies": {
16 | "babel-cli": "^6.24.0",
17 | "babel-core": "^6.24.0",
18 | "babel-plugin-add-module-exports": "^0.2.1",
19 | "babel-plugin-transform-class-properties": "^6.23.0",
20 | "babel-plugin-transform-decorators": "^6.24.1",
21 | "babel-plugin-transform-function-bind": "^6.22.0",
22 | "babel-plugin-transform-object-rest-spread": "^6.23.0",
23 | "babel-polyfill": "^6.23.0",
24 | "babel-preset-env": "^1.3.2",
25 | "babel-preset-react": "^6.24.1",
26 | "babel-runtime": "^6.23.0",
27 | "fast-async": "^6.2.2",
28 | "husky": "^0.13.3"
29 | },
30 | "repository": {
31 | "type": "git",
32 | "url": "git+https://github.com/AlloyTeam/AlloyFinger.git"
33 | },
34 | "keywords": [
35 | "gesture",
36 | "touch",
37 | "multitouch"
38 | ],
39 | "author": "dntzhang",
40 | "license": "MIT",
41 | "bugs": {
42 | "url": "https://github.com/AlloyTeam/AlloyFinger/issues"
43 | },
44 | "homepage": "https://github.com/AlloyTeam/AlloyFinger#readme"
45 | }
46 |
--------------------------------------------------------------------------------
/react/AlloyFinger.jsx:
--------------------------------------------------------------------------------
1 | /* AlloyFinger v0.1.0
2 | * By dntzhang
3 | * Reedited by nemoliao
4 | * Github: https://github.com/AlloyTeam/AlloyFinger
5 | */
6 |
7 | import React, { Component } from 'react';
8 |
9 | export default class AlloyFinger extends Component {
10 | constructor(props) {
11 | super(props);
12 |
13 | this.preV = { x: null, y: null };
14 | this.pinchStartLen = null;
15 | this.scale = 1;
16 | this.isSingleTap = false;
17 | this.isDoubleTap = false;
18 | this.delta = null;
19 | this.last = null;
20 | this.now = null;
21 | this.end = null;
22 | this.multiTouch = false;
23 | this.tapTimeout = null;
24 | this.longTapTimeout = null;
25 | this.singleTapTimeout = null;
26 | this.swipeTimeout=null;
27 | this.x1 = this.x2 = this.y1 = this.y2 = null;
28 | this.preTapPosition={x: null, y: null};
29 |
30 | // Disable taps after longTap
31 | this.afterLongTap = false;
32 | this.afterLongTapTimeout = null;
33 | }
34 |
35 | getLen(v) {
36 | return Math.sqrt(v.x * v.x + v.y * v.y);
37 | }
38 |
39 | dot(v1, v2) {
40 | return v1.x * v2.x + v1.y * v2.y;
41 | }
42 |
43 | getAngle(v1, v2) {
44 | var mr = this.getLen(v1) * this.getLen(v2);
45 | if (mr === 0) return 0;
46 | var r = this.dot(v1, v2) / mr;
47 | if (r > 1) r = 1;
48 | return Math.acos(r);
49 | }
50 |
51 | cross(v1, v2) {
52 | return v1.x * v2.y - v2.x * v1.y;
53 | }
54 |
55 | getRotateAngle(v1, v2) {
56 | var angle = this.getAngle(v1, v2);
57 | if (this.cross(v1, v2) > 0) {
58 | angle *= -1;
59 | }
60 |
61 | return angle * 180 / Math.PI;
62 | }
63 |
64 | _resetState() {
65 | this.setState({
66 | x: null,
67 | y: null,
68 | swiping: false,
69 | start: 0
70 | });
71 | }
72 |
73 |
74 | _emitEvent(name, ...arg) {
75 | if (this.props[name]) {
76 | this.props[name](...arg);
77 | }
78 | }
79 |
80 | _handleTouchStart (evt) {
81 | this._emitEvent('onTouchStart', evt);
82 | if (!evt.touches) return;
83 | this.now = Date.now();
84 | this.x1 = evt.touches[0].pageX;
85 | this.y1 = evt.touches[0].pageY;
86 | this.delta = this.now - (this.last || this.now);
87 | if (this.preTapPosition.x!==null) {
88 | this.isDoubleTap = (this.delta > 0 && this.delta <= 250&&Math.abs(this.preTapPosition.x-this.x1)<30&&Math.abs(this.preTapPosition.y-this.y1)<30);
89 | }
90 | this.preTapPosition.x=this.x1;
91 | this.preTapPosition.y=this.y1;
92 | this.last = this.now;
93 | var preV = this.preV,
94 | len = evt.touches.length;
95 |
96 | if (len > 1) {
97 | this._cancelLongTap();
98 | this._cancelSingleTap();
99 | var v = { x: evt.touches[1].pageX - this.x1, y: evt.touches[1].pageY - this.y1 };
100 | preV.x = v.x;
101 | preV.y = v.y;
102 | this.pinchStartLen = this.getLen(preV);
103 | this._emitEvent('onMultipointStart', evt);
104 | } else {
105 | this.isSingleTap = true;
106 | }
107 | this.longTapTimeout = setTimeout(() => {
108 | this._emitEvent('onLongTap', evt);
109 | this.afterLongTap = true;
110 | this.afterLongTapTimeout = setTimeout(() => {
111 | this.afterLongTap = false;
112 | }, 1000);
113 | }, 750);
114 | }
115 |
116 | _handleTouchMove(evt) {
117 | this._emitEvent('onTouchMove', evt);
118 | var preV = this.preV,
119 | len = evt.touches.length,
120 | currentX = evt.touches[0].pageX,
121 | currentY = evt.touches[0].pageY;
122 | this.isSingleTap = false;
123 | this.isDoubleTap = false;
124 | if (len > 1) {
125 | var v = { x: evt.touches[1].pageX - currentX, y: evt.touches[1].pageY - currentY };
126 | if (preV.x !== null) {
127 | if (this.pinchStartLen > 0) {
128 | evt.center = {
129 | x: (evt.touches[1].pageX + currentX) / 2,
130 | y: (evt.touches[1].pageY + currentY) / 2
131 | };
132 | evt.scale = evt.zoom = this.getLen(v) / this.pinchStartLen;
133 | this._emitEvent('onPinch', evt);
134 | }
135 | evt.angle = this.getRotateAngle(v, preV);
136 | this._emitEvent('onRotate', evt);
137 | }
138 | preV.x = v.x;
139 | preV.y = v.y;
140 | this.multiTouch = true;
141 | } else {
142 | if (this.x2 !== null) {
143 | evt.deltaX = currentX - this.x2;
144 | evt.deltaY = currentY - this.y2;
145 | } else {
146 | evt.deltaX = 0;
147 | evt.deltaY = 0;
148 | }
149 | this._emitEvent('onPressMove', evt);
150 | }
151 | this._cancelLongTap();
152 | this.x2 = currentX;
153 | this.y2 = currentY;
154 |
155 | if (len > 1) {
156 | evt.preventDefault();
157 | }
158 | }
159 |
160 | _handleTouchCancel(evt) {
161 | this._emitEvent('onTouchCancel', evt);
162 | clearInterval(this.singleTapTimeout);
163 | clearInterval(this.tapTimeout);
164 | clearInterval(this.longTapTimeout);
165 | clearInterval(this.swipeTimeout);
166 | }
167 |
168 | _handleTouchEnd(evt) {
169 | this._emitEvent('onTouchEnd', evt);
170 | this.end = Date.now();
171 | this._cancelLongTap();
172 |
173 | if (this.multiTouch === true && evt.touches.length < 2) {
174 | this._emitEvent('onMultipointEnd', evt);
175 | }
176 |
177 | evt.origin = [this.x1, this.y1];
178 | if (this.multiTouch === false) {
179 | if ((this.x2 && Math.abs(this.x1 - this.x2) > 30) ||
180 | (this.y2 && Math.abs(this.y1 - this.y2) > 30)) {
181 | evt.direction = this._swipeDirection(this.x1, this.x2, this.y1, this.y2);
182 | evt.distance = Math.abs(this.x1 - this.x2);
183 | this.swipeTimeout = setTimeout(() => {
184 | this._emitEvent('onSwipe', evt);
185 | }, 0);
186 | } else {
187 | if (this.afterLongTap) {
188 | clearTimeout(this.afterLongTapTimeout);
189 | this.afterLongTap = false;
190 | } else {
191 | this.tapTimeout = setTimeout(() => {
192 | this._emitEvent('onTap', evt);
193 | if (this.isDoubleTap) {
194 | this._emitEvent('onDoubleTap', evt);
195 | clearTimeout(this.singleTapTimeout);
196 | this.isDoubleTap = false;
197 | } else if (this.isSingleTap) {
198 | this.singleTapTimeout = setTimeout(()=>{
199 | this._emitEvent('onSingleTap', evt);
200 | }, 250);
201 | this.isSingleTap = false;
202 | }
203 | }, 0);
204 | }
205 | }
206 | }
207 |
208 | this.preV.x = 0;
209 | this.preV.y = 0;
210 | this.scale = 1;
211 | this.pinchStartLen = null;
212 | this.x1 = this.x2 = this.y1 = this.y2 = null;
213 | this.multiTouch = false;
214 | }
215 |
216 | _cancelLongTap () {
217 | clearTimeout(this.longTapTimeout);
218 | }
219 |
220 | _cancelSingleTap () {
221 | clearTimeout(this.singleTapTimeout);
222 | }
223 |
224 | _swipeDirection (x1, x2, y1, y2) {
225 | if (Math.abs(x1 - x2) > 80 || this.end-this.now < 250) {
226 | return Math.abs(x1 - x2) >= Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down');
227 | } else {
228 | return 'Nochange';
229 | }
230 |
231 | }
232 |
233 | render() {
234 | return React.cloneElement(React.Children.only(this.props.children), {
235 | onTouchStart: this._handleTouchStart.bind(this),
236 | onTouchMove: this._handleTouchMove.bind(this),
237 | onTouchCancel: this._handleTouchCancel.bind(this),
238 | onTouchEnd: this._handleTouchEnd.bind(this)
239 | });
240 | }
241 | }
242 |
--------------------------------------------------------------------------------
/transformjs/README.md:
--------------------------------------------------------------------------------
1 |
2 | transformjs have been moved to here https://github.com/AlloyTeam/AlloyTouch/tree/master/transformjs
3 |
4 |
--------------------------------------------------------------------------------
/transformjs/transform.js:
--------------------------------------------------------------------------------
1 | /* transformjs
2 | * By dntzhang
3 | * Github: https://github.com/AlloyTeam/AlloyTouch/tree/master/transformjs
4 | */
5 | ;(function () {
6 |
7 | var Matrix3D = function (n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44) {
8 | this.elements =window.Float32Array ? new Float32Array(16) : [];
9 | var te = this.elements;
10 | te[0] = (n11 !== undefined) ? n11 : 1; te[4] = n12 || 0; te[8] = n13 || 0; te[12] = n14 || 0;
11 | te[1] = n21 || 0; te[5] = (n22 !== undefined) ? n22 : 1; te[9] = n23 || 0; te[13] = n24 || 0;
12 | te[2] = n31 || 0; te[6] = n32 || 0; te[10] = (n33 !== undefined) ? n33 : 1; te[14] = n34 || 0;
13 | te[3] = n41 || 0; te[7] = n42 || 0; te[11] = n43 || 0; te[15] = (n44 !== undefined) ? n44 : 1;
14 | };
15 |
16 | Matrix3D.DEG_TO_RAD = Math.PI / 180;
17 |
18 | Matrix3D.prototype = {
19 | set: function (n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44) {
20 | var te = this.elements;
21 | te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14;
22 | te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24;
23 | te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34;
24 | te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44;
25 | return this;
26 | },
27 | identity: function () {
28 | this.set(
29 | 1, 0, 0, 0,
30 | 0, 1, 0, 0,
31 | 0, 0, 1, 0,
32 | 0, 0, 0, 1
33 | );
34 | return this;
35 | },
36 | multiplyMatrices: function (a, be) {
37 |
38 | var ae = a.elements;
39 | var te = this.elements;
40 | var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12];
41 | var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13];
42 | var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14];
43 | var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15];
44 |
45 | var b11 = be[0], b12 = be[1], b13 = be[2], b14 = be[3];
46 | var b21 = be[4], b22 = be[5], b23 = be[6], b24 = be[7];
47 | var b31 = be[8], b32 = be[9], b33 = be[10], b34 = be[11];
48 | var b41 = be[12], b42 = be[13], b43 = be[14], b44 = be[15];
49 |
50 | te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
51 | te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
52 | te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
53 | te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
54 |
55 | te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
56 | te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
57 | te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
58 | te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
59 |
60 | te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
61 | te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
62 | te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
63 | te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
64 |
65 | te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
66 | te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
67 | te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
68 | te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
69 |
70 | return this;
71 |
72 | },
73 | // 解决角度为90的整数倍导致Math.cos得到极小的数,其实是0。导致不渲染
74 | _rounded: function(value,i){
75 | i= Math.pow(10, i || 15);
76 | // default
77 | return Math.round(value*i)/i;
78 | },
79 | appendTransform: function (x, y, z, scaleX, scaleY, scaleZ, rotateX, rotateY, rotateZ,skewX,skewY, originX, originY, originZ) {
80 |
81 | var rx = rotateX * Matrix3D.DEG_TO_RAD;
82 | var cosx =this._rounded( Math.cos(rx));
83 | var sinx = this._rounded(Math.sin(rx));
84 | var ry = rotateY * Matrix3D.DEG_TO_RAD;
85 | var cosy =this._rounded( Math.cos(ry));
86 | var siny = this._rounded(Math.sin(ry));
87 | var rz = rotateZ * Matrix3D.DEG_TO_RAD;
88 | var cosz =this._rounded( Math.cos(rz * -1));
89 | var sinz =this._rounded( Math.sin(rz * -1));
90 |
91 | this.multiplyMatrices(this, [
92 | 1, 0, 0, x,
93 | 0, cosx, sinx, y,
94 | 0, -sinx, cosx, z,
95 | 0, 0, 0, 1
96 | ]);
97 |
98 | this.multiplyMatrices(this, [
99 | cosy, 0, siny, 0,
100 | 0, 1, 0, 0,
101 | -siny, 0, cosy, 0,
102 | 0, 0, 0, 1
103 | ]);
104 |
105 | this.multiplyMatrices(this,[
106 | cosz * scaleX, sinz * scaleY, 0, 0,
107 | -sinz * scaleX, cosz * scaleY, 0, 0,
108 | 0, 0, 1 * scaleZ, 0,
109 | 0, 0, 0, 1
110 | ]);
111 |
112 | if(skewX||skewY){
113 | this.multiplyMatrices(this,[
114 | this._rounded(Math.cos(skewX* Matrix3D.DEG_TO_RAD)), this._rounded( Math.sin(skewX* Matrix3D.DEG_TO_RAD)), 0, 0,
115 | -1*this._rounded(Math.sin(skewY* Matrix3D.DEG_TO_RAD)), this._rounded( Math.cos(skewY* Matrix3D.DEG_TO_RAD)), 0, 0,
116 | 0, 0, 1, 0,
117 | 0, 0, 0, 1
118 | ]);
119 | }
120 |
121 | if (originX || originY || originZ) {
122 | this.elements[12] -= originX * this.elements[0] + originY * this.elements[4] + originZ * this.elements[8];
123 | this.elements[13] -= originX * this.elements[1] + originY * this.elements[5] + originZ * this.elements[9];
124 | this.elements[14] -= originX * this.elements[2] + originY * this.elements[6] + originZ * this.elements[10];
125 | }
126 | return this;
127 | }
128 | };
129 |
130 | function observe(target, props, callback) {
131 | for (var i = 0, len = props.length; i < len; i++) {
132 | var prop = props[i];
133 | watch(target, prop, callback);
134 | }
135 | }
136 |
137 | function watch(target, prop, callback) {
138 | Object.defineProperty(target, prop, {
139 | get: function () {
140 | return this["__" + prop];
141 | },
142 | set: function (value) {
143 | if (value !== this["__" + prop]) {
144 | this["__" + prop] = value;
145 | callback();
146 | }
147 |
148 | }
149 | });
150 | }
151 |
152 | window.Transform = function (element,notPerspective) {
153 |
154 | observe(
155 | element,
156 | ["translateX", "translateY", "translateZ", "scaleX", "scaleY", "scaleZ", "rotateX", "rotateY", "rotateZ", "skewX", "skewY", "originX", "originY", "originZ"],
157 | function () {
158 | var mtx = element.matrix3D.identity().appendTransform(element.translateX, element.translateY, element.translateZ, element.scaleX, element.scaleY, element.scaleZ, element.rotateX, element.rotateY, element.rotateZ, element.skewX, element.skewY, element.originX, element.originY, element.originZ);
159 | element.style.transform = element.style.msTransform = element.style.OTransform = element.style.MozTransform = element.style.webkitTransform =(notPerspective?"":"perspective(" + (element.perspective===undefined?500:element.perspective) + "px) ")+ "matrix3d(" + Array.prototype.slice.call(mtx.elements).join(",") + ")";
160 | });
161 |
162 | element.matrix3D = new Matrix3D();
163 |
164 | if (!notPerspective) {
165 | observe(
166 | element,
167 | ["perspective"],
168 | function () {
169 | element.style.transform = element.style.msTransform = element.style.OTransform = element.style.MozTransform = element.style.webkitTransform = "perspective(" + element.perspective + "px) matrix3d(" + Array.prototype.slice.call(element.matrix3D.elements).join(",") + ")";
170 | });
171 | element.perspective = 500;
172 | }
173 |
174 | element.scaleX = element.scaleY = element.scaleZ = 1;
175 | //由于image自带了x\y\z,所有加上translate前缀
176 | element.translateX = element.translateY = element.translateZ = element.rotateX = element.rotateY = element.rotateZ = element.skewX = element.skewY = element.originX = element.originY = element.originZ = 0;
177 | }
178 | })();
179 |
--------------------------------------------------------------------------------