commit
fa5e132c2d
|
@ -1453,14 +1453,14 @@ export class History {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 清除记录
|
||||
clean() {
|
||||
this.FabricVue?.canvas?.clear()
|
||||
this.index = 0
|
||||
this.diffs = []
|
||||
this.canvasData = {}
|
||||
}
|
||||
|
||||
// 重新加载历史记录
|
||||
initHistory() {
|
||||
const canvas = this.FabricVue.canvas
|
||||
if (canvas) {
|
||||
|
|
|
@ -69,7 +69,7 @@ export const createWindow = async (type, data) => {
|
|||
// parent: mainWin, // 父窗口
|
||||
// autoClose: true, // 关闭窗口后自动关闭
|
||||
}
|
||||
// data.isConsole = true // 是否开启控制台
|
||||
data.isConsole = true // 是否开启控制台
|
||||
data.option = {...defOption, ...option}
|
||||
const win = await toolWindow(data)
|
||||
win.type = type // 唯一标识
|
||||
|
@ -145,7 +145,7 @@ export function toolWindow({url, isConsole, option={}}) {
|
|||
// 内部监听器-是否打印
|
||||
if (!!isConsole) {
|
||||
win.webContents.on('console-message', (e,leve,m,lin,s) => {
|
||||
console.log('console-msg: ', m)
|
||||
console.log(m)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
|
|
@ -4,27 +4,28 @@
|
|||
</template>
|
||||
<script setup>
|
||||
// 功能说明:画板
|
||||
import { ref, onMounted, watchEffect } from 'vue'
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import {FabricVue, TYPES} from '@/plugins/fabric'
|
||||
const canvasRef = ref(null) // 画布
|
||||
const isMouse = ref(true) // 鼠标是否在画布上
|
||||
const props = defineProps({
|
||||
modelValue: String
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
// 画板初始化配置
|
||||
onMounted(async() => {
|
||||
if (canvasRef.value) {
|
||||
FabricVue.drawConfig.drawColors = ['red']
|
||||
FabricVue.boardConfig.mode = TYPES.ActionMode.OTHER
|
||||
FabricVue.boardConfig.backgroundColor = 'transparent'
|
||||
const option = { freeDrawingCursor: 'default' }
|
||||
await FabricVue.initCanvas(canvasRef.value, option)
|
||||
}
|
||||
})
|
||||
|
||||
// 监听
|
||||
watchEffect(() => {
|
||||
// console.log('board 画板: ', props.modelValue)
|
||||
isMouse.value = false
|
||||
switch(props.modelValue) {
|
||||
watch(() => props.modelValue, (newVal, oldVal) => {
|
||||
// console.log(newVal, oldVal)
|
||||
switch(newVal) {
|
||||
case 'select': // 选择模式
|
||||
FabricVue.handleMode(TYPES.ActionMode.OTHER)
|
||||
break
|
||||
|
@ -35,6 +36,10 @@ watchEffect(() => {
|
|||
case 'eraser': // 板擦模式
|
||||
FabricVue.handleMode(TYPES.ActionMode.ERASE)
|
||||
break
|
||||
case 'clear': // 清空画布
|
||||
FabricVue.history?.clean()
|
||||
emit('update:modelValue', oldVal)
|
||||
break
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
|
||||
/**
|
||||
* @description 工具栏-拖拽 自定义指令
|
||||
*/
|
||||
class Drag {
|
||||
isDrag = false // 是否开始拖拽
|
||||
rafId // requestAnimationFrame id
|
||||
x = 0 // 鼠标按下时的x坐标
|
||||
y = 0 // 鼠标按下时的y坐标
|
||||
data // 其他参数 元素实际坐标值
|
||||
el; handle; // el, handle 挂载元素和拖拽元素
|
||||
pos // 拖拽元素实际坐标值
|
||||
max // 拖拽元素最大边界
|
||||
// 构造器
|
||||
constructor(el, binding) {
|
||||
this.el = el
|
||||
const { value } = binding
|
||||
const handleSelector = value instanceof Object ? value.handle : value
|
||||
if (!!handleSelector) {
|
||||
if (handleSelector instanceof HTMLElement) this.handle = handleSelector
|
||||
else {
|
||||
this.handle = document.querySelector(handleSelector)
|
||||
// .forEach((child) => { this.handleArray.push(child) })
|
||||
}
|
||||
}
|
||||
if (!this.handle) this.handle = el // 默认为当前元素
|
||||
// 被拖拽元素初始坐标
|
||||
const pos = this.handle?.getBoundingClientRect()
|
||||
this.data = {left:this.toRound(pos.left), top:this.toRound(pos.top)}
|
||||
this.pos = pos
|
||||
this.max = {w: window.innerWidth, h: window.innerHeight}
|
||||
}
|
||||
// 移入
|
||||
down(e) {
|
||||
this.isDrag = true
|
||||
const {cx, cy} = this.getMousePos(e)
|
||||
this.x = cx
|
||||
this.y = cy
|
||||
// 手动-触发事件 v-drag-start
|
||||
this.el.dispatchEvent(new CustomEvent('v-drag-start', {detail:{drag: this}}))
|
||||
}
|
||||
// 移动过程
|
||||
move = (e) => {
|
||||
if (!this.isDrag) return
|
||||
if (this.rafId) cancelAnimationFrame(this.rafId) // 清除上一次动画
|
||||
this.rafId = requestAnimationFrame(() => this.updatePosition(e))
|
||||
}
|
||||
// 移出
|
||||
up = (e) => {
|
||||
// e.preventDefault(); // 阻止默认行为
|
||||
// e.stopPropagation(); // 阻止事件传播
|
||||
this.isDrag = false
|
||||
cancelAnimationFrame(this.rafId)
|
||||
this.rafId = null
|
||||
document.removeEventListener('mousemove', this.move);
|
||||
document.removeEventListener('mouseup', this.up);
|
||||
document.addEventListener('touchmove', this.move);
|
||||
document.addEventListener('touchend', this.up);
|
||||
}
|
||||
// 业务逻辑
|
||||
updatePosition(e) {
|
||||
const {cx, cy} = this.getMousePos(e)
|
||||
const {left, top} = this.data
|
||||
const dx = cx - this.x
|
||||
const dy = cy - this.y
|
||||
this.x = cx
|
||||
this.y = cy
|
||||
const {x, y} = this.getPos(left + dx, top + dy) // 调用边界函数
|
||||
this.data.left = x // 设置边界-x
|
||||
this.data.top = y // 设置边界-y
|
||||
// console.log(JSON.stringify(this))
|
||||
this.handle.style.left = `${this.data?.left}px`
|
||||
this.handle.style.top = `${this.data?.top}px`
|
||||
this.handle.style.bottom = 'unset'
|
||||
this.handle.style.transform = 'unset'
|
||||
this.rafId = requestAnimationFrame(() => this.updatePosition(e))
|
||||
}
|
||||
// 获取鼠标位置 | Get mouse position
|
||||
getMousePos(e){
|
||||
let cx = e.clientX || e.touches[0].clientX
|
||||
let cy = e.clientY || e.touches[0].clientY
|
||||
cx = this.toRound(cx)
|
||||
cy = this.toRound(cy)
|
||||
return {cx, cy}
|
||||
}
|
||||
// 获取移动后坐标
|
||||
getPos(x, y) {
|
||||
const w = this.max.w - this.toRound(this.el.clientWidth)
|
||||
const h = this.max.h - this.toRound(this.el.clientHeight)
|
||||
x = x < 0 ? 0 : x > w ? w : x
|
||||
y = y < 0 ? 0 : y > h ? h : y
|
||||
return { x, y }
|
||||
}
|
||||
// 小数转整数
|
||||
toRound = v => Math.round(v)
|
||||
}
|
||||
export default {
|
||||
mounted(el, binding) {
|
||||
// const { style } = binding.value
|
||||
const drag = new Drag(el, binding)
|
||||
const dragStart = (e) => {
|
||||
drag.down(e)
|
||||
document.addEventListener('mousemove', drag.move);
|
||||
document.addEventListener('mouseup', drag.up);
|
||||
document.addEventListener('touchmove', drag.move);
|
||||
document.addEventListener('touchend', drag.up);
|
||||
}
|
||||
el.addEventListener('mousedown', dragStart)
|
||||
el.addEventListener('touchstart', dragStart)
|
||||
},
|
||||
}
|
|
@ -1,14 +1,13 @@
|
|||
<template>
|
||||
<div class="warp-all">
|
||||
<board-vue v-model="tabActive"></board-vue>
|
||||
<!-- 底部工具栏 -->
|
||||
<div ref="tool" class="tool-bottom-all" :style="dataPos.style"
|
||||
<!-- 底部工具栏 :style="dataPos.style"-->
|
||||
<div class="tool-bottom-all"
|
||||
@mouseenter="mouseChange(0)" @mouseleave="mouseChange(1)">
|
||||
<div @mousedown="e => dargHandle(e,'down')"
|
||||
@mousemove="e => dargHandle(e,'move')"
|
||||
@mouseup="e => dargHandle(e,'up')">
|
||||
<div v-drag="{handle:'.tool-bottom-all', dragtime}"
|
||||
@v-drag-start="dragtime = Date.now()">
|
||||
<div class="c-logo" @click="logoHandle" title="拖动 | 折叠 | 展开">
|
||||
<el-image :src="logo" />
|
||||
<el-image :src="logo" draggable="false" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="tool-btns" v-show="!isFold">
|
||||
|
@ -16,7 +15,7 @@
|
|||
@change="tabChange">
|
||||
<template #default="{item}">
|
||||
<div class="c-btn flex flex-col items-center gap-2 p-2">
|
||||
<i class="iconfont" :class="item.icon"></i>
|
||||
<i class="iconfont" :class="item.icon" :style="item.style"></i>
|
||||
<span>{{item.label}}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -31,27 +30,27 @@
|
|||
import { onMounted, ref, reactive } from 'vue'
|
||||
import logo from '@root/resources/icon.png' // logo
|
||||
import boardVue from './components/board.vue' // 画板
|
||||
import vDrag from '@/directive/drag'
|
||||
import { tryOnUnmounted } from '@vueuse/core'
|
||||
import vDrag from './directive/drag'
|
||||
// const Remote = require('@electron/remote') // remote对象
|
||||
const { ipcRenderer } = require('electron')
|
||||
const { ipcRenderer } = require('electron') // app使用
|
||||
// const ipcRenderer = { send: () => {} } // 网页测试使用
|
||||
|
||||
const tool = ref()
|
||||
const tabActive = ref('select') // 工具栏当前选中项
|
||||
const isFold = ref(false) // 折叠工具栏
|
||||
const isDrag = ref(false) // 开始拖拽
|
||||
const dataPos = reactive({style:{}}) // 对象属性
|
||||
const dragtime = ref(0)
|
||||
const btnList = [ // 工具栏按钮列表
|
||||
{ label: '选择', value: 'select', icon: 'icon-mouse' },
|
||||
{ label: '画笔', value: 'brush', icon: 'icon-huabi' },
|
||||
{ label: '板擦', value: 'eraser', icon: 'icon-xiangpica' },
|
||||
{ label: '互动', value: 'interact', icon: 'icon-hudong' },
|
||||
{ label: '聚焦', value: 'focus', icon: 'icon-jujiao' },
|
||||
{ label: '更多', value: 'more', icon: 'icon-xiazai9' },
|
||||
{ label: '清除', value: 'clear', icon: 'icon-xiangpica', style: 'color: #ccc' },
|
||||
// { label: '互动', value: 'interact', icon: 'icon-hudong' },
|
||||
// { label: '聚焦', value: 'focus', icon: 'icon-jujiao' },
|
||||
// { label: '更多', value: 'more', icon: 'icon-xiazai9' },
|
||||
]
|
||||
let offsetX = 0, offsetY = 0, dragtime = 0
|
||||
// ==== 方法 ===
|
||||
const tabChange = (val) => { // 切换tab-change
|
||||
console.log(val)
|
||||
switch (val) {
|
||||
case 'brush': // 画笔
|
||||
break
|
||||
|
@ -71,47 +70,11 @@ const tabChange = (val) => { // 切换tab-change
|
|||
}
|
||||
}
|
||||
const logoHandle = (e,t) => { // logo 点击-事件 折叠|展开
|
||||
if (Date.now() - dragtime < 200) {
|
||||
if (Date.now() - dragtime.value < 200) {
|
||||
isFold.value = !isFold.value
|
||||
}
|
||||
console.log('click', isDrag.value)
|
||||
}
|
||||
const dargHandle = (e, type) => { // 拖拽处理
|
||||
e.preventDefault(); // 阻止默认的拖拽行为
|
||||
if (type == 'down') {
|
||||
dragtime = Date.now()
|
||||
return isDrag.value = true
|
||||
} else if (type == 'up') {
|
||||
return isDrag.value = false
|
||||
} else {
|
||||
if (!isDrag.value) return false
|
||||
if (!e.clientX&&!e.clientY){ // 最后一次松开坐标为0
|
||||
offsetX = 0
|
||||
offsetY = 0
|
||||
return false
|
||||
}
|
||||
if (!offsetX&&!offsetY) { // 第一次, 获取元素坐标
|
||||
setStyle()
|
||||
} else {
|
||||
const x = e.clientX - offsetX
|
||||
const y = e.clientY - offsetY
|
||||
setStyle(x, y)
|
||||
}
|
||||
offsetX = e.clientX
|
||||
offsetY = e.clientY
|
||||
}
|
||||
}
|
||||
const setStyle = (x, y) => { // 拖拽-设置值
|
||||
if (offsetX && offsetY) { // 有值
|
||||
const {left, top} = dataPos.style
|
||||
const ox = parseInt(left.replace('px',''))
|
||||
const oy = parseInt(top.replace('px',''))
|
||||
dataPos.style = {...dataPos.style, left: ox + x + 'px', top: oy + y + 'px'}
|
||||
} else { // 初始值
|
||||
const {left, top} = tool.value.getBoundingClientRect() // 获取元素位置
|
||||
dataPos.style = {bottom: 'unset', transform:'unset', left: left+'px', top: top+'px'}
|
||||
}
|
||||
}
|
||||
|
||||
const mouseChange = (bool) => { // 鼠标移入工具栏 是否穿透
|
||||
let resBool = false
|
||||
if (tabActive.value == 'select') resBool = !!bool
|
||||
|
@ -153,8 +116,7 @@ const mouseChange = (bool) => { // 鼠标移入工具栏 是否穿透
|
|||
:deep(.el-segmented__item){
|
||||
position: relative;
|
||||
margin: 0 0.5rem;
|
||||
&:nth-last-child(1):before,
|
||||
&:nth-last-child(2):before{
|
||||
&:not(:nth-of-type(1)):before{
|
||||
content: "";
|
||||
width: 2px;
|
||||
height: calc(100% - 20px);
|
||||
|
|
Loading…
Reference in New Issue