mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
主题配置功能
This commit is contained in:
parent
90d878e9a3
commit
c0cf96a4b5
@ -54,7 +54,7 @@ export default defineComponent({
|
||||
else a = Math.round(left * 100 / containerWidth) / 100
|
||||
|
||||
if(color.value.a !== a) {
|
||||
emit('change', {
|
||||
emit('colorChange', {
|
||||
r: color.value.r,
|
||||
g: color.value.g,
|
||||
b: color.value.b,
|
||||
|
@ -30,7 +30,7 @@ export default defineComponent({
|
||||
|
||||
const handleInput = (e: InputEvent) => {
|
||||
const value = (e.target as HTMLInputElement).value
|
||||
if(value.length >= 6) emit('change', tinycolor(value).toRgb())
|
||||
if(value.length >= 6) emit('colorChange', tinycolor(value).toRgb())
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -71,7 +71,7 @@ export default defineComponent({
|
||||
h = (360 * percent / 100)
|
||||
}
|
||||
if(color.value.h !== h) {
|
||||
emit('change', {
|
||||
emit('colorChange', {
|
||||
h,
|
||||
l: color.value.l,
|
||||
s: color.value.s,
|
||||
|
@ -48,7 +48,7 @@ export default defineComponent({
|
||||
const pointerLeft = computed(() => color.value.s * 100 + '%')
|
||||
|
||||
const emitChangeEvent = throttle(function(param) {
|
||||
emit('change', param)
|
||||
emit('colorChange', param)
|
||||
}, 20, { leading: true, trailing: false })
|
||||
|
||||
const saturationRef = ref<HTMLElement>()
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="color-picker">
|
||||
<div class="picker-saturation-wrap">
|
||||
<Saturation :value="color" :hue="hue" @change="value => changeColor(value)" />
|
||||
<Saturation :value="color" :hue="hue" @colorChange="value => changeColor(value)" />
|
||||
</div>
|
||||
<div class="picker-controls">
|
||||
<div class="picker-color-wrap">
|
||||
@ -10,16 +10,16 @@
|
||||
</div>
|
||||
<div class="picker-sliders">
|
||||
<div class="picker-hue-wrap">
|
||||
<Hue :value="color" :hue="hue" @change="value => changeColor(value)" />
|
||||
<Hue :value="color" :hue="hue" @colorChange="value => changeColor(value)" />
|
||||
</div>
|
||||
<div class="picker-alpha-wrap">
|
||||
<Alpha :value="color" @change="value => changeColor(value)" />
|
||||
<Alpha :value="color" @colorChange="value => changeColor(value)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="picker-field">
|
||||
<EditableInput :value="color" @change="value => changeColor(value)" />
|
||||
<EditableInput :value="color" @colorChange="value => changeColor(value)" />
|
||||
</div>
|
||||
|
||||
<div class="picker-presets">
|
||||
|
@ -1,7 +1,3 @@
|
||||
import { PPTElementOutline } from '@/types/slides'
|
||||
|
||||
const DEFAULT_COLOR = '#d14424'
|
||||
|
||||
export const ELEMENT_TYPE = {
|
||||
'text': '文本',
|
||||
'image': '图片',
|
||||
@ -11,58 +7,6 @@ export const ELEMENT_TYPE = {
|
||||
'table': '表格',
|
||||
}
|
||||
|
||||
export const DEFAULT_TEXT = {
|
||||
content: '请输入内容',
|
||||
}
|
||||
|
||||
export const DEFAULT_IMAGE = {
|
||||
left: 0,
|
||||
top: 0,
|
||||
fixedRatio: true,
|
||||
}
|
||||
|
||||
export const DEFAULT_SHAPE = {
|
||||
fill: DEFAULT_COLOR,
|
||||
fixedRatio: false,
|
||||
}
|
||||
|
||||
export const DEFAULT_LINE = {
|
||||
style: 'solid',
|
||||
width: 4,
|
||||
color: DEFAULT_COLOR,
|
||||
}
|
||||
|
||||
export const DEFAULT_CHART = {
|
||||
left: 300,
|
||||
top: 81.25,
|
||||
width: 400,
|
||||
height: 400,
|
||||
data: {
|
||||
labels: ['类别1', '类别2', '类别3', '类别4', '类别5'],
|
||||
series: [
|
||||
[12, 19, 5, 2, 18],
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
const tableOutline: PPTElementOutline = {
|
||||
width: 2,
|
||||
style: 'solid',
|
||||
color: '#eeece1',
|
||||
}
|
||||
export const DEFAULT_TABLE = {
|
||||
left: 0,
|
||||
top: 0,
|
||||
outline: tableOutline,
|
||||
theme: {
|
||||
color: DEFAULT_COLOR,
|
||||
rowHeader: true,
|
||||
rowFooter: false,
|
||||
colHeader: false,
|
||||
colFooter: false,
|
||||
},
|
||||
}
|
||||
|
||||
export const MIN_SIZE = {
|
||||
text: 20,
|
||||
image: 20,
|
||||
|
@ -1,8 +1,8 @@
|
||||
export const PRESET_THEMES = [
|
||||
{ color: '#d14424', background: '#ffffff', text: '#333' },
|
||||
{ color: '#42464b', background: '#ffffff', text: '#333' },
|
||||
{ color: '#5d82ba', background: '#ffffff', text: '#333' },
|
||||
{ color: '#005a6f', background: '#ffffff', text: '#333' },
|
||||
{ color: '#232d05', background: '#fff244', text: '#333' },
|
||||
{ color: '#d0614c', background: '#dfb044', text: '#333' },
|
||||
{ color: '#86a1ad', background: '#dfdbd4', text: '#333' },
|
||||
{ color: '#697586', background: '#d5c4a4', text: '#333' },
|
||||
|
@ -1,19 +1,12 @@
|
||||
import { computed } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { MutationTypes } from '@/store'
|
||||
import { MutationTypes, State } from '@/store'
|
||||
import { createRandomCode } from '@/utils/common'
|
||||
import { getImageSize } from '@/utils/image'
|
||||
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
|
||||
import { ChartType, PPTElement, TableCell } from '@/types/slides'
|
||||
import { ShapePoolItem } from '@/configs/shapes'
|
||||
import { LinePoolItem } from '@/configs/lines'
|
||||
import {
|
||||
DEFAULT_IMAGE,
|
||||
DEFAULT_TEXT,
|
||||
DEFAULT_SHAPE,
|
||||
DEFAULT_LINE,
|
||||
DEFAULT_CHART,
|
||||
DEFAULT_TABLE,
|
||||
} from '@/configs/element'
|
||||
import useHistorySnapshot from '@/hooks/useHistorySnapshot'
|
||||
|
||||
interface CommonElementPosition {
|
||||
@ -31,12 +24,12 @@ interface LineElementPosition {
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const store = useStore()
|
||||
const store = useStore<State>()
|
||||
const themeColor = computed(() => store.state.theme.themeColor)
|
||||
const fontColor = computed(() => store.state.theme.fontColor)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
|
||||
|
||||
const createElement = (element: PPTElement) => {
|
||||
store.commit(MutationTypes.ADD_ELEMENT, element)
|
||||
store.commit(MutationTypes.SET_ACTIVE_ELEMENT_ID_LIST, [element.id])
|
||||
@ -57,22 +50,35 @@ export default () => {
|
||||
}
|
||||
|
||||
createElement({
|
||||
...DEFAULT_IMAGE,
|
||||
type: 'image',
|
||||
id: createRandomCode(),
|
||||
src,
|
||||
width,
|
||||
height,
|
||||
left: 0,
|
||||
top: 0,
|
||||
fixedRatio: true,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const createChartElement = (chartType: ChartType) => {
|
||||
createElement({
|
||||
...DEFAULT_CHART,
|
||||
type: 'chart',
|
||||
id: createRandomCode(),
|
||||
chartType,
|
||||
left: 300,
|
||||
top: 81.25,
|
||||
width: 400,
|
||||
height: 400,
|
||||
themeColor: themeColor.value,
|
||||
gridColor: fontColor.value,
|
||||
data: {
|
||||
labels: ['类别1', '类别2', '类别3', '类别4', '类别5'],
|
||||
series: [
|
||||
[12, 19, 5, 2, 18],
|
||||
],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@ -86,33 +92,45 @@ export default () => {
|
||||
const colWidths: number[] = new Array(col).fill(1 / col)
|
||||
|
||||
createElement({
|
||||
...DEFAULT_TABLE,
|
||||
type: 'table',
|
||||
id: createRandomCode(),
|
||||
width: col * DEFAULT_CELL_WIDTH,
|
||||
height: row * DEFAULT_CELL_HEIGHT,
|
||||
colWidths,
|
||||
data,
|
||||
left: 0,
|
||||
top: 0,
|
||||
outline: {
|
||||
width: 2,
|
||||
style: 'solid',
|
||||
color: '#eeece1',
|
||||
},
|
||||
theme: {
|
||||
color: themeColor.value,
|
||||
rowHeader: true,
|
||||
rowFooter: false,
|
||||
colHeader: false,
|
||||
colFooter: false,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const createTextElement = (position: CommonElementPosition) => {
|
||||
const { left, top, width, height } = position
|
||||
createElement({
|
||||
...DEFAULT_TEXT,
|
||||
type: 'text',
|
||||
id: createRandomCode(),
|
||||
left,
|
||||
top,
|
||||
width,
|
||||
height,
|
||||
content: '请输入内容',
|
||||
})
|
||||
}
|
||||
|
||||
const createShapeElement = (position: CommonElementPosition, data: ShapePoolItem) => {
|
||||
const { left, top, width, height } = position
|
||||
createElement({
|
||||
...DEFAULT_SHAPE,
|
||||
type: 'shape',
|
||||
id: createRandomCode(),
|
||||
left,
|
||||
@ -121,13 +139,14 @@ export default () => {
|
||||
height,
|
||||
viewBox: data.viewBox,
|
||||
path: data.path,
|
||||
fill: themeColor.value,
|
||||
fixedRatio: false,
|
||||
})
|
||||
}
|
||||
|
||||
const createLineElement = (position: LineElementPosition, data: LinePoolItem) => {
|
||||
const { left, top, start, end } = position
|
||||
createElement({
|
||||
...DEFAULT_LINE,
|
||||
type: 'line',
|
||||
id: createRandomCode(),
|
||||
left,
|
||||
@ -135,6 +154,9 @@ export default () => {
|
||||
start,
|
||||
end,
|
||||
points: data.points,
|
||||
color: themeColor.value,
|
||||
style: 'solid',
|
||||
width: 2,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ export const slides: Slide[] = [
|
||||
width: 300,
|
||||
height: 300,
|
||||
chartType: 'line',
|
||||
themeColor: '#d70206',
|
||||
data: {
|
||||
labels: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
|
||||
series: [
|
||||
|
@ -132,7 +132,7 @@ export interface PPTChartElement {
|
||||
data: ChartData;
|
||||
options?: ILineChartOptions & IBarChartOptions & IPieChartOptions;
|
||||
outline?: PPTElementOutline;
|
||||
themeColors?: string[];
|
||||
themeColor: string;
|
||||
gridColor?: string;
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,10 @@
|
||||
class="editable-element"
|
||||
ref="elementRef"
|
||||
:id="'editable-element-' + elementInfo.id"
|
||||
:style="{ zIndex: elementIndex }"
|
||||
:style="{
|
||||
zIndex: elementIndex,
|
||||
color: themeFontColor,
|
||||
}"
|
||||
>
|
||||
<component
|
||||
:is="currentElementComponent"
|
||||
@ -16,6 +19,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { State } from '@/store'
|
||||
import { ElementTypes, PPTElement } from '@/types/slides'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
|
||||
@ -56,6 +61,9 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore<State>()
|
||||
const themeFontColor = computed(() => store.state.theme.fontColor)
|
||||
|
||||
const currentElementComponent = computed(() => {
|
||||
const elementTypeMap = {
|
||||
[ElementTypes.IMAGE]: ImageElement,
|
||||
@ -145,6 +153,7 @@ export default defineComponent({
|
||||
return {
|
||||
currentElementComponent,
|
||||
contextmenus,
|
||||
themeFontColor,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -55,35 +55,14 @@
|
||||
</div>
|
||||
<div class="row">
|
||||
<div style="flex: 2;">主题配色:</div>
|
||||
<Popover trigger="click" placement="bottom" v-model:visible="themePoolVisible">
|
||||
<Popover trigger="click">
|
||||
<template #content>
|
||||
<div class="theme-pool">
|
||||
<div
|
||||
class="theme-item"
|
||||
v-for="(theme, index) in CHART_THEME_COLORS"
|
||||
:key="index"
|
||||
@click="updateTheme(theme)"
|
||||
>
|
||||
<div
|
||||
class="color-block"
|
||||
v-for="(color, index) in theme"
|
||||
:key="index"
|
||||
:style="{ backgroundColor: color }"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<ColorPicker
|
||||
:modelValue="themeColor"
|
||||
@update:modelValue="value => updateTheme(value)"
|
||||
/>
|
||||
</template>
|
||||
<Button class="theme-color-btn" style="flex: 3;">
|
||||
<div class="theme-color-content">
|
||||
<div
|
||||
class="color-block"
|
||||
v-for="(color, index) in themeColors"
|
||||
:key="index"
|
||||
:style="{ backgroundColor: color }"
|
||||
></div>
|
||||
</div>
|
||||
<IconPlatte class="theme-color-btn-icon" />
|
||||
</Button>
|
||||
<ColorButton :color="themeColor" style="flex: 3;" />
|
||||
</Popover>
|
||||
</div>
|
||||
<div class="row">
|
||||
@ -144,13 +123,12 @@ export default defineComponent({
|
||||
const handleElement = computed<PPTChartElement>(() => store.getters.handleElement)
|
||||
|
||||
const chartDataEditorVisible = ref(false)
|
||||
const themePoolVisible = ref(false)
|
||||
|
||||
const { addHistorySnapshot } = useHistorySnapshot()
|
||||
|
||||
const fill = ref<string>()
|
||||
|
||||
const themeColors = ref<string[]>([])
|
||||
const themeColor = ref<string>('')
|
||||
const gridColor = ref('')
|
||||
|
||||
const lineSmooth = ref<boolean | Function>(true)
|
||||
@ -179,7 +157,7 @@ export default defineComponent({
|
||||
if(_donut !== undefined) donut.value = _donut
|
||||
}
|
||||
|
||||
themeColors.value = handleElement.value.themeColors || CHART_THEME_COLORS[0]
|
||||
themeColor.value = handleElement.value.themeColor
|
||||
gridColor.value = handleElement.value.gridColor || 'rgba(0, 0, 0, 0.4)'
|
||||
}, { deep: true, immediate: true })
|
||||
|
||||
@ -204,9 +182,8 @@ export default defineComponent({
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
const updateTheme = (themeColors: string[]) => {
|
||||
themePoolVisible.value = false
|
||||
const props = { themeColors }
|
||||
const updateTheme = (themeColor: string) => {
|
||||
const props = { themeColor }
|
||||
store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
|
||||
addHistorySnapshot()
|
||||
}
|
||||
@ -219,7 +196,6 @@ export default defineComponent({
|
||||
|
||||
return {
|
||||
chartDataEditorVisible,
|
||||
themePoolVisible,
|
||||
handleElement,
|
||||
updateData,
|
||||
fill,
|
||||
@ -230,7 +206,7 @@ export default defineComponent({
|
||||
horizontalBars,
|
||||
donut,
|
||||
updateOptions,
|
||||
themeColors,
|
||||
themeColor,
|
||||
gridColor,
|
||||
CHART_THEME_COLORS,
|
||||
updateTheme,
|
||||
@ -253,52 +229,4 @@ export default defineComponent({
|
||||
.btn-icon {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.theme-item {
|
||||
border-radius: $borderRadius;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 -12px;
|
||||
padding: 5px 32px;
|
||||
transition: background-color .1s;
|
||||
|
||||
& + .theme-item {
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #e1e1e1;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.theme-color-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 !important;
|
||||
}
|
||||
.theme-color-content {
|
||||
height: 20px;
|
||||
margin-left: 8px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.color-block {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
|
||||
& + .color-block {
|
||||
margin-left: -3px;
|
||||
}
|
||||
}
|
||||
.theme-color-btn-icon {
|
||||
width: 30px;
|
||||
font-size: 12px;
|
||||
margin-top: 2px;
|
||||
color: #bfbfbf;
|
||||
}
|
||||
</style>
|
@ -267,7 +267,34 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
const applyThemeAllSlide = () => {
|
||||
console.log('applyThemeAllSlide')
|
||||
const newSlides: Slide[] = JSON.parse(JSON.stringify(slides.value))
|
||||
const { themeColor, backgroundColor, fontColor } = theme.value
|
||||
|
||||
for(const slide of newSlides) {
|
||||
slide.background = {
|
||||
...slide.background,
|
||||
type: 'solid',
|
||||
color: backgroundColor
|
||||
}
|
||||
|
||||
const elements = slide.elements
|
||||
for(const el of elements) {
|
||||
if(el.type === 'shape') el.fill = themeColor
|
||||
else if(el.type === 'line') el.color = themeColor
|
||||
else if(el.type === 'text') {
|
||||
if(el.fill) el.fill = themeColor
|
||||
}
|
||||
else if(el.type === 'table') {
|
||||
if(el.theme) el.theme.color = themeColor
|
||||
}
|
||||
else if(el.type === 'chart') {
|
||||
el.themeColor = themeColor
|
||||
el.gridColor = fontColor
|
||||
}
|
||||
}
|
||||
}
|
||||
store.commit(MutationTypes.SET_SLIDES, newSlides)
|
||||
addHistorySnapshot()
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -3,6 +3,7 @@
|
||||
class="screen-element"
|
||||
:style="{
|
||||
zIndex: elementIndex,
|
||||
color: themeFontColor,
|
||||
visibility: needWaitAnimation ? 'hidden' : 'visible',
|
||||
}"
|
||||
>
|
||||
@ -56,6 +57,7 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
const store = useStore<State>()
|
||||
const themeFontColor = computed(() => store.state.theme.fontColor)
|
||||
const currentSlide = computed<Slide>(() => store.getters.currentSlide)
|
||||
|
||||
const needWaitAnimation = computed(() => {
|
||||
@ -68,6 +70,7 @@ export default defineComponent({
|
||||
return {
|
||||
currentElementComponent,
|
||||
needWaitAnimation,
|
||||
themeFontColor,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -1,7 +1,10 @@
|
||||
<template>
|
||||
<div
|
||||
class="base-element"
|
||||
:style="{ zIndex: elementIndex }"
|
||||
:style="{
|
||||
zIndex: elementIndex,
|
||||
color: themeFontColor,
|
||||
}"
|
||||
>
|
||||
<component
|
||||
:is="currentElementComponent"
|
||||
@ -13,6 +16,8 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { State } from '@/store'
|
||||
import { ElementTypes, PPTElement } from '@/types/slides'
|
||||
|
||||
import BaseImageElement from '@/views/components/element/ImageElement/BaseImageElement.vue'
|
||||
@ -35,6 +40,9 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const store = useStore<State>()
|
||||
const themeFontColor = computed(() => store.state.theme.fontColor)
|
||||
|
||||
const currentElementComponent = computed(() => {
|
||||
const elementTypeMap = {
|
||||
[ElementTypes.IMAGE]: BaseImageElement,
|
||||
@ -49,6 +57,7 @@ export default defineComponent({
|
||||
|
||||
return {
|
||||
currentElementComponent,
|
||||
themeFontColor,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -18,9 +18,9 @@
|
||||
:height="elementInfo.height"
|
||||
:outline="elementInfo.outline"
|
||||
/>
|
||||
<IconChartLine :fill="color" strokeWidth="2" :size="size" v-if="elementInfo.chartType === 'line'" />
|
||||
<IconChartHistogram :fill="color" strokeWidth="2" :size="size" v-else-if="elementInfo.chartType === 'bar'" />
|
||||
<IconChartProportion :fill="color" strokeWidth="2" :size="size" v-else-if="elementInfo.chartType === 'pie'" />
|
||||
<IconChartLine :fill="elementInfo.themeColor" strokeWidth="2" :size="size" v-if="elementInfo.chartType === 'line'" />
|
||||
<IconChartHistogram :fill="elementInfo.themeColor" strokeWidth="2" :size="size" v-else-if="elementInfo.chartType === 'bar'" />
|
||||
<IconChartProportion :fill="elementInfo.themeColor" strokeWidth="2" :size="size" v-else-if="elementInfo.chartType === 'pie'" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -28,7 +28,6 @@
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { PPTChartElement } from '@/types/slides'
|
||||
import { CHART_THEME_COLORS } from '@/configs/chartTheme'
|
||||
|
||||
import ElementOutline from '@/views/components/element/ElementOutline.vue'
|
||||
|
||||
@ -45,13 +44,9 @@ export default defineComponent({
|
||||
},
|
||||
setup(props) {
|
||||
const size = computed(() => Math.min(props.elementInfo.width, props.elementInfo.height))
|
||||
const color = computed(() => {
|
||||
return props.elementInfo.themeColors ? props.elementInfo.themeColors[0] : CHART_THEME_COLORS[0][0]
|
||||
})
|
||||
|
||||
return {
|
||||
size,
|
||||
color,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
@ -15,6 +15,7 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent, inject, onMounted, PropType, ref, Ref, watch } from 'vue'
|
||||
import upperFirst from 'lodash/upperFirst'
|
||||
import tinycolor from 'tinycolor2'
|
||||
import Chartist, {
|
||||
IChartistLineChart,
|
||||
IChartistBarChart,
|
||||
@ -49,8 +50,9 @@ export default defineComponent({
|
||||
options: {
|
||||
type: Object as PropType<ILineChartOptions & IBarChartOptions & IPieChartOptions>,
|
||||
},
|
||||
themeColors: {
|
||||
type: Array as PropType<string[]>,
|
||||
themeColor: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
gridColor: {
|
||||
type: String,
|
||||
@ -102,17 +104,24 @@ export default defineComponent({
|
||||
const updateTheme = () => {
|
||||
if(!chartRef.value) return
|
||||
|
||||
if(props.themeColors) {
|
||||
for(let i = 0; i < props.themeColors.length; i++) {
|
||||
chartRef.value.style.setProperty(`--theme-color-${i + 1}`, props.themeColors[i])
|
||||
const hsla = tinycolor(props.themeColor).toHsl()
|
||||
|
||||
for(let i = 0; i < 10; i++) {
|
||||
let h = hsla.h + i * 36
|
||||
if(h > 360) h = h - 360
|
||||
|
||||
const _hsla = {
|
||||
...hsla,
|
||||
h,
|
||||
}
|
||||
chartRef.value.style.setProperty(`--theme-color-${i + 1}`, tinycolor(_hsla).toRgbString())
|
||||
}
|
||||
|
||||
if(props.gridColor) chartRef.value.style.setProperty(`--grid-color`, props.gridColor)
|
||||
}
|
||||
|
||||
watch([
|
||||
() => props.themeColors,
|
||||
() => props.themeColor,
|
||||
() => props.gridColor,
|
||||
], updateTheme)
|
||||
onMounted(updateTheme)
|
||||
@ -133,12 +142,18 @@ export default defineComponent({
|
||||
|
||||
<style lang="scss">
|
||||
.chart-content {
|
||||
$ct-series-names: (a, b, c, d);
|
||||
$ct-series-names: (a, b, c, d, e, f, g, h, i, j);
|
||||
|
||||
--theme-color-1: #d70206;
|
||||
--theme-color-2: #f05b4f;
|
||||
--theme-color-3: #f4c63d;
|
||||
--theme-color-4: #d17905;
|
||||
--theme-color-1: #666;
|
||||
--theme-color-2: #666;
|
||||
--theme-color-3: #666;
|
||||
--theme-color-4: #666;
|
||||
--theme-color-5: #666;
|
||||
--theme-color-6: #666;
|
||||
--theme-color-7: #666;
|
||||
--theme-color-8: #666;
|
||||
--theme-color-9: #666;
|
||||
--theme-color-10: #666;
|
||||
|
||||
@for $i from 1 to length($ct-series-names) {
|
||||
$color: var(--theme-color-#{$i});
|
||||
|
@ -24,7 +24,7 @@
|
||||
:type="elementInfo.chartType"
|
||||
:data="elementInfo.data"
|
||||
:options="elementInfo.options"
|
||||
:themeColors="elementInfo.themeColors"
|
||||
:themeColor="elementInfo.themeColor"
|
||||
:gridColor="elementInfo.gridColor"
|
||||
/>
|
||||
</div>
|
||||
|
@ -27,7 +27,7 @@
|
||||
:type="elementInfo.chartType"
|
||||
:data="elementInfo.data"
|
||||
:options="elementInfo.options"
|
||||
:themeColors="elementInfo.themeColors"
|
||||
:themeColor="elementInfo.themeColor"
|
||||
:gridColor="elementInfo.gridColor"
|
||||
/>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user