mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
feat: 图表支持图例(#45)
This commit is contained in:
parent
3f364e6801
commit
1265c9536d
@ -94,6 +94,7 @@ export default () => {
|
|||||||
gridColor: fontColor.value,
|
gridColor: fontColor.value,
|
||||||
data: {
|
data: {
|
||||||
labels: ['类别1', '类别2', '类别3', '类别4', '类别5'],
|
labels: ['类别1', '类别2', '类别3', '类别4', '类别5'],
|
||||||
|
legends: ['系列1'],
|
||||||
series: [
|
series: [
|
||||||
[12, 19, 5, 2, 18],
|
[12, 19, 5, 2, 18],
|
||||||
],
|
],
|
||||||
|
@ -400,6 +400,12 @@ export default () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (el.fill) options.fill = formatColor(el.fill).color
|
if (el.fill) options.fill = formatColor(el.fill).color
|
||||||
|
if (el.legend) {
|
||||||
|
options.showLegend = true
|
||||||
|
options.legendPos = el.legend === 'top' ? 't' : 'b'
|
||||||
|
options.legendColor = formatColor(el.gridColor || '#000000').color
|
||||||
|
options.legendFontSize = 14 * 0.75
|
||||||
|
}
|
||||||
|
|
||||||
let type = pptx.ChartType.bar
|
let type = pptx.ChartType.bar
|
||||||
if (el.chartType === 'bar') {
|
if (el.chartType === 'bar') {
|
||||||
|
@ -325,6 +325,7 @@ export interface PPTLineElement extends Omit<PPTBaseElement, 'height'> {
|
|||||||
export type ChartType = 'bar' | 'line' | 'pie'
|
export type ChartType = 'bar' | 'line' | 'pie'
|
||||||
export interface ChartData {
|
export interface ChartData {
|
||||||
labels: string[];
|
labels: string[];
|
||||||
|
legends: string[];
|
||||||
series: number[][];
|
series: number[][];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,6 +347,8 @@ export interface ChartData {
|
|||||||
* themeColor: 主题色
|
* themeColor: 主题色
|
||||||
*
|
*
|
||||||
* gridColor?: 网格&坐标颜色
|
* gridColor?: 网格&坐标颜色
|
||||||
|
*
|
||||||
|
* legend?: 图例/位置
|
||||||
*/
|
*/
|
||||||
export interface PPTChartElement extends PPTBaseElement {
|
export interface PPTChartElement extends PPTBaseElement {
|
||||||
type: 'chart';
|
type: 'chart';
|
||||||
@ -356,6 +359,7 @@ export interface PPTChartElement extends PPTBaseElement {
|
|||||||
outline?: PPTElementOutline;
|
outline?: PPTElementOutline;
|
||||||
themeColor: string[];
|
themeColor: string[];
|
||||||
gridColor?: string;
|
gridColor?: string;
|
||||||
|
legend?: '' | 'top' | 'bottom',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,8 +23,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="rowIndex in 30" :key="rowIndex">
|
<tr v-for="rowIndex in 31" :key="rowIndex">
|
||||||
<td v-for="colIndex in 7" :key="colIndex" :class="{ 'head': colIndex === 1 && rowIndex <= selectedRange[1] }">
|
<td
|
||||||
|
v-for="colIndex in 7"
|
||||||
|
:key="colIndex"
|
||||||
|
:class="{ 'head': (colIndex === 1 && rowIndex <= selectedRange[1]) || (rowIndex === 1 && colIndex <= selectedRange[0]) }"
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
:class="['item', { 'selected': rowIndex <= selectedRange[1] && colIndex <= selectedRange[0] }]"
|
:class="['item', { 'selected': rowIndex <= selectedRange[1] && colIndex <= selectedRange[0] }]"
|
||||||
:id="`cell-${rowIndex - 1}-${colIndex - 1}`"
|
:id="`cell-${rowIndex - 1}-${colIndex - 1}`"
|
||||||
@ -38,8 +42,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="btns">
|
<div class="btns">
|
||||||
|
<div class="left">
|
||||||
|
<Button class="btn" @click="clear()">清空</Button>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
<Button class="btn" @click="closeEditor()">取消</Button>
|
<Button class="btn" @click="closeEditor()">取消</Button>
|
||||||
<Button type="primary" class="btn" @click="getTableData()">确认</Button>
|
<Button type="primary" class="btn" @click="getTableData()" style="margin-left: 10px;">确认</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -89,10 +98,11 @@ export default defineComponent({
|
|||||||
const initData = () => {
|
const initData = () => {
|
||||||
const _data: string[][] = []
|
const _data: string[][] = []
|
||||||
|
|
||||||
const { labels, series } = props.data
|
const { labels, legends, series } = props.data
|
||||||
const rowCount = labels.length
|
const rowCount = labels.length
|
||||||
const colCount = series.length
|
const colCount = series.length
|
||||||
|
|
||||||
|
_data.push(['', ...legends])
|
||||||
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
||||||
const row = [labels[rowIndex]]
|
const row = [labels[rowIndex]]
|
||||||
for (let colIndex = 0; colIndex < colCount; colIndex++) {
|
for (let colIndex = 0; colIndex < colCount; colIndex++) {
|
||||||
@ -101,7 +111,7 @@ export default defineComponent({
|
|||||||
_data.push(row)
|
_data.push(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
for (let rowIndex = 0; rowIndex < rowCount + 1; rowIndex++) {
|
||||||
for (let colIndex = 0; colIndex < colCount + 1; colIndex++) {
|
for (let colIndex = 0; colIndex < colCount + 1; colIndex++) {
|
||||||
const inputRef = document.querySelector(`#cell-${rowIndex}-${colIndex}`) as HTMLInputElement
|
const inputRef = document.querySelector(`#cell-${rowIndex}-${colIndex}`) as HTMLInputElement
|
||||||
if (!inputRef) continue
|
if (!inputRef) continue
|
||||||
@ -109,7 +119,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedRange.value = [colCount + 1, rowCount]
|
selectedRange.value = [colCount + 1, rowCount + 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(initData)
|
onMounted(initData)
|
||||||
@ -140,19 +150,26 @@ export default defineComponent({
|
|||||||
const [col, row] = selectedRange.value
|
const [col, row] = selectedRange.value
|
||||||
|
|
||||||
const labels: string[] = []
|
const labels: string[] = []
|
||||||
|
const legends: string[] = []
|
||||||
const series: number[][] = []
|
const series: number[][] = []
|
||||||
|
|
||||||
// 第一列为系列名,实际数据从第二列开始
|
// 第一行为系列名,第一列为项目名,实际数据从第二行第二列开始
|
||||||
for (let rowIndex = 0; rowIndex < row; rowIndex++) {
|
for (let rowIndex = 1; rowIndex < row; rowIndex++) {
|
||||||
let labelsItem = `类别${rowIndex + 1}`
|
let labelsItem = `类别${rowIndex}`
|
||||||
const labelInputRef = document.querySelector(`#cell-${rowIndex}-0`) as HTMLInputElement
|
const labelInputRef = document.querySelector(`#cell-${rowIndex}-0`) as HTMLInputElement
|
||||||
if (labelInputRef && labelInputRef.value) labelsItem = labelInputRef.value
|
if (labelInputRef && labelInputRef.value) labelsItem = labelInputRef.value
|
||||||
labels.push(labelsItem)
|
labels.push(labelsItem)
|
||||||
}
|
}
|
||||||
|
for (let colIndex = 1; colIndex < col; colIndex++) {
|
||||||
|
let legendsItem = `系列${colIndex}`
|
||||||
|
const labelInputRef = document.querySelector(`#cell-0-${colIndex}`) as HTMLInputElement
|
||||||
|
if (labelInputRef && labelInputRef.value) legendsItem = labelInputRef.value
|
||||||
|
legends.push(legendsItem)
|
||||||
|
}
|
||||||
|
|
||||||
for (let colIndex = 1; colIndex < col; colIndex++) {
|
for (let colIndex = 1; colIndex < col; colIndex++) {
|
||||||
const seriesItem = []
|
const seriesItem = []
|
||||||
for (let rowIndex = 0; rowIndex < row; rowIndex++) {
|
for (let rowIndex = 1; rowIndex < row; rowIndex++) {
|
||||||
const valueInputRef = document.querySelector(`#cell-${rowIndex}-${colIndex}`) as HTMLInputElement
|
const valueInputRef = document.querySelector(`#cell-${rowIndex}-${colIndex}`) as HTMLInputElement
|
||||||
let value = 0
|
let value = 0
|
||||||
if (valueInputRef && valueInputRef.value && !!(+valueInputRef.value)) {
|
if (valueInputRef && valueInputRef.value && !!(+valueInputRef.value)) {
|
||||||
@ -162,8 +179,19 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
series.push(seriesItem)
|
series.push(seriesItem)
|
||||||
}
|
}
|
||||||
const data = { labels, series }
|
|
||||||
emit('save', data)
|
emit('save', { labels, legends, series })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清空表格数据
|
||||||
|
const clear = () => {
|
||||||
|
for (let rowIndex = 1; rowIndex < 31; rowIndex++) {
|
||||||
|
for (let colIndex = 1; colIndex < 7; colIndex++) {
|
||||||
|
const inputRef = document.querySelector(`#cell-${rowIndex}-${colIndex}`) as HTMLInputElement
|
||||||
|
if (!inputRef) continue
|
||||||
|
inputRef.value = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关闭图表数据编辑器
|
// 关闭图表数据编辑器
|
||||||
@ -230,6 +258,7 @@ export default defineComponent({
|
|||||||
changeSelectRange,
|
changeSelectRange,
|
||||||
getTableData,
|
getTableData,
|
||||||
closeEditor,
|
closeEditor,
|
||||||
|
clear,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ -346,10 +375,7 @@ table {
|
|||||||
}
|
}
|
||||||
.btns {
|
.btns {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
text-align: right;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
.btn {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -41,6 +41,17 @@
|
|||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div style="flex: 2;">图例:</div>
|
||||||
|
<Select style="flex: 3;" :value="legend" @change="value => updateLegend(value)">
|
||||||
|
<SelectOption value="">不显示</SelectOption>
|
||||||
|
<SelectOption value="top">显示在上方</SelectOption>
|
||||||
|
<SelectOption value="bottom">显示在下方</SelectOption>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div style="flex: 2;">背景填充:</div>
|
<div style="flex: 2;">背景填充:</div>
|
||||||
<Popover trigger="click">
|
<Popover trigger="click">
|
||||||
@ -145,6 +156,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
const themeColor = ref<string[]>([])
|
const themeColor = ref<string[]>([])
|
||||||
const gridColor = ref('')
|
const gridColor = ref('')
|
||||||
|
const legend = ref('')
|
||||||
|
|
||||||
const lineSmooth = ref(true)
|
const lineSmooth = ref(true)
|
||||||
const showLine = ref(true)
|
const showLine = ref(true)
|
||||||
@ -174,6 +186,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
themeColor.value = handleElement.value.themeColor
|
themeColor.value = handleElement.value.themeColor
|
||||||
gridColor.value = handleElement.value.gridColor || 'rgba(0, 0, 0, 0.4)'
|
gridColor.value = handleElement.value.gridColor || 'rgba(0, 0, 0, 0.4)'
|
||||||
|
legend.value = handleElement.value.legend || ''
|
||||||
}, { deep: true, immediate: true })
|
}, { deep: true, immediate: true })
|
||||||
|
|
||||||
// 设置图表数据
|
// 设置图表数据
|
||||||
@ -234,6 +247,13 @@ export default defineComponent({
|
|||||||
addHistorySnapshot()
|
addHistorySnapshot()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设置图例位置/不显示
|
||||||
|
const updateLegend = (legend: '' | 'top' | 'bottom') => {
|
||||||
|
const props = { legend }
|
||||||
|
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||||
|
addHistorySnapshot()
|
||||||
|
}
|
||||||
|
|
||||||
const openDataEditor = () => chartDataEditorVisible.value = true
|
const openDataEditor = () => chartDataEditorVisible.value = true
|
||||||
|
|
||||||
emitter.on(EmitterEvents.OPEN_CHART_DATA_EDITOR, openDataEditor)
|
emitter.on(EmitterEvents.OPEN_CHART_DATA_EDITOR, openDataEditor)
|
||||||
@ -255,10 +275,12 @@ export default defineComponent({
|
|||||||
updateOptions,
|
updateOptions,
|
||||||
themeColor,
|
themeColor,
|
||||||
gridColor,
|
gridColor,
|
||||||
|
legend,
|
||||||
updateTheme,
|
updateTheme,
|
||||||
addThemeColor,
|
addThemeColor,
|
||||||
deleteThemeColor,
|
deleteThemeColor,
|
||||||
updateGridColor,
|
updateGridColor,
|
||||||
|
updateLegend,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -1,19 +1,33 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="chart">
|
<div
|
||||||
|
class="chart"
|
||||||
|
:style="{ flexDirection: legend === 'top' ? 'column-reverse' : 'column' }"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="chart-content"
|
class="chart-content"
|
||||||
ref="chartRef"
|
ref="chartRef"
|
||||||
:style="{
|
:style="{
|
||||||
width: width + 'px',
|
width: width + 'px',
|
||||||
height: height + 'px',
|
height: chartHeight + 'px',
|
||||||
transform: `scale(${1 / slideScale})`,
|
transform: `scale(${1 / slideScale})`,
|
||||||
}"
|
}"
|
||||||
></div>
|
></div>
|
||||||
|
<div class="legends" :style="{ transform: `scale(${1 / slideScale})` }" v-if="legend">
|
||||||
|
<div
|
||||||
|
class="legend"
|
||||||
|
v-for="(legend, index) in legends"
|
||||||
|
:key="index"
|
||||||
|
:style="{ color: gridColor }"
|
||||||
|
>
|
||||||
|
<div class="block" :style="{ backgroundColor: themeColors[index] }"></div>
|
||||||
|
{{legend}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, inject, onMounted, PropType, ref, Ref, watch } from 'vue'
|
import { computed, defineComponent, inject, onMounted, PropType, ref, Ref, watch } from 'vue'
|
||||||
import { upperFirst } from 'lodash'
|
import { upperFirst } from 'lodash'
|
||||||
import tinycolor from 'tinycolor2'
|
import tinycolor from 'tinycolor2'
|
||||||
import Chartist, {
|
import Chartist, {
|
||||||
@ -54,9 +68,16 @@ export default defineComponent({
|
|||||||
type: Array as PropType<string[]>,
|
type: Array as PropType<string[]>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
legends: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
gridColor: {
|
gridColor: {
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
|
legend: {
|
||||||
|
type: String as PropType<'' | 'top' | 'bottom'>,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const chartRef = ref<HTMLElement>()
|
const chartRef = ref<HTMLElement>()
|
||||||
@ -64,12 +85,17 @@ export default defineComponent({
|
|||||||
|
|
||||||
let chart: IChartistLineChart | IChartistBarChart | IChartistPieChart | undefined
|
let chart: IChartistLineChart | IChartistBarChart | IChartistPieChart | undefined
|
||||||
|
|
||||||
|
const chartHeight = computed(() => {
|
||||||
|
if (props.legend) return props.height - 20
|
||||||
|
return props.height
|
||||||
|
})
|
||||||
|
|
||||||
const getDataAndOptions = () => {
|
const getDataAndOptions = () => {
|
||||||
const propsOptopns = props.options || {}
|
const propsOptopns = props.options || {}
|
||||||
const options = {
|
const options = {
|
||||||
...propsOptopns,
|
...propsOptopns,
|
||||||
width: props.width * slideScale.value,
|
width: props.width * slideScale.value,
|
||||||
height: props.height * slideScale.value,
|
height: chartHeight.value * slideScale.value,
|
||||||
}
|
}
|
||||||
const data = props.type === 'pie' ? { ...props.data, series: props.data.series[0] } : props.data
|
const data = props.type === 'pie' ? { ...props.data, series: props.data.series[0] } : props.data
|
||||||
return { data, options }
|
return { data, options }
|
||||||
@ -101,11 +127,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
onMounted(renderChart)
|
onMounted(renderChart)
|
||||||
|
|
||||||
// 更新主题配色:
|
const themeColors = computed(() => {
|
||||||
// 如果当前所设置的主题色数小于10,剩余部分获取最后一个主题色的相近颜色作为配色
|
|
||||||
const updateTheme = () => {
|
|
||||||
if (!chartRef.value) return
|
|
||||||
|
|
||||||
let colors: string[] = []
|
let colors: string[] = []
|
||||||
if (props.themeColor.length === 10) colors = props.themeColor
|
if (props.themeColor.length === 10) colors = props.themeColor
|
||||||
else if (props.themeColor.length === 1) colors = tinycolor(props.themeColor[0]).analogous(10).map(color => color.toHexString())
|
else if (props.themeColor.length === 1) colors = tinycolor(props.themeColor[0]).analogous(10).map(color => color.toHexString())
|
||||||
@ -114,13 +136,20 @@ export default defineComponent({
|
|||||||
const supplement = tinycolor(props.themeColor[len - 1]).analogous(10 + 1 - len).map(color => color.toHexString())
|
const supplement = tinycolor(props.themeColor[len - 1]).analogous(10 + 1 - len).map(color => color.toHexString())
|
||||||
colors = [...props.themeColor.slice(0, len - 1), ...supplement]
|
colors = [...props.themeColor.slice(0, len - 1), ...supplement]
|
||||||
}
|
}
|
||||||
|
return colors
|
||||||
|
})
|
||||||
|
|
||||||
|
// 更新主题配色:
|
||||||
|
// 如果当前所设置的主题色数小于10,剩余部分获取最后一个主题色的相近颜色作为配色
|
||||||
|
const updateTheme = () => {
|
||||||
|
if (!chartRef.value) return
|
||||||
|
|
||||||
for (let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
chartRef.value.style.setProperty(`--theme-color-${i + 1}`, colors[i])
|
chartRef.value.style.setProperty(`--theme-color-${i + 1}`, themeColors.value[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => props.themeColor, updateTheme)
|
watch(themeColors, updateTheme)
|
||||||
onMounted(updateTheme)
|
onMounted(updateTheme)
|
||||||
|
|
||||||
// 更新网格颜色,包括坐标的文字部分
|
// 更新网格颜色,包括坐标的文字部分
|
||||||
@ -133,6 +162,8 @@ export default defineComponent({
|
|||||||
onMounted(updateGridColor)
|
onMounted(updateGridColor)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
chartHeight,
|
||||||
|
themeColors,
|
||||||
slideScale,
|
slideScale,
|
||||||
chartRef,
|
chartRef,
|
||||||
}
|
}
|
||||||
@ -141,6 +172,10 @@ export default defineComponent({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.chart {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
.chart-content {
|
.chart-content {
|
||||||
transform-origin: 0 0;
|
transform-origin: 0 0;
|
||||||
}
|
}
|
||||||
@ -194,4 +229,26 @@ export default defineComponent({
|
|||||||
color: var(--grid-color);
|
color: var(--grid-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.legends {
|
||||||
|
height: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.legend {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
& + .legend {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.block {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -26,6 +26,8 @@
|
|||||||
:options="elementInfo.options"
|
:options="elementInfo.options"
|
||||||
:themeColor="elementInfo.themeColor"
|
:themeColor="elementInfo.themeColor"
|
||||||
:gridColor="elementInfo.gridColor"
|
:gridColor="elementInfo.gridColor"
|
||||||
|
:legends="elementInfo.data.legends"
|
||||||
|
:legend="elementInfo.legend || ''"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
:options="elementInfo.options"
|
:options="elementInfo.options"
|
||||||
:themeColor="elementInfo.themeColor"
|
:themeColor="elementInfo.themeColor"
|
||||||
:gridColor="elementInfo.gridColor"
|
:gridColor="elementInfo.gridColor"
|
||||||
|
:legends="elementInfo.data.legends"
|
||||||
|
:legend="elementInfo.legend || ''"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user