diff --git a/.env.example b/.env.example
index 2a2b1e90ac..068552f107 100644
--- a/.env.example
+++ b/.env.example
@@ -68,3 +68,6 @@ APPSMITH_RECAPTCHA_ENABLED=
# Intercom
APPSMITH_DISABLE_INTERCOM=
+
+# baidu map
+BMAP_AK=
diff --git a/.gitignore b/.gitignore
index eb79f65bc9..44970bbf83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,3 +34,4 @@ app/client/yalc.lock
.idea
.fleet/*
app/client/.fleet/*
+*debug.log
diff --git a/README.md b/README.md
index 052279c818..d6285ba946 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,9 @@
# 前端低代码工具(base on AppSmith-v1.7.3)
## 🎈 启动项目(windows)
-[非windows](/contributions/ClientSetup.md)
+
+[非 windows](/contributions/ClientSetup.md)
+
```
// 配置 host
127.0.0.1 dev.appsmith.com
@@ -14,11 +16,12 @@ cd app/client
yarn start-proxy
// 启动前端服务
-yarn
+yarn
yarn start-win ( yarn start-cloudos )
```
[服务端指南](/contributions/ServerSetup.md)
+
```
// .env 环境变量,开发测试 mongo、redis 地址
APPSMITH_MONGODB_URI="mongodb://10.10.13.50:27017/appsmith"
@@ -36,6 +39,7 @@ bash ./scripts/start-dev-server.sh
```
## 💕 合并 GitHub 更新
+
```
// 外网代理
export https_proxy=http://127.0.0.1:3083
@@ -50,6 +54,7 @@ git push origin master
```
## 📦 打包发布
+
```
// 前端打包
cd app/client
@@ -77,6 +82,7 @@ docker-registry-idc01-sz.cloudtogo.cn/pageplug-server:cloudtogo
```
## 🌱 系统安装脚本
+
```
install.sh
@@ -86,6 +92,7 @@ sed -i 's/index\.docker\.io\/appsmith\/appsmith-server/harbor\.cloud2go\.cn\/clo
```
## 🌼 小程序环境变量
+
```
// 小程序 ID、密钥,用于获取小程序码
CLOUDOS_WECHAT_APPID="wx414ad0dbeda1a70b"
@@ -93,6 +100,7 @@ CLOUDOS_WECHAT_SECRET="d5289fd08b1fb31290f66ea2ce5ec7dc"
```
## 🔔 StarOS 版本注意
+
```
// StarOS 版本环境变量
// 同步春景 API 列表
@@ -104,7 +112,7 @@ CLOUDOS_IN_CLOUDOS=true
// nginx.conf 配置前端环境变量,替换 index.html 中的配置
sub_filter __PAGEPLUG_CLOUDOS_LOGIN_URL__ 'http://factory.dev.staros.local/user/login';
-
+sub_filter __BMAP_AK__ 'nWCpSjRnXLfGuBc3iLZ9kYv8Y6wYaxf8';
🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨
StarOS 版本使用固定用户
在开启 inCloudOS 前需要
diff --git a/app/client/public/index.html b/app/client/public/index.html
index 73e2f13111..351ad24ec2 100755
--- a/app/client/public/index.html
+++ b/app/client/public/index.html
@@ -19,12 +19,14 @@
transition: all ease-in 0.3s;
}
+
+
-
+
diff --git a/app/client/src/api/ApplicationApi.tsx b/app/client/src/api/ApplicationApi.tsx
index 1f1bb468b3..3526dfb82c 100644
--- a/app/client/src/api/ApplicationApi.tsx
+++ b/app/client/src/api/ApplicationApi.tsx
@@ -114,6 +114,7 @@ export type UpdateApplicationPayload = {
appLayout?: AppLayoutConfig;
applicationVersion?: number;
viewerLayout?: string;
+ chartTheme?: string;
};
export type UpdateApplicationRequest = UpdateApplicationPayload & {
@@ -129,6 +130,7 @@ export interface ApplicationObject {
workspaceId: string;
pages: ApplicationPagePayload[];
userPermissions: string[];
+ chartTheme?: string;
}
export interface PermissionGroup {
diff --git a/app/client/src/ce/constants/ReduxActionConstants.tsx b/app/client/src/ce/constants/ReduxActionConstants.tsx
index b92ed9f60e..bd2d9c59c9 100644
--- a/app/client/src/ce/constants/ReduxActionConstants.tsx
+++ b/app/client/src/ce/constants/ReduxActionConstants.tsx
@@ -481,6 +481,8 @@ export const ReduxActionTypes = {
UPDATE_CANVAS_STRUCTURE: "UPDATE_CANVAS_STRUCTURE",
SET_SELECTED_WIDGET_ANCESTORY: "SET_SELECTED_WIDGET_ANCESTORY",
START_EVALUATION: "START_EVALUATION",
+ CURRENT_APPLICATION_CHART_THEME_UPDATE:
+ "CURRENT_APPLICATION_CHART_THEME_UPDATE",
CURRENT_APPLICATION_NAME_UPDATE: "CURRENT_APPLICATION_NAME_UPDATE",
CURRENT_APPLICATION_LAYOUT_UPDATE: "CURRENT_APPLICATION_LAYOUT_UPDATE",
CURRENT_APPLICATION_VIEWER_LAYOUT_UPDATE:
@@ -1024,6 +1026,7 @@ export interface ApplicationPayload {
viewerLayout?: string;
isAutoUpdate?: boolean;
isManualUpdate?: boolean;
+ chartTheme?: string;
}
export type WorkspaceDetails = {
diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts
index 396af60cb4..bc39e61409 100644
--- a/app/client/src/ce/constants/messages.ts
+++ b/app/client/src/ce/constants/messages.ts
@@ -988,6 +988,10 @@ export const APP_THEME_BETA_CARD_HEADING = () => `🎨 修改应用风格`;
export const APP_THEME_BETA_CARD_CONTENT = () =>
`自定义全局样式风格,后面对所有组件进行支持`;
+// echat theme
+export const CHANGE_ECHART_THEME = (name: string) =>
+ `Echart主题已切换为 ${name} 风格主题`;
+
export const UPGRADE_TO_EE = (authLabel: string) =>
`你好,我想升级并且开始使用 ${authLabel} 鉴权`;
export const UPGRADE_TO_EE_GENERIC = () => `你好,我想升级`;
diff --git a/app/client/src/ce/reducers/uiReducers/applicationsReducer.tsx b/app/client/src/ce/reducers/uiReducers/applicationsReducer.tsx
index c6206bda79..c67b6b48c0 100644
--- a/app/client/src/ce/reducers/uiReducers/applicationsReducer.tsx
+++ b/app/client/src/ce/reducers/uiReducers/applicationsReducer.tsx
@@ -133,6 +133,16 @@ export const handlers = {
currentApplication: action.payload,
isFetchingApplication: false,
}),
+ [ReduxActionTypes.CURRENT_APPLICATION_CHART_THEME_UPDATE]: (
+ state: ApplicationsReduxState,
+ action: ReduxAction<{ chartTheme: string }>,
+ ) => ({
+ ...state,
+ currentApplication: {
+ ...state.currentApplication,
+ chartTheme: action.payload.chartTheme,
+ },
+ }),
[ReduxActionTypes.CURRENT_APPLICATION_NAME_UPDATE]: (
state: ApplicationsReduxState,
action: ReduxAction<{ name: string; slug: string }>,
diff --git a/app/client/src/components/editorComponents/ActionRightPane/SuggestedWidgets.tsx b/app/client/src/components/editorComponents/ActionRightPane/SuggestedWidgets.tsx
index ba774765f4..3e38fb1b52 100644
--- a/app/client/src/components/editorComponents/ActionRightPane/SuggestedWidgets.tsx
+++ b/app/client/src/components/editorComponents/ActionRightPane/SuggestedWidgets.tsx
@@ -86,6 +86,12 @@ export const WIDGET_DATA_FIELD_MAP: Record = {
widgetName: "Chart",
image: "https://assets.appsmith.com/widgetSuggestion/chart.svg",
},
+ ECHART_WIDGET: {
+ label: "chart-series-data-control",
+ propertyName: "chartData",
+ widgetName: "EChart",
+ image: "https://assets.appsmith.com/widgetSuggestion/chart.svg",
+ },
SELECT_WIDGET: {
label: "选项",
propertyName: "options",
@@ -147,6 +153,20 @@ function getWidgetProps(
dynamicBindingPathList: [{ key: `chartData.${reactKey}.data` }],
},
};
+ case "ECHART_WIDGET":
+ const ereactKey = generateReactKey();
+ return {
+ type: suggestedWidget.type,
+ props: {
+ [fieldName]: {
+ [ereactKey]: {
+ seriesName: "Sales",
+ data: `{{${actionName}.${suggestedWidget.bindingQuery}}}`,
+ },
+ },
+ dynamicBindingPathList: [{ key: `echartData.${ereactKey}.data` }],
+ },
+ };
case "SELECT_WIDGET":
return {
type: suggestedWidget.type,
diff --git a/app/client/src/components/editorComponents/CodeEditor/index.tsx b/app/client/src/components/editorComponents/CodeEditor/index.tsx
index 35b6abeffd..404b917a43 100644
--- a/app/client/src/components/editorComponents/CodeEditor/index.tsx
+++ b/app/client/src/components/editorComponents/CodeEditor/index.tsx
@@ -677,6 +677,7 @@ class CodeEditor extends Component {
});
}
const inputValue = this.props.input.value || "";
+ // console.log(inputValue, "handleChange");
if (
this.props.input.onChange &&
((value !== inputValue && this.state.isFocused) ||
diff --git a/app/client/src/components/propertyControls/EchartDataControl.tsx b/app/client/src/components/propertyControls/EchartDataControl.tsx
new file mode 100644
index 0000000000..da10e90ab4
--- /dev/null
+++ b/app/client/src/components/propertyControls/EchartDataControl.tsx
@@ -0,0 +1,328 @@
+import React from "react";
+import { get, isString } from "lodash";
+import BaseControl, { ControlProps } from "./BaseControl";
+import { ControlWrapper, StyledPropertyPaneButton } from "./StyledControls";
+import styled from "constants/DefaultTheme";
+import { FormIcons } from "icons/FormIcons";
+import { AnyStyledComponent } from "styled-components";
+import { CodeEditorExpected } from "components/editorComponents/CodeEditor";
+import {
+ EditorModes,
+ EditorSize,
+ EditorTheme,
+ TabBehaviour,
+} from "components/editorComponents/CodeEditor/EditorConfig";
+import { Size, Category } from "design-system";
+import { AllChartData, ChartData } from "widgets/ChartWidget/constants";
+import { generateReactKey } from "utils/generators";
+import { AutocompleteDataType } from "utils/autocomplete/TernServer";
+import CodeEditor from "components/editorComponents/LazyCodeEditorWrapper";
+
+const Wrapper = styled.div`
+ background-color: ${(props) =>
+ props.theme.colors.propertyPane.dropdownSelectBg};
+ padding: 0 8px;
+`;
+
+const StyledOptionControlWrapper = styled(ControlWrapper)`
+ display: flex;
+ justify-content: flex-start;
+ padding: 0;
+ width: 100%;
+`;
+
+const StyledDynamicInput = styled.div`
+ width: 100%;
+ &&& {
+ input {
+ border: none;
+ color: ${(props) => props.theme.colors.textOnDarkBG};
+ background: ${(props) => props.theme.colors.paneInputBG};
+ &:focus {
+ border: none;
+ color: ${(props) => props.theme.colors.textOnDarkBG};
+ background: ${(props) => props.theme.colors.paneInputBG};
+ }
+ }
+ }
+`;
+
+const StyledDeleteIcon = styled(FormIcons.DELETE_ICON as AnyStyledComponent)`
+ padding: 0;
+ position: relative;
+ margin-left: 15px;
+ cursor: pointer;
+
+ &&& svg {
+ path {
+ fill: ${(props) => props.theme.colors.propertyPane.jsIconBg};
+ }
+ }
+`;
+
+const ActionHolder = styled.div`
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+`;
+
+const StyledLabel = styled.label`
+ margin: 8px auto 8px 0;
+
+ && {
+ color: ${(props) => props.theme.colors.propertyPane.label};
+ }
+`;
+
+const Box = styled.div`
+ height: 16px;
+`;
+
+type labelType = {
+ titleLabel: string;
+ areaLabel: string;
+ btnLabel: string;
+};
+
+type RenderComponentProps = {
+ index: string;
+ item: ChartData;
+ length: number;
+ dataTreePath: string;
+ deleteOption: (index: string) => void;
+ updateOption: (index: string, key: string, value: string) => void;
+ evaluated: {
+ seriesName: string;
+ data: Array<{ name: string; value: string }> | any;
+ };
+ theme: EditorTheme;
+ noTitle?: boolean;
+ label?: labelType;
+};
+
+const expectedSeriesName: CodeEditorExpected = {
+ type: "string",
+ example: "series1",
+ autocompleteDataType: AutocompleteDataType.STRING,
+};
+const expectedSeriesData: CodeEditorExpected = {
+ type: "Array<{ name: string, value: number Required }>",
+ example: [
+ {
+ name: "Mon",
+ value: 10000,
+ },
+ ],
+ autocompleteDataType: AutocompleteDataType.ARRAY,
+};
+
+function DataControlComponent(props: RenderComponentProps) {
+ const {
+ dataTreePath,
+ deleteOption,
+ evaluated,
+ index,
+ item,
+ length,
+ updateOption,
+ noTitle,
+ label,
+ } = props;
+ return (
+
+ {!noTitle ? (
+ <>
+
+ {label?.titleLabel}
+ {length > 1 && (
+ {
+ deleteOption(index);
+ }}
+ width={20}
+ />
+ )}
+
+
+ | string,
+ ) => {
+ let value: string = event as string;
+ if (typeof event !== "string") {
+ value = event.target.value;
+ }
+ updateOption(index, "seriesName", value);
+ },
+ }}
+ mode={EditorModes.JAVASCRIPT}
+ placeholder={label?.titleLabel}
+ size={EditorSize.EXTENDED}
+ tabBehaviour={TabBehaviour.INPUT}
+ theme={props.theme}
+ />
+
+ >
+ ) : null}
+ {label?.areaLabel}
+
+ | string,
+ ) => {
+ let value: string = event as string;
+ if (typeof event !== "string") {
+ value = event.target.value;
+ }
+ updateOption(index, "data", value);
+ },
+ }}
+ mode={EditorModes.JSON_WITH_BINDING}
+ placeholder={label?.areaLabel}
+ size={EditorSize.EXTENDED}
+ tabBehaviour={TabBehaviour.INPUT}
+ theme={props.theme}
+ />
+
+
+
+ );
+}
+
+const Name_Data_Array = ["xAxis", "yAxis"];
+
+const ControlLabel = (propertyName: string) => {
+ if (Name_Data_Array.includes(propertyName)) {
+ return {
+ titleLabel: "标签",
+ areaLabel: "数据",
+ hasAddBtn: false,
+ btnLabel: "ADD AXIS",
+ };
+ }
+ return {
+ titleLabel: "Series Title",
+ areaLabel: "Series Data",
+ hasAddBtn: true,
+ btnLabel: "ADD SERIES",
+ };
+};
+
+class EchartDataControl extends BaseControl {
+ render() {
+ const chartData: AllChartData =
+ isString(this.props.propertyValue) || !this.props.propertyValue
+ ? {}
+ : this.props.propertyValue;
+ const dataLength = Object.keys(chartData).length;
+ const isDataSet = this.props.propertyName === "dataSet";
+ const evaluatedValue = this.props.evaluatedValue;
+ const firstKey = Object.keys(chartData)[0] as string;
+ if (this.props.widgetProperties.chartType === "PIE_CHART") {
+ const data = dataLength
+ ? get(chartData, `${firstKey}`)
+ : {
+ seriesName: "",
+ data: [],
+ };
+ return (
+
+ );
+ }
+
+ return (
+ <>
+
+ {Object.keys(chartData).map((key: string) => {
+ const data = get(chartData, `${key}`);
+ return (
+
+ );
+ })}
+
+
+ {/* 新增按钮 */}
+ {ControlLabel(this.props.propertyName).hasAddBtn ? (
+
+ ) : null}
+ >
+ );
+ }
+
+ deleteOption = (index: string) => {
+ this.deleteProperties([`${this.props.propertyName}.${index}`]);
+ };
+
+ updateOption = (
+ index: string,
+ propertyName: string,
+ updatedValue: string,
+ ) => {
+ this.updateProperty(
+ `${this.props.propertyName}.${index}.${propertyName}`,
+ updatedValue,
+ );
+ };
+
+ /**
+ * it adds new series data object in the chartData
+ */
+ addOption = () => {
+ const randomString = generateReactKey();
+ this.updateProperty(`${this.props.propertyName}.${randomString}`, {
+ seriesName: "",
+ data: JSON.stringify([{ name: "label", value: 51 }]),
+ });
+ };
+
+ static getControlType() {
+ return "ECHART_DATA";
+ }
+}
+
+export default EchartDataControl;
diff --git a/app/client/src/components/propertyControls/index.ts b/app/client/src/components/propertyControls/index.ts
index a7c201c0bf..e600f49a70 100644
--- a/app/client/src/components/propertyControls/index.ts
+++ b/app/client/src/components/propertyControls/index.ts
@@ -16,6 +16,7 @@ import DatePickerControl, {
DatePickerControlProps,
} from "components/propertyControls/DatePickerControl";
import ChartDataControl from "components/propertyControls/ChartDataControl";
+import EchartDataControl from "components/propertyControls/EchartDataControl";
import LocationSearchControl from "components/propertyControls/LocationSearchControl";
import StepControl, {
StepControlProps,
@@ -90,6 +91,7 @@ export const PropertyControls = {
ColumnActionSelectorControl,
MultiSwitchControl,
ChartDataControl,
+ EchartDataControl,
LocationSearchControl,
StepControl,
TabControl,
diff --git a/app/client/src/constants/EchartContants.ts b/app/client/src/constants/EchartContants.ts
new file mode 100644
index 0000000000..cc31a050e8
--- /dev/null
+++ b/app/client/src/constants/EchartContants.ts
@@ -0,0 +1,64 @@
+import { EchartTheme } from "entities/AppTheming";
+
+import macarons from "theme/echart/macarons.json";
+import chalk from "theme/echart/chalk.json";
+import walden from "theme/echart/walden.json";
+import westeros from "theme/echart/westeros.json";
+
+type echartsMap = {
+ [key: string]: EchartTheme;
+};
+
+export const echartThemes: any = {
+ macarons: {
+ themeKey: "macarons",
+ ...macarons,
+ },
+ chalk: {
+ themeKey: "chalk",
+ ...chalk,
+ },
+ walden: {
+ themeKey: "walden",
+ ...walden,
+ },
+ westeros: {
+ themeKey: "westeros",
+ ...westeros,
+ },
+ dark: {
+ themeKey: "dark",
+ backgroundColor: "#100c2a",
+ color: [
+ "#5470c6",
+ "#91cc75",
+ "#fac858",
+ "#ee6666",
+ "#73c0de",
+ "#3ba272",
+ "#fc8452",
+ "#9a60b4",
+ "#ea7ccc",
+ ],
+ },
+ default: {
+ themeKey: "default",
+ backgroundColor: "#ffffff",
+ color: [
+ "#5470c6",
+ "#91cc75",
+ "#fac858",
+ "#ee6666",
+ "#73c0de",
+ "#3ba272",
+ "#fc8452",
+ "#9a60b4",
+ "#ea7ccc",
+ ],
+ },
+ transparent: {
+ themeKey: "transparent",
+ backgroundColor: "transparent",
+ color: [],
+ },
+};
diff --git a/app/client/src/constants/HelpConstants.ts b/app/client/src/constants/HelpConstants.ts
index dd1b00a122..fd71b6956a 100644
--- a/app/client/src/constants/HelpConstants.ts
+++ b/app/client/src/constants/HelpConstants.ts
@@ -275,6 +275,10 @@ export const HelpMap: Record = {
path: "/widget-reference/map-chart",
searchKey: "Map Chart",
},
+ ECHART_WIDGET: {
+ path: "/widget-reference/chart",
+ searchKey: "Echart",
+ },
};
export const HelpBaseURL = "https://docs.appsmith.com";
diff --git a/app/client/src/entities/AppTheming/index.ts b/app/client/src/entities/AppTheming/index.ts
index 10b477656d..43d578ba62 100644
--- a/app/client/src/entities/AppTheming/index.ts
+++ b/app/client/src/entities/AppTheming/index.ts
@@ -70,3 +70,10 @@ export type AppTheme = {
};
};
};
+
+export type EchartTheme = {
+ themeKey: string;
+ backgroundColor?: string;
+ color?: string[];
+ [key: string]: any;
+};
diff --git a/app/client/src/entities/DataTree/actionTriggers.ts b/app/client/src/entities/DataTree/actionTriggers.ts
index ba0090642c..6b2235acfb 100644
--- a/app/client/src/entities/DataTree/actionTriggers.ts
+++ b/app/client/src/entities/DataTree/actionTriggers.ts
@@ -21,6 +21,7 @@ export enum ActionTriggerType {
STOP_WATCHING_CURRENT_LOCATION = "STOP_WATCHING_CURRENT_LOCATION",
CONFIRMATION_MODAL = "CONFIRMATION_MODAL",
POST_MESSAGE = "POST_MESSAGE",
+ CALL_FUNC = "CALL_FUNC",
}
export const ActionTriggerFunctionNames: Record = {
@@ -35,6 +36,7 @@ export const ActionTriggerFunctionNames: Record = {
[ActionTriggerType.SET_INTERVAL]: "setInterval",
[ActionTriggerType.SHOW_ALERT]: "showAlert",
[ActionTriggerType.SHOW_MODAL_BY_NAME]: "showModal",
+ [ActionTriggerType.CALL_FUNC]: "callFunc",
[ActionTriggerType.STORE_VALUE]: "storeValue",
[ActionTriggerType.REMOVE_VALUE]: "removeValue",
[ActionTriggerType.CLEAR_STORE]: "clearStore",
@@ -193,12 +195,30 @@ export type PostMessageDescription = {
};
};
+// type optionProps = {
+// widgetName: string;
+// funcName: string;
+// params: any;
+// };
+
+type EchartActionPayload = {
+ options?: any;
+ widgetName: string;
+ funcName: string;
+};
+
+export type EchartAction = {
+ type: ActionTriggerType.CALL_FUNC;
+ payload: EchartActionPayload;
+};
+
export type ActionDescription =
| RunPluginActionDescription
| ClearPluginActionDescription
| NavigateActionDescription
| ShowAlertActionDescription
| ShowModalActionDescription
+ | EchartAction
| CloseModalActionDescription
| StoreValueActionDescription
| RemoveValueActionDescription
diff --git a/app/client/src/pages/Editor/CanvasPropertyPane/index.tsx b/app/client/src/pages/Editor/CanvasPropertyPane/index.tsx
index 359b58c336..f734b40993 100644
--- a/app/client/src/pages/Editor/CanvasPropertyPane/index.tsx
+++ b/app/client/src/pages/Editor/CanvasPropertyPane/index.tsx
@@ -15,6 +15,7 @@ const Title = styled.p`
type Props = {
skipThemeEditor?: boolean;
};
+import EchartThemeEditor from "../ThemePropertyPane/Echart/EchartThemeEditor";
export function CanvasPropertyPane(props: Props) {
const isMobile = useSelector(isMobileLayout);
@@ -31,6 +32,7 @@ export function CanvasPropertyPane(props: Props) {
)}
{!props.skipThemeEditor && }
+
);
diff --git a/app/client/src/pages/Editor/FirstTimeUserOnboarding/testUtils.ts b/app/client/src/pages/Editor/FirstTimeUserOnboarding/testUtils.ts
index 26ac4513d8..2b62b2dfae 100644
--- a/app/client/src/pages/Editor/FirstTimeUserOnboarding/testUtils.ts
+++ b/app/client/src/pages/Editor/FirstTimeUserOnboarding/testUtils.ts
@@ -32,6 +32,7 @@ export const initialState: any = {
currentApplication: {
lastDeployedAt: null,
slug: "applicationSlug",
+ chartTheme: "default",
},
},
onBoarding: {
diff --git a/app/client/src/pages/Editor/ThemePropertyPane/Echart/EchartThemeEditor.tsx b/app/client/src/pages/Editor/ThemePropertyPane/Echart/EchartThemeEditor.tsx
new file mode 100644
index 0000000000..83624a5e8b
--- /dev/null
+++ b/app/client/src/pages/Editor/ThemePropertyPane/Echart/EchartThemeEditor.tsx
@@ -0,0 +1,88 @@
+// import { createGlobalStyle } from "styled-components";
+// import { get, startCase } from "lodash";
+// import MoreIcon from "remixicon-react/MoreFillIcon";
+import { useDispatch, useSelector } from "react-redux";
+import React, { useCallback, useState } from "react";
+
+import ThemeCard from "./ThemeCard";
+import {
+ AppThemingMode,
+ getAppThemingStack,
+ getSelectedEchartTheme,
+} from "selectors/appThemingSelectors";
+import {
+ // resetThemeAction,
+ setAppThemingModeStackAction,
+ // updateSelectedAppThemeAction,
+} from "actions/appThemingActions";
+// import SettingSection from "../SettingSection";
+import SaveThemeModal from "../SaveThemeModal";
+// import { AppTheme } from "entities/AppTheming";
+import AnalyticsUtil from "utils/AnalyticsUtil";
+import { Button, Category, Size } from "design-system";
+// import { getCurrentApplicationId } from "selectors/editorSelectors";
+import BetaCard from "components/editorComponents/BetaCard";
+
+// const THEMING_BETA_CARD_POPOVER_CLASSNAME = `theming-beta-card-popover`;
+
+function EchartThemeEditor() {
+ const dispatch = useDispatch();
+ // const applicationId = useSelector(getCurrentApplicationId);
+ // const selectedTheme = useSelector(getSelectedAppTheme);
+ const selectedEchartTheme = useSelector(getSelectedEchartTheme);
+ const themingStack = useSelector(getAppThemingStack);
+ const [isSaveModalOpen, setSaveModalOpen] = useState(false);
+
+ /**
+ * sets the mode to THEME_EDIT
+ */
+ const onClickChangeThemeButton = useCallback(() => {
+ AnalyticsUtil.logEvent("APP_THEMING_CHOOSE_THEME");
+
+ dispatch(
+ setAppThemingModeStackAction([
+ ...themingStack,
+ AppThemingMode.ECHART_THEME_SELECTION,
+ ]),
+ );
+ }, [setAppThemingModeStackAction]);
+
+ /**
+ * on close save modal
+ */
+ const onCloseSaveModal = useCallback(() => {
+ setSaveModalOpen(false);
+ }, [setSaveModalOpen]);
+
+ return (
+ <>
+
+
+ >
+ );
+}
+
+export default EchartThemeEditor;
diff --git a/app/client/src/pages/Editor/ThemePropertyPane/Echart/EchartThemeSelector.tsx b/app/client/src/pages/Editor/ThemePropertyPane/Echart/EchartThemeSelector.tsx
new file mode 100644
index 0000000000..b9baa9c732
--- /dev/null
+++ b/app/client/src/pages/Editor/ThemePropertyPane/Echart/EchartThemeSelector.tsx
@@ -0,0 +1,82 @@
+import React from "react";
+import { useDispatch, useSelector } from "react-redux";
+
+import {
+ // getAppThemes,
+ getAppThemingStack,
+ // getSelectedAppTheme,
+ getSelectedEchartTheme,
+} from "selectors/appThemingSelectors";
+import * as _ from "lodash";
+import { echartThemes as ECHART_THEMES } from "./constants";
+import { ThemeCard } from "./ThemeCard";
+import { SettingSection } from "../SettingSection";
+import ArrowLeft from "remixicon-react/ArrowLeftSLineIcon";
+import { setAppThemingModeStackAction } from "actions/appThemingActions";
+
+function EchartThemeSelector() {
+ const dispatch = useDispatch();
+ // const themes = useSelector(getAppThemes);
+ const themingStack = useSelector(getAppThemingStack);
+ const selectedEchartTheme = useSelector(getSelectedEchartTheme);
+
+ /**
+ * goes to previous screen in the pane
+ */
+ const onClickBack = () => {
+ dispatch(setAppThemingModeStackAction(themingStack.slice(0, -1)));
+ };
+
+ /**
+ * stores user saved themes
+ */
+ // const userSavedThemes = themes.filter(
+ // (theme) => theme.isSystemTheme === false,
+ // );
+
+ const userSavedThemes = {};
+
+ /**
+ * stores default system themes
+ */
+ const systemThemes = ECHART_THEMES;
+ const currentTheme =
+ ECHART_THEMES[selectedEchartTheme?.themeKey] || selectedEchartTheme;
+ return (
+
+
+ {_.size(userSavedThemes) > 0 && (
+
+ 你的Echart主题
+ {_.map(userSavedThemes, (theme) => (
+
+ ))}
+
+ )}
+
+ 特色Echart主题
+ {_.map(systemThemes, (theme: any) => (
+
+ ))}
+
+
+ );
+}
+
+export default EchartThemeSelector;
diff --git a/app/client/src/pages/Editor/ThemePropertyPane/Echart/ThemeCard.tsx b/app/client/src/pages/Editor/ThemePropertyPane/Echart/ThemeCard.tsx
new file mode 100644
index 0000000000..c52de409ee
--- /dev/null
+++ b/app/client/src/pages/Editor/ThemePropertyPane/Echart/ThemeCard.tsx
@@ -0,0 +1,177 @@
+import { last } from "lodash";
+import classNames from "classnames";
+import styled from "styled-components";
+import * as _ from "lodash";
+import * as Sentry from "@sentry/react";
+import React, { useState } from "react";
+import { message } from "antd";
+import { useDispatch, useSelector } from "react-redux";
+// import DeleteIcon from "remixicon-react/DeleteBinLineIcon";
+
+import { updateApplication } from "actions/applicationActions";
+
+import {
+ AppThemingMode,
+ getAppThemingStack,
+ // getAppThemes,
+ // getSelectedEchartTheme,
+} from "selectors/appThemingSelectors";
+import { AppTheme, EchartTheme } from "entities/AppTheming";
+// import AnalyticsUtil from "utils/AnalyticsUtil";
+// import DeleteThemeModal from "../DeleteThemeModal";
+import { getComplementaryGrayscaleColor } from "widgets/WidgetUtils";
+import { getCurrentApplicationId } from "selectors/editorSelectors";
+
+/**
+ * ----------------------------------------------------------------------------
+ * TYPES
+ *-----------------------------------------------------------------------------
+ */
+type ThemeCard = React.PropsWithChildren<{
+ theme: EchartTheme;
+ isSelected?: boolean;
+ className?: string;
+ selectable?: boolean;
+ deletable?: boolean;
+}>;
+
+const MainContainer = styled.main<{ backgroundColor: string }>`
+ background: ${({ backgroundColor }) => backgroundColor};
+`;
+
+const HeaderContainer = styled.main<{ primaryColor: string }>`
+ background-color: ${({ primaryColor }) => primaryColor};
+ color: ${({ primaryColor }) => getComplementaryGrayscaleColor(primaryColor)};
+`;
+
+const MainText = styled.main<{ backgroundColor: string }>`
+ color: ${({ backgroundColor }) =>
+ getComplementaryGrayscaleColor(backgroundColor)};
+`;
+
+const MainTextTransparentBg = styled.main<{ backgroundColor: string }>`
+ background: #fff;
+ background-image: linear-gradient(
+ 45deg,
+ #e7e7e7 25%,
+ transparent 0,
+ transparent 75%,
+ #e7e7e7 0
+ ),
+ linear-gradient(
+ 45deg,
+ #e7e7e7 25%,
+ transparent 0,
+ transparent 75%,
+ #e7e7e7 0
+ );
+ background-position: 0 0, 15px 15px;
+ background-size: 30px 30px;
+`;
+
+const ThemeColorCircle = styled.main<{ backgroundColor: string }>`
+ background-color: ${({ backgroundColor }) => backgroundColor};
+`;
+
+/**
+ * ----------------------------------------------------------------------------
+ * COMPONENT
+ *-----------------------------------------------------------------------------
+ */
+export function ThemeCard(props: ThemeCard) {
+ const { selectable, theme } = props;
+ const dispatch = useDispatch();
+ // const selectedEchart = useSelector(getSelectedEchartTheme);
+ const themingStack = useSelector(getAppThemingStack);
+ const themingMode = last(themingStack);
+ const applicationId = useSelector(getCurrentApplicationId);
+ const isThemeSelectionMode =
+ themingMode === AppThemingMode.ECHART_THEME_SELECTION;
+
+ // colors
+ const userDefinedColors = _.slice(theme.color, 0, 6);
+ const backgroundColor = theme.backgroundColor;
+
+ /**
+ * fires action for changing theme
+ *
+ * NOTE: since we are same card in theme edit and theme selection,
+ * we don't need to fire the action in theme edit mode on click on the card
+ */
+
+ const changeSelectedTheme = () => {
+ const data = {
+ id: applicationId,
+ chartTheme: theme.themeKey,
+ };
+ if (isThemeSelectionMode && selectable) {
+ dispatch(updateApplication(applicationId, data));
+ message.success(`Echart主题已切换为 ${theme.themeKey} 风格主题`);
+ }
+ };
+
+ const TRANSPARENT_BG = ["transparent", "rgba(0,0,0,0)"];
+
+ const MainWrap: any =
+ backgroundColor === "transparent" ? MainTextTransparentBg : MainContainer;
+ return (
+
+ {selectable && (
+
+
+ {props.theme.displayName}
+
+
+ )}
+
+
+
+
+ {theme.themeKey}
+
+
+ {userDefinedColors.map((colorKey: any, index: number) => (
+
+ ))}
+
+
+
+
+
+ {props.children}
+
+
+ );
+}
+
+ThemeCard.displayName = "ThemeCard";
+
+export default Sentry.withProfiler(ThemeCard);
diff --git a/app/client/src/pages/Editor/ThemePropertyPane/Echart/constants.ts b/app/client/src/pages/Editor/ThemePropertyPane/Echart/constants.ts
new file mode 100644
index 0000000000..cc31a050e8
--- /dev/null
+++ b/app/client/src/pages/Editor/ThemePropertyPane/Echart/constants.ts
@@ -0,0 +1,64 @@
+import { EchartTheme } from "entities/AppTheming";
+
+import macarons from "theme/echart/macarons.json";
+import chalk from "theme/echart/chalk.json";
+import walden from "theme/echart/walden.json";
+import westeros from "theme/echart/westeros.json";
+
+type echartsMap = {
+ [key: string]: EchartTheme;
+};
+
+export const echartThemes: any = {
+ macarons: {
+ themeKey: "macarons",
+ ...macarons,
+ },
+ chalk: {
+ themeKey: "chalk",
+ ...chalk,
+ },
+ walden: {
+ themeKey: "walden",
+ ...walden,
+ },
+ westeros: {
+ themeKey: "westeros",
+ ...westeros,
+ },
+ dark: {
+ themeKey: "dark",
+ backgroundColor: "#100c2a",
+ color: [
+ "#5470c6",
+ "#91cc75",
+ "#fac858",
+ "#ee6666",
+ "#73c0de",
+ "#3ba272",
+ "#fc8452",
+ "#9a60b4",
+ "#ea7ccc",
+ ],
+ },
+ default: {
+ themeKey: "default",
+ backgroundColor: "#ffffff",
+ color: [
+ "#5470c6",
+ "#91cc75",
+ "#fac858",
+ "#ee6666",
+ "#73c0de",
+ "#3ba272",
+ "#fc8452",
+ "#9a60b4",
+ "#ea7ccc",
+ ],
+ },
+ transparent: {
+ themeKey: "transparent",
+ backgroundColor: "transparent",
+ color: [],
+ },
+};
diff --git a/app/client/src/pages/Editor/ThemePropertyPane/index.tsx b/app/client/src/pages/Editor/ThemePropertyPane/index.tsx
index 791759613d..6fafeae1e1 100644
--- a/app/client/src/pages/Editor/ThemePropertyPane/index.tsx
+++ b/app/client/src/pages/Editor/ThemePropertyPane/index.tsx
@@ -4,6 +4,7 @@ import { last } from "lodash";
import ThemeEditor from "./ThemeEditor";
import ThemeSelector from "./ThemeSelector";
+import EchartThemeSelector from "./Echart/EchartThemeSelector";
import {
AppThemingMode,
getAppThemingStack,
@@ -26,6 +27,8 @@ export function ThemePropertyPane() {
return ;
case themingMode === AppThemingMode.APP_THEME_SELECTION:
return ;
+ case themingMode === AppThemingMode.ECHART_THEME_SELECTION:
+ return ;
default:
return ;
}
diff --git a/app/client/src/reducers/entityReducers/appReducer.ts b/app/client/src/reducers/entityReducers/appReducer.ts
index d429076ef1..88c7a76219 100644
--- a/app/client/src/reducers/entityReducers/appReducer.ts
+++ b/app/client/src/reducers/entityReducers/appReducer.ts
@@ -40,6 +40,7 @@ export type AppDataState = {
canBeRequested: boolean;
currentPosition?: Partial;
};
+ echartInstance: any;
};
const initialState: AppDataState = {
@@ -67,6 +68,7 @@ const initialState: AppDataState = {
canBeRequested: "geolocation" in navigator,
currentPosition: {},
},
+ echartInstance: {},
};
const appReducer = createReducer(initialState, {
diff --git a/app/client/src/sagas/ActionExecution/ActionExecutionSagas.ts b/app/client/src/sagas/ActionExecution/ActionExecutionSagas.ts
index b519a6592a..f88edcd88a 100644
--- a/app/client/src/sagas/ActionExecution/ActionExecutionSagas.ts
+++ b/app/client/src/sagas/ActionExecution/ActionExecutionSagas.ts
@@ -46,6 +46,7 @@ import {
setIntervalSaga,
} from "sagas/ActionExecution/SetIntervalSaga";
import {
+ getEchartSaga,
getCurrentLocationSaga,
stopWatchCurrentLocation,
watchCurrentLocation,
@@ -128,7 +129,14 @@ export function* executeActionTriggers(
triggerMeta,
);
break;
-
+ case ActionTriggerType.CALL_FUNC:
+ response = yield call(
+ getEchartSaga,
+ trigger.payload,
+ eventType,
+ triggerMeta,
+ );
+ break;
case ActionTriggerType.WATCH_CURRENT_LOCATION:
response = yield call(
watchCurrentLocation,
diff --git a/app/client/src/sagas/ActionExecution/GetCurrentLocationSaga.ts b/app/client/src/sagas/ActionExecution/GetCurrentLocationSaga.ts
index 9cd8d6fc0e..d88cfeb25b 100644
--- a/app/client/src/sagas/ActionExecution/GetCurrentLocationSaga.ts
+++ b/app/client/src/sagas/ActionExecution/GetCurrentLocationSaga.ts
@@ -1,5 +1,6 @@
import {
GetCurrentLocationDescription,
+ EchartAction,
WatchCurrentLocationDescription,
} from "entities/DataTree/actionTriggers";
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
@@ -7,13 +8,19 @@ import {
executeAppAction,
TriggerMeta,
} from "sagas/ActionExecution/ActionExecutionSagas";
-import { call, put, spawn, take } from "redux-saga/effects";
+import _find from "lodash/find";
+import { call, put, spawn, take, select } from "redux-saga/effects";
import {
logActionExecutionError,
TriggerFailureError,
} from "sagas/ActionExecution/errorUtils";
import { setUserCurrentGeoLocation } from "actions/browserRequestActions";
import { Channel, channel } from "redux-saga";
+import { getEchartWidget } from "selectors/widgetSelectors";
+import { FlattenedWidgetProps } from "reducers/entityReducers/canvasWidgetsReducer";
+import { ActionValidationError } from "sagas/ActionExecution/errorUtils";
+import { ActionTriggerType } from "entities/DataTree/actionTriggers";
+import { getType, Types } from "utils/TypeHelpers";
// Making the getCurrentPosition call in a promise fashion
const getUserLocation = (options?: PositionOptions) =>
@@ -128,6 +135,56 @@ export function* getCurrentLocationSaga(
}
}
+export function* getEchartSaga(
+ actionPayload: EchartAction["payload"],
+ eventType: EventType,
+ triggerMeta: TriggerMeta,
+) {
+ const { widgetName, funcName, options } = actionPayload;
+ const echartWidgets: {
+ [widgetId: string]: FlattenedWidgetProps;
+ } = yield select(getEchartWidget);
+ const _target = _find(echartWidgets, (it: any) => it.name === widgetName);
+ const _instance = _target?.instance;
+ if (typeof widgetName !== "string") {
+ throw new ActionValidationError(
+ ActionTriggerType.CALL_FUNC,
+ "widgetName",
+ Types.STRING,
+ getType(widgetName),
+ );
+ }
+ if (typeof funcName !== "string") {
+ throw new ActionValidationError(
+ ActionTriggerType.CALL_FUNC,
+ "funcName",
+ Types.STRING,
+ getType(funcName),
+ );
+ }
+
+ try {
+ if (_instance) {
+ const res = _instance[funcName](options);
+ if (funcName === "getDom") {
+ logActionExecutionError(
+ "postmessage could not be cloned",
+ triggerMeta.source,
+ triggerMeta.triggerPropertyName,
+ );
+ }
+ return [res];
+ }
+ } catch (error) {
+ logActionExecutionError(
+ (error as Error).message,
+ triggerMeta.source,
+ triggerMeta.triggerPropertyName,
+ );
+ return [error];
+ }
+}
+
let watchId: number | undefined;
export function* watchCurrentLocation(
actionPayload: WatchCurrentLocationDescription["payload"],
diff --git a/app/client/src/sagas/ApplicationSagas.tsx b/app/client/src/sagas/ApplicationSagas.tsx
index 082578a391..45a2588a42 100644
--- a/app/client/src/sagas/ApplicationSagas.tsx
+++ b/app/client/src/sagas/ApplicationSagas.tsx
@@ -360,6 +360,10 @@ export function* updateApplicationSaga(
type: ReduxActionTypes.UPDATE_APPLICATION_SUCCESS,
payload: response.data,
});
+ yield put({
+ type: ReduxActionTypes.CURRENT_APPLICATION_CHART_THEME_UPDATE,
+ payload: response.data,
+ });
}
if (request.currentApp) {
yield put({
diff --git a/app/client/src/selectors/appThemingSelectors.tsx b/app/client/src/selectors/appThemingSelectors.tsx
index c51e8aa9fa..e37f21c1d0 100644
--- a/app/client/src/selectors/appThemingSelectors.tsx
+++ b/app/client/src/selectors/appThemingSelectors.tsx
@@ -1,8 +1,10 @@
import { AppState } from "@appsmith/reducers";
+import { echartThemes } from "constants/EchartContants";
export enum AppThemingMode {
APP_THEME_EDIT = "APP_THEME_EDIT",
APP_THEME_SELECTION = "APP_THEME_SELECTION",
+ ECHART_THEME_SELECTION = "ECHART_THEME_SELECTION",
}
/**
@@ -45,6 +47,19 @@ export const getSelectedAppThemeStylesheet = (state: AppState) => {
return state.ui.appTheming.selectedTheme.stylesheet;
};
+/**
+ * get the selected echart theme
+ *
+ * @param state
+ * @returns
+ */
+export const getSelectedEchartTheme = (state: AppState) => {
+ if (state.ui.applications.currentApplication?.chartTheme) {
+ return echartThemes[state.ui.applications.currentApplication?.chartTheme];
+ }
+ return echartThemes["default"];
+};
+
/**
* get the preview theme or selected theme
*
diff --git a/app/client/src/selectors/widgetSelectors.ts b/app/client/src/selectors/widgetSelectors.ts
index 9f631f825a..758c09551f 100644
--- a/app/client/src/selectors/widgetSelectors.ts
+++ b/app/client/src/selectors/widgetSelectors.ts
@@ -1,5 +1,6 @@
import { createSelector } from "reselect";
import { AppState } from "@appsmith/reducers";
+import * as echarts from "echarts";
import {
CanvasWidgetsReduxState,
FlattenedWidgetProps,
@@ -43,6 +44,24 @@ export const getModalDropdownList = createSelector(
},
);
+export const getEchartWidget = createSelector(getCanvasWidgets, (widgets) => {
+ const echartWidgets = Object.values(widgets).filter(
+ (widget: FlattenedWidgetProps) => widget.type === "ECHART_WIDGET",
+ );
+ if (echartWidgets.length === 0) return undefined;
+ return echartWidgets.map((widget: FlattenedWidgetProps) => {
+ const chartId = `${widget.widgetId}-echart-container`;
+ const c_dom: HTMLElement | null = document
+ ? document.getElementById(`${chartId}`)
+ : null;
+ return {
+ id: widget.widgetId,
+ name: widget.widgetName,
+ instance: c_dom ? echarts.getInstanceByDom(c_dom) : null,
+ };
+ });
+});
+
export const getNextModalName = createSelector(
getExistingWidgetNames,
(names) => {
diff --git a/app/client/src/theme/echart/chalk.json b/app/client/src/theme/echart/chalk.json
new file mode 100644
index 0000000000..37b651f751
--- /dev/null
+++ b/app/client/src/theme/echart/chalk.json
@@ -0,0 +1,396 @@
+
+{
+ "color": [
+ "#fc97af",
+ "#87f7cf",
+ "#f7f494",
+ "#72ccff",
+ "#f7c5a0",
+ "#d4a4eb",
+ "#d2f5a6",
+ "#76f2f2"
+ ],
+ "backgroundColor": "rgba(41,52,65,1)",
+ "textStyle": {},
+ "title": {
+ "textStyle": {
+ "color": "#ffffff"
+ },
+ "subtextStyle": {
+ "color": "#dddddd"
+ }
+ },
+ "line": {
+ "itemStyle": {
+ "borderWidth": "4"
+ },
+ "lineStyle": {
+ "width": "3"
+ },
+ "symbolSize": "0",
+ "symbol": "circle",
+ "smooth": true
+ },
+ "radar": {
+ "itemStyle": {
+ "borderWidth": "4"
+ },
+ "lineStyle": {
+ "width": "3"
+ },
+ "symbolSize": "0",
+ "symbol": "circle",
+ "smooth": true
+ },
+ "bar": {
+ "itemStyle": {
+ "barBorderWidth": 0,
+ "barBorderColor": "#ccc"
+ }
+ },
+ "pie": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "scatter": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "boxplot": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "parallel": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "sankey": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "funnel": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "gauge": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "candlestick": {
+ "itemStyle": {
+ "color": "#fc97af",
+ "color0": "transparent",
+ "borderColor": "#fc97af",
+ "borderColor0": "#87f7cf",
+ "borderWidth": "2"
+ }
+ },
+ "graph": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ },
+ "lineStyle": {
+ "width": "1",
+ "color": "#ffffff"
+ },
+ "symbolSize": "0",
+ "symbol": "circle",
+ "smooth": true,
+ "color": [
+ "#fc97af",
+ "#87f7cf",
+ "#f7f494",
+ "#72ccff",
+ "#f7c5a0",
+ "#d4a4eb",
+ "#d2f5a6",
+ "#76f2f2"
+ ],
+ "label": {
+ "color": "#293441"
+ }
+ },
+ "map": {
+ "itemStyle": {
+ "areaColor": "#f3f3f3",
+ "borderColor": "#999999",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#893448"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "areaColor": "rgba(255,178,72,1)",
+ "borderColor": "#eb8146",
+ "borderWidth": 1
+ },
+ "label": {
+ "color": "rgb(137,52,72)"
+ }
+ }
+ },
+ "geo": {
+ "itemStyle": {
+ "areaColor": "#f3f3f3",
+ "borderColor": "#999999",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#893448"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "areaColor": "rgba(255,178,72,1)",
+ "borderColor": "#eb8146",
+ "borderWidth": 1
+ },
+ "label": {
+ "color": "rgb(137,52,72)"
+ }
+ }
+ },
+ "categoryAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#666666"
+ }
+ },
+ "axisTick": {
+ "show": false,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#aaaaaa"
+ },
+ "splitLine": {
+ "show": false,
+ "lineStyle": {
+ "color": [
+ "#e6e6e6"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.05)",
+ "rgba(200,200,200,0.02)"
+ ]
+ }
+ }
+ },
+ "valueAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#666666"
+ }
+ },
+ "axisTick": {
+ "show": false,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#aaaaaa"
+ },
+ "splitLine": {
+ "show": false,
+ "lineStyle": {
+ "color": [
+ "#e6e6e6"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.05)",
+ "rgba(200,200,200,0.02)"
+ ]
+ }
+ }
+ },
+ "logAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#666666"
+ }
+ },
+ "axisTick": {
+ "show": false,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#aaaaaa"
+ },
+ "splitLine": {
+ "show": false,
+ "lineStyle": {
+ "color": [
+ "#e6e6e6"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.05)",
+ "rgba(200,200,200,0.02)"
+ ]
+ }
+ }
+ },
+ "timeAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#666666"
+ }
+ },
+ "axisTick": {
+ "show": false,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#aaaaaa"
+ },
+ "splitLine": {
+ "show": false,
+ "lineStyle": {
+ "color": [
+ "#e6e6e6"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.05)",
+ "rgba(200,200,200,0.02)"
+ ]
+ }
+ }
+ },
+ "toolbox": {
+ "iconStyle": {
+ "borderColor": "#999999"
+ },
+ "emphasis": {
+ "iconStyle": {
+ "borderColor": "#666666"
+ }
+ }
+ },
+ "legend": {
+ "textStyle": {
+ "color": "#999999"
+ }
+ },
+ "tooltip": {
+ "axisPointer": {
+ "lineStyle": {
+ "color": "#cccccc",
+ "width": 1
+ },
+ "crossStyle": {
+ "color": "#cccccc",
+ "width": 1
+ }
+ }
+ },
+ "timeline": {
+ "lineStyle": {
+ "color": "#87f7cf",
+ "width": 1
+ },
+ "itemStyle": {
+ "color": "#87f7cf",
+ "borderWidth": 1
+ },
+ "controlStyle": {
+ "color": "#87f7cf",
+ "borderColor": "#87f7cf",
+ "borderWidth": 0.5
+ },
+ "checkpointStyle": {
+ "color": "#fc97af",
+ "borderColor": "#fc97af"
+ },
+ "label": {
+ "color": "#87f7cf"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "color": "#f7f494"
+ },
+ "controlStyle": {
+ "color": "#87f7cf",
+ "borderColor": "#87f7cf",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#87f7cf"
+ }
+ }
+ },
+ "visualMap": {
+ "color": [
+ "#fc97af",
+ "#87f7cf"
+ ]
+ },
+ "dataZoom": {
+ "backgroundColor": "rgba(255,255,255,0)",
+ "dataBackgroundColor": "rgba(114,204,255,1)",
+ "fillerColor": "rgba(114,204,255,0.2)",
+ "handleColor": "#72ccff",
+ "handleSize": "100%",
+ "textStyle": {
+ "color": "#333333"
+ }
+ },
+ "markPoint": {
+ "label": {
+ "color": "#293441"
+ },
+ "emphasis": {
+ "label": {
+ "color": "#293441"
+ }
+ }
+ }
+}
diff --git a/app/client/src/theme/echart/macarons.json b/app/client/src/theme/echart/macarons.json
new file mode 100644
index 0000000000..a851e5cc53
--- /dev/null
+++ b/app/client/src/theme/echart/macarons.json
@@ -0,0 +1,420 @@
+
+{
+ "color": [
+ "#2ec7c9",
+ "#b6a2de",
+ "#5ab1ef",
+ "#ffb980",
+ "#d87a80",
+ "#8d98b3",
+ "#e5cf0d",
+ "#97b552",
+ "#95706d",
+ "#dc69aa",
+ "#07a2a4",
+ "#9a7fd1",
+ "#588dd5",
+ "#f5994e",
+ "#c05050",
+ "#59678c",
+ "#c9ab00",
+ "#7eb00a",
+ "#6f5553",
+ "#c14089"
+ ],
+ "backgroundColor": "rgba(0,0,0,0)",
+ "textStyle": {},
+ "title": {
+ "textStyle": {
+ "color": "#008acd"
+ },
+ "subtextStyle": {
+ "color": "#aaaaaa"
+ }
+ },
+ "line": {
+ "itemStyle": {
+ "borderWidth": 1
+ },
+ "lineStyle": {
+ "width": 2
+ },
+ "symbolSize": 3,
+ "symbol": "emptyCircle",
+ "smooth": true
+ },
+ "radar": {
+ "itemStyle": {
+ "borderWidth": 1
+ },
+ "lineStyle": {
+ "width": 2
+ },
+ "symbolSize": 3,
+ "symbol": "emptyCircle",
+ "smooth": true
+ },
+ "bar": {
+ "itemStyle": {
+ "barBorderWidth": 0,
+ "barBorderColor": "#ccc"
+ }
+ },
+ "pie": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "scatter": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "boxplot": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "parallel": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "sankey": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "funnel": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "gauge": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "candlestick": {
+ "itemStyle": {
+ "color": "#d87a80",
+ "color0": "#2ec7c9",
+ "borderColor": "#d87a80",
+ "borderColor0": "#2ec7c9",
+ "borderWidth": 1
+ }
+ },
+ "graph": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ },
+ "lineStyle": {
+ "width": 1,
+ "color": "#aaaaaa"
+ },
+ "symbolSize": 3,
+ "symbol": "emptyCircle",
+ "smooth": true,
+ "color": [
+ "#2ec7c9",
+ "#b6a2de",
+ "#5ab1ef",
+ "#ffb980",
+ "#d87a80",
+ "#8d98b3",
+ "#e5cf0d",
+ "#97b552",
+ "#95706d",
+ "#dc69aa",
+ "#07a2a4",
+ "#9a7fd1",
+ "#588dd5",
+ "#f5994e",
+ "#c05050",
+ "#59678c",
+ "#c9ab00",
+ "#7eb00a",
+ "#6f5553",
+ "#c14089"
+ ],
+ "label": {
+ "color": "#eeeeee"
+ }
+ },
+ "map": {
+ "itemStyle": {
+ "areaColor": "#dddddd",
+ "borderColor": "#eeeeee",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#d87a80"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "areaColor": "rgba(254,153,78,1)",
+ "borderColor": "#444",
+ "borderWidth": 1
+ },
+ "label": {
+ "color": "rgb(100,0,0)"
+ }
+ }
+ },
+ "geo": {
+ "itemStyle": {
+ "areaColor": "#dddddd",
+ "borderColor": "#eeeeee",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#d87a80"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "areaColor": "rgba(254,153,78,1)",
+ "borderColor": "#444",
+ "borderWidth": 1
+ },
+ "label": {
+ "color": "rgb(100,0,0)"
+ }
+ }
+ },
+ "categoryAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#008acd"
+ }
+ },
+ "axisTick": {
+ "show": true,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#333"
+ },
+ "splitLine": {
+ "show": false,
+ "lineStyle": {
+ "color": [
+ "#eee"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.3)",
+ "rgba(200,200,200,0.3)"
+ ]
+ }
+ }
+ },
+ "valueAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#008acd"
+ }
+ },
+ "axisTick": {
+ "show": true,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#333"
+ },
+ "splitLine": {
+ "show": true,
+ "lineStyle": {
+ "color": [
+ "#eee"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": true,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.3)",
+ "rgba(200,200,200,0.3)"
+ ]
+ }
+ }
+ },
+ "logAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#008acd"
+ }
+ },
+ "axisTick": {
+ "show": true,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#333"
+ },
+ "splitLine": {
+ "show": true,
+ "lineStyle": {
+ "color": [
+ "#eee"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": true,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.3)",
+ "rgba(200,200,200,0.3)"
+ ]
+ }
+ }
+ },
+ "timeAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#008acd"
+ }
+ },
+ "axisTick": {
+ "show": true,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#333"
+ },
+ "splitLine": {
+ "show": true,
+ "lineStyle": {
+ "color": [
+ "#eee"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.3)",
+ "rgba(200,200,200,0.3)"
+ ]
+ }
+ }
+ },
+ "toolbox": {
+ "iconStyle": {
+ "borderColor": "#2ec7c9"
+ },
+ "emphasis": {
+ "iconStyle": {
+ "borderColor": "#18a4a6"
+ }
+ }
+ },
+ "legend": {
+ "textStyle": {
+ "color": "#333333"
+ }
+ },
+ "tooltip": {
+ "axisPointer": {
+ "lineStyle": {
+ "color": "#008acd",
+ "width": "1"
+ },
+ "crossStyle": {
+ "color": "#008acd",
+ "width": "1"
+ }
+ }
+ },
+ "timeline": {
+ "lineStyle": {
+ "color": "#008acd",
+ "width": 1
+ },
+ "itemStyle": {
+ "color": "#008acd",
+ "borderWidth": 1
+ },
+ "controlStyle": {
+ "color": "#008acd",
+ "borderColor": "#008acd",
+ "borderWidth": 0.5
+ },
+ "checkpointStyle": {
+ "color": "#2ec7c9",
+ "borderColor": "#2ec7c9"
+ },
+ "label": {
+ "color": "#008acd"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "color": "#a9334c"
+ },
+ "controlStyle": {
+ "color": "#008acd",
+ "borderColor": "#008acd",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#008acd"
+ }
+ }
+ },
+ "visualMap": {
+ "color": [
+ "#5ab1ef",
+ "#e0ffff"
+ ]
+ },
+ "dataZoom": {
+ "backgroundColor": "rgba(47,69,84,0)",
+ "dataBackgroundColor": "#efefff",
+ "fillerColor": "rgba(182,162,222,0.2)",
+ "handleColor": "#008acd",
+ "handleSize": "100%",
+ "textStyle": {
+ "color": "#333333"
+ }
+ },
+ "markPoint": {
+ "label": {
+ "color": "#eeeeee"
+ },
+ "emphasis": {
+ "label": {
+ "color": "#eeeeee"
+ }
+ }
+ }
+}
diff --git a/app/client/src/theme/echart/walden.json b/app/client/src/theme/echart/walden.json
new file mode 100644
index 0000000000..2549c910b9
--- /dev/null
+++ b/app/client/src/theme/echart/walden.json
@@ -0,0 +1,392 @@
+
+{
+ "color": [
+ "#3fb1e3",
+ "#6be6c1",
+ "#626c91",
+ "#a0a7e6",
+ "#c4ebad",
+ "#96dee8"
+ ],
+ "backgroundColor": "rgba(252,252,252,0)",
+ "textStyle": {},
+ "title": {
+ "textStyle": {
+ "color": "#666666"
+ },
+ "subtextStyle": {
+ "color": "#999999"
+ }
+ },
+ "line": {
+ "itemStyle": {
+ "borderWidth": "2"
+ },
+ "lineStyle": {
+ "width": "3"
+ },
+ "symbolSize": "8",
+ "symbol": "emptyCircle",
+ "smooth": false
+ },
+ "radar": {
+ "itemStyle": {
+ "borderWidth": "2"
+ },
+ "lineStyle": {
+ "width": "3"
+ },
+ "symbolSize": "8",
+ "symbol": "emptyCircle",
+ "smooth": false
+ },
+ "bar": {
+ "itemStyle": {
+ "barBorderWidth": 0,
+ "barBorderColor": "#ccc"
+ }
+ },
+ "pie": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "scatter": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "boxplot": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "parallel": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "sankey": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "funnel": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "gauge": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "candlestick": {
+ "itemStyle": {
+ "color": "#e6a0d2",
+ "color0": "transparent",
+ "borderColor": "#e6a0d2",
+ "borderColor0": "#3fb1e3",
+ "borderWidth": "2"
+ }
+ },
+ "graph": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ },
+ "lineStyle": {
+ "width": "1",
+ "color": "#cccccc"
+ },
+ "symbolSize": "8",
+ "symbol": "emptyCircle",
+ "smooth": false,
+ "color": [
+ "#3fb1e3",
+ "#6be6c1",
+ "#626c91",
+ "#a0a7e6",
+ "#c4ebad",
+ "#96dee8"
+ ],
+ "label": {
+ "color": "#ffffff"
+ }
+ },
+ "map": {
+ "itemStyle": {
+ "areaColor": "#eeeeee",
+ "borderColor": "#aaaaaa",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#ffffff"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "areaColor": "rgba(63,177,227,0.25)",
+ "borderColor": "#3fb1e3",
+ "borderWidth": 1
+ },
+ "label": {
+ "color": "#3fb1e3"
+ }
+ }
+ },
+ "geo": {
+ "itemStyle": {
+ "areaColor": "#eeeeee",
+ "borderColor": "#aaaaaa",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#ffffff"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "areaColor": "rgba(63,177,227,0.25)",
+ "borderColor": "#3fb1e3",
+ "borderWidth": 1
+ },
+ "label": {
+ "color": "#3fb1e3"
+ }
+ }
+ },
+ "categoryAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#cccccc"
+ }
+ },
+ "axisTick": {
+ "show": false,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#999999"
+ },
+ "splitLine": {
+ "show": true,
+ "lineStyle": {
+ "color": [
+ "#eeeeee"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.05)",
+ "rgba(200,200,200,0.02)"
+ ]
+ }
+ }
+ },
+ "valueAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#cccccc"
+ }
+ },
+ "axisTick": {
+ "show": false,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#999999"
+ },
+ "splitLine": {
+ "show": true,
+ "lineStyle": {
+ "color": [
+ "#eeeeee"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.05)",
+ "rgba(200,200,200,0.02)"
+ ]
+ }
+ }
+ },
+ "logAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#cccccc"
+ }
+ },
+ "axisTick": {
+ "show": false,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#999999"
+ },
+ "splitLine": {
+ "show": true,
+ "lineStyle": {
+ "color": [
+ "#eeeeee"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.05)",
+ "rgba(200,200,200,0.02)"
+ ]
+ }
+ }
+ },
+ "timeAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#cccccc"
+ }
+ },
+ "axisTick": {
+ "show": false,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#999999"
+ },
+ "splitLine": {
+ "show": true,
+ "lineStyle": {
+ "color": [
+ "#eeeeee"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.05)",
+ "rgba(200,200,200,0.02)"
+ ]
+ }
+ }
+ },
+ "toolbox": {
+ "iconStyle": {
+ "borderColor": "#999999"
+ },
+ "emphasis": {
+ "iconStyle": {
+ "borderColor": "#666666"
+ }
+ }
+ },
+ "legend": {
+ "textStyle": {
+ "color": "#999999"
+ }
+ },
+ "tooltip": {
+ "axisPointer": {
+ "lineStyle": {
+ "color": "#cccccc",
+ "width": 1
+ },
+ "crossStyle": {
+ "color": "#cccccc",
+ "width": 1
+ }
+ }
+ },
+ "timeline": {
+ "lineStyle": {
+ "color": "#626c91",
+ "width": 1
+ },
+ "itemStyle": {
+ "color": "#626c91",
+ "borderWidth": 1
+ },
+ "controlStyle": {
+ "color": "#626c91",
+ "borderColor": "#626c91",
+ "borderWidth": 0.5
+ },
+ "checkpointStyle": {
+ "color": "#3fb1e3",
+ "borderColor": "#3fb1e3"
+ },
+ "label": {
+ "color": "#626c91"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "color": "#626c91"
+ },
+ "controlStyle": {
+ "color": "#626c91",
+ "borderColor": "#626c91",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#626c91"
+ }
+ }
+ },
+ "visualMap": {
+ "color": [
+ "#2a99c9",
+ "#afe8ff"
+ ]
+ },
+ "dataZoom": {
+ "backgroundColor": "rgba(255,255,255,0)",
+ "dataBackgroundColor": "rgba(222,222,222,1)",
+ "fillerColor": "rgba(114,230,212,0.25)",
+ "handleColor": "#cccccc",
+ "handleSize": "100%",
+ "textStyle": {
+ "color": "#999999"
+ }
+ },
+ "markPoint": {
+ "label": {
+ "color": "#ffffff"
+ },
+ "emphasis": {
+ "label": {
+ "color": "#ffffff"
+ }
+ }
+ }
+}
diff --git a/app/client/src/theme/echart/westeros.json b/app/client/src/theme/echart/westeros.json
new file mode 100644
index 0000000000..310990e57f
--- /dev/null
+++ b/app/client/src/theme/echart/westeros.json
@@ -0,0 +1,393 @@
+
+{
+ "color": [
+ "#516b91",
+ "#59c4e6",
+ "#edafda",
+ "#93b7e3",
+ "#a5e7f0",
+ "#cbb0e3"
+ ],
+ "backgroundColor": "rgba(0,0,0,0)",
+ "textStyle": {},
+ "title": {
+ "textStyle": {
+ "color": "#516b91"
+ },
+ "subtextStyle": {
+ "color": "#93b7e3"
+ }
+ },
+ "line": {
+ "itemStyle": {
+ "borderWidth": "2"
+ },
+ "lineStyle": {
+ "width": "2"
+ },
+ "symbolSize": "6",
+ "symbol": "emptyCircle",
+ "smooth": true
+ },
+ "radar": {
+ "itemStyle": {
+ "borderWidth": "2"
+ },
+ "lineStyle": {
+ "width": "2"
+ },
+ "symbolSize": "6",
+ "symbol": "emptyCircle",
+ "smooth": true
+ },
+ "bar": {
+ "itemStyle": {
+ "barBorderWidth": 0,
+ "barBorderColor": "#ccc"
+ }
+ },
+ "pie": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "scatter": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "boxplot": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "parallel": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "sankey": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "funnel": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "gauge": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ }
+ },
+ "candlestick": {
+ "itemStyle": {
+ "color": "#edafda",
+ "color0": "transparent",
+ "borderColor": "#d680bc",
+ "borderColor0": "#8fd3e8",
+ "borderWidth": "2"
+ }
+ },
+ "graph": {
+ "itemStyle": {
+ "borderWidth": 0,
+ "borderColor": "#ccc"
+ },
+ "lineStyle": {
+ "width": 1,
+ "color": "#aaaaaa"
+ },
+ "symbolSize": "6",
+ "symbol": "emptyCircle",
+ "smooth": true,
+ "color": [
+ "#516b91",
+ "#59c4e6",
+ "#edafda",
+ "#93b7e3",
+ "#a5e7f0",
+ "#cbb0e3"
+ ],
+ "label": {
+ "color": "#eeeeee"
+ }
+ },
+ "map": {
+ "itemStyle": {
+ "areaColor": "#f3f3f3",
+ "borderColor": "#516b91",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#000"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "areaColor": "#a5e7f0",
+ "borderColor": "#516b91",
+ "borderWidth": 1
+ },
+ "label": {
+ "color": "#516b91"
+ }
+ }
+ },
+ "geo": {
+ "itemStyle": {
+ "areaColor": "#f3f3f3",
+ "borderColor": "#516b91",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#000"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "areaColor": "#a5e7f0",
+ "borderColor": "#516b91",
+ "borderWidth": 1
+ },
+ "label": {
+ "color": "#516b91"
+ }
+ }
+ },
+ "categoryAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#cccccc"
+ }
+ },
+ "axisTick": {
+ "show": false,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#999999"
+ },
+ "splitLine": {
+ "show": true,
+ "lineStyle": {
+ "color": [
+ "#eeeeee"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.05)",
+ "rgba(200,200,200,0.02)"
+ ]
+ }
+ }
+ },
+ "valueAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#cccccc"
+ }
+ },
+ "axisTick": {
+ "show": false,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#999999"
+ },
+ "splitLine": {
+ "show": true,
+ "lineStyle": {
+ "color": [
+ "#eeeeee"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.05)",
+ "rgba(200,200,200,0.02)"
+ ]
+ }
+ }
+ },
+ "logAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#cccccc"
+ }
+ },
+ "axisTick": {
+ "show": false,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#999999"
+ },
+ "splitLine": {
+ "show": true,
+ "lineStyle": {
+ "color": [
+ "#eeeeee"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.05)",
+ "rgba(200,200,200,0.02)"
+ ]
+ }
+ }
+ },
+ "timeAxis": {
+ "axisLine": {
+ "show": true,
+ "lineStyle": {
+ "color": "#cccccc"
+ }
+ },
+ "axisTick": {
+ "show": false,
+ "lineStyle": {
+ "color": "#333"
+ }
+ },
+ "axisLabel": {
+ "show": true,
+ "color": "#999999"
+ },
+ "splitLine": {
+ "show": true,
+ "lineStyle": {
+ "color": [
+ "#eeeeee"
+ ]
+ }
+ },
+ "splitArea": {
+ "show": false,
+ "areaStyle": {
+ "color": [
+ "rgba(250,250,250,0.05)",
+ "rgba(200,200,200,0.02)"
+ ]
+ }
+ }
+ },
+ "toolbox": {
+ "iconStyle": {
+ "borderColor": "#999999"
+ },
+ "emphasis": {
+ "iconStyle": {
+ "borderColor": "#666666"
+ }
+ }
+ },
+ "legend": {
+ "textStyle": {
+ "color": "#999999"
+ }
+ },
+ "tooltip": {
+ "axisPointer": {
+ "lineStyle": {
+ "color": "#cccccc",
+ "width": 1
+ },
+ "crossStyle": {
+ "color": "#cccccc",
+ "width": 1
+ }
+ }
+ },
+ "timeline": {
+ "lineStyle": {
+ "color": "#8fd3e8",
+ "width": 1
+ },
+ "itemStyle": {
+ "color": "#8fd3e8",
+ "borderWidth": 1
+ },
+ "controlStyle": {
+ "color": "#8fd3e8",
+ "borderColor": "#8fd3e8",
+ "borderWidth": 0.5
+ },
+ "checkpointStyle": {
+ "color": "#8fd3e8",
+ "borderColor": "#8a7ca8"
+ },
+ "label": {
+ "color": "#8fd3e8"
+ },
+ "emphasis": {
+ "itemStyle": {
+ "color": "#8fd3e8"
+ },
+ "controlStyle": {
+ "color": "#8fd3e8",
+ "borderColor": "#8fd3e8",
+ "borderWidth": 0.5
+ },
+ "label": {
+ "color": "#8fd3e8"
+ }
+ }
+ },
+ "visualMap": {
+ "color": [
+ "#516b91",
+ "#59c4e6",
+ "#a5e7f0"
+ ]
+ },
+ "dataZoom": {
+ "backgroundColor": "rgba(0,0,0,0)",
+ "dataBackgroundColor": "rgba(255,255,255,0.3)",
+ "fillerColor": "rgba(167,183,204,0.4)",
+ "handleColor": "#a7b7cc",
+ "handleSize": "100%",
+ "textStyle": {
+ "color": "#333"
+ }
+ },
+ "markPoint": {
+ "label": {
+ "color": "#eeeeee"
+ },
+ "emphasis": {
+ "label": {
+ "color": "#eeeeee"
+ }
+ }
+ }
+}
diff --git a/app/client/src/utils/AppUtils.ts b/app/client/src/utils/AppUtils.ts
index afb15a0fbf..1c9d28e43f 100644
--- a/app/client/src/utils/AppUtils.ts
+++ b/app/client/src/utils/AppUtils.ts
@@ -26,3 +26,21 @@ const getEnvLogLevel = (configLevel: LogLevelDesc): LogLevelDesc => {
}
return logLevel;
};
+
+/**
+ * read json data from json url
+ * @param blobUrl
+ * @returns
+ */
+export async function readBlob(blobUrl: string): Promise {
+ const file = await fetch(blobUrl, {
+ referrer: "",
+ }).then((r) => r.blob());
+ return new Promise((resolve) => {
+ const reader = new FileReader();
+ reader.readAsText(file);
+ reader.onloadend = () => {
+ resolve(reader.result);
+ };
+ });
+}
diff --git a/app/client/src/utils/DynamicBindingUtils.ts b/app/client/src/utils/DynamicBindingUtils.ts
index ef1e6fae84..9295822641 100644
--- a/app/client/src/utils/DynamicBindingUtils.ts
+++ b/app/client/src/utils/DynamicBindingUtils.ts
@@ -2,6 +2,7 @@ import _, { get, isString, VERSION as lodashVersion } from "lodash";
import { DATA_BIND_REGEX } from "constants/BindingsConstants";
import { Action } from "entities/Action";
import moment from "moment-timezone";
+import * as echarts from "echarts";
import { WidgetProps } from "widgets/BaseWidget";
import parser from "fast-xml-parser";
@@ -187,6 +188,13 @@ export const extraLibraries: ExtraLibrary[] = [
docsURL: "https://github.com/digitalbazaar/forge",
displayName: "forge",
},
+ {
+ accessor: "echarts",
+ lib: echarts,
+ version: "5.4.0",
+ docsURL: `https://echarts.apache.org/handbook/zh/how-to/animation/transition/`,
+ displayName: "echarts",
+ },
];
/**
* creates dynamic list of constants based on
diff --git a/app/client/src/utils/WidgetRegistry.tsx b/app/client/src/utils/WidgetRegistry.tsx
index 4e3aa44e09..12d7088fa1 100644
--- a/app/client/src/utils/WidgetRegistry.tsx
+++ b/app/client/src/utils/WidgetRegistry.tsx
@@ -23,6 +23,9 @@ import CanvasWidget, {
import ChartWidget, {
CONFIG as CHART_WIDGET_CONFIG,
} from "widgets/ChartWidget";
+import EChartWidget, {
+ CONFIG as ECHART_WIDGET_CONFIG,
+} from "widgets/EchartWidget";
import CheckboxGroupWidget, {
CONFIG as CHECKBOX_GROUP_WIDGET_CONFIG,
} from "widgets/CheckboxGroupWidget";
@@ -240,6 +243,7 @@ export const ALL_WIDGETS_AND_CONFIG = [
[TabsWidget, TABS_WIDGET_CONFIG],
[ModalWidget, MODAL_WIDGET_CONFIG],
[ChartWidget, CHART_WIDGET_CONFIG],
+ [EChartWidget, ECHART_WIDGET_CONFIG],
[MapWidget, MAP_WIDGET_CONFIG],
[RichTextEditorWidget, RICH_TEXT_EDITOR_WIDGET_CONFIG],
[DatePickerWidget2, DATE_PICKER_WIDGET_2_CONFIG],
diff --git a/app/client/src/utils/autocomplete/EntityDefinitions.ts b/app/client/src/utils/autocomplete/EntityDefinitions.ts
index 7c5971eac4..9ef4af94fd 100644
--- a/app/client/src/utils/autocomplete/EntityDefinitions.ts
+++ b/app/client/src/utils/autocomplete/EntityDefinitions.ts
@@ -39,6 +39,10 @@ export const entityDefinitions = {
watchPosition: "fn(options: object) -> void",
clearWatch: "fn() -> void",
},
+ echartInstance: {
+ callFunc:
+ "fn(widgetName: string, funcName: string, options?: any) -> +Promise[:t=[!0..:t]]",
+ },
};
}
return generatedTypeDef;
@@ -350,6 +354,20 @@ export const entityDefinitions = {
yAxisName: "string",
selectedDataPoint: "$__chartDataPoint__$",
},
+ ECHART_WIDGET: {
+ "!doc":
+ "EChart widget is used to view the graphical representation of your data. Echart is the go-to widget for your data visualisation needs.",
+ "!url": "https://docs.appsmith.com/widget-reference/chart",
+ isVisible: true,
+ chartData: {
+ seriesName: "string",
+ // data: "[$__chartDataPoint__$]",
+ data: "any",
+ },
+ xAxisName: "string",
+ yAxisName: "string",
+ selectedDataItem: "any",
+ },
FORM_WIDGET: (widget: any, extraDefsToDefine?: ExtraDef) => ({
"!doc":
"Form is used to capture a set of data inputs from a user. Forms are used specifically because they reset the data inputs when a form is submitted and disable submission for invalid data inputs",
diff --git a/app/client/src/utils/migrations/ChartWidgetReskinningMigrations.ts b/app/client/src/utils/migrations/ChartWidgetReskinningMigrations.ts
index e9d0eeb9d8..fe3290d355 100644
--- a/app/client/src/utils/migrations/ChartWidgetReskinningMigrations.ts
+++ b/app/client/src/utils/migrations/ChartWidgetReskinningMigrations.ts
@@ -3,7 +3,7 @@ import { DSLWidget } from "widgets/constants";
export const migrateChartWidgetReskinningData = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: WidgetProps) => {
- if (child.type === "CHART_WIDGET") {
+ if (child.type === "CHART_WIDGET" || child.type === "ECHART_WIDGET") {
if (
!(
child.hasOwnProperty("accentColor") &&
diff --git a/app/client/src/widgets/EchartWidget/component/index.tsx b/app/client/src/widgets/EchartWidget/component/index.tsx
new file mode 100644
index 0000000000..4061ebbde4
--- /dev/null
+++ b/app/client/src/widgets/EchartWidget/component/index.tsx
@@ -0,0 +1,303 @@
+/* eslint-disable @typescript-eslint/ban-ts-comment */
+import React, { useEffect, useRef, useState } from "react";
+import * as echarts from "echarts";
+import "echarts-gl";
+import * as _ from "lodash";
+import "echarts/extension/bmap/bmap";
+import macarons from "theme/echart/macarons.json";
+import chalk from "theme/echart/chalk.json";
+import walden from "theme/echart/walden.json";
+import westeros from "theme/echart/westeros.json";
+import { useSelector } from "react-redux";
+import { EchartTheme } from "entities/AppTheming";
+import { getSelectedEchartTheme } from "selectors/appThemingSelectors";
+import { LabelOrientation, AllChartData } from "../constants";
+import { NO_AXIS, ECHART_BASIC_OPTION, ECHART_TYPE_MAP } from "../constants";
+import { convertStringFunciton } from "../widget/helper";
+import { readBlob } from "utils/AppUtils";
+import { message } from "antd";
+
+interface pointType {
+ name: string | number;
+ value: number;
+}
+
+function customizer(objValue: any, srcValue: any) {
+ if (_.isArray(objValue)) {
+ return objValue.concat(srcValue);
+ }
+}
+const DARK_THEMES = ["dark", "chalk", "transparent"];
+
+function EchartComponent(props: EchartComponentProps) {
+ const echartRef = useRef();
+ const echartInstance = useRef();
+ const selectedEchartTheme = useSelector(getSelectedEchartTheme);
+ const objectRef = useRef();
+ const [preChartTheme, setCurrentChart] = useState();
+
+ const chartContainerId = props.widgetId + "-echart-container";
+
+ const {
+ onDataPointClick,
+ chartType,
+ chartName,
+ xAxisName,
+ yAxisName,
+ chartData,
+ customEchartConfig,
+ borderRadius,
+ boxShadow,
+ backgroundColor,
+ registerMapJsonUrl,
+ registerMapName,
+ } = props;
+
+ const handleEvent = () => {
+ const _echartInstance = echartInstance.current;
+ const { onDataPointClick } = props;
+ if (onDataPointClick && _echartInstance) {
+ _echartInstance.on("click", (evt: any) => {
+ onDataPointClick(evt);
+ });
+ }
+ };
+
+ const registerEchartTheme = (theme: string | undefined) => {
+ switch (theme) {
+ case "macarons":
+ echarts.registerTheme("macarons", macarons);
+ break;
+ case "chalk":
+ echarts.registerTheme("chalk", chalk);
+ break;
+ case "westeros":
+ echarts.registerTheme("westeros", westeros);
+ break;
+ case "walden":
+ echarts.registerTheme("walden", walden);
+ break;
+ default:
+ break;
+ }
+ };
+
+ const registerMap = () => {
+ if (registerMapName && registerMapJsonUrl && echartInstance.current) {
+ if (echarts.getMap(registerMapName)) {
+ // already register
+ } else {
+ readBlob(registerMapJsonUrl)
+ .then((resData) => {
+ echarts.registerMap(registerMapName, resData);
+ })
+ .catch(() => {
+ message.warn("地图注册失败");
+ });
+ }
+ }
+ };
+
+ useEffect(() => {
+ const { onInstance } = props;
+ onInstance && echartInstance.current && onInstance(echartInstance.current);
+ }, [echartInstance.current]);
+
+ // props更新调用
+ useEffect(() => {
+ if (!chartData) {
+ return;
+ }
+ if (!echartInstance.current && echartRef.current) {
+ echartInstance.current = echarts.init(echartRef?.current, "default");
+ }
+ /*register theme*/
+ const registerTheme: EchartTheme | undefined = selectedEchartTheme;
+ if (preChartTheme !== registerTheme && registerTheme) {
+ echartInstance.current.dispose();
+ registerEchartTheme(registerTheme.themeKey);
+ echartInstance.current = echarts.init(
+ echartRef?.current,
+ registerTheme.themeKey,
+ );
+ }
+
+ if (echartInstance.current) {
+ // 清空一下实例
+ echartInstance.current.clear();
+ const _seriesD = getSeriesAndXaxisData();
+ let newOption: any = {
+ title: {
+ text: chartName,
+ },
+ xAxis: {
+ name: xAxisName,
+ data: _seriesD.xAxis,
+ },
+ yAxis: {
+ name: yAxisName,
+ },
+ darkMode: true,
+ series: _seriesD.series,
+ };
+ if (backgroundColor) {
+ _.set(newOption, "backgroundColor", backgroundColor);
+ }
+ if (
+ selectedEchartTheme &&
+ DARK_THEMES.includes(selectedEchartTheme.themeKey)
+ ) {
+ _.set(newOption, "darkMode", true);
+ }
+
+ if (chartType === "CUSTOM_CHART" && customEchartConfig) {
+ newOption = customEchartConfig;
+ }
+
+ _.mergeWith(newOption, ECHART_BASIC_OPTION, customizer);
+
+ /**
+ * 如果在opts.replaceMerge里指定组件类型,这类组件会进行替换合并。
+ * 否则,会进行普通合并
+ */
+ const replaceMerge: string[] = [];
+
+ if (NO_AXIS[chartType]) {
+ replaceMerge.push("xAxis", "yAxis");
+ _.set(newOption, "yAxis.show", false);
+ _.set(newOption, "xAxis.show", false);
+ } else {
+ _.set(newOption, "yAxis.show", true);
+ _.set(newOption, "xAxis.show", true);
+ }
+ const newOptions: any = convertStringFunciton(newOption);
+ echartInstance.current.setOption(newOptions, { replaceMerge });
+ setCurrentChart(selectedEchartTheme);
+ }
+ }, [
+ chartType,
+ chartName,
+ xAxisName,
+ yAxisName,
+ chartData,
+ customEchartConfig,
+ backgroundColor,
+ selectedEchartTheme,
+ registerMapName,
+ registerMapJsonUrl,
+ ]);
+
+ useEffect(() => {
+ registerMap();
+ }, [registerMapJsonUrl, registerMapName]);
+
+ // 点击事件handler
+ useEffect(() => {
+ return () => {
+ echartInstance.current &&
+ echartInstance.current.off("click", onDataPointClick);
+ };
+ }, [onDataPointClick]);
+
+ // bind event
+ useEffect(() => {
+ if (echartRef.current) {
+ handleEvent();
+ }
+ registerMap();
+ }, []);
+
+ const getSeriesAndXaxisData = () => {
+ const series: any[] = [];
+ const xAxis: any[] = [];
+ _.each(chartData, (c_data, c_key) => {
+ if (chartType === "PIE_CHART") {
+ series.push({
+ ...c_data,
+ id: c_key,
+ name: c_data.seriesName,
+ type: ECHART_TYPE_MAP[chartType],
+ data: c_data.data.map((it: pointType) => {
+ return {
+ name: it.name,
+ value: it.value,
+ };
+ }),
+ });
+ } else {
+ series.push({
+ ...c_data,
+ id: c_key,
+ name: c_data.seriesName,
+ type: ECHART_TYPE_MAP[chartType],
+ data: c_data.data.map((it: pointType) => {
+ !xAxis.includes(it.name) && xAxis.push(it.name);
+ return it.value;
+ }),
+ });
+ }
+ });
+ return { xAxis, series };
+ };
+
+ useEffect(() => {
+ objectRef.current.contentDocument.defaultView.addEventListener(
+ "resize",
+ () => {
+ echartInstance.current.resize();
+ },
+ );
+ }, [objectRef.current]);
+
+ const style = {
+ borderRadius,
+ boxShadow,
+ };
+ return (
+
+ );
+}
+
+export interface EchartComponentProps {
+ widgetId?: string;
+ allowScroll: boolean;
+ chartData: AllChartData;
+ chartName: string;
+ chartType: string;
+ customEchartConfig: any;
+ isVisible?: boolean;
+ isLoading: boolean;
+ setAdaptiveYMin: boolean; // set adaptive YAxis
+ labelOrientation?: LabelOrientation; // adjust xAxis label orientation
+ onDataPointClick: (selectedDataPoint: any) => void;
+ onInstance: (instance?: any) => void;
+ xAxisName: string;
+ yAxisName: string;
+ borderRadius: string;
+ boxShadow?: string;
+ primaryColor?: string;
+ backgroundColor?: string;
+ fontFamily?: string;
+ registerMapJsonUrl?: string;
+ registerMapName?: string;
+}
+
+export default EchartComponent;
diff --git a/app/client/src/widgets/EchartWidget/constants.ts b/app/client/src/widgets/EchartWidget/constants.ts
new file mode 100644
index 0000000000..8c4c54443d
--- /dev/null
+++ b/app/client/src/widgets/EchartWidget/constants.ts
@@ -0,0 +1,142 @@
+export type ChartType =
+ | "LINE_CHART"
+ | "BAR_CHART"
+ | "PIE_CHART"
+ | "COLUMN_CHART"
+ | "AREA_CHART"
+ | "SCATTER_CHART"
+ | "CUSTOM_CHART";
+
+export interface ChartDataPoint {
+ x: any;
+ y: any;
+}
+
+export interface DataSetT {
+ value: any;
+ name: string;
+}
+
+export interface ChartData {
+ name?: string;
+ seriesName?: string;
+ data: DataSetT[];
+ type: string;
+}
+
+export interface CustomFusionChartConfig {
+ type: string;
+ dataSource?: any;
+}
+
+export interface AllChartData {
+ [key: string]: ChartData;
+}
+
+export interface ChartSelectedDataPoint {
+ x: any;
+ y: any;
+ seriesTitle: string;
+}
+
+export const defaultColors = [
+ "#3366FF",
+ "#91cc75",
+ "#fac858",
+ "#ee6666",
+ "#38AFF4",
+ "#03b365",
+ "#fc8452",
+ "#9a60b4",
+ "#ea7ccc",
+];
+
+export const CUSTOM_CHART_TYPES = [
+ "line",
+ "bar",
+ "pie",
+ "scatter",
+ "effectScatter",
+ "radar",
+ "tree",
+ "treemap",
+ "sunburst",
+ "boxplot",
+ "candlestick",
+ "heatmap",
+ "map",
+ "parallel",
+ "lines",
+ "graph",
+ "sankey",
+ "funnel",
+ "gauge",
+ "pictorialBar",
+ "themeRiver",
+ "custom",
+];
+
+type Feature = {
+ type: string;
+ properties: any;
+};
+
+export interface RegisterMapData {
+ type: string;
+ features: Feature[];
+}
+
+export const CUSTOM_CHART_DEFAULT_PARSED = {
+ type: "",
+ xAxis: {},
+ yAxis: {},
+ series: [],
+};
+
+export enum LabelOrientation {
+ AUTO = "auto",
+ SLANT = "slant",
+ ROTATE = "rotate",
+ STAGGER = "stagger",
+}
+
+export enum AxisType {
+ CATEGORY = "category",
+ VALUE = "value",
+ TIME = "time",
+ LOG = "log",
+}
+
+export const LABEL_ORIENTATION_COMPATIBLE_CHARTS = [
+ "LINE_CHART",
+ "AREA_CHART",
+ "COLUMN_CHART",
+];
+
+export const ECHART_TYPE_MAP: any = {
+ LINE_CHART: "line",
+ BAR_CHART: "bar",
+ PIE_CHART: "pie",
+ COLUMN_CHART: "bar",
+ AREA_CHART: "line",
+ SCATTER_CHART: "scatter",
+ CUSTOM_CHART: "custom",
+};
+
+export const NO_AXIS: any = {
+ PIE_CHART: 1,
+};
+
+export const isLabelOrientationApplicableFor = (chartType: string) =>
+ LABEL_ORIENTATION_COMPATIBLE_CHARTS.includes(chartType);
+
+export const ECHART_BASIC_OPTION = {
+ xAxis: {
+ type: "category",
+ },
+ animation: true,
+ yAxis: {
+ type: "value",
+ },
+ series: [],
+};
diff --git a/app/client/src/widgets/EchartWidget/icon.svg b/app/client/src/widgets/EchartWidget/icon.svg
new file mode 100644
index 0000000000..3b612e9c04
--- /dev/null
+++ b/app/client/src/widgets/EchartWidget/icon.svg
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/app/client/src/widgets/EchartWidget/index.ts b/app/client/src/widgets/EchartWidget/index.ts
new file mode 100644
index 0000000000..ba95d2bdcf
--- /dev/null
+++ b/app/client/src/widgets/EchartWidget/index.ts
@@ -0,0 +1,94 @@
+import Widget from "./widget";
+import IconSVG from "./icon.svg";
+import { generateReactKey } from "widgets/WidgetUtils";
+import { ECHART_TYPE_MAP } from "./constants";
+const DEFAUTL_CHART = {
+ name: "",
+ chartName: "秋季系列",
+ chartType: "LINE_CHART",
+ type: ECHART_TYPE_MAP["LINE_CHART"],
+ data: [
+ {
+ value: 335,
+ name: "衬衫",
+ },
+ {
+ value: 234,
+ name: "羊毛衫",
+ },
+ {
+ value: 1548,
+ name: "雪纺衫",
+ },
+ {
+ value: 758,
+ name: "裤子",
+ },
+ {
+ value: 358,
+ name: "高跟鞋",
+ },
+ {
+ value: 658,
+ name: "袜子",
+ },
+ ],
+ xAxisName: "品类",
+ yAxisName: "销量",
+};
+const defaultKey = generateReactKey();
+export const CONFIG = {
+ type: Widget.getWidgetType(),
+ name: "Echart", // The display name which will be made in uppercase and show in the widgets panel ( can have spaces )
+ iconSVG: IconSVG,
+ needsMeta: true, // Defines if this widget adds any meta properties
+ searchTags: ["graph", "echart", "chart", "visualisations"],
+ defaults: {
+ widgetName: "Echart",
+ mycustom: 2,
+ rows: 32,
+ columns: 24,
+ version: 1,
+ chartData: {
+ [defaultKey]: {
+ type: DEFAUTL_CHART.type,
+ seriesName: DEFAUTL_CHART.chartName,
+ data: DEFAUTL_CHART.data,
+ },
+ },
+ chartType: DEFAUTL_CHART.chartType,
+ chartName: DEFAUTL_CHART.name,
+ xAxisName: DEFAUTL_CHART.xAxisName,
+ yAxisName: DEFAUTL_CHART.yAxisName,
+ allowScroll: false,
+ animateLoading: true,
+ customEchartConfig: {
+ title: {
+ text: "基础折线图",
+ },
+ xAxis: {
+ type: "category",
+ data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
+ },
+ yAxis: {
+ type: "value",
+ },
+ series: [
+ {
+ data: [150, 230, 224, 218, 135, 147, 260],
+ type: "line",
+ },
+ ],
+ },
+ },
+ properties: {
+ derived: Widget.getDerivedPropertiesMap(),
+ default: Widget.getDefaultPropertiesMap(),
+ meta: Widget.getMetaPropertiesMap(),
+ config: Widget.getPropertyPaneConfig(),
+ contentConfig: Widget.getPropertyPaneContentConfig(),
+ styleConfig: Widget.getPropertyPaneStyleConfig(),
+ },
+};
+
+export default Widget;
diff --git a/app/client/src/widgets/EchartWidget/widget/helper.ts b/app/client/src/widgets/EchartWidget/widget/helper.ts
new file mode 100644
index 0000000000..6b50edc60b
--- /dev/null
+++ b/app/client/src/widgets/EchartWidget/widget/helper.ts
@@ -0,0 +1,30 @@
+/* eslint-disable @typescript-eslint/ban-types */
+import * as _ from "lodash";
+
+function updater_customer(params: string) {
+ return new Function("return " + params)();
+}
+
+/**
+ * convert string function to funciton
+ * @param data object with string function
+ * @returns object with function
+ */
+export function convertStringFunciton(temp: any) {
+ const data = _.cloneDeep(temp);
+ function traverse(params: any, path: string) {
+ for (const key in params) {
+ const current_path = `${path}${path ? "." : ""}${key}`;
+ if (
+ typeof params[key] === "string" &&
+ params[key].trimStart().startsWith("function")
+ ) {
+ _.update(data, current_path, updater_customer);
+ } else if (typeof params[key] === "object") {
+ traverse(params[key], current_path);
+ }
+ }
+ }
+ traverse(temp, "");
+ return data;
+}
diff --git a/app/client/src/widgets/EchartWidget/widget/index.tsx b/app/client/src/widgets/EchartWidget/widget/index.tsx
new file mode 100644
index 0000000000..a4b41fb23f
--- /dev/null
+++ b/app/client/src/widgets/EchartWidget/widget/index.tsx
@@ -0,0 +1,130 @@
+import React, { lazy, Suspense } from "react";
+// import styled from "styled-components";
+import * as _ from "lodash";
+import Skeleton from "components/utils/Skeleton";
+import propertyConfig, { contentConfig, styleConfig } from "./propertyConfig";
+import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
+import { retryPromise } from "utils/AppsmithUtils";
+
+import BaseWidget, { WidgetProps, WidgetState } from "widgets/BaseWidget";
+import { DerivedPropertiesMap } from "utils/WidgetFactory";
+import { Colors } from "constants/Colors";
+import { AllChartData, ChartType } from "../constants";
+// import { computeFinalRowCols } from "components/editorComponents/ResizableUtils";
+// import { EchartComponentProps } from "../component";
+
+const EchartComponent = lazy(() =>
+ retryPromise(() =>
+ import(
+ /* webpackPrefetch: true, webpackChunkName: "charts" */ "../component"
+ ),
+ ),
+);
+class EchartWidget extends BaseWidget {
+ static getPropertyPaneConfig() {
+ return propertyConfig;
+ }
+
+ static getDerivedPropertiesMap(): DerivedPropertiesMap {
+ return {};
+ }
+
+ static getDefaultPropertiesMap(): Record {
+ return {};
+ }
+
+ static getPropertyPaneContentConfig() {
+ return contentConfig;
+ }
+
+ static getPropertyPaneStyleConfig() {
+ return styleConfig;
+ }
+
+ static getMetaPropertiesMap(): Record {
+ return {
+ selectedDataItem: undefined,
+ instance: null,
+ };
+ }
+
+ onDataPointClick = (selectedDataItem: any) => {
+ this.props.updateWidgetMetaProperty(
+ "selectedDataItem",
+ _.omit(selectedDataItem, "event"),
+ {
+ triggerPropertyName: "onDataPointClick",
+ dynamicString: this.props.onDataPointClick,
+ event: {
+ type: EventType.ON_DATA_POINT_CLICK,
+ },
+ },
+ );
+ };
+
+ getEchartInstance = (instance: any) => {
+ const params = {
+ name: "instance",
+ type: "custom",
+ id: instance.id,
+ };
+ this.props.updateWidgetMetaProperty("instance", params);
+ };
+
+ getPageView() {
+ // console.log(this.props.customEchartConfig, "echart");
+ return (
+ }>
+
+
+ );
+ }
+
+ static getWidgetType(): string {
+ return "ECHART_WIDGET";
+ }
+}
+
+export interface EchartWidgetProps extends WidgetProps {
+ chartType: ChartType;
+ chartData: AllChartData;
+ customEchartConfig: any;
+ xAxisName: string;
+ yAxisName: string;
+ chartName: string;
+ isVisible?: boolean;
+ allowScroll: boolean;
+ borderRadius: string;
+ boxShadow?: string;
+ accentColor?: string;
+ fontFamily?: string;
+ backgroundColor?: string;
+ onDataPointClick?: string;
+ registerMapName?: string;
+ registerMapJsonUrl?: string;
+}
+
+export default EchartWidget;
diff --git a/app/client/src/widgets/EchartWidget/widget/propertyConfig.ts b/app/client/src/widgets/EchartWidget/widget/propertyConfig.ts
new file mode 100644
index 0000000000..38b61379bf
--- /dev/null
+++ b/app/client/src/widgets/EchartWidget/widget/propertyConfig.ts
@@ -0,0 +1,695 @@
+// import { ChartWidgetProps } from "widgets/ChartWidget/widget";
+import { EchartWidgetProps } from "widgets/EchartWidget/widget";
+import { ValidationTypes } from "constants/WidgetValidation";
+import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
+// import { EditorModes } from "components/editorComponents/CodeEditor/EditorConfig";
+import {
+ // CUSTOM_CHART_TYPES,
+ LabelOrientation,
+ isLabelOrientationApplicableFor,
+} from "../constants";
+
+export default [
+ {
+ sectionName: "属性",
+ children: [
+ {
+ helpText: "给图表添加标题",
+ placeholderText: "Echart 标题",
+ propertyName: "chartName",
+ label: "标题",
+ controlType: "INPUT_TEXT",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.TEXT },
+ },
+ {
+ helpText: "修改图表数据展示形态",
+ propertyName: "chartType",
+ label: "图表类型",
+ controlType: "DROP_DOWN",
+ options: [
+ {
+ label: "折线图",
+ value: "LINE_CHART",
+ },
+ {
+ label: "柱状图",
+ value: "BAR_CHART",
+ },
+ {
+ label: "饼图",
+ value: "PIE_CHART",
+ },
+ {
+ label: "散点图",
+ value: "SCATTER_CHART",
+ },
+ {
+ label: "自定义图表",
+ value: "CUSTOM_CHART",
+ },
+ ],
+ isJSConvertible: true,
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: {
+ type: ValidationTypes.TEXT,
+ params: {
+ allowedValues: [
+ "LINE_CHART",
+ "BAR_CHART",
+ "PIE_CHART",
+ "SCATTER_CHART",
+ "CUSTOM_CHART",
+ ],
+ },
+ },
+ },
+ {
+ helpText: "完整配置请查阅 Echart 官方文档",
+ placeholderText: `Echart 图表配置`,
+ propertyName: "customEchartConfig",
+ label: "自定义 Echart 图表",
+ controlType: "INPUT_TEXT",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ // mode: EditorModes.JAVASCRIPT,
+ validation: {
+ type: ValidationTypes.OBJECT,
+ params: {
+ allowedKeys: [
+ {
+ type: ValidationTypes.ARRAY,
+ name: "series",
+ params: {
+ default: [] || {},
+ required: true,
+ },
+ },
+ ],
+ },
+ },
+ hidden: (props: EchartWidgetProps) =>
+ props.chartType !== "CUSTOM_CHART",
+ dependencies: ["chartType"],
+ evaluationSubstitutionType: EvaluationSubstitutionType.SMART_SUBSTITUTE,
+ },
+ {
+ helpText: "给图表添加数据",
+ propertyName: "chartData",
+ placeholderText: '[{ "name": "2021", "value": 94000 }]',
+ label: "图表序列",
+ controlType: "ECHART_DATA",
+ isBindProperty: false,
+ isTriggerProperty: false,
+ hidden: (props: EchartWidgetProps) =>
+ props.chartType === "CUSTOM_CHART",
+ dependencies: ["chartType"],
+ children: [
+ {
+ helpText: "Series data",
+ propertyName: "data",
+ label: "序列数据",
+ controlType: "INPUT_TEXT_AREA",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: {
+ type: ValidationTypes.ARRAY,
+ params: {
+ children: {
+ type: ValidationTypes.OBJECT,
+ params: {
+ required: true,
+ allowedKeys: [
+ {
+ name: "name",
+ type: ValidationTypes.TEXT,
+ params: {
+ required: true,
+ default: "",
+ },
+ },
+ {
+ name: "value",
+ type: ValidationTypes.NUMBER,
+ params: {
+ required: true,
+ default: 10,
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ evaluationSubstitutionType:
+ EvaluationSubstitutionType.SMART_SUBSTITUTE,
+ },
+ {
+ helpText: "Series Name",
+ propertyName: "seriesName",
+ label: "序列名称",
+ controlType: "INPUT_TEXT",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.TEXT },
+ },
+ ],
+ },
+ // {
+ // propertyName: "useDataSet",
+ // label: "使用数据集DataSet",
+ // helpText: "使用数据集设置图表数据",
+ // controlType: "SWITCH",
+ // isJSConvertible: true,
+ // isBindProperty: true,
+ // isTriggerProperty: false,
+ // validation: { type: ValidationTypes.BOOLEAN },
+ // },
+
+ {
+ propertyName: "isVisible",
+ label: "是否显示",
+ helpText: "控制组件的显示/隐藏",
+ controlType: "SWITCH",
+ isJSConvertible: true,
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.BOOLEAN },
+ },
+ {
+ propertyName: "animateLoading",
+ label: "加载时显示动画",
+ controlType: "SWITCH",
+ helpText: "组件依赖的数据加载时显示加载动画",
+ defaultValue: true,
+ isJSConvertible: true,
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.BOOLEAN },
+ },
+ {
+ helpText: "允许图表内部滚动",
+ propertyName: "allowScroll",
+ label: "允许滚动",
+ controlType: "SWITCH",
+ isBindProperty: false,
+ isTriggerProperty: false,
+ hidden: (x: EchartWidgetProps) =>
+ x.chartType === "CUSTOM_CHART" || x.chartType === "PIE_CHART",
+ dependencies: ["chartType"],
+ },
+ ],
+ },
+ {
+ sectionName: "坐标轴配置",
+ children: [
+ {
+ helpText: "设置x轴标签",
+ propertyName: "xAxisName",
+ placeholderText: "设置x轴标签",
+ label: "x轴标签",
+ controlType: "INPUT_TEXT",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.TEXT },
+ dependencies: ["chartType"],
+ },
+ {
+ helpText: "设置y轴标签",
+ propertyName: "yAxisName",
+ placeholderText: "设置y轴标签",
+ label: "y轴标签",
+ controlType: "INPUT_TEXT",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.TEXT },
+ dependencies: ["chartType"],
+ },
+ {
+ helpText: "修改x轴标签方向",
+ propertyName: "labelOrientation",
+ label: "x轴标签方向",
+ hidden: (x: EchartWidgetProps) =>
+ !isLabelOrientationApplicableFor(x.chartType),
+ isBindProperty: false,
+ isTriggerProperty: false,
+ dependencies: ["chartType"],
+ controlType: "DROP_DOWN",
+ options: [
+ {
+ label: "自动",
+ value: LabelOrientation.AUTO,
+ },
+ {
+ label: "倾斜",
+ value: LabelOrientation.SLANT,
+ },
+ {
+ label: "旋转",
+ value: LabelOrientation.ROTATE,
+ },
+ {
+ label: "交错",
+ value: LabelOrientation.STAGGER,
+ },
+ ],
+ },
+ {
+ propertyName: "setAdaptiveYMin",
+ label: "自适应坐标轴",
+ helpText: "定义坐标轴最小刻度",
+ controlType: "SWITCH",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.BOOLEAN },
+ },
+ ],
+ },
+ {
+ sectionName: "地图注册配置",
+ children: [
+ {
+ propertyName: "registerMapName",
+ label: "地图名称",
+ placeholderText: "地图名称",
+ helpText: "地图名称",
+ controlType: "INPUT_TEXT",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: {
+ type: ValidationTypes.TEXT,
+ params: {
+ regex: /\w+/,
+ },
+ },
+ // hidden: (x: any) => x.chartType !== "CUSTOM_CHART",
+ dependencies: ["chartType"],
+ },
+ {
+ helpText: "地图注册JSON数据",
+ propertyName: "registerMapJsonUrl",
+ label: "JSON链接",
+ controlType: "INPUT_TEXT",
+ placeholderText: "注册地图JSON数据链接",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ helpLink: "https://datav.aliyun.com/portal/school/atlas/area_selector",
+ validation: {
+ type: ValidationTypes.TEXT,
+ params: {
+ default: "",
+ required: false,
+ // regex: /(http(s?):)([/|.|\w|\s|-])*\.(?:json)/,
+ },
+ },
+ },
+ ],
+ },
+ {
+ sectionName: "事件",
+ children: [
+ {
+ helpText: "点击数据点时触发",
+ propertyName: "onDataPointClick",
+ label: "onDataPointClick",
+ controlType: "ACTION_SELECTOR",
+ isJSConvertible: true,
+ isBindProperty: true,
+ isTriggerProperty: true,
+ },
+ ],
+ },
+ {
+ sectionName: "样式",
+ children: [
+ {
+ propertyName: "borderRadius",
+ label: "边框圆角",
+ helpText: "边框圆角样式",
+ controlType: "BORDER_RADIUS_OPTIONS",
+ isJSConvertible: true,
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.TEXT },
+ },
+ {
+ propertyName: "boxShadow",
+ label: "阴影",
+ helpText: "组件轮廓投影",
+ controlType: "BOX_SHADOW_OPTIONS",
+ isJSConvertible: true,
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.TEXT },
+ },
+ {
+ propertyName: "backgroundColor",
+ helpText: "设置菜单项背景颜色",
+ label: "背景颜色",
+ controlType: "COLOR_PICKER",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ },
+ ],
+ },
+];
+
+export const contentConfig = [
+ {
+ sectionName: "数据",
+ children: [
+ {
+ helpText: "修改图表数据展示形态",
+ propertyName: "chartType",
+ label: "图表类型",
+ controlType: "DROP_DOWN",
+ options: [
+ {
+ label: "折线图",
+ value: "LINE_CHART",
+ },
+ {
+ label: "柱状图",
+ value: "BAR_CHART",
+ },
+ {
+ label: "饼图",
+ value: "PIE_CHART",
+ },
+ {
+ label: "散点图",
+ value: "SCATTER_CHART",
+ },
+ {
+ label: "自定义图表",
+ value: "CUSTOM_CHART",
+ },
+ ],
+ isJSConvertible: true,
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: {
+ type: ValidationTypes.TEXT,
+ params: {
+ allowedValues: [
+ "LINE_CHART",
+ "BAR_CHART",
+ "PIE_CHART",
+ "SCATTER_CHART",
+ "CUSTOM_CHART",
+ ],
+ },
+ },
+ },
+ {
+ helpText: "完整配置请查阅 Echart 官方文档",
+ placeholderText: `Echart 图表配置`,
+ propertyName: "customEchartConfig",
+ label: "自定义 Echart 图表",
+ controlType: "INPUT_TEXT",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: {
+ type: ValidationTypes.OBJECT,
+ params: {
+ allowedKeys: [
+ {
+ type: ValidationTypes.ARRAY,
+ name: "series",
+ params: {
+ default: [] || {},
+ required: true,
+ },
+ },
+ ],
+ },
+ },
+ hidden: (props: EchartWidgetProps) =>
+ props.chartType !== "CUSTOM_CHART",
+ dependencies: ["chartType"],
+ // mode: EditorModes.JAVASCRIPT,
+ evaluationSubstitutionType: EvaluationSubstitutionType.SMART_SUBSTITUTE,
+ },
+ {
+ helpText: "给图表添加数据",
+ propertyName: "chartData",
+ placeholderText: '[{ "name": "2021", "value": 94000 }]',
+ label: "图表序列",
+ controlType: "ECHART_DATA",
+ isBindProperty: false,
+ isTriggerProperty: false,
+ hidden: (props: EchartWidgetProps) =>
+ props.chartType === "CUSTOM_CHART",
+ dependencies: ["chartType"],
+ children: [
+ {
+ helpText: "Series data",
+ propertyName: "data",
+ label: "序列数据",
+ controlType: "INPUT_TEXT_AREA",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: {
+ type: ValidationTypes.ARRAY,
+ params: {
+ children: {
+ type: ValidationTypes.OBJECT,
+ params: {
+ required: true,
+ allowedKeys: [
+ {
+ name: "name",
+ type: ValidationTypes.TEXT,
+ params: {
+ required: true,
+ default: "",
+ },
+ },
+ {
+ name: "value",
+ type: ValidationTypes.NUMBER,
+ params: {
+ required: true,
+ default: 10,
+ },
+ },
+ ],
+ },
+ },
+ },
+ },
+ evaluationSubstitutionType:
+ EvaluationSubstitutionType.SMART_SUBSTITUTE,
+ },
+ ],
+ },
+ ],
+ },
+
+ {
+ sectionName: "属性",
+ children: [
+ {
+ helpText: "给图表添加标题",
+ placeholderText: "Echart 标题",
+ propertyName: "chartName",
+ label: "标题",
+ controlType: "INPUT_TEXT",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.TEXT },
+ },
+ {
+ propertyName: "isVisible",
+ label: "是否显示",
+ helpText: "控制组件的显示/隐藏",
+ controlType: "SWITCH",
+ isJSConvertible: true,
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.BOOLEAN },
+ },
+ {
+ propertyName: "animateLoading",
+ label: "加载时显示动画",
+ controlType: "SWITCH",
+ helpText: "组件依赖的数据加载时显示加载动画",
+ defaultValue: true,
+ isJSConvertible: true,
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.BOOLEAN },
+ },
+ {
+ helpText: "允许图表内部滚动",
+ propertyName: "allowScroll",
+ label: "允许滚动",
+ controlType: "SWITCH",
+ isBindProperty: false,
+ isTriggerProperty: false,
+ hidden: (x: EchartWidgetProps) =>
+ x.chartType === "CUSTOM_CHART" || x.chartType === "PIE_CHART",
+ dependencies: ["chartType"],
+ },
+ ],
+ },
+ {
+ sectionName: "坐标轴配置",
+ children: [
+ {
+ propertyName: "setAdaptiveYMin",
+ label: "自适应坐标轴",
+ helpText: "定义坐标轴最小刻度",
+ controlType: "SWITCH",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.BOOLEAN },
+ },
+ {
+ helpText: "设置x轴标签",
+ propertyName: "xAxisName",
+ placeholderText: "日期",
+ label: "x轴标签",
+ controlType: "INPUT_TEXT",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.TEXT },
+ hidden: (x: any) => x.chartType === "CUSTOM_CHART",
+ dependencies: ["chartType"],
+ },
+ {
+ helpText: "设置y轴标签",
+ propertyName: "yAxisName",
+ placeholderText: "收入",
+ label: "y轴标签",
+ controlType: "INPUT_TEXT",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.TEXT },
+ hidden: (x: any) => x.chartType === "CUSTOM_CHART",
+ dependencies: ["chartType"],
+ },
+ // {
+ // helpText: "修改x轴标签方向",
+ // propertyName: "labelOrientation",
+ // label: "x轴标签方向",
+ // hidden: (x: EchartWidgetProps) =>
+ // !isLabelOrientationApplicableFor(x.chartType),
+ // isBindProperty: false,
+ // isTriggerProperty: false,
+ // dependencies: ["chartType"],
+ // controlType: "DROP_DOWN",
+ // options: [
+ // {
+ // label: "自动",
+ // value: LabelOrientation.AUTO,
+ // },
+ // {
+ // label: "倾斜",
+ // value: LabelOrientation.SLANT,
+ // },
+ // {
+ // label: "旋转",
+ // value: LabelOrientation.ROTATE,
+ // },
+ // {
+ // label: "交错",
+ // value: LabelOrientation.STAGGER,
+ // },
+ // ],
+ // },
+ ],
+ },
+ {
+ sectionName: "地图注册配置",
+ children: [
+ {
+ propertyName: "registerMapName",
+ label: "地图名称",
+ helpText: "地图名称",
+ placeholderText: "地图名称",
+ controlType: "INPUT_TEXT",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: {
+ type: ValidationTypes.TEXT,
+ params: {
+ regex: /\w+/,
+ },
+ },
+ // hidden: (x: any) => x.chartType === "CUSTOM_CHART",
+ dependencies: ["chartType"],
+ },
+ {
+ helpText: "地图注册JSON数据",
+ propertyName: "registerMapJsonUrl",
+ label: "JSON链接",
+ controlType: "INPUT_TEXT",
+ placeholderText: "注册地图JSON数据链接",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ helpLink: "https://datav.aliyun.com/portal/school/atlas/area_selector",
+ validation: {
+ type: ValidationTypes.TEXT,
+ params: {
+ default: "",
+ required: false,
+ // regex: /(http(s?):)([/|.|\w|\s|-])*\.(?:json)/,
+ },
+ },
+ },
+ ],
+ },
+ {
+ sectionName: "事件",
+ children: [
+ {
+ helpText: "点击数据点时触发",
+ propertyName: "onDataPointClick",
+ label: "onDataPointClick",
+ controlType: "ACTION_SELECTOR",
+ isJSConvertible: true,
+ isBindProperty: true,
+ isTriggerProperty: true,
+ },
+ ],
+ },
+];
+
+export const styleConfig = [
+ {
+ sectionName: "轮廓样式",
+ children: [
+ {
+ propertyName: "borderRadius",
+ label: "边框圆角",
+ helpText: "边框圆角样式",
+ controlType: "BORDER_RADIUS_OPTIONS",
+ isJSConvertible: true,
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.TEXT },
+ },
+ {
+ propertyName: "boxShadow",
+ label: "阴影",
+ helpText: "组件轮廓投影",
+ controlType: "BOX_SHADOW_OPTIONS",
+ isJSConvertible: true,
+ isBindProperty: true,
+ isTriggerProperty: false,
+ validation: { type: ValidationTypes.TEXT },
+ },
+ {
+ propertyName: "backgroundColor",
+ helpText: "设置菜单项背景颜色",
+ label: "背景颜色",
+ controlType: "COLOR_PICKER",
+ isBindProperty: true,
+ isTriggerProperty: false,
+ },
+ ],
+ },
+];
diff --git a/app/client/src/widgets/ListWidget/index.ts b/app/client/src/widgets/ListWidget/index.ts
index 0f9314a084..71dda1a706 100644
--- a/app/client/src/widgets/ListWidget/index.ts
+++ b/app/client/src/widgets/ListWidget/index.ts
@@ -334,6 +334,7 @@ export const CONFIG = {
"BUTTON_GROUP_WIDGET",
"BUTTON_WIDGET",
"CHART_WIDGET",
+ "ECHART_WIDGET",
"CHECKBOX_WIDGET",
"CHECKBOX_GROUP_WIDGET",
"DIVIDER_WIDGET",
diff --git a/app/client/src/workers/Evaluation/Actions.ts b/app/client/src/workers/Evaluation/Actions.ts
index 66d1730766..cf8f996089 100644
--- a/app/client/src/workers/Evaluation/Actions.ts
+++ b/app/client/src/workers/Evaluation/Actions.ts
@@ -81,6 +81,22 @@ export const DATA_TREE_FUNCTIONS: Record<
executionType: ExecutionType.PROMISE,
};
},
+ callFunc: {
+ qualifier: (entity) => isAppsmithEntity(entity),
+ path: "appsmith.echartInstance.callFunc",
+ func: () =>
+ function(widgetName: string, funcName: string, options?: any) {
+ return {
+ type: ActionTriggerType.CALL_FUNC,
+ payload: {
+ widgetName,
+ funcName,
+ options,
+ },
+ executionType: ExecutionType.PROMISE,
+ };
+ },
+ },
storeValue: function(key: string, value: string, persist = true) {
// momentarily store this value in local state to support loops
_.set(self, ["appsmith", "store", key], value);
diff --git a/app/client/start-https.sh b/app/client/start-https.sh
index 7ea68242f1..2b7af86473 100755
--- a/app/client/start-https.sh
+++ b/app/client/start-https.sh
@@ -257,6 +257,7 @@ $(if [[ $use_https == 1 ]]; then echo "
sub_filter __APPSMITH_DISABLE_INTERCOM__ '${APPSMITH_DISABLE_INTERCOM-}';
sub_filter __APPSMITH_FORM_LOGIN_DISABLED__ '${APPSMITH_FORM_LOGIN_DISABLED-}';
sub_filter __APPSMITH_SIGNUP_DISABLED__ '${APPSMITH_SIGNUP_DISABLED-}';
+ sub_filter __BMAP_AK__ '${BMAP_AK-}';
sub_filter __APPSMITH_ZIPY_SDK_KEY__ '${APPSMITH_ZIPY_SDK_KEY-}';
sub_filter __APPSMITH_HIDE_WATERMARK__ '${APPSMITH_HIDE_WATERMARK-}';
sub_filter __APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX__ '${APPSMITH_DISABLE_IFRAME_WIDGET_SANDBOX-}';
diff --git a/app/client/test/factories/Widgets/EchartFactory.ts b/app/client/test/factories/Widgets/EchartFactory.ts
new file mode 100644
index 0000000000..1e5951bd45
--- /dev/null
+++ b/app/client/test/factories/Widgets/EchartFactory.ts
@@ -0,0 +1,61 @@
+import * as Factory from "factory.ts";
+import { generateReactKey } from "utils/generators";
+import { WidgetProps } from "widgets/BaseWidget";
+
+export const EchartFactory = Factory.Sync.makeFactory({
+ isVisible: true,
+ chartType: "LINE_CHART",
+ chartName: "Sales on working days",
+ allowScroll: false,
+ chartData: [
+ {
+ seriesName: "Sales",
+ data: [
+ {
+ x: "Mon",
+ y: 10000,
+ },
+ {
+ x: "Tue",
+ y: 12000,
+ },
+ {
+ x: "Wed",
+ y: 32000,
+ },
+ {
+ x: "Thu",
+ y: 28000,
+ },
+ {
+ x: "Fri",
+ y: 14000,
+ },
+ {
+ x: "Sat",
+ y: 19000,
+ },
+ {
+ x: "Sun",
+ y: 36000,
+ },
+ ],
+ },
+ ],
+ xAxisName: "Last Week",
+ yAxisName: "Total Order Revenue $",
+ type: "ECHART_WIDGET",
+ isLoading: false,
+ parentColumnSpace: 71.75,
+ parentRowSpace: 38,
+ leftColumn: 2,
+ rightColumn: 8,
+ topRow: 1,
+ bottomRow: 9,
+ parentId: "rglduihhzk",
+ dynamicBindingPathList: [],
+ widgetName: Factory.each((i) => `Echart${i + 1}`),
+ widgetId: generateReactKey(),
+ renderMode: "CANVAS",
+ version: 1,
+});
diff --git a/app/client/test/factories/Widgets/WidgetTypeFactories.ts b/app/client/test/factories/Widgets/WidgetTypeFactories.ts
index 57620c73d2..944df71cc3 100644
--- a/app/client/test/factories/Widgets/WidgetTypeFactories.ts
+++ b/app/client/test/factories/Widgets/WidgetTypeFactories.ts
@@ -13,6 +13,7 @@ import { OldTabsFactory, TabsFactory } from "./TabsFactory";
import { ModalFactory } from "./ModalFactory";
import { RichTextFactory } from "./RichTextFactory";
import { ChartFactory } from "./ChartFactory";
+import { EchartFactory } from "./EchartFactory";
import { FormFactory } from "./FormFactory";
import { FormButtonFactory } from "./FormButtonFactory";
import { MapFactory } from "./MapFactory";
@@ -42,6 +43,7 @@ export const WidgetTypeFactories: Record = {
MODAL_WIDGET: ModalFactory,
RICH_TEXT_EDITOR_WIDGET: RichTextFactory,
CHART_WIDGET: ChartFactory,
+ ECHART_WIDGET: EchartFactory,
FORM_WIDGET: FormFactory,
FORM_BUTTON_WIDGET: FormButtonFactory,
MAP_WIDGET: MapFactory,
diff --git a/app/server/.env b/app/server/.env
index 7d8152fb1c..c498d4e8d0 100644
--- a/app/server/.env
+++ b/app/server/.env
@@ -34,3 +34,4 @@ APPSMITH_CODEC_SIZE=10
#APPSMITH_RECAPTCHA_SITE_KEY=""
#APPSMITH_RECAPTCHA_SECRET_KEY=""
+BMAP_AK="nWCpSjRnXLfGuBc3iLZ9kYv8Y6wYaxf8"
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Application.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Application.java
index c61ba5e761..821544ae77 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Application.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/domains/Application.java
@@ -69,6 +69,8 @@ public class Application extends BaseDomain {
String icon;
+ String chartTheme;
+
private String slug;
AppLayout unpublishedAppLayout;
@@ -163,6 +165,7 @@ public class Application extends BaseDomain {
this.clonedFromApplicationId = application.getId();
this.color = application.getColor();
this.icon = application.getIcon();
+ this.chartTheme = application.getChartTheme();
this.unpublishedAppLayout = application.getUnpublishedAppLayout() == null ? null : new AppLayout(application.getUnpublishedAppLayout().type);
this.publishedAppLayout = application.getPublishedAppLayout() == null ? null : new AppLayout(application.getPublishedAppLayout().type);
this.viewerLayout = application.getViewerLayout();
diff --git a/app/server/envs/dev.env.example b/app/server/envs/dev.env.example
index dcacecc8fa..88d00ceebe 100644
--- a/app/server/envs/dev.env.example
+++ b/app/server/envs/dev.env.example
@@ -37,3 +37,4 @@ APPSMITH_CLOUD_SERVICES_BASE_URL="https://release-cs.appsmith.com"
#APPSMITH_RECAPTCHA_SITE_KEY=""
#APPSMITH_RECAPTCHA_SECRET_KEY=""
+BMAP_AK="nWCpSjRnXLfGuBc3iLZ9kYv8Y6wYaxf8"
\ No newline at end of file
diff --git a/deploy/template/nginx_app.conf.sh b/deploy/template/nginx_app.conf.sh
index a9014ceea4..b24c9237fc 100644
--- a/deploy/template/nginx_app.conf.sh
+++ b/deploy/template/nginx_app.conf.sh
@@ -59,6 +59,7 @@ $NGINX_SSL_CMNT server_name $custom_domain ;
sub_filter __APPSMITH_DISABLE_INTERCOM__ '\${APPSMITH_DISABLE_INTERCOM}';
sub_filter __APPSMITH_FORM_LOGIN_DISABLED__ '\${APPSMITH_FORM_LOGIN_DISABLED}';
sub_filter __APPSMITH_SIGNUP_DISABLED__ '\${APPSMITH_SIGNUP_DISABLED}';
+ sub_filter __BMAP_AK__ '\${BMAP_AK}';
}