feat: echarts
This commit is contained in:
parent
f35e575d00
commit
47669c0d9f
|
|
@ -68,3 +68,6 @@ APPSMITH_RECAPTCHA_ENABLED=
|
|||
|
||||
# Intercom
|
||||
APPSMITH_DISABLE_INTERCOM=
|
||||
|
||||
# baidu map
|
||||
BMAP_AK=
|
||||
|
|
|
|||
|
|
@ -34,3 +34,4 @@ app/client/yalc.lock
|
|||
.idea
|
||||
.fleet/*
|
||||
app/client/.fleet/*
|
||||
*debug.log
|
||||
|
|
|
|||
14
README.md
14
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 前需要
|
||||
|
|
|
|||
|
|
@ -19,12 +19,14 @@
|
|||
transition: all ease-in 0.3s;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
if ("%REACT_APP_IN_CLOUDOS%".trim() === "true") {
|
||||
document.querySelector(':root').style.setProperty("--loader-bar-color", "#613eea");
|
||||
document.title = "Methodot";
|
||||
}
|
||||
</script>
|
||||
<script src="/logger.js"></script>
|
||||
<script>
|
||||
// '' (empty strings), 'false' are falsy
|
||||
// could return either boolean or string based on value
|
||||
|
|
@ -55,7 +57,20 @@
|
|||
head && head.appendChild(script);
|
||||
}
|
||||
</script>
|
||||
<script src="/logger.js"></script>
|
||||
<script>
|
||||
const BMAP_AK = parseConfig("__BMAP_AK__");
|
||||
const script = document.createElement('script');
|
||||
script.type = "text/javascript"
|
||||
script.src = `https://api.map.baidu.com/api?v=3.0&ak=${BMAP_AK}`;
|
||||
const head = document.getElementsByTagName('head')[0];
|
||||
head && head.appendChild(script);
|
||||
script.onload = () => {
|
||||
const script1 = document.createElement('script');
|
||||
script1.src = `https://api.map.baidu.com/getscript?v=3.0&ak=${BMAP_AK}&services=&t=${(new Date()).getTime()}`
|
||||
script1.type = "text/javascript"
|
||||
head && head.appendChild(script1);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="appsmith-light-theme">
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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 = () => `你好,我想升级`;
|
||||
|
|
|
|||
|
|
@ -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 }>,
|
||||
|
|
|
|||
|
|
@ -86,6 +86,12 @@ export const WIDGET_DATA_FIELD_MAP: Record<string, WidgetBindingInfo> = {
|
|||
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,
|
||||
|
|
|
|||
|
|
@ -677,6 +677,7 @@ class CodeEditor extends Component<Props, State> {
|
|||
});
|
||||
}
|
||||
const inputValue = this.props.input.value || "";
|
||||
// console.log(inputValue, "handleChange");
|
||||
if (
|
||||
this.props.input.onChange &&
|
||||
((value !== inputValue && this.state.isFocused) ||
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<StyledOptionControlWrapper orientation={"VERTICAL"}>
|
||||
{!noTitle ? (
|
||||
<>
|
||||
<ActionHolder>
|
||||
<StyledLabel>{label?.titleLabel}</StyledLabel>
|
||||
{length > 1 && (
|
||||
<StyledDeleteIcon
|
||||
height={20}
|
||||
onClick={() => {
|
||||
deleteOption(index);
|
||||
}}
|
||||
width={20}
|
||||
/>
|
||||
)}
|
||||
</ActionHolder>
|
||||
<StyledOptionControlWrapper orientation={"HORIZONTAL"}>
|
||||
<CodeEditor
|
||||
dataTreePath={`${dataTreePath}.seriesName`}
|
||||
evaluatedValue={evaluated?.seriesName}
|
||||
expected={expectedSeriesName}
|
||||
input={{
|
||||
value: item.seriesName,
|
||||
onChange: (
|
||||
event: React.ChangeEvent<HTMLTextAreaElement> | 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}
|
||||
/>
|
||||
</StyledOptionControlWrapper>
|
||||
</>
|
||||
) : null}
|
||||
<StyledLabel>{label?.areaLabel}</StyledLabel>
|
||||
<StyledDynamicInput
|
||||
className={"t--property-control-chart-series-data-control"}
|
||||
>
|
||||
<CodeEditor
|
||||
dataTreePath={`${dataTreePath}.data`}
|
||||
evaluatedValue={evaluated?.data}
|
||||
expected={expectedSeriesData}
|
||||
input={{
|
||||
value: item.data,
|
||||
onChange: (
|
||||
event: React.ChangeEvent<HTMLTextAreaElement> | 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}
|
||||
/>
|
||||
</StyledDynamicInput>
|
||||
<Box />
|
||||
</StyledOptionControlWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
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<ControlProps> {
|
||||
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 (
|
||||
<DataControlComponent
|
||||
noTitle={isDataSet}
|
||||
dataTreePath={`${this.props.dataTreePath}.${firstKey}`}
|
||||
deleteOption={this.deleteOption}
|
||||
evaluated={get(evaluatedValue, `${firstKey}`)}
|
||||
index={firstKey}
|
||||
item={data}
|
||||
length={1}
|
||||
theme={this.props.theme}
|
||||
updateOption={this.updateOption}
|
||||
label={ControlLabel(this.props.propertyName)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Wrapper>
|
||||
{Object.keys(chartData).map((key: string) => {
|
||||
const data = get(chartData, `${key}`);
|
||||
return (
|
||||
<DataControlComponent
|
||||
noTitle={isDataSet}
|
||||
dataTreePath={`${this.props.dataTreePath}.${key}`}
|
||||
deleteOption={this.deleteOption}
|
||||
evaluated={get(evaluatedValue, `${key}`)}
|
||||
index={key}
|
||||
item={data}
|
||||
key={key}
|
||||
length={dataLength}
|
||||
theme={this.props.theme}
|
||||
updateOption={this.updateOption}
|
||||
label={ControlLabel(this.props.propertyName)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Wrapper>
|
||||
|
||||
{/* 新增按钮 */}
|
||||
{ControlLabel(this.props.propertyName).hasAddBtn ? (
|
||||
<StyledPropertyPaneButton
|
||||
category={Category.tertiary}
|
||||
icon="plus"
|
||||
onClick={this.addOption}
|
||||
size={Size.medium}
|
||||
tag="button"
|
||||
text={ControlLabel(this.props.propertyName).btnLabel}
|
||||
type="button"
|
||||
/>
|
||||
) : 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;
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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: [],
|
||||
},
|
||||
};
|
||||
|
|
@ -275,6 +275,10 @@ export const HelpMap: Record<string, { path: string; searchKey: string }> = {
|
|||
path: "/widget-reference/map-chart",
|
||||
searchKey: "Map Chart",
|
||||
},
|
||||
ECHART_WIDGET: {
|
||||
path: "/widget-reference/chart",
|
||||
searchKey: "Echart",
|
||||
},
|
||||
};
|
||||
|
||||
export const HelpBaseURL = "https://docs.appsmith.com";
|
||||
|
|
|
|||
|
|
@ -70,3 +70,10 @@ export type AppTheme = {
|
|||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type EchartTheme = {
|
||||
themeKey: string;
|
||||
backgroundColor?: string;
|
||||
color?: string[];
|
||||
[key: string]: any;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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<ActionTriggerType, string> = {
|
||||
|
|
@ -35,6 +36,7 @@ export const ActionTriggerFunctionNames: Record<ActionTriggerType, string> = {
|
|||
[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
|
||||
|
|
|
|||
|
|
@ -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 && <ThemeEditor />}
|
||||
<EchartThemeEditor />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ export const initialState: any = {
|
|||
currentApplication: {
|
||||
lastDeployedAt: null,
|
||||
slug: "applicationSlug",
|
||||
chartTheme: "default",
|
||||
},
|
||||
},
|
||||
onBoarding: {
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<>
|
||||
<div>
|
||||
<header className="px-3 space-y-2">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-2">
|
||||
<h3 className="text-sm font-normal capitalize">Echart主题配置</h3>
|
||||
<BetaCard />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ThemeCard theme={selectedEchartTheme}>
|
||||
<aside
|
||||
className={`absolute left-0 top-0 bottom-0 right-0 items-center justify-center hidden group-hover:flex backdrop-filter bg-gray-900 bg-opacity-50 backdrop-blur-sm `}
|
||||
>
|
||||
<Button
|
||||
category={Category.primary}
|
||||
className="t--change-theme-btn"
|
||||
onClick={onClickChangeThemeButton}
|
||||
size={Size.medium}
|
||||
text="选择Echart主题"
|
||||
/>
|
||||
</aside>
|
||||
</ThemeCard>
|
||||
</header>
|
||||
</div>
|
||||
<SaveThemeModal isOpen={isSaveModalOpen} onClose={onCloseSaveModal} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default EchartThemeEditor;
|
||||
|
|
@ -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 (
|
||||
<div className="relative">
|
||||
<section className="sticky top-0 items-center justify-between bg-white z-1 ">
|
||||
<button
|
||||
className="inline-flex items-center px-3 py-2 space-x-1 text-gray-500 cursor-pointer t--theme-select-back-btn"
|
||||
onClick={onClickBack}
|
||||
type="button"
|
||||
>
|
||||
<ArrowLeft className="w-4 h-4 transition-all transform" />
|
||||
<h3 className="text-xs font-medium uppercase">返回</h3>
|
||||
</button>
|
||||
<SettingSection
|
||||
className="px-3 py-3 border-t border-b"
|
||||
isDefaultOpen={false}
|
||||
title="当前Echart主题"
|
||||
>
|
||||
<ThemeCard theme={currentTheme} />
|
||||
</SettingSection>
|
||||
</section>
|
||||
{_.size(userSavedThemes) > 0 && (
|
||||
<section className="relative px-3 py-3 space-y-3">
|
||||
<h3 className="text-base font-medium capitalize">你的Echart主题</h3>
|
||||
{_.map(userSavedThemes, (theme) => (
|
||||
<ThemeCard selectable theme={theme} />
|
||||
))}
|
||||
</section>
|
||||
)}
|
||||
<section className="relative px-3 py-3 space-y-3">
|
||||
<h3 className="text-base font-medium capitalize">特色Echart主题</h3>
|
||||
{_.map(systemThemes, (theme: any) => (
|
||||
<ThemeCard selectable theme={theme} />
|
||||
))}
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EchartThemeSelector;
|
||||
|
|
@ -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 (
|
||||
<div className="space-y-1 group">
|
||||
{selectable && (
|
||||
<div className="flex items-center justify-between">
|
||||
<h3 className="text-sm text-gray-600 break-all">
|
||||
{props.theme.displayName}
|
||||
</h3>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={classNames({
|
||||
"border relative group transition-all t--theme-card": true,
|
||||
"overflow-hidden": !selectable,
|
||||
"hover:shadow-xl cursor-pointer": selectable,
|
||||
})}
|
||||
onClick={changeSelectedTheme}
|
||||
>
|
||||
<MainWrap backgroundColor={backgroundColor}>
|
||||
<section className="flex justify-between px-3 pt-3">
|
||||
<MainText
|
||||
backgroundColor={
|
||||
TRANSPARENT_BG.includes(backgroundColor || "")
|
||||
? "white"
|
||||
: backgroundColor
|
||||
}
|
||||
className="text-base"
|
||||
>
|
||||
{theme.themeKey}
|
||||
</MainText>
|
||||
<div className="flex items-center space-x-2">
|
||||
{userDefinedColors.map((colorKey: any, index: number) => (
|
||||
<ThemeColorCircle
|
||||
backgroundColor={colorKey}
|
||||
className="w-4 h-4 border rounded-full"
|
||||
key={index}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
<section className="p-2">
|
||||
<div className="flex space-x-2" />
|
||||
</section>
|
||||
</MainWrap>
|
||||
<aside
|
||||
className={`absolute bottom-0 left-0 right-0 items-center justify-center hidden bg-gray-900/80 ${
|
||||
selectable ? "group-hover:flex" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="py-1 text-xs tracking-wide text-white uppercase">
|
||||
使用这个主题
|
||||
</div>
|
||||
</aside>
|
||||
{props.children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ThemeCard.displayName = "ThemeCard";
|
||||
|
||||
export default Sentry.withProfiler(ThemeCard);
|
||||
|
|
@ -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: [],
|
||||
},
|
||||
};
|
||||
|
|
@ -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 <ThemeEditor />;
|
||||
case themingMode === AppThemingMode.APP_THEME_SELECTION:
|
||||
return <ThemeSelector />;
|
||||
case themingMode === AppThemingMode.ECHART_THEME_SELECTION:
|
||||
return <EchartThemeSelector />;
|
||||
default:
|
||||
return <ThemeEditor />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ export type AppDataState = {
|
|||
canBeRequested: boolean;
|
||||
currentPosition?: Partial<GeolocationPosition>;
|
||||
};
|
||||
echartInstance: any;
|
||||
};
|
||||
|
||||
const initialState: AppDataState = {
|
||||
|
|
@ -67,6 +68,7 @@ const initialState: AppDataState = {
|
|||
canBeRequested: "geolocation" in navigator,
|
||||
currentPosition: {},
|
||||
},
|
||||
echartInstance: {},
|
||||
};
|
||||
|
||||
const appReducer = createReducer(initialState, {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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"],
|
||||
|
|
|
|||
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<any> {
|
||||
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);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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],
|
||||
|
|
|
|||
|
|
@ -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.<i>.: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",
|
||||
|
|
|
|||
|
|
@ -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") &&
|
||||
|
|
|
|||
|
|
@ -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<any>();
|
||||
const echartInstance = useRef<any>();
|
||||
const selectedEchartTheme = useSelector(getSelectedEchartTheme);
|
||||
const objectRef = useRef<any>();
|
||||
const [preChartTheme, setCurrentChart] = useState<EchartTheme | null>();
|
||||
|
||||
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 (
|
||||
<div
|
||||
className={`w-full h-full overflow-hidden relative ${
|
||||
_.includes(DARK_THEMES, selectedEchartTheme.themeKey)
|
||||
? "bg-transparent"
|
||||
: "bg-white"
|
||||
}`}
|
||||
style={style}
|
||||
>
|
||||
<div id={chartContainerId} ref={echartRef} className="h-full w-full" />
|
||||
{/* 监听组件大小 */}
|
||||
<object
|
||||
ref={objectRef}
|
||||
tabIndex={-1}
|
||||
type="text/html"
|
||||
aria-hidden="true"
|
||||
data="about:blank"
|
||||
className="absolute block top-0 left-0 w-full h-full border-0 opacity-0 z-[-1000] pointer-events-none"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -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: [],
|
||||
};
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<svg width="200" height="200" viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<ellipse cx="100" cy="99.9414" rx="96.5651" ry="96.5075" transform="rotate(-0.2588 100 99.9414)" fill="#4b4848" />
|
||||
<path
|
||||
d="M83.506 43C94.8782 43 104.885 49.2273 114.334 56.7415C132.077 70.8503 137.701 97.0118 127.501 118.08C126.498 120.15 126.514 119.704 125.586 121.803C122.995 127.658 124.89 133.591 130.229 136.685C132.011 137.718 133.953 138.215 135.874 138.215C139.357 138.215 142.775 136.58 145.057 133.537C148.82 128.52 148.171 122.48 143.298 118.08C142.117 117.013 140.698 116.207 138.788 114.857C141.224 113.608 143.585 113.013 145.733 113.013C150.48 113.013 154.184 115.92 155.334 121.104C156.093 124.528 157.024 126.618 160.713 128.043C168.408 131.016 169.893 143.664 165.715 145.462C165.665 145.484 165.612 145.494 165.558 145.494C165.024 145.494 164.315 144.521 163.995 143.849C161.269 138.14 157.497 135.162 153.184 135.162C150.324 135.162 147.225 136.472 144.039 139.165C133.964 147.679 122.932 153.92 109.71 156.066C105.835 156.695 102.005 157 98.2425 157C65.9789 157 38.8531 134.554 33.6656 101.604C30.3265 80.397 39.7375 60.1715 57.7121 49.9243C65.8455 45.2876 74.707 42.9996 83.506 43ZM135.093 128.38C134.468 128.017 133.612 127.521 134.429 125.676C134.647 125.183 134.921 124.646 135.223 124.079C135.88 124.518 136.55 124.967 136.805 125.197C138.267 126.518 137.867 127.051 137.314 127.788C136.782 128.498 136.183 128.625 135.874 128.604C135.671 128.589 135.353 128.53 135.093 128.38Z"
|
||||
fill="#ffffff" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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<EchartWidgetProps, WidgetState> {
|
||||
static getPropertyPaneConfig() {
|
||||
return propertyConfig;
|
||||
}
|
||||
|
||||
static getDerivedPropertiesMap(): DerivedPropertiesMap {
|
||||
return {};
|
||||
}
|
||||
|
||||
static getDefaultPropertiesMap(): Record<string, string> {
|
||||
return {};
|
||||
}
|
||||
|
||||
static getPropertyPaneContentConfig() {
|
||||
return contentConfig;
|
||||
}
|
||||
|
||||
static getPropertyPaneStyleConfig() {
|
||||
return styleConfig;
|
||||
}
|
||||
|
||||
static getMetaPropertiesMap(): Record<string, any> {
|
||||
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 (
|
||||
<Suspense fallback={<Skeleton />}>
|
||||
<EchartComponent
|
||||
allowScroll={this.props.allowScroll}
|
||||
borderRadius={this.props.borderRadius}
|
||||
boxShadow={this.props.boxShadow}
|
||||
chartData={this.props.chartData}
|
||||
chartName={this.props.chartName}
|
||||
chartType={this.props.chartType}
|
||||
customEchartConfig={this.props.customEchartConfig}
|
||||
fontFamily={this.props.fontFamily ?? "Nunito Sans"}
|
||||
isLoading={this.props.isLoading}
|
||||
isVisible={this.props.isVisible}
|
||||
key={this.props.widgetId}
|
||||
labelOrientation={this.props.labelOrientation}
|
||||
primaryColor={this.props.accentColor ?? Colors.ROYAL_BLUE_2}
|
||||
backgroundColor={this.props.backgroundColor}
|
||||
setAdaptiveYMin={this.props.setAdaptiveYMin}
|
||||
widgetId={this.props.widgetId}
|
||||
xAxisName={this.props.xAxisName}
|
||||
yAxisName={this.props.yAxisName}
|
||||
onDataPointClick={this.onDataPointClick}
|
||||
onInstance={this.getEchartInstance}
|
||||
registerMapName={this.props.registerMapName}
|
||||
registerMapJsonUrl={this.props.registerMapJsonUrl}
|
||||
/>
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -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,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
@ -334,6 +334,7 @@ export const CONFIG = {
|
|||
"BUTTON_GROUP_WIDGET",
|
||||
"BUTTON_WIDGET",
|
||||
"CHART_WIDGET",
|
||||
"ECHART_WIDGET",
|
||||
"CHECKBOX_WIDGET",
|
||||
"CHECKBOX_GROUP_WIDGET",
|
||||
"DIVIDER_WIDGET",
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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-}';
|
||||
|
|
|
|||
|
|
@ -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<WidgetProps>({
|
||||
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,
|
||||
});
|
||||
|
|
@ -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<string, any> = {
|
|||
MODAL_WIDGET: ModalFactory,
|
||||
RICH_TEXT_EDITOR_WIDGET: RichTextFactory,
|
||||
CHART_WIDGET: ChartFactory,
|
||||
ECHART_WIDGET: EchartFactory,
|
||||
FORM_WIDGET: FormFactory,
|
||||
FORM_BUTTON_WIDGET: FormButtonFactory,
|
||||
MAP_WIDGET: MapFactory,
|
||||
|
|
|
|||
|
|
@ -34,3 +34,4 @@ APPSMITH_CODEC_SIZE=10
|
|||
|
||||
#APPSMITH_RECAPTCHA_SITE_KEY=""
|
||||
#APPSMITH_RECAPTCHA_SECRET_KEY=""
|
||||
BMAP_AK="nWCpSjRnXLfGuBc3iLZ9kYv8Y6wYaxf8"
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -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}';
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue