OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 'use strict'; | 5 'use strict'; |
6 | 6 |
7 /** | 7 /** |
8 * Slide mode displays a single image and has a set of controls to navigate | 8 * Slide mode displays a single image and has a set of controls to navigate |
9 * between the images and to edit an image. | 9 * between the images and to edit an image. |
10 * | 10 * |
(...skipping 1354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1365 | 1365 |
1366 /** | 1366 /** |
1367 * Event on beginning of the current gesture. | 1367 * Event on beginning of the current gesture. |
1368 * The variable is updated when the number of touch finger changed. | 1368 * The variable is updated when the number of touch finger changed. |
1369 * @type {TouchEvent} | 1369 * @type {TouchEvent} |
1370 * @private | 1370 * @private |
1371 */ | 1371 */ |
1372 this.gestureStartEvent_ = null; | 1372 this.gestureStartEvent_ = null; |
1373 | 1373 |
1374 /** | 1374 /** |
| 1375 * Rotation value on beginning of the current gesture. |
| 1376 * @type {number} |
| 1377 * @private |
| 1378 */ |
| 1379 this.gestureStartRotation_ = 0; |
| 1380 |
| 1381 /** |
1375 * Last touch event. | 1382 * Last touch event. |
1376 * @type {TouchEvent} | 1383 * @type {TouchEvent} |
1377 * @private | 1384 * @private |
1378 */ | 1385 */ |
1379 this.lastEvent_ = null; | 1386 this.lastEvent_ = null; |
1380 | 1387 |
1381 /** | 1388 /** |
1382 * Zoom value just after last touch event. | 1389 * Zoom value just after last touch event. |
1383 * @type {number} | 1390 * @type {number} |
1384 * @private | 1391 * @private |
1385 */ | 1392 */ |
1386 this.lastZoom_ = 1.0; | 1393 this.lastZoom_ = 1.0; |
1387 | 1394 |
1388 targetElement.addEventListener('touchstart', this.onTouchStart_.bind(this)); | 1395 targetElement.addEventListener('touchstart', this.onTouchStart_.bind(this)); |
1389 var onTouchEventBound = this.onTouchEvent_.bind(this); | 1396 var onTouchEventBound = this.onTouchEvent_.bind(this); |
1390 targetElement.ownerDocument.addEventListener('touchmove', onTouchEventBound); | 1397 targetElement.ownerDocument.addEventListener('touchmove', onTouchEventBound); |
1391 targetElement.ownerDocument.addEventListener('touchend', onTouchEventBound); | 1398 targetElement.ownerDocument.addEventListener('touchend', onTouchEventBound); |
1392 } | 1399 } |
1393 | 1400 |
1394 /** | 1401 /** |
1395 * If the user touched the image and moved the finger more than SWIPE_THRESHOLD | 1402 * If the user touched the image and moved the finger more than SWIPE_THRESHOLD |
1396 * horizontally it's considered as a swipe gesture (change the current image). | 1403 * horizontally it's considered as a swipe gesture (change the current image). |
1397 * @type {number} | 1404 * @type {number} |
1398 * @const | 1405 * @const |
1399 */ | 1406 */ |
1400 TouchHandler.SWIPE_THRESHOLD = 100; | 1407 TouchHandler.SWIPE_THRESHOLD = 100; |
1401 | 1408 |
1402 /** | 1409 /** |
| 1410 * Rotation threshold in degrees. |
| 1411 * @type {number} |
| 1412 * @const |
| 1413 */ |
| 1414 TouchHandler.ROTATION_THRESHOLD = 25; |
| 1415 |
| 1416 /** |
1403 * Obtains distance between fingers. | 1417 * Obtains distance between fingers. |
1404 * @param {TouchEvent} event Touch event. It should include more than two | 1418 * @param {TouchEvent} event Touch event. It should include more than two |
1405 * touches. | 1419 * touches. |
1406 * @return {boolean} Distance between touch[0] and touch[1]. | 1420 * @return {boolean} Distance between touch[0] and touch[1]. |
1407 */ | 1421 */ |
1408 TouchHandler.getDistance = function(event) { | 1422 TouchHandler.getDistance = function(event) { |
1409 var touch1 = event.touches[0]; | 1423 var touch1 = event.touches[0]; |
1410 var touch2 = event.touches[1]; | 1424 var touch2 = event.touches[1]; |
1411 var dx = touch1.clientX - touch2.clientX; | 1425 var dx = touch1.clientX - touch2.clientX; |
1412 var dy = touch1.clientY - touch2.clientY; | 1426 var dy = touch1.clientY - touch2.clientY; |
1413 return Math.sqrt(dx * dx + dy * dy); | 1427 return Math.sqrt(dx * dx + dy * dy); |
1414 }; | 1428 }; |
1415 | 1429 |
1416 TouchHandler.prototype = { | 1430 TouchHandler.prototype = { |
1417 /** | 1431 /** |
1418 * @param {boolean} flag New value. | 1432 * @param {boolean} flag New value. |
1419 */ | 1433 */ |
1420 set enabled(flag) { | 1434 set enabled(flag) { |
1421 this.enabled_ = flag; | 1435 this.enabled_ = flag; |
1422 if (!this.enabled_) | 1436 if (!this.enabled_) |
1423 this.stopOperation(); | 1437 this.stopOperation(); |
1424 } | 1438 } |
1425 }; | 1439 }; |
1426 | 1440 |
1427 /** | 1441 /** |
| 1442 * Obtains the degrees of the pinch twist angle. |
| 1443 * @param {TouchEvent} event1 Start touch event. It should include more than two |
| 1444 * touches. |
| 1445 * @param {TouchEvent} event2 Current touch event. It should include more than |
| 1446 * two touches. |
| 1447 * @return {number} Degrees of the pinch twist angle. |
| 1448 */ |
| 1449 TouchHandler.getTwistAngle = function(event1, event2) { |
| 1450 var dx1 = event1.touches[1].clientX - event1.touches[0].clientX; |
| 1451 var dy1 = event1.touches[1].clientY - event1.touches[0].clientY; |
| 1452 var dx2 = event2.touches[1].clientX - event2.touches[0].clientX; |
| 1453 var dy2 = event2.touches[1].clientY - event2.touches[0].clientY; |
| 1454 var innerProduct = dx1 * dx2 + dy1 * dy2; // |v1| * |v2| * cos(t) = x / r |
| 1455 var outerProduct = dx1 * dy2 - dy1 * dx2; // |v1| * |v2| * sin(t) = y / r |
| 1456 return Math.atan2(outerProduct, innerProduct) * 180 / Math.PI; // atan(y / x) |
| 1457 }; |
| 1458 |
| 1459 /** |
1428 * Stops the current touch operation. | 1460 * Stops the current touch operation. |
1429 */ | 1461 */ |
1430 TouchHandler.prototype.stopOperation = function() { | 1462 TouchHandler.prototype.stopOperation = function() { |
1431 this.touchStarted_ = false; | 1463 this.touchStarted_ = false; |
1432 this.done_ = false; | 1464 this.done_ = false; |
1433 this.gestureStartEvent_ = null; | 1465 this.gestureStartEvent_ = null; |
1434 this.lastEvent_ = null; | 1466 this.lastEvent_ = null; |
1435 this.lastZoom_ = 1.0; | 1467 this.lastZoom_ = 1.0; |
1436 }; | 1468 }; |
1437 | 1469 |
(...skipping 11 matching lines...) Expand all Loading... |
1449 if (!this.touchStarted_) | 1481 if (!this.touchStarted_) |
1450 return; | 1482 return; |
1451 | 1483 |
1452 // Check if the current touch operation ends with the event. | 1484 // Check if the current touch operation ends with the event. |
1453 if (event.touches.length === 0) { | 1485 if (event.touches.length === 0) { |
1454 this.stopOperation(); | 1486 this.stopOperation(); |
1455 return; | 1487 return; |
1456 } | 1488 } |
1457 | 1489 |
1458 // Check if a new gesture started or not. | 1490 // Check if a new gesture started or not. |
| 1491 var viewport = this.slideMode_.getViewport(); |
1459 if (!this.lastEvent_ || | 1492 if (!this.lastEvent_ || |
1460 this.lastEvent_.touches.length !== event.touches.length) { | 1493 this.lastEvent_.touches.length !== event.touches.length) { |
1461 if (event.touches.length === 2 || | 1494 if (event.touches.length === 2 || |
1462 event.touches.length === 1) { | 1495 event.touches.length === 1) { |
1463 this.gestureStartEvent_ = event; | 1496 this.gestureStartEvent_ = event; |
| 1497 this.gestureStartRotation_ = viewport.getRotation(); |
1464 this.lastEvent_ = event; | 1498 this.lastEvent_ = event; |
1465 this.lastZoom_ = this.slideMode_.getViewport().getZoom(); | 1499 this.lastZoom_ = viewport.getZoom(); |
1466 } else { | 1500 } else { |
1467 this.gestureStartEvent_ = null; | 1501 this.gestureStartEvent_ = null; |
| 1502 this.gestureStartRotation_ = 0; |
1468 this.lastEvent_ = null; | 1503 this.lastEvent_ = null; |
1469 this.lastZoom_ = 1.0; | 1504 this.lastZoom_ = 1.0; |
1470 } | 1505 } |
1471 return; | 1506 return; |
1472 } | 1507 } |
1473 | 1508 |
1474 // Handle the gesture movement. | 1509 // Handle the gesture movement. |
1475 var viewport = this.slideMode_.getViewport(); | |
1476 switch (event.touches.length) { | 1510 switch (event.touches.length) { |
1477 case 1: | 1511 case 1: |
1478 if (viewport.isZoomed()) { | 1512 if (viewport.isZoomed()) { |
1479 // Scrolling an image by swipe. | 1513 // Scrolling an image by swipe. |
1480 var dx = event.touches[0].screenX - this.lastEvent_.touches[0].screenX; | 1514 var dx = event.touches[0].screenX - this.lastEvent_.touches[0].screenX; |
1481 var dy = event.touches[0].screenY - this.lastEvent_.touches[0].screenY; | 1515 var dy = event.touches[0].screenY - this.lastEvent_.touches[0].screenY; |
1482 viewport.setOffset( | 1516 viewport.setOffset( |
1483 viewport.getOffsetX() + dx, viewport.getOffsetY() + dy); | 1517 viewport.getOffsetX() + dx, viewport.getOffsetY() + dy); |
1484 this.slideMode_.applyViewportChange(); | 1518 this.slideMode_.applyViewportChange(); |
1485 } else { | 1519 } else { |
(...skipping 14 matching lines...) Expand all Loading... |
1500 break; | 1534 break; |
1501 | 1535 |
1502 case 2: | 1536 case 2: |
1503 // Pinch zoom. | 1537 // Pinch zoom. |
1504 var distance1 = TouchHandler.getDistance(this.lastEvent_); | 1538 var distance1 = TouchHandler.getDistance(this.lastEvent_); |
1505 var distance2 = TouchHandler.getDistance(event); | 1539 var distance2 = TouchHandler.getDistance(event); |
1506 if (distance1 === 0) | 1540 if (distance1 === 0) |
1507 break; | 1541 break; |
1508 var zoom = distance2 / distance1 * this.lastZoom_; | 1542 var zoom = distance2 / distance1 * this.lastZoom_; |
1509 viewport.setZoom(zoom); | 1543 viewport.setZoom(zoom); |
| 1544 |
| 1545 // Pinch rotation. |
| 1546 var angle = TouchHandler.getTwistAngle(this.gestureStartEvent_, event); |
| 1547 if (angle > TouchHandler.ROTATION_THRESHOLD) |
| 1548 viewport.setRotation(this.gestureStartRotation_ + 1); |
| 1549 else if (angle < -TouchHandler.ROTATION_THRESHOLD) |
| 1550 viewport.setRotation(this.gestureStartRotation_ - 1); |
| 1551 else |
| 1552 viewport.setRotation(this.gestureStartRotation_); |
1510 this.slideMode_.applyViewportChange(); | 1553 this.slideMode_.applyViewportChange(); |
1511 break; | 1554 break; |
1512 } | 1555 } |
1513 | 1556 |
1514 // Update the last event. | 1557 // Update the last event. |
1515 this.lastEvent_ = event; | 1558 this.lastEvent_ = event; |
1516 this.lastZoom_ = viewport.getZoom(); | 1559 this.lastZoom_ = viewport.getZoom(); |
1517 }; | 1560 }; |
OLD | NEW |