')
+ .find('#test-container');
+ options = {
+ xaxes: [{ autoScale: 'exact' }],
+ yaxes: [{ autoScale: 'exact' }],
+ zoom: { interactive: true, amount: 10, active: true },
+ pan: { interactive: true, frameRate: -1, enableTouch: true, active: true }
+ };
+ });
+
+ it('shows that the eventHolder is cleared through shutdown when the plot is replaced', function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventPlaceholder = plot.getEventHolder();
+ spy = spyOn(eventPlaceholder, 'removeEventListener').and.callThrough();
+
+ plot = $.plot(placeholder, [[]], options);
+
+ expect(spy).toHaveBeenCalledWith('touchstart', jasmine.any(Function))
+ expect(spy).toHaveBeenCalledWith('touchmove', jasmine.any(Function));
+ expect(spy).toHaveBeenCalledWith('touchend', jasmine.any(Function));
+ });
+
+ it('do not stop origin touch event propagation if it is allowed', () => {
+ jasmine.clock().install().mockDate();
+
+ var oldPropagateSupportedGesture = options.propagateSupportedGesture ;
+ options.propagateSupportedGesture = true;
+
+ plot = $.plot(placeholder, [[]], options);
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('origin touch event handler');
+
+ eventHolder.parentNode.addEventListener('touchstart', spy, { once: true });
+ eventHolder.parentNode.addEventListener('touchmove', spy, { once: true });
+ eventHolder.parentNode.addEventListener('touchend', spy, { once: true });
+
+ var bubbleTouchEvents = [
+ new UIEvent('touchstart', { bubbles: true }),
+ new UIEvent('touchmove', { bubbles: true }),
+ new UIEvent('touchend', { bubbles: true }),
+ ];
+ bubbleTouchEvents.forEach((event) => {
+ event.touches = [{ identifier: 0, target: eventHolder }];
+ eventHolder.dispatchEvent(event);
+ });
+
+ expect(spy).toHaveBeenCalledTimes(3);
+
+ options.propagateSupportedGesture = oldPropagateSupportedGesture;
+ jasmine.clock().uninstall();
+ });
+
+ describe('long tap', function() {
+
+ beforeEach(function() {
+ jasmine.clock().install().mockDate();
+ });
+
+ afterEach(function() {
+ jasmine.clock().uninstall();
+ });
+
+ it('should trigger the long tap event',function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('long tap handler'),
+ coords = [{x: 10, y: 20}];
+
+ eventHolder.addEventListener('longtap', spy);
+
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+ jasmine.clock().tick(1600);
+ jasmine.clock().tick(1600);
+ jasmine.clock().tick(1600);
+
+ expect(spy).toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(1);
+ });
+
+ it('should trigger the long tap event even when there is a small move of the touch point',function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('long tap handler'),
+ initialCoords = [{x: 10, y: 20}],
+ finalCoords = [{x: 11, y: 21}];
+
+ eventHolder.addEventListener('longtap', spy);
+
+ simulate.sendTouchEvents(initialCoords, eventHolder, 'touchstart');
+ simulate.sendTouchEvents(finalCoords, eventHolder, 'touchmove');
+ jasmine.clock().tick(1600);
+
+ expect(spy).toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(1);
+ });
+
+ it('should not trigger the long tap event when there is a large move of the touch point',function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('long tap handler'),
+ initialCoords = [{x: 10, y: 20}],
+ finalCoords = [{x: 100, y: 200}];
+
+ eventHolder.addEventListener('longtap', spy);
+
+ simulate.sendTouchEvents(initialCoords, eventHolder, 'touchstart');
+ simulate.sendTouchEvents(finalCoords, eventHolder, 'touchmove');
+ jasmine.clock().tick(1600);
+
+ expect(spy).not.toHaveBeenCalled();
+ });
+
+ it('should not trigger the long tap event when the touch ends too soon',function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('long tap handler'),
+ coords = [{x: 10, y: 20}];
+
+ eventHolder.addEventListener('longtap', spy);
+
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+ jasmine.clock().tick(1400);
+ simulate.sendTouchEvents(coords, eventHolder, 'touchend');
+ jasmine.clock().tick(200);
+
+ expect(spy).not.toHaveBeenCalled();
+ });
+
+ it('should not trigger the long tap event when the plot is replaced', function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('long tap handler'),
+ coords = [{x: 10, y: 20}];
+
+ eventHolder.addEventListener('longtap', spy);
+
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+ plot = $.plot(placeholder, [[]], options);
+ jasmine.clock().tick(1600);
+
+ expect(spy).not.toHaveBeenCalled();
+ });
+
+ it('should trigger multiple long tap events',function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('long tap handler'),
+ coords = [{x: 10, y: 20}];
+
+ eventHolder.addEventListener('longtap', spy);
+
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+ jasmine.clock().tick(1600);
+ simulate.sendTouchEvents(coords, eventHolder, 'touchend');
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+ jasmine.clock().tick(1600);
+ simulate.sendTouchEvents(coords, eventHolder, 'touchend');
+
+ expect(spy).toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(2);
+ });
+ });
+
+ describe('pinch', function() {
+
+ beforeEach(function() {
+ jasmine.clock().install().mockDate();
+ });
+
+ afterEach(function() {
+ jasmine.clock().uninstall();
+ });
+
+ it('should be able to trigger pinchstart event',function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('pinch handler'),
+ coords = [{x: 10, y: 20}, {x: 15, y: 20}];
+
+ eventHolder.addEventListener('pinchstart', spy);
+
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+
+ expect(spy).toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(1);
+ });
+
+ it('should not trigger pinch event for plot not active',function() {
+ plot = $.plot(placeholder, [
+ [
+ [0, 0],
+ [10, 10]
+ ]
+ ], {
+ xaxes: [{ autoScale: 'exact' }],
+ yaxes: [{ autoScale: 'exact' }],
+ zoom: { interactive: true, active: false, amount: 10 },
+ pan: { interactive: true, active: false, frameRate: -1 }
+ });
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('pinch handler'),
+ coords = [{x: 10, y: 20}, {x: 15, y: 20}];
+
+ eventHolder.addEventListener('pinchstart', spy);
+
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+
+ expect(spy).not.toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(0);
+ });
+
+ it('should not trigger pinch event for only one touch',function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('pinch handler'),
+ coords = [{x: 10, y: 20}];
+
+ eventHolder.addEventListener('pinchstart', spy);
+
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+
+ expect(spy).not.toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(0);
+ });
+
+ it('should not trigger pinch event for touch outside plot',function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ mockEventHolder = {},
+ spy = jasmine.createSpy('pinch handler'),
+ coords = [{x: 10, y: 20}, {x: 15, y: 20}];
+
+ eventHolder.addEventListener('pinchstart', spy);
+
+ mockEventHolder.dispatchEvent = function() {};
+
+ simulate.sendTouchEvents(coords, mockEventHolder, 'touchstart');
+
+ expect(spy).not.toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(0);
+ });
+
+ it('allows default propagation for three touches',function() {
+ plot = $.plot(placeholder, [], options);
+
+ var eventHolder = plot.getEventHolder(),
+ touchCoords = [{pageX: 10, pageY: 20}, {pageX: 15, pageY: 20}, {pageX: 20, pageY: 25}],
+ touchStartEvent = new CustomEvent('touchstart'),
+ touchMoveEvent = new CustomEvent('touchmove');
+
+ touchStartEvent.touches = touchCoords;
+ touchStartEvent.preventDefault = jasmine.createSpy();
+ touchMoveEvent.touches = touchCoords;
+ touchMoveEvent.preventDefault = jasmine.createSpy();
+
+ eventHolder.dispatchEvent(touchStartEvent);
+ eventHolder.dispatchEvent(touchMoveEvent);
+
+ expect(touchStartEvent.preventDefault).not.toHaveBeenCalled();
+ expect(touchMoveEvent.preventDefault).not.toHaveBeenCalled();
+
+ });
+ });
+
+ describe('pan', function() {
+
+ beforeEach(function() {
+ jasmine.clock().install().mockDate();
+ });
+
+ afterEach(function() {
+ jasmine.clock().uninstall();
+ });
+
+ it('should be able to trigger pan event',function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('pan handler'),
+ coords = [{x: 10, y: 20}];
+
+ eventHolder.addEventListener('pan', spy);
+
+ simulate.sendTouchEvents(coords, eventHolder, 'pan');
+
+ expect(spy).toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(1);
+ });
+
+ it('should not trigger pan event for plot not active',function() {
+ plot = $.plot(placeholder, [
+ [
+ [0, 0],
+ [10, 10]
+ ]
+ ], {
+ xaxes: [{ autoScale: 'exact' }],
+ yaxes: [{ autoScale: 'exact' }],
+ zoom: { interactive: true, active: false, amount: 10 },
+ pan: { interactive: true, active: false, frameRate: -1 }
+ });
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('pan handler'),
+ coords = [{x: 10, y: 20}];
+
+ eventHolder.addEventListener('pan', spy);
+
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+
+ expect(spy).not.toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(0);
+ });
+
+ it('should not trigger pan event for touch outside plot',function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ mockEventHolder = {},
+ spy = jasmine.createSpy('pan handler'),
+ coords = [{x: 10, y: 20}];
+
+ eventHolder.addEventListener('panstart', spy);
+
+ mockEventHolder.dispatchEvent = function() {};
+
+ simulate.sendTouchEvents(coords, mockEventHolder, 'touchstart');
+
+ expect(spy).not.toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(0);
+ });
+ });
+
+ describe('doubletap', function() {
+
+ beforeEach(function() {
+ jasmine.clock().install().mockDate();
+ });
+
+ afterEach(function() {
+ jasmine.clock().uninstall();
+ });
+
+ it('should trigger the double tap event', function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('double tap handler'),
+ coords = [{x: 10, y: 20}];
+
+ eventHolder.addEventListener('doubletap', spy);
+
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+ jasmine.clock().tick(200);
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+
+ expect(spy).toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(1);
+ });
+
+ it('should trigger the double tap event even when there is a different touch point', function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('double tap handler'),
+ initialCoords = [{x: 10, y: 20}],
+ finalCoords = [{x: 11, y: 21}];
+
+ eventHolder.addEventListener('doubletap', spy);
+
+ simulate.sendTouchEvents(initialCoords, eventHolder, 'touchstart');
+ jasmine.clock().tick(300);
+ simulate.sendTouchEvents(finalCoords, eventHolder, 'touchstart');
+
+ expect(spy).toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(1);
+ });
+
+ it('should not trigger the double tap event for a big interval between taps', function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('double tap handler'),
+ coords = [{x: 10, y: 20}];
+
+ eventHolder.addEventListener('doubletap', spy);
+
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+ jasmine.clock().tick(1000);
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+
+ expect(spy).not.toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(0);
+ });
+
+ it('should not trigger the double tap event for one of the touches outside plot area', function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ mockEventHolder = {},
+ spy = jasmine.createSpy('double tap handler'),
+ initialCoords = [{x: 10, y: 20}],
+ finalCoords = [{x: 100, y: 200}];
+
+ mockEventHolder.dispatchEvent = function() {};
+
+ eventHolder.addEventListener('doubletap', spy);
+
+ simulate.sendTouchEvents(initialCoords, eventHolder, 'touchstart');
+ jasmine.clock().tick(100);
+ simulate.sendTouchEvents(finalCoords, mockEventHolder, 'touchmove');
+
+ expect(spy).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('tap', function() {
+
+ beforeEach(function() {
+ jasmine.clock().install().mockDate();
+ });
+
+ afterEach(function() {
+ jasmine.clock().uninstall();
+ });
+
+ it('should trigger the tap event', function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('tap handler'),
+ coords = [{x: 10, y: 20}];
+
+ eventHolder.addEventListener('tap', spy);
+
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+ jasmine.clock().tick(50);
+ simulate.sendTouchEvents(coords, eventHolder, 'touchend');
+
+ expect(spy).toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(1);
+ });
+
+ it('should trigger the tap event even when there is a different touch point', function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('tap handler'),
+ initialCoords = [{x: 10, y: 20}],
+ finalCoords = [{x: 11, y: 21}];
+
+ eventHolder.addEventListener('tap', spy);
+
+ simulate.sendTouchEvents(initialCoords, eventHolder, 'touchstart');
+ jasmine.clock().tick(50);
+ simulate.sendTouchEvents(finalCoords, eventHolder, 'touchend');
+
+ expect(spy).toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(1);
+ });
+
+ it('should not trigger the tap event for a big interval between taps', function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('tap handler'),
+ coords = [{x: 10, y: 20}];
+
+ eventHolder.addEventListener('tap', spy);
+
+ simulate.sendTouchEvents(coords, eventHolder, 'touchstart');
+ jasmine.clock().tick(200);
+ simulate.sendTouchEvents(coords, eventHolder, 'touchend');
+
+ expect(spy).not.toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(0);
+ });
+
+ it('should not trigger the tap event for a big interval between taps', function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventHolder = plot.getEventHolder(),
+ spy = jasmine.createSpy('tap handler'),
+ initalCoords = [{x: 10, y: 20}],
+ moveCoords = [{x: 30, y: 60}];;
+
+ eventHolder.addEventListener('tap', spy);
+
+ simulate.sendTouchEvents(initalCoords, eventHolder, 'touchstart');
+ simulate.sendTouchEvents(moveCoords, eventHolder, 'touchmove');
+ jasmine.clock().tick(30);
+ simulate.sendTouchEvents(moveCoords, eventHolder, 'touchend');
+
+ expect(spy).not.toHaveBeenCalled();
+ expect(spy.calls.count()).toBe(0);
+ });
+ });
+});
diff --git a/tests/jquery.flot.touchNavigate.Test.js b/tests/jquery.flot.touchNavigate.Test.js
new file mode 100644
index 000000000..6bac9d79d
--- /dev/null
+++ b/tests/jquery.flot.touchNavigate.Test.js
@@ -0,0 +1,1253 @@
+/* eslint-disable */
+/* global $, describe, it, xit, xdescribe, after, afterEach, expect*/
+
+describe("flot touch navigate plugin", function () {
+ var placeholder, plot, options;
+ var minFrameDuration = 1 / 60 * 1000;
+
+ beforeEach(function () {
+ placeholder = setFixtures('
')
+ .find('#test-container');
+ options = {
+ xaxes: [{ autoScale: 'exact' }],
+ yaxes: [{ autoScale: 'exact' }],
+ zoom: { interactive: true, active: true, amount: 10, enableTouch: true },
+ pan: { interactive: true, active: true, frameRate: -1, enableTouch: true }
+ };
+ jasmine.clock().install();
+ });
+
+ afterEach(function() {
+ jasmine.clock().uninstall();
+ });
+
+ it('shows that the eventHolder is cleared through shutdown when the plot is replaced', function() {
+ plot = $.plot(placeholder, [[]], options);
+
+ var eventPlaceholder = plot.getEventHolder(),
+ spy = spyOn(eventPlaceholder, 'removeEventListener').and.callThrough();
+
+ plot = $.plot(placeholder, [[]], options);
+
+ expect(spy).toHaveBeenCalledWith('panstart', jasmine.any(Function))
+ expect(spy).toHaveBeenCalledWith('pandrag', jasmine.any(Function));
+ expect(spy).toHaveBeenCalledWith('panend', jasmine.any(Function));
+ });
+
+ var simulateTouchEvent = function (coords, eventHolder, eventName) {
+ simulate.sendTouchEvents(coords, eventHolder, eventName);
+ jasmine.clock().tick(minFrameDuration);
+ }
+
+ describe('touchZoom', function() {
+ it('should zoom the plot',function() {
+ plot = $.plot(placeholder, [
+ [
+ [-1, 2],
+ [11, 12]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ initialCoords = [
+ getPairOfCoords(xaxis, yaxis, 3, 5),
+ getPairOfCoords(xaxis, yaxis, 7, 9)
+ ],
+ finalCoords = [
+ getPairOfCoords(xaxis, yaxis, 2, 4),
+ getPairOfCoords(xaxis, yaxis, 8, 10)
+ ],
+ midPointCoords = {
+ x: (xaxis.c2p(finalCoords[0].x - plot.offset().left) + xaxis.c2p(finalCoords[1].x - plot.offset().left)) / 2,
+ y: (yaxis.c2p(finalCoords[0].y - plot.offset().top) + yaxis.c2p(finalCoords[1].y - plot.offset().top)) / 2
+ },
+ amount = getDistance(finalCoords) / getDistance(initialCoords);
+
+ simulateTouchEvent(initialCoords, eventHolder, 'touchstart');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchmove');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchend');
+
+ expect(xaxis.min).toBeCloseTo((midPointCoords.x - initialXmin) * (1 - 1/amount) + initialXmin, 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax - (initialXmax - midPointCoords.x) * (1 - 1/amount), 6);
+ expect(yaxis.min).toBeCloseTo((midPointCoords.y - initialYmin) * (1 - 1/amount) + initialYmin, 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax - (initialYmax - midPointCoords.y) * (1 - 1/amount), 6);
+ });
+
+ it('should pan the plot for two fingers with constant distance',function() {
+ plot = $.plot(placeholder, [
+ [
+ [-1, 2],
+ [11, 12]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 3, y : 5 }, { x : 7, y : 9 }, { x : 2, y : 4 }, { x : 6, y : 8 }],
+ initialCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y)
+ ],
+ finalCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[2].x, canvasCoords[2].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[3].x, canvasCoords[3].y)
+ ];
+
+ simulateTouchEvent(initialCoords, eventHolder, 'touchstart');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchmove');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchend');
+
+ expect(xaxis.min).toBeCloseTo(initialXmin + (canvasCoords[0].x - canvasCoords[2].x), 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax + (canvasCoords[0].x - canvasCoords[2].x), 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin + (canvasCoords[0].y - canvasCoords[2].y), 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax + (canvasCoords[0].y - canvasCoords[2].y), 6);
+ });
+
+ it('should not zoom the plot for two fingers with small distance variation',function() {
+ plot = $.plot(placeholder, [
+ [
+ [-1, 2],
+ [11, 12]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 3, y : 5 }, { x : 7, y : 8.999 }, { x : 2, y : 4 }, { x : 6.001, y : 8 }],
+ initialCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y)
+ ],
+ finalCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[2].x, canvasCoords[2].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[3].x, canvasCoords[3].y)
+ ];
+
+ var spy = spyOn(plot, 'zoom').and.callThrough();
+
+ simulateTouchEvent(initialCoords, eventHolder, 'touchstart');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchmove');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchend');
+
+ expect(spy).not.toHaveBeenCalled();
+ });
+
+ it('should zoom the plot correctly using pageXY when the canvas is placed in the bottom scrollable area of the page', function () {
+ var largeDiv = $('
');
+ $(largeDiv).insertBefore(placeholder);
+
+ plot = $.plot(placeholder, [
+ [
+ [-1, 2],
+ [11, 12]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ initialCoords = [
+ getPairOfCoords(xaxis, yaxis, 3, 5),
+ getPairOfCoords(xaxis, yaxis, 7, 9)
+ ],
+ finalCoords = [
+ getPairOfCoords(xaxis, yaxis, 2, 4),
+ getPairOfCoords(xaxis, yaxis, 8, 10)
+ ],
+ midPointCoords = {
+ x: (xaxis.c2p(finalCoords[0].x - plot.offset().left) + xaxis.c2p(finalCoords[1].x - plot.offset().left)) / 2,
+ y: (yaxis.c2p(finalCoords[0].y - plot.offset().top) + yaxis.c2p(finalCoords[1].y - plot.offset().top)) / 2
+ },
+ amount = getDistance(finalCoords) / getDistance(initialCoords);
+
+ simulateTouchEvent(initialCoords, plot.getEventHolder(), 'touchstart');
+ simulateTouchEvent(finalCoords, plot.getEventHolder(), 'touchmove');
+ simulateTouchEvent(finalCoords, plot.getEventHolder(), 'touchend');
+
+ expect(xaxis.min).toBeCloseTo((midPointCoords.x - initialXmin) * (1 - 1/amount) + initialXmin, 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax - (initialXmax - midPointCoords.x) * (1 - 1/amount), 6);
+ expect(yaxis.min).toBeCloseTo((midPointCoords.y - initialYmin) * (1 - 1/amount) + initialYmin, 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax - (initialYmax - midPointCoords.y) * (1 - 1/amount), 6);
+ });
+
+ it('should zoom the entire plot for touches not on the same axis',function() {
+ plot = $.plot(placeholder, [
+ [
+ [-1, 2],
+ [11, 12]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ initialCoords = [
+ { x: xaxis.p2c(4), y: xaxis.box.top + plot.offset().top + 10 },
+ { x: xaxis.p2c(5), y: xaxis.box.top + plot.offset().top - 10 }
+ ],
+ finalCoords = [
+ getPairOfCoords(xaxis, yaxis, 2, 4),
+ getPairOfCoords(xaxis, yaxis, 6, 6)
+ ],
+ midPointCoords = {
+ x: (xaxis.c2p(finalCoords[0].x - plot.offset().left) + xaxis.c2p(finalCoords[1].x - plot.offset().left)) / 2,
+ y: (yaxis.c2p(finalCoords[0].y - plot.offset().top) + yaxis.c2p(finalCoords[1].y - plot.offset().top)) / 2
+ },
+ amount = getDistance(finalCoords) / getDistance(initialCoords);
+
+ simulateTouchEvent(initialCoords, eventHolder, 'touchstart');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchmove');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchend');
+
+ expect(xaxis.min).not.toBeCloseTo(initialYmin, 6);
+ expect(xaxis.max).not.toBeCloseTo(initialYmax, 6);
+ expect(yaxis.min).not.toBeCloseTo(initialYmin, 6);
+ expect(yaxis.max).not.toBeCloseTo(initialYmax, 6);
+ });
+
+ it('should zoom the plot on axis x',function() {
+ plot = $.plot(placeholder, [
+ [
+ [-1, 2],
+ [11, 12]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ initialCoords = [
+ { x: xaxis.p2c(4), y: xaxis.box.top + plot.offset().top + 10 },
+ { x: xaxis.p2c(5), y: xaxis.box.top + plot.offset().top + 10 }
+ ],
+ finalCoords = [
+ getPairOfCoords(xaxis, yaxis, 2, 4),
+ getPairOfCoords(xaxis, yaxis, 6, 6)
+ ],
+ midPointCoords = {
+ x: (xaxis.c2p(finalCoords[0].x - plot.offset().left) + xaxis.c2p(finalCoords[1].x - plot.offset().left)) / 2,
+ y: (yaxis.c2p(finalCoords[0].y - plot.offset().top) + yaxis.c2p(finalCoords[1].y - plot.offset().top)) / 2
+ },
+ amount = getDistance(finalCoords) / getDistance(initialCoords);
+
+ simulateTouchEvent(initialCoords, eventHolder, 'touchstart');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchmove');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchend');
+
+ expect(Math.abs(xaxis.min - ((midPointCoords.x - initialXmin) * (1 - 1/amount) + initialXmin))).toBeLessThan(1);
+ expect(Math.abs(xaxis.max - (initialXmax - (initialXmax - midPointCoords.x) * (1 - 1/amount)))).toBeLessThan(1);
+ expect(yaxis.min).toBeCloseTo(initialYmin, 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax, 6);
+ });
+
+ it('should zoom the plot on axis y',function() {
+ plot = $.plot(placeholder, [
+ [
+ [-1, 2],
+ [11, 12]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ initialCoords = [
+ { x: xaxis.box.left - 10, y: yaxis.p2c(4) + plot.offset().top},
+ { x: xaxis.box.left - 11, y: yaxis.p2c(5) + plot.offset().top}
+ ],
+ finalCoords = [
+ getPairOfCoords(xaxis, yaxis, 2, 4),
+ getPairOfCoords(xaxis, yaxis, 6, 6)
+ ],
+ midPointCoords = {
+ x: (xaxis.c2p(finalCoords[0].x - plot.offset().left) + xaxis.c2p(finalCoords[1].x - plot.offset().left)) / 2,
+ y: (yaxis.c2p(finalCoords[0].y - plot.offset().top) + yaxis.c2p(finalCoords[1].y - plot.offset().top)) / 2
+ },
+ amount = getDistance(finalCoords) / getDistance(initialCoords);
+
+ simulateTouchEvent(initialCoords, eventHolder, 'touchstart');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchmove');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchend');
+
+ expect(xaxis.min).toBeCloseTo(initialXmin, 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax, 6);
+ expect(Math.abs(yaxis.min - ((midPointCoords.y - initialYmin) * (1 - 1/amount) + initialYmin))).toBeLessThan(1);
+ expect(Math.abs(yaxis.max - (initialYmax - (initialYmax - midPointCoords.x) * (1 - 1/amount)))).toBeLessThan(1);
+ });
+
+ it('should not zoom the plot on axis for axis zoom not enabled',function() {
+ plot = $.plot(placeholder, [
+ [
+ [0, 0],
+ [10, 10]
+ ]
+ ], {
+ xaxes: [{ autoScale: 'exact', axisZoom: false, axisPan: false }],
+ yaxes: [{ autoScale: 'exact' }],
+ zoom: { interactive: true, active: true, amount: 10 },
+ pan: { interactive: true, active: true, frameRate: -1, enableTouch: true }
+ });
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialCoords = [
+ { x: xaxis.p2c(4), y: xaxis.box.top + plot.offset().top + 10 },
+ { x: xaxis.p2c(5), y: xaxis.box.top + plot.offset().top + 10 }
+ ],
+ finalCoords = [
+ getPairOfCoords(xaxis, yaxis, 2, 4),
+ getPairOfCoords(xaxis, yaxis, 6, 6)
+ ],
+ amount = getDistance(finalCoords) / getDistance(initialCoords);
+
+ simulateTouchEvent(initialCoords, eventHolder, 'touchstart');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchmove');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchend');
+
+ expect(xaxis.min).toBe(0);
+ expect(xaxis.max).toBe(10);
+ expect(yaxis.min).toBe(0);
+ expect(yaxis.max).toBe(10);
+ });
+
+ it('should not zoom the axis for plot zoom not enabled',function() {
+ plot = $.plot(placeholder, [
+ [
+ [0, 0],
+ [10, 10]
+ ]
+ ], {
+ xaxes: [{ autoScale: 'exact', plotZoom: false, plotPan: false }],
+ yaxes: [{ autoScale: 'exact' }],
+ zoom: { interactive: true, active: true, amount: 10, enableTouch: true },
+ pan: { interactive: true, active: true, frameRate: -1, enableTouch: true }
+ });
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialCoords = [
+ { x: 0, y: 10 },
+ { x: 1, y: 50 }
+ ],
+ finalCoords = [
+ getPairOfCoords(xaxis, yaxis, 2, 4),
+ getPairOfCoords(xaxis, yaxis, 6, 6)
+ ],
+ amount = getDistance(finalCoords) / getDistance(initialCoords);
+
+ simulateTouchEvent(initialCoords, eventHolder, 'touchstart');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchmove');
+ simulateTouchEvent(finalCoords, eventHolder, 'touchend');
+
+ expect(xaxis.min).toBe(0);
+ expect(xaxis.max).toBe(10);
+ expect(yaxis.min).not.toBe(0);
+ expect(yaxis.max).not.toBe(10);
+ });
+
+ function getDistance(coords) {
+ return Math.sqrt((coords[0].x - coords[1].x) * (coords[0].x - coords[1].x) + ((coords[0].y - coords[1].y) * (coords[0].y - coords[1].y)));
+ }
+ });
+
+ describe('touchDrag', function() {
+ it('should drag the plot',function() {
+
+ plot = $.plot(placeholder, [
+ [
+ [-10, -10],
+ [120, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 1, y : 1 }, { x : 100, y : 100 }],
+ pointCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y)
+ ];
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulateTouchEvent([], eventHolder, 'touchend'); // it can correctly trigger panend event.
+
+ expect(xaxis.min).toBeCloseTo(initialXmin + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ });
+
+ it('should snap horizontal drag to x direction in smart pan mode', function() {
+ var oldTouchMode = options.pan.touchMode;
+ options.pan.touchMode = 'smart';
+
+ plot = $.plot(placeholder, [
+ [
+ [-10, -10],
+ [120, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0];
+
+ var initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 1, y : 1 }, { x : 100, y : 2 }],
+ pointCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y)
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulateTouchEvent([], eventHolder, 'touchend'); // it can correctly trigger panend event.
+
+ expect(xaxis.min).toBeCloseTo(initialXmin + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(yaxis.min).toBe(initialYmin);
+ expect(yaxis.max).toBe(initialYmax);
+
+ options.pan.touchMode = oldTouchMode;
+ });
+
+ it('should snap vertical drag to x direction in smart pan mode', function() {
+ var oldTouchMode = options.pan.touchMode;
+ options.pan.touchMode = 'smart';
+
+ plot = $.plot(placeholder, [
+ [
+ [-10, -10],
+ [120, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0];
+
+ var initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 1, y : 1 }, { x : 2, y : 100 }],
+ pointCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y)
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulateTouchEvent([], eventHolder, 'touchend'); // it can correctly trigger panend event.
+
+ expect(xaxis.min).toBe(initialXmin);
+ expect(xaxis.max).toBe(initialXmax);
+ expect(yaxis.min).toBeCloseTo(initialYmin + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax + (canvasCoords[0].y - canvasCoords[1].y), 6);
+
+ options.pan.touchMode = oldTouchMode;
+ });
+
+ it('should no snap diagonal drag in smart pan mode', function() {
+ var oldTouchMode = options.pan.touchMode;
+ options.pan.touchMode = 'smart';
+
+ plot = $.plot(placeholder, [
+ [
+ [-10, -10],
+ [120, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0];
+
+ var initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 1, y : 1 }, { x : 100, y : 100 }],
+ pointCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y)
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulateTouchEvent([], eventHolder, 'touchend'); // it can correctly trigger panend event.
+
+ expect(xaxis.min).toBeCloseTo(initialXmin + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax + (canvasCoords[0].y - canvasCoords[1].y), 6);
+
+ options.pan.touchMode = oldTouchMode;
+ });
+
+ it('should snap horizontally-start-drag to x direction in smartLock pan mode', function() {
+ var oldTouchMode = options.pan.touchMode;
+ options.pan.touchMode = 'smartLock';
+
+ plot = $.plot(placeholder, [
+ [
+ [-10, -10],
+ [120, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0];
+
+ var initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 1, y : 1 }, { x : 100, y : 2 }, { x: 100, y: 100 }],
+ pointCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[2].x, canvasCoords[2].y)
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchmove(eventHolder, pointCoords[2].x, pointCoords[2].y);
+ simulateTouchEvent([], eventHolder, 'touchend'); // it can correctly trigger panend event.
+
+ expect(xaxis.min).toBeCloseTo(initialXmin + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(yaxis.min).toBe(initialYmin);
+ expect(yaxis.max).toBe(initialYmax);
+
+ options.pan.touchMode = oldTouchMode;
+ });
+
+ it('should snap vertically-start-drag to y direction in smartLock pan mode', function() {
+ var oldTouchMode = options.pan.touchMode;
+ options.pan.touchMode = 'smartLock';
+
+ plot = $.plot(placeholder, [
+ [
+ [-10, -10],
+ [120, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0];
+
+ var initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 1, y : 1 }, { x : 2, y : 100 }, { x: 100, y: 100 }],
+ pointCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[2].x, canvasCoords[2].y)
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchmove(eventHolder, pointCoords[2].x, pointCoords[2].y);
+ simulateTouchEvent([], eventHolder, 'touchend'); // it can correctly trigger panend event.
+
+ expect(xaxis.min).toBe(initialXmin);
+ expect(xaxis.max).toBe(initialXmax);
+ expect(yaxis.min).toBeCloseTo(initialYmin + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax + (canvasCoords[0].y - canvasCoords[1].y), 6);
+
+ options.pan.touchMode = oldTouchMode;
+ });
+
+ it('should not drag if pan mode is invalid', function () {
+ var oldTouchMode = options.pan.touchMode;
+ options.pan.touchMode = '';
+
+ plot = $.plot(placeholder, [
+ [
+ [-10, -10],
+ [120, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 1, y : 1 }, { x : 100, y : 100 }],
+ pointCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y)
+ ];
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulateTouchEvent([], eventHolder, 'touchend'); // it can correctly trigger panend event.
+
+ expect(xaxis.min).toBe(initialXmin);
+ expect(xaxis.max).toBe(initialXmax);
+ expect(yaxis.min).toBe(initialYmin);
+ expect(yaxis.max).toBe(initialYmax);
+
+ options.pan.touchMode = oldTouchMode;
+ });
+
+ it('should drag the logarithmic plot', function() {
+ var d1 = [];
+ for (var i = 0; i < 14; i += 0.2) {
+ d1.push([i, 1.01 + Math.sin(i)]);
+ }
+
+ var plot = $.plot(placeholder, [d1], {
+ series: {
+ lines: { show: true },
+ points: { show: true }
+ },
+ xaxis: { autoScale: 'exact' },
+ yaxis: { mode: 'log', showTickLabels: "all", autoScale: 'exact' },
+ zoom: { interactive: true, active: true },
+ pan: { interactive: true, active: true, enableTouch: true }
+ });
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 4, y : 0.7 }, { x : 2, y : 10 } ],
+ pointCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y)
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ expect(xaxis.min).toBeCloseTo(initialXmin + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(yaxis.min).toBeCloseTo((yaxis.c2p(yaxis.p2c(initialYmin) + (pointCoords[0].y - pointCoords[1].y))), 6);
+ expect(yaxis.max).toBeCloseTo((yaxis.c2p(yaxis.p2c(initialYmax) + (pointCoords[0].y - pointCoords[1].y))), 6);
+
+ });
+
+ it('should drag the point in the same way for many sequential moves as for one long move',function() {
+
+ //deactivate ticks for precision
+ options.yaxes[0].showTickLabels = 'none';
+ options.xaxes[0].showTickLabels = 'all';
+
+ plot = $.plot(placeholder, [
+ [
+ [-10, -10],
+ [120, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ limit = 5,
+ canvasCoords = [],
+ pointCoords = [];
+
+ for (var i = 1; i <= limit; i++) {
+ canvasCoords[i] = { x: i, y: i };
+ pointCoords[i] = getPairOfCoords(xaxis, yaxis, canvasCoords[i].x, canvasCoords[i].y);
+ }
+
+ //simulate drag from (1, 1) to (100, 100) sequentially
+ simulate.touchstart(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ for (var i = 2; i <= limit; i++) {
+ simulate.touchmove(eventHolder, pointCoords[i].x, pointCoords[i].y);
+ }
+
+ simulate.touchend(eventHolder, pointCoords[limit].x, pointCoords[limit].y);
+
+ // compare axes after sequential drag with axes after direct drag
+ expect(Math.abs(xaxis.min - (initialXmin + (canvasCoords[1].x - canvasCoords[limit].x)))).toBeLessThan(1);
+ expect(Math.abs(xaxis.max - (initialXmax + (canvasCoords[1].x - canvasCoords[limit].x)))).toBeLessThan(1);
+ expect(yaxis.min).toBeCloseTo(initialYmin + (canvasCoords[1].y - canvasCoords[limit].y), 0);
+ expect(yaxis.max).toBeCloseTo(initialYmax + (canvasCoords[1].y - canvasCoords[limit].y), 0);
+ });
+
+ it('should not pan the plot for a finger outside canvas',function() {
+ plot = $.plot(placeholder, [
+ [
+ [-10, 120],
+ [-10, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 20, y : 20 }, { x : 120, y : 120 }],
+ plotRight = plot.width() + plot.offset().left + plot.offset().right,
+ plotBottom = plot.height() + plot.offset().top + plot.offset().bottom,
+ pointCoords = [
+ {x: plotRight + canvasCoords[0].x, y: plotBottom + canvasCoords[0].y},
+ {x: plotRight + canvasCoords[1].x, y: plotBottom + canvasCoords[1].y}
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ expect(xaxis.min).toBeCloseTo(initialXmin, 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax, 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin, 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax, 6);
+ });
+
+ it('should not pan the plot for a finger which comes from outside canvas',function() {
+ plot = $.plot(placeholder, [
+ [
+ [-10, 120],
+ [-10, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 20, y : 20 }, { x : 120, y : 120 }],
+ plotRight = plot.width() + plot.offset().left + plot.offset().right,
+ plotBottom = plot.height() + plot.offset().top + plot.offset().bottom,
+ pointCoords = [
+ {x: plotRight + canvasCoords[0].x, y: plotBottom + canvasCoords[0].y},
+ {x: canvasCoords[1].x, y: canvasCoords[1].y}
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ expect(xaxis.min).toBeCloseTo(initialXmin, 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax, 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin, 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax, 6);
+ });
+
+ it('should drag the plot on the yaxis only', function() {
+ plot = $.plot(placeholder, [
+ [
+ [0, 0],
+ [10, 10]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ pointCoords = [
+ { x: xaxis.box.left - 10, y: yaxis.p2c(4) },
+ { x: xaxis.box.left - 20, y: yaxis.p2c(5) }
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ expect(xaxis.min).toBe(0);
+ expect(xaxis.max).toBe(10);
+ expect(yaxis.min).toBeCloseTo(yaxis.c2p(yaxis.p2c(initialYmin) + (pointCoords[0].y - pointCoords[1].y)), 6);
+ expect(yaxis.max).toBeCloseTo(yaxis.c2p(yaxis.p2c(initialYmax) + (pointCoords[0].y - pointCoords[1].y)), 6);
+ });
+
+ it('should drag the plot on the xaxis only', function() {
+ plot = $.plot(placeholder, [
+ [
+ [0, 0],
+ [10, 10]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ pointCoords = [
+ { x: xaxis.p2c(4), y: xaxis.box.top + plot.offset().top + 10 },
+ { x: xaxis.p2c(5), y: xaxis.box.top + plot.offset().top + 15 }
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ expect(xaxis.min).toBeCloseTo(xaxis.c2p(xaxis.p2c(initialXmin) + (pointCoords[0].x - pointCoords[1].x)), 6);
+ expect(xaxis.max).toBeCloseTo(xaxis.c2p(xaxis.p2c(initialXmax) + (pointCoords[0].x - pointCoords[1].x)), 6);
+ expect(yaxis.min).toBe(0);
+ expect(yaxis.max).toBe(10);
+ });
+
+ it('should not drag the plot on axis for axis pan not enabled', function() {
+ plot = $.plot(placeholder, [
+ [
+ [0, 0],
+ [10, 10]
+ ]
+ ], {
+ xaxes: [{ autoScale: 'exact', axisPan: false }],
+ yaxes: [{ autoScale: 'exact' }],
+ zoom: { interactive: true, active: true, amount: 10 },
+ pan: { interactive: true, active: true, frameRate: -1, enableTouch: true }
+ });
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ pointCoords = [
+ { x: xaxis.p2c(4), y: xaxis.box.top + plot.offset().top + 10 },
+ { x: xaxis.p2c(5), y: xaxis.box.top + plot.offset().top + 15 }
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ expect(xaxis.min).toBe(0);
+ expect(yaxis.max).toBe(10);
+ expect(yaxis.min).toBe(0);
+ expect(yaxis.max).toBe(10);
+ });
+
+ it('should not drag the axis for plot pan not enabled', function() {
+ plot = $.plot(placeholder, [
+ [
+ [0, 0],
+ [10, 10]
+ ]
+ ], {
+ xaxes: [{ autoScale: 'exact', plotPan: false }],
+ yaxes: [{ autoScale: 'exact', plotPan: false }],
+ zoom: { interactive: true, active: true, amount: 10 },
+ pan: { interactive: true, active: true, frameRate: -1, enableTouch: true }
+ });
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ pointCoords = [
+ { x: 0, y: 50 },
+ { x: 50, y: 100 }
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ expect(xaxis.min).toBe(0);
+ expect(xaxis.max).toBe(10);
+ expect(yaxis.min).toBe(0);
+ expect(yaxis.max).toBe(10);
+ });
+
+ it('should recompute the axis to drag after a pinch event ended',function() {
+ plot = $.plot(placeholder, [
+ [
+ [-1, 2],
+ [11, 12]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ previousXmin, previousXmax, previousYmin, previousYmax,
+ initialCoords = [
+ getPairOfCoords(xaxis, yaxis, 1, 3),
+ getPairOfCoords(xaxis, yaxis, 2, 4),
+ ],
+ midPointCoords = [
+ getPairOfCoords(xaxis, yaxis, 3, 7),
+ { x: xaxis.p2c(4), y: xaxis.box.top + plot.offset().top + 10 }
+ ],
+ finalCoordsPinch = [
+ { x: xaxis.p2c(4), y: xaxis.box.top + plot.offset().top + 10 }
+ ],
+ finalCoordsPan = [
+ { x: xaxis.p2c(5), y: xaxis.box.top + plot.offset().top + 15 }
+ ];
+
+ //simulate pinch
+ simulateTouchEvent(initialCoords, eventHolder, 'touchstart');
+ simulateTouchEvent(midPointCoords, eventHolder, 'touchmove');
+ simulateTouchEvent(finalCoordsPinch, eventHolder, 'touchend');
+
+ previousXmin = xaxis.min;
+ previousXmax = xaxis.max;
+ previousYmin = yaxis.min;
+ previousYmax = yaxis.max;
+
+ expect(previousXmin).not.toBeCloseTo(initialXmin, 6);
+ expect(previousXmax).not.toBeCloseTo(initialXmax, 6);
+ expect(previousYmin).not.toBeCloseTo(initialYmin, 6);
+ expect(previousYmax).not.toBeCloseTo(initialYmax, 6);
+
+ //simulate pan after pinch event
+ simulateTouchEvent(finalCoordsPan, eventHolder, 'touchmove');
+ simulateTouchEvent(finalCoordsPan, eventHolder, 'touchend');
+
+ expect(xaxis.min).toBeCloseTo(xaxis.c2p(xaxis.p2c(previousXmin) + (finalCoordsPinch[0].x - finalCoordsPan[0].x)), 6);
+ expect(xaxis.max).toBeCloseTo(xaxis.c2p(xaxis.p2c(previousXmax) + (finalCoordsPinch[0].x - finalCoordsPan[0].x)), 6);
+ expect(yaxis.min).toBe(previousYmin);
+ expect(yaxis.max).toBe(previousYmax);
+ });
+
+ it('can disable pinch', function() {
+ var oldTouchZoom = options.zoom.enableTouch;
+ options.zoom.enableTouch = false;
+
+ plot = $.plot(placeholder, [
+ [
+ [-10, -10],
+ [120, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0];
+
+ var initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 1, y : 1 }, { x : 100, y : 5 }],
+ initialCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x + 1, canvasCoords[0].y + 1),
+ ],
+ finalCoordsPinch = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x + 1, canvasCoords[1].y + 1),
+ ];
+
+ //simulate pinch
+ simulateTouchEvent(initialCoords, eventHolder, 'touchstart');
+ simulateTouchEvent(finalCoordsPinch, eventHolder, 'touchmove');
+ simulateTouchEvent(finalCoordsPinch, eventHolder, 'touchend');
+
+ expect(xaxis.min).toBe(initialXmin);
+ expect(xaxis.max).toBe(initialXmax);
+ expect(yaxis.min).toBe(initialYmin);
+ expect(yaxis.max).toBe(initialYmax);
+
+ options.zoom.enableTouch = oldTouchZoom;
+ })
+ });
+
+ describe('doubleTap', function() {
+ it('should recenter the plot',function() {
+
+ plot = $.plot(placeholder, [
+ [
+ [-10, 120],
+ [-10, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 1, y : 2 }, { x : 3, y : 5 }],
+ pointCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y)
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ //check if the drag modified the plot correctly
+ expect(xaxis.min).toBeCloseTo(initialXmin + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax + (canvasCoords[0].y - canvasCoords[1].y), 6);
+
+ //simulate double tap
+ simulate.touchstart(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchstart(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ //check if axis values returned to initial coordinates
+ expect(xaxis.min).toBeCloseTo(initialXmin, 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax, 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin, 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax, 6);
+
+ });
+
+ it('should not recenter for doubletap event triggered by touchmove', function() {
+ //when touchmove to somewhere close to last doubletap point, another doubletap will be triggered
+ //this doubletap event should not do recenter
+ plot = $.plot(placeholder, [
+ [
+ [-10, 120],
+ [-10, 120]
+ ]
+ ], options);
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 1, y : 2 }, { x : 3, y : 5 }],
+ pointCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y)
+ ];
+
+ //simulate double tap
+ simulate.touchstart(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchstart(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ //drag the plot
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ //check if the drag modified the plot correctly
+ expect(xaxis.min).toBeCloseTo(initialXmin + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax + (canvasCoords[0].y - canvasCoords[1].y), 6);
+
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ });
+
+ it('should recenter the plot on axis x',function() {
+
+ plot = $.plot(placeholder, [
+ [
+ [-10, -10],
+ [120, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 1, y : 2 }, { x : 3, y : 5 }],
+ pointCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y)
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ //check if the drag modified the plot correctly
+ expect(xaxis.min).toBeCloseTo(initialXmin + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax + (canvasCoords[0].y - canvasCoords[1].y), 6);
+
+ //simulate double tap
+ simulate.touchstart(eventHolder, xaxis.p2c(5), xaxis.box.top + plot.offset().top + 15);
+ simulate.touchend(eventHolder, xaxis.p2c(5), xaxis.box.top + plot.offset().top + 15);
+ simulate.touchstart(eventHolder, xaxis.p2c(5), xaxis.box.top + plot.offset().top + 15);
+ simulate.touchend(eventHolder, xaxis.p2c(5), xaxis.box.top + plot.offset().top + 15);
+
+ //check if axis values returned to initial coordinates
+ expect(xaxis.min).toBeCloseTo(initialXmin, 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax, 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ });
+
+ // intermittent test on Firefox
+ xit('should recenter the plot on axis y',function() {
+
+ plot = $.plot(placeholder, [
+ [
+ [-10, -10],
+ [120, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 1, y : 2 }, { x : 3, y : 5 }],
+ pointCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y)
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ //check if the drag modified the plot correctly
+ expect(xaxis.min).toBeCloseTo(initialXmin + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax + (canvasCoords[0].y - canvasCoords[1].y), 6);
+
+ //simulate double tap
+ simulate.touchstart(eventHolder, xaxis.box.left - 20, yaxis.p2c(5));
+ simulate.touchend(eventHolder, xaxis.box.left - 20, yaxis.p2c(5));
+ simulate.touchstart(eventHolder, xaxis.box.left - 20, yaxis.p2c(5));
+ simulate.touchend(eventHolder, xaxis.box.left - 20, yaxis.p2c(5));
+
+ //check if axis values returned to initial coordinates
+ expect(xaxis.min).toBeCloseTo(initialXmin, 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax, 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin, 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax, 6);
+ });
+
+ it('should not recenter the plot for one touch inside axis box and one inside plot area', function(){
+ plot = $.plot(placeholder, [
+ [
+ [-10, -10],
+ [120, 120]
+ ]
+ ], options);
+
+ var eventHolder = plot.getEventHolder(),
+ xaxis = plot.getXAxes()[0],
+ yaxis = plot.getYAxes()[0],
+ initialXmin = xaxis.min,
+ initialXmax = xaxis.max,
+ initialYmin = yaxis.min,
+ initialYmax = yaxis.max,
+ canvasCoords = [ { x : 1, y : 2 }, { x : 3, y : 5 }],
+ pointCoords = [
+ getPairOfCoords(xaxis, yaxis, canvasCoords[0].x, canvasCoords[0].y),
+ getPairOfCoords(xaxis, yaxis, canvasCoords[1].x, canvasCoords[1].y)
+ ];
+
+ simulate.touchstart(eventHolder, pointCoords[0].x, pointCoords[0].y);
+ simulate.touchmove(eventHolder, pointCoords[1].x, pointCoords[1].y);
+ simulate.touchend(eventHolder, pointCoords[1].x, pointCoords[1].y);
+
+ //check if the drag modified the plot correctly
+ expect(xaxis.min).toBeCloseTo(initialXmin + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax + (canvasCoords[0].y - canvasCoords[1].y), 6);
+
+ //simulate double tap
+ simulate.touchstart(eventHolder, xaxis.box.left - 20, yaxis.p2c(5));
+ simulate.touchend(eventHolder, xaxis.box.left - 20, yaxis.p2c(5));
+ simulate.touchstart(eventHolder, 10, 20);
+ simulate.touchend(eventHolder, 10, 20);
+
+ //check if axis values remained the same
+ expect(xaxis.min).toBeCloseTo(initialXmin + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(xaxis.max).toBeCloseTo(initialXmax + (canvasCoords[0].x - canvasCoords[1].x), 6);
+ expect(yaxis.min).toBeCloseTo(initialYmin + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ expect(yaxis.max).toBeCloseTo(initialYmax + (canvasCoords[0].y - canvasCoords[1].y), 6);
+ });
+ });
+
+ function getPairOfCoords(xaxis, yaxis, x, y) {
+ return {
+ x : xaxis.p2c(x) + plot.offset().left,
+ y : yaxis.p2c(y) + plot.offset().top
+ }
+ }
+});
diff --git a/tests/svgstyle.css b/tests/svgstyle.css
new file mode 100644
index 000000000..308fccd02
--- /dev/null
+++ b/tests/svgstyle.css
@@ -0,0 +1,5 @@
+/* Used in a test from composeImages. */
+circle.externalCSS {
+ stroke: black;
+ stroke-width: 4px;
+}
diff --git a/tests/testUtils/colors.js b/tests/testUtils/colors.js
new file mode 100644
index 000000000..ca445cde3
--- /dev/null
+++ b/tests/testUtils/colors.js
@@ -0,0 +1,226 @@
+/* eslint-disable */
+(function() {
+ 'use strict';
+
+ window.colors = {};
+
+ var colors = window.colors;
+
+ //see https://jasmine.github.io/2.0/custom_matcher.html
+ var jasmineMatchers = {
+ toFillPixel: function(util, customEqualityTesters) {
+ return {
+ compare: function() {
+ var expected = arguments[0],
+ plot = arguments[1],
+ x = arguments[2], y = arguments[3],
+ ctx = plot.getCanvas().getContext('2d'),
+ plotOffset = plot.getPlotOffset(),
+ pixelRatio = plot.getSurface().pixelRatio,
+ cx = (plotOffset.left + x) * pixelRatio,
+ cy = (plotOffset.top + y) * pixelRatio,
+ actual = getPixelColor(ctx, cx, cy),
+ result = {};
+ result.pass = isClose(actual, expected);
+ if (!result.pass) {
+ result.message =
+ 'Expected ' + printColor(expected) +
+ ' at ' + x + ',' + y +
+ ' / ' + cx + ',' + cy +
+ ' actual ' + printColor(actual);
+ }
+ return result;
+ }
+ };
+ },
+
+ toMatchPixelColor: function(util, customEqualityTesters) {
+ return {
+ compare: function(actual, expected) {
+ if (expected === undefined) {
+ expected = expected || [-1000, -1000, -999, -999]; //no color should match these values
+ }
+
+ var pixelData = actual,
+ r = expected[0],
+ g = expected[1],
+ b = expected[2],
+ a = expected[3],
+
+ result = {};
+ result.pass = matchPixelColor(pixelData, r, g, b, a);
+ if (!result.pass) {
+ result.message =
+ 'Expected [' + pixelData +
+ '] to match [' + r + ',' + g + ',' + b + ',' + a + ']';
+ }
+ return result;
+ }
+ };
+ },
+
+ toMatchPixelColorWithError: function(util, customEqualityTesters) {
+ return {
+ compare: function(actual, expected) {
+ if (expected === undefined) {
+ expected = expected || [-1000, -1000, -999, -999, -1500]; //no color should match these values
+ }
+
+ var pixelData = actual,
+ r = expected[0],
+ g = expected[1],
+ b = expected[2],
+ a = expected[3],
+ err = expected[4],
+
+ result = {};
+ result.pass = matchPixelColorWithError(pixelData, r, g, b, a, err);
+ if (!result.pass) {
+ result.message =
+ 'Expected [' + pixelData +
+ '] to match [' + r + ',' + g + ',' + b + ',' + a + ']';
+ }
+ return result;
+ }
+ };
+ },
+
+ toContainPixelColor: function(util, customEqualityTesters) {
+ return {
+ compare: function(actual, expected) {
+ if (expected === undefined) {
+ expected = expected || [-1000, -1000, -999, -999]; //no color should match these values
+ }
+
+ var result = {};
+ var i, i4, pixelData, r, g, b, a, actualLength;
+ r = expected[0];
+ g = expected[1];
+ b = expected[2];
+ a = expected[3];
+ actualLength = actual.length >> 2; //fast divide by 4
+
+ result.pass = false;
+ pixelData = [];
+ for (i = 0; i < actualLength; i = i + 4) {
+ i4 = i * 4;
+ pixelData[0] = actual[i4 + 0];
+ pixelData[1] = actual[i4 + 1];
+ pixelData[2] = actual[i4 + 2];
+ pixelData[3] = actual[i4 + 3];
+ result.pass = result.pass || matchPixelColor(pixelData, r, g, b, a);
+ if (result.pass) {
+ break;
+ }
+ }
+
+ if (!result.pass) {
+ result.message =
+ 'Expected pixelData[...' +
+ '] to contain pixel color: [' + r + ',' + g + ',' + b + ',' + a + ']. Pixel index is: ' + i;
+ }
+ return result;
+ }
+ };
+ },
+
+ toMatchCanvasArea: function(util, customEqualityTesters) {
+ return {
+ compare: function(actual, expected) {
+ if (expected === undefined) {
+ expected = [];
+ }
+
+ var result = {};
+ result.pass = matchPixelDataArrays(actual, expected);
+ if (!result.pass) {
+ result.message =
+ 'Expected actual[...]' +
+ ' to match expected[...]';
+ }
+ return result;
+ }
+ };
+ }
+ };
+
+ function printColor(c) {
+ if (c) {
+ c = (c instanceof Array) ? c : [c[0], c[1], c[2], c[3]];
+ return 'rgba(' + c.join() + ')';
+ } else {
+ return 'undefined';
+ }
+ }
+
+ function getPixelColor(ctx, x, y) {
+ return ctx.getImageData(x, y, 1, 1).data;
+ }
+
+ function getScaledPixelColor(ctx, r, x, y) {
+ return getPixelColor(ctx, x * r, y * r);
+ }
+
+ function rgba(r, g, b, a) {
+ return [r, g, b, a * 255];
+ }
+
+ function isClose(c1, c2) {
+ var tolerance = 5,
+ close = c2
+ .map(function(v, i) { return Math.abs(v - c1[i]); })
+ .every(function(d) { return d <= tolerance; });
+ return close;
+ }
+
+ function matchPixelColor(pixelData, r, g, b, a) {
+ return (pixelData[0] === r) && (pixelData[1] === g) && (pixelData[2] === b) && (pixelData[3] === a);
+ }
+
+ function matchPixelColorWithError(pixelData, r, g, b, a, err) {
+ return (Math.abs(pixelData[0] - r) <= err) && (Math.abs(pixelData[1] - g) <= err) && (Math.abs(pixelData[2] - b) <= err) && (Math.abs(pixelData[3] - a) <= err);
+ }
+
+ function canvasData(canvas, x, y, width, height) {
+ return canvas.getContext('2d').getImageData(x, y, width, height).data;
+ }
+
+ function getEntireCanvasData(canvas) {
+ return canvasData(canvas, 0, 0, canvas.width, canvas.height);
+ }
+
+ //hexToRgb from https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
+ function hexToRgb(hex) {
+ var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+ return result ? {
+ r: parseInt(result[1], 16),
+ g: parseInt(result[2], 16),
+ b: parseInt(result[3], 16)
+ } : null;
+ }
+
+ function matchPixelDataArrays(pixelData1, pixelData2) {
+ var sameValue = true;
+ if (pixelData1.length !== pixelData2.length) {
+ sameValue = false;
+ } else {
+ for (var i = 0; i < pixelData1.length; i++) {
+ if (pixelData1[i] !== pixelData2[i]) {
+ sameValue = false;
+ break;
+ }
+ }
+ }
+ return sameValue;
+ }
+
+ colors.jasmineMatchers = jasmineMatchers;
+ colors.getPixelColor = getPixelColor;
+ colors.getScaledPixelColor = getScaledPixelColor;
+ colors.rgba = rgba;
+ colors.isClose = isClose;
+ colors.canvasData = canvasData;
+ colors.getEntireCanvasData = getEntireCanvasData;
+ colors.hexToRgb = hexToRgb;
+
+})();
diff --git a/tests/testUtils/simulate.js b/tests/testUtils/simulate.js
new file mode 100644
index 000000000..946a9136d
--- /dev/null
+++ b/tests/testUtils/simulate.js
@@ -0,0 +1,213 @@
+/* eslint-disable */
+(function() {
+ 'use strict';
+
+ window.simulate = {};
+
+ var simulate = window.simulate;
+ var noButton = 0;
+ var leftButton = 1;
+ var buttonsToWhichMap = { 0: 0, 1: 1, 4: 2, 8: 3 };
+ var buttonsToButtonMap = { 0: undefined, 1: 0, 2: 1, 4: 2 };
+
+ function mouseEvent(type, sx, sy, cx, cy, buttons, detail, key) {
+ var e = buildMouseEventOptions(type, sx, sy, cx, cy, buttons, detail, key, undefined, undefined),
+ evt = new MouseEvent(type, e);
+ return evt;
+ }
+
+ function wheelEvent(type, sx, sy, cx, cy, buttons, detail, key, deltaX, deltaY) {
+ var e = buildMouseEventOptions(type, sx, sy, cx, cy, buttons, detail, key, deltaX, deltaY),
+ evt = new WheelEvent(type, e);
+ return evt;
+ }
+
+ function buildMouseEventOptions(type, sx, sy, cx, cy, buttons, detail, key, deltaX, deltaY) {
+ buttons = (buttons != null) ? buttons : noButton;
+
+ var which = buttonsToWhichMap[buttons],
+ button = buttonsToButtonMap[buttons],
+ e = {
+ bubbles: true,
+ cancelable: (type !== 'mousemove'),
+ view: window,
+ deltaX: deltaX,
+ deltaY: deltaY,
+ detail: detail,
+ screenX: sx,
+ screenY: sy,
+ clientX: cx,
+ clientY: cy,
+ pageX: cx,
+ pageY: cy,
+ ctrlKey: false,
+ altKey: false,
+ shiftKey: false,
+ metaKey: false,
+ button: button,
+ buttons: buttons,
+ which: which,
+ relatedTarget: undefined
+ };
+
+ var keys = ['ctrlKey', 'altKey', 'shiftKey', 'metaKey'],
+ pressedKeyIndex = keys.indexOf(key);
+ if (pressedKeyIndex !== -1) {
+ e[key] = true;
+ }
+
+ return e;
+ }
+
+ function dispatchEvent(el, evt) {
+ if (el.dispatchEvent) {
+ el.dispatchEvent(evt);
+ }
+ return evt;
+ }
+
+ function simulateMouseDown(el, x, y, buttons) {
+ var bBox = el.getBoundingClientRect();
+
+ var clickX = bBox.left + x;
+ var clickY = bBox.top + y;
+
+ buttons = (buttons != null) ? buttons : leftButton;
+ var evt = mouseEvent('mousedown', clickX, clickY, clickX, clickY, buttons);
+ return dispatchEvent(el, evt);
+ }
+
+ function simulateMouseMove(el, x, y, buttons) {
+ var bBox = el.getBoundingClientRect();
+
+ var clickX = bBox.left + x;
+ var clickY = bBox.top + y;
+
+ buttons = (buttons != null) ? buttons : leftButton;
+ var evt = mouseEvent('mousemove', clickX, clickY, clickX, clickY, buttons);
+ return dispatchEvent(el, evt);
+ }
+
+ function simulateMouseUp(el, x, y, buttons) {
+ var bBox = el.getBoundingClientRect();
+
+ var clickX = bBox.left + x;
+ var clickY = bBox.top + y;
+
+ var evt = mouseEvent('mouseup', clickX, clickY, clickX, clickY, buttons);
+ return dispatchEvent(el, evt);
+ }
+
+ function simulateMouseWheel(el, x, y, deltaX, deltaY) {
+ var bBox = el.getBoundingClientRect();
+
+ var clickX = bBox.left + x;
+ var clickY = bBox.top + y;
+
+ // Different browsers or OSes are passing information about the scroll delta differently.
+ // Passing a numeric value to 'detail' is one of them. On MacOS the deltaY counts.
+ var detail = deltaY;
+
+ var evt = wheelEvent('DOMMouseScroll', clickX, clickY, clickX, clickY, 0, detail, undefined, deltaX, deltaY);
+ return dispatchEvent(el, evt);
+ }
+
+ function simulateDblclick(el, x, y, buttons) {
+ var bBox = el.getBoundingClientRect();
+ var clickX = bBox.left + x;
+ var clickY = bBox.top + y;
+
+ var evt = mouseEvent('dblclick', clickX, clickY, clickX, clickY, buttons);
+ return dispatchEvent(el, evt);
+ }
+
+ function simulateClick(el, x, y, buttons, key) {
+ var bBox = el.getBoundingClientRect();
+ var clickX = bBox.left + x;
+ var clickY = bBox.top + y;
+
+ var evt = mouseEvent('click', clickX, clickY, clickX, clickY, buttons, undefined, key);
+ return dispatchEvent(el, evt);
+ }
+
+ function simulateTouchStart(el, x, y) {
+ return sendTouchEvent(x, y, el, 'touchstart');
+ }
+
+ function simulateTouchMove(el, x, y) {
+ return sendTouchEvent(x, y, el, 'touchmove');
+ }
+
+ function simulateTouchEnd(el, x, y) {
+ return sendTouchEvent(x, y, el, 'touchend');
+ }
+
+ function simulateTouchDrag(el, x, y, deltaX, deltaY) {
+ return [
+ simulateTouchStart(el, x, y),
+ simulateTouchMove(el, x + deltaX, y + deltaY),
+ simulateTouchEnd(el, x + deltaX, y + deltaY)
+ ];
+ }
+
+ function sendTouchEvent(x, y, element, eventType) {
+ return sendTouchEvents([{x: x, y: y}], element, eventType);
+ }
+
+ function sendTouchEvents(coords, element, eventType) {
+ var touchObjects = [];
+
+ for(var i = 0; i < coords.length; i++) {
+ touchObjects[i] = {
+ identifier: Date.now(),
+ target: element,
+ pageX: coords[i].x,
+ pageY: coords[i].y,
+ clientX: pageXtoClientX(coords[i].x),
+ clientY: pageYtoClientY(coords[i].y),
+ radiusX: 2.5,
+ radiusY: 2.5,
+ rotationAngle: 10,
+ force: 0.5
+ };
+ }
+
+ var event;
+ if (typeof UIEvent === 'function') {
+ event = new UIEvent(eventType);
+ } else {
+ event = document.createEvent('UIEvent');
+ event.initUIEvent(eventType, true, true);
+ }
+
+ event.touches = touchObjects;
+ event.targetTouches = [];
+ event.changedTouches = touchObjects;
+ event.shiftKey = true;
+
+ element.dispatchEvent(event);
+ return event;
+ }
+
+ function pageXtoClientX(pageX) {
+ var doc = document.documentElement;
+ return pageX - (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
+ }
+
+ function pageYtoClientY(pageY) {
+ var doc = document.documentElement;
+ return pageY - (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
+ }
+
+ simulate.mouseDown = simulateMouseDown;
+ simulate.mouseMove = simulateMouseMove;
+ simulate.mouseUp = simulateMouseUp;
+ simulate.mouseWheel = simulateMouseWheel;
+ simulate.dblclick = simulateDblclick;
+ simulate.touchstart = simulateTouchStart;
+ simulate.touchmove = simulateTouchMove;
+ simulate.touchend = simulateTouchEnd;
+ simulate.touchdrag = simulateTouchDrag;
+ simulate.sendTouchEvents = sendTouchEvents;
+ simulate.click = simulateClick;
+})();
diff --git a/update_docs.js b/update_docs.js
new file mode 100644
index 000000000..1cb857ff2
--- /dev/null
+++ b/update_docs.js
@@ -0,0 +1,34 @@
+/* jshint node: true*/
+
+"use strict";
+
+var literate = require('ljs');
+var fs = require('fs');
+
+var docs2generate = [
+ ['docs/canvaswrapper.md', 'jquery.canvaswrapper.js'],
+ // ['docs/colorhelpers.md', 'jquery.colorhelpers.js'],
+ ['docs/absRelTime.md', 'jquery.flot.absRelTime.js'],
+ // ['docs/axislabels.md', 'jquery.flot.axislabels.js'],
+ ['docs/browser.md', 'jquery.flot.browser.js'],
+ ['docs/composeImages.md', 'jquery.flot.composeImages.js'],
+ ['docs/drawSeries.md', 'jquery.flot.drawSeries.js'],
+ ['docs/hover.md', 'jquery.flot.hover.js'],
+ // ['docs/legend.md', 'jquery.flot.legend.js'],
+ ['docs/logaxis.md', 'jquery.flot.logaxis.js'],
+ ['docs/navigate.md', 'jquery.flot.navigate.js'],
+ // ['docs/selection.md', 'jquery.flot.selection.js'],
+ // ['docs/symbol.md', 'jquery.flot.symbol.js'],
+ // ['docs/touch.md', 'jquery.flot.touch.js'],
+ // ['docs/touchNavigate.md', 'jquery.flot.touchNavigate.js'],
+ // ['docs/uiConstants.md', 'jquery.flot.uiConstants.js']
+];
+
+docs2generate.forEach(function (doc) {
+ console.log(doc[0], '...');
+ var documentation = literate(doc[1], {
+ code: false
+ });
+
+ fs.writeFileSync(doc[0], documentation);
+});