Skip to content

Commit

Permalink
fix #100
Browse files Browse the repository at this point in the history
  • Loading branch information
y-takey committed Mar 31, 2024
1 parent 7c7d76f commit 02741eb
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 38 deletions.
46 changes: 46 additions & 0 deletions examples/demo/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,3 +426,49 @@ createChart("Case.14 horizontal bar chart with parsing option", {
plugins: { stacked100: { enable: true } },
},
});

createChart("Case.15 Complex parsing options", {
type: "bar",
data: {
labels: ["Alice", "Bob"],
datasets: [
{
label: "bad",
data: [{ count: 1, user: "Alice" }],
backgroundColor: COLORS.red,
parsing: {
xAxisKey: "user",
yAxisKey: "count",
},
},
{
label: "better",
data: [{ count: 2, user: "Bob" }],
backgroundColor: COLORS.yellow,
parsing: {
xAxisKey: "user",
yAxisKey: "count",
},
},
{
label: "good",
data: [
{ count: 3, user: "Alice" },
{ count: 1, user: "Bob" },
],
backgroundColor: COLORS.blue,
parsing: {
xAxisKey: "user",
yAxisKey: "count",
},
},
],
},
options: {
plugins: {
stacked100: {
enable: true,
},
},
},
} as any);
70 changes: 47 additions & 23 deletions src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,50 @@ import {
ParsingOptions,
} from "chart.js";

import { dataValue, setOriginalData, round, getPrecision } from "./utils";
import { dataValue, setOriginalData, round, getPrecision, isObject } from "./utils";
import { ExtendedChartData, ExtendedPlugin } from "./types";

export const defaultStackKey = Symbol();

const getDataIndex = (
labels: unknown[],
data: unknown,
parsing: ParsingOptions["parsing"],
isHorizontal: boolean,
srcIndex: number,
) => {
if (!isObject(data)) return srcIndex;

const axis = isHorizontal ? "y" : "x";
const parseKey = parsing && parsing[`${axis}AxisKey`];
if (!parseKey) return srcIndex;
const label = data[parseKey];
if (!label) return srcIndex;
const labelIndex = labels.findIndex((l) => l === label);

return labelIndex < 0 ? srcIndex : labelIndex;
};

