diff --git a/package-lock.json b/package-lock.json
index 829c48d7..45b86824 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,7 @@
"clipboard": "^2.0.11",
"crypto-js": "^4.2.0",
"dexie": "3.0.3",
+ "echarts": "^5.5.1",
"file-saver": "^2.0.5",
"hfmath": "^0.0.2",
"html-to-image": "^1.11.11",
@@ -2317,6 +2318,15 @@
"node": ">=8"
}
},
+ "node_modules/echarts": {
+ "version": "5.5.1",
+ "resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.5.1.tgz",
+ "integrity": "sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==",
+ "dependencies": {
+ "tslib": "2.3.0",
+ "zrender": "5.6.0"
+ }
+ },
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -4933,6 +4943,11 @@
"typescript": ">=4.2.0"
}
},
+ "node_modules/tslib": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
+ "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
+ },
"node_modules/txml": {
"version": "5.1.1",
"resolved": "https://registry.npmmirror.com/txml/-/txml-5.1.1.tgz",
@@ -5250,6 +5265,14 @@
"engines": {
"node": ">=10"
}
+ },
+ "node_modules/zrender": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.6.0.tgz",
+ "integrity": "sha512-uzgraf4njmmHAbEUxMJ8Oxg+P3fT04O+9p7gY+wJRVxo8Ge+KmYv0WJev945EH4wFuc4OY2NLXz46FZrWS9xJg==",
+ "dependencies": {
+ "tslib": "2.3.0"
+ }
}
},
"dependencies": {
@@ -6850,6 +6873,15 @@
"is-obj": "^2.0.0"
}
},
+ "echarts": {
+ "version": "5.5.1",
+ "resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.5.1.tgz",
+ "integrity": "sha512-Fce8upazaAXUVUVsjgV6mBnGuqgO+JNDlcgF79Dksy4+wgGpQB2lmYoO4TSweFg/mZITdpGHomw/cNBJZj1icA==",
+ "requires": {
+ "tslib": "2.3.0",
+ "zrender": "5.6.0"
+ }
+ },
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -8929,6 +8961,11 @@
"dev": true,
"requires": {}
},
+ "tslib": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
+ "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
+ },
"txml": {
"version": "5.1.1",
"resolved": "https://registry.npmmirror.com/txml/-/txml-5.1.1.tgz",
@@ -9137,6 +9174,14 @@
"resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz",
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
"dev": true
+ },
+ "zrender": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.6.0.tgz",
+ "integrity": "sha512-uzgraf4njmmHAbEUxMJ8Oxg+P3fT04O+9p7gY+wJRVxo8Ge+KmYv0WJev945EH4wFuc4OY2NLXz46FZrWS9xJg==",
+ "requires": {
+ "tslib": "2.3.0"
+ }
}
}
}
diff --git a/package.json b/package.json
index a2484bf9..fa964b5a 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"clipboard": "^2.0.11",
"crypto-js": "^4.2.0",
"dexie": "3.0.3",
+ "echarts": "^5.5.1",
"file-saver": "^2.0.5",
"hfmath": "^0.0.2",
"html-to-image": "^1.11.11",
diff --git a/src/configs/chart.ts b/src/configs/chart.ts
new file mode 100644
index 00000000..d289d9f2
--- /dev/null
+++ b/src/configs/chart.ts
@@ -0,0 +1,54 @@
+import type { ChartData } from '@/types/slides'
+
+export const CHART_DEFAULT_DATA: { [key: string]: ChartData } = {
+ 'bar': {
+ labels: ['类别1', '类别2', '类别3', '类别4', '类别5'],
+ legends: ['系列1', '系列2'],
+ series: [[12, 19, 5, 2, 18], [7, 11, 13, 21, 9]],
+ },
+ 'column': {
+ labels: ['类别1', '类别2', '类别3', '类别4', '类别5'],
+ legends: ['系列1', '系列2'],
+ series: [[12, 19, 5, 2, 18], [7, 11, 13, 21, 9]],
+ },
+ 'line': {
+ labels: ['类别1', '类别2', '类别3', '类别4', '类别5'],
+ legends: ['系列1', '系列2'],
+ series: [[12, 19, 5, 2, 18], [7, 11, 13, 21, 9]],
+ },
+ 'pie': {
+ labels: ['类别1', '类别2', '类别3', '类别4', '类别5'],
+ legends: ['值'],
+ series: [[12, 19, 5, 2, 18]],
+ },
+ 'ring': {
+ labels: ['类别1', '类别2', '类别3', '类别4', '类别5'],
+ legends: ['值'],
+ series: [[12, 19, 5, 2, 18]],
+ },
+ 'area': {
+ labels: ['类别1', '类别2', '类别3', '类别4', '类别5'],
+ legends: ['系列1', '系列2'],
+ series: [[12, 19, 5, 2, 18], [7, 11, 13, 21, 9]],
+ },
+ 'scatter': {
+ labels: ['坐标1', '坐标2', '坐标3', '坐标4', '坐标5'],
+ legends: ['X', 'Y'],
+ series: [[12, 19, 5, 2, 18], [7, 11, 13, 21, 9]],
+ },
+}
+
+export const CHART_PRESET_THEMES = [
+ ['#d87c7c', '#919e8b', '#d7ab82', '#6e7074', '#61a0a8', '#efa18d'],
+ ['#dd6b66', '#759aa0', '#e69d87', '#8dc1a9', '#ea7e53', '#eedd78'],
+ ['#516b91', '#59c4e6', '#edafda', '#93b7e3', '#a5e7f0', '#cbb0e3'],
+ ['#893448', '#d95850', '#eb8146', '#ffb248', '#f2d643', '#ebdba4'],
+ ['#4ea397', '#22c3aa', '#7bd9a5', '#d0648a', '#f58db2', '#f2b3c9'],
+ ['#3fb1e3', '#6be6c1', '#626c91', '#a0a7e6', '#c4ebad', '#96dee8'],
+ ['#fc97af', '#87f7cf', '#f7f494', '#72ccff', '#f7c5a0', '#d4a4eb'],
+ ['#c1232b', '#27727b', '#fcce10', '#e87c25', '#b5c334', '#fe8463'],
+ ['#2ec7c9', '#b6a2de', '#5ab1ef', '#ffb980', '#d87a80', '#8d98b3'],
+ ['#e01f54', '#001852', '#f5e8c8', '#b8d2c7', '#c6b38e', '#a4d8c2'],
+ ['#c12e34', '#e6b600', '#0098d9', '#2b821d', '#005eaa', '#339ca8'],
+ ['#8a7ca8', '#e098c7', '#8fd3e8', '#71669e', '#cc70af', '#7cb4cc'],
+]
\ No newline at end of file
diff --git a/src/configs/chartTypes.ts b/src/configs/chartTypes.ts
deleted file mode 100644
index 400821f7..00000000
--- a/src/configs/chartTypes.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { ChartType } from '@/types/slides'
-
-interface ChartTypes {
- [propName: string]: ChartType
-}
-
-export const CHART_TYPES: ChartTypes = {
- bar: 'bar',
- horizontalBar: 'bar',
- line: 'line',
- area: 'line',
- scatter: 'line',
- pie: 'pie',
- ring: 'pie',
-}
\ No newline at end of file
diff --git a/src/hooks/useCreateElement.ts b/src/hooks/useCreateElement.ts
index a9fef573..570534d5 100644
--- a/src/hooks/useCreateElement.ts
+++ b/src/hooks/useCreateElement.ts
@@ -2,10 +2,10 @@ import { storeToRefs } from 'pinia'
import { nanoid } from 'nanoid'
import { useMainStore, useSlidesStore } from '@/store'
import { getImageSize } from '@/utils/image'
-import type { PPTLineElement, PPTElement, TableCell, TableCellStyle, PPTShapeElement, PPTChartElement, ChartOptions, PresetChartType } from '@/types/slides'
+import type { PPTLineElement, PPTElement, TableCell, TableCellStyle, PPTShapeElement, ChartType } from '@/types/slides'
import { type ShapePoolItem, SHAPE_PATH_FORMULAS } from '@/configs/shapes'
import type { LinePoolItem } from '@/configs/lines'
-import { CHART_TYPES } from '@/configs/chartTypes'
+import { CHART_DEFAULT_DATA } from '@/configs/chart'
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
interface CommonElementPosition {
@@ -86,40 +86,19 @@ export default () => {
* 创建图表元素
* @param chartType 图表类型
*/
- const createChartElement = (type: PresetChartType) => {
- const newElement: PPTChartElement = {
+ const createChartElement = (type: ChartType) => {
+ createElement({
type: 'chart',
id: nanoid(10),
- chartType: CHART_TYPES[type],
+ chartType: type,
left: 300,
top: 81.25,
width: 400,
height: 400,
rotate: 0,
- themeColor: [theme.value.themeColor],
- gridColor: theme.value.fontColor,
- data: {
- labels: ['类别1', '类别2', '类别3', '类别4', '类别5'],
- legends: ['系列1'],
- series: [
- [12, 19, 5, 2, 18],
- ],
- },
- }
-
- const options: ChartOptions = {
- ...(type === 'bar' ? { horizontalBars: false, stackBars: false } : {}),
- ...(type === 'horizontalBar' ? { horizontalBars: true, stackBars: false } : {}),
- ...(type === 'line' ? { showLine: true, lineSmooth: true, showArea: false } : {}),
- ...(type === 'area' ? { showLine: true, lineSmooth: true, showArea: true } : {}),
- ...(type === 'scatter' ? { showLine: false, lineSmooth: true, showArea: false } : {}),
- ...(type === 'pie' ? { donut: false } : {}),
- ...(type === 'ring' ? { donut: true } : {}),
- }
-
- createElement({
- ...newElement,
- options,
+ themeColors: [theme.value.themeColor],
+ textColor: theme.value.fontColor,
+ data: CHART_DEFAULT_DATA[type],
})
}
diff --git a/src/hooks/useExport.ts b/src/hooks/useExport.ts
index d8e5fdfc..9e997385 100644
--- a/src/hooks/useExport.ts
+++ b/src/hooks/useExport.ts
@@ -611,12 +611,12 @@ export default () => {
}
let chartColors: string[] = []
- if (el.themeColor.length === 10) chartColors = el.themeColor.map(color => formatColor(color).color)
- else if (el.themeColor.length === 1) chartColors = tinycolor(el.themeColor[0]).analogous(10).map(color => formatColor(color.toHexString()).color)
+ if (el.themeColors.length === 10) chartColors = el.themeColors.map(color => formatColor(color).color)
+ else if (el.themeColors.length === 1) chartColors = tinycolor(el.themeColors[0]).analogous(10).map(color => formatColor(color.toHexString()).color)
else {
- const len = el.themeColor.length
- const supplement = tinycolor(el.themeColor[len - 1]).analogous(10 + 1 - len).map(color => color.toHexString())
- chartColors = [...el.themeColor.slice(0, len - 1), ...supplement].map(color => formatColor(color).color)
+ const len = el.themeColors.length
+ const supplement = tinycolor(el.themeColors[len - 1]).analogous(10 + 1 - len).map(color => color.toHexString())
+ chartColors = [...el.themeColors.slice(0, len - 1), ...supplement].map(color => formatColor(color).color)
}
const options: pptxgen.IChartOpts = {
@@ -624,40 +624,63 @@ export default () => {
y: el.top / ratioPx2Inch.value,
w: el.width / ratioPx2Inch.value,
h: el.height / ratioPx2Inch.value,
- chartColors: el.chartType === 'pie' ? chartColors : chartColors.slice(0, el.data.series.length),
+ chartColors: (el.chartType === 'pie' || el.chartType === 'ring') ? chartColors : chartColors.slice(0, el.data.series.length),
}
- if (el.fill) options.plotArea = { fill: { color: formatColor(el.fill).color } }
- if (el.legend) {
+ const textColor = formatColor(el.textColor || '#000000').color
+ options.catAxisLabelColor = textColor
+ options.valAxisLabelColor = textColor
+
+ const fontSize = 14 / ratioPx2Pt.value
+ options.catAxisLabelFontSize = fontSize
+ options.valAxisLabelFontSize = fontSize
+
+ if (el.fill || el.outline) {
+ const plotArea: pptxgen.IChartPropsFillLine = {}
+ if (el.fill) {
+ plotArea.fill = { color: formatColor(el.fill).color }
+ }
+ if (el.outline) {
+ plotArea.border = {
+ pt: el.outline.width! / ratioPx2Pt.value,
+ color: formatColor(el.outline.color!).color,
+ }
+ }
+ options.plotArea = plotArea
+ }
+
+ if ((el.data.series.length > 1 && el.chartType !== 'scatter') || el.chartType === 'pie' || el.chartType === 'ring') {
options.showLegend = true
- options.legendPos = el.legend === 'top' ? 't' : 'b'
- options.legendColor = formatColor(el.gridColor || '#000000').color
- options.legendFontSize = 14 / ratioPx2Pt.value
+ options.legendPos = 'b'
+ options.legendColor = textColor
+ options.legendFontSize = fontSize
}
let type = pptx.ChartType.bar
if (el.chartType === 'bar') {
type = pptx.ChartType.bar
- options.barDir = el.options?.horizontalBars ? 'bar' : 'col'
+ options.barDir = 'col'
+ }
+ else if (el.chartType === 'column') {
+ type = pptx.ChartType.bar
+ options.barDir = 'bar'
}
else if (el.chartType === 'line') {
- if (el.options?.showArea) type = pptx.ChartType.area
- else if (el.options?.showLine === false) {
- type = pptx.ChartType.scatter
-
- chartData.unshift({ name: 'X-Axis', values: Array(el.data.series[0].length).fill(0).map((v, i) => i) })
- options.lineSize = 0
- }
- else type = pptx.ChartType.line
-
- if (el.options?.lineSmooth) options.lineSmooth = true
+ type = pptx.ChartType.line
+ }
+ else if (el.chartType === 'area') {
+ type = pptx.ChartType.area
+ }
+ else if (el.chartType === 'scatter') {
+ type = pptx.ChartType.scatter
+ options.lineSize = 0
}
else if (el.chartType === 'pie') {
- if (el.options?.donut) {
- type = pptx.ChartType.doughnut
- options.holeSize = 75
- }
- else type = pptx.ChartType.pie
+ type = pptx.ChartType.pie
+ }
+ else if (el.chartType === 'ring') {
+ type = pptx.ChartType.doughnut
+ options.holeSize = 60
}
pptxSlide.addChart(type, chartData, options)
diff --git a/src/hooks/useImport.ts b/src/hooks/useImport.ts
index 2365f610..ee303b2c 100644
--- a/src/hooks/useImport.ts
+++ b/src/hooks/useImport.ts
@@ -14,7 +14,6 @@ import type {
TableCellStyle,
TableCell,
ChartType,
- ChartOptions,
SlideBackground,
PPTShapeElement,
PPTLineElement,
@@ -389,10 +388,9 @@ export default () => {
let series: number[][]
if (el.chartType === 'scatterChart' || el.chartType === 'bubbleChart') {
- const data = el.data
- labels = data[0].map(item => item + '')
- legends = ['系列1']
- series = [data[1]]
+ labels = el.data[0].map((item, index) => `坐标${index + 1}`)
+ legends = ['X', 'Y']
+ series = el.data
}
else {
const data = el.data as ChartItem[]
@@ -401,32 +399,32 @@ export default () => {
series = data.map(item => item.values.map(v => v.y))
}
- const options: ChartOptions = {}
-
let chartType: ChartType = 'bar'
switch (el.chartType) {
case 'barChart':
case 'bar3DChart':
chartType = 'bar'
- if (el.barDir === 'bar') options.horizontalBars = true
- if (el.grouping === 'stacked' || el.grouping === 'percentStacked') options.stackBars = true
+ if (el.barDir === 'bar') chartType = 'column'
break
case 'lineChart':
case 'line3DChart':
+ chartType = 'line'
+ break
case 'areaChart':
case 'area3DChart':
+ chartType = 'area'
+ break
case 'scatterChart':
case 'bubbleChart':
- chartType = 'line'
- if (el.chartType === 'areaChart' || el.chartType === 'area3DChart') options.showArea = true
- if (el.chartType === 'scatterChart' || el.chartType === 'bubbleChart') options.showLine = false
+ chartType = 'scatter'
break
case 'pieChart':
case 'pie3DChart':
- case 'doughnutChart':
chartType = 'pie'
- if (el.chartType === 'doughnutChart') options.donut = true
+ break
+ case 'doughnutChart':
+ chartType = 'ring'
break
default:
}
@@ -440,14 +438,13 @@ export default () => {
left: el.left,
top: el.top,
rotate: 0,
- themeColor: [theme.value.themeColor],
- gridColor: theme.value.fontColor,
+ themeColors: [theme.value.themeColor],
+ textColor: theme.value.fontColor,
data: {
labels,
legends,
series,
},
- options,
})
}
else if (el.type === 'group' || el.type === 'diagram') {
diff --git a/src/types/slides.ts b/src/types/slides.ts
index ce5a9fd3..f71db1dd 100644
--- a/src/types/slides.ts
+++ b/src/types/slides.ts
@@ -395,9 +395,7 @@ export interface PPTLineElement extends Omit