zoom_and_pan.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. /**
  2. * DevExtreme (viz/chart_components/zoom_and_pan.js)
  3. * Version: 19.1.16
  4. * Build date: Tue Oct 18 2022
  5. *
  6. * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
  7. * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
  8. */
  9. "use strict";
  10. var _type = require("../../core/utils/type");
  11. var _extend = require("../../core/utils/extend");
  12. var _utils = require("../core/utils");
  13. var _wheel = require("../../events/core/wheel");
  14. var _transform = require("../../events/transform");
  15. var _transform2 = _interopRequireDefault(_transform);
  16. var _drag = require("../../events/drag");
  17. var _drag2 = _interopRequireDefault(_drag);
  18. function _interopRequireDefault(obj) {
  19. return obj && obj.__esModule ? obj : {
  20. "default": obj
  21. }
  22. }
  23. var EVENTS_NS = ".zoomAndPanNS";
  24. var DRAG_START_EVENT_NAME = _drag2.default.start + EVENTS_NS;
  25. var DRAG_EVENT_NAME = _drag2.default.move + EVENTS_NS;
  26. var DRAG_END_EVENT_NAME = _drag2.default.end + EVENTS_NS;
  27. var PINCH_START_EVENT_NAME = _transform2.default.pinchstart + EVENTS_NS;
  28. var PINCH_EVENT_NAME = _transform2.default.pinch + EVENTS_NS;
  29. var PINCH_END_EVENT_NAME = _transform2.default.pinchend + EVENTS_NS;
  30. var SCROLL_BAR_START_EVENT_NAME = "dxc-scroll-start" + EVENTS_NS;
  31. var SCROLL_BAR_MOVE_EVENT_NAME = "dxc-scroll-move" + EVENTS_NS;
  32. var SCROLL_BAR_END_EVENT_NAME = "dxc-scroll-end" + EVENTS_NS;
  33. var GESTURE_TIMEOUT = 300;
  34. var MIN_DRAG_DELTA = 5;
  35. var _min = Math.min;
  36. var _max = Math.max;
  37. var _abs = Math.abs;
  38. function canvasToRect(canvas) {
  39. return {
  40. x: canvas.left,
  41. y: canvas.top,
  42. width: canvas.width - canvas.left - canvas.right,
  43. height: canvas.height - canvas.top - canvas.bottom
  44. }
  45. }
  46. function checkCoords(rect, coords) {
  47. var x = coords.x;
  48. var y = coords.y;
  49. return x >= rect.x && x <= rect.width + rect.x && y >= rect.y && y <= rect.height + rect.y
  50. }
  51. function sortAxes(axes, onlyAxisToNotify) {
  52. if (onlyAxisToNotify) {
  53. axes = axes.sort(function(a, b) {
  54. if (a === onlyAxisToNotify) {
  55. return -1
  56. }
  57. if (b === onlyAxisToNotify) {
  58. return 1
  59. }
  60. return 0
  61. })
  62. }
  63. return axes
  64. }
  65. function isNotEmptyAxisBusinessRange(axis) {
  66. return !axis.getTranslator().getBusinessRange().isEmpty()
  67. }
  68. module.exports = {
  69. name: "zoom_and_pan",
  70. init: function() {
  71. var chart = this;
  72. var renderer = this._renderer;
  73. function cancelEvent(e) {
  74. if (e.originalEvent) {
  75. cancelEvent(e.originalEvent)
  76. }
  77. if (false !== e.cancelable) {
  78. e.cancel = true
  79. }
  80. }
  81. function startAxesViewportChanging(zoomAndPan, actionField, e) {
  82. var options = zoomAndPan.options;
  83. var actionData = zoomAndPan.actionData;
  84. var axes = [];
  85. if (options.argumentAxis[actionField]) {
  86. axes.push(chart.getArgumentAxis())
  87. }
  88. if (options.valueAxis[actionField]) {
  89. axes = axes.concat(actionData.valueAxes)
  90. }
  91. axes.reduce(function(isPrevented, axis) {
  92. if (isPrevented) {
  93. return isPrevented
  94. }
  95. if (isNotEmptyAxisBusinessRange(axis)) {
  96. return axis.handleZooming(null, {
  97. end: true
  98. }, e, actionField).isPrevented
  99. }
  100. return isPrevented
  101. }, false) && cancelEvent(e)
  102. }
  103. function axesViewportChanging(zoomAndPan, actionField, e, offsetCalc, centerCalc) {
  104. function zoomAxes(axes, criteria, coordField, e, actionData) {
  105. var zoom = {
  106. zoomed: false
  107. };
  108. criteria && axes.filter(isNotEmptyAxisBusinessRange).forEach(function(axis) {
  109. var options = axis.getOptions();
  110. var viewport = axis.visualRange();
  111. var scale = axis.getTranslator().getEventScale(e);
  112. var translate = -offsetCalc(e, actionData, coordField, scale);
  113. zoom = (0, _extend.extend)(true, zoom, axis.getTranslator().zoom(translate, scale, axis.getZoomBounds()));
  114. var range = axis.adjustRange((0, _utils.getVizRangeObject)([zoom.min, zoom.max]));
  115. var isMinZoom = axis.isZoomingLowerLimitOvercome(actionField, scale, range);
  116. if (!(0, _type.isDefined)(viewport) || viewport.startValue.valueOf() !== range.startValue.valueOf() || viewport.endValue.valueOf() !== range.endValue.valueOf()) {
  117. axis.handleZooming(isMinZoom ? null : range, {
  118. start: true,
  119. end: true
  120. }, e, actionField);
  121. if (!isMinZoom) {
  122. zoom.zoomed = true;
  123. zoom.deltaTranslate = translate - zoom.translate
  124. }
  125. } else {
  126. if ("touch" === e.pointerType && "discrete" === options.type) {
  127. var isMinPosition = axis.isExtremePosition(false);
  128. var isMaxPosition = axis.isExtremePosition(true);
  129. var zoomInEnabled = scale > 1 && !isMinZoom;
  130. var zoomOutEnabled = scale < 1 && (!isMinPosition || !isMaxPosition);
  131. var panningEnabled = 1 === scale && !(isMinPosition && (translate < 0 && !options.inverted || translate > 0 && options.inverted) || isMaxPosition && (translate > 0 && !options.inverted || translate < 0 && options.inverted));
  132. zoom.enabled = zoomInEnabled || zoomOutEnabled || panningEnabled
  133. }
  134. }
  135. });
  136. return zoom
  137. }
  138. function storeOffset(e, actionData, zoom, coordField) {
  139. if (zoom.zoomed) {
  140. actionData.offset[coordField] = (e.offset ? e.offset[coordField] : actionData.offset[coordField]) + zoom.deltaTranslate
  141. }
  142. }
  143. function storeCenter(center, actionData, zoom, coordField) {
  144. if (zoom.zoomed) {
  145. actionData.center[coordField] = center[coordField] + zoom.deltaTranslate
  146. }
  147. }
  148. var rotated = chart.option("rotated");
  149. var actionData = zoomAndPan.actionData;
  150. var options = zoomAndPan.options;
  151. var argZoom = {};
  152. var valZoom = {};
  153. if (!actionData.fallback) {
  154. argZoom = zoomAxes(chart._argumentAxes, options.argumentAxis[actionField], rotated ? "y" : "x", e, actionData);
  155. valZoom = zoomAxes(actionData.valueAxes, options.valueAxis[actionField], rotated ? "x" : "y", e, actionData);
  156. chart._requestChange(["VISUAL_RANGE"]);
  157. storeOffset(e, actionData, argZoom, rotated ? "y" : "x");
  158. storeOffset(e, actionData, valZoom, rotated ? "x" : "y")
  159. }
  160. var center = centerCalc(e);
  161. storeCenter(center, actionData, argZoom, rotated ? "y" : "x");
  162. storeCenter(center, actionData, valZoom, rotated ? "x" : "y");
  163. if (!argZoom.zoomed && !valZoom.zoomed) {
  164. actionData.center = center
  165. }
  166. return argZoom.zoomed || valZoom.zoomed || actionData.fallback || argZoom.enabled || valZoom.enabled
  167. }
  168. function finishAxesViewportChanging(zoomAndPan, actionField, e, offsetCalc) {
  169. function zoomAxes(axes, criteria, coordField, e, actionData, onlyAxisToNotify) {
  170. var zoomStarted = false;
  171. criteria && axes.forEach(function(axis) {
  172. var silent = onlyAxisToNotify && axis !== onlyAxisToNotify;
  173. var scale = e.scale || 1;
  174. var zoom = axis.getTranslator().zoom(-offsetCalc(e, actionData, coordField, scale), scale, axis.getZoomBounds());
  175. var range = {
  176. startValue: zoom.min,
  177. endValue: zoom.max
  178. };
  179. var isMinZoom = axis.isZoomingLowerLimitOvercome(actionField, scale, range);
  180. axis.handleZooming(isMinZoom ? null : range, {
  181. start: true,
  182. end: silent
  183. }, e, actionField);
  184. isMinZoom ? axis.handleZoomEnd() : zoomStarted = true
  185. });
  186. return zoomStarted
  187. }
  188. var rotated = chart.option("rotated");
  189. var actionData = zoomAndPan.actionData;
  190. var options = zoomAndPan.options;
  191. var zoomStarted = true;
  192. if (actionData.fallback) {
  193. zoomStarted &= zoomAxes(chart._argumentAxes, options.argumentAxis[actionField], rotated ? "y" : "x", e, actionData, chart.getArgumentAxis());
  194. zoomStarted |= zoomAxes(actionData.valueAxes, options.valueAxis[actionField], rotated ? "x" : "y", e, actionData)
  195. } else {
  196. var axes = [];
  197. if (options.argumentAxis[actionField]) {
  198. axes.push(chart.getArgumentAxis())
  199. }
  200. if (options.valueAxis[actionField]) {
  201. axes = axes.concat(actionData.valueAxes)
  202. }
  203. axes.filter(isNotEmptyAxisBusinessRange).forEach(function(axis) {
  204. axis.handleZooming(null, {
  205. start: true
  206. }, e, actionField)
  207. });
  208. zoomStarted = zoomStarted && axes.length
  209. }
  210. zoomStarted && chart._requestChange(["VISUAL_RANGE"])
  211. }
  212. function prepareActionData(coords, action) {
  213. var axes = chart._argumentAxes.filter(function(axis) {
  214. return checkCoords(canvasToRect(axis.getCanvas()), coords)
  215. });
  216. return {
  217. fallback: chart._lastRenderingTime > GESTURE_TIMEOUT,
  218. cancel: !axes.length || !(0, _type.isDefined)(action),
  219. action: action,
  220. curAxisRect: axes.length && canvasToRect(axes[0].getCanvas()),
  221. valueAxes: axes.length && chart._valueAxes.filter(function(axis) {
  222. return checkCoords(canvasToRect(axis.getCanvas()), coords)
  223. }),
  224. offset: {
  225. x: 0,
  226. y: 0
  227. },
  228. center: coords,
  229. startCenter: coords
  230. }
  231. }
  232. function getPointerCoord(rect, e) {
  233. var rootOffset = renderer.getRootOffset();
  234. return {
  235. x: _min(_max(e.pageX - rootOffset.left, rect.x), rect.width + rect.x),
  236. y: _min(_max(e.pageY - rootOffset.top, rect.y), rect.height + rect.y)
  237. }
  238. }
  239. function calcCenterForPinch(e) {
  240. var rootOffset = renderer.getRootOffset();
  241. var x1 = e.pointers[0].pageX;
  242. var x2 = e.pointers[1].pageX;
  243. var y1 = e.pointers[0].pageY;
  244. var y2 = e.pointers[1].pageY;
  245. return {
  246. x: _min(x1, x2) + _abs(x2 - x1) / 2 - rootOffset.left,
  247. y: _min(y1, y2) + _abs(y2 - y1) / 2 - rootOffset.top
  248. }
  249. }
  250. function calcCenterForDrag(e) {
  251. var rootOffset = renderer.getRootOffset();
  252. return {
  253. x: e.pageX - rootOffset.left,
  254. y: e.pageY - rootOffset.top
  255. }
  256. }
  257. function calcOffsetForDrag(e, actionData, coordField) {
  258. return e.offset[coordField] - actionData.offset[coordField]
  259. }
  260. function preventDefaults(e) {
  261. if (false !== e.cancelable) {
  262. e.preventDefault();
  263. e.stopPropagation()
  264. }
  265. chart._stopCurrentHandling()
  266. }
  267. var zoomAndPan = {
  268. dragStartHandler: function(e) {
  269. var options = zoomAndPan.options;
  270. var isTouch = "touch" === e.pointerType;
  271. var wantPan = options.argumentAxis.pan || options.valueAxis.pan;
  272. var wantZoom = options.argumentAxis.zoom || options.valueAxis.zoom;
  273. var panKeyPressed = (0, _type.isDefined)(options.panKey) && e[(0, _utils.normalizeEnum)(options.panKey) + "Key"];
  274. var dragToZoom = options.dragToZoom;
  275. var action;
  276. e._cancelPreventDefault = true;
  277. if (isTouch) {
  278. if (options.allowTouchGestures && wantPan) {
  279. var cancelPanning = !zoomAndPan.panningVisualRangeEnabled() || zoomAndPan.skipEvent;
  280. action = cancelPanning ? null : "pan"
  281. }
  282. } else {
  283. if (dragToZoom && wantPan && panKeyPressed) {
  284. action = "pan"
  285. } else {
  286. if (!dragToZoom && wantPan) {
  287. action = "pan"
  288. } else {
  289. if (dragToZoom && wantZoom) {
  290. action = "zoom"
  291. }
  292. }
  293. }
  294. }
  295. var actionData = prepareActionData(calcCenterForDrag(e), action);
  296. if (actionData.cancel) {
  297. zoomAndPan.skipEvent = false;
  298. if (false !== e.cancelable) {
  299. e.cancel = true
  300. }
  301. return
  302. }
  303. zoomAndPan.actionData = actionData;
  304. if ("zoom" === action) {
  305. actionData.startCoords = getPointerCoord(actionData.curAxisRect, e);
  306. actionData.rect = renderer.rect(0, 0, 0, 0).attr(options.dragBoxStyle).append(renderer.root)
  307. } else {
  308. startAxesViewportChanging(zoomAndPan, "pan", e)
  309. }
  310. },
  311. dragHandler: function(e) {
  312. var rotated = chart.option("rotated");
  313. var options = zoomAndPan.options;
  314. var actionData = zoomAndPan.actionData;
  315. var isTouch = "touch" === e.pointerType;
  316. e._cancelPreventDefault = true;
  317. if (!actionData || isTouch && !zoomAndPan.panningVisualRangeEnabled()) {
  318. return
  319. }
  320. if ("zoom" === actionData.action) {
  321. preventDefaults(e);
  322. var curCanvas = actionData.curAxisRect;
  323. var startCoords = actionData.startCoords;
  324. var curCoords = getPointerCoord(curCanvas, e);
  325. var zoomArg = options.argumentAxis.zoom;
  326. var zoomVal = options.valueAxis.zoom;
  327. var rect = {
  328. x: _min(startCoords.x, curCoords.x),
  329. y: _min(startCoords.y, curCoords.y),
  330. width: _abs(startCoords.x - curCoords.x),
  331. height: _abs(startCoords.y - curCoords.y)
  332. };
  333. if (!zoomArg || !zoomVal) {
  334. if (!zoomArg && !rotated || !zoomVal && rotated) {
  335. rect.x = curCanvas.x;
  336. rect.width = curCanvas.width
  337. } else {
  338. rect.y = curCanvas.y;
  339. rect.height = curCanvas.height
  340. }
  341. }
  342. actionData.rect.attr(rect)
  343. } else {
  344. if ("pan" === actionData.action) {
  345. axesViewportChanging(zoomAndPan, "pan", e, calcOffsetForDrag, function(e) {
  346. return e.offset
  347. });
  348. var deltaOffsetY = Math.abs(e.offset.y - actionData.offset.y);
  349. var deltaOffsetX = Math.abs(e.offset.x - actionData.offset.x);
  350. if (isTouch && (deltaOffsetY > MIN_DRAG_DELTA && deltaOffsetY > Math.abs(actionData.offset.x) || deltaOffsetX > MIN_DRAG_DELTA && deltaOffsetX > Math.abs(actionData.offset.y))) {
  351. return
  352. }
  353. preventDefaults(e)
  354. }
  355. }
  356. },
  357. dragEndHandler: function(e) {
  358. var rotated = chart.option("rotated");
  359. var options = zoomAndPan.options;
  360. var actionData = zoomAndPan.actionData;
  361. var isTouch = "touch" === e.pointerType;
  362. var panIsEmpty = actionData && "pan" === actionData.action && !actionData.fallback && 0 === actionData.offset.x && 0 === actionData.offset.y;
  363. if (!actionData || isTouch && !zoomAndPan.panningVisualRangeEnabled() || panIsEmpty) {
  364. return
  365. }(!isTouch || !zoomAndPan.actionData.isNative) && preventDefaults(e);
  366. if ("zoom" === actionData.action) {
  367. var zoomAxes = function(axes, criteria, coordField, startCoords, curCoords, onlyAxisToNotify) {
  368. axes = sortAxes(axes, onlyAxisToNotify);
  369. var curCoord = curCoords[coordField];
  370. var startCoord = startCoords[coordField];
  371. var zoomStarted = false;
  372. if (criteria && _abs(curCoord - startCoord) > MIN_DRAG_DELTA) {
  373. axes.some(function(axis) {
  374. var tr = axis.getTranslator();
  375. if (tr.getBusinessRange().isEmpty()) {
  376. return
  377. }
  378. var silent = onlyAxisToNotify && axis !== onlyAxisToNotify;
  379. var range = [tr.from(startCoord), tr.from(curCoord)];
  380. var isMinZoom = axis.isZoomingLowerLimitOvercome(actionData.action, tr.getMinScale(true), range);
  381. var result = axis.handleZooming(isMinZoom ? null : range, {
  382. start: !!silent,
  383. end: !!silent
  384. }, e, actionData.action);
  385. isMinZoom ? axis.handleZoomEnd() : zoomStarted = true;
  386. return onlyAxisToNotify && result.isPrevented
  387. })
  388. }
  389. return zoomStarted
  390. };
  391. var curCoords = getPointerCoord(actionData.curAxisRect, e);
  392. var argumentAxesZoomed = zoomAxes(chart._argumentAxes, options.argumentAxis.zoom, rotated ? "y" : "x", actionData.startCoords, curCoords, chart.getArgumentAxis());
  393. var valueAxesZoomed = zoomAxes(actionData.valueAxes, options.valueAxis.zoom, rotated ? "x" : "y", actionData.startCoords, curCoords);
  394. if (valueAxesZoomed || argumentAxesZoomed) {
  395. chart._requestChange(["VISUAL_RANGE"])
  396. }
  397. actionData.rect.dispose()
  398. } else {
  399. if ("pan" === actionData.action) {
  400. finishAxesViewportChanging(zoomAndPan, "pan", e, calcOffsetForDrag)
  401. }
  402. }
  403. zoomAndPan.actionData = null
  404. },
  405. pinchStartHandler: function(e) {
  406. var actionData = prepareActionData(calcCenterForPinch(e), "zoom");
  407. actionData.isNative = !zoomAndPan.panningVisualRangeEnabled();
  408. if (actionData.cancel) {
  409. cancelEvent(e);
  410. return
  411. }
  412. zoomAndPan.actionData = actionData;
  413. startAxesViewportChanging(zoomAndPan, "zoom", e)
  414. },
  415. pinchHandler: function(e) {
  416. if (!zoomAndPan.actionData) {
  417. return
  418. }
  419. var viewportChanged = axesViewportChanging(zoomAndPan, "zoom", e, function(e, actionData, coordField, scale) {
  420. return calcCenterForPinch(e)[coordField] - actionData.center[coordField] + (actionData.center[coordField] - actionData.center[coordField] * scale)
  421. }, calcCenterForPinch);
  422. zoomAndPan.defineTouchBehavior(!viewportChanged, e);
  423. !viewportChanged && (zoomAndPan.actionData = null)
  424. },
  425. pinchEndHandler: function(e) {
  426. if (!zoomAndPan.actionData) {
  427. return
  428. }
  429. finishAxesViewportChanging(zoomAndPan, "zoom", e, function(e, actionData, coordField, scale) {
  430. return actionData.center[coordField] - actionData.startCenter[coordField] + (actionData.startCenter[coordField] - actionData.startCenter[coordField] * scale)
  431. });
  432. zoomAndPan.actionData = null
  433. },
  434. cleanup: function() {
  435. renderer.root.off(EVENTS_NS);
  436. zoomAndPan.actionData && zoomAndPan.actionData.rect && zoomAndPan.actionData.rect.dispose();
  437. zoomAndPan.actionData = null;
  438. renderer.root.css({
  439. "touch-action": "",
  440. "-ms-touch-action": ""
  441. })
  442. },
  443. setup: function(options) {
  444. zoomAndPan.cleanup();
  445. if (!options.argumentAxis.pan) {
  446. renderer.root.on(SCROLL_BAR_START_EVENT_NAME, cancelEvent)
  447. }
  448. if (options.argumentAxis.none && options.valueAxis.none) {
  449. return
  450. }
  451. zoomAndPan.options = options;
  452. var rotated = chart.option("rotated");
  453. if ((options.argumentAxis.zoom || options.valueAxis.zoom) && options.allowMouseWheel) {
  454. renderer.root.on(_wheel.name + EVENTS_NS, function(e) {
  455. function zoomAxes(axes, coord, delta, onlyAxisToNotify) {
  456. axes = sortAxes(axes, onlyAxisToNotify);
  457. var zoomStarted = false;
  458. axes.some(function(axis) {
  459. var translator = axis.getTranslator();
  460. if (translator.getBusinessRange().isEmpty()) {
  461. return
  462. }
  463. var silent = onlyAxisToNotify && axis !== onlyAxisToNotify;
  464. var scale = translator.getMinScale(delta > 0);
  465. var zoom = translator.zoom(-(coord - coord * scale), scale, axis.getZoomBounds());
  466. var range = {
  467. startValue: zoom.min,
  468. endValue: zoom.max
  469. };
  470. var isMinZoom = axis.isZoomingLowerLimitOvercome("zoom", scale, range);
  471. var result = axis.handleZooming(isMinZoom ? null : range, {
  472. start: !!silent,
  473. end: !!silent
  474. }, e, "zoom");
  475. isMinZoom ? axis.handleZoomEnd() : zoomStarted = true;
  476. return onlyAxisToNotify && result.isPrevented
  477. });
  478. return !!zoomStarted
  479. }
  480. var coords = calcCenterForDrag(e);
  481. var axesZoomed = false;
  482. var targetAxes;
  483. if (options.valueAxis.zoom) {
  484. targetAxes = chart._valueAxes.filter(function(axis) {
  485. return checkCoords(canvasToRect(axis.getCanvas()), coords)
  486. });
  487. if (0 === targetAxes.length) {
  488. var targetCanvas = chart._valueAxes.reduce(function(r, axis) {
  489. if (!r && axis.coordsIn(coords.x, coords.y)) {
  490. r = axis.getCanvas()
  491. }
  492. return r
  493. }, null);
  494. if (targetCanvas) {
  495. targetAxes = chart._valueAxes.filter(function(axis) {
  496. return checkCoords(canvasToRect(axis.getCanvas()), {
  497. x: targetCanvas.left,
  498. y: targetCanvas.top
  499. })
  500. })
  501. }
  502. }
  503. axesZoomed |= zoomAxes(targetAxes, rotated ? coords.x : coords.y, e.delta)
  504. }
  505. if (options.argumentAxis.zoom) {
  506. var canZoom = chart._argumentAxes.some(function(axis) {
  507. if (checkCoords(canvasToRect(axis.getCanvas()), coords) || axis.coordsIn(coords.x, coords.y)) {
  508. return true
  509. }
  510. return false
  511. });
  512. axesZoomed |= canZoom && zoomAxes(chart._argumentAxes, rotated ? coords.y : coords.x, e.delta, chart.getArgumentAxis())
  513. }
  514. if (axesZoomed) {
  515. chart._requestChange(["VISUAL_RANGE"]);
  516. zoomAndPan.panningVisualRangeEnabled(targetAxes) && preventDefaults(e)
  517. }
  518. })
  519. }
  520. if (options.allowTouchGestures) {
  521. if (options.argumentAxis.zoom || options.valueAxis.zoom) {
  522. renderer.root.on(PINCH_START_EVENT_NAME, {
  523. passive: false
  524. }, zoomAndPan.pinchStartHandler).on(PINCH_EVENT_NAME, {
  525. passive: false
  526. }, zoomAndPan.pinchHandler).on(PINCH_END_EVENT_NAME, zoomAndPan.pinchEndHandler)
  527. }
  528. }
  529. renderer.root.on(DRAG_START_EVENT_NAME, {
  530. immediate: true,
  531. passive: false
  532. }, zoomAndPan.dragStartHandler).on(DRAG_EVENT_NAME, {
  533. immediate: true,
  534. passive: false
  535. }, zoomAndPan.dragHandler).on(DRAG_END_EVENT_NAME, zoomAndPan.dragEndHandler);
  536. if (options.argumentAxis.pan) {
  537. renderer.root.on(SCROLL_BAR_START_EVENT_NAME, function(e) {
  538. zoomAndPan.actionData = {
  539. valueAxes: [],
  540. offset: {
  541. x: 0,
  542. y: 0
  543. },
  544. center: {
  545. x: 0,
  546. y: 0
  547. }
  548. };
  549. preventDefaults(e);
  550. startAxesViewportChanging(zoomAndPan, "pan", e)
  551. }).on(SCROLL_BAR_MOVE_EVENT_NAME, function(e) {
  552. preventDefaults(e);
  553. axesViewportChanging(zoomAndPan, "pan", e, calcOffsetForDrag, function(e) {
  554. return e.offset
  555. })
  556. }).on(SCROLL_BAR_END_EVENT_NAME, function(e) {
  557. preventDefaults(e);
  558. finishAxesViewportChanging(zoomAndPan, "pan", e, calcOffsetForDrag);
  559. zoomAndPan.actionData = null
  560. })
  561. }
  562. },
  563. defineTouchBehavior: function(isDefault, e) {
  564. zoomAndPan.actionData && (zoomAndPan.actionData.isNative = isDefault);
  565. if (!isDefault) {
  566. preventDefaults(e)
  567. }
  568. },
  569. panningVisualRangeEnabled: function(targetAxes) {
  570. if (targetAxes && targetAxes.length) {
  571. return targetAxes.some(function(axis) {
  572. return !axis.isExtremePosition(false) || !axis.isExtremePosition(true)
  573. })
  574. }
  575. var enablePanByValueAxis = chart._valueAxes.some(function(axis) {
  576. return !axis.isExtremePosition(false) || !axis.isExtremePosition(true)
  577. });
  578. var enablePanByArgumentAxis = chart._argumentAxes.some(function(axis) {
  579. return !axis.isExtremePosition(false) || !axis.isExtremePosition(true)
  580. });
  581. return enablePanByValueAxis || enablePanByArgumentAxis
  582. }
  583. };
  584. this._zoomAndPan = zoomAndPan
  585. },
  586. members: {
  587. _setupZoomAndPan: function() {
  588. this._zoomAndPan.setup(this._themeManager.getOptions("zoomAndPan"))
  589. }
  590. },
  591. dispose: function() {
  592. this._zoomAndPan.cleanup()
  593. },
  594. customize: function(constructor) {
  595. constructor.addChange({
  596. code: "ZOOM_AND_PAN",
  597. handler: function() {
  598. this._setupZoomAndPan()
  599. },
  600. isThemeDependent: true,
  601. isOptionChange: true,
  602. option: "zoomAndPan"
  603. })
  604. }
  605. };