feat: 接入echarts
This commit is contained in:
@@ -16,6 +16,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tailwindcss/postcss": "^4.3.3",
|
"@tailwindcss/postcss": "^4.3.3",
|
||||||
|
"echarts": "^6.1.0",
|
||||||
"element-plus": "^2.14.4",
|
"element-plus": "^2.14.4",
|
||||||
"pinia": "^4.0.2",
|
"pinia": "^4.0.2",
|
||||||
"postcss": "^8.5.26",
|
"postcss": "^8.5.26",
|
||||||
|
|||||||
Generated
+23
@@ -11,6 +11,9 @@ importers:
|
|||||||
'@tailwindcss/postcss':
|
'@tailwindcss/postcss':
|
||||||
specifier: ^4.3.3
|
specifier: ^4.3.3
|
||||||
version: 4.3.3
|
version: 4.3.3
|
||||||
|
echarts:
|
||||||
|
specifier: ^6.1.0
|
||||||
|
version: 6.1.0
|
||||||
element-plus:
|
element-plus:
|
||||||
specifier: ^2.14.4
|
specifier: ^2.14.4
|
||||||
version: 2.14.4(vue@3.5.41(typescript@6.0.3))
|
version: 2.14.4(vue@3.5.41(typescript@6.0.3))
|
||||||
@@ -1076,6 +1079,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
||||||
|
echarts@6.1.0:
|
||||||
|
resolution: {integrity: sha512-q0yaFPggC9FUdsWH4blavRWFmxdrIodbkoKNAjJudAI6CA9gNPxHtV2RcZNEepZVlk4yvBYkOkbk6HIVpIyHZA==}
|
||||||
|
|
||||||
electron-to-chromium@1.5.406:
|
electron-to-chromium@1.5.406:
|
||||||
resolution: {integrity: sha512-hWH5ORBi3d0IipnMh7BN5GDTaAmrSSSWmznwt2zltdiRNEWoEQyTwF0FFSBxzHO7hLSRT6loQu3IQGV0wg/Tvg==}
|
resolution: {integrity: sha512-hWH5ORBi3d0IipnMh7BN5GDTaAmrSSSWmznwt2zltdiRNEWoEQyTwF0FFSBxzHO7hLSRT6loQu3IQGV0wg/Tvg==}
|
||||||
|
|
||||||
@@ -1823,6 +1829,9 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
typescript: '>=4.8.4'
|
typescript: '>=4.8.4'
|
||||||
|
|
||||||
|
tslib@2.3.0:
|
||||||
|
resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==}
|
||||||
|
|
||||||
type-check@0.4.0:
|
type-check@0.4.0:
|
||||||
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
@@ -2101,6 +2110,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
|
zrender@6.1.0:
|
||||||
|
resolution: {integrity: sha512-oEGMDB6pOP2S6OwRR4PdVv610zrjnA3Bh+JnSG12fYJlBKjtNAoEb5fSUoCOOINlH96I2fU38/A2UpRKs67xYQ==}
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@alloc/quick-lru@5.2.0': {}
|
'@alloc/quick-lru@5.2.0': {}
|
||||||
@@ -3051,6 +3063,11 @@ snapshots:
|
|||||||
|
|
||||||
detect-libc@2.1.2: {}
|
detect-libc@2.1.2: {}
|
||||||
|
|
||||||
|
echarts@6.1.0:
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.3.0
|
||||||
|
zrender: 6.1.0
|
||||||
|
|
||||||
electron-to-chromium@1.5.406: {}
|
electron-to-chromium@1.5.406: {}
|
||||||
|
|
||||||
element-plus@2.14.4(vue@3.5.41(typescript@6.0.3)):
|
element-plus@2.14.4(vue@3.5.41(typescript@6.0.3)):
|
||||||
@@ -3753,6 +3770,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
typescript: 6.0.3
|
typescript: 6.0.3
|
||||||
|
|
||||||
|
tslib@2.3.0: {}
|
||||||
|
|
||||||
type-check@0.4.0:
|
type-check@0.4.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
prelude-ls: 1.2.1
|
prelude-ls: 1.2.1
|
||||||
@@ -4044,3 +4063,7 @@ snapshots:
|
|||||||
yaml@2.9.0: {}
|
yaml@2.9.0: {}
|
||||||
|
|
||||||
yocto-queue@0.1.0: {}
|
yocto-queue@0.1.0: {}
|
||||||
|
|
||||||
|
zrender@6.1.0:
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.3.0
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ function onStart(event: DragEvent) {
|
|||||||
@dragstart="onStart"
|
@dragstart="onStart"
|
||||||
>
|
>
|
||||||
<div>{{ props.material.name }}</div>
|
<div>{{ props.material.name }}</div>
|
||||||
<div class="border border-white/20 h-full"><Icon :icon="props.material.icon" /></div>
|
<div class="flex justify-center items-center h-full border border-white/20">
|
||||||
|
<Icon :icon="props.material.icon" width="64" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { getValue } from '@/utils'
|
import { getValue } from '@/utils'
|
||||||
import { ElInput, ElInputNumber, ElColorPicker } from 'element-plus'
|
import { ElInput, ElInputNumber, ElColorPicker, ElCheckbox, ElSelect } from 'element-plus'
|
||||||
import { useUndoRedo } from '@/composables/useUndoRedo'
|
import { useUndoRedo } from '@/composables/useUndoRedo'
|
||||||
|
|
||||||
defineProps(['setters', 'formData'])
|
defineProps(['setters', 'formData'])
|
||||||
@@ -11,6 +11,8 @@ const componentMap: Record<string, any> = {
|
|||||||
input: ElInput,
|
input: ElInput,
|
||||||
number: (props: Record<string, any>) => h(ElInputNumber, { precision: 0, ...props }),
|
number: (props: Record<string, any>) => h(ElInputNumber, { precision: 0, ...props }),
|
||||||
color: ElColorPicker,
|
color: ElColorPicker,
|
||||||
|
checkbox: ElCheckbox,
|
||||||
|
select: ElSelect,
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -21,6 +23,7 @@ const componentMap: Record<string, any> = {
|
|||||||
<component
|
<component
|
||||||
:is="componentMap[setter.type]"
|
:is="componentMap[setter.type]"
|
||||||
:model-value="getValue(formData, setter.key)"
|
:model-value="getValue(formData, setter.key)"
|
||||||
|
v-bind="setter.props"
|
||||||
@update:model-value="(value: any) => applyChange(formData, setter.key, value)"
|
@update:model-value="(value: any) => applyChange(formData, setter.key, value)"
|
||||||
@focus="startBatch()"
|
@focus="startBatch()"
|
||||||
@blur="commitBatch()"
|
@blur="commitBatch()"
|
||||||
|
|||||||
@@ -11,7 +11,12 @@ defineOptions({
|
|||||||
const editorStore = useEditorStore()
|
const editorStore = useEditorStore()
|
||||||
const { selectedNode } = storeToRefs(editorStore)
|
const { selectedNode } = storeToRefs(editorStore)
|
||||||
|
|
||||||
const setters = getMaterialSetters(selectedNode.value?.type || '') ?? []
|
const setters = computed(() => {
|
||||||
|
return getMaterialSetters(selectedNode.value?.type || '') ?? []
|
||||||
|
})
|
||||||
|
|
||||||
|
// 属性分组默认全部展开
|
||||||
|
const activeNames = ref(['layout', 'component'])
|
||||||
|
|
||||||
// 布局属性
|
// 布局属性
|
||||||
const layoutSetters = [
|
const layoutSetters = [
|
||||||
@@ -40,11 +45,11 @@ const layoutSetters = [
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="px-2">
|
<div class="px-2">
|
||||||
<el-collapse>
|
<el-collapse v-model="activeNames">
|
||||||
<el-collapse-item title="布局属性">
|
<el-collapse-item title="布局属性" name="layout">
|
||||||
<FormCreate :setters="layoutSetters" :form-data="selectedNode" />
|
<FormCreate :setters="layoutSetters" :form-data="selectedNode" />
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
<el-collapse-item title="组件属性">
|
<el-collapse-item title="组件属性" name="component">
|
||||||
<FormCreate :setters="setters" :form-data="selectedNode" />
|
<FormCreate :setters="setters" :form-data="selectedNode" />
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
</el-collapse>
|
</el-collapse>
|
||||||
|
|||||||
@@ -0,0 +1,179 @@
|
|||||||
|
import type { MaterialDefinition } from '@/schema/materials'
|
||||||
|
|
||||||
|
export const areaMaterial: MaterialDefinition = {
|
||||||
|
name: '面积图',
|
||||||
|
group: 'charts',
|
||||||
|
icon: 'solar:graph-new-bold',
|
||||||
|
setters: [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
label: '标题',
|
||||||
|
key: 'props.option.title.text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'color',
|
||||||
|
label: '标题色',
|
||||||
|
key: 'props.option.title.textStyle.color',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'checkbox',
|
||||||
|
label: '图例显示',
|
||||||
|
key: 'props.option.legend.show',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '对齐',
|
||||||
|
key: 'props.option.title.left',
|
||||||
|
props: {
|
||||||
|
options: [
|
||||||
|
{ label: '左对齐', value: 'left' },
|
||||||
|
{ label: '居中', value: 'center' },
|
||||||
|
{ label: '右对齐', value: 'right' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'color',
|
||||||
|
label: '线颜色',
|
||||||
|
key: 'props.option.series.0.lineStyle.color',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'color',
|
||||||
|
label: '面积色',
|
||||||
|
key: 'props.option.series.0.areaStyle.color',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
label: 'X字段',
|
||||||
|
key: 'props.option.series.0.encode.x',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
label: 'Y字段',
|
||||||
|
key: 'props.option.series.0.encode.y',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '上边距',
|
||||||
|
key: 'props.option.grid.top',
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '右边距',
|
||||||
|
key: 'props.option.grid.right',
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '下边距',
|
||||||
|
key: 'props.option.grid.bottom',
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '左边距',
|
||||||
|
key: 'props.option.grid.left',
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
schema: {
|
||||||
|
type: 'area-chart',
|
||||||
|
name: '面积图',
|
||||||
|
layout: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 400,
|
||||||
|
height: 260,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
option: {
|
||||||
|
legend: {
|
||||||
|
top: 38,
|
||||||
|
left: 'center',
|
||||||
|
itemWidth: 12,
|
||||||
|
itemHeight: 8,
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
color: '#cbd5e1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: '成交额趋势',
|
||||||
|
top: 8,
|
||||||
|
left: 'center',
|
||||||
|
textStyle: {
|
||||||
|
color: '#ffffff',
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
},
|
||||||
|
dataset: {
|
||||||
|
source: [
|
||||||
|
{ date: '周一', revenue: 120 },
|
||||||
|
{ date: '周二', revenue: 200 },
|
||||||
|
{ date: '周三', revenue: 150 },
|
||||||
|
{ date: '周四', revenue: 260 },
|
||||||
|
{ date: '周五', revenue: 330 },
|
||||||
|
{ date: '周六', revenue: 420 },
|
||||||
|
{ date: '周日', revenue: 510 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
top: 86,
|
||||||
|
right: 24,
|
||||||
|
bottom: 32,
|
||||||
|
left: 48,
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#64748b',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#cbd5e1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
axisLabel: {
|
||||||
|
color: '#cbd5e1',
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: 'rgba(148, 163, 184, 0.18)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '成交额',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
symbolSize: 8,
|
||||||
|
encode: {
|
||||||
|
x: 'date',
|
||||||
|
y: 'revenue',
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
width: 3,
|
||||||
|
color: '#22d3ee',
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#22d3ee',
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
color: 'rgba(34, 211, 238, 0.25)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,163 @@
|
|||||||
|
import type { MaterialDefinition } from '@/schema/materials'
|
||||||
|
|
||||||
|
export const barMaterial: MaterialDefinition = {
|
||||||
|
name: '柱状图',
|
||||||
|
group: 'charts',
|
||||||
|
icon: 'solar:chart-2-bold',
|
||||||
|
setters: [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
label: '标题',
|
||||||
|
key: 'props.option.title.text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'color',
|
||||||
|
label: '标题色',
|
||||||
|
key: 'props.option.title.textStyle.color',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'checkbox',
|
||||||
|
label: '图例显示',
|
||||||
|
key: 'props.option.legend.show',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '对齐',
|
||||||
|
key: 'props.option.title.left',
|
||||||
|
props: {
|
||||||
|
options: [
|
||||||
|
{ label: '左对齐', value: 'left' },
|
||||||
|
{ label: '居中', value: 'center' },
|
||||||
|
{ label: '右对齐', value: 'right' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'color',
|
||||||
|
label: '柱颜色',
|
||||||
|
key: 'props.option.series.0.itemStyle.color',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
label: 'X字段',
|
||||||
|
key: 'props.option.series.0.encode.x',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
label: 'Y字段',
|
||||||
|
key: 'props.option.series.0.encode.y',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '上边距',
|
||||||
|
key: 'props.option.grid.top',
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '右边距',
|
||||||
|
key: 'props.option.grid.right',
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '下边距',
|
||||||
|
key: 'props.option.grid.bottom',
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '左边距',
|
||||||
|
key: 'props.option.grid.left',
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
schema: {
|
||||||
|
type: 'bar-chart',
|
||||||
|
name: '柱状图',
|
||||||
|
layout: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 400,
|
||||||
|
height: 260,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
option: {
|
||||||
|
legend: {
|
||||||
|
top: 38,
|
||||||
|
left: 'center',
|
||||||
|
itemWidth: 12,
|
||||||
|
itemHeight: 8,
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
color: '#cbd5e1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: '销售额统计',
|
||||||
|
top: 8,
|
||||||
|
left: 'center',
|
||||||
|
textStyle: {
|
||||||
|
color: '#ffffff',
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {},
|
||||||
|
dataset: {
|
||||||
|
source: [
|
||||||
|
{ month: '一月', sales: 120 },
|
||||||
|
{ month: '二月', sales: 200 },
|
||||||
|
{ month: '三月', sales: 150 },
|
||||||
|
{ month: '四月', sales: 80 },
|
||||||
|
{ month: '五月', sales: 170 },
|
||||||
|
{ month: '六月', sales: 240 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
top: 86,
|
||||||
|
right: 24,
|
||||||
|
bottom: 32,
|
||||||
|
left: 48,
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#64748b',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#cbd5e1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
axisLabel: {
|
||||||
|
color: '#cbd5e1',
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: 'rgba(148, 163, 184, 0.18)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '销售额',
|
||||||
|
type: 'bar',
|
||||||
|
barWidth: '45%',
|
||||||
|
encode: {
|
||||||
|
x: 'month',
|
||||||
|
y: 'sales',
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#22d3ee',
|
||||||
|
borderRadius: [4, 4, 0, 0],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<!-- echarts组件 -->
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { MaterialSchema } from '@/schema/materials'
|
||||||
|
import { init, type EChartsType } from 'echarts'
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'ChartMaterial',
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = defineProps<{ schema: MaterialSchema }>()
|
||||||
|
const chartRef = useTemplateRef('chartRef')
|
||||||
|
let chart: EChartsType
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.schema.props.option,
|
||||||
|
(newOption) => {
|
||||||
|
if (chartRef.value) {
|
||||||
|
chart.setOption(newOption)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true },
|
||||||
|
)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (chartRef.value) {
|
||||||
|
chart = init(chartRef.value)
|
||||||
|
chart.setOption(props.schema.props.option)
|
||||||
|
|
||||||
|
// 监听窗口大小变化,自动调整图表大小
|
||||||
|
const resizeObserver = new ResizeObserver(() => {
|
||||||
|
chart.resize()
|
||||||
|
})
|
||||||
|
|
||||||
|
resizeObserver.observe(chartRef.value)
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
resizeObserver.disconnect()
|
||||||
|
if (chart) {
|
||||||
|
chart.dispose()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full h-full" ref="chartRef"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -1,26 +1,17 @@
|
|||||||
import type { MaterialDefinition } from '@/schema/materials'
|
import type { MaterialDefinition } from '@/schema/materials'
|
||||||
|
import ChartMaterial from './component.vue'
|
||||||
|
import { barMaterial } from './bar'
|
||||||
|
import { areaMaterial } from './area'
|
||||||
|
import { lineMaterial } from './line'
|
||||||
|
import { pieMaterial } from './pie'
|
||||||
|
|
||||||
export const chartsMaterial: MaterialDefinition = {
|
export function install(register: (material: MaterialDefinition, component: Component) => void) {
|
||||||
name: '柱状图',
|
|
||||||
icon: '',
|
|
||||||
group: 'charts',
|
|
||||||
setters: [],
|
|
||||||
schema: {
|
|
||||||
type: 'chart',
|
|
||||||
name: '柱状图',
|
|
||||||
layout: {
|
|
||||||
x: 0,
|
|
||||||
y: 0,
|
|
||||||
width: 400,
|
|
||||||
height: 300,
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
data: [],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export function install(register: (material: MaterialDefinition) => void) {
|
|
||||||
// 注册柱状图物料
|
// 注册柱状图物料
|
||||||
register(chartsMaterial)
|
register(barMaterial, ChartMaterial)
|
||||||
|
// 注册面积图物料
|
||||||
|
register(areaMaterial, ChartMaterial)
|
||||||
|
// 注册折线图物料
|
||||||
|
register(lineMaterial, ChartMaterial)
|
||||||
|
// 注册饼图物料
|
||||||
|
register(pieMaterial, ChartMaterial)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,171 @@
|
|||||||
|
import type { MaterialDefinition } from '@/schema/materials'
|
||||||
|
|
||||||
|
export const lineMaterial: MaterialDefinition = {
|
||||||
|
name: '折线图',
|
||||||
|
group: 'charts',
|
||||||
|
icon: 'solar:graph-up-bold',
|
||||||
|
setters: [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
label: '标题',
|
||||||
|
key: 'props.option.title.text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'color',
|
||||||
|
label: '标题色',
|
||||||
|
key: 'props.option.title.textStyle.color',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'checkbox',
|
||||||
|
label: '图例显示',
|
||||||
|
key: 'props.option.legend.show',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '对齐',
|
||||||
|
key: 'props.option.title.left',
|
||||||
|
props: {
|
||||||
|
options: [
|
||||||
|
{ label: '左对齐', value: 'left' },
|
||||||
|
{ label: '居中', value: 'center' },
|
||||||
|
{ label: '右对齐', value: 'right' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'color',
|
||||||
|
label: '线颜色',
|
||||||
|
key: 'props.option.series.0.lineStyle.color',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
label: 'X字段',
|
||||||
|
key: 'props.option.series.0.encode.x',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
label: 'Y字段',
|
||||||
|
key: 'props.option.series.0.encode.y',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '上边距',
|
||||||
|
key: 'props.option.grid.top',
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '右边距',
|
||||||
|
key: 'props.option.grid.right',
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '下边距',
|
||||||
|
key: 'props.option.grid.bottom',
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'number',
|
||||||
|
label: '左边距',
|
||||||
|
key: 'props.option.grid.left',
|
||||||
|
span: 12,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
schema: {
|
||||||
|
type: 'line-chart',
|
||||||
|
name: '折线图',
|
||||||
|
layout: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 400,
|
||||||
|
height: 260,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
option: {
|
||||||
|
legend: {
|
||||||
|
top: 38,
|
||||||
|
left: 'center',
|
||||||
|
itemWidth: 12,
|
||||||
|
itemHeight: 8,
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
color: '#cbd5e1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: '访问量趋势',
|
||||||
|
top: 8,
|
||||||
|
left: 'center',
|
||||||
|
textStyle: {
|
||||||
|
color: '#ffffff',
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
},
|
||||||
|
dataset: {
|
||||||
|
source: [
|
||||||
|
{ date: '周一', visits: 820 },
|
||||||
|
{ date: '周二', visits: 932 },
|
||||||
|
{ date: '周三', visits: 901 },
|
||||||
|
{ date: '周四', visits: 934 },
|
||||||
|
{ date: '周五', visits: 1290 },
|
||||||
|
{ date: '周六', visits: 1330 },
|
||||||
|
{ date: '周日', visits: 1320 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
top: 86,
|
||||||
|
right: 24,
|
||||||
|
bottom: 32,
|
||||||
|
left: 48,
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#64748b',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#cbd5e1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value',
|
||||||
|
axisLabel: {
|
||||||
|
color: '#cbd5e1',
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: 'rgba(148, 163, 184, 0.18)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '访问量',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
symbolSize: 8,
|
||||||
|
encode: {
|
||||||
|
x: 'date',
|
||||||
|
y: 'visits',
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
width: 3,
|
||||||
|
color: '#38bdf8',
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#38bdf8',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
import type { MaterialDefinition } from '@/schema/materials'
|
||||||
|
|
||||||
|
export const pieMaterial: MaterialDefinition = {
|
||||||
|
name: '饼图',
|
||||||
|
group: 'charts',
|
||||||
|
icon: 'solar:pie-chart-2-bold',
|
||||||
|
setters: [
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
label: '标题',
|
||||||
|
key: 'props.option.title.text',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'color',
|
||||||
|
label: '标题色',
|
||||||
|
key: 'props.option.title.textStyle.color',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'checkbox',
|
||||||
|
label: '图例显示',
|
||||||
|
key: 'props.option.legend.show',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'select',
|
||||||
|
label: '对齐',
|
||||||
|
key: 'props.option.title.left',
|
||||||
|
props: {
|
||||||
|
options: [
|
||||||
|
{ label: '左对齐', value: 'left' },
|
||||||
|
{ label: '居中', value: 'center' },
|
||||||
|
{ label: '右对齐', value: 'right' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'color',
|
||||||
|
label: '主色',
|
||||||
|
key: 'props.option.color.0',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
label: '名称字段',
|
||||||
|
key: 'props.option.series.0.encode.itemName',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
label: '数值字段',
|
||||||
|
key: 'props.option.series.0.encode.value',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
schema: {
|
||||||
|
type: 'pie-chart',
|
||||||
|
name: '饼图',
|
||||||
|
layout: {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
width: 400,
|
||||||
|
height: 260,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
option: {
|
||||||
|
color: ['#22d3ee', '#a78bfa', '#f59e0b', '#34d399', '#fb7185'],
|
||||||
|
legend: {
|
||||||
|
top: 38,
|
||||||
|
left: 'center',
|
||||||
|
itemWidth: 12,
|
||||||
|
itemHeight: 8,
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
color: '#cbd5e1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: '访问来源占比',
|
||||||
|
top: 8,
|
||||||
|
left: 'center',
|
||||||
|
textStyle: {
|
||||||
|
color: '#ffffff',
|
||||||
|
fontSize: 16,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
},
|
||||||
|
dataset: {
|
||||||
|
source: [
|
||||||
|
{ channel: '搜索引擎', value: 1048 },
|
||||||
|
{ channel: '直接访问', value: 735 },
|
||||||
|
{ channel: '联盟广告', value: 484 },
|
||||||
|
{ channel: '视频广告', value: 300 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '访问来源',
|
||||||
|
type: 'pie',
|
||||||
|
center: ['50%', '62%'],
|
||||||
|
avoidLabelOverlap: true,
|
||||||
|
label: {
|
||||||
|
color: '#e2e8f0',
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#94a3b8',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
encode: {
|
||||||
|
itemName: 'channel',
|
||||||
|
value: 'value',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ import TextMaterial from './component.vue'
|
|||||||
|
|
||||||
const textMaterial: MaterialDefinition = {
|
const textMaterial: MaterialDefinition = {
|
||||||
name: '文本',
|
name: '文本',
|
||||||
icon: '',
|
icon: 'solar:text-bold',
|
||||||
group: 'info',
|
group: 'info',
|
||||||
setters: [
|
setters: [
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user