Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Export zoomRect and make it more configurable #659

Merged
merged 6 commits into from Sep 1, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 7 additions & 2 deletions docs/guide/developers.md
Expand Up @@ -57,17 +57,22 @@ MyScale.id = 'myScale';
MyScale.defaults = defaultConfigObject;

zoomPlugin.zoomFunctions.myScale = (scale, zoom, center, limits) => false;
zoomPlugin.zoomRectFunctions.myScale = (scale, from, to, limits) => false;
zoomPlugin.panFunctions.myScale = (scale, delta, limits) => false;
// zoomRectFunctions can normally be omitted; chartjs-plugin-zoom can translate
// to an equivalent zoomFunctions call.
```

The zoom and pan functions take the following arguments:
The zoom, zoomRect, and pan functions take the following arguments:

| Name | Type | For | Description
| ---- | ---- | --- | ----------
| `scale` | `Scale` | Zoom, Pan | The custom scale instance (usually derived from `Chart.Scale`)
| `zoom` | `number` | Zoom | The zoom fraction; 1.0 is unzoomed, 0.5 means zoomed in to 50% of the original area, etc.
| `center` | `{x, y}` | Zoom | Pixel coordinates of the center of the zoom operation. `{x: 0, y: 0}` is the upper left corner of the chart's canvas.
| `from` | `number` | ZoomRect | Pixel coordinate of the start of the zoomRect operation.
| `to` | `number` | ZoomRect | Pixel coordinate of the end of the zoomRect operation.
| `delta` | `number` | Pan | Pixel amount to pan by
| `limits` | [Limits](./options#limits) | Zoom, Pan | Zoom and pan limits (from chart options)

For examples, see chartjs-plugin-zoom's [default zoomFunctions and panFunctions handling for standard Chart.js axes](https://github.com/chartjs/chartjs-plugin-zoom/blob/v1.0.1/src/scale.types.js#L128).
For examples, see chartjs-plugin-zoom's [default zoomFunctions, zoomRectFunctions, and panFunctions handling for standard Chart.js axes](https://github.com/chartjs/chartjs-plugin-zoom/blob/v1.0.1/src/scale.types.js#L128).
20 changes: 8 additions & 12 deletions src/core.js
@@ -1,5 +1,5 @@
import {each, callback as call, sign, valueOrDefault} from 'chart.js/helpers';
import {panFunctions, updateRange, zoomFunctions} from './scale.types';
import {panFunctions, updateRange, zoomFunctions, zoomRectFunctions} from './scale.types';
import {getState} from './state';
import {directionEnabled, getEnabledScalesByPoint} from './utils';

Expand Down Expand Up @@ -43,6 +43,11 @@ function doZoom(scale, amount, center, limits) {
call(fn, [scale, amount, center, limits]);
}

function doZoomRect(scale, amount, from, to, limits) {
const fn = zoomRectFunctions[scale.type] || zoomRectFunctions.default;
call(fn, [scale, amount, from, to, limits]);
}

function getCenter(chart) {
const ca = chart.chartArea;
return {
Expand Down Expand Up @@ -81,15 +86,6 @@ export function zoom(chart, amount, transition = 'none') {
call(zoomOptions.onZoom, [{chart}]);
}

function getRange(scale, pixel0, pixel1) {
const v0 = scale.getValueForPixel(pixel0);
const v1 = scale.getValueForPixel(pixel1);
return {
min: Math.min(v0, v1),
max: Math.max(v0, v1)
};
}

export function zoomRect(chart, p0, p1, transition = 'none') {
const state = getState(chart);
const {options: {limits, zoom: zoomOptions}} = state;
Expand All @@ -101,9 +97,9 @@ export function zoomRect(chart, p0, p1, transition = 'none') {

each(chart.scales, function(scale) {
if (scale.isHorizontal() && xEnabled) {
updateRange(scale, getRange(scale, p0.x, p1.x), limits, true);
doZoomRect(scale, p0.x, p1.x, limits);
} else if (!scale.isHorizontal() && yEnabled) {
updateRange(scale, getRange(scale, p0.y, p1.y), limits, true);
doZoomRect(scale, p0.y, p1.y, limits);
}
});

Expand Down
9 changes: 5 additions & 4 deletions src/plugin.js
@@ -1,8 +1,8 @@
import Hammer from 'hammerjs';
import {addListeners, computeDragRect, removeListeners} from './handlers';
import {startHammer, stopHammer} from './hammer';
import {pan, zoom, resetZoom, zoomScale, getZoomLevel, getInitialScaleBounds, isZoomedOrPanned} from './core';
import {panFunctions, zoomFunctions} from './scale.types';
import {pan, zoom, resetZoom, zoomScale, getZoomLevel, getInitialScaleBounds, isZoomedOrPanned, zoomRect} from './core';
import {panFunctions, zoomFunctions, zoomRectFunctions} from './scale.types';
import {getState, removeState} from './state';
import {version} from '../package.json';

Expand Down Expand Up @@ -49,6 +49,7 @@ export default {

chart.pan = (delta, panScales, transition) => pan(chart, delta, panScales, transition);
chart.zoom = (args, transition) => zoom(chart, args, transition);
chart.zoomRect = (p0, p1, transition) => zoomRect(chart, p0, p1, transition);
chart.zoomScale = (id, range, transition) => zoomScale(chart, id, range, transition);
chart.resetZoom = (transition) => resetZoom(chart, transition);
chart.getZoomLevel = () => getZoomLevel(chart);
Expand Down Expand Up @@ -103,6 +104,6 @@ export default {
},

panFunctions,

zoomFunctions
zoomFunctions,
zoomRectFunctions,
};
17 changes: 17 additions & 0 deletions src/scale.types.js
Expand Up @@ -29,6 +29,15 @@ function getLimit(state, scale, scaleLimits, prop, fallback) {
return valueOrDefault(limit, fallback);
}

function getRange(scale, pixel0, pixel1) {
const v0 = scale.getValueForPixel(pixel0);
const v1 = scale.getValueForPixel(pixel1);
return {
min: Math.min(v0, v1),
max: Math.max(v0, v1)
};
}

export function updateRange(scale, {min, max}, limits, zoom = false) {
const state = getState(scale.chart);
const {id, axis, options: scaleOpts} = scale;
Expand Down Expand Up @@ -72,6 +81,10 @@ function zoomNumericalScale(scale, zoom, center, limits) {
return updateRange(scale, newRange, limits, true);
}

function zoomRectNumericalScale(scale, from, to, limits) {
updateRange(scale, getRange(scale, from, to), limits, true);
}

const integerChange = (v) => v === 0 || isNaN(v) ? 0 : v < 0 ? Math.min(Math.round(v), -1) : Math.max(Math.round(v), 1);

function existCategoryFromMaxZoom(scale) {
Expand Down Expand Up @@ -158,6 +171,10 @@ export const zoomFunctions = {
default: zoomNumericalScale,
};

export const zoomRectFunctions = {
default: zoomRectNumericalScale,
};

export const panFunctions = {
category: panCategoryScale,
default: panNumericalScale,
Expand Down
1 change: 1 addition & 0 deletions test/specs/api.spec.js
Expand Up @@ -5,6 +5,7 @@ describe('api', function() {
expect(typeof chart.pan).toBe('function');
expect(typeof chart.zoom).toBe('function');
expect(typeof chart.zoomScale).toBe('function');
expect(typeof chart.zoomRect).toBe('function');
expect(typeof chart.resetZoom).toBe('function');
expect(typeof chart.getZoomLevel).toBe('function');
expect(typeof chart.getInitialScaleBounds).toBe('function');
Expand Down
3 changes: 2 additions & 1 deletion test/specs/module.spec.js
Expand Up @@ -7,8 +7,9 @@ describe('module', function() {
expect(window.ChartZoom.id).toBe('zoom');
});

it ('should expose zoomFunctions and panFunctions', function() {
it ('should expose zoomFunctions, zoomRectFunctions, and panFunctions', function() {
expect(window.ChartZoom.zoomFunctions instanceof Object).toBe(true);
expect(window.ChartZoom.zoomRectFunctions instanceof Object).toBe(true);
expect(window.ChartZoom.panFunctions instanceof Object).toBe(true);
});

Expand Down
13 changes: 4 additions & 9 deletions types/index.d.ts
@@ -1,4 +1,4 @@
import { Plugin, ChartType, Chart, Scale, UpdateMode, ScaleTypeRegistry } from 'chart.js';
import { Plugin, ChartType, Scale, UpdateMode, ScaleTypeRegistry } from 'chart.js';
import { DistributiveArray } from 'chart.js/types/utils';
import { LimitOptions, ZoomPluginOptions } from './options';

Expand All @@ -21,6 +21,7 @@ declare module 'chart.js' {
interface Chart<TType extends keyof ChartTypeRegistry = keyof ChartTypeRegistry, TData = DistributiveArray<ChartTypeRegistry[TType]['defaultDataPoint']>, TLabel = unknown> {
pan(pan: PanAmount, scales?: Scale[], mode?: UpdateMode): void;
zoom(zoom: ZoomAmount, mode?: UpdateMode): void;
zoomRect(p0: Point, p1: Point, mode?: UpdateMode): void;
zoomScale(id: string, range: ScaleRange, mode?: UpdateMode): void;
resetZoom(mode?: UpdateMode): void;
getZoomLevel(): number;
Expand All @@ -30,6 +31,7 @@ declare module 'chart.js' {
}

export type ZoomFunction = (scale: Scale, zoom: number, center: Point, limits: LimitOptions) => boolean;
export type ZoomRectFunction = (scale: Scale, from: number, to: number, limits: LimitOptions) => boolean;
export type PanFunction = (scale: Scale, delta: number, limits: LimitOptions) => boolean;

type ScaleFunctions<T> = {
Expand All @@ -40,15 +42,8 @@ type ScaleFunctions<T> = {

declare const Zoom: Plugin & {
zoomFunctions: ScaleFunctions<ZoomFunction>;
zoomRectFunctions: ScaleFunctions<ZoomRectFunction>;
panFunctions: ScaleFunctions<PanFunction>;
};

export default Zoom;

export function pan(chart: Chart, amount: PanAmount, scales?: Scale[], mode?: UpdateMode): void;
export function zoom(chart: Chart, amount: ZoomAmount, mode?: UpdateMode): void;
export function zoomScale(chart: Chart, scaleId: string, range: ScaleRange, mode?: UpdateMode): void;
export function resetZoom(chart: Chart, mode?: UpdateMode): void;
export function getZoomLevel(chart: Chart): number;
export function getInitialScaleBounds(chart: Chart): Record<string, {min: number, max: number}>;
export function isZoomedOrPanned(chart: Chart): boolean;
joshkel marked this conversation as resolved.
Show resolved Hide resolved
8 changes: 4 additions & 4 deletions types/tests/exports.ts
@@ -1,5 +1,5 @@
import { Chart } from 'chart.js';
import Zoom, { pan, zoom, resetZoom } from '../index';
import Zoom from '../index';

Chart.register(Zoom);
Chart.unregister(Zoom);
Expand Down Expand Up @@ -55,6 +55,6 @@ chart.zoom({ x: 1, y: 1.1, focalPoint: { x: 10, y: 10 } }, 'zoom');
chart.pan(10);
chart.pan({ x: 10, y: 20 }, [chart.scales.x]);

pan(chart, -42, undefined, 'zoom');
zoom(chart, { x: 1, y: 1.1, focalPoint: { x: 10, y: 10 } }, 'zoom');
resetZoom(chart, 'none');
chart.zoomRect({ x: 10, y: 20 }, { x: 30, y: 40 });

chart.resetZoom('none');