mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
添加图表元素
This commit is contained in:
parent
c538cb0fc1
commit
c4c87b1b9c
1124
package-lock.json
generated
1124
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -2,8 +2,9 @@
|
||||
<div
|
||||
class="chart"
|
||||
:style="{
|
||||
width: width + 'px',
|
||||
height: height + 'px',
|
||||
width: width * scale + 'px',
|
||||
height: height * scale + 'px',
|
||||
transform: `scale(${1 / scale})`,
|
||||
}"
|
||||
>
|
||||
<canvas ref="canvasRef"></canvas>
|
||||
@ -11,35 +12,56 @@
|
||||
</template>
|
||||
|
||||
<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 { ChartData, ChartType } from '@/types/slides'
|
||||
|
||||
interface ChartData {
|
||||
labels: string[];
|
||||
values: number[][];
|
||||
const commonConfigs = {
|
||||
backgroundColor: 'rgba(209, 68, 36, 0.3)',
|
||||
borderColor: 'rgba(209, 68, 36)',
|
||||
borderWidth: 2,
|
||||
}
|
||||
|
||||
// const data = {
|
||||
// labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
|
||||
// values: [
|
||||
// [12, 19, 3, 5, 2, 3],
|
||||
// [22, 9, 13, 25, 12, 5],
|
||||
// ]
|
||||
// }
|
||||
|
||||
// bar
|
||||
// horizontalBar
|
||||
// line
|
||||
// radar
|
||||
// pie
|
||||
// doughnut
|
||||
// polarArea
|
||||
const defaultOptions: Chart.ChartOptions = {
|
||||
maintainAspectRatio: false,
|
||||
animation: {
|
||||
duration: 0,
|
||||
},
|
||||
hover: {
|
||||
animationDuration: 0,
|
||||
},
|
||||
responsiveAnimationDuration: 0,
|
||||
layout: {
|
||||
padding: {
|
||||
left: 5,
|
||||
right: 5,
|
||||
top: 5,
|
||||
bottom: 5,
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
elements: {
|
||||
line: {
|
||||
tension: 0,
|
||||
fill: false,
|
||||
...commonConfigs,
|
||||
},
|
||||
rectangle: {
|
||||
...commonConfigs,
|
||||
},
|
||||
arc: {
|
||||
...commonConfigs,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'chart',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
type: String as PropType<ChartType>,
|
||||
required: true,
|
||||
},
|
||||
width: {
|
||||
@ -54,6 +76,13 @@ export default defineComponent({
|
||||
type: Object as PropType<ChartData>,
|
||||
required: true,
|
||||
},
|
||||
options: {
|
||||
type: Object as PropType<Chart.ChartOptions>,
|
||||
},
|
||||
scale: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const canvasRef = ref<HTMLCanvasElement | null>(null)
|
||||
@ -61,63 +90,27 @@ export default defineComponent({
|
||||
|
||||
const data = computed(() => ({
|
||||
labels: props.data.labels,
|
||||
datasets: props.data.values.map(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,
|
||||
}
|
||||
}),
|
||||
datasets: props.data.series.map(item => ({ data: item })),
|
||||
}))
|
||||
|
||||
const options = computed(() => {
|
||||
const options = props.options || {}
|
||||
return { ...defaultOptions, ...options }
|
||||
})
|
||||
|
||||
watch(data, () => {
|
||||
if(!chart) return
|
||||
chart.data = data.value
|
||||
chart.update()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if(!canvasRef.value) return
|
||||
const ctx = canvasRef.value.getContext('2d') as CanvasRenderingContext2D
|
||||
chart = new Chart(ctx, {
|
||||
type: props.type,
|
||||
data: data.value,
|
||||
options: {
|
||||
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,
|
||||
},
|
||||
},
|
||||
},
|
||||
options: options.value,
|
||||
})
|
||||
})
|
||||
|
||||
@ -129,3 +122,9 @@ export default defineComponent({
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.chart {
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
</style>
|
@ -23,5 +23,6 @@ export default {
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
outline: 0;
|
||||
}
|
||||
</style>
|
@ -35,6 +35,12 @@ export const DEFAULT_CHART = {
|
||||
top: 0,
|
||||
width: 500,
|
||||
height: 500,
|
||||
data: {
|
||||
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
|
||||
series: [
|
||||
[12, 19, 3, 5, 2, 18],
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
export const DEFAULT_TABLE = {
|
||||
|
@ -3,7 +3,7 @@ import { MutationTypes } from '@/store'
|
||||
import { createRandomCode } from '@/utils/common'
|
||||
import { getImageSize } from '@/utils/image'
|
||||
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 { LinePoolItem } from '@/configs/lines'
|
||||
import {
|
||||
@ -67,13 +67,12 @@ export default () => {
|
||||
})
|
||||
}
|
||||
|
||||
const createChartElement = (chartType: string, data: string) => {
|
||||
const createChartElement = (chartType: ChartType) => {
|
||||
createElement({
|
||||
...DEFAULT_CHART,
|
||||
type: 'chart',
|
||||
id: createRandomCode(),
|
||||
chartType,
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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',
|
||||
elements: [
|
||||
|
@ -105,6 +105,11 @@ export interface PPTLineElement {
|
||||
shadow?: PPTElementShadow;
|
||||
}
|
||||
|
||||
export type ChartType = 'bar' | 'horizontalBar' | 'line' | 'pie' | 'doughnut' | 'polarArea' | 'radar'
|
||||
export interface ChartData {
|
||||
labels: string[];
|
||||
series: number[][];
|
||||
}
|
||||
export interface PPTChartElement {
|
||||
type: 'chart';
|
||||
id: string;
|
||||
@ -114,8 +119,8 @@ export interface PPTChartElement {
|
||||
groupId?: string;
|
||||
width: number;
|
||||
height: number;
|
||||
chartType: string;
|
||||
data: string;
|
||||
chartType: ChartType;
|
||||
data: ChartData;
|
||||
outline?: PPTElementOutline;
|
||||
theme?: string;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from 'vue'
|
||||
import { PPTElement } from '@/types/slides'
|
||||
import { ElementTypes, PPTElement } from '@/types/slides'
|
||||
import { ContextmenuItem } from '@/components/Contextmenu/types'
|
||||
|
||||
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 ShapeElement from '@/views/components/element/ShapeElement/index.vue'
|
||||
import LineElement from '@/views/components/element/LineElement/index.vue'
|
||||
import ChartElement from '@/views/components/element/ChartElement/index.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'editable-element',
|
||||
@ -57,10 +58,11 @@ export default defineComponent({
|
||||
setup(props) {
|
||||
const currentElementComponent = computed(() => {
|
||||
const elementTypeMap = {
|
||||
'image': ImageElement,
|
||||
'text': TextElement,
|
||||
'shape': ShapeElement,
|
||||
'line': LineElement,
|
||||
[ElementTypes.IMAGE]: ImageElement,
|
||||
[ElementTypes.TEXT]: TextElement,
|
||||
[ElementTypes.SHAPE]: ShapeElement,
|
||||
[ElementTypes.LINE]: LineElement,
|
||||
[ElementTypes.CHART]: ChartElement,
|
||||
}
|
||||
return elementTypeMap[props.elementInfo.type] || null
|
||||
})
|
||||
|
75
src/views/Editor/Canvas/Operate/ChartElementOperate.vue
Normal file
75
src/views/Editor/Canvas/Operate/ChartElementOperate.vue
Normal 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>
|
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="text-element-operate">
|
||||
<div class="shape-element-operate">
|
||||
<BorderLine
|
||||
class="operate-border-line"
|
||||
v-for="line in borderLines"
|
||||
@ -39,7 +39,7 @@ import ResizeHandler from './ResizeHandler.vue'
|
||||
import BorderLine from './BorderLine.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'text-element-operate',
|
||||
name: 'shape-element-operate',
|
||||
inheritAttrs: false,
|
||||
components: {
|
||||
RotateHandler,
|
||||
|
@ -33,13 +33,14 @@
|
||||
import { defineComponent, PropType, computed, Ref } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { State } from '@/store'
|
||||
import { PPTElement, Slide } from '@/types/slides'
|
||||
import { ElementTypes, PPTElement, Slide } from '@/types/slides'
|
||||
import { OperateLineHandler, OperateResizeHandler } from '@/types/edit'
|
||||
|
||||
import ImageElementOperate from './ImageElementOperate.vue'
|
||||
import TextElementOperate from './TextElementOperate.vue'
|
||||
import ShapeElementOperate from './ShapeElementOperate.vue'
|
||||
import LineElementOperate from './LineElementOperate.vue'
|
||||
import ChartElementOperate from './ChartElementOperate.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'operate',
|
||||
@ -85,10 +86,11 @@ export default defineComponent({
|
||||
|
||||
const currentOperateComponent = computed(() => {
|
||||
const elementTypeMap = {
|
||||
'image': ImageElementOperate,
|
||||
'text': TextElementOperate,
|
||||
'shape': ShapeElementOperate,
|
||||
'line': LineElementOperate,
|
||||
[ElementTypes.IMAGE]: ImageElementOperate,
|
||||
[ElementTypes.TEXT]: TextElementOperate,
|
||||
[ElementTypes.SHAPE]: ShapeElementOperate,
|
||||
[ElementTypes.LINE]: LineElementOperate,
|
||||
[ElementTypes.CHART]: ChartElementOperate,
|
||||
}
|
||||
return elementTypeMap[props.elementInfo.type] || null
|
||||
})
|
||||
|
@ -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>
|
@ -17,6 +17,7 @@ import TextStylePanel from './TextStylePanel.vue'
|
||||
import ImageStylePanel from './ImageStylePanel.vue'
|
||||
import ShapeStylePanel from './ShapeStylePanel.vue'
|
||||
import LineStylePanel from './LineStylePanel.vue'
|
||||
import ChartStylePanel from './ChartStylePanel.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'element-style-panel',
|
||||
@ -32,6 +33,7 @@ export default defineComponent({
|
||||
[ElementTypes.IMAGE]: ImageStylePanel,
|
||||
[ElementTypes.SHAPE]: ShapeStylePanel,
|
||||
[ElementTypes.LINE]: LineStylePanel,
|
||||
[ElementTypes.CHART]: ChartStylePanel,
|
||||
}
|
||||
return panelMap[handleElement.value.type] || null
|
||||
})
|
||||
|
@ -29,7 +29,7 @@ export default {
|
||||
margin-left: 8px;
|
||||
flex: 1;
|
||||
}
|
||||
.color-btn-icon {
|
||||
svg.color-btn-icon {
|
||||
width: 30px;
|
||||
font-size: 12px;
|
||||
margin-top: 2px;
|
||||
|
@ -9,6 +9,7 @@
|
||||
<component
|
||||
:is="currentElementComponent"
|
||||
:elementInfo="elementInfo"
|
||||
target="screen"
|
||||
></component>
|
||||
</div>
|
||||
</template>
|
||||
@ -17,12 +18,13 @@
|
||||
import { computed, defineComponent, PropType, Ref } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
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 BaseTextElement from '@/views/components/element/TextElement/BaseTextElement.vue'
|
||||
import BaseShapeElement from '@/views/components/element/ShapeElement/BaseShapeElement.vue'
|
||||
import BaseLineElement from '@/views/components/element/LineElement/BaseLineElement.vue'
|
||||
import BaseChartElement from '@/views/components/element/ChartElement/BaseChartElement.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'screen-element',
|
||||
@ -43,10 +45,11 @@ export default defineComponent({
|
||||
setup(props) {
|
||||
const currentElementComponent = computed(() => {
|
||||
const elementTypeMap = {
|
||||
'image': BaseImageElement,
|
||||
'text': BaseTextElement,
|
||||
'shape': BaseShapeElement,
|
||||
'line': BaseLineElement,
|
||||
[ElementTypes.IMAGE]: BaseImageElement,
|
||||
[ElementTypes.TEXT]: BaseTextElement,
|
||||
[ElementTypes.SHAPE]: BaseShapeElement,
|
||||
[ElementTypes.LINE]: BaseLineElement,
|
||||
[ElementTypes.CHART]: BaseChartElement,
|
||||
}
|
||||
return elementTypeMap[props.elementInfo.type] || null
|
||||
})
|
||||
|
@ -20,7 +20,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, PropType, defineComponent } from 'vue'
|
||||
import { computed, PropType, defineComponent, inject } from 'vue'
|
||||
import { Slide } from '@/types/slides'
|
||||
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
|
||||
import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
|
||||
@ -37,10 +37,6 @@ export default defineComponent({
|
||||
type: Object as PropType<Slide>,
|
||||
required: true,
|
||||
},
|
||||
scale: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
animationIndex: {
|
||||
type: Number,
|
||||
default: -1,
|
||||
@ -50,7 +46,10 @@ export default defineComponent({
|
||||
const background = computed(() => props.slide.background)
|
||||
const { backgroundStyle } = useSlideBackgroundStyle(background)
|
||||
|
||||
const scale = inject('scale')
|
||||
|
||||
return {
|
||||
scale,
|
||||
backgroundStyle,
|
||||
VIEWPORT_SIZE,
|
||||
VIEWPORT_ASPECT_RATIO,
|
||||
|
@ -26,7 +26,6 @@
|
||||
}"
|
||||
>
|
||||
<ScreenSlide
|
||||
:scale="scale"
|
||||
:slide="slide"
|
||||
:animationIndex="animationIndex"
|
||||
/>
|
||||
@ -59,7 +58,7 @@
|
||||
</template>
|
||||
|
||||
<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 throttle from 'lodash/throttle'
|
||||
import { MutationTypes, State } from '@/store'
|
||||
@ -88,7 +87,9 @@ export default defineComponent({
|
||||
|
||||
const slideWidth = ref(0)
|
||||
const slideHeight = ref(0)
|
||||
|
||||
const scale = computed(() => slideWidth.value / VIEWPORT_SIZE)
|
||||
provide('scale', scale)
|
||||
|
||||
const slideThumbnailModelVisible = ref(false)
|
||||
|
||||
|
@ -6,18 +6,20 @@
|
||||
<component
|
||||
:is="currentElementComponent"
|
||||
:elementInfo="elementInfo"
|
||||
target="thumbnail"
|
||||
></component>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
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 BaseTextElement from '@/views/components/element/TextElement/BaseTextElement.vue'
|
||||
import BaseShapeElement from '@/views/components/element/ShapeElement/BaseShapeElement.vue'
|
||||
import BaseLineElement from '@/views/components/element/LineElement/BaseLineElement.vue'
|
||||
import BaseChartElement from '@/views/components/element/ChartElement/BaseChartElement.vue'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'base-element',
|
||||
@ -34,10 +36,11 @@ export default defineComponent({
|
||||
setup(props) {
|
||||
const currentElementComponent = computed(() => {
|
||||
const elementTypeMap = {
|
||||
'image': BaseImageElement,
|
||||
'text': BaseTextElement,
|
||||
'shape': BaseShapeElement,
|
||||
'line': BaseLineElement,
|
||||
[ElementTypes.IMAGE]: BaseImageElement,
|
||||
[ElementTypes.TEXT]: BaseTextElement,
|
||||
[ElementTypes.SHAPE]: BaseShapeElement,
|
||||
[ElementTypes.LINE]: BaseLineElement,
|
||||
[ElementTypes.CHART]: BaseChartElement,
|
||||
}
|
||||
return elementTypeMap[props.elementInfo.type] || null
|
||||
})
|
||||
|
@ -10,7 +10,7 @@
|
||||
:style="{
|
||||
width: VIEWPORT_SIZE + 'px',
|
||||
height: VIEWPORT_SIZE * VIEWPORT_ASPECT_RATIO + 'px',
|
||||
transform: `scale(${size / VIEWPORT_SIZE})`,
|
||||
transform: `scale(${scale})`,
|
||||
}"
|
||||
>
|
||||
<div class="background" :style="{ ...backgroundStyle }"></div>
|
||||
@ -25,7 +25,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, PropType, defineComponent } from 'vue'
|
||||
import { computed, PropType, defineComponent, provide } from 'vue'
|
||||
import { Slide } from '@/types/slides'
|
||||
import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
|
||||
import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
|
||||
@ -51,7 +51,11 @@ export default defineComponent({
|
||||
const background = computed(() => props.slide.background)
|
||||
const { backgroundStyle } = useSlideBackgroundStyle(background)
|
||||
|
||||
const scale = computed(() => props.size / VIEWPORT_SIZE)
|
||||
provide('scale', 1)
|
||||
|
||||
return {
|
||||
scale,
|
||||
backgroundStyle,
|
||||
VIEWPORT_SIZE,
|
||||
VIEWPORT_ASPECT_RATIO,
|
||||
|
@ -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>
|
94
src/views/components/element/ChartElement/index.vue
Normal file
94
src/views/components/element/ChartElement/index.vue
Normal 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>
|
@ -4,6 +4,7 @@
|
||||
top: elementInfo.top + 'px',
|
||||
left: elementInfo.left + 'px',
|
||||
width: elementInfo.width + 'px',
|
||||
height: elementInfo.height + 'px',
|
||||
transform: `rotate(${elementInfo.rotate}deg)`,
|
||||
}"
|
||||
>
|
||||
|
@ -5,6 +5,7 @@
|
||||
top: elementInfo.top + 'px',
|
||||
left: elementInfo.left + 'px',
|
||||
width: elementInfo.width + 'px',
|
||||
height: elementInfo.height + 'px',
|
||||
transform: `rotate(${elementInfo.rotate}deg)`,
|
||||
}"
|
||||
@mousedown="$event => handleSelectElement($event)"
|
||||
|
Loading…
x
Reference in New Issue
Block a user