export const summarizeValues = (
datasets: ChartData["datasets"],
chartData: ChartData,
visibles: number[],
isHorizontal: boolean,
individual: boolean,
parsing?: ParsingOptions["parsing"],
) => {
const datasetDataLength =
datasets?.reduce((longestLength, dataset) => {
const length = dataset?.data?.length || 0;
return length > longestLength ? length : longestLength;
}, 0) || 0;
const { labels, datasets } = chartData;
const datasetDataLength = labels.length;

const isStack = datasets?.[0]?.stack;
const values = [...new Array(datasetDataLength)].map((el, i) => {
return datasets.reduce((sum, dataset, j) => {
const parsingOptions = dataset.parsing || parsing;
const key = dataset.stack || defaultStackKey;
const rec = dataset.data.find((ds, index) => {
return getDataIndex(labels, ds, parsingOptions, isHorizontal, index) == i;
});
if (!sum[key]) sum[key] = 0;
const value =
Math.abs(dataValue(dataset.data[i], isHorizontal, dataset.parsing || parsing) || 0) *
visibles[j];
const value = Math.abs(dataValue(rec, isHorizontal, parsingOptions) || 0) * visibles[j];
if (individual && !isStack) {
if (sum[key] < value) sum[key] = value;
} else {
Expand Down Expand Up @@ -68,19 +86,26 @@ const calculateRate = (
targetAxisId?: string,
parsing?: ParsingOptions["parsing"],
) => {
const totals = summarizeValues(data?.datasets, visibles, isHorizontal, individual, parsing);
const totals = summarizeValues(data, visibles, isHorizontal, individual, parsing);

return data.datasets.map((dataset) => {
const isTarget = isTargetDataset(dataset, targetAxisId);

return dataset.data.map((val, j) => {
const dv = dataValue(val, isHorizontal, dataset.parsing || parsing);
if (!isTarget) return dv;
const ret = new Array(data.labels.length);
dataset.data.forEach((val, j) => {
const parsingOptions = dataset.parsing || parsing;
const dv = dataValue(val, isHorizontal, parsingOptions);
const dataIndex = getDataIndex(data.labels, val, parsingOptions, isHorizontal, j);
if (isTarget) {
const key = dataset.stack || defaultStackKey;
const total = totals[dataIndex][key];

const total = totals[j][dataset.stack || defaultStackKey];

return dv && total ? round(dv / total, precision) : 0;
ret[dataIndex] = dv && total ? round(dv / total, precision) : 0;
} else {
ret[dataIndex] = dv;
}
});
return ret;
});
};

Expand All @@ -93,13 +118,12 @@ const tooltipLabel = (
const datasetIndex = tooltipItem.datasetIndex;
const index = tooltipItem.dataIndex;
const datasetLabel = data.datasets[datasetIndex].label || "";
const originalValue = data.originalData[datasetIndex][index];
const rateValue = data.calculatedData[datasetIndex][index];
const value = dataValue(
originalValue,
isHorizontal,
data.datasets[datasetIndex].parsing || tooltipItem.chart.options.parsing,
const parsing = data.datasets[datasetIndex].parsing || tooltipItem.chart.options.parsing;
const originalValue = data.originalData[datasetIndex].find(
(rec, i) => getDataIndex(data.labels, rec, parsing, isHorizontal, i) == index,
);
const rateValue = data.calculatedData[datasetIndex][index];
const value = dataValue(originalValue, isHorizontal, parsing);

if (!isTargetDataset(data.datasets[datasetIndex], targetAxisId)) {
return `${datasetLabel}: ${rateValue}`;
Expand Down
34 changes: 20 additions & 14 deletions src/test/plugin.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,42 @@ const allVisibles = [1, 1, 1, 1];

describe("summarizeValues", () => {
describe("no stack group", () => {
const datasets = [
{ data: [1, 5], label: "dummy1" },
{ data: [4, 2], label: "dummy2" },
];
const data = {
labels: ["l1", "l2"],
datasets: [
{ data: [1, 5], label: "dummy1" },
{ data: [4, 2], label: "dummy2" },
],
};

test("relative", () => {
expect(summarizeValues(datasets, allVisibles, true, false)).toEqual([
expect(summarizeValues(data, allVisibles, true, false)).toEqual([
{ [defaultStackKey]: 1 + 4 },
{ [defaultStackKey]: 5 + 2 },
]);
});

test("individual", () => {
expect(summarizeValues(datasets, allVisibles, true, true)).toEqual([
expect(summarizeValues(data, allVisibles, true, true)).toEqual([
{ [defaultStackKey]: Math.max(1, 4) },
{ [defaultStackKey]: Math.max(5, 2) },
]);
});
});

describe("stack group", () => {
const datasets = [
{ stack: "a", data: [1, 8] },
{ stack: "a", data: [7, 2] },
{ stack: "b", data: [3, 6] },
{ stack: "b", data: [4, 9] },
];
const data = {
labels: ["l1", "l2"],
datasets: [
{ stack: "a", data: [1, 8] },
{ stack: "a", data: [7, 2] },
{ stack: "b", data: [3, 6] },
{ stack: "b", data: [4, 9] },
],
};

test("relative", () => {
expect(summarizeValues(datasets, allVisibles, true, false)).toEqual([
expect(summarizeValues(data, allVisibles, true, false)).toEqual([
{ a: 1 + 7, b: 3 + 4 },
{ a: 8 + 2, b: 6 + 9 },
]);
Expand All @@ -43,7 +49,7 @@ describe("summarizeValues", () => {
test("individual", () => {
const group1Max = Math.max(1 + 7, 3 + 4);
const group2Max = Math.max(8 + 2, 6 + 9);
expect(summarizeValues(datasets, allVisibles, true, true)).toEqual([
expect(summarizeValues(data, allVisibles, true, true)).toEqual([
{ a: group1Max, b: group1Max },
{ a: group2Max, b: group2Max },
]);
Expand Down
2 changes: 1 addition & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ParsingOptions } from "chart.js";
import { ExtendedChartData, PluginOptions } from "./types";

export const isObject = (obj: any) => {
export const isObject = (obj: any): obj is Record<string, any> => {
const type = typeof obj;
return type === "object" && !!obj;
};
Expand Down

0 comments on commit 02741eb

Please sign in to comment.