@thewhitehaven04/chartjs-plugin-zoom 2.2.9 → 2.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/package.json +5 -5
  2. package/dist/@thewhitehaven04/chartjs-plugin-zoom.esm.js +0 -1172
  3. package/dist/@thewhitehaven04/chartjs-plugin-zoom.esm.js.map +0 -1
  4. package/dist/@thewhitehaven04/chartjs-plugin-zoom.js +0 -1179
  5. package/dist/@thewhitehaven04/chartjs-plugin-zoom.js.map +0 -1
  6. package/dist/@thewhitehaven04/chartjs-plugin-zoom.min.js +0 -8
  7. package/dist/@thewhitehaven04/chartjs-plugin-zoom.min.js.map +0 -1
  8. package/dist/src/core.d.ts +0 -24
  9. package/dist/src/core.d.ts.map +0 -1
  10. package/dist/src/defaults.d.ts +0 -3
  11. package/dist/src/defaults.d.ts.map +0 -1
  12. package/dist/src/hammer.d.ts +0 -6
  13. package/dist/src/hammer.d.ts.map +0 -1
  14. package/dist/src/handlers.d.ts +0 -24
  15. package/dist/src/handlers.d.ts.map +0 -1
  16. package/dist/src/index.d.ts +0 -31
  17. package/dist/src/index.d.ts.map +0 -1
  18. package/dist/src/index.umd.d.ts +0 -3
  19. package/dist/src/index.umd.d.ts.map +0 -1
  20. package/dist/src/options.d.ts +0 -196
  21. package/dist/src/options.d.ts.map +0 -1
  22. package/dist/src/plugin.d.ts +0 -25
  23. package/dist/src/plugin.d.ts.map +0 -1
  24. package/dist/src/scale.types.d.ts +0 -12
  25. package/dist/src/scale.types.d.ts.map +0 -1
  26. package/dist/src/scale.types.test.d.ts +0 -2
  27. package/dist/src/scale.types.test.d.ts.map +0 -1
  28. package/dist/src/state.d.ts +0 -53
  29. package/dist/src/state.d.ts.map +0 -1
  30. package/dist/src/types.d.ts +0 -11
  31. package/dist/src/types.d.ts.map +0 -1
  32. package/dist/src/utils.d.ts +0 -14
  33. package/dist/src/utils.d.ts.map +0 -1
  34. package/dist/src/utils.test.d.ts +0 -2
  35. package/dist/src/utils.test.d.ts.map +0 -1
