Merge branch 'dev' into master-fetch-dev

This commit is contained in:
奔跑的面条 2023-04-02 17:54:57 +08:00
commit 29339c4c7c
38 changed files with 4620 additions and 1444 deletions

View File

@ -75,7 +75,7 @@
"sass": "^1.49.11",
"sass-loader": "^12.6.0",
"typescript": "4.6.3",
"vite": "2.9.9",
"vite": "4.2.1",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-importer": "^0.2.5",
"vite-plugin-mock": "^2.9.6",

2831
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

100
src/api/mock/graph.json Normal file
View File

@ -0,0 +1,100 @@
{
"nodes": [
{
"id": "0",
"name": "Myriel",
"symbolSize": "@integer(0, 50)",
"x": -266.82776,
"y": 299.6904,
"value": "@integer(0, 50)",
"category": 3
},
{
"id": "1",
"name": "Napoleon",
"symbolSize": "@integer(0, 50)",
"x": -418.08344,
"y": 446.8853,
"value": "@integer(0, 50)",
"category": 5
},
{
"id": "2",
"name": "MlleBaptistine",
"symbolSize": "@integer(0, 50)",
"x": -212.76357,
"y": 245.29176,
"value": "@integer(0, 50)",
"category": 1
},
{
"id": "3",
"name": "MmeMagloire",
"symbolSize": "@integer(0, 50)",
"x": -242.82404,
"y": 235.26283,
"value": "@integer(0, 50)",
"category": 1
},
{
"id": "4",
"name": "CountessDeLo",
"symbolSize": "@integer(0, 50)",
"x": -379.30386,
"y": 429.06424,
"value": "@integer(0, 50)",
"category": 0
}
],
"links": [
{
"source": "1",
"target": "@integer(2, 4)"
},
{
"source": "2",
"target": "@integer(3, 4)"
},
{
"source": "3",
"target": "@integer(0, 2)"
},
{
"source": "3",
"target": "@integer(0, 1)"
},
{
"source": "4",
"target": "@integer(0, 3)"
}
],
"categories": [
{
"name": "A"
},
{
"name": "B"
},
{
"name": "C"
},
{
"name": "D"
},
{
"name": "E"
},
{
"name": "F"
},
{
"name": "G"
},
{
"name": "H"
},
{
"name": "I"
}
]
}

View File

