Skip to content

Commit ed107fe

Browse files
committed
fix: heatmap update onclick
1 parent ae0753a commit ed107fe

File tree

12 files changed

+86
-27
lines changed

12 files changed

+86
-27
lines changed

packages/pluggableWidgets/charts-web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@mendix/charts-web",
3-
"version": "6.2.0",
3+
"version": "6.2.1",
44
"description": "Chart widgets collection for data visualization",
55
"copyright": "© Mendix Technology BV 2025. All rights reserved.",
66
"license": "Apache-2.0",

packages/pluggableWidgets/charts-web/src/package.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8" ?>
22
<package xmlns="http://www.mendix.com/package/1.0/">
3-
<clientModule name="Charts" version="6.2.0" xmlns="http://www.mendix.com/clientModule/1.0/">
3+
<clientModule name="Charts" version="6.2.1" xmlns="http://www.mendix.com/clientModule/1.0/">
44
<widgetFiles>
55
<widgetFile path="AreaChart/AreaChart.xml" />
66
<widgetFile path="BarChart/BarChart.xml" />

packages/pluggableWidgets/heatmap-chart-web/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66

77
## [Unreleased]
88

9+
### Fixed
10+
11+
- We fixed on click events by correctly adding datasource and allow to listen to selection.
12+
913
## [6.0.0] - 2025-02-28
1014

1115
### Changed

packages/pluggableWidgets/heatmap-chart-web/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@mendix/heatmap-chart-web",
33
"widgetName": "HeatMap",
4-
"version": "6.0.0",
4+
"version": "6.2.1",
55
"description": "Shows data in a heatmap format graph.",
66
"copyright": "© Mendix Technology BV 2025. All rights reserved.",
77
"license": "Apache-2.0",

packages/pluggableWidgets/heatmap-chart-web/src/HeatMap.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ export function HeatMap(props: HeatMapContainerProps): ReactElement | null {
6868
tooltipHoverText: props.tooltipHoverText,
6969
verticalAxisAttribute: props.verticalAxisAttribute,
7070
verticalSortAttribute: props.verticalSortAttribute,
71-
verticalSortOrder: props.verticalSortOrder
71+
verticalSortOrder: props.verticalSortOrder,
72+
seriesItemSelection: props.seriesItemSelection
7273
});
7374

