Skip to content

Commit

Permalink
Merge pull request #372 from raheeliftikhar5/echarts-extension
Browse files Browse the repository at this point in the history
Echarts extension
  • Loading branch information
FalkWolsky authored Sep 14, 2023
2 parents 4968773 + b137622 commit 9a3126a
Show file tree
Hide file tree
Showing 23 changed files with 427 additions and 25 deletions.
3 changes: 2 additions & 1 deletion client/packages/lowcoder-comps/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lowcoder-comps",
"version": "0.0.12",
"version": "0.0.13",
"type": "module",
"license": "MIT",
"dependencies": {
Expand All @@ -14,6 +14,7 @@
"@types/react": "17",
"@types/react-dom": "17",
"big.js": "^6.2.1",
"echarts-extension-gmap": "^1.6.0",
"lowcoder-cli": "workspace:^",
"lowcoder-sdk": "workspace:^",
"mermaid": "^10.2.4",
Expand Down
52 changes: 43 additions & 9 deletions client/packages/lowcoder-comps/src/comps/chartComp/chartComp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,17 @@ import {
withViewFn,
ThemeContext,
chartColorPalette,
loadScript,
} from "lowcoder-sdk";
import { getEchartsLocale, trans } from "i18n/comps";
import { ItemColorComp } from "comps/chartComp/chartConfigs/lineChartConfig";
import {
echartsConfigOmitChildren,
getEchartsConfig,
getSelectedPoints,
loadGoogleMapsScript,
} from "comps/chartComp/chartUtils";
import 'echarts-extension-gmap';
import log from "loglevel";

let ChartTmpComp = (function () {
Expand All @@ -45,6 +48,7 @@ let ChartTmpComp = (function () {
ChartTmpComp = withViewFn(ChartTmpComp, (comp) => {
const echartsCompRef = useRef<ReactECharts | null>();
const [chartSize, setChartSize] = useState<ChartSize>();
const [mapScriptLoaded, setMapScriptLoaded] = useState(false);
const firstResize = useRef(true);
const theme = useContext(ThemeContext);
const defaultChartTheme = {
Expand Down Expand Up @@ -87,6 +91,34 @@ ChartTmpComp = withViewFn(ChartTmpComp, (comp) => {
);
}, [chartSize, ...Object.values(echartsConfigChildren)]);

const isMapScriptLoaded = useMemo(() => {
return mapScriptLoaded || window?.google;
}, [mapScriptLoaded])

const loadGoogleMapsData = () => {
const echartsCompInstance = echartsCompRef?.current?.getEchartsInstance();
if (!echartsCompInstance) {
return _.noop;
}
echartsCompInstance.getModel().getComponent("gmap").getGoogleMap();
}

const apiKey = comp.children.mapApiKey.getView();
const mode = comp.children.mode.getView();
useEffect(() => {
if(mode === 'map') {
const gMapScript = loadGoogleMapsScript('');
if(isMapScriptLoaded) {
loadGoogleMapsData();
return;
}
gMapScript.addEventListener('load', function () {
setMapScriptLoaded(true);
loadGoogleMapsData();
});
}
}, [mode, apiKey, option])

return (
<ReactResizeDetector
onResize={(w, h) => {
Expand All @@ -101,15 +133,17 @@ ChartTmpComp = withViewFn(ChartTmpComp, (comp) => {
}
}}
>
<ReactECharts
ref={(e) => (echartsCompRef.current = e)}
style={{ height: "100%" }}
notMerge
lazyUpdate
opts={{ locale: getEchartsLocale() }}
option={option}
theme={themeConfig}
/>
{(mode !== 'map' || (mode === 'map' && isMapScriptLoaded)) && (
<ReactECharts
ref={(e) => (echartsCompRef.current = e)}
style={{ height: "100%" }}
notMerge
lazyUpdate
opts={{ locale: getEchartsLocale() }}
option={option}
theme={mode !== 'map' ? themeConfig : undefined}
/>
)}
</ReactResizeDetector>
);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ const echartsUrlLocale = language === "zh" ? "zh" : "en";
export const optionUrl = `https://echarts.apache.org/${echartsUrlLocale}/option.html`;
export const examplesUrl = `https://echarts.apache.org/examples/${echartsUrlLocale}/index.html`;
export const xAxisTypeUrl = `${optionUrl}#xAxis.type`;
export const googleMapsApiUrl = `https://maps.googleapis.com/maps/api/js`;
export const mapOptionUrl = `https://github.com/plainheart/echarts-extension-gmap`;
export const mapExamplesUrl = `https://codepen.io/plainheart/pen/VweLGbR`;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { jsonControl, JSONObject, stateComp, toJSONObjectArray, toObject } from "lowcoder-sdk";
import { StringControl } from "lowcoder-sdk";
import { withDefault, BooleanControl, StringControl, NumberControl, JSONObjectControl } from "lowcoder-sdk";
import { dropdownControl } from "lowcoder-sdk";
import { eventHandlerControl } from "lowcoder-sdk";
import { valueComp, withType } from "lowcoder-sdk";
Expand All @@ -15,7 +15,6 @@ import { ScatterChartConfig } from "./chartConfigs/scatterChartConfig";
import { SeriesListComp } from "./seriesComp";
import { EChartsOption } from "echarts";
import { i18nObjs, trans } from "i18n/comps";
import { JSONValue } from "lowcoder";

export const ChartTypeOptions = [
{
Expand Down Expand Up @@ -45,6 +44,10 @@ const chartModeOptions = [
label: "ECharts JSON",
value: "json",
},
{
label: "Map",
value: "map",
},
] as const;

export const EventOptions = [
Expand Down Expand Up @@ -221,6 +224,14 @@ export const chartUiModeChildren = {
chartConfig: ChartOptionComp,
};

const chartMapModeChildren = {
mapApiKey: withDefault(StringControl, ''),
mapZoomLevel: withDefault(NumberControl, 3),
mapCenterLng: withDefault(NumberControl, 15.932644),
mapCenterLat: withDefault(NumberControl, 50.942063),
mapOptions: jsonControl(toObject, i18nObjs.defaultMapJsonOption),
}

export const chartChildrenMap = {
mode: dropdownControl(chartModeOptions, "ui"),
echartsOption: jsonControl(toObject, i18nObjs.defaultEchartsJsonOption),
Expand All @@ -236,6 +247,7 @@ export const chartChildrenMap = {
}>
>([]),
...chartUiModeChildren,
...chartMapModeChildren,
};

const chartUiChildrenMap = uiChildren(chartChildrenMap);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import {
RedButton,
Section,
sectionNames,
controlItem,
} from "lowcoder-sdk";
import { trans } from "i18n/comps";
import { examplesUrl, optionUrl } from "./chartConfigs/chartUrls";
import { examplesUrl, mapExamplesUrl, mapOptionUrl, optionUrl } from "./chartConfigs/chartUrls";

export function chartPropertyView(
children: ChartCompChildrenType,
Expand Down Expand Up @@ -147,6 +148,58 @@ export function chartPropertyView(
</>
);

const mapModePropertyView = (
<>
<Section name={'Map Configuration'}>
{children.mapApiKey.propertyView({
label: "API Key"
})}
{children.mapZoomLevel.propertyView({
label: "Zoom Level"
})}
{controlItem({}, (
<b style={{marginTop: '8px'}}>
{'Center Position'}
</b>
))}
{children.mapCenterLng.propertyView({
label: "Longitude"
})}
{children.mapCenterLat.propertyView({
label: "Latitude"
})}
</Section>
<Section name={'Map Data'}>
{children.mapOptions.propertyView({
label: trans("chart.echartsOptionLabel"),
styleName: "higher",
tooltip: (
<div>
<a href={mapOptionUrl} target="_blank" rel="noopener noreferrer">
{trans("chart.echartsMapOptionTooltip")}
</a>
<br />
<a href={mapExamplesUrl} target="_blank" rel="noopener noreferrer">
{trans("chart.echartsMapOptionExamples")}
</a>
</div>
),
})}
</Section>
<Section name={sectionNames.layout}>{hiddenPropertyView(children)}</Section>
</>
);

const getChatConfigByMode = (mode: string) => {
switch(mode) {
case "ui":
return uiModePropertyView;
case "json":
return jsonModePropertyView;
case "map":
return mapModePropertyView;
}
}
return (
<>
<Section name={trans("chart.mode")}>
Expand All @@ -155,7 +208,7 @@ export function chartPropertyView(
radioButton: true,
})}
</Section>
{children.mode.getView() === "ui" ? uiModePropertyView : jsonModePropertyView}
{getChatConfigByMode(children.mode.getView())}
</>
);
}
47 changes: 43 additions & 4 deletions client/packages/lowcoder-comps/src/comps/chartComp/chartUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ import {
noDataPieChartConfig,
} from "comps/chartComp/chartConstants";
import { getPieRadiusAndCenter } from "comps/chartComp/chartConfigs/pieChartConfig";
import { EChartsOption } from "echarts";
import { EChartsOptionWithMap } from "./reactEcharts/types";
import _ from "lodash";
import { chartColorPalette, isNumeric, JSONObject } from "lowcoder-sdk";
import { chartColorPalette, isNumeric, JSONObject, loadScript } from "lowcoder-sdk";
import { calcXYConfig } from "comps/chartComp/chartConfigs/cartesianAxisConfig";
import Big from "big.js";
import { googleMapsApiUrl } from "./chartConfigs/chartUrls";

export function transformData(
originData: JSONObject[],
Expand Down Expand Up @@ -122,10 +123,30 @@ export function getSeriesConfig(props: EchartsConfigProps) {
}

// https://echarts.apache.org/en/option.html
export function getEchartsConfig(props: EchartsConfigProps, chartSize?: ChartSize): EChartsOption {
export function getEchartsConfig(props: EchartsConfigProps, chartSize?: ChartSize): EChartsOptionWithMap {
if (props.mode === "json") {
return props.echartsOption ? props.echartsOption : {};
}
if(props.mode === "map") {
const {
mapZoomLevel,
mapCenterLat,
mapCenterLng,
mapOptions,
} = props;

const echartsOption = mapOptions ? mapOptions : {};
return {
gmap: {
center: [mapCenterLng, mapCenterLat],
zoom: mapZoomLevel,
renderOnMoving: true,
// echartsLayerZIndex: 2019,
roam: true
},
...echartsOption,
}
}
// axisChart
const axisChart = isAxisChart(props.chartConfig.type);
const gridPos = {
Expand All @@ -134,7 +155,7 @@ export function getEchartsConfig(props: EchartsConfigProps, chartSize?: ChartSiz
top: 50,
bottom: 35,
};
let config: EChartsOption = {
let config: EChartsOptionWithMap = {
title: { text: props.title, left: "center" },
tooltip: {
confine: true,
Expand Down Expand Up @@ -238,3 +259,21 @@ export function getSelectedPoints(param: any, option: any) {
}
return [];
}

export function loadGoogleMapsScript(apiKey?: string) {
const mapsUrl = `${googleMapsApiUrl}?key=${apiKey}`;
const scripts = document.getElementsByTagName('script');
const scriptIndex = _.findIndex(scripts, (script) => script.src === mapsUrl);
if(scriptIndex > -1) {
return scripts[scriptIndex];
}

const script = document.createElement("script");
script.type = "text/javascript";
script.src = mapsUrl;
script.async = true;
script.defer = true;
window.document.body.appendChild(script);

return script;
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ export default class EChartsReactCore extends PureComponent<EChartsReactProps> {
if (
!isEqual(prevProps.theme, this.props.theme) ||
!isEqual(prevProps.opts, this.props.opts) ||
!isEqual(prevProps.onEvents, this.props.onEvents)
!isEqual(prevProps.onEvents, this.props.onEvents) ||
this.props.option.gmap
) {
this.dispose();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as echarts from "echarts";
import { EChartsReactProps, EChartsOption, EChartsInstance } from "./types";
import { EChartsReactProps, EChartsInstance, EChartsOptionWithMap } from "./types";
import EChartsReactCore from "./core";

/**
* reference: https://github.com/hustcc/echarts-for-react
* add exception-catch for setOption
* if query isn't successfully loaded, chart will fail to load and can't reload
*/
export type { EChartsReactProps, EChartsOption, EChartsInstance };
export type { EChartsReactProps, EChartsOptionWithMap, EChartsInstance };

// export the Component the echarts Object.
export default class EChartsReact extends EChartsReactCore {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { CSSProperties } from "react";
import { EChartsOption } from "echarts";
import { GoogleMapComponentOption } from "echarts-extension-gmap";

export type EChartsOption = any;
export type EChartsOptionWithMap = EChartsOption & GoogleMapComponentOption<any>;

export type EChartsInstance = any;

Expand Down Expand Up @@ -28,7 +30,7 @@ export type EChartsReactProps = {
/**
* echarts option
*/
readonly option: EChartsOption;
readonly option: EChartsOptionWithMap;
/**
* echarts theme config, can be:
* 1. theme name string
Expand Down
2 changes: 2 additions & 0 deletions client/packages/lowcoder-comps/src/i18n/comps/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ export const en = {
echartsOptionLabel: "Option",
echartsOptionTooltip: "ECharts option",
echartsOptionExamples: "ECharts examples",
echartsMapOptionTooltip: "ECharts Map Option",
echartsMapOptionExamples: "ECharts Map Examples",
selectDesc: "Triggered when the user selects part of the data in the chart",
unselectDesc: "Triggered when the user unselects part of the data in the chart",
selectedPointsDesc: "Selected points",
Expand Down
Loading

0 comments on commit 9a3126a

Please sign in to comment.