[Mobile Gestures] Pan

Adds pan gesture to plots. Sets up the
zoom gesture addition. Also the back button
is visible on desktop versions.
This commit is contained in:
Shivam Dave
2015-08-20 11:26:09 -07:00
parent 9fec73da14
commit 1fbbf355f4
6 changed files with 169 additions and 104 deletions

View File

@ -21,7 +21,7 @@
--> -->
<div class='object-header object-header-mobile'> <div class='object-header object-header-mobile'>
<span class="label s-label"> <span class="label s-label">
<mct-representation class="desktop-hide" key="'back-arrow'"></mct-representation> <mct-representation key="'back-arrow'"></mct-representation>
<span class='type-icon icon ui-symbol'>{{type.getGlyph()}}</span> <span class='type-icon icon ui-symbol'>{{type.getGlyph()}}</span>
<span ng-if="parameters.mode" class='action'>{{parameters.mode}}</span> <span ng-if="parameters.mode" class='action'>{{parameters.mode}}</span>
<span class='type-name mobile-important-hide'>{{type.getName()}}</span> <span class='type-name mobile-important-hide'>{{type.getName()}}</span>

View File

@ -119,7 +119,7 @@
* this source code distribution or the Licensing information page available * this source code distribution or the Licensing information page available
* at runtime from the About dialog for additional information. * at runtime from the About dialog for additional information.
*****************************************************************************/ *****************************************************************************/
/* line 5, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ /* line 5, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
html, body, div, span, applet, object, iframe, html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre, h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code, a, abbr, acronym, address, big, cite, code,
@ -140,38 +140,38 @@ time, mark, audio, video {
font-size: 100%; font-size: 100%;
vertical-align: baseline; } vertical-align: baseline; }
/* line 22, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ /* line 22, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
html { html {
line-height: 1; } line-height: 1; }
/* line 24, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ /* line 24, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
ol, ul { ol, ul {
list-style: none; } list-style: none; }
/* line 26, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ /* line 26, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
table { table {
border-collapse: collapse; border-collapse: collapse;
border-spacing: 0; } border-spacing: 0; }
/* line 28, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ /* line 28, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
caption, th, td { caption, th, td {
text-align: left; text-align: left;
font-weight: normal; font-weight: normal;
vertical-align: middle; } vertical-align: middle; }
/* line 30, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ /* line 30, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
q, blockquote { q, blockquote {
quotes: none; } quotes: none; }
/* line 103, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ /* line 103, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
q:before, q:after, blockquote:before, blockquote:after { q:before, q:after, blockquote:before, blockquote:after {
content: ""; content: "";
content: none; } content: none; }
/* line 32, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ /* line 32, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
a img { a img {
border: none; } border: none; }
/* line 116, ../../../../../../../../.gem/ruby/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ /* line 116, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */
article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary {
display: block; } display: block; }
@ -905,54 +905,52 @@ mct-container {
.mobile-important-hide { .mobile-important-hide {
display: none !important; } } display: none !important; } }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) { /* line 189, ../sass/mobile/_layout.scss */
/* line 189, ../sass/mobile/_layout.scss */ .mobile-back-hide {
.mobile-back-hide { pointer-events: none;
pointer-events: none; -moz-transition-property: opacity;
-moz-transition-property: opacity; -o-transition-property: opacity;
-o-transition-property: opacity; -webkit-transition-property: opacity;
-webkit-transition-property: opacity; transition-property: opacity;
transition-property: opacity; -moz-transition-duration: 0.4s;
-moz-transition-duration: 0.4s; -o-transition-duration: 0.4s;
-o-transition-duration: 0.4s; -webkit-transition-duration: 0.4s;
-webkit-transition-duration: 0.4s; transition-duration: 0.4s;
transition-duration: 0.4s; -moz-transition-timing-function: ease-in-out;
-moz-transition-timing-function: ease-in-out; -o-transition-timing-function: ease-in-out;
-o-transition-timing-function: ease-in-out; -webkit-transition-timing-function: ease-in-out;
-webkit-transition-timing-function: ease-in-out; transition-timing-function: ease-in-out;
transition-timing-function: ease-in-out; opacity: 0; }
opacity: 0; } }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) { /* line 196, ../sass/mobile/_layout.scss */
/* line 198, ../sass/mobile/_layout.scss */ .mobile-back-unhide {
.mobile-back-unhide { pointer-events: all;
pointer-events: all; -moz-transition-property: opacity;
-moz-transition-property: opacity; -o-transition-property: opacity;
-o-transition-property: opacity; -webkit-transition-property: opacity;
-webkit-transition-property: opacity; transition-property: opacity;
transition-property: opacity; -moz-transition-duration: 0.4s;
-moz-transition-duration: 0.4s; -o-transition-duration: 0.4s;
-o-transition-duration: 0.4s; -webkit-transition-duration: 0.4s;
-webkit-transition-duration: 0.4s; transition-duration: 0.4s;
transition-duration: 0.4s; -moz-transition-timing-function: ease-in-out;
-moz-transition-timing-function: ease-in-out; -o-transition-timing-function: ease-in-out;
-o-transition-timing-function: ease-in-out; -webkit-transition-timing-function: ease-in-out;
-webkit-transition-timing-function: ease-in-out; transition-timing-function: ease-in-out;
transition-timing-function: ease-in-out; opacity: 1; }
opacity: 1; } }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) { @media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px) {
/* line 207, ../sass/mobile/_layout.scss */ /* line 203, ../sass/mobile/_layout.scss */
.phone-hide { .phone-hide {
display: none; } } display: none; } }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) { @media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
/* line 213, ../sass/mobile/_layout.scss */ /* line 209, ../sass/mobile/_layout.scss */
.tree-holder { .tree-holder {
overflow-x: hidden !important; } } overflow-x: hidden !important; } }
@media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) { @media screen and (orientation: portrait) and (max-width: 514px) and (max-height: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (max-height: 514px) and (max-width: 740px) and (max-device-width: 1024px) and (max-device-height: 799px), screen and (orientation: portrait) and (min-width: 515px) and (max-width: 799px) and (min-height: 741px) and (max-height: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 799px) and (max-device-height: 1024px), screen and (orientation: landscape) and (min-height: 515px) and (max-height: 799px) and (min-width: 741px) and (max-width: 1024px) and (max-device-width: 1024px) and (max-device-height: 799px) {
/* line 218, ../sass/mobile/_layout.scss */ /* line 214, ../sass/mobile/_layout.scss */
.mobile-disable-select { .mobile-disable-select {
-moz-user-select: -moz-none; -moz-user-select: -moz-none;
-ms-user-select: none; -ms-user-select: none;

View File

@ -187,20 +187,16 @@
} }
.mobile-back-hide { .mobile-back-hide {
@include phoneandtablet {
pointer-events: none; pointer-events: none;
@include trans-prop-nice(opacity, .4s); @include trans-prop-nice(opacity, .4s);
opacity: 0; opacity: 0;
}
} }
// Hides objects on phone and tablet // Hides objects on phone and tablet
.mobile-back-unhide { .mobile-back-unhide {
@include phoneandtablet {
pointer-events: all; pointer-events: all;
@include trans-prop-nice(opacity, .4s); @include trans-prop-nice(opacity, .4s);
opacity: 1; opacity: 1;
}
} }
// Hides objects only on the phone // Hides objects only on the phone

View File

@ -154,18 +154,6 @@ define(
}; };
} }
function onPinchStart(event) {
console.log("Pinch Start");
}
function onPinchChange(event) {
console.log("Pinch Change");
}
function onPinchEnd(event) {
console.log("Pinch End");
}
function followDataIfLive() { function followDataIfLive() {
if (isLive) { if (isLive) {
$scope.viewport = viewportForMaxDomain(); $scope.viewport = viewportForMaxDomain();
@ -175,9 +163,6 @@ define(
$scope.$on('series:data:add', followDataIfLive); $scope.$on('series:data:add', followDataIfLive);
$scope.$on('user:viewport:change:end', onUserViewportChangeEnd); $scope.$on('user:viewport:change:end', onUserViewportChangeEnd);
$scope.$on('user:viewport:change:start', onUserViewportChangeStart); $scope.$on('user:viewport:change:start', onUserViewportChangeStart);
$scope.$on('mct:pinch:start', onPinchStart);
$scope.$on('mct:pinch:change', onPinchChange);
$scope.$on('mct:pinch:end', onPinchEnd);
$scope.$watch('domainObject', linkDomainObject); $scope.$watch('domainObject', linkDomainObject);

View File

@ -29,32 +29,43 @@ define(
function MCTPinch($log, agentService) { function MCTPinch($log, agentService) {
function link($scope, element, attrs) { function link($scope, element, attrs) {
var posPrev,
evePrev;
// Returns position of touch event // Returns position of touch event
function trackPosition(event) { function trackPosition(event) {
return [event.clientX, event.clientY]; return {
clientX: event.clientX,
clientY: event.clientY
};
} }
function calculateMidpoint(coordOne, coordTwo) {
return {
clientX: (coordOne.clientX + coordTwo.clientX) / 2,
clientY: (coordOne.clientY + coordTwo.clientY) / 2
};
}
function calculateDistance(coordOne, coordTwo) {
return Math.sqrt(Math.pow(coordOne.clientX - coordTwo.clientX, 2) +
Math.pow(coordOne.clientY - coordTwo.clientY, 2));
}
// On touch start the 'touch' is tracked and // On touch start the 'touch' is tracked and
// the event is emitted through scope // the event is emitted through scope
function pinchStart(event) { function pinchStart(event) {
if (event.changedTouches.length === 2 || if (event.changedTouches.length === 2 ||
event.touches.length === 2) { event.touches.length === 2) {
var touchPosition = [trackPosition(event.touches[0]), var touchPositions = [trackPosition(event.touches[0]),
trackPosition(event.touches[1])], trackPosition(event.touches[1])];
touchPositionPrev = posPrev || touchPosition,
eventPrev = evePrev || event;
$scope.$emit('mct:pinch:start'); $scope.$emit('mct:pinch:start', {
// Set current position to be previous position touches: touchPositions,
// for next touch action bounds: event.target.getBoundingClientRect(),
posPrev = touchPosition; midpoint: calculateMidpoint(touchPositions[0], touchPositions[1]),
distance: calculateDistance(touchPositions[0], touchPositions[1])
// Set current event to be previous event });
// for next touch action
evePrev = event;
// Stops other gestures/button clicks from being active // Stops other gestures/button clicks from being active
event.preventDefault(); event.preventDefault();
@ -66,18 +77,14 @@ define(
function pinchChange(event) { function pinchChange(event) {
if (event.changedTouches.length === 2) { if (event.changedTouches.length === 2) {
var touchPosition = [trackPosition(event.changedTouches[0]), var touchPosition = [trackPosition(event.changedTouches[0]),
trackPosition(event.changedTouches[1])], trackPosition(event.changedTouches[1])];
touchPositionPrev = posPrev || touchPosition,
eventPrev = evePrev || event;
$scope.$emit('mct:pinch:change'); $scope.$emit('mct:pinch:change', {
// Set current position to be previous position touches: touchPosition,
// for next touch action bounds: event.target.getBoundingClientRect(),
posPrev = touchPosition; midpoint: calculateMidpoint(touchPosition[0], touchPosition[1]),
distance: calculateDistance(touchPosition[0], touchPosition[1])
// Set current event to be previous event });
// for next touch action
evePrev = event;
// Stops other gestures/button clicks from being active // Stops other gestures/button clicks from being active
event.preventDefault(); event.preventDefault();
@ -87,10 +94,10 @@ define(
// On the 'touchend' or 'touchcancel' the event // On the 'touchend' or 'touchcancel' the event
// is emitted through scope // is emitted through scope
function pinchEnd(event) { function pinchEnd(event) {
$scope.$emit('mct:pinch:end'); $scope.$emit('mct:pinch:end');
// Stops other gestures/button clicks from being active // Stops other gestures/button clicks from being active
event.preventDefault(); event.preventDefault();
} }
if (agentService.isMobile(navigator.userAgent)) { if (agentService.isMobile(navigator.userAgent)) {

View File

@ -39,16 +39,18 @@ define(
}; };
} }
var dragStart, var dragStart,
marqueeBox = {}, marqueeBox = {},
marqueeRect, // Set when exists. marqueeRect, // Set when exists.
chartElementBounds, chartElementBounds,
firstTouches,
firstTouchDistance,
firstTouchPan,
$canvas = $element.find('canvas'); $canvas = $element.find('canvas');
function updateAxesForCurrentViewport() { function updateAxesForCurrentViewport() {
// Update axes definitions for current viewport. // Update axes definitions for current viewport.
['domain', 'range'].forEach(function(axisName) { ['domain', 'range'].forEach(function (axisName) {
var axis = $scope.axes[axisName], var axis = $scope.axes[axisName],
firstTick = $scope.viewport.topLeft[axisName], firstTick = $scope.viewport.topLeft[axisName],
lastTick = $scope.viewport.bottomRight[axisName], lastTick = $scope.viewport.bottomRight[axisName],
@ -60,7 +62,7 @@ define(
// Yes, ticksize is negative for domain and positive for range. // Yes, ticksize is negative for domain and positive for range.
// It's because ticks are generated/displayed top to bottom and left to right. // It's because ticks are generated/displayed top to bottom and left to right.
axis.ticks = []; axis.ticks = [];
for (tickNumber = 0; tickNumber < axis.tickCount; tickNumber++) { for (tickNumber = 0; tickNumber < axis.tickCount; tickNumber = tickNumber + 1) {
tickIncrement = (axisSize * (tickNumber / denominator)); tickIncrement = (axisSize * (tickNumber / denominator));
tickValue = firstTick - tickIncrement; tickValue = firstTick - tickIncrement;
axis.ticks.push( axis.ticks.push(
@ -148,6 +150,32 @@ define(
$scope.$emit('user:viewport:change:end', $scope.viewport); $scope.$emit('user:viewport:change:end', $scope.viewport);
} }
function trackTouchPosition(touchPosition, bounds) {
var positionOverElement,
positionAsPlotPoint,
position;
chartElementBounds = bounds;
positionOverElement = {
x: touchPosition.clientX - bounds.left,
y: touchPosition.clientY - bounds.top
};
positionAsPlotPoint = utils.elementPositionAsPlotPosition(
positionOverElement,
bounds,
$scope.viewport
);
position = {
positionOverElement: positionOverElement,
positionAsPlotPoint: positionAsPlotPoint
};
return position;
}
function trackMousePosition($event) { function trackMousePosition($event) {
// Calculate coordinates of mouse related to canvas and as // Calculate coordinates of mouse related to canvas and as
// domain, range value and make available in scope for display. // domain, range value and make available in scope for display.
@ -158,6 +186,7 @@ define(
chartElementBounds = bounds; chartElementBounds = bounds;
positionOverElement = { positionOverElement = {
x: $event.clientX - bounds.left, x: $event.clientX - bounds.left,
y: $event.clientY - bounds.top y: $event.clientY - bounds.top
@ -202,13 +231,13 @@ define(
} }
function toggleInteractionMode(event) { function toggleInteractionMode(event) {
if (event.keyCode === '18') { // control key. if (event.keyCode === 16) { // shift key.
watchForDrag(); watchForDrag();
} }
} }
function resetInteractionMode(event) { function resetInteractionMode(event) {
if (event.keyCode === '18') { if (event.keyCode === 16) {
watchForMarquee(); watchForMarquee();
} }
} }
@ -242,10 +271,60 @@ define(
updateAxesForCurrentViewport(); updateAxesForCurrentViewport();
} }
function calculateDistanceChange(startDist, currDist) {
return startDist / currDist;
}
function updateZoom(midpoint, bounds, touches, distance) {
// calculate offset between points. Apply that offset to viewport.
var midpointPosition = trackTouchPosition(midpoint, bounds),
newPosition = midpointPosition.positionAsPlotPoint,
dDomain = firstTouchPan.domain - newPosition.domain,
dRange = firstTouchPan.range - newPosition.range;
$scope.viewport = {
topLeft: {
domain: $scope.viewport.topLeft.domain + dDomain,
range: $scope.viewport.topLeft.range + dRange
},
bottomRight: {
domain: $scope.viewport.bottomRight.domain + dDomain,
range: $scope.viewport.bottomRight.range + dRange
}
};
}
function startZoom(midpoint, bounds, touches, distance) {
$scope.$emit('user:viewport:change:start');
firstTouches = touches;
firstTouchDistance = distance;
firstTouchPan = trackTouchPosition(midpoint, bounds).positionAsPlotPoint;
}
function endZoom() {
$scope.$emit('user:viewport:change:end', $scope.viewport);
}
function onPinchStart(event, touch) {
startZoom(touch.midpoint, touch.bounds, touch.touches, touch.distance);
}
function onPinchChange(event, touch) {
updateZoom(touch.midpoint, touch.bounds, touch.touches, touch.distance);
}
function onPinchEnd(event) {
endZoom();
}
$scope.$watchCollection('viewport', onViewportChange); $scope.$watchCollection('viewport', onViewportChange);
$scope.$on('$destroy', stopWatching); $scope.$on('mct:pinch:start', onPinchStart);
$scope.$on('mct:pinch:change', onPinchChange);
$scope.$on('mct:pinch:end', onPinchEnd);
$scope.$on('$destroy', stopWatching);
} }
return { return {