@@ -25,7 +25,7 @@ | |||||
</div> | </div> | ||||
{{ $t("myCreating.title") }} | {{ $t("myCreating.title") }} | ||||
</div> | </div> | ||||
<!-- 测试功能页 --> | |||||
<!-- 测试功能页 v-if="false"--> | |||||
<div | <div | ||||
v-if="false" | v-if="false" | ||||
class="myRouter-item" | class="myRouter-item" | ||||
@@ -8,10 +8,13 @@ export {} | |||||
declare module '@vue/runtime-core' { | declare module '@vue/runtime-core' { | ||||
export interface GlobalComponents { | export interface GlobalComponents { | ||||
Breadcrumb: typeof import('./../components/Breadcrumb/index.vue')['default'] | Breadcrumb: typeof import('./../components/Breadcrumb/index.vue')['default'] | ||||
ElAlert: typeof import('element-plus/es')['ElAlert'] | |||||
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] | ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb'] | ||||
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] | ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] | ||||
ElButton: typeof import('element-plus/es')['ElButton'] | ElButton: typeof import('element-plus/es')['ElButton'] | ||||
ElCard: typeof import('element-plus/es')['ElCard'] | |||||
ElCol: typeof import('element-plus/es')['ElCol'] | ElCol: typeof import('element-plus/es')['ElCol'] | ||||
ElColorPicker: typeof import('element-plus/es')['ElColorPicker'] | |||||
ElDialog: typeof import('element-plus/es')['ElDialog'] | ElDialog: typeof import('element-plus/es')['ElDialog'] | ||||
ElDivider: typeof import('element-plus/es')['ElDivider'] | ElDivider: typeof import('element-plus/es')['ElDivider'] | ||||
ElDropdown: typeof import('element-plus/es')['ElDropdown'] | ElDropdown: typeof import('element-plus/es')['ElDropdown'] | ||||
@@ -21,35 +24,54 @@ declare module '@vue/runtime-core' { | |||||
ElFormItem: typeof import('element-plus/es')['ElFormItem'] | ElFormItem: typeof import('element-plus/es')['ElFormItem'] | ||||
ElIcon: typeof import('element-plus/es')['ElIcon'] | ElIcon: typeof import('element-plus/es')['ElIcon'] | ||||
ElInput: typeof import('element-plus/es')['ElInput'] | ElInput: typeof import('element-plus/es')['ElInput'] | ||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber'] | |||||
ElLink: typeof import('element-plus/es')['ElLink'] | |||||
ElOption: typeof import('element-plus/es')['ElOption'] | ElOption: typeof import('element-plus/es')['ElOption'] | ||||
ElPagination: typeof import('element-plus/es')['ElPagination'] | ElPagination: typeof import('element-plus/es')['ElPagination'] | ||||
ElPopover: typeof import('element-plus/es')['ElPopover'] | |||||
ElRadio: typeof import('element-plus/es')['ElRadio'] | |||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] | |||||
ElRow: typeof import('element-plus/es')['ElRow'] | ElRow: typeof import('element-plus/es')['ElRow'] | ||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] | ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] | ||||
ElSelect: typeof import('element-plus/es')['ElSelect'] | ElSelect: typeof import('element-plus/es')['ElSelect'] | ||||
ElSwitch: typeof import('element-plus/es')['ElSwitch'] | ElSwitch: typeof import('element-plus/es')['ElSwitch'] | ||||
ElTable: typeof import('element-plus/es')['ElTable'] | |||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn'] | |||||
ElTabPane: typeof import('element-plus/es')['ElTabPane'] | ElTabPane: typeof import('element-plus/es')['ElTabPane'] | ||||
ElTabs: typeof import('element-plus/es')['ElTabs'] | ElTabs: typeof import('element-plus/es')['ElTabs'] | ||||
ElTag: typeof import('element-plus/es')['ElTag'] | |||||
ElTooltip: typeof import('element-plus/es')['ElTooltip'] | ElTooltip: typeof import('element-plus/es')['ElTooltip'] | ||||
ElTree: typeof import('element-plus/es')['ElTree'] | |||||
ElTreeSelect: typeof import('element-plus/es')['ElTreeSelect'] | |||||
ElUpload: typeof import('element-plus/es')['ElUpload'] | |||||
GithubCorner: typeof import('./../components/GithubCorner/index.vue')['default'] | GithubCorner: typeof import('./../components/GithubCorner/index.vue')['default'] | ||||
Hamburger: typeof import('./../components/Hamburger/index.vue')['default'] | Hamburger: typeof import('./../components/Hamburger/index.vue')['default'] | ||||
IconSelect: typeof import('./../components/IconSelect/index.vue')['default'] | IconSelect: typeof import('./../components/IconSelect/index.vue')['default'] | ||||
IEpCaretBottom: typeof import('~icons/ep/caret-bottom')['default'] | |||||
IEpCaretTop: typeof import('~icons/ep/caret-top')['default'] | |||||
IEpClose: typeof import('~icons/ep/close')['default'] | IEpClose: typeof import('~icons/ep/close')['default'] | ||||
IEpCloseBold: typeof import('~icons/ep/close-bold')['default'] | IEpCloseBold: typeof import('~icons/ep/close-bold')['default'] | ||||
IEpCollection: typeof import('~icons/ep/collection')['default'] | |||||
IEpDelete: typeof import('~icons/ep/delete')['default'] | IEpDelete: typeof import('~icons/ep/delete')['default'] | ||||
IEpDocumentAdd: typeof import('~icons/ep/document-add')['default'] | IEpDocumentAdd: typeof import('~icons/ep/document-add')['default'] | ||||
IEpDownload: typeof import('~icons/ep/download')['default'] | IEpDownload: typeof import('~icons/ep/download')['default'] | ||||
IEpEdit: typeof import('~icons/ep/edit')['default'] | IEpEdit: typeof import('~icons/ep/edit')['default'] | ||||
IEpFolder: typeof import('~icons/ep/folder')['default'] | |||||
IEpFolderAdd: typeof import('~icons/ep/folder-add')['default'] | |||||
IEpGoods: typeof import('~icons/ep/goods')['default'] | IEpGoods: typeof import('~icons/ep/goods')['default'] | ||||
IEpHeadset: typeof import('~icons/ep/headset')['default'] | IEpHeadset: typeof import('~icons/ep/headset')['default'] | ||||
IEpLoading: typeof import('~icons/ep/loading')['default'] | IEpLoading: typeof import('~icons/ep/loading')['default'] | ||||
IEpLock: typeof import('~icons/ep/lock')['default'] | IEpLock: typeof import('~icons/ep/lock')['default'] | ||||
IEpMenu: typeof import('~icons/ep/menu')['default'] | IEpMenu: typeof import('~icons/ep/menu')['default'] | ||||
IEpMic: typeof import('~icons/ep/mic')['default'] | IEpMic: typeof import('~icons/ep/mic')['default'] | ||||
IEpPlus: typeof import('~icons/ep/plus')['default'] | |||||
IEpPosition: typeof import('~icons/ep/position')['default'] | |||||
IEpRefresh: typeof import('~icons/ep/refresh')['default'] | |||||
IEpRefreshLeft: typeof import('~icons/ep/refresh-left')['default'] | |||||
IEpSearch: typeof import('~icons/ep/search')['default'] | IEpSearch: typeof import('~icons/ep/search')['default'] | ||||
IEpSetting: typeof import('~icons/ep/setting')['default'] | IEpSetting: typeof import('~icons/ep/setting')['default'] | ||||
IEpSwitchButton: typeof import('~icons/ep/switch-button')['default'] | IEpSwitchButton: typeof import('~icons/ep/switch-button')['default'] | ||||
IEpTop: typeof import('~icons/ep/top')['default'] | |||||
IEpUploadFilled: typeof import('~icons/ep/upload-filled')['default'] | |||||
IEpVideoCamera: typeof import('~icons/ep/video-camera')['default'] | |||||
IEpVideoPause: typeof import('~icons/ep/video-pause')['default'] | IEpVideoPause: typeof import('~icons/ep/video-pause')['default'] | ||||
IEpVideoPlay: typeof import('~icons/ep/video-play')['default'] | IEpVideoPlay: typeof import('~icons/ep/video-play')['default'] | ||||
LangSelect: typeof import('./../components/LangSelect/index.vue')['default'] | LangSelect: typeof import('./../components/LangSelect/index.vue')['default'] | ||||
@@ -64,10 +86,9 @@ declare module '@vue/runtime-core' { | |||||
SizeSelect: typeof import('./../components/SizeSelect/index.vue')['default'] | SizeSelect: typeof import('./../components/SizeSelect/index.vue')['default'] | ||||
SvgIcon: typeof import('./../components/SvgIcon/index.vue')['default'] | SvgIcon: typeof import('./../components/SvgIcon/index.vue')['default'] | ||||
WangEditor: typeof import('./../components/WangEditor/index.vue')['default'] | WangEditor: typeof import('./../components/WangEditor/index.vue')['default'] | ||||
Websocket: typeof import('./../components/websocket.vue')['default'] | |||||
Websoket: typeof import('./../components/websoket.vue')['default'] | |||||
} | } | ||||
export interface ComponentCustomProperties { | export interface ComponentCustomProperties { | ||||
vInfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll'] | vInfiniteScroll: typeof import('element-plus/es')['ElInfiniteScroll'] | ||||
vLoading: typeof import('element-plus/es')['ElLoadingDirective'] | |||||
} | } | ||||
} | } |
@@ -18,18 +18,42 @@ | |||||
:placeholder="$t('createVideo.typeTitle')" | :placeholder="$t('createVideo.typeTitle')" | ||||
/> | /> | ||||
<el-icon class="icon-edit"><i-ep-edit /></el-icon> | <el-icon class="icon-edit"><i-ep-edit /></el-icon> | ||||
<!-- 编辑字幕框 --> | |||||
</div> | |||||
<div v-if="imgUrl&&SubtitlesSwitch" class="editSubtitlesBox "> | |||||
<div class="item">X: <el-input | |||||
v-model="SubtitlesTop" | |||||
width="30" | |||||
/></div> | |||||
<div class="item">Y: <el-input | |||||
v-model="SubtitlesLeft" | |||||
width="30" | |||||
/></div> | |||||
<div class="item">Size: <el-input | |||||
v-model="SubtitlesSize" | |||||
width="30" | |||||
/></div> | |||||
<div class="item">Color: <el-color-picker v-model="SubtitlesColor" show-alpha /></div> | |||||
<div class="item">BGC: <el-color-picker v-model="SubtitlesBgc" show-alpha /></div> | |||||
</div> | </div> | ||||
</el-row> | </el-row> | ||||
<!-- 中间展示大图 --> | <!-- 中间展示大图 --> | ||||
<div class="bigImg inmiddle"> | |||||
<div v-if="false" class="canvasBox"> | |||||
<canvas id="myCanvas" ref="myCanvasRef" > | |||||
</canvas> | |||||
</div> | |||||
<img id="canvasImg" ref="canvasImgRef" :src="imgUrl" alt="" class="inmiddle" /> | |||||
<div ref="canvasImgBox" class="bigImg inmiddle"> | |||||
<img id="canvasImg" :src="imgUrl" alt="" class="" /> | |||||
<div ref="SubtitlesBox" @mousedown="handleDrag" :style="SubtitlesStyle" v-if="SubtitlesSwitch" class="SubtitlesBox">请在文案区编辑您的正文 | |||||
<div class="stretchBox box1"></div> | |||||
<div class="stretchBox box2"></div> | |||||
<div class="stretchBox box3"></div> | |||||
<div class="stretchBox box4"></div> | |||||
<div class="stretchBox box5"></div> | |||||
<div class="stretchBox box6"></div> | |||||
<div class="stretchBox box7"></div> | |||||
<div class="stretchBox box8"></div> | |||||
</div> | |||||
</div> | </div> | ||||
<!-- 字幕开关 --> | <!-- 字幕开关 --> | ||||
<div v-if="false" class="SubtitlesSwitch"> | |||||
<div v-if="imgUrl" class="SubtitlesSwitch"> | |||||
<p>{{ $t('createVideo.subtitles') }}</p> | <p>{{ $t('createVideo.subtitles') }}</p> | ||||
<el-switch v-model="SubtitlesSwitch" /> | <el-switch v-model="SubtitlesSwitch" /> | ||||
</div> | </div> | ||||
@@ -1915,42 +1939,49 @@ function copyAnswerContent() { | |||||
//#endregion ---------------------------- | //#endregion ---------------------------- | ||||
//#region 字幕部分 | //#region 字幕部分 | ||||
const canvasImgBox=ref(null) //图片外盒子dom | |||||
const SubtitlesBox=ref(null) //字幕盒子dom | |||||
const SubtitlesSwitch=ref(false) //字幕开关 | const SubtitlesSwitch=ref(false) //字幕开关 | ||||
const canvas = ref(null); //canvas对象 | |||||
const myCanvasRef = ref(null); //画布dom | |||||
const canvasImgRef = ref(null); //图片dom | |||||
const imgWidth=ref(null) | |||||
const imgHeight=ref(null) | |||||
const myText = ref("hello world"); | |||||
const iText = new fabric.IText(myText.value, { | |||||
left: 100, | |||||
top: 100, | |||||
}); | |||||
function setCanvasText() { | |||||
canvas.value = new fabric.Canvas("myCanvas",{ | |||||
width:imgWidth.value, | |||||
height:imgHeight.value, | |||||
}); | |||||
iText.on("mouseup", function () { | |||||
console.log(iText, "iText"); | |||||
console.log(iText.angle.toFixed(0), "angle"); | |||||
console.log(iText.left.toFixed(0), "left"); | |||||
console.log(iText.top.toFixed(0), "top"); | |||||
console.log(iText.width.toFixed(0), "width"); | |||||
console.log(iText.height.toFixed(0), "height"); | |||||
}); | |||||
canvas.value.add(iText); | |||||
} | |||||
const SubtitlesTop=ref(0) //字幕Y轴 | |||||
const SubtitlesLeft=ref(0) //字幕X轴 | |||||
const SubtitlesSize=ref(18) //字幕字号 | |||||
const SubtitlesColor=ref('rgba(0, 0, 0, 1)') //字幕字色 | |||||
const SubtitlesBgc=ref('rgba(255, 255, 255,1 )') //字幕背景色 | |||||
// 计算属性来计算盒子位置 | |||||
const SubtitlesStyle = computed(() => { | |||||
return { | |||||
top: SubtitlesTop.value + 'px', | |||||
left: SubtitlesLeft.value + 'px', | |||||
fontSize: SubtitlesSize.value+ 'px', | |||||
color:SubtitlesColor.value, | |||||
backgroundColor: SubtitlesBgc.value, | |||||
}; | |||||
}); | |||||
// 拖动盒子 | |||||
const handleDrag = (event) => { | |||||
event.preventDefault(); | |||||
const boxElement = canvasImgBox.value; | |||||
const imageElement = SubtitlesBox.value; | |||||
const offsetX = event.clientX - imageElement.offsetLeft; | |||||
const offsetY = event.clientY - imageElement.offsetTop; | |||||
const onMouseMove = (event) => { | |||||
const newX = event.clientX - offsetX; | |||||
const newY = event.clientY - offsetY; | |||||
SubtitlesLeft.value= newX; | |||||
SubtitlesTop.value = newY; | |||||
}; | |||||
const onMouseUp = () => { | |||||
document.removeEventListener('mousemove', onMouseMove); | |||||
document.removeEventListener('mouseup', onMouseUp); | |||||
}; | |||||
document.addEventListener('mousemove', onMouseMove); | |||||
document.addEventListener('mouseup', onMouseUp); | |||||
}; | |||||
// 监听字幕显示 | // 监听字幕显示 | ||||
watch( | watch( | ||||
() => SubtitlesSwitch, | () => SubtitlesSwitch, | ||||
async (newValue, oldValue) => { | async (newValue, oldValue) => { | ||||
if(SubtitlesSwitch.value) { | |||||
setCanvasText() | |||||
} else { | |||||
canvas.value.remove(iText); | |||||
canvas.value=null; | |||||
} | |||||
}, | }, | ||||
{ deep: true } | { deep: true } | ||||
); | ); | ||||
@@ -1958,11 +1989,8 @@ watch( | |||||
watch( | watch( | ||||
() => imgUrl.value, | () => imgUrl.value, | ||||
async (newValue, oldValue) => { | async (newValue, oldValue) => { | ||||
await nextTick() | |||||
if(canvas.value) { | |||||
canvas.value.width=imgWidth.value, | |||||
canvas.value.height=imgHeight.value | |||||
} | |||||
await nextTick() | |||||
// console.log(getComputedStyle(document.getElementById("canvasImg"),null)); | |||||
}, | }, | ||||
{ deep: true } | { deep: true } | ||||
); | ); | ||||
@@ -2013,7 +2041,7 @@ onMounted(async () => { | |||||
} | } | ||||
}); | }); | ||||
createWS(); //创建websocket | createWS(); //创建websocket | ||||
}); | }); | ||||
//#endregion ---------------------------- | //#endregion ---------------------------- | ||||
@@ -2067,6 +2095,34 @@ onUnmounted(() => { | |||||
height: 67%; | height: 67%; | ||||
// height: calc(70vh - 80px ); | // height: calc(70vh - 80px ); | ||||
margin-bottom: 20px; | margin-bottom: 20px; | ||||
.editSubtitlesBox{ | |||||
display: flex; | |||||
justify-content: flex-start; | |||||
padding-right: 80px; | |||||
margin-left: 10px; | |||||
margin-right: 80px; | |||||
border-radius: 20px; | |||||
flex: 1; | |||||
line-height: 35px; | |||||
background-color: #f1f2f6; | |||||
font-size: 16px; | |||||
.item { | |||||
display: flex; | |||||
align-items: center; | |||||
margin-left: 10px; | |||||
.el-input { | |||||
width: 60px; | |||||
height: 25px; | |||||
} | |||||
} | |||||
:deep(.el-input__wrapper) { | |||||
border: none; | |||||
border: 2px solid #000; | |||||
border-radius: 5px; | |||||
box-shadow: none; | |||||
} | |||||
} | |||||
.uploadBtn { | .uploadBtn { | ||||
position: relative; | position: relative; | ||||
padding: 10px 15px; | padding: 10px 15px; | ||||
@@ -2086,34 +2142,74 @@ onUnmounted(() => { | |||||
width: 50%; | width: 50%; | ||||
height: 88%; | height: 88%; | ||||
margin-top: 20px; | margin-top: 20px; | ||||
.canvasBox { | |||||
.SubtitlesBox { | |||||
position: absolute; | position: absolute; | ||||
left: 0; | |||||
top: 0; | |||||
width: 100%; | |||||
height: 100%; | |||||
background-color: skyblue; | |||||
opacity: 0.5; | |||||
// z-index: 9; | |||||
.canvas-container { | |||||
// background-color: red; | |||||
// z-index: 9; | |||||
// width: 100%!important; | |||||
// height: 100%!important; | |||||
// #myCanvas { | |||||
// width: 100%!important; | |||||
// height: 100%!important; | |||||
// } | |||||
// .upper-canvas { | |||||
// width: 100%!important; | |||||
// height: 100%!important; | |||||
// } | |||||
user-select: none; | |||||
width: 300px; | |||||
padding: 5px 5px; | |||||
border: 2px solid #00ff00; | |||||
text-align: center; | |||||
background-color: #fff; | |||||
cursor: move; | |||||
.stretchBox { | |||||
position: absolute; | |||||
width: 10px; | |||||
height: 10px; | |||||
background-color: #fff; | |||||
} | |||||
.box1 { | |||||
top: -5px; | |||||
left: -5px; | |||||
cursor: nwse-resize; | |||||
} | |||||
.box2 { | |||||
top: -5px; | |||||
left: 50%; | |||||
transform: translateX(-50%); | |||||
cursor: ns-resize; | |||||
} | |||||
.box3 { | |||||
top: -5px; | |||||
left:100%; | |||||
transform: translateX(-5px); | |||||
cursor: nesw-resize; | |||||
} | |||||
.box4 { | |||||
top: 50%; | |||||
left: -5px; | |||||
transform: translateY(-5px); | |||||
cursor: ew-resize; | |||||
} | |||||
.box5 { | |||||
top: 50%; | |||||
left:100%; | |||||
transform: translate(-5px,-5px); | |||||
cursor: ew-resize; | |||||
} | |||||
.box6 { | |||||
top: 100%; | |||||
left: -5px; | |||||
transform: translateY(-5px); | |||||
cursor: nesw-resize; | |||||
} | |||||
.box7 { | |||||
top: 100%; | |||||
left: 50%; | |||||
transform: translate(-5px,-5px); | |||||
cursor: ns-resize; | |||||
} | |||||
.box8 { | |||||
top: 100%; | |||||
left: 100%; | |||||
transform: translate(-5px,-5px); | |||||
cursor: nwse-resize; | |||||
} | } | ||||
} | } | ||||
img { | img { | ||||
// position: absolute; | |||||
// left: 0; | |||||
// top: 0; | |||||
position: absolute; | |||||
left: 0; | |||||
top: 0; | |||||
max-width: 100%; | max-width: 100%; | ||||
max-height: 100%; | max-height: 100%; | ||||
border-radius: 15px; | border-radius: 15px; | ||||
@@ -1,136 +1,92 @@ | |||||
<template> | <template> | ||||
<div class="page"> | |||||
<div class="canvasBox"> | |||||
<canvas id="myCanvas" width="960" height="540"> </canvas> | |||||
<img | |||||
style="display: none; width: 200px; height: 200px" | |||||
id="bjImg" | |||||
src="../../assets/img/star.png" | |||||
alt="" | |||||
/> | |||||
<div> | |||||
<img src="../../assets/img/trueImg.png" ref="image" /> | |||||
<div | |||||
class="box" | |||||
ref="box" | |||||
:style="{ top: boxPosition.top + 'px', left: boxPosition.left + 'px' }" | |||||
@mousedown="handleDrag" | |||||
> | |||||
<!-- 这里可以放置盒子的内容 --> | |||||
</div> | </div> | ||||
<div class="container"> | |||||
<div class="box red"></div> | |||||
<div class="box white"></div> | |||||
<div class="box green"></div> | |||||
<div class="resizable-box" v-if="isResizing" @mousedown="handleResize"> | |||||
字幕 | |||||
</div> | </div> | ||||
<button @click="handleRotate">旋转</button> | |||||
</div> | </div> | ||||
</template> | </template> | ||||
<script setup> | <script setup> | ||||
//#region 导入 | |||||
import { fabric } from "fabric"; | |||||
import { ref, reactive } from "vue"; | |||||
//#endregion --------------------------- | |||||
const image = ref(null); | |||||
const box = ref(null); | |||||
const boxPosition = reactive({ top: 0, left: 0 }); | |||||
const isResizing = ref(false); | |||||
const rotationAngle = ref(0); | |||||
//#region 画布交互 | |||||
// let canvas = new fabric.Canvas("myCanvas"); | |||||
let canvas = null; | |||||
function setCanvasText() { | |||||
// let imgElement = document.getElementById("bjImg"); //声明我们的图片 | |||||
const myText = ref("hello world"); | |||||
const iText = new fabric.IText(myText.value, { | |||||
left: 100, | |||||
top: 100, | |||||
}); | |||||
canvas.add(iText); | |||||
iText.on("mouseup", function () { | |||||
console.log(iText, "iText"); | |||||
console.log(iText.angle.toFixed(0), "angle"); | |||||
console.log(iText.left.toFixed(0), "left"); | |||||
console.log(iText.top.toFixed(0), "top"); | |||||
console.log(iText.width.toFixed(0), "width"); | |||||
console.log(iText.height.toFixed(0), "height"); | |||||
}); | |||||
} | |||||
//#endregion --------------------------- | |||||
// 盒子位置拖动 | |||||
const handleDrag = (event) => { | |||||
event.preventDefault(); | |||||
const boxElement = box.value; | |||||
const imageElement = image.value; | |||||
onMounted(() => { | |||||
canvas = new fabric.Canvas("myCanvas"); | |||||
setCanvasText(); | |||||
// let imgInstance = new fabric.Image(imgElement, { | |||||
// //设置图片位置和样子 | |||||
// // left: 100, | |||||
// // top: 100, | |||||
// // width: 400, | |||||
// // height: 200, | |||||
// // angle: 30, //设置图形顺时针旋转角度 | |||||
// }); | |||||
// console.log(imgInstance); | |||||
// canvas.add(imgInstance); | |||||
}); | |||||
</script> | |||||
const offsetX = event.clientX - imageElement.offsetLeft; | |||||
const offsetY = event.clientY - imageElement.offsetTop; | |||||
<style lang="scss" scoped> | |||||
.page { | |||||
position: relative; | |||||
padding: 10px; | |||||
} | |||||
.canvasBox { | |||||
// position: absolute; | |||||
// top: 50%; | |||||
// left: 50%; | |||||
// transform: translate(-50%); | |||||
width: 100%; | |||||
height: 100%; | |||||
.canvas-container { | |||||
} | |||||
background-color: green; | |||||
.canvas { | |||||
background-color: skyblue; | |||||
.bjImg { | |||||
position: absolute; | |||||
top: 0; | |||||
left: 0; | |||||
width: 100px; | |||||
height: 100px; | |||||
z-index: 999; | |||||
img { | |||||
width: 100px; | |||||
height: 100px; | |||||
} | |||||
} | |||||
.people { | |||||
} | |||||
.other { | |||||
} | |||||
} | |||||
} | |||||
</style> | |||||
const onMouseMove = (event) => { | |||||
const newX = event.clientX - offsetX; | |||||
const newY = event.clientY - offsetY; | |||||
<style lang="scss" scoped> | |||||
.container { | |||||
display: flex; | |||||
align-items: center; | |||||
justify-content: space-between; | |||||
width: 80px; | |||||
height: 20px; | |||||
perspective: 500px; | |||||
transition: transform 0.5s; | |||||
} | |||||
boxPosition.left = newX; | |||||
boxPosition.top = newY; | |||||
}; | |||||
.box { | |||||
width: 20px; | |||||
height: 20px; | |||||
transition: transform 0.5s; | |||||
transform-style: preserve-3d; | |||||
} | |||||
const onMouseUp = () => { | |||||
document.removeEventListener("mousemove", onMouseMove); | |||||
document.removeEventListener("mouseup", onMouseUp); | |||||
}; | |||||
.red { | |||||
background-color: red; | |||||
} | |||||
document.addEventListener("mousemove", onMouseMove); | |||||
document.addEventListener("mouseup", onMouseUp); | |||||
}; | |||||
.white { | |||||
background-color: white; | |||||
transform: translateZ(20px); | |||||
} | |||||
// 边框拖动 | |||||
const handleResize = () => { | |||||
isResizing.value = true; | |||||
const onMouseMove = (event) => { | |||||
// 处理拉伸逻辑 | |||||
}; | |||||
const onMouseUp = () => { | |||||
isResizing.value = false; | |||||
document.removeEventListener("mousemove", onMouseMove); | |||||
document.removeEventListener("mouseup", onMouseUp); | |||||
}; | |||||
.green { | |||||
background-color: green; | |||||
transform: translateZ(-20px); | |||||
document.addEventListener("mousemove", onMouseMove); | |||||
document.addEventListener("mouseup", onMouseUp); | |||||
}; | |||||
// 图片旋转 | |||||
const handleRotate = () => { | |||||
rotationAngle.value += 90; | |||||
}; | |||||
</script> | |||||
<style> | |||||
.box { | |||||
position: absolute; | |||||
width: 100px; | |||||
height: 100px; | |||||
background-color: rgba(0, 0, 0, 0.5); | |||||
cursor: move; | |||||
} | } | ||||
.container:hover .box { | |||||
transform: rotateY(180deg); | |||||
.resizable-box { | |||||
border: 2px dashed #000; | |||||
resize: both; | |||||
overflow: auto; | |||||
} | } | ||||
</style> | </style> |