Skip to content

Commit 3861c58

Browse files
committed
feat: 添加复制粘贴元素,播放器外部控制
1 parent e50b018 commit 3861c58

File tree

2 files changed

+77
-31
lines changed

2 files changed

+77
-31
lines changed

src/components/player/CanvasPlayer.vue

+61-8
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,33 @@
11
<script setup lang="ts">
22
import movie from '/bird.mp4'
33
import { fabric } from 'fabric'
4-
import { onMounted, ref } from 'vue'
4+
import { storeToRefs } from 'pinia'
5+
import { onMounted, ref, watch } from 'vue'
56
import Logo from '~/assets/icons/icon-github.svg'
7+
import { usePlayerStore } from '~/stores/player'
8+
import emitter from '~/utils/bus'
69
710
defineProps<{
811
msg: string
912
}>()
13+
const container = ref<HTMLElement | null>(null)
14+
let video: HTMLVideoElement
15+
const playerStore = usePlayerStore()
16+
const { playStatus } = storeToRefs(playerStore)
17+
1018
let canvas: fabric.Canvas
1119
let ctx: CanvasRenderingContext2D
12-
const container = ref<HTMLElement | null>(null)
20+
let clipboard: fabric.Object | null = null
21+
22+
emitter.on('element:copy', onCopy)
23+
emitter.on('element:paste', onPaste)
24+
watch(playStatus, () => {
25+
if (playStatus.value) {
26+
video.play()
27+
} else {
28+
video.pause()
29+
}
30+
})
1331
1432
function initCanvas() {
1533
canvas = new fabric.Canvas('canvas', {
@@ -58,13 +76,10 @@ function drawStaticElements() {
5876
// 绘制视频
5977
// TODO 需要实现通过 webcodecs 进行视频解码后绘制
6078
function drawVideo() {
61-
const video = document.createElement('video')
79+
video = document.createElement('video')
6280
// video.src = 'https://assets.fedtop.com/picbed/movie.mp4'
6381
video.src = movie
64-
video.autoplay = true
6582
video.loop = true
66-
// 不静音就无法在未点击的情况下自动播放
67-
video.muted = true
6883
const canvasWidth = canvas.width!
6984
const canvasHeight = canvas.height!
7085
@@ -89,8 +104,6 @@ function drawVideo() {
89104
canvas.add(videoElement)
90105
canvas.setActiveObject(videoElement)
91106
continuouslyRepaint()
92-
// TODO 修改成外部控制
93-
video.play()
94107
})
95108
}
96109
@@ -151,6 +164,7 @@ function initControls() {
151164
// 添加删除按钮
152165
addDeleteButton()
153166
}
167+
154168
// editor 添加删除按钮
155169
function addDeleteButton() {
156170
// 有些地方也有用 fabric.Object.prototype.controls.delete
@@ -200,6 +214,45 @@ function resizePlayer() {
200214
201215
function canvasOnMouseDown() {}
202216
217+
// 复制元素
218+
function onCopy() {
219+
const activeObject = canvas.getActiveObject()
220+
if (!activeObject) return
221+
activeObject.clone((cloned: fabric.Object) => {
222+
clipboard = cloned
223+
})
224+
}
225+
226+
// TODO 视频元素为什么无法复制
227+
// 粘贴元素
228+
function onPaste() {
229+
if (clipboard === null) return
230+
// clone again, so you can do multiple copies.
231+
clipboard!.clone((clonedObj: any) => {
232+
canvas.discardActiveObject()
233+
clonedObj.set({
234+
left: clonedObj.left + 10,
235+
top: clonedObj.top + 10,
236+
evented: true
237+
})
238+
if (clonedObj.type === 'activeSelection') {
239+
// active selection needs a reference to the canvas.
240+
clonedObj.canvas = canvas
241+
clonedObj.forEachObject((obj: any) => {
242+
canvas.add(obj)
243+
})
244+
// this should solve the unselectability
245+
clonedObj.setCoords()
246+
} else {
247+
canvas.add(clonedObj)
248+
}
249+
clipboard!.top! += 10
250+
clipboard!.left! += 10
251+
canvas.setActiveObject(clonedObj)
252+
canvas.requestRenderAll()
253+
})
254+
}
255+
203256
onMounted((): void => {
204257
// 初始化画布
205258
initCanvas()

src/components/right-panel/RightPanel.vue

+16-23
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,19 @@
1-
<script setup lang="ts"></script>
1+
<script setup lang="ts">
2+
import emitter from '~/utils/bus'
3+
4+
function copy() {
5+
emitter.emit('element:copy')
6+
}
7+
function paste() {
8+
emitter.emit('element:paste')
9+
}
10+
</script>
211
<template>
312
<div class="right-panel w-[400px] bg-[#272836] flex justify-between">
413
<div class="p-8">
5-
<div role="tablist" class="tabs tabs-boxed mb-4">
6-
<a role="tab" class="tab">Tab 1</a>
7-
<a role="tab" class="tab tab-active overflow-hidden">Tab 2</a>
8-
<a role="tab" class="tab">Tab 3</a>
9-
<a role="tab" class="tab">Tab 4</a>
10-
</div>
11-
<div class="tooltip mb-4" data-tip="开发中...">
12-
<button class="btn">
13-
<span class="loading loading-spinner"></span>
14-
loading
15-
</button>
16-
</div>
17-
18-
<div>
19-
<input type="checkbox" class="toggle toggle-success" checked />
20-
<input type="checkbox" class="toggle toggle-warning" checked />
21-
<input type="checkbox" class="toggle toggle-info" checked />
22-
<input type="checkbox" class="toggle toggle-error" checked />
23-
</div>
24-
2514
<!-- Open the modal using ID.showModal() method -->
26-
<button class="btn btn-sm" onclick="my_modal_1.showModal()">open modal</button>
27-
<dialog id="my_modal_1" class="modal">
15+
<button class="btn btn-sm" onclick="testModal.showModal()">open modal</button>
16+
<dialog id="testModal" class="modal">
2817
<div class="modal-box">
2918
<h3 class="font-bold text-lg">Hello!</h3>
3019
<p class="py-4">Press ESC key or click the button below to close</p>
@@ -36,6 +25,10 @@
3625
</div>
3726
</div>
3827
</dialog>
28+
<div class="my-4 flex flex-col gap-4">
29+
<button class="btn btn-sm" @click="copy">Copy Selected Objects</button>
30+
<button class="btn btn-sm" @click="paste">Paste Selected Objects</button>
31+
</div>
3932
</div>
4033
<div class="w-[60px] bg-[#1c1c26] p-8"></div>
4134
</div>

0 commit comments

Comments
 (0)