Skip to content
Merged
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
2 changes: 2 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
v1.3.0 (24 September 2025):
- <Chart> component optional property 'showTableTitles' renamed to 'showTitles' as it now applies to both chart and table titles. Default value is true.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ drawChart(container, pxGraphData, locale);>
- showContextMenu: boolean - Flag to show or hide the context menu in the visualization.
- menuItemDefinitions: object[] - Definitions for custom context menu items. These can be either links or run custom functions. The provided object must implement either the IFunctionalMenuItem or ILinkMenuItem interface.
- menuIconInheritColor: boolean - Flag to inherit the color of the context menu icons from the parent element.
- showTableTitles: boolean - Flag to show or hide the titles in the table view.
- showTitles: boolean - Flag to show or hide the titles in the tables and charts.
- showTableUnits: boolean - Flag to show or hide the units in the table view.
- showTableSources: boolean - Flag to show or hide the sources in the table view.
- footnote: string - Custom footnote to be displayed in the visualization.
Expand Down
24 changes: 11 additions & 13 deletions package-lock.json

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

8 changes: 3 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@statisticsfinland/pxvisualizer",
"version": "1.2.4",
"version": "1.3.1",
"description": "Component library for visualizing PxGraf data",
"main": "./dist/pxv.cjs",
"jestSonar": {
Expand Down Expand Up @@ -68,8 +68,6 @@
"babel-loader": "^10.0.0",
"clean-publish": "^5.1.0",
"decimal.js": "^10.5.0",
"highcharts": "^12.1.2",
"highcharts-react-official": "^3.2.1",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-junit": "^16.0.0",
Expand All @@ -90,8 +88,8 @@
"dependencies": {
"decimal.js": "^10.5.0",
"fflate": "^0.8.2",
"highcharts": "^12.1.2",
"highcharts-react-official": "^3.2.1"
"highcharts": "^12.4.0",
"highcharts-react-official": "^3.2.2"
},
"peerDependencies": {
"react": "^18.2.0 || ^19.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/core/chartOptions/basicHorizontalBarchartOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { IChartOptions } from '../types/chartOptions';

export const basicHorizontalBarChartOptions = (view: View, locale: string, options?: IChartOptions): Options => {
return {
...commonHorizontalBarChartOptions(view, locale),
...commonHorizontalBarChartOptions(view, locale, options),
series: buildBarChartSeries(view, locale, false, options?.accessibilityMode),
chart: { type: 'bar', spacingBottom: 60 },
yAxis: {
Expand Down
19 changes: 10 additions & 9 deletions src/core/chartOptions/chartOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@ import { getLinearAxisTickPositionerFunction } from './Utility/tickPositioners';
import { IChartOptions } from '../types/chartOptions';
import { buildBarChartSeries, buildColumnChartSeries } from './Utility/seriesDataBuilder';

export const commonChartOptions = (view: View, locale: string): Options => {
export const commonChartOptions = (view: View, locale: string, options?: IChartOptions): Options => {
const showTitle: boolean = options?.showTitle ?? true;
return {
accessibility: {
point: {
descriptionFormatter: getScreenReaderFormatterCallbackFunction(view, locale)
}
},
title: { text: view.header[locale] },
title: { text: showTitle ? view.header[locale] : undefined },
subtitle: { text: view.subheaderValues.map(sv => sv[locale]).join(' | ') },
credits: { text: `${Translations.source[locale]}: ${view.sources.map(s => s[locale]).join(', ')}` },
tooltip: {
Expand Down Expand Up @@ -65,9 +66,9 @@ export const commonBasicHorizontalBarChartYAxisOptions = (view: View, locale: st
return yAxisOptions;
}

export const commonHorizontalBarChartOptions = (view: View, locale: string): Options => {
export const commonHorizontalBarChartOptions = (view: View, locale: string, options?: IChartOptions): Options => {
return {
...commonChartOptions(view, locale),
...commonChartOptions(view, locale, options),
chart: { type: 'bar' },
xAxis: {
categories: view.columnNameGroups.map(cng => cng.map(n => n[locale]).join(', ')),
Expand All @@ -83,7 +84,7 @@ export const commonHorizontalBarChartOptions = (view: View, locale: string): Opt

export const commonStackedHorizontalBarChartOptions = (view: View, locale: string, options?: IChartOptions): Options => {
return {
...commonHorizontalBarChartOptions(view, locale),
...commonHorizontalBarChartOptions(view, locale, options),
series: buildBarChartSeries(view, locale, true, options?.accessibilityMode),
legend: {
...commonLegendStyleOptions,
Expand All @@ -95,9 +96,9 @@ export const commonStackedHorizontalBarChartOptions = (view: View, locale: strin
};
}

export const commonVerticalBarChartOptions = (view: View, locale: string): Options => {
export const commonVerticalBarChartOptions = (view: View, locale: string, options?: IChartOptions): Options => {
const result = {
...commonChartOptions(view, locale),
...commonChartOptions(view, locale, options),
chart: { type: 'column' },
xAxis: getXAxisOptions(view, locale),
};
Expand All @@ -106,7 +107,7 @@ export const commonVerticalBarChartOptions = (view: View, locale: string): Optio

export const commonBasicVerticalBarChartOptions = (view: View, locale: string, options?: IChartOptions): Options => {
return {
...commonVerticalBarChartOptions(view, locale),
...commonVerticalBarChartOptions(view, locale, options),
series: buildColumnChartSeries(view, locale, false, options?.accessibilityMode),
yAxis: {
softMin: 0,
Expand All @@ -120,7 +121,7 @@ export const commonBasicVerticalBarChartOptions = (view: View, locale: string, o

export const commonStackedVerticalBarChartOptions = (view: View, locale: string, options?: IChartOptions): Options => {
return {
...commonVerticalBarChartOptions(view, locale),
...commonVerticalBarChartOptions(view, locale, options),
series: buildColumnChartSeries(view, locale, true, options?.accessibilityMode),
legend: {
...commonLegendStyleOptions,
Expand Down
2 changes: 1 addition & 1 deletion src/core/chartOptions/groupHorizontalBarChartOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { IChartOptions } from '../types/chartOptions';

export const groupHorizontalBarChartOptions = (view: View, locale: string, options?: IChartOptions): Options => {
return {
...commonHorizontalBarChartOptions(view, locale),
...commonHorizontalBarChartOptions(view, locale, options),
series: buildBarChartSeries(view, locale, false, options?.accessibilityMode),
yAxis: {
...commonBasicHorizontalBarChartYAxisOptions(view, locale),
Expand Down
2 changes: 1 addition & 1 deletion src/core/chartOptions/lineChartOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const lineChartOptions = (view: View, locale: string, options?: IChartOpt
const cutValueAxis = !view.visualizationSettings?.cutValueAxis ? 0 : undefined;
const markerSettings = options?.accessibilityMode ? { enabledThreshold: 3 } : { enabled: false };
return {
...commonChartOptions(view, locale),
...commonChartOptions(view, locale, options),
chart: { type: 'line' },
tooltip: {
formatter: getLineChartToolTipFormatterFunction(view, locale)
Expand Down
2 changes: 1 addition & 1 deletion src/core/chartOptions/pyramidChartOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const pyramidChartOptions = (view: View, locale: string, options?: IChart
const categories = view.columnNameGroups.map(cng => cng.map(n => n[locale]).join(', '));
const maxValue = Math.max(...view.series.map(s => Math.max(...s.series.map(dataCell => dataCell.value ?? 0))));
return {
...commonChartOptions(view, locale),
...commonChartOptions(view, locale, options),
chart: { type: 'bar' },
xAxis: {
categories: categories,
Expand Down
5 changes: 3 additions & 2 deletions src/core/chartOptions/scatterPlotOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import { Options } from 'highcharts';
import { IDataSeries, View } from "../types/view";
import { getScatterPlotTooltipFormatterFunction } from './Utility/formatters';
import { commonChartOptions, commonYAxisOptions } from './chartOptions';
import { IChartOptions } from '../types/chartOptions';

export const scatterPlotOptions = (view: View, locale: string): Options => {
export const scatterPlotOptions = (view: View, locale: string, options?: IChartOptions): Options => {
const X_INDEX = 1; const Y_INDEX = 0;
const cutValueAxis = !view.visualizationSettings?.cutValueAxis ? 0 : undefined;
return {
...commonChartOptions(view, locale),
...commonChartOptions(view, locale, options),
chart: { type: 'scatter' },
xAxis: {
softMin: 0,
Expand Down
2 changes: 1 addition & 1 deletion src/core/conversion/pxGrafDataConverter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const convertPxGraphDataToChartOptions = (locale: string, view: View, opt
case EVisualizationType.PyramidChart:
return pyramidChartOptions(view, locale, options);
case EVisualizationType.ScatterPlot:
return scatterPlotOptions(view, locale);
return scatterPlotOptions(view, locale, options);
default:
throw new Error('Unsupported chart type');
}
Expand Down
32 changes: 32 additions & 0 deletions src/core/tables/__snapshots__/htmlTable.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3542,3 +3542,35 @@ exports[`Html table render tests should match snapshot: Table with row variables
</p>
</div>"
`;

exports[`Html table render tests should match snapshot: Table with source and footnote 1`] = `
"<div
id="test-6895638450983059889"
>
<table
tabindex="0"
>
<caption
class="tableChart-caption"
>
Lukumäärä, Vantaa, Yksiöt, Vapaarahoitteinen 2022Q4
</caption>
<tbody>
<tr>
<td>
2 548
</td>
</tr>
</tbody>
</table>
<p>
Yksikkö: lukumäärä
</p>
<p>
Test footnote
</p>
<p>
Lähde: PxVisualizer-fi
</p>
</div>"
`;
23 changes: 23 additions & 0 deletions src/core/tables/htmlTable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,29 @@ describe('Html table render tests', () => {
document.body.removeChild(div);
});

it('should match snapshot: Table with source and footnote', () => {
const mockVarSelections = extractSelectableVariableValues(
TABLE_WITH_ONE_CELL.pxGraphData.selectableVariableCodes,
TABLE_WITH_ONE_CELL.pxGraphData.metaData,
TABLE_WITH_ONE_CELL.pxGraphData.visualizationSettings.defaultSelectableVariableCodes,
TABLE_WITH_ONE_CELL.selectedVariableCodes);
const mockView = convertPxGrafResponseToView(TABLE_WITH_ONE_CELL.pxGraphData, mockVarSelections);
const locale = 'fi';

const testId = 'test-6895638450983059889';

const div = document.createElement('div');
div.id = testId;
document.body.appendChild(div);

renderHtmlTable(mockView, locale, true, true, true, testId, 'Test footnote');

const renderedOutput = prettyDOM(div);
expect(renderedOutput).toMatchSnapshot();

document.body.removeChild(div);
});

it('should match snapshot: Table with missing data and selectable values', () => {
const mockVarSelections = extractSelectableVariableValues(
SELECTABLE_TABLE_WITH_MISSING_DATA.selectableVariableCodes,
Expand Down
14 changes: 7 additions & 7 deletions src/core/tables/htmlTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ export function renderHtmlTable(view: View, locale: string, showTitles: boolean,
container.append(pUnits);
}

// Footnote
if (footnote) {
const pFootnote = document.createElement('p');
pFootnote.append(footnote);
container.append(pFootnote);
}

// Sources
if (showSources) {
const pSources = document.createElement('p');
Expand All @@ -44,13 +51,6 @@ export function renderHtmlTable(view: View, locale: string, showTitles: boolean,
container.append(pSources);
}

// Footnote
if (footnote) {
const pFootnote = document.createElement('p');
pFootnote.append(footnote);
container.append(pFootnote);
}

} catch (error) {
console.error(error);
container.replaceChildren();
Expand Down
1 change: 1 addition & 0 deletions src/core/types/chartOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
*/
export interface IChartOptions {
accessibilityMode?: boolean;
showTitle?: boolean;
}
20 changes: 12 additions & 8 deletions src/react/components/burgerMenu/burgerMenu.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ describe('burgerMenu, rendering tests', () => {
});

const viewData = { tableReference: "testTable" } as unknown as View;
const mockExportChartLocal = jest.fn();
const mockExportChart = jest.fn();
beforeEach(() => {
mockExportChartLocal.mockClear();
mockExportChart.mockClear();
});

const mockTableToggle = {
Expand Down Expand Up @@ -221,10 +221,12 @@ describe('burgerMenu, functional tests', () => {
expect(finalHeight).toEqual(3000);
});

it('should call exportChartLocal with correct parameters for SVG export', () => {
it('should call export chart with correct parameters for SVG export', () => {
const mockRef = {
chart: {
exportChartLocal: mockExportChartLocal,
exporting: {
exportChart: mockExportChart,
},
chartWidth: 800,
chartHeight: 400
}
Expand All @@ -235,7 +237,7 @@ describe('burgerMenu, functional tests', () => {
fireEvent.click(screen.getByText(Translations.downloadSVG["fi"]));

const { finalWidth, finalHeight } = calculateExportDimensions(mockRef);
expect(mockExportChartLocal).toHaveBeenCalledWith({
expect(mockExportChart).toHaveBeenCalledWith({
filename: generateFilename(viewData.tableReferenceName),
type: "image/svg+xml",
sourceWidth: finalWidth,
Expand All @@ -244,10 +246,12 @@ describe('burgerMenu, functional tests', () => {
}, {});
});

it('should call exportChartLocal with correct parameters for PNG export', () => {
it('should call export chart with correct parameters for PNG export', () => {
const mockRef = {
chart: {
exportChartLocal: mockExportChartLocal,
exporting: {
exportChart: mockExportChart,
},
chartWidth: 800,
chartHeight: 400
}
Expand All @@ -258,7 +262,7 @@ describe('burgerMenu, functional tests', () => {
fireEvent.click(screen.getByText(Translations.downloadPNG["fi"]));

const { finalWidth, finalHeight } = calculateExportDimensions(mockRef);
expect(mockExportChartLocal).toHaveBeenCalledWith({
expect(mockExportChart).toHaveBeenCalledWith({
filename: generateFilename(viewData.tableReferenceName),
sourceWidth: finalWidth,
sourceHeight: finalHeight,
Expand Down
Loading
Loading