Skip to content

Commit

Permalink
fix: incorrect zoom out factor when using using wheel (#888)
Browse files Browse the repository at this point in the history
* fix: incorrect zoom out factor when using using wheel

* fix: lint

* fix: increase jasmine timeout
  • Loading branch information
kurkle authored Nov 17, 2024
1 parent 437b2ca commit b2aeae6
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 28 deletions.
4 changes: 2 additions & 2 deletions docs/samples/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ const actions = [
}, {
name: 'Zoom -10%',
handler(chart) {
chart.zoom(0.9);
chart.zoom(2 - 1 / 0.9);
},
}, {
name: 'Zoom x +10%',
Expand All @@ -81,7 +81,7 @@ const actions = [
}, {
name: 'Zoom x -10%',
handler(chart) {
chart.zoom({x: 0.9});
chart.zoom({x: 2 - 1 / 0.9});
},
}, {
name: 'Pan x 100px (anim)',
Expand Down
8 changes: 7 additions & 1 deletion docs/samples/wheel/log.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ const scales = {
display: true,
text: 'Frequency',
},
},
y: {
// constant width for the scale
afterFit: (scale) => {
scale.width = 50;
},
}
};
// </block:scales>
Expand Down Expand Up @@ -157,7 +163,7 @@ const config = {
},
}
},
}
},
};
// </block:config>

Expand Down
3 changes: 2 additions & 1 deletion karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ module.exports = function(karma) {

client: {
jasmine: {
stopOnSpecFailure: !!karma.autoWatch
stopOnSpecFailure: !!karma.autoWatch,
timeoutInterval: 10000,
}
},

Expand Down
7 changes: 4 additions & 3 deletions src/handlers.js
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,11 @@ export function wheel(chart, event) {
}

const rect = event.target.getBoundingClientRect();
const speed = 1 + (event.deltaY >= 0 ? -zoomOptions.wheel.speed : zoomOptions.wheel.speed);
const speed = zoomOptions.wheel.speed;
const percentage = event.deltaY >= 0 ? 2 - 1 / (1 - speed) : 1 + speed;
const amount = {
x: speed,
y: speed,
x: percentage,
y: percentage,
focalPoint: {
x: event.clientX - rect.left,
y: event.clientY - rect.top
Expand Down
55 changes: 40 additions & 15 deletions src/scale.types.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {valueOrDefault} from 'chart.js/helpers';
import {almostEquals, valueOrDefault} from 'chart.js/helpers';
import {getState} from './state';

/**
Expand Down Expand Up @@ -112,6 +112,40 @@ function linearRange(scale, pixel0, pixel1) {
};
}

/**
* @param {number} range
* @param {{ min: number; max: number; minLimit: number; maxLimit: number; }} options
* @param {{ min: { scale?: number; options?: number; }; max: { scale?: number; options?: number; }}} [originalLimits]
*/
function fixRange(range, {min, max, minLimit, maxLimit}, originalLimits) {
const offset = (range - max + min) / 2;
min -= offset;
max += offset;

// In case the values are really close to the original values, use the original values.
const origMin = originalLimits.min.options ?? originalLimits.min.scale;
const origMax = originalLimits.max.options ?? originalLimits.max.scale;

const epsilon = range / 1e6;
if (almostEquals(min, origMin, epsilon)) {
min = origMin;
}
if (almostEquals(max, origMax, epsilon)) {
max = origMax;
}

// Apply limits
if (min < minLimit) {
min = minLimit;
max = Math.min(minLimit + range, maxLimit);
} else if (max > maxLimit) {
max = maxLimit;
min = Math.max(maxLimit - range, minLimit);
}

return {min, max};
}

/**
* @param {Scale} scale
* @param {ScaleRange} minMax
Expand Down Expand Up @@ -141,24 +175,15 @@ export function updateRange(scale, {min, max}, limits, zoom = false) {
return true;
}

const offset = (range - max + min) / 2;
min -= offset;
max += offset;
const newRange = fixRange(range, {min, max, minLimit, maxLimit}, state.originalScaleLimits[scale.id]);

if (min < minLimit) {
min = minLimit;
max = Math.min(minLimit + range, maxLimit);
} else if (max > maxLimit) {
max = maxLimit;
min = Math.max(maxLimit - range, minLimit);
}
scaleOpts.min = min;
scaleOpts.max = max;
scaleOpts.min = newRange.min;
scaleOpts.max = newRange.max;

state.updatedScaleLimits[scale.id] = {min, max};
state.updatedScaleLimits[scale.id] = newRange;

// return true if the scale range is changed
return scale.parse(min) !== scale.min || scale.parse(max) !== scale.max;
return scale.parse(newRange.min) !== scale.min || scale.parse(newRange.max) !== scale.max;
}

function zoomNumericalScale(scale, zoom, center, limits) {
Expand Down
28 changes: 22 additions & 6 deletions test/specs/zoom.wheel.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,34 +278,50 @@ describe('zoom with wheel', function() {
const chart = window.acquireChart(config);
const scaleY = chart.scales.y;

const wheelEv = {
const zoomIn = {
x: Math.round(scaleY.left + (scaleY.right - scaleY.left) / 2),
y: Math.round(scaleY.top + (scaleY.bottom - scaleY.top) / 2),
deltaY: -1
};

const zoomOut = {
...zoomIn,
deltaY: 1
};

expect(scaleY.min).toBe(1);
expect(scaleY.max).toBe(10000);

jasmine.triggerWheelEvent(chart, wheelEv);
jasmine.triggerWheelEvent(chart, zoomIn);

expect(scaleY.min).toBeCloseTo(1.6, 1);
expect(scaleY.max).toBeCloseTo(6310, -1);

jasmine.triggerWheelEvent(chart, wheelEv);
jasmine.triggerWheelEvent(chart, zoomIn);

expect(scaleY.min).toBeCloseTo(2.4, 1);
expect(scaleY.max).toBeCloseTo(4170, -1);

jasmine.triggerWheelEvent(chart, zoomOut);
jasmine.triggerWheelEvent(chart, zoomOut);

expect(scaleY.min).toBe(1);
expect(scaleY.max).toBe(10000);

chart.resetZoom();

expect(scaleY.min).toBe(1);
expect(scaleY.max).toBe(10000);

jasmine.triggerWheelEvent(chart, {...wheelEv, deltaY: 1});
jasmine.triggerWheelEvent(chart, zoomOut);

expect(scaleY.min).toBeCloseTo(0.6, 1);
expect(scaleY.max).toBeCloseTo(16700, -2);

jasmine.triggerWheelEvent(chart, zoomIn);

expect(scaleY.min).toBe(0.6);
expect(scaleY.max).toBeCloseTo(15800, -2);
expect(scaleY.min).toBeCloseTo(1);
expect(scaleY.max).toBeCloseTo(10000);
});
});

Expand Down

0 comments on commit b2aeae6

Please sign in to comment.