Skip to content

Commit 7ce0150

Browse files
authored
Merge pull request #2857 from onesimus-wiafe/plugin/fix_epoch_time_to_date_on_axis_label
Show appropriate date when date is part of grouped data on chart.
2 parents 6f4be68 + bc0736f commit 7ce0150

File tree

2 files changed

+347
-2
lines changed

2 files changed

+347
-2
lines changed

packages/perspective-viewer-d3fc/src/ts/legend/filter.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,32 @@
1313
import { groupFromKey } from "../series/seriesKey";
1414
import { DataRowsWithKey, Settings } from "../types";
1515

16+
function refineDateData(settings: Settings) {
17+
let dataToRefine = settings.data;
18+
const { crossValues } = settings;
19+
20+
crossValues.forEach(({ type }, index) => {
21+
console.log("Type:", type);
22+
const formatType =
23+
type === "date" || type === "datetime"
24+
? (value: any) => new Date(value).toLocaleString()
25+
: null;
26+
27+
if (formatType) {
28+
dataToRefine.forEach((row: { __ROW_PATH__: any[] }) => {
29+
row.__ROW_PATH__[index] = formatType(row.__ROW_PATH__[index]);
30+
});
31+
}
32+
});
33+
34+
return dataToRefine;
35+
}
36+
1637
export function filterData(
1738
settings: Settings,
1839
data: any[] | undefined = undefined
1940
) {
20-
const useData = data || settings.data;
41+
const useData = data || refineDateData(settings);
2142
const len = settings.hideKeys?.length ?? 0;
2243
return len > 0
2344
? useData.map((col) => {
@@ -31,7 +52,7 @@ export function filterData(
3152
}
3253

3354
export function filterDataByGroup(settings: Settings): DataRowsWithKey {
34-
const newData = settings.data;
55+
const newData = refineDateData(settings);
3556
const hideKeysLen = settings.hideKeys?.length ?? 0;
3657
const splitValsLen = settings.splitValues.length;
3758
return hideKeysLen > 0
Lines changed: 324 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,324 @@
1+
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2+
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
3+
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
4+
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
5+
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
6+
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
7+
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
8+
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
9+
// ┃ This file is part of the Perspective library, distributed under the terms ┃
10+
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
11+
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
12+
13+
import { expect, test } from "@finos/perspective-test";
14+
15+
test.beforeEach(async ({ page }) => {
16+
await page.goto("/tools/perspective-test/src/html/basic-test.html");
17+
await page.evaluate(async () => {
18+
while (!window["__TEST_PERSPECTIVE_READY__"]) {
19+
await new Promise((x) => setTimeout(x, 10));
20+
}
21+
});
22+
23+
await page.evaluate(async () => {
24+
let viewer = document.querySelector("perspective-viewer");
25+
await viewer!.restore({
26+
plugin: "Datagrid",
27+
group_by: ["Order Date", "Profit"],
28+
x_axis: ["Row ID"],
29+
});
30+
31+
return await viewer.save();
32+
});
33+
34+
await page.click("#settings_button");
35+
await page.click(".plugin-select-item");
36+
});
37+
38+
function confirmDataIsDate(dateValues: any[]) {
39+
if (dateValues.length === 0) {
40+
throw Error("No date values recorded");
41+
}
42+
43+
const filtered_dates = dateValues.filter((_) => isNaN(Date.parse(_)));
44+
45+
expect(filtered_dates.length).toEqual(0);
46+
}
47+
48+
function confirmDataIsNotEpochForm(dateValues: any[]) {
49+
confirmDataIsDate(dateValues);
50+
51+
const isEpoch = (date: any): boolean => {
52+
return !isNaN(date) && (date.length === 10 || date.length === 13);
53+
};
54+
55+
const filtered_dates = dateValues.filter((_) => isEpoch(_));
56+
57+
expect(filtered_dates.length).toEqual(0);
58+
}
59+
60+
test.describe("Axis Values With Grouped Data With A Date Field In The Group", () => {
61+
test("X Bar y-axis label with grouped data", async ({ page }) => {
62+
await page.click('div[data-plugin="X Bar"]');
63+
await page.waitForSelector("perspective-viewer");
64+
65+
const dateValues = await page.evaluate(async () => {
66+
let viewer = document.querySelector("perspective-viewer");
67+
68+
if (!viewer) {
69+
return Error("Invalid Viewer");
70+
}
71+
72+
const plugin_element = viewer.querySelector(
73+
`perspective-viewer-d3fc-xbar`
74+
);
75+
76+
if (!plugin_element) {
77+
throw Error("Invalid Plugin Element");
78+
}
79+
80+
const shadowRoot = plugin_element.shadowRoot;
81+
const dateTextElements = shadowRoot.querySelectorAll(
82+
"div d3fc-group d3fc-svg.y-axis.left-axis svg g.group:last-child g.tick text"
83+
);
84+
85+
// collect and return the actual date data to be used.
86+
return Array.from(dateTextElements).map((el) =>
87+
el.textContent?.trim()
88+
);
89+
});
90+
91+
confirmDataIsNotEpochForm(dateValues);
92+
});
93+
94+
test("Y Bar x-axis label with grouped data", async ({ page }) => {
95+
await page.click('div[data-plugin="Y Bar"]');
96+
await page.waitForSelector("perspective-viewer");
97+
98+
const dateValues = await page.evaluate(async () => {
99+
let viewer = document.querySelector("perspective-viewer");
100+
101+
if (!viewer) {
102+
return Error("Invalid Viewer");
103+
}
104+
105+
const plugin_element = viewer.querySelector(
106+
`perspective-viewer-d3fc-ybar`
107+
);
108+
109+
if (!plugin_element) {
110+
throw Error("Invalid Plugin Element");
111+
}
112+
113+
const shadowRoot = plugin_element.shadowRoot;
114+
const dateTextElements = shadowRoot.querySelectorAll(
115+
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg g.group:last-child g.tick text"
116+
);
117+
118+
// collect and return the actual date data to be used.
119+
return Array.from(dateTextElements).map((el) =>
120+
el.textContent?.trim()
121+
);
122+
});
123+
124+
confirmDataIsNotEpochForm(dateValues);
125+
});
126+
127+
test("OHLC x-axis label with grouped data", async ({ page }) => {
128+
await page.click('div[data-plugin="OHLC"]');
129+
await page.waitForSelector("perspective-viewer");
130+
131+
const dateValues = await page.evaluate(async () => {
132+
let viewer = document.querySelector("perspective-viewer");
133+
134+
if (!viewer) {
135+
return Error("Invalid Viewer");
136+
}
137+
138+
const plugin_element = viewer.querySelector(
139+
`perspective-viewer-d3fc-ohlc`
140+
);
141+
142+
if (!plugin_element) {
143+
throw Error("Invalid Plugin Element");
144+
}
145+
146+
const shadowRoot = plugin_element.shadowRoot;
147+
const dateTextElements = shadowRoot.querySelectorAll(
148+
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg g.group:last-child g.tick text"
149+
);
150+
151+
// collect and return the actual date data to be used.
152+
return Array.from(dateTextElements).map((el) =>
153+
el.textContent?.trim()
154+
);
155+
});
156+
157+
confirmDataIsNotEpochForm(dateValues);
158+
});
159+
160+
test("Heatmap x-axis label with grouped data", async ({ page }) => {
161+
await page.click('div[data-plugin="Heatmap"]');
162+
await page.waitForSelector("perspective-viewer");
163+
164+
const dateValues = await page.evaluate(async () => {
165+
let viewer = document.querySelector("perspective-viewer");
166+
167+
if (!viewer) {
168+
return Error("Invalid Viewer");
169+
}
170+
171+
const plugin_element = viewer.querySelector(
172+
`perspective-viewer-d3fc-heatmap`
173+
);
174+
175+
if (!plugin_element) {
176+
throw Error("Invalid Plugin Element");
177+
}
178+
179+
const shadowRoot = plugin_element.shadowRoot;
180+
const dateTextElements = shadowRoot.querySelectorAll(
181+
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg g.group:last-child g.tick text"
182+
);
183+
184+
// collect and return the actual date data to be used.
185+
return Array.from(dateTextElements).map((el) =>
186+
el.textContent?.trim()
187+
);
188+
});
189+
190+
confirmDataIsNotEpochForm(dateValues);
191+
});
192+
193+
test("Y Line x-axis label with grouped data", async ({ page }) => {
194+
await page.click('div[data-plugin="Y Line"]');
195+
await page.waitForSelector("perspective-viewer");
196+
197+
const dateValues = await page.evaluate(async () => {
198+
let viewer = document.querySelector("perspective-viewer");
199+
200+
if (!viewer) {
201+
return Error("Invalid Viewer");
202+
}
203+
204+
const plugin_element = viewer.querySelector(
205+
`perspective-viewer-d3fc-yline`
206+
);
207+
208+
if (!plugin_element) {
209+
throw Error("Invalid Plugin Element");
210+
}
211+
212+
const shadowRoot = plugin_element.shadowRoot;
213+
const dateTextElements = shadowRoot.querySelectorAll(
214+
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg g.group:last-child g.tick text"
215+
);
216+
217+
// collect and return the actual date data to be used.
218+
return Array.from(dateTextElements).map((el) =>
219+
el.textContent?.trim()
220+
);
221+
});
222+
223+
confirmDataIsNotEpochForm(dateValues);
224+
});
225+
226+
test("Y Area x-axis label with grouped data", async ({ page }) => {
227+
await page.click('div[data-plugin="Y Area"]');
228+
await page.waitForSelector("perspective-viewer");
229+
230+
const dateValues = await page.evaluate(async () => {
231+
let viewer = document.querySelector("perspective-viewer");
232+
233+
if (!viewer) {
234+
return Error("Invalid Viewer");
235+
}
236+
237+
const plugin_element = viewer.querySelector(
238+
`perspective-viewer-d3fc-yarea`
239+
);
240+
241+
if (!plugin_element) {
242+
throw Error("Invalid Plugin Element");
243+
}
244+
245+
const shadowRoot = plugin_element.shadowRoot;
246+
const dateTextElements = shadowRoot.querySelectorAll(
247+
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg g.group:last-child g.tick text"
248+
);
249+
250+
// collect and return the actual date data to be used.
251+
return Array.from(dateTextElements).map((el) =>
252+
el.textContent?.trim()
253+
);
254+
});
255+
256+
confirmDataIsNotEpochForm(dateValues);
257+
});
258+
259+
test("Y Scatter x-axis label with grouped data", async ({ page }) => {
260+
await page.click('div[data-plugin="Y Scatter"]');
261+
await page.waitForSelector("perspective-viewer");
262+
263+
const dateValues = await page.evaluate(async () => {
264+
let viewer = document.querySelector("perspective-viewer");
265+
266+
if (!viewer) {
267+
return Error("Invalid Viewer");
268+
}
269+
270+
const plugin_element = viewer.querySelector(
271+
`perspective-viewer-d3fc-yscatter`
272+
);
273+
274+
if (!plugin_element) {
275+
throw Error("Invalid Plugin Element");
276+
}
277+
278+
const shadowRoot = plugin_element.shadowRoot;
279+
const dateTextElements = shadowRoot.querySelectorAll(
280+
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg g.group:last-child g.tick text"
281+
);
282+
283+
// collect and return the actual date data to be used.
284+
return Array.from(dateTextElements).map((el) =>
285+
el.textContent?.trim()
286+
);
287+
});
288+
289+
confirmDataIsNotEpochForm(dateValues);
290+
});
291+
292+
test("CandleStick x-axis label with grouped data", async ({ page }) => {
293+
await page.click('div[data-plugin="Candlestick"]');
294+
await page.waitForSelector("perspective-viewer");
295+
296+
const dateValues = await page.evaluate(async () => {
297+
let viewer = document.querySelector("perspective-viewer");
298+
299+
if (!viewer) {
300+
return Error("Invalid Viewer");
301+
}
302+
303+
const plugin_element = viewer.querySelector(
304+
`perspective-viewer-d3fc-candlestick`
305+
);
306+
307+
if (!plugin_element) {
308+
throw Error("Invalid Plugin Element");
309+
}
310+
311+
const shadowRoot = plugin_element.shadowRoot;
312+
const dateTextElements = shadowRoot.querySelectorAll(
313+
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg g.group:last-child g.tick text"
314+
);
315+
316+
// collect and return the actual date data to be used.
317+
return Array.from(dateTextElements).map((el) =>
318+
el.textContent?.trim()
319+
);
320+
});
321+
322+
confirmDataIsNotEpochForm(dateValues);
323+
});
324+
});

0 commit comments

Comments
 (0)