chartjs / chartjs-plugin-zoom

Zoom and pan plugin for Chart.js
MIT License
596 stars 327 forks source link

fix: trigger onZoom from zoomScale #889

Closed kurkle closed 5 days ago

kurkle commented 5 days ago

fix #775

github-actions[bot] commented 5 days ago

Size Change: +12 B (+0.06%)

Total Size: 20.5 kB

Filename Size Change
dist/chartjs-plugin-zoom.esm.js 7.44 kB +2 B (+0.03%)
dist/chartjs-plugin-zoom.js 7.58 kB +4 B (+0.05%)
dist/chartjs-plugin-zoom.min.js 5.51 kB +6 B (+0.11%)

compressed-size-action

yubiuser commented 3 days ago

This update broke our use case and I don't know how to mitigate the new behavior. We basically have the same situation as described as in https://github.com/chartjs/chartjs-plugin-zoom/issues/768:

We have a time series bar chart with only positive y-values. When zooming, y-axis should stay fixed at zero, because it does not make sense to lose the zero anchor. We basically used onZoom to trigger chart.zoomScale to set the new scale with fixed y min to zero.

Screenshot from 2024-11-19 17-40-09

But with this change, this causes an endless loop. Any idea how to circumvent this?

Old code

      onZoom: function ({ chart }) {
        // The first time the chart is zoomed, save the maximum initial scale bound
        if (!chart.absMax) chart.absMax = chart.getInitialScaleBounds().y.max;
        // Calculate the maximum value to be shown for the current zoom level
        const zoomMax = chart.absMax / chart.getZoomLevel();
        // Update the y axis scale
        chart.zoomScale("y", { min: 0, max: zoomMax }, "default");
        // Update the y axis ticks and round values to natural numbers
        chart.options.scales.y.ticks.callback = function (value) {
          return value.toFixed(0);
        };
kurkle commented 3 days ago

Instead of calling zoomScale from onZoom, just specify min: 0 in the y-scale options?

Or, you can just update the scale directly:

chart.options.scales.y.min = 0;
chart.options.scales.y.max = chart.absMax / chart.getZoomLevel(); // probably not needed
chart.update();
yubiuser commented 3 days ago

Instead of calling zoomScale from onZoom, just specify min: 0 in the y-scale options?

This does not work, as it specifies the minimum, but not the maximal minimum (it doesn't get negative).


chart.options.scales.y.min = 0;
chart.options.scales.y.max = chart.absMax / chart.getZoomLevel(); // probably not needed
chart.update();

This works, but gives an unpleasant scale jump Peek 2024-11-20 07-49

Before it was smooth Peek 2024-11-20 07-55

kurkle commented 2 days ago

maybe chart.update('none') produces similar result?

yubiuser commented 2 days ago

Yes, but now I can only zoom in, and not zoom out again.

      onZoom: function ({ chart }) {
        chart.options.scales.y.min = 0;
        chart.update('none');
        }
kurkle commented 14 hours ago

I've created #901 for letting you do something like:

      onZoom: function ({ chart, trigger }) {
        if (trigger === 'api') {
          // Ignore onZoom triggered by the chart.zoomScale api call below
          return;
        }
        // The first time the chart is zoomed, save the maximum initial scale bound
        if (!chart.absMax) chart.absMax = chart.getInitialScaleBounds().y.max;
        // Calculate the maximum value to be shown for the current zoom level
        const zoomMax = chart.absMax / chart.getZoomLevel();
        // Update the y axis scale
        chart.zoomScale("y", { min: 0, max: zoomMax }, "default");
        // Update the y axis ticks and round values to natural numbers
        chart.options.scales.y.ticks.callback = function (value) {
          return value.toFixed(0);
        };
yubiuser commented 1 hour ago

Perfect. Tested it locally compiled and it works like charm.

Peek 2024-11-23 09-10