添加图表元素

This commit is contained in:
pipipi-pikachu 2021-01-15 15:49:28 +08:00
parent c538cb0fc1
commit c4c87b1b9c
23 changed files with 1055 additions and 705 deletions

1124
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,9 @@
<div <div
class="chart" class="chart"
:style="{ :style="{
width: width + 'px', width: width * scale + 'px',
height: height + 'px', height: height * scale + 'px',
transform: `scale(${1 / scale})`,
}" }"
> >
<canvas ref="canvasRef"></canvas> <canvas ref="canvasRef"></canvas>
@ -11,35 +12,56 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, onMounted, onUnmounted, PropType, ref } from 'vue' import { computed, defineComponent, onMounted, onUnmounted, PropType, ref, watch } from 'vue'
import Chart from 'chart.js' import Chart from 'chart.js'
import { ChartData, ChartType } from '@/types/slides'
interface ChartData { const commonConfigs = {
labels: string[]; backgroundColor: 'rgba(209, 68, 36, 0.3)',
values: number[][]; borderColor: 'rgba(209, 68, 36)',
borderWidth: 2,
} }
// const data = { const defaultOptions: Chart.ChartOptions = {
// labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'], maintainAspectRatio: false,
// values: [ animation: {
// [12, 19, 3, 5, 2, 3], duration: 0,
// [22, 9, 13, 25, 12, 5], },
// ] hover: {
// } animationDuration: 0,
},
// bar responsiveAnimationDuration: 0,
// horizontalBar layout: {
// line padding: {
// radar left: 5,
// pie right: 5,
// doughnut top: 5,
// polarArea bottom: 5,
},
},
legend: {
display: false,
},
elements: {
line: {
tension: 0,
fill: false,
...commonConfigs,
},
rectangle: {
...commonConfigs,
},
arc: {
...commonConfigs,
},
},
}
export default defineComponent({ export default defineComponent({
name: 'chart', name: 'chart',
props: { props: {
type: { type: {
type: String, type: String as PropType<ChartType>,
required: true, required: true,
}, },
width: { width: {
@ -54,6 +76,13 @@ export default defineComponent({
type: Object as PropType<ChartData>, type: Object as PropType<ChartData>,
required: true, required: true,
}, },
options: {
type: Object as PropType<Chart.ChartOptions>,
},
scale: {
type: Number,
default: 1,
},
}, },
setup(props) { setup(props) {
const canvasRef = ref<HTMLCanvasElement | null>(null) const canvasRef = ref<HTMLCanvasElement | null>(null)
@ -61,63 +90,27 @@ export default defineComponent({
const data = computed(() => ({ const data = computed(() => ({
labels: props.data.labels, labels: props.data.labels,
datasets: props.data.values.map(item => { datasets: props.data.series.map(item => ({ data: item })),
return {
data: item,
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)',
],
borderColor: [
'rgba(255, 99, 132, 0.5)',
'rgba(54, 162, 235, 0.5)',
'rgba(255, 206, 86, 0.5)',
'rgba(75, 192, 192, 0.5)',
'rgba(153, 102, 255, 0.5)',
'rgba(255, 159, 64, 0.5)',
],
borderWidth: 1,
}
}),
})) }))
const options = computed(() => {
const options = props.options || {}
return { ...defaultOptions, ...options }
})
watch(data, () => {
if(!chart) return
chart.data = data.value
chart.update()
})
onMounted(() => { onMounted(() => {
if(!canvasRef.value) return if(!canvasRef.value) return
const ctx = canvasRef.value.getContext('2d') as CanvasRenderingContext2D const ctx = canvasRef.value.getContext('2d') as CanvasRenderingContext2D
chart = new Chart(ctx, { chart = new Chart(ctx, {
type: props.type, type: props.type,
data: data.value, data: data.value,
options: { options: options.value,
maintainAspectRatio: false,
animation: {
duration: 0,
},
hover: {
animationDuration: 0,
},
responsiveAnimationDuration: 0,
layout: {
padding: {
left: 8,
right: 8,
top: 8,
bottom: 8
},
},
legend: {
display: false,
},
elements: {
line: {
tension: 0,
fill: false,
},
},
},
}) })
}) })
@ -129,3 +122,9 @@ export default defineComponent({
}, },
}) })
</script> </script>
<style lang="scss" scoped>
.chart {
transform-origin: 0 0;
}
</style>

View File

@ -23,5 +23,6 @@ export default {
vertical-align: -0.15em; vertical-align: -0.15em;
fill: currentColor; fill: currentColor;
overflow: hidden; overflow: hidden;
outline: 0;
} }
</style> </style>

View File

@ -35,6 +35,12 @@ export const DEFAULT_CHART = {
top: 0, top: 0,
width: 500, width: 500,
height: 500, height: 500,
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
series: [
[12, 19, 3, 5, 2, 18],
]
},
} }
export const DEFAULT_TABLE = { export const DEFAULT_TABLE = {

View File

@ -3,7 +3,7 @@ import { MutationTypes } from '@/store'
import { createRandomCode } from '@/utils/common' import { createRandomCode } from '@/utils/common'
import { getImageSize } from '@/utils/image' import { getImageSize } from '@/utils/image'
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas' import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
import { PPTElement, TableElementCell } from '@/types/slides' import { ChartType, PPTElement, TableElementCell } from '@/types/slides'
import { ShapePoolItem } from '@/configs/shapes' import { ShapePoolItem } from '@/configs/shapes'
import { LinePoolItem } from '@/configs/lines' import { LinePoolItem } from '@/configs/lines'
import { import {
@ -67,13 +67,12 @@ export default () => {
}) })
} }
const createChartElement = (chartType: string, data: string) => { const createChartElement = (chartType: ChartType) => {
createElement({ createElement({
...DEFAULT_CHART, ...DEFAULT_CHART,
type: 'chart', type: 'chart',
id: createRandomCode(), id: createRandomCode(),
chartType, chartType,
data,
}) })
} }

