Skip to content

Commit

Permalink
fix(Yagr plugin): add aligner for uplot date (#410)
Browse files Browse the repository at this point in the history
  • Loading branch information
Flunt1k authored Feb 7, 2024
1 parent 8eb55e4 commit 7774575
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 5 deletions.
7 changes: 4 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
],
"dependencies": {
"@bem-react/classname": "^1.6.0",
"@gravity-ui/date-utils": "^1.4.1",
"@gravity-ui/date-utils": "^1.4.2",
"@gravity-ui/yagr": "^4.2.3",
"afterframe": "^1.0.2",
"d3": "^7.8.5",
Expand Down
41 changes: 40 additions & 1 deletion src/plugins/yagr/__tests__/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,27 @@
import {shapeYagrConfig} from '../renderer/utils';
import {shapeYagrConfig, getUplotTimezoneAligner} from '../renderer/utils';
import type {YagrWidgetData, MinimalValidConfig} from '../types';
import type {YagrChartOptions} from '@gravity-ui/yagr';

const DATA: YagrWidgetData['data'] = {
timeline: [1],
graphs: [{data: [45]}],
};

jest.mock('@gravity-ui/date-utils', () => {
const originalModule = jest.requireActual('@gravity-ui/date-utils');
return {
__esModule: true,
...originalModule,
dateTime: ({input, timeZone}: {input: number; timeZone?: string}) => {
const browserMockedTimezone = 'Europe/Moscow';
return originalModule.dateTime({
input,
timeZone: timeZone || browserMockedTimezone,
});
},
};
});

describe('plugins/yagr/utils', () => {
describe('shapeYagrConfig > check chart property', () => {
test.each<[Partial<MinimalValidConfig['chart']>, Partial<MinimalValidConfig['chart']>]>([
Expand All @@ -26,4 +42,27 @@ describe('plugins/yagr/utils', () => {
expect(config.chart).toEqual(expected);
});
});

describe('GetUplotTimezoneAligner', () => {
test.each<[YagrChartOptions | undefined, string | undefined, number, number]>([
// UTC
[{}, 'UTC', 1706659878000, 1706670678000],
// UTC + 1
[{}, 'Europe/Belgrade', 1706659878000, 1706667078000],
// UTC - 1
[{}, 'America/Scoresbysund', 1706659878000, 1706674278000],
// UTC + 4
[{}, 'Asia/Muscat', 1706659878000, 1706656278000],
])(
'should return timestamp with added timezone diff',
(chart, timeZone, timestamp, expectedResult) => {
const uplotTimezoneAligener = getUplotTimezoneAligner(chart, timeZone);

// timestamp is UTC Wed Jan 31 2024 00:11:18
const result = uplotTimezoneAligener(timestamp);

expect(result.getTime()).toEqual(expectedResult);
},
);
});
});
23 changes: 23 additions & 0 deletions src/plugins/yagr/renderer/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,24 @@ const getXAxisFormatter =
});
};

/**
* This function needs to align timezone that uplot is processing.
* Uplot uses simple new Date() when [processing ticks](https://github.com/leeoniya/uPlot/blob/master/src/opts.js#L177) on axis.
* It leads that timestamp will be converted to user browser timezone.
* In this function we artificially add shift diff between browser timezone and user timeozne to reset new Date() affects.
*/
export const getUplotTimezoneAligner =
(chart?: YagrChartOptions, timeZone?: string) => (ts: number) => {
const dt = ts / (chart?.timeMultiplier || 1);
const browserDate = dateTime({input: dt});
const browserTimezone = browserDate.utcOffset();
const timestampRealTimezone = dateTime({input: dt, timeZone}).utcOffset();

const uPlotOffset = (browserTimezone - timestampRealTimezone) * 60 * 1000;

return new Date(browserDate.valueOf() + uPlotOffset);
};

export const shapeYagrConfig = (args: ShapeYagrConfigArgs): MinimalValidConfig => {
const {data, libraryConfig, theme} = args;
const config: MinimalValidConfig = {
Expand Down Expand Up @@ -176,6 +194,11 @@ export const shapeYagrConfig = (args: ShapeYagrConfigArgs): MinimalValidConfig =
config.axes = config.axes || {};
const xAxis = config.axes[defaults.DEFAULT_X_SCALE];

config.editUplotOptions = (opts) => ({
...opts,
tzDate: timeZone ? getUplotTimezoneAligner(config.chart, timeZone) : undefined,
});

if (xAxis && !xAxis.values) {
xAxis.values = getXAxisFormatter(config.chart.timeMultiplier, timeZone);
}
Expand Down

0 comments on commit 7774575

Please sign in to comment.