@ -19,6 +19,8 @@ export const capsuleUrl = '/mock/capsule'
export const wordCloudUrl = '/mock/wordCloud'
export const treemapUrl = '/mock/treemap'
export const threeEarth01Url = '/mock/threeEarth01Data'
export const sankeyUrl = '/mock/sankey'
export const graphUrl = '/mock/graphData'
const mockObject: MockMethod[] = [
{
@ -103,6 +105,16 @@ const mockObject: MockMethod[] = [
method: RequestHttpEnum.GET,
response: () => test.threeEarth01Data
},
{
url: sankeyUrl,
method: RequestHttpEnum.GET,
response: () => test.fetchSankey
},
{
url: graphUrl,
method: RequestHttpEnum.GET,
response: () => test.graphData
},
]
export default mockObject

86
src/api/mock/sankey.json Normal file
View File

@ -0,0 +1,86 @@
{
"label": [
{
"name": "a"
},
{
"name": "b"
},
{
"name": "a1"
},
{
"name": "a2"
},
{
"name": "b1"
},
{
"name": "b2"
}
],
"links": [
{
"source": "a",
"target": "a1",
"value": "@integer(0, 10)"
},
{
"source": "a",
"target": "a2",
"value": "@integer(0, 10)"
},
{
"source": "b",
"target": "b1",
"value": "@integer(0, 10)"
},
{
"source": "a",
"target": "b1",
"value": "@integer(0, 10)"
},
{
"source": "b1",
"target": "a1",
"value": "@integer(0, 10)"
},
{
"source": "b1",
"target": "b2",
"value": "@integer(0, 10)"
}
],
"levels": [
{
"depth": 0,
"itemStyle": {
"color": "#decbe4"
},
"lineStyle": {
"color": "source",
"opacity": 0.9
}
},
{
"depth": 1,
"itemStyle": {
"color": "#b3cde3"
},
"lineStyle": {
"color": "source",
"opacity": 0.6
}
},
{
"depth": 2,
"itemStyle": {
"color": "#ccebc5"
},
"lineStyle": {
"color": "source",
"opacity": 0.6
}
}
]
}

View File

@ -2,6 +2,8 @@ import heatmapJson from './heatMapData.json'
import scatterJson from './scatter.json'
import mapJson from './map.json'
import tTreemapJson from './treemap.json'
import sankeyJson from './sankey.json'
import graphDataJson from './graph.json'
export default {
// 单图表
@ -219,5 +221,19 @@ export default {
'endArray|10': [{ name: '@name', N: '@integer(10, 100)', E: '@integer(10, 100)' }]
}
]
}
},
// 桑基图
fetchSankey: {
code: 0,
status: 200,
msg: '请求成功',
data: sankeyJson
},
// 关系图
graphData: {
code: 0,
status: 200,
msg: '请求成功',
data: graphDataJson
},
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -12,6 +12,7 @@ export enum DragKeyEnum {
// 不同页面保存操作
export enum SavePageEnum {
CHART = 'SaveChart',
CHART_TO_PREVIEW = 'ChartToPreview',
JSON = 'SaveJSON',
CLOSE = 'close'
}

View File

@ -1,13 +1,9 @@
<template>
<router-view>
<template #default="{ Component, route }">
<component
v-if="route.noKeepAlive"
:is="Component"
:key="route.fullPath"
></component>
<component v-if="route.meta.noKeepAlive" :is="Component"></component>
<keep-alive v-else>
<component :is="Component" :key="route.fullPath"></component>
<component :is="Component"></component>
</keep-alive>
</template>
</router-view>

View File

@ -2,7 +2,7 @@
<router-view #default="{ Component, route }">
<transition name="fade" mode="out-in" appear>
<component
v-if="route.noKeepAlive"
v-if="route.meta.noKeepAlive"
:is="Component"
:key="route.fullPath"
></component>

View File

@ -1,15 +1,8 @@
<template>
<v-chart
ref="vChartRef"
:init-options="initOptions"
:theme="themeColor"
:option="option"
:manual-update="isPreview()"
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option" :manual-update="isPreview()"
:update-options="{
replaceMerge: replaceMergeArr
}"
autoresize
></v-chart>
}" autoresize></v-chart>
</template>
<script setup lang="ts">
@ -27,6 +20,7 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore
import { isPreview } from '@/utils'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
import isObject from 'lodash/isObject'
import cloneDeep from 'lodash/cloneDeep'
const props = defineProps({
themeSetting: {
@ -61,11 +55,20 @@ watch(
if (!isObject(newData) || !('dimensions' in newData)) return
if (Array.isArray(newData?.dimensions)) {
const seriesArr = []
for (let i = 0; i < newData.dimensions.length - 1; i++) {
seriesArr.push(seriesItem)
// oldData
// dimensionsYdimensions.length011X
const oldDimensions = Array.isArray(oldData?.dimensions)&&oldData.dimensions.length >= 1 ? oldData.dimensions.length : 1;
const newDimensions = newData.dimensions.length >= 1 ? newData.dimensions.length : 1;
const dimensionsGap = newDimensions - oldDimensions;
if (dimensionsGap < 0) {
props.chartConfig.option.series.splice(newDimensions - 1)
} else if (dimensionsGap > 0) {
for (let i = 0; i < dimensionsGap; i++) {
seriesArr.push(cloneDeep(seriesItem))
}
props.chartConfig.option.series.push(...seriesArr)
}
replaceMergeArr.value = ['series']
props.chartConfig.option.series = seriesArr
nextTick(() => {
replaceMergeArr.value = []
})

View File

@ -26,6 +26,7 @@ import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore
import { isPreview } from '@/utils'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
import isObject from 'lodash/isObject'
import cloneDeep from 'lodash/cloneDeep'
const props = defineProps({
themeSetting: {
@ -61,7 +62,7 @@ watch(
if (Array.isArray(newData?.dimensions)) {
const seriesArr = []
for (let i = 0; i < newData.dimensions.length - 1; i++) {
seriesArr.push(seriesItem)
seriesArr.push(cloneDeep(seriesItem))
}
replaceMergeArr.value = ['series']
props.chartConfig.option.series = seriesArr

View File

@ -0,0 +1,91 @@
import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
import { DialConfig } from './index'
import { CreateComponentType } from '@/packages/index.d'
import cloneDeep from 'lodash/cloneDeep'
export const includes = []
const option = {
backgroundColor: '#0E1327',
dataset:70,
series: [{
type: "gauge",
data: [{
value: 70,
itemStyle: { // 指针样式
color: '#2AF4FF'
}
}],
min: 0, //最小刻度
max: 100, //最大刻度
splitNumber: 10, //刻度数量
center: ['50%', '55%'],
radius: '80%',
axisLine: {
lineStyle: {
color: [
[0, 'rgba(0,212,230,0.5)'],
[1, 'rgba(28,128,245,0)']
],
width: 170
}
},
axisLabel: { // 文字样式
color: '#eee',
fontSize: 14,
},
axisTick: {
show: false,
},
splitLine: {
show: false,
},
detail: {
show: false,
},
pointer: {
length: '80%',
width: 4
},
animationDuration: 2000,
},
{
name: '外部刻度',
type: 'gauge',
center: ['50%', '55%'],
radius: '90%',
axisLine: {
show: true,
lineStyle: {
width: 25,
color: [ // 表盘外部颜色
[0, '#1369E380'],
[1, '#1369E380']
],
}
},
axisLabel: {
show:false,
},
axisTick: {
splitNumber: 5,
lineStyle: { //刻度颜色
color: '#42E5FB',
width: 2,
},
},
splitLine: {
length: 15,
lineStyle: {
color: '#42E5FB',
}
},
},
]
};
export default class Config extends PublicConfigClass implements CreateComponentType {
public key: string = DialConfig.key
public chartConfig = cloneDeep(DialConfig)
// 图表配置项
public option = echartOptionProfixHandle(option, includes)
}

View File

@ -0,0 +1,84 @@
<template>
<!-- 遍历 seriesList -->
<CollapseItem :name="`圆环`" :expanded="true">
<SettingItemBox name="数据">
<SettingItem name="数值">
<n-input-number v-model:value="config.dataset" :min="dialConfig.min" :max="dialConfig.max" :step="1" size="small" placeholder="数值">
</n-input-number>
</SettingItem>
</SettingItemBox>
<!-- Echarts 全局设置 -->
<!-- 表盘刻度字体 -->
<SettingItemBox name="字体">
<SettingItem name="颜色">
<n-color-picker size="small" :modes="['hex']" v-model:value="dialConfig.axisLabel.color"></n-color-picker>
</SettingItem>
<SettingItem name="字体大小">
<n-input-number
v-model:value="dialConfig.axisLabel.fontSize"
:min="0"
:step="1"
size="small"
placeholder="字体大小"
>
</n-input-number>
</SettingItem>
</SettingItemBox>
<!-- 表盘 -->
<SettingItemBox name="表盘外部">
<SettingItem name="颜色" >
<n-color-picker size="small" :modes="['hex']" v-model:value="config.series[1].axisLine.lineStyle.color[1][1]"></n-color-picker>
</SettingItem>
</SettingItemBox>
<!-- 指针 -->
<SettingItemBox name="指针">
<SettingItem name="颜色" >
<n-color-picker size="small" :modes="['hex']" v-model:value="dialConfig.data[0].itemStyle.color"></n-color-picker>
</SettingItem>
<SettingItem name="宽度">
<n-input-number v-model:value="dialConfig.pointer.width" :min="0" :step="1" size="small" placeholder="数值">
</n-input-number>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="刻度">
<SettingItem name="最小值">
<n-input-number v-model:value="dialConfig.min" :min="0" :step="1" size="small" placeholder="数值">
</n-input-number>
</SettingItem>
<SettingItem name="最大值">
<n-input-number v-model:value="dialConfig.max" :min="0" :step="1" size="small" placeholder="数值">
</n-input-number>
</SettingItem>
<SettingItem name="颜色" >
<n-color-picker size="small" :modes="['hex']" v-model:value="config.series[1].axisTick.lineStyle.color" @update:value="updateClick"></n-color-picker>
</SettingItem>
</SettingItemBox>
</CollapseItem>
</template>
<script setup lang="ts">
import { PropType, computed } from 'vue'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { GlobalThemeJsonType } from '@/settings/chartThemes'
const props = defineProps({
optionData: {
type: Object as PropType<GlobalThemeJsonType>,
required: true
}
})
const config = computed(() => {
return props.optionData
})
const dialConfig = computed(() => {
return props.optionData.series[0]
})
const updateClick = (val: any) => {
props.optionData.series[1].splitLine.lineStyle.color=val
}
</script>

View File

@ -0,0 +1,14 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
export const DialConfig: ConfigType = {
key: 'Dial',
chartKey: 'VDial',
conKey: 'VCDial',
title: '表盘',
category: ChatCategoryEnum.MORE,
categoryName: ChatCategoryEnumName.MORE,
package: PackagesCategoryEnum.CHARTS,
chartFrame: ChartFrameEnum.COMMON,
image:'dial.png'
}

View File

@ -0,0 +1,69 @@
<template>
<v-chart :theme="themeColor" :init-options="initOptions" :option="option.value" autoresize> </v-chart>
</template>
<script setup lang="ts">
import { PropType, reactive, watch } from 'vue'
import VChart from 'vue-echarts'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { PieChart } from 'echarts/charts'
import { mergeTheme } from '@/packages/public/chart'
import config, { includes } from './config'
import { useChartDataFetch } from '@/hooks'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent, TitleComponent } from 'echarts/components'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<config>,
required: true
}
})
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
use([DatasetComponent, CanvasRenderer, PieChart, GridComponent, TooltipComponent, LegendComponent, TitleComponent])
const option = reactive({
value: {}
})
const dataHandle = (newData: any) => {
let config = props.chartConfig.option
config.series[0].data[0].value = newData
option.value = mergeTheme(props.chartConfig.option, props.themeSetting, includes)
option.value = props.chartConfig.option
}
//
watch(
() => props.chartConfig.option.dataset,
newData => {
try {
dataHandle(newData)
} catch (error) {
console.log(error)
}
},
{
immediate: true,
deep: false
}
)
//
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: number) => {
// @ts-ignore
option.value.series[0].data[0].value = resData
})
</script>

View File

@ -0,0 +1,71 @@
import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
import { GraphConfig } from './index'
import { CreateComponentType } from '@/packages/index.d'
import cloneDeep from 'lodash/cloneDeep'
import dataJson from './data.json'
export const includes = []
// 关系图布局
export const GraphLayout = [
{ label: '无', value: 'none' },
{ label: '环形', value: 'circular' }
]
// 标签开关
export const LabelSwitch = [
{ label: '开启', value: 1 },
{ label: '关闭', value: 0 }
]
// 标签位置
export const LabelPosition = [
{ label: '左侧', value: 'left' },
{ label: '右侧', value: 'right' },
{ label: '顶部', value: 'top' },
{ label: '底部', value: 'bottom' },
{ label: '内部', value: 'inside' },
]
export const option = {
dataset: { ...dataJson },
tooltip: {},
legend:{
show:true,
textStyle:{
color:"#eee",
fontSize: 14 ,
},
data: dataJson.categories.map(function (a) {
return a.name;
})
},
series: [
{
type: 'graph',
layout: 'none', // none circular环形布局
data: dataJson.nodes,
links: dataJson.links,
categories: dataJson.categories,
label: { // 标签
show: 1,
position: 'right',
formatter: '{b}'
},
labelLayout: {
hideOverlap: true
},
lineStyle: {
color: 'source', // 线条颜色
curveness: 0.2 // 线条卷曲程度
}
}
]
};
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = GraphConfig.key
public chartConfig = cloneDeep(GraphConfig)
// 图表配置项
public option = echartOptionProfixHandle(option, includes)
}

View File

@ -0,0 +1,62 @@
<template>
<div>
<CollapseItem name="关系图" :expanded="true">
<SettingItemBox name="样式">
<setting-item name="布局">
<n-select v-model:value="graphConfig.layout" :options="GraphLayout" size="small" />
</setting-item>
</SettingItemBox>
<SettingItemBox name="标签">
<setting-item name="展示">
<n-select v-model:value="graphConfig.label.show" :options="LabelSwitch" size="small" />
</setting-item>
<setting-item name="位置">
<n-select v-model:value="graphConfig.label.position" :options="LabelPosition" size="small" />
</setting-item>
</SettingItemBox>
<SettingItemBox name="线条">
<SettingItem name="弧线">
<!-- 需要输入两位的小数才会变化 -->
<n-input-number
v-model:value="optionData.series[0].lineStyle.curveness"
:min="0"
:step="0.01"
placeholder="弯曲程度"
size="small"
></n-input-number>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="图例">
<SettingItem name="颜色">
<n-color-picker
size="small"
:modes="['hex']"
v-model:value="optionData.legend.textStyle.color"
></n-color-picker>
</SettingItem>
<SettingItem name="文本">
<n-input-number v-model:value="optionData.legend.textStyle.fontSize" :min="0" :step="1" size="small" placeholder="文字大小">
</n-input-number>
</SettingItem>
</SettingItemBox>
</CollapseItem>
</div>
</template>
<script setup lang="ts">
import { PropType, computed } from 'vue'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { option, GraphLayout, LabelSwitch, LabelPosition } from './config'
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
const props = defineProps({
optionData: {
type: Object as PropType<typeof option & GlobalThemeJsonType>,
required: true
}
})
const graphConfig = computed<typeof option.series[0]>(() => {
return props.optionData.series[0]
})
</script>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
export const GraphConfig: ConfigType = {
key: 'Graph',
chartKey: 'VGraph',
conKey: 'VCGraph',
title: '关系图',
category: ChatCategoryEnum.MORE,
categoryName: ChatCategoryEnumName.MORE,
package: PackagesCategoryEnum.CHARTS,
chartFrame: ChartFrameEnum.COMMON,
image: 'graph.png'
}

View File

@ -0,0 +1,80 @@
<template>
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option" :manual-update="isPreview()" autoresize></v-chart>
</template>
<script setup lang="ts">
import { ref, computed, PropType, watch } from 'vue'
import VChart from 'vue-echarts'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import dataJson from './data.json'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { RadarChart } from 'echarts/charts'
import { includes } from './config'
import { mergeTheme, setOption } from '@/packages/public/chart'
import { useChartDataFetch } from '@/hooks'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { isPreview } from '@/utils'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
use([DatasetComponent, CanvasRenderer, RadarChart, GridComponent, TooltipComponent, LegendComponent])
const vChartRef = ref<typeof VChart>()
const option = computed(() => {
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
const dataSetHandle = (dataset: typeof dataJson) => {
if (dataset.nodes) {
props.chartConfig.option.series[0].data = dataset.nodes
}
if (dataset.links) {
props.chartConfig.option.series[0].links = dataset.links
}
if (dataset.categories) {
props.chartConfig.option.series[0].categories = dataset.categories
// @ts-ignore
props.chartConfig.option.legend.data = dataset.categories.map((i: { name: string }) => i.name)
}
if (vChartRef.value && isPreview()) {
setOption(vChartRef.value, props.chartConfig.option)
}
}
watch(
() => props.chartConfig.option.dataset,
newData => {
try {
dataSetHandle(newData)
} catch (error) {
console.log(error)
}
},
{
deep: false
}
)
useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
dataSetHandle(newData)
})
</script>

View File

@ -0,0 +1,43 @@
import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
import { SankeyConfig } from './index'
import { CreateComponentType } from '@/packages/index.d'
import cloneDeep from 'lodash/cloneDeep'
import dataJson from './data.json'
export const includes = ['legend']
// 图表方向
export const orientList = [
{ label: '水平', value: 'horizontal' },
{ label: '垂直', value: 'vertical' }
]
// 标签展示
export const toolTipSwitch = [
{ label: '开启', value: 1 },
{ label: '关闭', value: 0 }
]
export const option = {
dataset: { ...dataJson },
tooltip: {
show: 1,
trigger: 'item',
triggerOn: 'mousemove'
},
series: {
type: 'sankey',
layout: 'none',
orient:'horizontal',
data: dataJson.label,
links: dataJson.links,
levels: dataJson.levels
}
};
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = SankeyConfig.key
public chartConfig = cloneDeep(SankeyConfig)
// 图表配置项
public option = echartOptionProfixHandle(option, includes)
}

View File

@ -0,0 +1,43 @@
<template>
<div>
<CollapseItem name="桑基图" :expanded="true">
<SettingItemBox name="样式">
<SettingItem name="方向">
<n-select
v-model:value="sankeyConfig.orient"
size="small"
:options="orientList"
placeholder="选择方向"
/>
</SettingItem>
<SettingItem name="提示标签">
<n-select
v-model:value="optionData.tooltip.show"
size="small"
:options="toolTipSwitch"
placeholder="是否开启"
/>
</SettingItem>
</SettingItemBox>
</CollapseItem>
</div>
</template>
<script setup lang="ts">
import { PropType, computed } from 'vue'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { option, orientList, toolTipSwitch } from './config'
import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
const props = defineProps({
optionData: {
type: Object as PropType<typeof option & GlobalThemeJsonType>,
required: true
}
})
const sankeyConfig = computed<typeof option.series>(() => {
return props.optionData.series
})
</script>

View File

@ -0,0 +1,86 @@
{
"label": [
{
"name": "a"
},
{
"name": "b"
},
{
"name": "a1"
},
{
"name": "a2"
},
{
"name": "b1"
},
{
"name": "b2"
}
],
"links": [
{
"source": "a",
"target": "a1",
"value": 5
},
{
"source": "a",
"target": "a2",
"value": 3
},
{
"source": "b",
"target": "b1",
"value": 8
},
{
"source": "a",
"target": "b1",
"value": 3
},
{
"source": "b1",
"target": "a1",
"value": 1
},
{
"source": "b1",
"target": "b2",
"value": 2
}
],
"levels": [
{
"depth": 0,
"itemStyle": {
"color": "#decbe4"
},
"lineStyle": {
"color": "source",
"opacity": 0.9
}
},
{
"depth": 1,
"itemStyle": {
"color": "#b3cde3"
},
"lineStyle": {
"color": "source",
"opacity": 0.6
}
},
{
"depth": 2,
"itemStyle": {
"color": "#ccebc5"
},
"lineStyle": {
"color": "source",
"opacity": 0.6
}
}
]
}

View File

@ -0,0 +1,14 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
export const SankeyConfig: ConfigType = {
key: 'Sankey',
chartKey: 'VSankey',
conKey: 'VCSankey',
title: '桑基图',
category: ChatCategoryEnum.MORE,
categoryName: ChatCategoryEnumName.MORE,
package: PackagesCategoryEnum.CHARTS,
chartFrame: ChartFrameEnum.COMMON,
image: 'sankey.png'
}

View File

@ -0,0 +1,78 @@
<template>
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option" :manual-update="isPreview()" autoresize></v-chart>
</template>
<script setup lang="ts">
import { ref, computed, PropType, watch } from 'vue'
import VChart from 'vue-echarts'
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import dataJson from './data.json'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { RadarChart } from 'echarts/charts'
import { includes } from './config'
import { mergeTheme, setOption } from '@/packages/public/chart'
import { useChartDataFetch } from '@/hooks'
import { CreateComponentType } from '@/packages/index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { isPreview } from '@/utils'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
const props = defineProps({
themeSetting: {
type: Object,
required: true
},
themeColor: {
type: Object,
required: true
},
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
use([DatasetComponent, CanvasRenderer, RadarChart, GridComponent, TooltipComponent, LegendComponent])
const vChartRef = ref<typeof VChart>()
const option = computed(() => {
return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
})
const dataHandle = (dataset: typeof dataJson) => {
if (dataset.label) {
props.chartConfig.option.series.data = dataset.label
}
if (dataset.links) {
props.chartConfig.option.series.links = dataset.links
}
if (dataset.levels) {
props.chartConfig.option.series.levels = dataset.levels
}
if (vChartRef.value && isPreview()) {
setOption(vChartRef.value, props.chartConfig.option)
}
}
watch(
() => props.chartConfig.option.dataset,
newData => {
try {
dataHandle(newData)
} catch (error) {
console.log(error)
}
},
{
deep: true
}
)
useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
dataHandle(newData)
})
</script>

View File

@ -4,5 +4,8 @@ import { FunnelConfig } from './Funnel/index'
import { HeatmapConfig } from './Heatmap/index'
import { WaterPoloConfig } from './WaterPolo/index'
import { TreeMapConfig } from './TreeMap/index'
import { DialConfig } from './Dial/index'
import { SankeyConfig } from './Sankey/index'
import { GraphConfig } from './Graph/index'
export default [ProcessConfig, RadarConfig, FunnelConfig, HeatmapConfig, WaterPoloConfig, TreeMapConfig]
export default [ProcessConfig, RadarConfig, FunnelConfig, HeatmapConfig, WaterPoloConfig, TreeMapConfig, GraphConfig, SankeyConfig, DialConfig]

View File

@ -15,7 +15,7 @@ export interface IResources {
const fileSuffix = ['earth', 'gradient', 'redCircle', 'label', 'aperture', 'glow', 'light_column', 'aircraft']
const textures: ITextures[] = []
const modules = import.meta.globEager("../../images/earth/*");
const modules: Record<string, { default: string }> = import.meta.glob("../../images/earth/*", { eager: true })
for(let item in modules) {
const n = item.split('/').pop()

View File

@ -4,9 +4,15 @@ import { InformationList } from '@/packages/components/Informations/index'
import { TableList } from '@/packages/components/Tables/index'
import { PackagesCategoryEnum, PackagesType, ConfigType, FetchComFlagType } from '@/packages/index.d'
const configModules = import.meta.globEager('./components/**/config.vue')
const indexModules = import.meta.globEager('./components/**/index.vue')
const imagesModules = import.meta.globEager('../assets/images/chart/**')
const configModules: Record<string, { default: string }> = import.meta.glob('./components/**/config.vue', {
eager: true
})
const indexModules: Record<string, { default: string }> = import.meta.glob('./components/**/index.vue', {
eager: true
})
const imagesModules: Record<string, { default: string }> = import.meta.glob('../assets/images/chart/**', {
eager: true
})
// * 所有图表
export let packagesList: PackagesType = {

View File

@ -65,6 +65,7 @@ import { RequestHeader } from '../RequestHeader'
import { isDev } from '@/utils'
import { icon } from '@/plugins'
import {
graphUrl,
chartDataUrl,
chartSingleDataUrl,
rankListUrl,
@ -80,7 +81,8 @@ import {
capsuleUrl,
wordCloudUrl,
treemapUrl,
threeEarth01Url
threeEarth01Url,
sankeyUrl
} from '@/api/mock'
const props = defineProps({
@ -142,6 +144,12 @@ const apiList = [
},
{
value: `【三维地球】${threeEarth01Url}`
},
{
value: `【桑基图】${sankeyUrl}`
},
{
value: `【关系图】${graphUrl}`
}
]
</script>

View File

@ -25,6 +25,11 @@ export const syncData = () => {
})
}
// 同步数据到预览页
export const syncDataToPreview = () => {
dispatchEvent(new CustomEvent(SavePageEnum.CHART_TO_PREVIEW, { detail: chartEditStore.getStorageInfo }))
}
// 侦听器更新
const useSyncUpdateHandle = () => {
// 定义侦听器变量
@ -49,8 +54,8 @@ const useSyncUpdateHandle = () => {
// document.hasFocus() && syncData()
// }, editToJsonInterval)
// 失焦同步数据(暂不开启)
// addEventListener('blur', syncData)
// 失焦同步数据
addEventListener('blur', syncDataToPreview)
// 监听编辑器保存事件 刷新工作台图表
addEventListener(SavePageEnum.JSON, updateFn)
@ -62,7 +67,7 @@ const useSyncUpdateHandle = () => {
// 关闭侦听
const unUse = () => {
// clearInterval(timer)
// removeEventListener('blur', syncData)
removeEventListener('blur', syncDataToPreview)
removeEventListener(SavePageEnum.JSON, updateFn)
}

View File

@ -322,6 +322,15 @@ $asideBottom: 70px;
border-radius: 25px;
}
}
&::after {
content: '';
position: absolute;
left: 0;
width: 100%;
height: 10px;
bottom: -10px;
cursor: pointer;
}
}
/* 最小化 */
&.isMini {
@ -348,6 +357,7 @@ $asideBottom: 70px;
50% {
opacity: 0;
bottom: calc(#{$dockMiniBottom} - 10px);
pointer-events: none;
}
100% {
opacity: 1;
@ -362,15 +372,6 @@ $asideBottom: 70px;
display: none;
}
}
&::after {
content: '';
position: absolute;
left: 0;
width: 100%;
height: 20px;
bottom: -20px;
cursor: pointer;
}
}
}
</style>

View File

@ -11,7 +11,7 @@
<!-- 模块展示按钮 -->
<n-tooltip v-for="item in btnList" :key="item.key" placement="bottom" trigger="hover">
<template #trigger>
<n-button size="small" ghost :type="styleHandle(item)" @click="clickHandle(item)">
<n-button size="small" ghost :type="styleHandle(item)" :focusable="false" @click="clickHandle(item)">
<component :is="item.icon"></component>
</n-button>
</template>

View File

@ -1,105 +1,16 @@
<template>
<div
:class="`go-preview ${chartEditStore.editCanvasConfig.previewScaleType}`"
>
<template v-if="showEntity">
<!-- 实体区域 -->
<div ref="entityRef" class="go-preview-entity">
<!-- 缩放层 -->
<div ref="previewRef" class="go-preview-scale">
<!-- 展示层 -->
<div :style="previewRefStyle" v-if="show">
<!-- 渲染层 -->
<preview-render-list></preview-render-list>
</div>
</div>
</div>
</template>
<template v-else>
<!-- 缩放层 -->
<div ref="previewRef" class="go-preview-scale">
<!-- 展示层 -->
<div :style="previewRefStyle" v-if="show">
<!-- 渲染层 -->
<preview-render-list></preview-render-list>
</div>
</div>
</template>
</div>
</template>
<!--
Copyright 2023 MT
<script setup lang="ts">
import { computed } from 'vue'
import { PreviewRenderList } from './components/PreviewRenderList'
import { getFilterStyle, routerTurnByName, setTitle } from '@/utils'
import { getEditCanvasConfigStyle, getSessionStorageInfo } from './utils'
import { PageEnum } from '@/enums/pageEnum'
import { useScale } from './hooks/useScale.hook'
import { useStore } from './hooks/useStore.hook'
import { PreviewScaleEnum } from '@/enums/styleEnum'
import { useComInstall } from './hooks/useComInstall.hook'
import type { ChartEditStorageType } from './index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
await getSessionStorageInfo()
const chartEditStore = useChartEditStore() as unknown as ChartEditStorageType
http://www.apache.org/licenses/LICENSE-2.0
setTitle(`预览-${chartEditStore.editCanvasConfig.projectName}`)
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
// @ts-ignore
if(chartEditStore.isRelease === false) {
routerTurnByName(PageEnum.REDIRECT_UN_PUBLISH_NAME, true, false)
}
const previewRefStyle = computed(() => {
return {
...getEditCanvasConfigStyle(chartEditStore.editCanvasConfig),
...getFilterStyle(chartEditStore.editCanvasConfig.filterShow ? chartEditStore.editCanvasConfig : undefined),
}
})
const showEntity = computed(() => {
const type = chartEditStore.editCanvasConfig.previewScaleType
return (
type === PreviewScaleEnum.SCROLL_Y || type === PreviewScaleEnum.SCROLL_X
)
})
useStore(chartEditStore)
const { entityRef, previewRef } = useScale(chartEditStore)
const { show } = useComInstall(chartEditStore)
</script>
<style lang="scss" scoped>
@include go('preview') {
position: relative;
height: 100vh;
width: 100vw;
@include background-image('background-image');
&.fit,
&.full {
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
.go-preview-scale {
transform-origin: center center;
}
}
&.scrollY {
overflow-x: hidden;
.go-preview-scale {
transform-origin: left top;
}
}
&.scrollX {
overflow-y: hidden;
.go-preview-scale {
transform-origin: left top;
}
}
.go-preview-entity {
overflow: hidden;
}
}
</style>

View File

@ -14,7 +14,7 @@ import Preview from './index.vue'
let key = ref(Date.now())
// ->
;[SavePageEnum.JSON, SavePageEnum.CHART].forEach((saveEvent: string) => {
;[SavePageEnum.JSON, SavePageEnum.CHART_TO_PREVIEW].forEach((saveEvent: string) => {
if (!window.opener) return
window.opener.addEventListener(saveEvent, async (e: any) => {
const localStorageInfo: ChartEditStorageType = await getSessionStorageInfo() as unknown as ChartEditStorageType

View File

@ -45,8 +45,7 @@ const collapsed = ref<boolean>(false)
const { getAsideCollapsedWidth } = toRefs(useSettingStore())
const route = useRoute()
const routeRame = computed(() => route.name)
const menuValue = ref(routeRame)
const menuValue = computed(() => route.name)
const menuOptions = menuOptionsInit()