@@ -1,1179 +0,0 @@
1
- /*!
2
- * @thewhitehaven04/chartjs-plugin-zoom v2.2.7
3
- * https://www.chartjs.org/chartjs-plugin-zoom/2.2.7/
4
- * (c) 2016-2026 chartjs-plugin-zoom Contributors
5
- * Released under the MIT License
6
- */
7
- (function (global, factory) {
8
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('chart.js'), require('hammerjs'), require('chart.js/helpers')) :
9
- typeof define === 'function' && define.amd ? define(['chart.js', 'hammerjs', 'chart.js/helpers'], factory) :
10
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.ChartZoom = factory(global.Chart, global.Hammer, global.Chart.helpers));
11
- })(this, (function (chart_js, Hammer, helpers) { 'use strict';
12
-
13
- const eventKey = (key)=>`${key}Key`;
14
- const getModifierKey = (opts)=>opts?.enabled && opts.modifierKey ? opts.modifierKey : undefined;
15
- const keyPressed = (key, event)=>key && event[eventKey(key)];
16
- const keyNotPressed = (key, event)=>key && !event[eventKey(key)];
17
- function directionEnabled(mode, dir, chart) {
18
- if (mode === undefined) {
19
- return true;
20
- } else if (typeof mode === 'string') {
21
- return mode.indexOf(dir) !== -1;
22
- } else if (typeof mode === 'function') {
23
- return mode({
24
- chart
25
- }).indexOf(dir) !== -1;
26
- }
27
- return false;
28
- }
29
- function directionsEnabled(mode, chart) {
30
- if (typeof mode === 'function') {
31
- mode = mode({
32
- chart
33
- });
34
- }
35
- if (typeof mode === 'string') {
36
- return {
37
- x: mode.indexOf('x') !== -1,
38
- y: mode.indexOf('y') !== -1
39
- };
40
- }
41
- return {
42
- x: false,
43
- y: false
44
- };
45
- }
46
- function debounce(fn, delay) {
47
- let timeout;
48
- return function() {
49
- clearTimeout(timeout);
50
- timeout = setTimeout(fn, delay);
51
- return delay;
52
- };
53
- }
54
- function getScaleUnderPoint({ x, y }, chart) {
55
- const scales = chart.scales;
56
- const scaleIds = Object.keys(scales);
57
- for(let i = 0; i < scaleIds.length; i++){
58
- const scale = scales[scaleIds[i]];
59
- if (y >= scale.top && y <= scale.bottom && x >= scale.left && x <= scale.right) {
60
- return scale;
61
- }
62
- }
63
- return null;
64
- }
65
- const convertOverScaleMode = (chart, overScaleMode, scaleEnabled, enabled)=>{
66
- if (!overScaleMode) {
67
- return;
68
- }
69
- const overScaleEnabled = directionsEnabled(overScaleMode, chart);
70
- for (const axis of [
71
- 'x',
72
- 'y'
73
- ]){
74
- if (overScaleEnabled[axis]) {
75
- scaleEnabled[axis] = enabled[axis];
76
- enabled[axis] = false;
77
- }
78
- }
79
- };
80
- const getEnabledScales = (chart, enabled)=>{
81
- const enabledScales = [];
82
- for (const scaleItem of Object.values(chart.scales)){
83
- if (enabled[scaleItem.axis]) {
84
- enabledScales.push(scaleItem);
85
- }
86
- }
87
- return enabledScales || Object.values(chart.scales);
88
- };
89
- function getEnabledScalesByPoint(options, point, chart) {
90
- const { mode = 'xy', scaleMode, overScaleMode } = options || {};
91
- const scale = getScaleUnderPoint(point, chart);
92
- const enabled = directionsEnabled(mode, chart);
93
- const scaleEnabled = directionsEnabled(scaleMode, chart);
94
- convertOverScaleMode(chart, overScaleMode, scaleEnabled, enabled);
95
- if (scale && scaleEnabled[scale.axis]) {
96
- return [
97
- scale
98
- ];
99
- }
100
- return getEnabledScales(chart, enabled);
101
- }
102
-
103
- const chartStates = new WeakMap();
104
- function getState(chart) {
105
- let state = chartStates.get(chart);
106
- if (!state) {
107
- state = {
108
- originalScaleLimits: {},
109
- updatedScaleLimits: {},
110
- handlers: {},
111
- options: {},
112
- targets: {},
113
- panDelta: {},
114
- dragging: false,
115
- panning: false
116
- };
117
- chartStates.set(chart, state);
118
- }
119
- return state;
120
- }
121
- function removeState(chart) {
122
- chartStates.delete(chart);
123
- }
124
-
125
- const isTimeScale = (scale)=>scale.type === 'time';
126
- const isNotNumber = (value)=>value === undefined || isNaN(value);
127
- function zoomDelta(val, min, range, newRange) {
128
- const minPercent = range && helpers.isNumber(val) && helpers.isNumber(min) ? Math.max(0, Math.min(1, (val - min) / range)) : 0;
129
- const maxPercent = 1 - minPercent;
130
- return {
131
- min: newRange * minPercent,
132
- max: newRange * maxPercent
133
- };
134
- }
135
- function getValueAtPoint(scale, point) {
136
- const pixel = scale.isHorizontal() ? point.x : point.y;
137
- return scale.getValueForPixel(pixel);
138
- }
139
- function linearZoomDelta(scale, zoom, center) {
140
- const range = scale.max - scale.min;
141
- const newRange = range * (zoom - 1);
142
- const centerValue = getValueAtPoint(scale, center);
143
- return zoomDelta(centerValue, scale.min, range, newRange);
144
- }
145
- function logarithmicZoomRange(scale, zoom, center) {
146
- const centerValue = getValueAtPoint(scale, center);
147
- if (centerValue === undefined) {
148
- return {
149
- min: scale.min,
150
- max: scale.max
151
- };
152
- }
153
- const logMin = Math.log10(scale.min);
154
- const logMax = Math.log10(scale.max);
155
- const logCenter = Math.log10(centerValue);
156
- const logRange = logMax - logMin;
157
- const newLogRange = logRange * (zoom - 1);
158
- const delta = zoomDelta(logCenter, logMin, logRange, newLogRange);
159
- return {
160
- min: Math.pow(10, logMin + delta.min),
161
- max: Math.pow(10, logMax - delta.max)
162
- };
163
- }
164
- function getScaleLimits(scale, limits) {
165
- return limits?.[scale.id] || limits?.[scale.axis] || {};
166
- }
167
- function getLimit(state, scale, scaleLimits, prop, fallback) {
168
- let limit = scaleLimits[prop];
169
- if (limit === 'original') {
170
- const original = state.originalScaleLimits[scale.id][prop];
171
- if (helpers.isNumber(original.options)) {
172
- return original.options;
173
- }
174
- if (!helpers.isNullOrUndef(original.options)) {
175
- const parsed = scale.parse(original.options);
176
- if (helpers.isNumber(parsed)) {
177
- return parsed;
178
- }
179
- }
180
- limit = original.scale;
181
- }
182
- return helpers.valueOrDefault(limit, fallback);
183
- }
184
- function linearRange(scale, pixel0, pixel1) {
185
- const v0 = scale.getValueForPixel(pixel0) ?? scale.min;
186
- const v1 = scale.getValueForPixel(pixel1) ?? scale.max;
187
- return {
188
- min: Math.min(v0, v1),
189
- max: Math.max(v0, v1)
190
- };
191
- }
192
- function fixRange(range, { min, max, minLimit, maxLimit }, state, scale) {
193
- const offset = (range - max + min) / 2;
194
- min -= offset;
195
- max += offset;
196
- const origLimits = {
197
- min: 'original',
198
- max: 'original'
199
- };
200
- const origMin = getLimit(state, scale, origLimits, 'min', -Infinity);
201
- const origMax = getLimit(state, scale, origLimits, 'max', Infinity);
202
- const epsilon = range / 1e6;
203
- if (helpers.almostEquals(min, origMin, epsilon)) {
204
- min = origMin;
205
- }
206
- if (helpers.almostEquals(max, origMax, epsilon)) {
207
- max = origMax;
208
- }
209
- if (min < minLimit) {
210
- min = minLimit;
211
- max = Math.min(minLimit + range, maxLimit);
212
- } else if (max > maxLimit) {
213
- max = maxLimit;
214
- min = Math.max(maxLimit - range, minLimit);
215
- }
216
- return {
217
- min,
218
- max
219
- };
220
- }
221
- function updateRange(scale, { min, max }, limits, zoom = false, pan = false) {
222
- const state = getState(scale.chart);
223
- const { options: scaleOpts } = scale;
224
- const scaleLimits = getScaleLimits(scale, limits);
225
- const { minRange = 0 } = scaleLimits;
226
- const minLimit = getLimit(state, scale, scaleLimits, 'min', -Infinity);
227
- const maxLimit = getLimit(state, scale, scaleLimits, 'max', Infinity);
228
- if (pan && (min < minLimit || max > maxLimit)) {
229
- return true;
230
- }
231
- const scaleRange = scale.max - scale.min;
232
- const range = zoom ? Math.max(max - min, minRange) : scaleRange;
233
- if (zoom && range === minRange && scaleRange <= minRange) {
234
- return true;
235
- }
236
- const newRange = fixRange(range, {
237
- min,
238
- max,
239
- minLimit,
240
- maxLimit
241
- }, state, scale);
242
- scaleOpts.min = newRange.min;
243
- scaleOpts.max = newRange.max;
244
- state.updatedScaleLimits[scale.id] = newRange;
245
- return scale.parse(newRange.min) !== scale.min || scale.parse(newRange.max) !== scale.max;
246
- }
247
- function zoomNumericalScale(scale, zoom, center, limits) {
248
- const delta = linearZoomDelta(scale, zoom, center);
249
- const newRange = {
250
- min: scale.min + delta.min,
251
- max: scale.max - delta.max
252
- };
253
- return updateRange(scale, newRange, limits, true);
254
- }
255
- function zoomLogarithmicScale(scale, zoom, center, limits) {
256
- const newRange = logarithmicZoomRange(scale, zoom, center);
257
- return updateRange(scale, newRange, limits, true);
258
- }
259
- function zoomRectNumericalScale(scale, from, to, limits) {
260
- return updateRange(scale, linearRange(scale, from, to), limits, true);
261
- }
262
- const integerChange = (v)=>v === 0 || isNaN(v) ? 0 : v < 0 ? Math.min(Math.round(v), -1) : Math.max(Math.round(v), 1);
263
- function existCategoryFromMaxZoom(scale) {
264
- const labels = scale.getLabels();
265
- const maxIndex = labels.length - 1;
266
- if (scale.min > 0) {
267
- scale.min -= 1;
268
- }
269
- if (scale.max < maxIndex) {
270
- scale.max += 1;
271
- }
272
- }
273
- function zoomCategoryScale(scale, zoom, center, limits) {
274
- const delta = linearZoomDelta(scale, zoom, center);
275
- if (scale.min === scale.max && zoom < 1) {
276
- existCategoryFromMaxZoom(scale);
277
- }
278
- const newRange = {
279
- min: scale.min + integerChange(delta.min),
280
- max: scale.max - integerChange(delta.max)
281
- };
282
- return updateRange(scale, newRange, limits, true);
283
- }
284
- function scaleLength(scale) {
285
- return scale.isHorizontal() ? scale.width : scale.height;
286
- }
287
- function panCategoryScale(scale, delta, limits) {
288
- const labels = scale.getLabels();
289
- const lastLabelIndex = labels.length - 1;
290
- let { min, max } = scale;
291
- const range = Math.max(max - min, 1);
292
- const stepDelta = Math.round(scaleLength(scale) / Math.max(range, 10));
293
- const stepSize = Math.round(Math.abs(delta / stepDelta));
294
- let applied;
295
- if (delta < -stepDelta) {
296
- max = Math.min(max + stepSize, lastLabelIndex);
297
- min = range === 1 ? max : max - range;
298
- applied = max === lastLabelIndex;
299
- } else if (delta > stepDelta) {
300
- min = Math.max(0, min - stepSize);
301
- max = range === 1 ? min : min + range;
302
- applied = min === 0;
303
- }
304
- return updateRange(scale, {
305
- min,
306
- max
307
- }, limits) || Boolean(applied);
308
- }
309
- const OFFSETS = {
310
- millisecond: 0,
311
- second: 500,
312
- minute: 30 * 1000,
313
- hour: 30 * 60 * 1000,
314
- day: 12 * 60 * 60 * 1000,
315
- week: 3.5 * 24 * 60 * 60 * 1000,
316
- month: 15 * 24 * 60 * 60 * 1000,
317
- quarter: 60 * 24 * 60 * 60 * 1000,
318
- year: 182 * 24 * 60 * 60 * 1000
319
- };
320
- function panNumericalScale(scale, delta, limits, canZoom = false) {
321
- const { min: prevStart, max: prevEnd } = scale;
322
- let offset = 0;
323
- if (isTimeScale(scale)) {
324
- const round = scale.options.time?.round;
325
- offset = round ? OFFSETS[round] : 0;
326
- }
327
- const newMin = scale.getValueForPixel(scale.getPixelForValue(prevStart + offset) - delta);
328
- const newMax = scale.getValueForPixel(scale.getPixelForValue(prevEnd + offset) - delta);
329
- if (isNotNumber(newMin) || isNotNumber(newMax)) {
330
- return true;
331
- }
332
- return updateRange(scale, {
333
- min: newMin,
334
- max: newMax
335
- }, limits, canZoom, true);
336
- }
337
- function panNonLinearScale(scale, delta, limits) {
338
- return panNumericalScale(scale, delta, limits, true);
339
- }
340
- const zoomFunctions = {
341
- category: zoomCategoryScale,
342
- default: zoomNumericalScale,
343
- logarithmic: zoomLogarithmicScale
344
- };
345
- const zoomRectFunctions = {
346
- default: zoomRectNumericalScale
347
- };
348
- const panFunctions = {
349
- category: panCategoryScale,
350
- default: panNumericalScale,
351
- logarithmic: panNonLinearScale,
352
- timeseries: panNonLinearScale
353
- };
354
-
355
- function shouldUpdateScaleLimits(scale, originalScaleLimits, updatedScaleLimits) {
356
- const { id, options: { min, max } } = scale;
357
- if (!originalScaleLimits[id] || !updatedScaleLimits[id]) {
358
- return true;
359
- }
360
- const previous = updatedScaleLimits[id];
361
- return previous.min !== min || previous.max !== max;
362
- }
363
- function removeMissingScales(limits, scales) {
364
- for (const key of Object.keys(limits)){
365
- if (!scales[key]) {
366
- delete limits[key];
367
- }
368
- }
369
- }
370
- function storeOriginalScaleLimits(chart, state) {
371
- const { scales } = chart;
372
- const { originalScaleLimits, updatedScaleLimits } = state;
373
- for (const scale of Object.values(scales)){
374
- if (shouldUpdateScaleLimits(scale, originalScaleLimits, updatedScaleLimits)) {
375
- originalScaleLimits[scale.id] = {
376
- min: {
377
- scale: scale.min,
378
- options: scale.options.min
379
- },
380
- max: {
381
- scale: scale.max,
382
- options: scale.options.max
383
- }
384
- };
385
- }
386
- }
387
- removeMissingScales(originalScaleLimits, scales);
388
- removeMissingScales(updatedScaleLimits, scales);
389
- return originalScaleLimits;
390
- }
391
- function doZoom(scale, amount, center, limits) {
392
- const fn = zoomFunctions[scale.type] || zoomFunctions.default;
393
- fn?.(scale, amount, center, limits);
394
- }
395
- function doZoomRect(scale, from, to, limits) {
396
- const fn = zoomRectFunctions[scale.type] || zoomRectFunctions.default;
397
- fn?.(scale, from, to, limits);
398
- }
399
- function getCenter(chart) {
400
- const ca = chart.chartArea;
401
- return {
402
- x: (ca.left + ca.right) / 2,
403
- y: (ca.top + ca.bottom) / 2
404
- };
405
- }
406
- function zoom(chart, amount, transition = 'none', trigger = 'api') {
407
- const { x = 1, y = 1, focalPoint = getCenter(chart) } = typeof amount === 'number' ? {
408
- x: amount,
409
- y: amount
410
- } : amount;
411
- const state = getState(chart);
412
- const { options: { limits = {}, zoom: zoomOptions } } = state;
413
- storeOriginalScaleLimits(chart, state);
414
- const xEnabled = x !== 1;
415
- const yEnabled = y !== 1;
416
- const enabledScales = getEnabledScalesByPoint(zoomOptions, focalPoint, chart);
417
- for (const scale of enabledScales){
418
- if (scale.isHorizontal() && xEnabled) {
419
- doZoom(scale, x, focalPoint, limits);
420
- } else if (!scale.isHorizontal() && yEnabled) {
421
- doZoom(scale, y, focalPoint, limits);
422
- }
423
- }
424
- chart.update(transition);
425
- zoomOptions?.onZoom?.({
426
- chart,
427
- trigger,
428
- amount: {
429
- x,
430
- y,
431
- focalPoint
432
- }
433
- });
434
- }
435
- function zoomRect(chart, p0, p1, transition = 'none', trigger = 'api') {
436
- const state = getState(chart);
437
- const { options: { limits = {}, zoom: zoomOptions = {} } } = state;
438
- const { mode = 'xy' } = zoomOptions;
439
- storeOriginalScaleLimits(chart, state);
440
- const xEnabled = directionEnabled(mode, 'x', chart);
441
- const yEnabled = directionEnabled(mode, 'y', chart);
442
- for (const scale of Object.values(chart.scales)){
443
- if (scale.isHorizontal() && xEnabled) {
444
- doZoomRect(scale, p0.x, p1.x, limits);
445
- } else if (!scale.isHorizontal() && yEnabled) {
446
- doZoomRect(scale, p0.y, p1.y, limits);
447
- }
448
- }
449
- chart.update(transition);
450
- zoomOptions.onZoom?.({
451
- chart,
452
- trigger
453
- });
454
- }
455
- function zoomScale(chart, scaleId, range, transition = 'none', trigger = 'api') {
456
- const state = getState(chart);
457
- storeOriginalScaleLimits(chart, state);
458
- const scale = chart.scales[scaleId];
459
- updateRange(scale, range, undefined, true);
460
- chart.update(transition);
461
- state.options.zoom?.onZoom?.({
462
- chart,
463
- trigger
464
- });
465
- }
466
- function resetZoom(chart, transition = 'default') {
467
- const state = getState(chart);
468
- const originalScaleLimits = storeOriginalScaleLimits(chart, state);
469
- for (const scale of Object.values(chart.scales)){
470
- const scaleOptions = scale.options;
471
- if (originalScaleLimits[scale.id]) {
472
- scaleOptions.min = originalScaleLimits[scale.id].min.options;
473
- scaleOptions.max = originalScaleLimits[scale.id].max.options;
474
- } else {
475
- delete scaleOptions.min;
476
- delete scaleOptions.max;
477
- }
478
- delete state.updatedScaleLimits[scale.id];
479
- }
480
- chart.update(transition);
481
- state.options.zoom?.onZoomComplete?.({
482
- chart
483
- });
484
- }
485
- function getOriginalRange(state, scaleId) {
486
- const original = state.originalScaleLimits[scaleId];
487
- if (!original) {
488
- return undefined;
489
- }
490
- const { min, max } = original;
491
- if (helpers.isNumber(max.options) && helpers.isNumber(min.options)) {
492
- return max.options - min.options;
493
- }
494
- if (helpers.isNumber(max.scale) && helpers.isNumber(min.scale)) {
495
- return max.scale - min.scale;
496
- }
497
- return undefined;
498
- }
499
- function getZoomLevel(chart) {
500
- const state = getState(chart);
501
- let min = 1;
502
- let max = 1;
503
- for (const scale of Object.values(chart.scales)){
504
- const origRange = getOriginalRange(state, scale.id);
505
- if (origRange) {
506
- const level = Math.round(origRange / (scale.max - scale.min) * 100) / 100;
507
- min = Math.min(min, level);
508
- max = Math.max(max, level);
509
- }
510
- }
511
- return min < 1 ? min : max;
512
- }
513
- function panScale(scale, delta, limits, state) {
514
- const { panDelta } = state;
515
- const storedDelta = panDelta[scale.id] || 0;
516
- if (helpers.sign(storedDelta) === helpers.sign(delta)) {
517
- delta += storedDelta;
518
- }
519
- const fn = panFunctions[scale.type] || panFunctions.default;
520
- if (fn?.(scale, delta, limits)) {
521
- panDelta[scale.id] = 0;
522
- } else {
523
- panDelta[scale.id] = delta;
524
- }
525
- }
526
- function pan(chart, delta, enabledScales, transition = 'none', trigger = 'other') {
527
- const { x = 0, y = 0 } = typeof delta === 'number' ? {
528
- x: delta,
529
- y: delta
530
- } : delta;
531
- const state = getState(chart);
532
- const { options: { pan: panOptions, limits = {} } } = state;
533
- const { onPan } = panOptions || {};
534
- storeOriginalScaleLimits(chart, state);
535
- const xEnabled = x !== 0;
536
- const yEnabled = y !== 0;
537
- const scales = enabledScales || Object.values(chart.scales);
538
- for (const scale of scales){
539
- if (scale.isHorizontal() && xEnabled) {
540
- panScale(scale, x, limits, state);
541
- } else if (!scale.isHorizontal() && yEnabled) {
542
- panScale(scale, y, limits, state);
543
- }
544
- }
545
- chart.update(transition);
546
- onPan?.({
547
- chart,
548
- trigger,
549
- delta: {
550
- x,
551
- y
552
- }
553
- });
554
- }
555
- function getInitialScaleBounds(chart) {
556
- const state = getState(chart);
557
- storeOriginalScaleLimits(chart, state);
558
- const scaleBounds = {};
559
- for (const scaleId of Object.keys(chart.scales)){
560
- const { min, max } = state.originalScaleLimits[scaleId] || {
561
- min: {},
562
- max: {}
563
- };
564
- scaleBounds[scaleId] = {
565
- min: min.scale,
566
- max: max.scale
567
- };
568
- }
569
- return scaleBounds;
570
- }
571
- function getZoomedScaleBounds(chart) {
572
- const state = getState(chart);
573
- const scaleBounds = {};
574
- for (const scaleId of Object.keys(chart.scales)){
575
- scaleBounds[scaleId] = state.updatedScaleLimits[scaleId];
576
- }
577
- return scaleBounds;
578
- }
579
- function isZoomedOrPanned(chart) {
580
- const scaleBounds = getInitialScaleBounds(chart);
581
- for (const scaleId of Object.keys(chart.scales)){
582
- const { min: originalMin, max: originalMax } = scaleBounds[scaleId];
583
- if (originalMin !== undefined && chart.scales[scaleId].min !== originalMin) {
584
- return true;
585
- }
586
- if (originalMax !== undefined && chart.scales[scaleId].max !== originalMax) {
587
- return true;
588
- }
589
- }
590
- return false;
591
- }
592
- function isZoomingOrPanningState(state) {
593
- return state.panning || state.dragging;
594
- }
595
- function isZoomingOrPanning(chart) {
596
- const state = getState(chart);
597
- return !!(isZoomingOrPanningState(state) || state.filterNextClick);
598
- }
599
-
600
- const clamp = (x, from, to)=>Math.min(to, Math.max(from, x));
601
- function removeHandler(chart, type) {
602
- const { handlers, targets } = getState(chart);
603
- const handler = handlers[type];
604
- const target = targets[type];
605
- if (handler && target) {
606
- target.removeEventListener(type, handler);
607
- delete handlers[type];
608
- }
609
- }
610
- function addHandler(chart, target, type, handler) {
611
- const { handlers, options, targets } = getState(chart);
612
- const oldHandler = handlers[type];
613
- if (oldHandler && targets[type] === target) {
614
- return;
615
- }
616
- removeHandler(chart, type);
617
- const listener = handlers[type] = (event)=>handler(chart, event, options);
618
- targets[type] = target;
619
- const passive = type === 'wheel' ? false : undefined;
620
- target.addEventListener(type, listener, {
621
- passive
622
- });
623
- }
624
- function mouseMove(chart, event) {
625
- const state = getState(chart);
626
- if (state.dragStart) {
627
- state.dragging = true;
628
- state.dragEnd = event;
629
- chart.draw();
630
- }
631
- }
632
- function keyDown(chart, event) {
633
- const state = getState(chart);
634
- if (!state.dragStart || event.key !== 'Escape') {
635
- return;
636
- }
637
- removeHandler(chart, 'keydown');
638
- state.dragging = false;
639
- state.dragStart = state.dragEnd = undefined;
640
- chart.draw();
641
- }
642
- function getPointPosition(event, chart) {
643
- if (event.target !== chart.canvas) {
644
- const canvasArea = chart.canvas.getBoundingClientRect();
645
- return {
646
- x: event.clientX - canvasArea.left,
647
- y: event.clientY - canvasArea.top
648
- };
649
- }
650
- return helpers.getRelativePosition(event, chart)
651
- ;
652
- }
653
- function zoomStart(chart, event, zoomOptions) {
654
- const { onZoomStart, onZoomRejected } = zoomOptions;
655
- if (onZoomStart) {
656
- const point = getPointPosition(event, chart);
657
- if (onZoomStart?.({
658
- chart,
659
- event,
660
- point
661
- }) === false) {
662
- onZoomRejected?.({
663
- chart,
664
- event
665
- });
666
- return false;
667
- }
668
- }
669
- }
670
- function mouseDown(chart, event) {
671
- if (chart.legend) {
672
- const point = helpers.getRelativePosition(event, chart)
673
- ;
674
- if (helpers._isPointInArea(point, chart.legend)) {
675
- return;
676
- }
677
- }
678
- const state = getState(chart);
679
- const { pan: panOptions, zoom: zoomOptions = {} } = state.options;
680
- if (event.button !== 0 || keyPressed(getModifierKey(panOptions), event) || keyNotPressed(getModifierKey(zoomOptions.drag), event)) {
681
- return zoomOptions.onZoomRejected?.({
682
- chart,
683
- event
684
- });
685
- }
686
- if (zoomStart(chart, event, zoomOptions) === false) {
687
- return;
688
- }
689
- state.dragStart = event;
690
- addHandler(chart, chart.canvas.ownerDocument, 'mousemove', mouseMove);
691
- addHandler(chart, window.document, 'keydown', keyDown);
692
- }
693
- function applyAspectRatio({ begin, end }, aspectRatio) {
694
- let width = end.x - begin.x;
695
- let height = end.y - begin.y;
696
- const ratio = Math.abs(width / height);
697
- if (ratio > aspectRatio) {
698
- width = Math.sign(width) * Math.abs(height * aspectRatio);
699
- } else if (ratio < aspectRatio) {
700
- height = Math.sign(height) * Math.abs(width / aspectRatio);
701
- }
702
- end.x = begin.x + width;
703
- end.y = begin.y + height;
704
- }
705
- function applyMinMaxProps(rect, chartArea, points, { min, max, prop }) {
706
- rect[min] = clamp(Math.min(points.begin[prop], points.end[prop]), chartArea[min], chartArea[max]);
707
- rect[max] = clamp(Math.max(points.begin[prop], points.end[prop]), chartArea[min], chartArea[max]);
708
- }
709
- function getRelativePoints(chart, pointEvents, maintainAspectRatio) {
710
- const points = {
711
- begin: getPointPosition(pointEvents.dragStart, chart),
712
- end: getPointPosition(pointEvents.dragEnd, chart)
713
- };
714
- if (maintainAspectRatio) {
715
- const aspectRatio = chart.chartArea.width / chart.chartArea.height;
716
- applyAspectRatio(points, aspectRatio);
717
- }
718
- return points;
719
- }
720
- function computeDragRect(chart, mode, pointEvents, maintainAspectRatio) {
721
- const xEnabled = directionEnabled(mode, 'x', chart);
722
- const yEnabled = directionEnabled(mode, 'y', chart);
723
- const { top, left, right, bottom, width: chartWidth, height: chartHeight } = chart.chartArea;
724
- const rect = {
725
- top,
726
- left,
727
- right,
728
- bottom
729
- };
730
- const points = getRelativePoints(chart, pointEvents, maintainAspectRatio && xEnabled && yEnabled);
731
- if (xEnabled) {
732
- applyMinMaxProps(rect, chart.chartArea, points, {
733
- min: 'left',
734
- max: 'right',
735
- prop: 'x'
736
- });
737
- }
738
- if (yEnabled) {
739
- applyMinMaxProps(rect, chart.chartArea, points, {
740
- min: 'top',
741
- max: 'bottom',
742
- prop: 'y'
743
- });
744
- }
745
- const width = rect.right - rect.left;
746
- const height = rect.bottom - rect.top;
747
- return {
748
- ...rect,
749
- width,
750
- height,
751
- zoomX: xEnabled && width ? 1 + (chartWidth - width) / chartWidth : 1,
752
- zoomY: yEnabled && height ? 1 + (chartHeight - height) / chartHeight : 1
753
- };
754
- }
755
- function mouseUp(chart, event) {
756
- const state = getState(chart);
757
- if (!state.dragStart) {
758
- return;
759
- }
760
- removeHandler(chart, 'mousemove');
761
- const { mode, onZoomComplete, drag } = state.options.zoom ?? {};
762
- const { threshold = 0, maintainAspectRatio } = drag ?? {};
763
- const rect = computeDragRect(chart, mode, {
764
- dragStart: state.dragStart,
765
- dragEnd: event
766
- }, maintainAspectRatio);
767
- const distanceX = directionEnabled(mode, 'x', chart) ? rect.width : 0;
768
- const distanceY = directionEnabled(mode, 'y', chart) ? rect.height : 0;
769
- const distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
770
- state.dragStart = state.dragEnd = undefined;
771
- if (distance <= threshold) {
772
- state.dragging = false;
773
- chart.draw();
774
- return;
775
- }
776
- zoomRect(chart, {
777
- x: rect.left,
778
- y: rect.top
779
- }, {
780
- x: rect.right,
781
- y: rect.bottom
782
- }, 'zoom', 'drag');
783
- state.dragging = false;
784
- state.filterNextClick = true;
785
- onZoomComplete?.({
786
- chart
787
- });
788
- }
789
- function wheelPreconditions(chart, event, zoomOptions) {
790
- if (keyNotPressed(getModifierKey(zoomOptions.wheel), event)) {
791
- zoomOptions.onZoomRejected?.({
792
- chart,
793
- event
794
- });
795
- return;
796
- }
797
- if (zoomStart(chart, event, zoomOptions) === false) {
798
- return;
799
- }
800
- if (event.cancelable) {
801
- event.preventDefault();
802
- }
803
- if (event.deltaY === undefined) {
804
- return;
805
- }
806
- return true;
807
- }
808
- function wheel(chart, event) {
809
- const { handlers: { onZoomComplete }, options: { zoom: zoomOptions = {} } } = getState(chart);
810
- if (!wheelPreconditions(chart, event, zoomOptions)) {
811
- return;
812
- }
813
- const rect = event.target?.getBoundingClientRect();
814
- const speed = zoomOptions?.wheel?.speed ?? 0.1;
815
- const percentage = event.deltaY >= 0 ? 2 - 1 / (1 - speed) : 1 + speed;
816
- const amount = {
817
- x: percentage,
818
- y: percentage,
819
- focalPoint: {
820
- x: event.clientX - rect.left,
821
- y: event.clientY - rect.top
822
- }
823
- };
824
- zoom(chart, amount, 'zoom', 'wheel');
825
- onZoomComplete?.(event);
826
- }
827
- function addDebouncedHandler(chart, name, handler, delay) {
828
- if (handler) {
829
- getState(chart).handlers[name] = debounce(()=>handler?.({
830
- chart
831
- }), delay);
832
- }
833
- }
834
- function addListeners(chart, options) {
835
- const canvas = chart.canvas;
836
- const { wheel: wheelOptions, drag: dragOptions, onZoomComplete } = options.zoom ?? {};
837
- if (wheelOptions?.enabled) {
838
- addHandler(chart, canvas, 'wheel', wheel);
839
- addDebouncedHandler(chart, 'onZoomComplete', onZoomComplete, 250);
840
- } else {
841
- removeHandler(chart, 'wheel');
842
- }
843
- if (dragOptions?.enabled) {
844
- addHandler(chart, canvas, 'mousedown', mouseDown);
845
- addHandler(chart, canvas.ownerDocument, 'mouseup', mouseUp);
846
- } else {
847
- removeHandler(chart, 'mousedown');
848
- removeHandler(chart, 'mousemove');
849
- removeHandler(chart, 'mouseup');
850
- removeHandler(chart, 'keydown');
851
- }
852
- }
853
- function removeListeners(chart) {
854
- removeHandler(chart, 'mousedown');
855
- removeHandler(chart, 'mousemove');
856
- removeHandler(chart, 'mouseup');
857
- removeHandler(chart, 'wheel');
858
- removeHandler(chart, 'click');
859
- removeHandler(chart, 'keydown');
860
- }
861
-
862
- function createEnabler(chart, state) {
863
- return function(_recognizer, event) {
864
- const { pan: panOptions, zoom: zoomOptions = {} } = state.options;
865
- if (!panOptions || !panOptions.enabled) {
866
- return false;
867
- }
868
- const srcEvent = event && event.srcEvent;
869
- if (!srcEvent) {
870
- return true;
871
- }
872
- if (!state.panning && event.pointerType === 'mouse' && (keyNotPressed(getModifierKey(panOptions), srcEvent) || keyPressed(getModifierKey(zoomOptions.drag), srcEvent))) {
873
- panOptions.onPanRejected?.({
874
- chart,
875
- event
876
- });
877
- return false;
878
- }
879
- return true;
880
- };
881
- }
882
- function pinchAxes(p0, p1) {
883
- const pinchX = Math.abs(p0.clientX - p1.clientX);
884
- const pinchY = Math.abs(p0.clientY - p1.clientY);
885
- const p = pinchX / pinchY;
886
- let x, y;
887
- if (p > 0.3 && p < 1.7) {
888
- x = y = true;
889
- } else if (pinchX > pinchY) {
890
- x = true;
891
- } else {
892
- y = true;
893
- }
894
- return {
895
- x,
896
- y
897
- };
898
- }
899
- function handlePinch(chart, state, e) {
900
- if (state.scale) {
901
- const { center, pointers } = e;
902
- const zoomPercent = 1 / state.scale * e.scale;
903
- const rect = e.target.getBoundingClientRect();
904
- const pinch = pinchAxes(pointers[0], pointers[1]);
905
- const mode = state.options.zoom?.mode;
906
- const amount = {
907
- x: pinch.x && directionEnabled(mode, 'x', chart) ? zoomPercent : 1,
908
- y: pinch.y && directionEnabled(mode, 'y', chart) ? zoomPercent : 1,
909
- focalPoint: {
910
- x: center.x - rect.left,
911
- y: center.y - rect.top
912
- }
913
- };
914
- zoom(chart, amount, 'zoom', 'pinch');
915
- state.scale = e.scale;
916
- }
917
- }
918
- function startPinch(chart, state, e) {
919
- if (state.options.zoom?.pinch?.enabled) {
920
- const point = helpers.getRelativePosition(e.srcEvent, chart)
921
- ;
922
- if (state.options.zoom?.onZoomStart?.({
923
- chart,
924
- event: e.srcEvent,
925
- point
926
- }) === false) {
927
- state.scale = null;
928
- state.options.zoom?.onZoomRejected?.({
929
- chart,
930
- event: e.srcEvent
931
- });
932
- } else {
933
- state.scale = 1;
934
- }
935
- }
936
- }
937
- function endPinch(chart, state, e) {
938
- if (state.scale) {
939
- handlePinch(chart, state, e);
940
- state.scale = null
941
- ;
942
- state.options.zoom?.onZoomComplete?.({
943
- chart
944
- });
945
- }
946
- }
947
- function handlePan(chart, state, e) {
948
- const delta = state.delta;
949
- if (delta) {
950
- state.panning = true;
951
- pan(chart, {
952
- x: e.deltaX - delta.x,
953
- y: e.deltaY - delta.y
954
- }, state.panScales && state.panScales.map((i)=>chart.scales[i]).filter(Boolean));
955
- state.delta = {
956
- x: e.deltaX,
957
- y: e.deltaY
958
- };
959
- }
960
- }
961
- function startPan(chart, state, event) {
962
- const { enabled, onPanStart, onPanRejected } = state.options.pan ?? {};
963
- if (!enabled) {
964
- return;
965
- }
966
- const rect = event.target.getBoundingClientRect();
967
- const point = {
968
- x: event.center.x - rect.left,
969
- y: event.center.y - rect.top
970
- };
971
- if (onPanStart?.({
972
- chart,
973
- event,
974
- point
975
- }) === false) {
976
- return onPanRejected?.({
977
- chart,
978
- event
979
- });
980
- }
981
- state.panScales = getEnabledScalesByPoint(state.options.pan, point, chart).map((i)=>i.id);
982
- state.delta = {
983
- x: 0,
984
- y: 0
985
- };
986
- handlePan(chart, state, event);
987
- }
988
- function endPan(chart, state) {
989
- state.delta = null;
990
- if (state.panning) {
991
- state.panning = false;
992
- state.filterNextClick = true;
993
- state.options.pan?.onPanComplete?.({
994
- chart
995
- });
996
- }
997
- }
998
- const hammers = new WeakMap();
999
- function startHammer(chart, options) {
1000
- const state = getState(chart);
1001
- const canvas = chart.canvas;
1002
- const { pan: panOptions, zoom: zoomOptions } = options;
1003
- const mc = new Hammer.Manager(canvas);
1004
- if (zoomOptions?.pinch?.enabled) {
1005
- mc.add(new Hammer.Pinch());
1006
- mc.on('pinchstart', (e)=>startPinch(chart, state, e));
1007
- mc.on('pinch', (e)=>handlePinch(chart, state, e));
1008
- mc.on('pinchend', (e)=>endPinch(chart, state, e));
1009
- }
1010
- if (panOptions && panOptions.enabled) {
1011
- mc.add(new Hammer.Pan({
1012
- threshold: panOptions.threshold,
1013
- enable: createEnabler(chart, state)
1014
- }));
1015
- mc.on('panstart', (e)=>startPan(chart, state, e));
1016
- mc.on('panmove', (e)=>handlePan(chart, state, e));
1017
- mc.on('panend', ()=>endPan(chart, state));
1018
- }
1019
- hammers.set(chart, mc);
1020
- }
1021
- function stopHammer(chart) {
1022
- const mc = hammers.get(chart);
1023
- if (mc) {
1024
- mc.remove('pinchstart');
1025
- mc.remove('pinch');
1026
- mc.remove('pinchend');
1027
- mc.remove('panstart');
1028
- mc.remove('pan');
1029
- mc.remove('panend');
1030
- mc.destroy();
1031
- hammers.delete(chart);
1032
- }
1033
- }
1034
- function hammerOptionsChanged(oldOptions, newOptions) {
1035
- const { pan: oldPan, zoom: oldZoom } = oldOptions;
1036
- const { pan: newPan, zoom: newZoom } = newOptions;
1037
- if (oldZoom?.pinch?.enabled !== newZoom?.pinch?.enabled) {
1038
- return true;
1039
- }
1040
- if (oldPan?.enabled !== newPan?.enabled) {
1041
- return true;
1042
- }
1043
- if (oldPan?.threshold !== newPan?.threshold) {
1044
- return true;
1045
- }
1046
- return false;
1047
- }
1048
-
1049
- var version = "2.2.7";
1050
-
1051
- const defaults = {
1052
- pan: {
1053
- enabled: false,
1054
- mode: 'xy',
1055
- threshold: 10,
1056
- modifierKey: null
1057
- },
1058
- zoom: {
1059
- wheel: {
1060
- enabled: false,
1061
- speed: 0.1,
1062
- modifierKey: null
1063
- },
1064
- drag: {
1065
- enabled: false,
1066
- drawTime: 'beforeDatasetsDraw',
1067
- modifierKey: null
1068
- },
1069
- pinch: {
1070
- enabled: false
1071
- },
1072
- mode: 'xy'
1073
- }
1074
- };
1075
-
1076
- function draw(chart, caller, options) {
1077
- const dragOptions = options.zoom?.drag;
1078
- const { dragStart, dragEnd } = getState(chart);
1079
- if (dragOptions?.drawTime !== caller || !dragStart || !dragEnd) {
1080
- return;
1081
- }
1082
- const { left, top, width, height } = computeDragRect(chart, options.zoom?.mode, {
1083
- dragStart,
1084
- dragEnd
1085
- }, dragOptions.maintainAspectRatio);
1086
- const ctx = chart.ctx;
1087
- ctx.save();
1088
- ctx.beginPath();
1089
- ctx.fillStyle = dragOptions.backgroundColor || 'rgba(225,225,225,0.3)';
1090
- ctx.fillRect(left, top, width, height);
1091
- if (dragOptions.borderWidth) {
1092
- ctx.lineWidth = dragOptions.borderWidth;
1093
- ctx.strokeStyle = dragOptions.borderColor || 'rgba(225,225,225)';
1094
- ctx.strokeRect(left, top, width, height);
1095
- }
1096
- ctx.restore();
1097
- }
1098
- const bindApi = (chart)=>{
1099
- chart.pan = (delta, panScales, transition)=>pan(chart, delta, panScales, transition, 'api');
1100
- chart.zoom = (args, transition)=>zoom(chart, args, transition);
1101
- chart.zoomRect = (p0, p1, transition)=>zoomRect(chart, p0, p1, transition);
1102
- chart.zoomScale = (id, range, transition)=>zoomScale(chart, id, range, transition);
1103
- chart.resetZoom = (transition)=>resetZoom(chart, transition);
1104
- chart.getZoomLevel = ()=>getZoomLevel(chart);
1105
- chart.getInitialScaleBounds = ()=>getInitialScaleBounds(chart);
1106
- chart.getZoomedScaleBounds = ()=>getZoomedScaleBounds(chart);
1107
- chart.isZoomedOrPanned = ()=>isZoomedOrPanned(chart);
1108
- chart.isZoomingOrPanning = ()=>isZoomingOrPanning(chart);
1109
- };
1110
- var Zoom = {
1111
- id: 'zoom',
1112
- version,
1113
- defaults,
1114
- start (chart, _args, options) {
1115
- const state = getState(chart);
1116
- state.options = options;
1117
- if (Object.prototype.hasOwnProperty.call(options.zoom, 'enabled')) {
1118
- console.warn('The option `zoom.enabled` is no longer supported. Please use `zoom.wheel.enabled`, `zoom.drag.enabled`, or `zoom.pinch.enabled`.');
1119
- }
1120
- if (Object.prototype.hasOwnProperty.call(options.zoom, 'overScaleMode') || Object.prototype.hasOwnProperty.call(options.pan, 'overScaleMode')) {
1121
- console.warn('The option `overScaleMode` is deprecated. Please use `scaleMode` instead (and update `mode` as desired).');
1122
- }
1123
- if (Hammer) {
1124
- startHammer(chart, options);
1125
- }
1126
- bindApi(chart);
1127
- },
1128
- beforeEvent (chart, { event }) {
1129
- const state = getState(chart);
1130
- if (isZoomingOrPanningState(state)) {
1131
- return false;
1132
- }
1133
- if (event.type === 'click' || event.type === 'mouseup') {
1134
- if (state.filterNextClick) {
1135
- state.filterNextClick = false;
1136
- return false;
1137
- }
1138
- }
1139
- },
1140
- beforeUpdate (chart, _args, options) {
1141
- const state = getState(chart);
1142
- const previousOptions = state.options;
1143
- state.options = options;
1144
- if (hammerOptionsChanged(previousOptions, options)) {
1145
- stopHammer(chart);
1146
- startHammer(chart, options);
1147
- }
1148
- addListeners(chart, options);
1149
- },
1150
- beforeDatasetsDraw (chart, _args, options) {
1151
- draw(chart, 'beforeDatasetsDraw', options);
1152
- },
1153
- afterDatasetsDraw (chart, _args, options) {
1154
- draw(chart, 'afterDatasetsDraw', options);
1155
- },
1156
- beforeDraw (chart, _args, options) {
1157
- draw(chart, 'beforeDraw', options);
1158
- },
1159
- afterDraw (chart, _args, options) {
1160
- draw(chart, 'afterDraw', options);
1161
- },
1162
- stop (chart) {
1163
- removeListeners(chart);
1164
- if (Hammer) {
1165
- stopHammer(chart);
1166
- }
1167
- removeState(chart);
1168
- },
1169
- panFunctions,
1170
- zoomFunctions,
1171
- zoomRectFunctions
1172
- };
1173
-
1174
- chart_js.Chart.register(Zoom);
1175
-
1176
- return Zoom;
1177
-
1178
- }));
1179
- //# sourceMappingURL=chartjs-plugin-zoom.js.map