@gooddata/react-components
Version:
GoodData.UI - A powerful JavaScript library for building analytical applications
378 lines (329 loc) • 17.6 kB
text/typescript
// (C) 2007-2020 GoodData Corporation
import {
ITEM_HEIGHT,
LEGEND_PADDING,
RESPONSIVE_ITEM_MIN_WIDTH,
UTF_NON_BREAKING_SPACE,
calculateFluidLegend,
calculateStaticLegend,
getColorLegendConfiguration,
buildColorLabelsConfig,
heatmapLegendConfigMatrix,
heatmapSmallLegendConfigMatrix,
verticalHeatmapConfig,
getComboChartSeries,
LEGEND_AXIS_INDICATOR,
LEGEND_SEPARATOR,
groupSeriesItemsByType,
} from "../helpers";
import { VisualizationTypes } from "../../../../../constants/visualizationTypes";
import { ISeriesItem } from "../../../../../interfaces/Config";
describe("helpers", () => {
describe("calculateFluidLegend", () => {
describe("2 columns layout", () => {
const containerWidth = 500;
it("should show 4 items with paging for 10 series", () => {
const { hasPaging, visibleItemsCount } = calculateFluidLegend(10, containerWidth);
expect(hasPaging).toEqual(true);
expect(visibleItemsCount).toEqual(4);
});
it("should show 4 items without paging for 4 series", () => {
const { hasPaging, visibleItemsCount } = calculateFluidLegend(4, containerWidth);
expect(hasPaging).toEqual(false);
expect(visibleItemsCount).toEqual(4);
});
});
describe("3 columns layout", () => {
const containerWidth = 700;
it("should show 6 items with paging for 10 series", () => {
const { hasPaging, visibleItemsCount } = calculateFluidLegend(10, containerWidth);
expect(hasPaging).toEqual(true);
expect(visibleItemsCount).toEqual(6);
});
it("should show 6 items without paging for 6 series", () => {
const { hasPaging, visibleItemsCount } = calculateFluidLegend(6, containerWidth);
expect(hasPaging).toEqual(false);
expect(visibleItemsCount).toEqual(6);
});
});
describe("overlapping columns", () => {
const containerWidth = 3 * RESPONSIVE_ITEM_MIN_WIDTH + 1 + 2 * LEGEND_PADDING;
it("should not show paging for 5 items", () => {
const { hasPaging, visibleItemsCount } = calculateFluidLegend(6, containerWidth);
expect(hasPaging).toEqual(false);
expect(visibleItemsCount).toEqual(6);
});
it("should show paging for 7 items", () => {
const { hasPaging, visibleItemsCount } = calculateFluidLegend(7, containerWidth);
expect(hasPaging).toEqual(true);
expect(visibleItemsCount).toEqual(4);
});
});
});
describe("calculateStaticLegend", () => {
it("should show paging if needed", () => {
const itemsCount = 10;
const containerHeight = itemsCount * ITEM_HEIGHT;
let legendObj = calculateStaticLegend(itemsCount, containerHeight);
expect(legendObj.hasPaging).toEqual(false);
expect(legendObj.visibleItemsCount).toEqual(10);
legendObj = calculateStaticLegend(itemsCount, containerHeight - ITEM_HEIGHT);
expect(legendObj.hasPaging).toEqual(true);
expect(legendObj.visibleItemsCount).toEqual(6);
});
});
describe("getColorLegendConfiguration", () => {
const format = "#,##";
const numericSymbols = ["k", "m", "b", "g"];
const series = [
{ range: { from: 0, to: 10 }, color: "rgb(255,255,255)", legendIndex: 0 },
{ range: { from: 10, to: 20 }, color: "rgb(0,0,0)", legendIndex: 1 },
{ range: { from: 20, to: 30 }, color: "rgb(0,0,0)", legendIndex: 2 },
{ range: { from: 30, to: 40 }, color: "rgb(0,0,0)", legendIndex: 3 },
{ range: { from: 40, to: 50 }, color: "rgb(0,0,0)", legendIndex: 4 },
{ range: { from: 50, to: 60 }, color: "rgb(0,0,0)", legendIndex: 5 },
{ range: { from: 60, to: 70 }, color: "rgb(0,0,0)", legendIndex: 6 },
];
const seriesForShortening = [
{ range: { from: 99999, to: 100000 }, color: "rgb(255,255,255)", legendIndex: 0 },
{ range: { from: 100000, to: 100001 }, color: "rgb(0,0,0)", legendIndex: 1 },
{ range: { from: 100002, to: 100003 }, color: "rgb(0,0,0)", legendIndex: 2 },
{ range: { from: 100003, to: 100004 }, color: "rgb(0,0,0)", legendIndex: 3 },
{ range: { from: 100004, to: 100005 }, color: "rgb(0,0,0)", legendIndex: 4 },
{ range: { from: 100005, to: 100006 }, color: "rgb(0,0,0)", legendIndex: 5 },
{ range: { from: 100006, to: 100007 }, color: "rgb(0,0,0)", legendIndex: 6 },
];
const labels = [
{ key: "label-0", label: "0", style: { textAlign: "left", width: 30 } },
{ key: "label-1", label: "10", style: { textAlign: "center", width: 40 } },
{ key: "empty-2", label: UTF_NON_BREAKING_SPACE, style: { width: 10 } },
{ key: "label-3", label: "20", style: { textAlign: "center", width: 40 } },
{ key: "empty-4", label: UTF_NON_BREAKING_SPACE, style: { width: 10 } },
{ key: "label-5", label: "30", style: { textAlign: "center", width: 40 } },
{ key: "empty-6", label: UTF_NON_BREAKING_SPACE, style: { width: 10 } },
{ key: "label-7", label: "40", style: { textAlign: "center", width: 40 } },
{ key: "empty-8", label: UTF_NON_BREAKING_SPACE, style: { width: 10 } },
{ key: "label-9", label: "50", style: { textAlign: "center", width: 40 } },
{ key: "empty-10", label: UTF_NON_BREAKING_SPACE, style: { width: 10 } },
{ key: "label-11", label: "60", style: { textAlign: "center", width: 40 } },
{ key: "label-12", label: "70", style: { textAlign: "right", width: 30 } },
];
const labelsSmall = [
{ key: "label-0", label: "0", style: { textAlign: "left", width: 20 } },
{ key: "label-1", label: "10", style: { textAlign: "center", width: 40 } },
{ key: "label-2", label: "20", style: { textAlign: "center", width: 40 } },
{ key: "label-3", label: "30", style: { textAlign: "center", width: 38 } },
{ key: "label-4", label: "40", style: { textAlign: "center", width: 38 } },
{ key: "label-5", label: "50", style: { textAlign: "center", width: 40 } },
{ key: "label-6", label: "60", style: { textAlign: "center", width: 40 } },
{ key: "label-7", label: "70", style: { textAlign: "right", width: 20 } },
];
const boxes = [
{
class: null,
key: "item-0",
style: { backgroundColor: "rgb(255,255,255)", border: "1px solid #ccc" },
},
{ class: null, key: "item-1", style: { backgroundColor: "rgb(0,0,0)", border: "none" } },
{ class: null, key: "item-2", style: { backgroundColor: "rgb(0,0,0)", border: "none" } },
{ class: "middle", key: "item-3", style: { backgroundColor: "rgb(0,0,0)", border: "none" } },
{ class: null, key: "item-4", style: { backgroundColor: "rgb(0,0,0)", border: "none" } },
{ class: null, key: "item-5", style: { backgroundColor: "rgb(0,0,0)", border: "none" } },
{ class: null, key: "item-6", style: { backgroundColor: "rgb(0,0,0)", border: "none" } },
];
it("should prepare legend config without shortening when everything fits", () => {
const expectedResult = {
classes: ["viz-legend", "color-legend", "position-top", null],
labels,
boxes,
position: "top",
};
const result = getColorLegendConfiguration(series, format, numericSymbols, false, "top");
expect(result).toEqual(expectedResult);
});
it("should prepare legend config with position on right, without shortening when everything fits", () => {
const expectedLabels = [
{ key: "label-0", label: "0", style: { textAlign: "left", height: 15, lineHeight: "11px" } },
{ key: "label-1", label: "10", style: { textAlign: "left", height: 30, lineHeight: "30px" } },
{ key: "label-2", label: "20", style: { textAlign: "left", height: 30, lineHeight: "30px" } },
{ key: "label-3", label: "30", style: { textAlign: "left", height: 30, lineHeight: "30px" } },
{ key: "label-4", label: "40", style: { textAlign: "left", height: 30, lineHeight: "30px" } },
{ key: "label-5", label: "50", style: { textAlign: "left", height: 30, lineHeight: "30px" } },
{ key: "label-6", label: "60", style: { textAlign: "left", height: 30, lineHeight: "30px" } },
{ key: "label-7", label: "70", style: { textAlign: "left", height: 15, lineHeight: "20px" } },
];
const expectedResult = {
classes: ["viz-legend", "color-legend", "position-right", null],
labels: expectedLabels,
boxes,
position: "right",
};
const result = getColorLegendConfiguration(series, format, numericSymbols, false, null);
expect(result).toEqual(expectedResult);
});
it("should prepare small legend config without shortening when everything fits", () => {
const expectedResult = {
classes: ["viz-legend", "color-legend", "position-top", "small"],
labels: labelsSmall,
boxes,
position: "top",
};
const result = getColorLegendConfiguration(series, format, numericSymbols, true, "top");
expect(result).toEqual(expectedResult);
});
it("should prepare small legend config with bottom position, without shortening when everything fits", () => {
const expectedResult = {
classes: ["viz-legend", "color-legend", "position-bottom", "small"],
labels: labelsSmall,
boxes,
position: "bottom",
};
const result = getColorLegendConfiguration(series, format, numericSymbols, true, "right");
expect(result).toEqual(expectedResult);
});
it("should prepare legend config with shortening", () => {
const expectedLabels = [
{ key: "label-0", label: "99999", style: { textAlign: "left", width: 45 } },
{ key: "dots-1", label: "...", style: { textAlign: "center", width: 10 } },
{ key: "label-2", label: "100002", style: { textAlign: "center", width: 90 } },
{ key: "dots-3", label: "...", style: { textAlign: "center", width: 10 } },
{ key: "empty-4", label: " ", style: { width: 40 } },
{ key: "dots-5", label: "...", style: { textAlign: "center", width: 10 } },
{ key: "label-6", label: "100005", style: { textAlign: "center", width: 90 } },
{ key: "dots-7", label: "...", style: { textAlign: "center", width: 10 } },
{ key: "label-8", label: "100007", style: { textAlign: "right", width: 45 } },
];
const expectedResult = {
classes: ["viz-legend", "color-legend", "position-top", null],
labels: expectedLabels,
boxes,
position: "top",
};
const result = getColorLegendConfiguration(
seriesForShortening,
format,
numericSymbols,
false,
"top",
);
expect(result).toEqual(expectedResult);
});
it("should prepare small legend config with shortening", () => {
const expectedLabels = [
{ key: "label-0", label: "99999", style: { textAlign: "left", width: 35 } },
{ key: "dots-1", label: "...", style: { textAlign: "center", width: 10 } },
{ key: "label-2", label: "100002", style: { textAlign: "center", width: 70 } },
{ key: "dots-3", label: "...", style: { textAlign: "center", width: 10 } },
{ key: "empty-4", label: " ", style: { width: 26 } },
{ key: "dots-5", label: "...", style: { textAlign: "center", width: 10 } },
{ key: "label-6", label: "100005", style: { textAlign: "center", width: 70 } },
{ key: "dots-7", label: "...", style: { textAlign: "center", width: 10 } },
{ key: "label-8", label: "100007", style: { textAlign: "right", width: 35 } },
];
const expectedResult = {
classes: ["viz-legend", "color-legend", "position-top", "small"],
labels: expectedLabels,
boxes,
position: "top",
};
const result = getColorLegendConfiguration(
seriesForShortening,
format,
numericSymbols,
true,
"top",
);
expect(result).toEqual(expectedResult);
});
it("should sum widths to 350", () => {
const labels = ["0", "1", "2", "3", "4", "5", "6", "7"];
heatmapLegendConfigMatrix.forEach((config: any) => {
const elementsConfig = buildColorLabelsConfig(labels, config);
const width = elementsConfig.reduce((sum: number, item: any) => {
return sum + item.style.width;
}, 0);
expect(width).toEqual(350);
});
});
it("should sum widths to 276 in small legend", () => {
const labels = ["0", "1", "2", "3", "4", "5", "6", "7"];
heatmapSmallLegendConfigMatrix.forEach((config: any) => {
const elementsConfig = buildColorLabelsConfig(labels, config);
const width = elementsConfig.reduce((sum: number, item: any) => {
return sum + item.style.width;
}, 0);
expect(width).toEqual(276);
});
});
it("should sum heights to 210 in vertical legend", () => {
const labels = ["0", "1", "2", "3", "4", "5", "6", "7"];
const elementsConfig = buildColorLabelsConfig(labels, verticalHeatmapConfig);
const width = elementsConfig.reduce((sum: number, item: any) => {
return sum + item.style.height;
}, 0);
expect(width).toEqual(210);
});
});
describe("groupSeriesItemsByType", () => {
it("should group items which are having same chart type", () => {
const { COLUMN, LINE } = VisualizationTypes;
const series: ISeriesItem[] = [
{ type: COLUMN, yAxis: 0, legendIndex: 0 },
{ type: LINE, yAxis: 1, legendIndex: 2 },
{ type: COLUMN, yAxis: 0, legendIndex: 1 },
];
expect(groupSeriesItemsByType(series)).toEqual({
primaryItems: [series[0], series[2]],
secondaryItems: [series[1]],
});
});
it("should return empty groups when there is no series item", () => {
expect(groupSeriesItemsByType([])).toEqual({
primaryItems: [],
secondaryItems: [],
});
});
});
describe("getComboChartSeries", () => {
const { COLUMN, LINE, COMBO } = VisualizationTypes;
it("should indicate which measure belongs to Column(Left) and Line(Right)", () => {
const series: ISeriesItem[] = [
{ type: COLUMN, yAxis: 0, legendIndex: 0 },
{ type: LINE, yAxis: 1, legendIndex: 1 },
];
expect(getComboChartSeries(series)).toEqual([
{ type: LEGEND_AXIS_INDICATOR, labelKey: COMBO, data: [COLUMN, "left"] },
series[0],
{ type: LEGEND_SEPARATOR },
{ type: LEGEND_AXIS_INDICATOR, labelKey: COMBO, data: [LINE, "right"] },
series[1],
]);
});
it("should indicate which chart type of each measure when dual axis is off", () => {
const series: ISeriesItem[] = [
{ type: COLUMN, yAxis: 0, legendIndex: 0 },
{ type: LINE, yAxis: 0, legendIndex: 1 },
];
expect(getComboChartSeries(series)).toEqual([
{ type: LEGEND_AXIS_INDICATOR, labelKey: COLUMN },
series[0],
{ type: LEGEND_SEPARATOR },
{ type: LEGEND_AXIS_INDICATOR, labelKey: LINE },
series[1],
]);
});
it("should transform to dual axis series when all measures have same chart type", () => {
const series: ISeriesItem[] = [
{ type: COLUMN, yAxis: 0, legendIndex: 0 },
{ type: COLUMN, yAxis: 1, legendIndex: 1 },
];
expect(getComboChartSeries(series)).toEqual([
{ type: LEGEND_AXIS_INDICATOR, labelKey: "left" },
series[0],
{ type: LEGEND_SEPARATOR },
{ type: LEGEND_AXIS_INDICATOR, labelKey: "right" },
series[1],
]);
});
});
});