feat: 图表添加配置(平滑曲线、堆叠模式)

This commit is contained in:
zxc 2024-09-13 22:58:20 +08:00
parent 495799aafa
commit 2e4a3df988
8 changed files with 110 additions and 30 deletions

View File

@ -660,13 +660,16 @@ export default () => {
if (el.chartType === 'bar') {
type = pptx.ChartType.bar
options.barDir = 'col'
if (el.options?.stack) options.barGrouping = 'stacked'
}
else if (el.chartType === 'column') {
type = pptx.ChartType.bar
options.barDir = 'bar'
if (el.options?.stack) options.barGrouping = 'stacked'
}
else if (el.chartType === 'line') {
type = pptx.ChartType.line
if (el.options?.lineSmooth) options.lineSmooth = true
}
else if (el.chartType === 'area') {
type = pptx.ChartType.area

View File

@ -19,6 +19,7 @@ import type {
PPTLineElement,
ShapeTextAlign,
PPTTextElement,
ChartOptions,
} from '@/types/slides'
const convertFontSizePtToPx = (html: string, ratio: number) => {
@ -398,6 +399,8 @@ export default () => {
legends = data.map(item => item.key)
series = data.map(item => item.values.map(v => v.y))
}
const options: ChartOptions = {}
let chartType: ChartType = 'bar'
@ -406,6 +409,7 @@ export default () => {
case 'bar3DChart':
chartType = 'bar'
if (el.barDir === 'bar') chartType = 'column'
if (el.grouping === 'stacked' || el.grouping === 'percentStacked') options.stack = true
break
case 'lineChart':
case 'line3DChart':
@ -413,6 +417,7 @@ export default () => {
break
case 'areaChart':
case 'area3DChart':
if (el.grouping === 'stacked' || el.grouping === 'percentStacked') options.stack = true
chartType = 'area'
break
case 'scatterChart':
@ -445,6 +450,7 @@ export default () => {
legends,
series,
},
options,
})
}
else if (el.type === 'group' || el.type === 'diagram') {

View File

@ -394,6 +394,12 @@ export interface PPTLineElement extends Omit<PPTBaseElement, 'height' | 'rotate'
export type ChartType = 'bar' | 'column' | 'line' | 'pie' | 'ring' | 'area' | 'scatter'
export interface ChartOptions {
lineSmooth?: boolean
stack?: boolean
}
export interface ChartData {
labels: string[]
legends: string[]
@ -411,6 +417,8 @@ export interface ChartData {
*
* data: 图表数据
*
* options: 扩展选项
*
* outline?: 边框
*
* themeColors: 主题色
@ -422,6 +430,7 @@ export interface PPTChartElement extends PPTBaseElement {
fill?: string
chartType: ChartType
data: ChartData
options?: ChartOptions
outline?: PPTElementOutline
themeColors: string[]
textColor?: string

View File

@ -6,6 +6,24 @@
<Divider />
<template v-if="['bar', 'column', 'area', 'line'].includes(handleChartElement.chartType)">
<div class="row">
<Checkbox
v-if="handleChartElement.chartType === 'line'"
@update:value="value => updateOptions({ lineSmooth: value })"
:value="lineSmooth"
>使用平滑曲线</Checkbox>
<Checkbox
v-if="['bar', 'column', 'area'].includes(handleChartElement.chartType)"
@update:value="value => updateOptions({ stack: value })"
:value="stack"
style="flex: 1;"
>堆叠样式</Checkbox>
</div>
<Divider />
</template>
<div class="row">
<div style="width: 40%;">背景填充</div>
<Popover trigger="click" style="width: 60%;">
@ -99,7 +117,7 @@
import { onUnmounted, ref, watch, type Ref } from 'vue'
import { storeToRefs } from 'pinia'
import { useMainStore, useSlidesStore } from '@/store'
import type { ChartData, PPTChartElement } from '@/types/slides'
import type { ChartData, ChartOptions, PPTChartElement } from '@/types/slides'
import emitter, { EmitterEvents } from '@/utils/emitter'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
import { CHART_PRESET_THEMES } from '@/configs/chart'
@ -110,6 +128,7 @@ import ColorButton from '@/components/ColorButton.vue'
import ColorPicker from '@/components/ColorPicker/index.vue'
import Modal from '@/components/Modal.vue'
import Divider from '@/components/Divider.vue'
import Checkbox from '@/components/Checkbox.vue'
import Button from '@/components/Button.vue'
import ButtonGroup from '@/components/ButtonGroup.vue'
import Popover from '@/components/Popover.vue'
@ -131,11 +150,26 @@ const fill = ref<string>('#000')
const themeColors = ref<string[]>([])
const textColor = ref('')
const lineSmooth = ref(false)
const stack = ref(false)
watch(handleElement, () => {
if (!handleElement.value || handleElement.value.type !== 'chart') return
fill.value = handleElement.value.fill || '#fff'
lineSmooth.value = false
stack.value = false
if (handleElement.value.options) {
const {
lineSmooth: _lineSmooth,
stack: _stack,
} = handleElement.value.options
if (_lineSmooth !== undefined) lineSmooth.value = _lineSmooth
if (_stack !== undefined) stack.value = _stack
}
themeColors.value = handleElement.value.themeColors
textColor.value = handleElement.value.textColor || '#333'
}, { deep: true, immediate: true })
@ -156,6 +190,15 @@ const updateFill = (value: string) => {
updateElement({ fill: value })
}
//
const updateOptions = (optionProps: ChartOptions) => {
console.log(optionProps)
const _handleElement = handleElement.value as PPTChartElement
const newOptions = { ..._handleElement.options, ...optionProps }
updateElement({ options: newOptions })
}
//
const updateTheme = (color: string, index: number) => {
const props = {

View File

@ -29,7 +29,7 @@
:data="elementInfo.data"
:themeColors="elementInfo.themeColors"
:textColor="elementInfo.textColor"
:legends="elementInfo.data.legends"
:options="elementInfo.options"
/>
</div>
</div>

View File

@ -6,7 +6,7 @@
import { onMounted, ref, computed, watch } from 'vue'
import * as echarts from 'echarts'
import tinycolor from 'tinycolor2'
import type { ChartData, ChartType } from '@/types/slides'
import type { ChartData, ChartOptions, ChartType } from '@/types/slides'
import { getChartOption } from './chartOption'
const props = defineProps<{
@ -15,8 +15,8 @@ const props = defineProps<{
type: ChartType
data: ChartData
themeColors: string[]
legends: string[]
textColor?: string
options?: ChartOptions
}>()
let chart: echarts.ECharts | null = null
@ -40,6 +40,8 @@ const updateOption = () => {
data: props.data,
themeColors: themeColors.value,
textColor: props.textColor,
lineSmooth: props.options?.lineSmooth || false,
stack: props.options?.stack || false,
})
if (option) chart!.setOption(option, true)
}

View File

@ -6,6 +6,8 @@ export interface ChartOptionPayload {
data: ChartData
themeColors: string[]
textColor?: string
lineSmooth?: boolean
stack?: boolean
}
export const getChartOption = ({
@ -13,6 +15,8 @@ export const getChartOption = ({
data,
themeColors,
textColor,
lineSmooth,
stack,
}: ChartOptionPayload): echarts.EChartsOption | null => {
if(type === 'bar') {
return {
@ -39,14 +43,18 @@ export const getChartOption = ({
yAxis: {
type: 'value',
},
series: data.series.map((item, index) => ({
data: item,
name: data.legends[index],
type: 'bar',
label: {
show: true,
},
})),
series: data.series.map((item, index) => {
const seriesItem: echarts.SeriesOption = {
data: item,
name: data.legends[index],
type: 'bar',
label: {
show: true,
},
}
if (stack) seriesItem.stack = 'A'
return seriesItem
}),
}
}
if(type === 'column') {
@ -74,14 +82,18 @@ export const getChartOption = ({
xAxis: {
type: 'value',
},
series: data.series.map((item, index) => ({
data: item,
name: data.legends[index],
type: 'bar',
label: {
show: true,
},
})),
series: data.series.map((item, index) => {
const seriesItem: echarts.SeriesOption = {
data: item,
name: data.legends[index],
type: 'bar',
label: {
show: true,
},
}
if (stack) seriesItem.stack = 'A'
return seriesItem
}),
}
}
if(type === 'line') {
@ -113,6 +125,7 @@ export const getChartOption = ({
data: item,
name: data.legends[index],
type: 'line',
smooth: lineSmooth,
label: {
show: true,
},
@ -230,15 +243,19 @@ export const getChartOption = ({
yAxis: {
type: 'value',
},
series: data.series.map((item, index) => ({
data: item,
name: data.legends[index],
type: 'line',
areaStyle: {},
label: {
show: true,
},
})),
series: data.series.map((item, index) => {
const seriesItem: echarts.SeriesOption = {
data: item,
name: data.legends[index],
type: 'line',
areaStyle: {},
label: {
show: true,
},
}
if (stack) seriesItem.stack = 'A'
return seriesItem
}),
}
}
if(type === 'scatter') {

View File

@ -34,7 +34,7 @@
:data="elementInfo.data"
:themeColors="elementInfo.themeColors"
:textColor="elementInfo.textColor"
:legends="elementInfo.data.legends"
:options="elementInfo.options"
/>
</div>
</div>