Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ module.exports = function(karma) {
{pattern: 'node_modules/chart.js/dist/chart.js'},
{pattern: 'node_modules/hammer-simulator/index.js'},
{pattern: 'node_modules/hammerjs/hammer.js'},
{pattern: 'node_modules/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.js'},
{pattern: 'test/index.js'},
{pattern: 'src/index.js'},
{pattern: 'test/specs/**/*.js'}
Expand Down
11 changes: 10 additions & 1 deletion src/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,17 @@ export function resetZoom(chart) {
}

function panScale(scale, delta, panOptions, limits) {
const {panDelta} = getState(scale.chart);
// Add possible cumulative delta from previous pan attempts where scale did not change
delta += panDelta[scale.id] || 0;
const fn = panFunctions[scale.type] || panFunctions.default;
call(fn, [scale, delta, panOptions, limits]);
if (call(fn, [scale, delta, panOptions, limits])) {
// The scale changed, reset cumulative delta
panDelta[scale.id] = 0;
} else {
// The scale did not change, store cumulative delta
panDelta[scale.id] = delta;
}
}

export function doPan(chart, pan, enabledScales) {
Expand Down
1 change: 0 additions & 1 deletion src/hammer.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ function endPinch(chart, state, e) {
}
}


function handlePan(chart, state, e) {
const delta = state.delta;
if (delta !== null) {
Expand Down
29 changes: 22 additions & 7 deletions src/scale.types.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ function updateRange(scale, {min, max}, limits, zoom = false) {
}
scaleOpts.min = min;
scaleOpts.max = max;
// return true if the scale range is changed
return scale.parse(min) !== scale.min || scale.parse(max) !== scale.max;
}

function zoomNumericalScale(scale, zoom, center, limits) {
const delta = zoomDelta(scale, zoom, center);
const newRange = {min: scale.min + delta.min, max: scale.max - delta.max};
updateRange(scale, newRange, limits, true);
return updateRange(scale, newRange, limits, true);
}

const integerChange = (v) => v === 0 || isNaN(v) ? 0 : v < 0 ? Math.min(Math.round(v), -1) : Math.max(Math.round(v), 1);
Expand All @@ -61,7 +63,7 @@ function zoomCategoryScale(scale, zoom, center, limits) {
}
const delta = zoomDelta(scale, zoom, center);
const newRange = {min: scale.min + integerChange(delta.min), max: scale.max - integerChange(delta.max)};
updateRange(scale, newRange, limits, true);
return updateRange(scale, newRange, limits, true);
}

const categoryDelta = new WeakMap();
Expand All @@ -80,14 +82,27 @@ function panCategoryScale(scale, delta, panOptions, limits) {

categoryDelta.set(scale, minIndex !== scaleMin ? 0 : cumDelta);

updateRange(scale, {min: minIndex, max: maxIndex}, limits);
return updateRange(scale, {min: minIndex, max: maxIndex}, limits);
}

const OFFSETS = {
second: 500, // 500 ms
minute: 30 * 1000, // 30 s
hour: 30 * 60 * 1000, // 30 m
day: 12 * 60 * 60 * 1000, // 12 h
week: 3.5 * 24 * 60 * 60 * 1000, // 3.5 d
month: 15 * 24 * 60 * 60 * 1000, // 15 d
quarter: 60 * 24 * 60 * 60 * 1000, // 60 d
year: 182 * 24 * 60 * 60 * 1000 // 182 d
};

function panNumericalScale(scale, delta, panOptions, limits) {
const {min: prevStart, max: prevEnd} = scale;
const newMin = scale.getValueForPixel(scale.getPixelForValue(prevStart) - delta);
const newMax = scale.getValueForPixel(scale.getPixelForValue(prevEnd) - delta);
updateRange(scale, {min: newMin, max: newMax}, limits);
const {min: prevStart, max: prevEnd, options} = scale;
const round = options.time && options.time.round;
const offset = OFFSETS[round] || 0;
const newMin = scale.getValueForPixel(scale.getPixelForValue(prevStart + offset) - delta);
const newMax = scale.getValueForPixel(scale.getPixelForValue(prevEnd + offset) - delta);
return updateRange(scale, {min: newMin, max: newMax}, limits);
}

export const zoomFunctions = {
Expand Down
1 change: 1 addition & 0 deletions src/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export function getState(chart) {
state = {
originalScaleLimits: {},
handlers: {},
panDelta: {}
};
chartStates.set(chart, state);
}
Expand Down
66 changes: 66 additions & 0 deletions test/fixtures/pan/time-day-left.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;
const ctx = canvas.getContext('2d');

module.exports = {
config: {
type: 'bar',
data: {
labels: [new Date(2020, 0, 2), new Date(2020, 0, 3), new Date(2020, 0, 4), new Date(2020, 0, 5)],
datasets: [
{
backgroundColor: ['red', 'green', 'blue', 'orange'],
data: [1, 2, 3, 4]
}
]
},
options: {
animation: false,
events: [],
scales: {
y: {
display: false,
max: 5
},
x: {
type: 'time',
min: new Date(2020, 0, 3),
max: new Date(2020, 0, 5),
time: {
unit: 'day',
round: 'day',
}
}
},
plugins: {
legend: false,
zoom: {
pan: {
enabled: true,
mode: 'x',
}
}
}
}
},
options: {
spriteText: true,
run(chart) {
const steps = 4;
const n = Math.sqrt(steps);
const side = 512 / n;
for (let i = 0; i < steps; i++) {
const col = i % n;
const row = Math.floor(i / n);
if (i > 0) {
chart.pan({x: 150});
chart.update();
}
ctx.drawImage(chart.canvas, col * side, row * side, side, side);
}
Chart.helpers.clearCanvas(chart.canvas);
chart.ctx.drawImage(canvas, 0, 0);
}
}
};
Binary file added test/fixtures/pan/time-day-left.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 66 additions & 0 deletions test/fixtures/pan/time-day-right.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;
const ctx = canvas.getContext('2d');

module.exports = {
config: {
type: 'bar',
data: {
labels: [new Date(2020, 0, 2), new Date(2020, 0, 3), new Date(2020, 0, 4), new Date(2020, 0, 5)],
datasets: [
{
backgroundColor: ['red', 'green', 'blue', 'orange'],
data: [1, 2, 3, 4]
}
]
},
options: {
animation: false,
events: [],
scales: {
y: {
display: false,
max: 5
},
x: {
type: 'time',
min: new Date(2020, 0, 1),
max: new Date(2020, 0, 3),
time: {
unit: 'day',
round: 'day',
}
}
},
plugins: {
legend: false,
zoom: {
pan: {
enabled: true,
mode: 'x',
}
}
}
}
},
options: {
spriteText: true,
run(chart) {
const steps = 4;
const n = Math.sqrt(steps);
const side = 512 / n;
for (let i = 0; i < steps; i++) {
const col = i % n;
const row = Math.floor(i / n);
if (i > 0) {
chart.pan({x: -150});
chart.update();
}
ctx.drawImage(chart.canvas, col * side, row * side, side, side);
}
Chart.helpers.clearCanvas(chart.canvas);
chart.ctx.drawImage(canvas, 0, 0);
}
}
};
Binary file added test/fixtures/pan/time-day-right.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.