7475
const heatmapChartLayout = useMemo<ChartWidgetProps["layoutOptions"]>(() => {

packages/pluggableWidgets/heatmap-chart-web/src/HeatMap.xml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020
<attributeType name="Long" />
2121
</attributeTypes>
2222
</property>
23+
<property key="seriesItemSelection" type="selection" dataSource="seriesDataSource">
24+
<caption>Selection type</caption>
25+
<description />
26+
<selectionTypes>
27+
<selectionType name="None" />
28+
<selectionType name="Single" />
29+
</selectionTypes>
30+
</property>
2331
</propertyGroup>
2432
<propertyGroup caption="Axis">
2533
<property key="horizontalAxisAttribute" type="attribute" required="false" dataSource="seriesDataSource">
@@ -184,7 +192,7 @@
184192
</propertyGroup>
185193
<propertyGroup caption="Events">
186194
<propertyGroup caption="Events">
187-
<property key="onClickAction" type="action" required="false">
195+
<property key="onClickAction" type="action" required="false" dataSource="seriesDataSource">
188196
<caption>On click action</caption>
189197
<description />
190198
</property>

packages/pluggableWidgets/heatmap-chart-web/src/hooks/data.ts

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import { ValueStatus } from "mendix";
2-
import { useEffect, useMemo, useState } from "react";
1+
import { ValueStatus, ObjectItem } from "mendix";
2+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
33
import { ensure } from "@mendix/pluggable-widgets-tools";
44
import { HeatMapContainerProps } from "../../typings/HeatMapProps";
55
import { ChartWidgetProps, compareAttrValuesAsc } from "@mendix/shared-charts/main";
66
import { executeAction } from "@mendix/widget-plugin-platform/framework/execute-action";
77
import Big from "big.js";
8+
import { PlotDatum } from "plotly.js-dist-min";
89

910
type HeatMapDataSeriesHooks = Pick<
1011
HeatMapContainerProps,
@@ -22,6 +23,7 @@ type HeatMapDataSeriesHooks = Pick<
2223
| "verticalAxisAttribute"
2324
| "verticalSortAttribute"
2425
| "verticalSortOrder"
26+
| "seriesItemSelection"
2527
>;
2628

2729
type AttributeValue = string | number | Date | undefined;
@@ -33,6 +35,7 @@ type LocalHeatMapData = {
3335
verticalAxisValue: AttributeValue;
3436
horizontalSortValue: string | Big | Date | undefined;
3537
verticalSortValue: string | Big | Date | undefined;
38+
id: string;
3639
};
3740

3841
function getUniqueValues<T>(values: T[]): T[] {
@@ -64,20 +67,28 @@ export const useHeatMapDataSeries = ({
6467
tooltipHoverText,
6568
verticalAxisAttribute,
6669
verticalSortAttribute,
67-
verticalSortOrder
70+
verticalSortOrder,
71+
seriesItemSelection
6872
}: HeatMapDataSeriesHooks): HeatMapHookData => {
6973
const [heatmapChartData, setHeatMapData] = useState<LocalHeatMapData[]>([]);
74+
const objectMap = useRef<Map<string, ObjectItem>>(new Map());
7075

7176
useEffect(() => {
7277
if (seriesDataSource.status === ValueStatus.Available && seriesDataSource.items) {
73-
const dataSourceItems = seriesDataSource.items.map(dataSourceItem => ({
74-
value: ensure(seriesValueAttribute).get(dataSourceItem).value?.toNumber(),
75-
hoverText: tooltipHoverText?.get(dataSourceItem).value,
76-
horizontalAxisValue: formatValueAttribute(horizontalAxisAttribute?.get(dataSourceItem).value),
77-
horizontalSortValue: horizontalSortAttribute?.get(dataSourceItem).value,
78-
verticalAxisValue: formatValueAttribute(verticalAxisAttribute?.get(dataSourceItem).value),
79-
verticalSortValue: verticalSortAttribute?.get(dataSourceItem).value
80-
}));
78+
objectMap.current = new Map();
79+
const dataSourceItems = seriesDataSource.items.map(dataSourceItem => {
80+
objectMap.current.set(dataSourceItem.id, dataSourceItem);
81+
const item = {
82+
value: ensure(seriesValueAttribute).get(dataSourceItem).value?.toNumber(),
83+
hoverText: tooltipHoverText?.get(dataSourceItem).value,
84+
horizontalAxisValue: formatValueAttribute(horizontalAxisAttribute?.get(dataSourceItem).value),
85+
horizontalSortValue: horizontalSortAttribute?.get(dataSourceItem).value,
86+
verticalAxisValue: formatValueAttribute(verticalAxisAttribute?.get(dataSourceItem).value),
87+
verticalSortValue: verticalSortAttribute?.get(dataSourceItem).value,
88+
id: dataSourceItem.id
89+
};
90+
return item;
91+
});
8192
setHeatMapData(dataSourceItems);
8293
}
8394
}, [
@@ -90,7 +101,32 @@ export const useHeatMapDataSeries = ({
90101
verticalSortAttribute
91102
]);
92103

93-
const onClick = useMemo(() => (onClickAction ? () => executeAction(onClickAction) : undefined), [onClickAction]);
104+
const onClick = useCallback(
105+
(item: ObjectItem, data: PlotDatum) => {
106+
let selectedObjectItem: ObjectItem | undefined = item;
107+
if (selectedObjectItem === null || selectedObjectItem === undefined) {
108+
const selectedLocalHeatmapData = heatmapChartData.values().find(heatMapPointData => {
109+
return (
110+
heatMapPointData.horizontalAxisValue === data.x &&
111+
heatMapPointData.verticalAxisValue === data.y &&
112+
heatMapPointData.value === data.z
113+
);
114+
});
115+
116+
if (selectedLocalHeatmapData) {
117+
selectedObjectItem = objectMap.current.get(selectedLocalHeatmapData.id);
118+
}
119+
}
120+
121+
if (selectedObjectItem) {
122+
executeAction(onClickAction?.get(selectedObjectItem));
123+
if (seriesItemSelection && seriesItemSelection.type === "Single") {
124+
seriesItemSelection.setSelection(selectedObjectItem);
125+
}
126+
}
127+
},
128+
[onClickAction, heatmapChartData, seriesItemSelection]
129+
);
94130

95131
return useMemo<HeatMapHookData>(() => {
96132
// `Array.reverse` mutates, so we make a copy.

packages/pluggableWidgets/heatmap-chart-web/src/package.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8" ?>
22
<package xmlns="http://www.mendix.com/package/1.0/">
3-
<clientModule name="HeatMap" version="6.0.0" xmlns="http://www.mendix.com/clientModule/1.0/">
3+
<clientModule name="HeatMap" version="6.2.1" xmlns="http://www.mendix.com/clientModule/1.0/">
44
<widgetFiles>
55
<widgetFile path="HeatMap.xml" />
66
</widgetFiles>

packages/pluggableWidgets/heatmap-chart-web/typings/HeatMapProps.d.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* @author Mendix Widgets Framework Team
55
*/
66
import { ComponentType, CSSProperties, ReactNode } from "react";
7-
import { ActionValue, DynamicValue, ListValue, ListAttributeValue, ListExpressionValue } from "mendix";
7+
import { DynamicValue, ListValue, ListActionValue, ListAttributeValue, ListExpressionValue, SelectionSingleValue } from "mendix";
88
import { Big } from "big.js";
99

1010
export type HorizontalSortOrderEnum = "asc" | "desc";
@@ -34,6 +34,7 @@ export interface HeatMapContainerProps {
3434
tabIndex?: number;
3535
seriesDataSource: ListValue;
3636
seriesValueAttribute: ListAttributeValue<Big>;
37+
seriesItemSelection?: SelectionSingleValue;
3738
horizontalAxisAttribute?: ListAttributeValue<string>;
3839
horizontalSortAttribute?: ListAttributeValue<Big | string | Date>;
3940
horizontalSortOrder: HorizontalSortOrderEnum;
@@ -55,7 +56,7 @@ export interface HeatMapContainerProps {
5556
width: number;
5657
heightUnit: HeightUnitEnum;
5758
height: number;
58-
onClickAction?: ActionValue;
59+
onClickAction?: ListActionValue;
5960
tooltipHoverText?: ListExpressionValue<string>;
6061
enableThemeConfig: boolean;
6162
customLayout: string;
@@ -76,6 +77,7 @@ export interface HeatMapPreviewProps {
7677
translate: (text: string) => string;
7778
seriesDataSource: {} | { caption: string } | { type: string } | null;
7879
seriesValueAttribute: string;
80+
seriesItemSelection: "None" | "Single";
7981
horizontalAxisAttribute: string;
8082
horizontalSortAttribute: string;
8183
horizontalSortOrder: HorizontalSortOrderEnum;

packages/shared/charts/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@mendix/shared-charts",
3-
"version": "2.2.0",
3+
"version": "2.2.1",
44
"description": "Shared components for charts",
55
"copyright": "© Mendix Technology BV 2025. All rights reserved.",
66
"private": true,

packages/shared/charts/src/components/ChartView.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,16 @@ export const ChartView = ({
3535
const [{ curveNumber, pointIndex, pointIndices, pointNumber, pointNumbers }] = event.points;
3636
const index = pointIndex ?? pointNumber;
3737
const indices = pointIndices ?? pointNumbers;
38-
const itemIndex = getItemIndex(index, indices);
39-
const { dataSourceItems, onClick } = data[curveNumber];
40-
const item = dataSourceItems[itemIndex];
41-
onClick?.(item);
38+
try {
39+
const itemIndex = getItemIndex(index, indices);
40+
const { dataSourceItems, onClick } = data[curveNumber];
41+
const item = dataSourceItems[itemIndex];
42+
onClick?.(item);
43+
} catch (_e: any) {
44+
// let the chart handle it's own onClick
45+
const { onClick } = data[curveNumber];
46+
onClick?.(null, event.points[0]);
47+
}
4248
},
4349
[data]
4450
);

packages/shared/charts/src/components/types.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { ObjectItem } from "mendix";
2-
import { Config, Data, Layout } from "plotly.js-dist-min";
2+
import { Config, Data, Layout, PlotDatum } from "plotly.js-dist-min";
33

44
declare module "plotly.js-dist-min" {
55
interface PlotDatum {
66
/** This array appears on only when aggregation is used */
77
pointIndices?: number[];
88
pointNumbers?: number[];
9+
// this is only appear on 3 dimentional matrix datasource
10+
z?: number;
911
}
1012
}
1113
export type ExtraTraceProps = {
@@ -14,7 +16,7 @@ export type ExtraTraceProps = {
1416
/** JSON string. Expected to be an object with custom 'trace' options. */
1517
customSeriesOptions: string | undefined;
1618
/** Click handler for each point on current 'trace'. Should be call with ObjectItem associated with clicked point. */
17-
onClick?: (item: ObjectItem) => void;
19+
onClick?: (item: ObjectItem | null, data?: Partial<PlotDatum>) => void;
1820
};
1921

2022
export type PlotTrace = Partial<Data> & ExtraTraceProps;

0 commit comments

Comments
 (0)