chore: [Map chart widget] Replace fusion charts with Echarts as chart provider (#31482)

# Description
This pr replaces fusion chart lib with echarts in the map chart widget.
It also checkins the necessary maps.

#### PR fixes following issue(s)
Fixes https://github.com/appsmithorg/appsmith/issues/31081


#### Type of change

- Chore (housekeeping or task changes that don't impact user perception)

## Testing
>
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also
list any relevant details for your test configuration.
> Delete anything that is not relevant
- [x] Manual
- [ ] JUnit
- [ ] Jest
- [ ] Cypress
>
>
#### Test Plan
> Add Testsmith test cases links that relate to this PR
>
>
#### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
>
>
>
## Checklist:
#### Dev activity
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Updated the Widget interface to make link properties optional,
enhancing flexibility.
- Added a `retryPromise` function for improved error handling and retry
logic in asynchronous operations.
- Introduced new mapping data and utilities for the MapChartWidget,
enabling detailed country/region information and dynamic map types.

- **Enhancements**
- Improved error handling in widget callouts to gracefully handle
missing links.
- Enhanced the MapChartWidget with new functionalities including dynamic
map data loading, chart resizing, and skeleton UI for loading state.

- **Refactor**
- Refactored chart configurations and event handling in MapChartWidget
for better performance and readability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
balajisoundar 2024-03-08 13:38:55 +05:30 committed by GitHub
parent 583c478ab3
commit 1cce29987c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 1677 additions and 290 deletions

View File

@ -79,6 +79,7 @@
"@tanstack/virtual-core": "^3.0.0-beta.18",
"@tinymce/tinymce-react": "^3.13.0",
"@types/babel__standalone": "^7.1.7",
"@types/d3-geo": "^3.1.0",
"@types/google.maps": "^3.51.0",
"@types/react-page-visibility": "^6.4.1",
"@types/web": "^0.0.99",
@ -106,6 +107,7 @@
"craco-babel-loader": "^1.0.4",
"cssnano": "^6.0.1",
"cypress-log-to-output": "^1.1.2",
"d3-geo": "^3.1.0",
"dayjs": "^1.10.6",
"deep-diff": "^1.0.2",
"design-system": "npm:@appsmithorg/design-system@2.1.35",
@ -118,7 +120,6 @@
"focus-trap-react": "^8.9.2",
"fuse.js": "^3.4.5",
"fusioncharts": "^3.18.0",
"fusionmaps": "^3.18.0",
"graphql": "^16.8.1",
"history": "^4.10.1",
"http-proxy": "^1.18.1",
@ -170,7 +171,6 @@
"react-documents": "^1.0.4",
"react-dom": "^17.0.2",
"react-full-screen": "^1.1.0",
"react-fusioncharts": "^3.1.2",
"react-google-recaptcha": "^2.1.0",
"react-helmet": "^5.2.1",
"react-hook-form": "^7.28.0",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -131,7 +131,7 @@ type GetEditorCallouts = (props: WidgetProps) => WidgetCallout[];
export interface WidgetCallout {
message: string;
links: [
links?: [
{
text: string;
url: string;

View File

@ -106,7 +106,7 @@ export function renderWidgetCallouts(props: WidgetProps): JSX.Element[] {
if (getEditorCallouts) {
const callouts: WidgetCallout[] = getEditorCallouts(props);
return callouts.map((callout, index) => {
const links = callout.links.map((link) => {
const links = callout.links?.map((link) => {
return {
children: link.text,
to: link.url,

View File

@ -343,27 +343,41 @@ export function hexToRgb(hex: string): {
};
}
/*
* Function to call the given function until the promise it returns resolves or the max retries are reached
*
* @param fn - function that returns a promise
* @param retriesLeft - number of retries
* @param interval - interval between retries
* @param shouldRetry - function to determine if the promise should be retried, helpful when we want to retry only on specific errors
* @returns Promise
*
*/
export const retryPromise = async (
fn: () => Promise<any>,
retriesLeft = 5,
interval = 1000,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
shouldRetry = (e: Error) => true, // default to retry on all errors
): Promise<any> => {
return new Promise((resolve, reject) => {
fn()
.then(resolve)
.catch(() => {
setTimeout(async () => {
if (retriesLeft === 1) {
return Promise.reject({
code: ERROR_CODES.SERVER_ERROR,
message: createMessage(ERROR_500),
show: false,
});
}
.catch((e) => {
if (shouldRetry(e)) {
setTimeout(async () => {
if (retriesLeft === 1) {
return Promise.reject({
code: ERROR_CODES.SERVER_ERROR,
message: createMessage(ERROR_500),
show: false,
});
}
// Passing on "reject" is the important part
retryPromise(fn, retriesLeft - 1, interval).then(resolve, reject);
}, interval);
// Passing on "reject" is the important part
retryPromise(fn, retriesLeft - 1, interval).then(resolve, reject);
}, interval);
}
});
});
};

View File

@ -1,17 +0,0 @@
export const CUSTOM_MAP_PLUGINS: Record<string, any> = {
world: require(`fusionmaps/maps/fusioncharts.world.js`),
worldwithantarctica: require(
`fusionmaps/maps/fusioncharts.worldwithantarctica.js`,
),
europe: require(`fusionmaps/maps/fusioncharts.europe.js`),
northamerica: require(`fusionmaps/maps/fusioncharts.northamerica.js`),
southamerica: require(`fusionmaps/maps/fusioncharts.southamerica.js`),
asia: require(`fusionmaps/maps/fusioncharts.asia.js`),
oceania: require(`fusionmaps/maps/fusioncharts.oceania.js`),
africa: require(`fusionmaps/maps/fusioncharts.africa.js`),
usa: require(`fusionmaps/maps/fusioncharts.usa.js`),
};
export const CUSTOM_MAP_TYPES = Object.keys(CUSTOM_MAP_PLUGINS).map(
(each) => `maps/${each}`,
);

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +1,11 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useMemo, useRef, useState } from "react";
import styled from "styled-components";
// Include the react-fusioncharts component
import ReactFC from "react-fusioncharts";
// Include the fusioncharts library
import type { ChartObject } from "fusioncharts";
import FusionCharts from "fusioncharts";
// Import FusionMaps
import FusionMaps from "fusioncharts/fusioncharts.maps";
import World from "fusioncharts/maps/fusioncharts.world";
import USA from "fusioncharts/maps/fusioncharts.usa";
// Include the theme as fusion
import FusionTheme from "fusioncharts/themes/fusioncharts.theme.fusion";
// Import the dataset and the colorRange of the map
import type { MapColorObject } from "../constants";
import { dataSetForWorld, MapTypes } from "../constants";
import { CUSTOM_MAP_PLUGINS } from "../CustomMapConstants";
import { Colors } from "constants/Colors";
// Adding the chart and theme as dependency to the core fusioncharts
ReactFC.fcRoot(FusionCharts, FusionMaps, World, FusionTheme, USA);
import type { MapColorObject, MapTypes } from "../constants";
import type { MapData } from "./types";
import { getChartOption, loadMap } from "./utilities";
import * as echarts from "echarts";
import countryDetails from "./countryDetails";
import clsx from "clsx";
const MapChartContainer = styled.div<{
borderRadius?: string;
@ -40,217 +24,133 @@ const MapChartContainer = styled.div<{
}
`;
export interface MapData {
value?: string;
displayValue?: string;
toolText?: string;
color?: string;
alpha?: number;
link?: string;
font?: string;
fontSize?: string;
fontColor?: string;
fontBold?: boolean;
showLabel?: boolean;
showToolTip?: boolean;
labelConnectorColor?: string;
labelConnectorAlpha?: number;
useHoverColor?: boolean;
}
export default function EchartComponent(props: MapChartComponentProps) {
const [isLoading, setIsLoading] = useState(false);
export type MapType = keyof typeof MapTypes;
const [key, setKey] = useState(0);
export interface EntityData {
id: string;
label: string;
originalId: string;
shortLabel: string;
value: number;
}
function MapChartComponent(props: MapChartComponentProps) {
const { caption, colorRange, data, onDataPointClick, showLabels, type } =
props;
const fontFamily =
props.fontFamily === "System Default" ? "inherit" : props.fontFamily;
props.fontFamily === "System Default" ? "" : props.fontFamily;
// Creating the JSON object to store the chart configurations
const defaultChartConfigs: ChartObject = {
type: "maps/world", // The chart type
width: "100%", // Width of the chart
height: "100%", // Height of the chart
dataFormat: "json", // Data type
dataSource: {
// Map Configuration
chart: {
caption: "Average Annual Population Growth",
includevalueinlabels: "1",
labelsepchar: ": ",
entityFillHoverColor: "#FFF9C4",
theme: "fusion",
const colorRangePieces = useMemo(() => {
return colorRange.map((color) => {
const alpha = color.alpha ?? 100;
// Caption
captionFontSize: "24",
captionAlignment: "center",
captionPadding: "20",
captionFontColor: Colors.THUNDER,
captionFontBold: "1",
return {
min: color.minValue,
max: color.maxValue,
color: color.code,
colorAlpha: alpha ? alpha / 100 : 0,
label: color.displayValue,
};
});
}, [colorRange]);
// Legend
legendIconSides: "4",
legendIconBgAlpha: "100",
legendIconAlpha: "100",
legendItemFont: fontFamily,
legendPosition: "top",
valueFont: fontFamily,
const transformedData = useMemo(() => {
return data.map((each) => ({
name: each.id,
value: each.value,
}));
}, [data]);
// Spacing
chartLeftMargin: "10",
chartTopMargin: "15",
chartRightMargin: "10",
chartBottomMargin: "10",
const chartContainer = useRef<HTMLDivElement>(null);
// Base Styling
baseFont: fontFamily,
bgColor: Colors.WHITE,
},
// Aesthetics; ranges synced with the slider
colorRange: {
gradient: "0",
},
// Source data as JSON --> id represents countries of the world.
data: dataSetForWorld,
},
events: {},
};
const [chartConfigs, setChartConfigs] = useState(defaultChartConfigs);
const [chart, setChart] = useState(new FusionCharts(defaultChartConfigs));
const chartInstance = useRef<echarts.ECharts | null>();
useEffect(() => {
// Attach event handlers
const newChartConfigs: any = {
...chartConfigs,
chartInstance.current = echarts.init(
chartContainer.current!,
{},
{
width: props.width,
height: props.height,
},
);
}, [chartContainer]);
useEffect(() => {
const handler = (event: any) => {
const id = event.data.name;
const regionDetail = countryDetails[type][id];
onDataPointClick({
value: parseFloat(event.data.value),
label: regionDetail.label,
shortLabel: regionDetail.short_label,
originalId: id,
id: id.toLowerCase(),
});
};
newChartConfigs["events"]["entityClick"] = onDataPointClick;
setChartConfigs(newChartConfigs);
chartInstance.current?.on("click", "series", handler);
return () => {
chart.removeEventListener("entityClick", onDataPointClick);
chartInstance.current?.off("click", handler);
};
}, [onDataPointClick]);
}, [onDataPointClick, chartInstance.current, type]);
useEffect(() => {
const newChartConfigs: any = {
...chartConfigs,
};
const fontFamily =
props.fontFamily === "System Default" ? "inherit" : props.fontFamily;
setIsLoading(true);
newChartConfigs["dataSource"]["chart"]["legendItemFont"] = fontFamily;
newChartConfigs["dataSource"]["chart"]["valueFont"] = fontFamily;
newChartConfigs["dataSource"]["chart"]["baseFont"] = fontFamily;
setChartConfigs(newChartConfigs);
}, [props.fontFamily]);
loadMap(type).then(() => {
setIsLoading(false);
// we are using Math.random to force the chart to set options again
// to avoid the race conditions while loading maps
setKey(Math.random());
});
}, [type]);
useEffect(() => {
const newChartConfigs: any = {
...chartConfigs,
};
newChartConfigs["dataSource"]["chart"]["caption"] = caption;
setChartConfigs(newChartConfigs);
}, [caption]);
useEffect(() => {
const targetValue = showLabels ? "1" : "0";
const newChartConfigs: any = {
...chartConfigs,
};
newChartConfigs["dataSource"]["chart"]["showLabels"] = targetValue;
setChartConfigs(newChartConfigs);
}, [showLabels]);
useEffect(() => {
const newChartConfigs: any = {
...chartConfigs,
};
newChartConfigs["dataSource"]["colorRange"]["color"] = colorRange;
chart.setChartData(newChartConfigs.dataSource, "json");
}, [JSON.stringify(colorRange)]);
useEffect(() => {
const newChartConfigs = {
...chartConfigs,
dataSource: {
...(chartConfigs.dataSource || {}),
data,
},
};
switch (type) {
case MapTypes.WORLD_WITH_ANTARCTICA:
newChartConfigs.type = "maps/worldwithantarctica";
break;
case MapTypes.EUROPE:
newChartConfigs.type = "maps/europe";
break;
case MapTypes.NORTH_AMERICA:
newChartConfigs.type = "maps/northamerica";
break;
case MapTypes.SOURTH_AMERICA:
newChartConfigs.type = "maps/southamerica";
break;
case MapTypes.ASIA:
newChartConfigs.type = "maps/asia";
break;
case MapTypes.OCEANIA:
newChartConfigs.type = "maps/oceania";
break;
case MapTypes.AFRICA:
newChartConfigs.type = "maps/africa";
break;
case MapTypes.USA:
newChartConfigs.type = "maps/usa";
break;
default:
newChartConfigs.type = "maps/world";
break;
if (!isLoading && !!echarts.getMap(type)) {
chartInstance.current?.setOption(
getChartOption(
caption,
showLabels,
colorRangePieces,
transformedData,
type,
props.height,
props.width,
fontFamily,
),
true,
);
}
}, [
isLoading,
caption,
showLabels,
colorRangePieces,
transformedData,
fontFamily,
chartInstance.current,
type,
key,
props.height,
props.width,
]);
if (type === MapTypes.WORLD) {
setChartConfigs(newChartConfigs);
return;
}
initializeMap(newChartConfigs);
}, [JSON.stringify(data), type]);
// Called by FC-React component to return the rendered chart
const renderComplete = (chart: FusionCharts.FusionCharts) => {
setChart(chart);
};
const initializeMap = (configs: ChartObject) => {
const { type: mapType } = configs;
if (mapType) {
const alias = mapType.substring(5);
const mapDefinition = CUSTOM_MAP_PLUGINS[alias];
ReactFC.fcRoot(FusionCharts, FusionMaps, mapDefinition, FusionTheme);
setChartConfigs(configs);
}
};
useEffect(() => {
chartInstance.current?.resize({
width: props.width,
height: props.height,
});
}, [props.width, props.height]);
return (
<MapChartContainer
borderRadius={props.borderRadius}
boxShadow={props.boxShadow}
className={clsx({
"bp3-skeleton": isLoading,
})}
onClick={(e) => e.stopPropagation()}
>
<ReactFC {...chartConfigs} onRender={renderComplete} />
<div ref={chartContainer} />
</MapChartContainer>
);
}
@ -262,10 +162,10 @@ export interface MapChartComponentProps {
isVisible: boolean;
onDataPointClick: (evt: any) => void;
showLabels: boolean;
type: MapType;
type: MapTypes;
borderRadius?: string;
boxShadow?: string;
fontFamily?: string;
height: number;
width: number;
}
export default MapChartComponent;

View File

@ -0,0 +1,8 @@
import type { MapTypes } from "widgets/MapChartWidget/constants";
export interface MapData {
id: string;
value: number;
}
export type MapType = keyof typeof MapTypes;

View File

@ -0,0 +1,286 @@
import * as echarts from "echarts";
import countryDetails from "./countryDetails";
import { MapTypes } from "../constants";
import { geoAlbers, geoAzimuthalEqualArea, geoMercator } from "d3-geo";
import log from "loglevel";
import * as Sentry from "@sentry/react";
import { retryPromise } from "utils/AppsmithUtils";
interface GeoSpecialAreas {
[areaName: string]: {
left: number;
top: number;
width?: number;
height?: number;
};
}
export function getSpecialAreas(map: MapTypes): GeoSpecialAreas {
switch (map) {
case MapTypes.USA:
return {
AK: {
left: -131,
top: 25,
width: 15,
},
HI: {
left: -110,
top: 25,
width: 5,
},
PR: {
left: -76,
top: 26,
width: 2,
},
};
default:
return {};
}
}
/*
* Function to load the map geojson file and register it with echarts
*/
export const loadMap = (() => {
let abortController: AbortController | null = null;
return async (type: MapTypes) => {
if (!echarts.getMap(type)) {
if (abortController && abortController.abort) {
abortController.abort();
}
if (AbortController) {
abortController = new AbortController();
}
return retryPromise(
async () => {
return fetch(`/static/maps/${type}.json`, {
signal: abortController?.signal,
});
},
3,
0,
(error: any) => error.code !== 20,
)
.then(
(response) => response.json(),
(error) => {
abortController = null;
if (error.code !== 20) {
log.error({ error });
Sentry.captureException(error);
}
},
)
.then((geoJson) => {
abortController = null;
echarts.registerMap(type, geoJson, getSpecialAreas(type));
});
} else {
return Promise.resolve();
}
};
})();
function getProjection(type: string) {
switch (type) {
case "OCEANIA":
return geoAzimuthalEqualArea()
.scale(242)
.center([22, -39])
.translate([480, 319])
.rotate([-165, 18, 0]);
case "ASIA":
return geoAzimuthalEqualArea()
.scale(400)
.center([-17, -26])
.translate([480, 303])
.rotate([-103, -55, 7]);
case "AFRICA":
return geoMercator()
.scale(278)
.center([110, 4])
.translate([936, 288])
.rotate([180, 180, 180]);
case "SOURTH_AMERICA":
return geoAlbers()
.scale(363)
.center([-15, 24])
.translate([450, 271])
.rotate([51, 55, 9]);
case "NORTH_AMERICA":
return geoAzimuthalEqualArea()
.scale(400)
.center([13, 25])
.translate([539, 415])
.rotate([-84, 174, -180]);
}
}
export function getPositionOffset(
type: MapTypes,
width: number,
height: number,
) {
switch (type) {
case MapTypes.SOURTH_AMERICA:
case MapTypes.NORTH_AMERICA:
case MapTypes.AFRICA:
return {
layoutSize: Math.min(width, height - 130),
layoutCenter: ["50%", height / 2 + 30],
};
case MapTypes.ASIA:
return {
layoutSize: Math.min(width, height - 65),
layoutCenter: ["50%", height / 2 + 30],
};
case MapTypes.EUROPE:
case MapTypes.USA:
return {
layoutSize: Math.min(width, height),
layoutCenter: ["50%", height / 2 + 30],
};
case MapTypes.WORLD:
case MapTypes.WORLD_WITH_ANTARCTICA:
return {
layoutSize: Math.min(width, height),
layoutCenter: ["50%", height / 2 + 40],
};
default:
return {};
}
}
export const getChartOption = (
caption: string,
showLabel: boolean,
colorRangePieces: {
min: number;
max: number;
color: string;
}[],
data: { name: string; value: number }[],
type: MapTypes,
height: number,
width: number,
fontFamily?: string,
) => {
const projection = getProjection(type);
let projectionConfig = {};
if (projection) {
projectionConfig = {
projection: {
project: (point: [number, number]) => projection(point),
unproject: (point: [number, number]) => projection.invert?.(point),
stream: projection.stream,
},
};
}
return {
title: {
text: caption,
left: "center",
top: "12px",
textStyle: {
fontSize: 24,
fontWeight: "bold",
fontFamily,
},
},
tooltip: {
trigger: "item",
showDelay: 0,
transitionDuration: 0.2,
},
visualMap: {
show: true,
type: "piecewise",
pieces: colorRangePieces,
formatter: (min: number, max: number) => {
return `${min}-${max}`;
},
orient: "horizontal",
top: "68px",
left: "center",
itemWidth: 12,
itemHeight: 12,
textStyle: {
fontSize: 14,
color: "#4c5664",
overflow: "break",
},
itemSymbol: "rect",
},
toolbox: {
show: false,
},
series: [
{
type: "map",
...getPositionOffset(type, width, height),
roam: true,
map: type,
itemStyle: {
borderColor: "#ccc",
areaColor: "#aeaeae",
},
emphasis: {
itemStyle: {
areaColor: "#FFF9C4",
},
},
tooltip: {
show: true,
borderColor: "#ccc",
padding: [4, 8],
fontFamily,
formatter: (d: any) => {
const key = d?.name as string;
const label = countryDetails[type][key]?.["label"];
return `${label}, ${d.data?.value || "-"}`;
},
textStyle: {
fontSize: 14,
color: "#4c5664",
},
extraCssText: "border-radius: 0;",
},
label: {
show: showLabel,
fontFamily,
position: "top",
formatter: (d: any) => {
const key = d?.name as string;
const label = countryDetails[type][key]["short_label"];
return `${label}: ${d.data?.value || "-"}`;
},
textStyle: {
fontSize: 12,
color: "#4c5664",
},
},
scaleLimit: {
min: 1,
max: 4,
},
labelLayout: () => {
return {
hideOverlap: true,
};
},
nameProperty: "id",
data,
...projectionConfig,
},
],
};
};

View File

@ -1,6 +1,4 @@
import React, { lazy, Suspense } from "react";
import Skeleton from "components/utils/Skeleton";
import React, { Suspense, lazy } from "react";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
@ -9,7 +7,6 @@ import { retryPromise } from "utils/AppsmithUtils";
import { AutocompleteDataType } from "utils/autocomplete/AutocompleteDataType";
import type { WidgetProps, WidgetState } from "widgets/BaseWidget";
import BaseWidget from "widgets/BaseWidget";
import type { MapType } from "../component";
import type { MapColorObject } from "../constants";
import {
dataSetForAfrica,
@ -27,6 +24,7 @@ import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
import type {
AnvilConfig,
AutocompletionDefinitions,
WidgetCallout,
} from "WidgetProvider/constants";
import { FILL_WIDGET_MIN_WIDTH } from "constants/minWidthConstants";
import {
@ -35,6 +33,8 @@ import {
} from "layoutSystems/common/utils/constants";
import IconSVG from "../icon.svg";
import { WIDGET_TAGS } from "constants/WidgetConstants";
import Skeleton from "components/utils/Skeleton";
import type { MapType } from "../component/types";
const MapChartComponent = lazy(async () =>
retryPromise(
@ -329,6 +329,15 @@ class MapChartWidget extends BaseWidget<MapChartWidgetProps, WidgetState> {
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
additionalAutoComplete: () => ({
selectedDataPoint: {
value: 1.1,
label: "",
shortLabel: "",
originalId: "",
id: "",
},
}),
},
],
},
@ -448,15 +457,31 @@ class MapChartWidget extends BaseWidget<MapChartWidgetProps, WidgetState> {
};
}
handleDataPointClick = (evt: any) => {
static getMethods() {
return {
getEditorCallouts(): WidgetCallout[] {
return [
{
message:
"Map chart widget switched from using Fusion chart library to Echarts. Please verify that the chart is displaying properly",
},
];
},
};
}
handleDataPointClick = (data: any) => {
const { onDataPointClick } = this.props;
this.props.updateWidgetMetaProperty("selectedDataPoint", evt.data, {
this.props.updateWidgetMetaProperty("selectedDataPoint", data, {
triggerPropertyName: "onDataPointClick",
dynamicString: onDataPointClick,
event: {
type: EventType.ON_DATA_POINT_CLICK,
},
globalContext: {
selectedDataPoint: data,
},
});
};
@ -469,14 +494,16 @@ class MapChartWidget extends BaseWidget<MapChartWidgetProps, WidgetState> {
<MapChartComponent
borderRadius={this.props.borderRadius}
boxShadow={this.props.boxShadow}
caption={mapTitle}
caption={mapTitle || ""}
colorRange={colorRange}
data={data}
fontFamily={this.props.fontFamily ?? "Nunito Sans"}
height={this.props.componentHeight}
isVisible={isVisible}
onDataPointClick={this.handleDataPointClick}
showLabels={showLabels}
type={mapType}
width={this.props.componentWidth}
/>
</Suspense>
);

View File

@ -10570,6 +10570,15 @@ __metadata:
languageName: node
linkType: hard
"@types/d3-geo@npm:^3.1.0":
version: 3.1.0
resolution: "@types/d3-geo@npm:3.1.0"
dependencies:
"@types/geojson": "*"
checksum: a4b2daa8a64012912ce7186891e8554af123925dca344c111b771e168a37477e02d504c6c94ee698440380e8c4f3f373d6755be97935da30eae0904f6745ce40
languageName: node
linkType: hard
"@types/deep-diff@npm:^1.0.0":
version: 1.0.0
resolution: "@types/deep-diff@npm:1.0.0"
@ -10754,6 +10763,13 @@ __metadata:
languageName: node
linkType: hard
"@types/geojson@npm:*":
version: 7946.0.14
resolution: "@types/geojson@npm:7946.0.14"
checksum: ae511bee6488ae3bd5a3a3347aedb0371e997b14225b8983679284e22fa4ebd88627c6e3ff8b08bf4cc35068cb29310c89427311ffc9322c255615821a922e71
languageName: node
linkType: hard
"@types/glob@npm:^7.1.3":
version: 7.2.0
resolution: "@types/glob@npm:7.2.0"
@ -13110,6 +13126,7 @@ __metadata:
"@tinymce/tinymce-react": ^3.13.0
"@types/babel__standalone": ^7.1.7
"@types/codemirror": ^0.0.96
"@types/d3-geo": ^3.1.0
"@types/deep-diff": ^1.0.0
"@types/dom-mediacapture-record": ^1.0.11
"@types/downloadjs": ^1.4.2
@ -13200,6 +13217,7 @@ __metadata:
cypress-terminal-report: ^5.3.6
cypress-wait-until: ^1.7.2
cypress-xpath: ^1.6.0
d3-geo: ^3.1.0
dayjs: ^1.10.6
deep-diff: ^1.0.2
design-system: "npm:@appsmithorg/design-system@2.1.35"
@ -13228,7 +13246,6 @@ __metadata:
focus-trap-react: ^8.9.2
fuse.js: ^3.4.5
fusioncharts: ^3.18.0
fusionmaps: ^3.18.0
graphql: ^16.8.1
history: ^4.10.1
http-proxy: ^1.18.1
@ -13301,7 +13318,6 @@ __metadata:
react-documents: ^1.0.4
react-dom: ^17.0.2
react-full-screen: ^1.1.0
react-fusioncharts: ^3.1.2
react-google-recaptcha: ^2.1.0
react-helmet: ^5.2.1
react-hook-form: ^7.28.0
@ -16798,6 +16814,24 @@ __metadata:
languageName: node
linkType: hard
"d3-array@npm:2.5.0 - 3":
version: 3.2.4
resolution: "d3-array@npm:3.2.4"
dependencies:
internmap: 1 - 2
checksum: a5976a6d6205f69208478bb44920dd7ce3e788c9dceb86b304dbe401a4bfb42ecc8b04c20facde486e9adcb488b5d1800d49393a3f81a23902b68158e12cddd0
languageName: node
linkType: hard
"d3-geo@npm:^3.1.0":
version: 3.1.0
resolution: "d3-geo@npm:3.1.0"
dependencies:
d3-array: 2.5.0 - 3
checksum: adf82b0c105c0c5951ae0a833d4dfc479a563791ad7938579fa14e1cffd623b469d8aa7a37dc413a327fb6ac56880f3da3f6c43d4abe3c923972dd98f34f37d1
languageName: node
linkType: hard
"damerau-levenshtein@npm:^1.0.7":
version: 1.0.8
resolution: "damerau-levenshtein@npm:1.0.8"
@ -20017,28 +20051,6 @@ __metadata:
languageName: node
linkType: hard
"fusionmaps@npm:^3.18.0":
version: 3.18.0
resolution: "fusionmaps@npm:3.18.0"
dependencies:
"@babel/runtime": ^7.9.2
"@fusioncharts/accessibility": ^1.5.0
"@fusioncharts/charts": ^3.18.0
"@fusioncharts/constructor": ^1.5.0
"@fusioncharts/core": ^1.5.0
"@fusioncharts/datatable": ^1.5.0
"@fusioncharts/features": ^1.5.0
"@fusioncharts/fusiontime": ^2.6.0
"@fusioncharts/maps": ^3.18.0
"@fusioncharts/powercharts": ^3.18.0
"@fusioncharts/utils": ^1.5.0
"@fusioncharts/widgets": ^3.18.0
mutationobserver-shim: ^0.3.5
promise-polyfill: ^8.1.3
checksum: 0d9de18e59f04a671a076de27cb0e1a1e15d7a8ef655a42c1f5f26b9f4110d02ed0dfee6d09703896767259f262c400c402daec80ca495c73dfcbe5ae06d50fa
languageName: node
linkType: hard
"gauge@npm:^4.0.3":
version: 4.0.4
resolution: "gauge@npm:4.0.4"
@ -21391,6 +21403,13 @@ __metadata:
languageName: node
linkType: hard
"internmap@npm:1 - 2":
version: 2.0.3
resolution: "internmap@npm:2.0.3"
checksum: 7ca41ec6aba8f0072fc32fa8a023450a9f44503e2d8e403583c55714b25efd6390c38a87161ec456bf42d7bc83aab62eb28f5aef34876b1ac4e60693d5e1d241
languageName: node
linkType: hard
"interpret@npm:^2.2.0":
version: 2.2.0
resolution: "interpret@npm:2.2.0"
@ -29000,17 +29019,6 @@ __metadata:
languageName: node
linkType: hard
"react-fusioncharts@npm:^3.1.2":
version: 3.1.2
resolution: "react-fusioncharts@npm:3.1.2"
dependencies:
uuid: ^3.2.1
peerDependencies:
react: ^0.14.0 || ^15.0.0 || ^16.0.0
checksum: a3df0368e580b48c614fcb955e212750b6532c59b7991c0a33298330c21bd75c8b871efa658b1e1b3479d241da6d20f4bde31c2ce7a69d426d07d9a3a6a3ba48
languageName: node
linkType: hard
"react-google-recaptcha@npm:^2.1.0":
version: 2.1.0
resolution: "react-google-recaptcha@npm:2.1.0"
@ -33855,15 +33863,6 @@ __metadata:
languageName: node
linkType: hard
"uuid@npm:^3.2.1":
version: 3.4.0
resolution: "uuid@npm:3.4.0"
bin:
uuid: ./bin/uuid
checksum: 58de2feed61c59060b40f8203c0e4ed7fd6f99d42534a499f1741218a1dd0c129f4aa1de797bcf822c8ea5da7e4137aa3673431a96dae729047f7aca7b27866f
languageName: node
linkType: hard
"uuid@npm:^8.3.2":
version: 8.3.2
resolution: "uuid@npm:8.3.2"