diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index bb57688e..b4bc2829 100755 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -145,9 +145,10 @@ module.exports = { title: 'Drag to Zoom', children: [ 'drag/category', - 'drag/linear', 'drag/linear-ratio', + 'drag/linear', 'drag/log', + 'drag/reject-outside', 'drag/time', 'drag/timeseries', ] diff --git a/docs/samples/drag/reject-outside.md b/docs/samples/drag/reject-outside.md new file mode 100644 index 00000000..c499503a --- /dev/null +++ b/docs/samples/drag/reject-outside.md @@ -0,0 +1,116 @@ +# Reject outside chartArea + +Zooming is performed by clicking and selecting an area over the chart with the mouse. Pan is activated by keeping `ctrl` pressed. + +```js chart-editor +// +const NUMBER_CFG = {count: 20, min: -100, max: 100}; +const data = { + datasets: [{ + label: 'My First dataset', + borderColor: Utils.randomColor(0.4), + backgroundColor: Utils.randomColor(0.1), + pointBorderColor: Utils.randomColor(0.7), + pointBackgroundColor: Utils.randomColor(0.5), + pointBorderWidth: 1, + data: Utils.points(NUMBER_CFG), + }, { + label: 'My Second dataset', + borderColor: Utils.randomColor(0.4), + backgroundColor: Utils.randomColor(0.1), + pointBorderColor: Utils.randomColor(0.7), + pointBackgroundColor: Utils.randomColor(0.5), + pointBorderWidth: 1, + data: Utils.points(NUMBER_CFG), + }] +}; +// + +// +const scaleOpts = { + reverse: true, + ticks: { + callback: (val, index, ticks) => index === 0 || index === ticks.length - 1 ? null : val, + }, + grid: { + borderColor: Utils.randomColor(1), + color: 'rgba( 0, 0, 0, 0.1)', + }, + title: { + display: true, + text: (ctx) => ctx.scale.axis + ' axis', + } +}; +const scales = { + x: { + position: 'top', + }, + y: { + position: 'right', + }, +}; +Object.keys(scales).forEach(scale => Object.assign(scales[scale], scaleOpts)); +// + +// +const dragColor = Utils.randomColor(0.4); +const zoomOptions = { + pan: { + enabled: true, + mode: 'xy', + modifierKey: 'ctrl', + }, + zoom: { + mode: 'xy', + // here is the magic! + onZoomStart: ({chart, point}) => chart.isPointInArea(point), + drag: { + enabled: true, + borderColor: 'rgb(54, 162, 235)', + borderWidth: 1, + backgroundColor: 'rgba(54, 162, 235, 0.3)' + } + } +}; +// + +const zoomStatus = () => zoomOptions.zoom.drag.enabled ? 'enabled' : 'disabled'; + +// +const config = { + type: 'scatter', + data: data, + options: { + scales: scales, + plugins: { + zoom: zoomOptions, + title: { + display: true, + position: 'bottom', + text: (ctx) => 'Zoom: ' + zoomStatus() + } + }, + } +}; +// + +const actions = [ + { + name: 'Toggle zoom', + handler(chart) { + zoomOptions.zoom.drag.enabled = !zoomOptions.zoom.drag.enabled; + chart.update(); + } + }, { + name: 'Reset zoom', + handler(chart) { + chart.resetZoom(); + } + } +]; + +module.exports = { + actions, + config, +}; +``` diff --git a/src/hammer.js b/src/hammer.js index d8d5ab96..6e0877fe 100644 --- a/src/hammer.js +++ b/src/hammer.js @@ -1,4 +1,4 @@ -import {callback as call} from 'chart.js/helpers'; +import {callback as call, getRelativePosition} from 'chart.js/helpers'; import Hammer from 'hammerjs'; import {pan, zoom} from './core'; import {getState} from './state'; @@ -66,9 +66,10 @@ function handlePinch(chart, state, e) { } } -function startPinch(chart, state) { +function startPinch(chart, state, event) { if (state.options.zoom.pinch.enabled) { - call(state.options.zoom.onZoomStart, [{chart}]); + const point = getRelativePosition(event, chart); + call(state.options.zoom.onZoomStart, [{chart, event, point}]); state.scale = 1; } } @@ -128,7 +129,7 @@ export function startHammer(chart, options) { const mc = new Hammer.Manager(canvas); if (zoomOptions && zoomOptions.pinch.enabled) { mc.add(new Hammer.Pinch()); - mc.on('pinchstart', () => startPinch(chart, state)); + mc.on('pinchstart', (e) => startPinch(chart, state, e)); mc.on('pinch', (e) => handlePinch(chart, state, e)); mc.on('pinchend', (e) => endPinch(chart, state, e)); }