Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show appropriate date when date is part of grouped data on chart. #2857

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
29 changes: 27 additions & 2 deletions packages/perspective-viewer-d3fc/src/ts/legend/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,36 @@
import { groupFromKey } from "../series/seriesKey";
import { DataRowsWithKey, Settings } from "../types";

function refineDateData(
settings: Settings,
data: any[] | undefined = undefined
) {
let dataToRefine = data ?? settings.data;
const { crossValues } = settings;

crossValues.forEach(({ type }, index) => {
const formatType =
type === "date" || type === "timestamp" || type === "datetime"
? (value: any) => new Date(value).toLocaleDateString()
: type === "time"
? (value: any) => new Date(value).toLocaleTimeString()
: null;

if (formatType) {
dataToRefine.forEach((row: { __ROW_PATH__: any[] }) => {
row.__ROW_PATH__[index] = formatType(row.__ROW_PATH__[index]);
});
}
});

return dataToRefine;
}

export function filterData(
settings: Settings,
data: any[] | undefined = undefined
) {
const useData = data || settings.data;
const useData = data || refineDateData(settings, settings.data);
const len = settings.hideKeys?.length ?? 0;
return len > 0
? useData.map((col) => {
Expand All @@ -31,7 +56,7 @@ export function filterData(
}

export function filterDataByGroup(settings: Settings): DataRowsWithKey {
const newData = settings.data;
const newData = refineDateData(settings);
const hideKeysLen = settings.hideKeys?.length ?? 0;
const splitValsLen = settings.splitValues.length;
return hideKeysLen > 0
Expand Down
335 changes: 335 additions & 0 deletions packages/perspective-viewer-d3fc/test/js/axisLabel.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,335 @@
// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
// ┃ ██████ ██████ ██████ █ █ █ █ █ █▄ ▀███ █ ┃
// ┃ ▄▄▄▄▄█ █▄▄▄▄▄ ▄▄▄▄▄█ ▀▀▀▀▀█▀▀▀▀▀ █ ▀▀▀▀▀█ ████████▌▐███ ███▄ ▀█ █ ▀▀▀▀▀ ┃
// ┃ █▀▀▀▀▀ █▀▀▀▀▀ █▀██▀▀ ▄▄▄▄▄ █ ▄▄▄▄▄█ ▄▄▄▄▄█ ████████▌▐███ █████▄ █ ▄▄▄▄▄ ┃
// ┃ █ ██████ █ ▀█▄ █ ██████ █ ███▌▐███ ███████▄ █ ┃
// ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫
// ┃ Copyright (c) 2017, the Perspective Authors. ┃
// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
// ┃ This file is part of the Perspective library, distributed under the terms ┃
// ┃ of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0). ┃
// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

import { expect, test } from "@finos/perspective-test";

test.beforeEach(async ({ page }) => {
await page.goto("/tools/perspective-test/src/html/basic-test.html");
await page.evaluate(async () => {
while (!window["__TEST_PERSPECTIVE_READY__"]) {
await new Promise((x) => setTimeout(x, 10));
}
});

await page.evaluate(async () => {
let viewer = document.querySelector("perspective-viewer");
await viewer!.restore({
plugin: "Datagrid",
group_by: ["Order Date", "Profit"],
x_axis: ["Row ID"],
});

return await viewer.save();
});

await page.click("#settings_button");
await page.click(".plugin-select-item");
});

function confirmDateData(dateValues: any[]) {
// expect the first to be a date.
expect(!isNaN(Date.parse(dateValues[0]))).toEqual(true);

// expect any random index of axisLabels to also be a date.
let len = dateValues.length;
const index = Math.floor(Math.random() * len);

expect(!isNaN(Date.parse(dateValues[index]))).toEqual(true);

// expect the last value to be a date.

expect(!isNaN(Date.parse(dateValues[len - 1]))).toEqual(true);

/**
* To confirm that the date string is not in epoch format.
* check if the entire string is numeric.
* if it is, confirm that the length is not 10 or 13.
* if it is not, return true.
*/
let isNumericOnly = /^\d+$/.test(dateValues[index]);

expect(isNumericOnly).toEqual(false);
}

test.describe("Axis Values With Grouped Data With A Date Field In The Group", () => {
test("X Bar y-axis label with grouped data", async ({ page }) => {
await page.click('div[data-plugin="X Bar"]');
await page.waitForSelector("perspective-viewer");

const dateValues = await page.evaluate(async () => {
let viewer = document.querySelector("perspective-viewer");

if (!viewer) return [];

const plugin_element = viewer.querySelector(
`perspective-viewer-d3fc-xbar`
);

if (!plugin_element) return [];

const shadowRoot = plugin_element.shadowRoot;
const elements = shadowRoot.querySelectorAll(
"div d3fc-group d3fc-svg.y-axis.left-axis svg, g.group"
);

// By how the data is grouped, the date values are the last in the array.
const lastGroup = elements[elements.length - 1];

const dateTextElements = lastGroup.querySelectorAll("g.tick text");

// collect and return the actual date data to be used.
return Array.from(dateTextElements).map((el) =>
el.textContent?.trim()
);
});

confirmDateData(dateValues);
});

test("Y Bar x-axis label with grouped data", async ({ page }) => {
await page.click('div[data-plugin="Y Bar"]');
await page.waitForSelector("perspective-viewer");

const dateValues = await page.evaluate(async () => {
let viewer = document.querySelector("perspective-viewer");

if (!viewer) return [];

const plugin_element = viewer.querySelector(
`perspective-viewer-d3fc-ybar`
);

if (!plugin_element) return [];

const shadowRoot = plugin_element.shadowRoot;
const elements = shadowRoot.querySelectorAll(
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg, g.group"
);

// By how the data is grouped, the date values are the last in the array.
const lastGroup = elements[elements.length - 1];

const dateTextElements = lastGroup.querySelectorAll("g.tick text");

// collect and return the actual date data to be used.
return Array.from(dateTextElements).map((el) =>
el.textContent?.trim()
);
});

confirmDateData(dateValues);
});

test("OHLC x-axis label with grouped data", async ({ page }) => {
await page.click('div[data-plugin="OHLC"]');
await page.waitForSelector("perspective-viewer");

const dateValues = await page.evaluate(async () => {
let viewer = document.querySelector("perspective-viewer");

if (!viewer) return [];

const plugin_element = viewer.querySelector(
`perspective-viewer-d3fc-ohlc`
);

if (!plugin_element) return [];

const shadowRoot = plugin_element.shadowRoot;
const elements = shadowRoot.querySelectorAll(
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg, g.group"
);

// By how the data is grouped, the date values are the last in the array.
const lastGroup = elements[elements.length - 1];

const dateTextElements = lastGroup.querySelectorAll("g.tick text");

// collect and return the actual date data to be used.
return Array.from(dateTextElements).map((el) =>
el.textContent?.trim()
);
});

confirmDateData(dateValues);
});

test("Heatmap x-axis label with grouped data", async ({ page }) => {
await page.click('div[data-plugin="Heatmap"]');
await page.waitForSelector("perspective-viewer");

const dateValues = await page.evaluate(async () => {
let viewer = document.querySelector("perspective-viewer");

if (!viewer) return [];

const plugin_element = viewer.querySelector(
`perspective-viewer-d3fc-heatmap`
);

if (!plugin_element) return [];

const shadowRoot = plugin_element.shadowRoot;
const elements = shadowRoot.querySelectorAll(
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg, g.group"
);

// By how the data is grouped, the date values are the last in the array.
const lastGroup = elements[elements.length - 1];

const dateTextElements = lastGroup.querySelectorAll("g.tick text");

// collect and return the actual date data to be used.
return Array.from(dateTextElements).map((el) =>
el.textContent?.trim()
);
});

confirmDateData(dateValues);
});

test("Y Line x-axis label with grouped data", async ({ page }) => {
await page.click('div[data-plugin="Y Line"]');
await page.waitForSelector("perspective-viewer");

const dateValues = await page.evaluate(async () => {
let viewer = document.querySelector("perspective-viewer");

if (!viewer) return [];

const plugin_element = viewer.querySelector(
`perspective-viewer-d3fc-yline`
);

if (!plugin_element) return [];

const shadowRoot = plugin_element.shadowRoot;
const elements = shadowRoot.querySelectorAll(
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg, g.group"
);

// By how the data is grouped, the date values are the last in the array.
const lastGroup = elements[elements.length - 1];

const dateTextElements = lastGroup.querySelectorAll("g.tick text");

// collect and return the actual date data to be used.
return Array.from(dateTextElements).map((el) =>
el.textContent?.trim()
);
});

confirmDateData(dateValues);
});

test("Y Area x-axis label with grouped data", async ({ page }) => {
await page.click('div[data-plugin="Y Area"]');
await page.waitForSelector("perspective-viewer");

const dateValues = await page.evaluate(async () => {
let viewer = document.querySelector("perspective-viewer");

if (!viewer) return [];

const plugin_element = viewer.querySelector(
`perspective-viewer-d3fc-yarea`
);

if (!plugin_element) return [];

const shadowRoot = plugin_element.shadowRoot;
const elements = shadowRoot.querySelectorAll(
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg, g.group"
);

// By how the data is grouped, the date values are the last in the array.
const lastGroup = elements[elements.length - 1];

const dateTextElements = lastGroup.querySelectorAll("g.tick text");

// collect and return the actual date data to be used.
return Array.from(dateTextElements).map((el) =>
el.textContent?.trim()
);
});

confirmDateData(dateValues);
});

test("Y Scatter x-axis label with grouped data", async ({ page }) => {
await page.click('div[data-plugin="Y Scatter"]');
await page.waitForSelector("perspective-viewer");

const dateValues = await page.evaluate(async () => {
let viewer = document.querySelector("perspective-viewer");

if (!viewer) return [];

const plugin_element = viewer.querySelector(
`perspective-viewer-d3fc-yscatter`
);

if (!plugin_element) return [];

const shadowRoot = plugin_element.shadowRoot;
const elements = shadowRoot.querySelectorAll(
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg, g.group"
);

// By how the data is grouped, the date values are the last in the array.
const lastGroup = elements[elements.length - 1];

const dateTextElements = lastGroup.querySelectorAll("g.tick text");

// collect and return the actual date data to be used.
return Array.from(dateTextElements).map((el) =>
el.textContent?.trim()
);
});

confirmDateData(dateValues);
});

test("CandleStick x-axis label with grouped data", async ({ page }) => {
await page.click('div[data-plugin="Candlestick"]');
await page.waitForSelector("perspective-viewer");

const dateValues = await page.evaluate(async () => {
let viewer = document.querySelector("perspective-viewer");

if (!viewer) return [];

const plugin_element = viewer.querySelector(
`perspective-viewer-d3fc-candlestick`
);

if (!plugin_element) return [];

const shadowRoot = plugin_element.shadowRoot;
const elements = shadowRoot.querySelectorAll(
"div d3fc-group d3fc-svg.x-axis.bottom-axis svg, g.group"
);

// By how the data is grouped, the date values are the last in the array.
const lastGroup = elements[elements.length - 1];

const dateTextElements = lastGroup.querySelectorAll("g.tick text");

// collect and return the actual date data to be used.
return Array.from(dateTextElements).map((el) =>
el.textContent?.trim()
);
});

confirmDateData(dateValues);
});
});
Loading