View File

@ -73,6 +73,26 @@ export const slides: Slide[] = [
}, },
], ],
}, },
{
id: 'sahduyi',
elements: [
{
id: 'sdasdax',
type: 'chart',
left: 0,
top: 0,
width: 400,
height: 400,
chartType: 'line',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
series: [
[12, 19, 3, 5, 4, 18],
]
},
},
],
},
{ {
id: 'sajd172', id: 'sajd172',
elements: [ elements: [

View File

@ -105,6 +105,11 @@ export interface PPTLineElement {
shadow?: PPTElementShadow; shadow?: PPTElementShadow;
} }
export type ChartType = 'bar' | 'horizontalBar' | 'line' | 'pie' | 'doughnut' | 'polarArea' | 'radar'
export interface ChartData {
labels: string[];
series: number[][];
}
export interface PPTChartElement { export interface PPTChartElement {
type: 'chart'; type: 'chart';
id: string; id: string;
@ -114,8 +119,8 @@ export interface PPTChartElement {
groupId?: string; groupId?: string;
width: number; width: number;
height: number; height: number;
chartType: string; chartType: ChartType;
data: string; data: ChartData;
outline?: PPTElementOutline; outline?: PPTElementOutline;
theme?: string; theme?: string;
} }

View File

@ -17,7 +17,7 @@
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, PropType } from 'vue' import { computed, defineComponent, PropType } from 'vue'
import { PPTElement } from '@/types/slides' import { ElementTypes, PPTElement } from '@/types/slides'
import { ContextmenuItem } from '@/components/Contextmenu/types' import { ContextmenuItem } from '@/components/Contextmenu/types'
import useLockElement from '@/hooks/useLockElement' import useLockElement from '@/hooks/useLockElement'
@ -33,6 +33,7 @@ import ImageElement from '@/views/components/element/ImageElement/index.vue'
import TextElement from '@/views/components/element/TextElement/index.vue' import TextElement from '@/views/components/element/TextElement/index.vue'
import ShapeElement from '@/views/components/element/ShapeElement/index.vue' import ShapeElement from '@/views/components/element/ShapeElement/index.vue'
import LineElement from '@/views/components/element/LineElement/index.vue' import LineElement from '@/views/components/element/LineElement/index.vue'
import ChartElement from '@/views/components/element/ChartElement/index.vue'
export default defineComponent({ export default defineComponent({
name: 'editable-element', name: 'editable-element',
@ -57,10 +58,11 @@ export default defineComponent({
setup(props) { setup(props) {
const currentElementComponent = computed(() => { const currentElementComponent = computed(() => {
const elementTypeMap = { const elementTypeMap = {
'image': ImageElement, [ElementTypes.IMAGE]: ImageElement,
'text': TextElement, [ElementTypes.TEXT]: TextElement,
'shape': ShapeElement, [ElementTypes.SHAPE]: ShapeElement,
'line': LineElement, [ElementTypes.LINE]: LineElement,
[ElementTypes.CHART]: ChartElement,
} }
return elementTypeMap[props.elementInfo.type] || null return elementTypeMap[props.elementInfo.type] || null
}) })

View File

@ -0,0 +1,75 @@
<template>
<div class="chart-element-operate">
<BorderLine
class="operate-border-line"
v-for="line in borderLines"
:key="line.type"
:type="line.type"
:style="line.style"
/>
<template v-if="!elementInfo.lock && (isActiveGroupElement || !isMultiSelect)">
<ResizeHandler
class="operate-resize-handler"
v-for="point in resizeHandlers"
:key="point.direction"
:type="point.direction"
:style="point.style"
@mousedown.stop="$event => scaleElement($event, elementInfo, point.direction)"
/>
</template>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, PropType } from 'vue'
import { useStore } from 'vuex'
import { State } from '@/store'
import { PPTShapeElement } from '@/types/slides'
import { OperateResizeHandler } from '@/types/edit'
import useCommonOperate from '../hooks/useCommonOperate'
import ResizeHandler from './ResizeHandler.vue'
import BorderLine from './BorderLine.vue'
export default defineComponent({
name: 'chart-element-operate',
inheritAttrs: false,
components: {
ResizeHandler,
BorderLine,
},
props: {
elementInfo: {
type: Object as PropType<PPTShapeElement>,
required: true,
},
isActiveGroupElement: {
type: Boolean,
required: true,
},
isMultiSelect: {
type: Boolean,
required: true,
},
scaleElement: {
type: Function as PropType<(e: MouseEvent, element: PPTShapeElement, command: OperateResizeHandler) => void>,
required: true,
},
},
setup(props) {
const store = useStore<State>()
const canvasScale = computed(() => store.state.canvasScale)
const scaleWidth = computed(() => props.elementInfo.width * canvasScale.value)
const scaleHeight = computed(() => props.elementInfo.height * canvasScale.value)
const { resizeHandlers, borderLines } = useCommonOperate(scaleWidth, scaleHeight)
return {
scaleWidth,
resizeHandlers,
borderLines,
}
},
})
</script>

View File

@ -1,5 +1,5 @@
<template> <template>
<div class="text-element-operate"> <div class="shape-element-operate">
<BorderLine <BorderLine
class="operate-border-line" class="operate-border-line"
v-for="line in borderLines" v-for="line in borderLines"
@ -39,7 +39,7 @@ import ResizeHandler from './ResizeHandler.vue'
import BorderLine from './BorderLine.vue' import BorderLine from './BorderLine.vue'
export default defineComponent({ export default defineComponent({
name: 'text-element-operate', name: 'shape-element-operate',
inheritAttrs: false, inheritAttrs: false,
components: { components: {
RotateHandler, RotateHandler,

View File

@ -33,13 +33,14 @@
import { defineComponent, PropType, computed, Ref } from 'vue' import { defineComponent, PropType, computed, Ref } from 'vue'
import { useStore } from 'vuex' import { useStore } from 'vuex'
import { State } from '@/store' import { State } from '@/store'
import { PPTElement, Slide } from '@/types/slides' import { ElementTypes, PPTElement, Slide } from '@/types/slides'
import { OperateLineHandler, OperateResizeHandler } from '@/types/edit' import { OperateLineHandler, OperateResizeHandler } from '@/types/edit'
import ImageElementOperate from './ImageElementOperate.vue' import ImageElementOperate from './ImageElementOperate.vue'
import TextElementOperate from './TextElementOperate.vue' import TextElementOperate from './TextElementOperate.vue'
import ShapeElementOperate from './ShapeElementOperate.vue' import ShapeElementOperate from './ShapeElementOperate.vue'
import LineElementOperate from './LineElementOperate.vue' import LineElementOperate from './LineElementOperate.vue'
import ChartElementOperate from './ChartElementOperate.vue'
export default defineComponent({ export default defineComponent({
name: 'operate', name: 'operate',
@ -85,10 +86,11 @@ export default defineComponent({
const currentOperateComponent = computed(() => { const currentOperateComponent = computed(() => {
const elementTypeMap = { const elementTypeMap = {
'image': ImageElementOperate, [ElementTypes.IMAGE]: ImageElementOperate,
'text': TextElementOperate, [ElementTypes.TEXT]: TextElementOperate,
'shape': ShapeElementOperate, [ElementTypes.SHAPE]: ShapeElementOperate,
'line': LineElementOperate, [ElementTypes.LINE]: LineElementOperate,
[ElementTypes.CHART]: ChartElementOperate,
} }
return elementTypeMap[props.elementInfo.type] || null return elementTypeMap[props.elementInfo.type] || null
}) })

View File

@ -0,0 +1,13 @@
<template>
<div class="chart-style-panel">
chart-style-panel
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name: 'chart-style-panel',
})
</script>

View File

@ -17,6 +17,7 @@ import TextStylePanel from './TextStylePanel.vue'
import ImageStylePanel from './ImageStylePanel.vue' import ImageStylePanel from './ImageStylePanel.vue'
import ShapeStylePanel from './ShapeStylePanel.vue' import ShapeStylePanel from './ShapeStylePanel.vue'
import LineStylePanel from './LineStylePanel.vue' import LineStylePanel from './LineStylePanel.vue'
import ChartStylePanel from './ChartStylePanel.vue'
export default defineComponent({ export default defineComponent({
name: 'element-style-panel', name: 'element-style-panel',
@ -32,6 +33,7 @@ export default defineComponent({
[ElementTypes.IMAGE]: ImageStylePanel, [ElementTypes.IMAGE]: ImageStylePanel,
[ElementTypes.SHAPE]: ShapeStylePanel, [ElementTypes.SHAPE]: ShapeStylePanel,
[ElementTypes.LINE]: LineStylePanel, [ElementTypes.LINE]: LineStylePanel,
[ElementTypes.CHART]: ChartStylePanel,
} }
return panelMap[handleElement.value.type] || null return panelMap[handleElement.value.type] || null
}) })

View File

@ -29,7 +29,7 @@ export default {
margin-left: 8px; margin-left: 8px;
flex: 1; flex: 1;
} }
.color-btn-icon { svg.color-btn-icon {
width: 30px; width: 30px;
font-size: 12px; font-size: 12px;
margin-top: 2px; margin-top: 2px;

View File

@ -9,6 +9,7 @@
<component <component
:is="currentElementComponent" :is="currentElementComponent"
:elementInfo="elementInfo" :elementInfo="elementInfo"
target="screen"
></component> ></component>
</div> </div>
</template> </template>
@ -17,12 +18,13 @@
import { computed, defineComponent, PropType, Ref } from 'vue' import { computed, defineComponent, PropType, Ref } from 'vue'
import { useStore } from 'vuex' import { useStore } from 'vuex'
import { State } from '@/store' import { State } from '@/store'
import { PPTElement, Slide } from '@/types/slides' import { ElementTypes, PPTElement, Slide } from '@/types/slides'
import BaseImageElement from '@/views/components/element/ImageElement/BaseImageElement.vue' import BaseImageElement from '@/views/components/element/ImageElement/BaseImageElement.vue'
import BaseTextElement from '@/views/components/element/TextElement/BaseTextElement.vue' import BaseTextElement from '@/views/components/element/TextElement/BaseTextElement.vue'
import BaseShapeElement from '@/views/components/element/ShapeElement/BaseShapeElement.vue' import BaseShapeElement from '@/views/components/element/ShapeElement/BaseShapeElement.vue'
import BaseLineElement from '@/views/components/element/LineElement/BaseLineElement.vue' import BaseLineElement from '@/views/components/element/LineElement/BaseLineElement.vue'
import BaseChartElement from '@/views/components/element/ChartElement/BaseChartElement.vue'
export default defineComponent({ export default defineComponent({
name: 'screen-element', name: 'screen-element',
@ -43,10 +45,11 @@ export default defineComponent({
setup(props) { setup(props) {
const currentElementComponent = computed(() => { const currentElementComponent = computed(() => {
const elementTypeMap = { const elementTypeMap = {
'image': BaseImageElement, [ElementTypes.IMAGE]: BaseImageElement,
'text': BaseTextElement, [ElementTypes.TEXT]: BaseTextElement,
'shape': BaseShapeElement, [ElementTypes.SHAPE]: BaseShapeElement,
'line': BaseLineElement, [ElementTypes.LINE]: BaseLineElement,
[ElementTypes.CHART]: BaseChartElement,
} }
return elementTypeMap[props.elementInfo.type] || null return elementTypeMap[props.elementInfo.type] || null
}) })

View File

@ -20,7 +20,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, PropType, defineComponent } from 'vue' import { computed, PropType, defineComponent, inject } from 'vue'
import { Slide } from '@/types/slides' import { Slide } from '@/types/slides'
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas' import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle' import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
@ -37,10 +37,6 @@ export default defineComponent({
type: Object as PropType<Slide>, type: Object as PropType<Slide>,
required: true, required: true,
}, },
scale: {
type: Number,
required: true,
},
animationIndex: { animationIndex: {
type: Number, type: Number,
default: -1, default: -1,
@ -50,7 +46,10 @@ export default defineComponent({
const background = computed(() => props.slide.background) const background = computed(() => props.slide.background)
const { backgroundStyle } = useSlideBackgroundStyle(background) const { backgroundStyle } = useSlideBackgroundStyle(background)
const scale = inject('scale')
return { return {
scale,
backgroundStyle, backgroundStyle,
VIEWPORT_SIZE, VIEWPORT_SIZE,
VIEWPORT_ASPECT_RATIO, VIEWPORT_ASPECT_RATIO,

View File

@ -26,7 +26,6 @@
}" }"
> >
<ScreenSlide <ScreenSlide
:scale="scale"
:slide="slide" :slide="slide"
:animationIndex="animationIndex" :animationIndex="animationIndex"
/> />
@ -59,7 +58,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, onMounted, onUnmounted, Ref, ref } from 'vue' import { computed, defineComponent, onMounted, onUnmounted, provide, Ref, ref } from 'vue'
import { useStore } from 'vuex' import { useStore } from 'vuex'
import throttle from 'lodash/throttle' import throttle from 'lodash/throttle'
import { MutationTypes, State } from '@/store' import { MutationTypes, State } from '@/store'
@ -88,7 +87,9 @@ export default defineComponent({
const slideWidth = ref(0) const slideWidth = ref(0)
const slideHeight = ref(0) const slideHeight = ref(0)
const scale = computed(() => slideWidth.value / VIEWPORT_SIZE) const scale = computed(() => slideWidth.value / VIEWPORT_SIZE)
provide('scale', scale)
const slideThumbnailModelVisible = ref(false) const slideThumbnailModelVisible = ref(false)

View File

@ -6,18 +6,20 @@
<component <component
:is="currentElementComponent" :is="currentElementComponent"
:elementInfo="elementInfo" :elementInfo="elementInfo"
target="thumbnail"
></component> ></component>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent, PropType } from 'vue' import { computed, defineComponent, PropType } from 'vue'
import { PPTElement } from '@/types/slides' import { ElementTypes, PPTElement } from '@/types/slides'
import BaseImageElement from '@/views/components/element/ImageElement/BaseImageElement.vue' import BaseImageElement from '@/views/components/element/ImageElement/BaseImageElement.vue'
import BaseTextElement from '@/views/components/element/TextElement/BaseTextElement.vue' import BaseTextElement from '@/views/components/element/TextElement/BaseTextElement.vue'
import BaseShapeElement from '@/views/components/element/ShapeElement/BaseShapeElement.vue' import BaseShapeElement from '@/views/components/element/ShapeElement/BaseShapeElement.vue'
import BaseLineElement from '@/views/components/element/LineElement/BaseLineElement.vue' import BaseLineElement from '@/views/components/element/LineElement/BaseLineElement.vue'
import BaseChartElement from '@/views/components/element/ChartElement/BaseChartElement.vue'
export default defineComponent({ export default defineComponent({
name: 'base-element', name: 'base-element',
@ -34,10 +36,11 @@ export default defineComponent({
setup(props) { setup(props) {
const currentElementComponent = computed(() => { const currentElementComponent = computed(() => {
const elementTypeMap = { const elementTypeMap = {
'image': BaseImageElement, [ElementTypes.IMAGE]: BaseImageElement,
'text': BaseTextElement, [ElementTypes.TEXT]: BaseTextElement,
'shape': BaseShapeElement, [ElementTypes.SHAPE]: BaseShapeElement,
'line': BaseLineElement, [ElementTypes.LINE]: BaseLineElement,
[ElementTypes.CHART]: BaseChartElement,
} }
return elementTypeMap[props.elementInfo.type] || null return elementTypeMap[props.elementInfo.type] || null
}) })

View File

@ -10,7 +10,7 @@
:style="{ :style="{
width: VIEWPORT_SIZE + 'px', width: VIEWPORT_SIZE + 'px',
height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO + 'px', height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO + 'px',
transform: `scale(${size / VIEWPORT_SIZE})`, transform: `scale(${scale})`,
}" }"
> >
<div class="background" :style="{ ...backgroundStyle }"></div> <div class="background" :style="{ ...backgroundStyle }"></div>
@ -25,7 +25,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, PropType, defineComponent } from 'vue' import { computed, PropType, defineComponent, provide } from 'vue'
import { Slide } from '@/types/slides' import { Slide } from '@/types/slides'
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas' import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle' import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
@ -51,7 +51,11 @@ export default defineComponent({
const background = computed(() => props.slide.background) const background = computed(() => props.slide.background)
const { backgroundStyle } = useSlideBackgroundStyle(background) const { backgroundStyle } = useSlideBackgroundStyle(background)
const scale = computed(() => props.size / VIEWPORT_SIZE)
provide('scale', 1)
return { return {
scale,
backgroundStyle, backgroundStyle,
VIEWPORT_SIZE, VIEWPORT_SIZE,
VIEWPORT_ASPECT_RATIO, VIEWPORT_ASPECT_RATIO,

View File

@ -0,0 +1,70 @@
<template>
<div class="base-element-chart"
:style="{
top: elementInfo.top + 'px',
left: elementInfo.left + 'px',
width: elementInfo.width + 'px',
height: elementInfo.height + 'px',
}"
>
<div class="element-content">
<ElementOutline
:width="elementInfo.width"
:height="elementInfo.height"
:outline="elementInfo.outline"
/>
<Chart
:type="elementInfo.chartType"
:width="elementInfo.width"
:height="elementInfo.height"
:data="elementInfo.data"
:scale="scale"
:options="target === 'thumbnail' ? { tooltips: { enabled: false } } : {}"
/>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, inject, PropType } from 'vue'
import { PPTChartElement } from '@/types/slides'
import ElementOutline from '@/views/components/element/ElementOutline.vue'
import Chart from '@/components/Chart.vue'
export default defineComponent({
name: 'base-element-chart',
components: {
ElementOutline,
Chart,
},
props: {
elementInfo: {
type: Object as PropType<PPTChartElement>,
required: true,
},
target: {
type: String as PropType<'thumbnail' | 'screen'>,
required: true,
},
},
setup() {
const scale = inject('scale') || 1
return {
scale,
}
},
})
</script>
<style lang="scss" scoped>
.base-element-chart {
position: absolute;
}
.element-content {
width: 100%;
height: 100%;
}
</style>

View File

@ -0,0 +1,94 @@
<template>
<div class="editable-element-chart"
:class="{ 'lock': elementInfo.lock }"
:style="{
top: elementInfo.top + 'px',
left: elementInfo.left + 'px',
width: elementInfo.width + 'px',
height: elementInfo.height + 'px',
}"
@mousedown="$event => handleSelectElement($event)"
>
<div
class="element-content"
v-contextmenu="contextmenus"
>
<ElementOutline
:width="elementInfo.width"
:height="elementInfo.height"
:outline="elementInfo.outline"
/>
<Chart
:type="elementInfo.chartType"
:width="elementInfo.width"
:height="elementInfo.height"
:data="elementInfo.data"
:scale="canvasScale"
/>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineComponent, PropType } from 'vue'
import { useStore } from 'vuex'
import { State } from '@/store'
import { PPTChartElement } from '@/types/slides'
import { ContextmenuItem } from '@/components/Contextmenu/types'
import ElementOutline from '@/views/components/element/ElementOutline.vue'
import Chart from '@/components/Chart.vue'
export default defineComponent({
name: 'editable-element-chart',
components: {
ElementOutline,
Chart,
},
props: {
elementInfo: {
type: Object as PropType<PPTChartElement>,
required: true,
},
selectElement: {
type: Function as PropType<(e: MouseEvent, element: PPTChartElement, canMove?: boolean) => void>,
required: true,
},
contextmenus: {
type: Function as PropType<() => ContextmenuItem[]>,
},
},
setup(props) {
const handleSelectElement = (e: MouseEvent) => {
if(props.elementInfo.lock) return
e.stopPropagation()
props.selectElement(e, props.elementInfo)
}
const store = useStore<State>()
const canvasScale = computed(() => store.state.canvasScale)
return {
handleSelectElement,
canvasScale,
}
},
})
</script>
<style lang="scss" scoped>
.editable-element-chart {
position: absolute;
cursor: move;
&.lock .element-content {
cursor: default;
}
}
.element-content {
width: 100%;
height: 100%;
}
</style>

View File

@ -4,6 +4,7 @@
top: elementInfo.top + 'px', top: elementInfo.top + 'px',
left: elementInfo.left + 'px', left: elementInfo.left + 'px',
width: elementInfo.width + 'px', width: elementInfo.width + 'px',
height: elementInfo.height + 'px',
transform: `rotate(${elementInfo.rotate}deg)`, transform: `rotate(${elementInfo.rotate}deg)`,
}" }"
> >

View File

@ -5,6 +5,7 @@
top: elementInfo.top + 'px', top: elementInfo.top + 'px',
left: elementInfo.left + 'px', left: elementInfo.left + 'px',
width: elementInfo.width + 'px', width: elementInfo.width + 'px',
height: elementInfo.height + 'px',
transform: `rotate(${elementInfo.rotate}deg)`, transform: `rotate(${elementInfo.rotate}deg)`,
}" }"
@mousedown="$event => handleSelectElement($event)" @mousedown="$event => handleSelectElement($event)"