-
@@ -16,12 +26,17 @@ import {
defineProps,
defineExpose,
nextTick,
- defineEmits
+ defineEmits,watchEffect
} from 'vue'
-import { fabric } from 'fabric'
+// import { fabric } from 'fabric'
import { ElMessage } from 'element-plus'
import { handleevent, savecanvsStore, initcanvasdata, displayData } from '@/utils/pdfAndFabric'
+import { fabricVue, TYPES } from '@/plugins/fabric'
+import { updateSmartBookMarkContent, addsmartBookMark,getBookMarkById } from '@/api/eTextbook/index'
+import {useToolState} from '@/store/modules/tool'
+const { ipcRenderer } = require('electron')
+const toolState = useToolState();
const props = defineProps({
pdfObj: {
type: Object,
@@ -32,13 +47,16 @@ const props = defineProps({
}
}
})
+const ispointer = ref(false) //是否画笔模式
// canvas的所有数据
const canvsStore = reactive({
- id: 'xxxx',
pageArr: []
})
const fabriccanvas = ref(null)
const fabriccanvas1 = ref(null)
+
+const canvasFabricVue = ref(null)
+const canvas1FabricVue = ref(null)
// 页面总数
const numPagesTotal = ref(0)
const imgarr = ref([])
@@ -50,10 +68,10 @@ const renderPage = async (canvasobj) => {
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise
// 渲染当前页
const page = await pdf.getPage(canvasobj.page)
- var screenWidth = window.innerWidth/2-100;
- var screenHeight = window.innerHeight;
- const viewport = page.getViewport({ scale:2})
-
+ var screenWidth = window.innerWidth / 2 - 100
+ var screenHeight = window.innerHeight
+ const viewport = page.getViewport({ scale: 2 })
+
const canvasElement = canvasobj.canvas
canvasElement.width = viewport.width
canvasElement.height = viewport.height
@@ -61,6 +79,8 @@ const renderPage = async (canvasobj) => {
canvasContext: canvasobj.context,
viewport: viewport
}
+ // console.log(renderContext,22222222222222222222)
+
page.render(renderContext).promise.then((res) => {
const img = document.createElement('img')
img.src = canvasobj.canvas.toDataURL('image/png')
@@ -71,34 +91,69 @@ const renderPage = async (canvasobj) => {
// 根据传过来的pdf对象 判断改渲染哪一个fabric
if (props.pdfObj.numberOfPdf == 2) {
if (canvasobj.index == 0) {
-
- fabriccanvas.value.setWidth(screenWidth)
- fabriccanvas.value.setHeight(screenHeight)
- displayData(fabriccanvas, canvsStore, canvasobj, fabric, img)
+ canvasFabricVue.value.canvas.setWidth(screenWidth)
+ canvasFabricVue.value.canvas.setHeight(screenHeight)
+ // updateCanvasBackgroundImage(canvasFabricVue,img)
+ displayData(canvasFabricVue, canvsStore, canvasobj, fabric, img)
} else {
- fabriccanvas1.value.setWidth(screenWidth)
- fabriccanvas1.value.setHeight(screenHeight)
- displayData(fabriccanvas1, canvsStore, canvasobj, fabric, img)
+ canvas1FabricVue.value.canvas.setWidth(screenWidth)
+ canvas1FabricVue.value.canvas.setHeight(screenHeight)
+ displayData(canvas1FabricVue, canvsStore, canvasobj, fabric, img)
}
} else {
- fabriccanvas.value.setWidth(screenWidth)
- fabriccanvas.value.setHeight(screenHeight)
- displayData(fabriccanvas, canvsStore, canvasobj, fabric, img)
+ canvasFabricVue.value.canvas.setHeight(screenHeight)
+ displayData(canvasFabricVue, canvsStore, canvasobj, fabric, img)
}
- // console.log(imgarr.value)
img.remove()
}
- // 判断imgarr的JSONdata在canvsStore.pageArr有没有
- canvsStore.pageArr.forEach((item) => {
- if (item.page == canvasobj.page) {
- imgarr.value.forEach((img) => {
- if (img.page == canvasobj.page) {
- img.JSONdata = item.JSONdata
- }
- })
+ // 判断imgarr的JSONdata在canvsStore.pageArr有没有
+ // canvsStore.pageArr.forEach((item) => {
+ // if (item.page == canvasobj.page) {
+ // imgarr.value.forEach((img) => {
+ // if (img.page == canvasobj.page) {
+ // img.JSONdata = item.JSONdata
+ // }
+ // })
+ // }
+ // })
+ })
+}
+// 保存数据
+const savaDataStore = () => {
+ imgarr.value.forEach((a) => {
+ if (a.index == 0) {
+ a.JSONdata = canvasFabricVue.value.canvas.toJSON()
+ } else {
+ a.JSONdata = canvas1FabricVue.value.canvas.toJSON()
+ }
+ })
+ const nameMap = new Map(canvsStore.pageArr.map((item) => [item.page, item.id]))
+ // 创建一个用于存储所有异步操作的数组
+ let promises = []
+ imgarr.value.forEach((item) => {
+ if (nameMap.has(item.page)) {
+ const params = {
+ id: nameMap.get(item.page),
+ contentData: JSON.stringify(item.JSONdata.objects)
+ }
+ promises.push(updateSmartBookMarkContent([params]))
+ } else {
+ promises.push(addsmartBookMark({
+ pageNum: item.page,
+ contentData: JSON.stringify(item.JSONdata.objects),
+ bookId: props.pdfObj.bookId,
+ type: '教材',
+ source: 'smarttalk'
+ }))
+
}
})
- })
+ Promise.all(promises).then(res=>{
+ toolState.isPdfWin=false
+ toolState.showBoardAll=true //恢复默认值
+ ipcRenderer.invoke('tool-sphere:reset') //重置tool状态
+ ipcRenderer.send('open-PDF:minimize')
+ })
}
const updatePage = (canvasobj) => {
renderPage(canvasobj)
@@ -108,16 +163,54 @@ const loadPdf = async (canvasobj) => {
}
const initPdf = async (type = 'default') => {
+ imgarr.value.forEach((a) => {
+ if (a.index == 0) {
+ a.JSONdata = canvasFabricVue.value.canvas.toJSON()
+ } else {
+ a.JSONdata = canvas1FabricVue.value.canvas.toJSON()
+ }
+ })
+ if (type != 'default') {
+ const nameMap = new Map(canvsStore.pageArr.map((item) => [item.page, item.id]))
+ // 创建一个用于存储所有异步操作的数组
+ let promises = []
+ imgarr.value.forEach((item) => {
+ if (nameMap.has(item.page)) {
+ const params = {
+ id: nameMap.get(item.page),
+ contentData: JSON.stringify(item.JSONdata.objects)
+ }
+ promises.push(updateSmartBookMarkContent([params]))
+ } else {
+ promises.push(addsmartBookMark({
+ pageNum: item.page,
+ contentData: JSON.stringify(item.JSONdata.objects),
+ bookId: props.pdfObj.bookId,
+ type: '教材',
+ source: 'smarttalk'
+ }))
+
+ }
+ })
+ Promise.all(promises).then(res=>{
+ getBookMarkById(props.pdfObj.bookId).then(res=>{
+ const pageArr=getUniqueArrayByLastOccurrence(res.data)
+ canvsStore.pageArr=[]
+ pageArr.forEach((a) => {
+ canvsStore.pageArr.push({ page: a.pageNum, id: a.id, JSONdata: a.contentData })
+ })
+ })
+ })
+ }
// 保存数据
- savecanvsStore(imgarr, canvsStore)
- // initcanvasdata(fabriccanvas)
- // initcanvasdata(fabriccanvas1)
- // 单页模式
- if (type == 'restone') {
- // 清除 canvas 上的所有对象
- fabriccanvas1.value.clear()
- // 释放 canvas 的资源
- fabriccanvas1.value.dispose()
+ // savecanvsStore(imgarr, canvsStore)
+
+ if (props.pdfObj.numberOfPdf == 1) {
+ // imgarr.value[0]
+ canvasFabricVue.value.history.clean()
+ } else {
+ canvasFabricVue.value.history.clean()
+ canvas1FabricVue.value.history.clean()
}
// 清除现有 canvas 元素的内容
canvasNumbsValue.value.forEach((canvasObj) => {
@@ -149,7 +242,6 @@ const initPdf = async (type = 'default') => {
} else {
canvasNumbsValue.value[i].page = props.pdfObj.numPages + 1
}
-
canvasNumbsValue.value[i].index = i
// 加载FabricVue
await loadPdf(canvasNumbsValue.value[i])
@@ -157,47 +249,144 @@ const initPdf = async (type = 'default') => {
}
}
}
+//根据page去重
+const getUniqueArrayByLastOccurrence=(array)=> {
+ const uniqueItems = array.reduce((acc, current) => {
+ // 使用 Map 来跟踪最后一个出现的 pageNum 和它的对象
+ acc.set(current.pageNum, current);
+ return acc;
+ }, new Map());
+
+ // 将 Map 的值转换回数组
+ const resultArray = Array.from(uniqueItems.values());
+
+ return resultArray;
+}
const initPdfone = async () => {
- setTimeout(() => {
- fabriccanvas1.value = new fabric.Canvas('pdf-fabric1')
- fabriccanvas1.value.isDrawingMode = true
- fabriccanvas1.value.freeDrawingBrush.color = '#A33AFE'
- fabriccanvas1.value.freeDrawingCursor = 'default'
- fabriccanvas1.value.setWidth(595)
- handleevent(fabriccanvas1.value, imgarr, 'two')
+ setTimeout(async () => {
+ const option = { freeDrawingCursor: 'default' }
+ const canvas2 = new fabricVue()
+ await canvas2.initCanvas(fabriccanvas1.value, option)
+ canvas2.canvas.setWidth(window.innerWidth / 2 - 100)
+ canvas1FabricVue.value = canvas2
+ await initPdf('addOnePage')
}, 0)
- initPdf('addOnePage')
}
onMounted(async () => {
try {
+ // 创建canvas转化成图片
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise
numPagesTotal.value = pdf.numPages
- // console.log(pdf)
// 初始化fabriccanvas
- fabriccanvas.value = new fabric.Canvas('pdf-fabric')
- fabriccanvas.value.setWidth(595)
- fabriccanvas.value.isDrawingMode = true
- fabriccanvas.value.freeDrawingBrush.color = '#A33AFE'
- fabriccanvas.value.freeDrawingCursor = 'default'
-
- fabriccanvas1.value = new fabric.Canvas('pdf-fabric1')
- fabriccanvas1.value.isDrawingMode = true
- fabriccanvas1.value.freeDrawingBrush.color = '#A33AFE'
- fabriccanvas1.value.freeDrawingCursor = 'default'
- fabriccanvas1.value.setWidth(595)
+ const option = { freeDrawingCursor: 'default' }
+ const canvas1 = new fabricVue()
+ // canvas1.boardConfig.mode= TYPES.ActionMode.OTHER
+ // canvas1.boardConfig.mode= TYPES.ActionMode.ERASE
+ await canvas1.initCanvas(fabriccanvas.value, option)
+ canvas1.canvas.setWidth(window.innerWidth / 2 - 100)
+ canvasFabricVue.value = canvas1
+ const canvas2 = new fabricVue()
+ await canvas2.initCanvas(fabriccanvas1.value, option)
+ canvas2.canvas.setWidth(window.innerWidth / 2 - 100)
+ // canvas2.canvas.isDrawingMode=false
+ canvas1FabricVue.value = canvas2
+ window.test = { canvas1, canvas2 }
emit('update:numPagesTotal', pdf.numPages)
- initPdf()
+
+ if (props.pdfObj.allPageData.length) {
+ props.pdfObj.allPageData.forEach((a) => {
+ if (a.pageNum == 1 || a.pageNum == 2) {
+ canvsStore.pageArr.push({ page: a.pageNum, id: a.id, JSONdata: a.contentData })
+ }
+ })
+ }
+ await initPdf()
} catch (error) {
console.log(error)
ElMessage.error('pdf文件错误')
}
+ setToolStatus()
// 监听2个canvas事件
- handleevent(fabriccanvas.value, imgarr)
- handleevent(fabriccanvas1.value, imgarr, 'two')
+ // handleevent(fabriccanvas.value, imgarr)
+ // handleevent(fabriccanvas1.value, imgarr, 'two')
})
+// zdg: 设置-底部工具栏-状态
+const setToolStatus = () => {
+ toolState.showBoardAll = false
+}
+// 判断元素是否加载完成
+const handleMode = (vale,type)=>{
+ if(vale=='select'){
+ ispointer.value=true
+ }else{
+ ispointer.value=false
+ }
+ switch(vale) {
+ case 'select': // 选择模式
+ canvasFabricVue.value?.handleMode(TYPES.ActionMode.OTHER)
+ canvas1FabricVue.value?.handleMode(TYPES.ActionMode.OTHER)
+ break
+ case 'brush': // 画笔模式
+ canvasFabricVue.value?.handleMode(TYPES.ActionMode.DRAW)
+ canvasFabricVue.value.canvas.freeDrawingCursor = 'default'
+ canvas1FabricVue.value?.handleMode(TYPES.ActionMode.DRAW)
+ canvas1FabricVue.value.canvas.freeDrawingCursor = 'default'
+ break
+ case 'erase': // 板擦模式
+ canvasFabricVue.value?.handleMode(TYPES.ActionMode.ERASE)
+ canvas1FabricVue.value?.handleMode(TYPES.ActionMode.ERASE)
+ break
+ case 'clear': // 清空画布
+ clearCanvas()
+ // canvas1FabricVue.value.history?.clean()
+ break
+ }
+}
+// 清空canvas
+const clearCanvas=()=>{
+ if(canvasFabricVue.value){
+ const objects = canvasFabricVue.value.canvas.getObjects();
+ objects.forEach((obj) => {
+ // 检查对象是否是背景
+ if (obj !== canvasFabricVue.value.canvas.backgroundImage) {
+ // 删除背景之外的对象
+ canvasFabricVue.value.canvas.remove(obj);
+ }
+ });
+
+ canvasFabricVue.value.canvas.renderAll();
+ }
+ if(canvas1FabricVue.value){
+ const objects = canvas1FabricVue.value.canvas.getObjects();
+ objects.forEach((obj) => {
+ // 检查对象是否是背景
+ if (obj !== canvas1FabricVue.value.canvas.backgroundImage) {
+ // 删除背景之外的对象
+ canvas1FabricVue.value.canvas.remove(obj);
+ }
+ });
+
+ canvas1FabricVue.value.canvas.renderAll();
+ }
+}
+const watchToolState=()=>{
+ if(toolState.showBoardAll){
+ setTimeout(() => {
+ toolState.showBoardAll=false
+ }, 200);
+ }
+ // 加载工具
+ handleMode(toolState.model)
+
+}
defineExpose({
initPdf,
- initPdfone
+ initPdfone,
+ savaDataStore
+})
+watchEffect(() => {
+ console.log(toolState.model,'监听')
+ watchToolState() //监听工具栏
})
@@ -207,6 +396,8 @@ defineExpose({
flex-wrap: wrap;
width: 100%;
justify-content: center;
+ overflow: hidden;
+ max-height: 100vh;
}
.pdfAdnFabric {
position: relative;
@@ -217,4 +408,7 @@ defineExpose({
margin-right: 10px;
}
}
+.ispointer {
+ pointer-events: none;
+}
\ No newline at end of file
diff --git a/src/renderer/src/plugins/fabric/index.js b/src/renderer/src/plugins/fabric/index.js
index 0a6439c..6a11848 100644
--- a/src/renderer/src/plugins/fabric/index.js
+++ b/src/renderer/src/plugins/fabric/index.js
@@ -1615,6 +1615,7 @@ export class fabricVue {
break
case TYPES.ActionMode.OTHER: // 其他(工具选择)
this.canvas.isDrawingMode = false
+ objectSet.selectable = false
this.canvas.freeDrawingCursor = 'default'
break
default:
diff --git a/src/renderer/src/plugins/shareStore.js b/src/renderer/src/plugins/shareStore.js
index 746332e..1a43c74 100644
--- a/src/renderer/src/plugins/shareStore.js
+++ b/src/renderer/src/plugins/shareStore.js
@@ -1,7 +1,8 @@
/**
* 共享数据状态-多窗口
*/
-const { ipcRenderer } = require('electron') // app使用
+const isNode = typeof require !== 'undefined' // 是否支持node函数
+const { ipcRenderer } = isNode?require('electron'):{} // app使用
export function shareStorePlugin({store}) {
store.$subscribe(() => { // 自动同步
// 在存储变化的时候执行
@@ -19,15 +20,16 @@ export function shareStorePlugin({store}) {
function stateSync(store) {
const storeName = store.$id
const jsonStr = JSON.stringify(store.$state)
+ // console.log('state-change', jsonStr, storeName)
// 通知主线程更新
- ipcRenderer.invoke('pinia-state-change', storeName, jsonStr)
+ ipcRenderer?.invoke('pinia-state-change', storeName, jsonStr)
}
// 同步数据-接收主线程消息
function stateChange(store) {
const storeName = store.$id
- ipcRenderer.on('pinia-state-set', (e, sName, jsonStr) => {
+ ipcRenderer?.on('pinia-state-set', (e, sName, jsonStr) => {
if (sName == storeName) { // 更新对应数据
- console.log('state-set', jsonStr, sName)
+ // console.log('state-set', jsonStr, sName)
const curJson = JSON.stringify(store.$state) // 当前数据
const isUp = curJson != jsonStr // 不同的时候才写入,不然会导致触发数据变化监听,导致死循环
if (!isUp) return
diff --git a/src/renderer/src/store/modules/tool.js b/src/renderer/src/store/modules/tool.js
index 224b5d7..c3fe9a7 100644
--- a/src/renderer/src/store/modules/tool.js
+++ b/src/renderer/src/store/modules/tool.js
@@ -5,8 +5,10 @@ import { defineStore } from 'pinia'
export const useToolState = defineStore('tool', {
state: () => ({
- model: 'select', // 悬浮球-当前模式
- showBoardAll: false, // 全屏画板-是否显示
+ model: 'select', // 悬浮球-当前模式
+ showBoardAll: false, // 全屏画板-是否显示
+ isPdfWin: false, // pdf窗口是否打开
+ isToolWin: false, // 工具窗口是否打开
}),
actions: {
}
diff --git a/src/renderer/src/utils/pdfAndFabric copy.js b/src/renderer/src/utils/pdfAndFabric copy.js
new file mode 100644
index 0000000..5a914b6
--- /dev/null
+++ b/src/renderer/src/utils/pdfAndFabric copy.js
@@ -0,0 +1,133 @@
+// 所有事件
+export function handleevent(canvas, imgarr, type = 'defalut') {
+ // // 鼠标按下
+ // canvas.on('mouse:down', function (e) {})
+ // // // 监听鼠标移动事件
+ // // canvas.on('mouse:move', (options) => {
+ // // console.log('Mouse move event:', options);
+ // // });
+
+ // // 监听鼠标释放事件
+ // canvas.on('mouse:up', (options) => {
+ // //判断是点击的哪一个
+ // if (type == 'defalut') {
+ // if (imgarr.value[0].index == 0) {
+ // imgarr.value[0].JSONdata = canvas.toJSON()
+ // }
+ // if (imgarr.value[1]?.index == 0) {
+ // imgarr.value[1].JSONdata = canvas.toJSON()
+ // }
+ // } else {
+ // if (imgarr.value[0].index == 1) {
+ // imgarr.value[0].JSONdata = canvas.toJSON()
+ // }
+ // if (imgarr.value[1]?.index == 1) {
+ // imgarr.value[1].JSONdata = canvas.toJSON()
+ // }
+ // }
+ // console.log(imgarr.value)
+
+ // })
+}
+// 保存数据
+export function savecanvsStore(imgarr, canvsStore) {
+ // canvsStore.pageArr = mergeAndReplace(canvsStore.pageArr, imgarr.value)
+}
+// 重显数据
+export function displayData(canvas, canvsStore, canvasobj, fabric, img) {
+ // // 初始化
+ // if (!canvsStore.pageArr.length) {
+ // fabric.Image.fromURL(img.src, (img) => {
+ // img.set({
+ // left: 0,
+ // top: 0,
+ // scaleX: canvas.value.width / img.width,
+ // scaleY: canvas.value.height / img.height
+ // })
+ // canvas.value.setBackgroundImage(img, canvas.value.renderAll.bind(canvas.value))
+ // })
+ // return
+ // }
+ // canvsStore.pageArr.forEach((item) => {
+ // //初始化
+ // if (item.page == canvasobj.page) {
+ // // canvas.value.clear() // 清除 Canvas
+ // // console.log(item.JSONdata, '找到一样的数据')
+ // canvas.value.loadFromJSON(item.JSONdata, () => {
+ // // 在所有对象加载完成后重新渲染画布
+ // canvas.value.renderAll.bind(canvas.value)
+ // canvas.value.renderAll()
+ // // requestAnimationFrame(() => {
+ // // // 渲染所有对象
+
+ // // })
+ // })
+ // } else {
+ // // 使用 requestAnimationFrame 来更新画布,确保在下一帧进行重绘
+ // // // 清除 Canvas
+ // canvas.value.clear()
+ // requestAnimationFrame(function () {
+ // fabric.Image.fromURL(img.src, (img) => {
+ // img.set({
+ // left: 0,
+ // top: 0,
+ // scaleX: canvas.value.width / img.width,
+ // scaleY: canvas.value.height / img.height
+ // })
+ // canvas.value.setBackgroundImage(img, canvas.value.renderAll.bind(canvas.value))
+ // })
+ // // 渲染所有对象
+ // canvas.value.renderAll.bind(canvas.value)
+ // canvas.value.renderAll()
+ // })
+ // }
+ // })
+}
+
+//page 一样替换
+const mergeAndReplace = (arr1, arr2) => {
+ // // 用于存储替换后的数组
+ // const resultArray = array1.map(item1 => {
+ // // 在 array2 中查找 page 相同的对象
+ // const replacement = array2.find(item2 => item2.page == item1.page);
+ // // 如果找到替换对象,则返回替换对象,否则返回原对象
+ // return replacement ? replacement : item1;
+ // });
+
+ // // 将 array2 中 page 不在 array1 中的对象追加到结果数组中
+ // array2.forEach(item2 => {
+ // const existsInArray1 = array1.some(item1 => item1.page == item2.page);
+ // if (!existsInArray1) {
+ // resultArray.push(item2);
+ // }
+ // });
+
+ // return resultArray;
+
+ // 创建一个映射,将 arr2 中的对象按 page 属性存储
+ let map = new Map(arr2.map((item) => [item.page, item]))
+
+ // 使用 map 替换 arr1 中相应 page 的对象,并添加 arr2 中的对象
+ arr1 = arr1.map((item) => (map.has(item.page) ? map.get(item.page) : item))
+
+ // 将 map 中存在但 arr1 中不存在的对象添加到 arr1
+ for (let [page, obj] of map) {
+ if (!arr1.some((item) => item.page === page)) {
+ arr1.push(obj)
+ }
+ }
+ return arr1
+}
+
+// 初始化数据
+export function initcanvasdata(canvas) {
+ canvas.value.clear() // 清除 Canvas
+ // 设置画布的背景色或其他属性
+ canvas.value.backgroundColor = 'rgba(255, 255, 255, 1)' // 白色背景
+
+ // 使用 requestAnimationFrame 来更新画布,确保在下一帧进行重绘
+ requestAnimationFrame(function () {
+ // 渲染所有对象
+ canvas.value.renderAll.bind(canvas.value)
+ })
+}
diff --git a/src/renderer/src/utils/pdfAndFabric.js b/src/renderer/src/utils/pdfAndFabric.js
index 3807034..8763356 100644
--- a/src/renderer/src/utils/pdfAndFabric.js
+++ b/src/renderer/src/utils/pdfAndFabric.js
@@ -1,108 +1,187 @@
+
// 所有事件
export function handleevent(canvas, imgarr, type = 'defalut') {
- // 鼠标按下
- canvas.on('mouse:down', function (e) {})
- // // 监听鼠标移动事件
- // canvas.on('mouse:move', (options) => {
- // console.log('Mouse move event:', options);
- // });
+ // // 鼠标按下
+ // canvas.on('mouse:down', function (e) {})
+ // // // 监听鼠标移动事件
+ // // canvas.on('mouse:move', (options) => {
+ // // console.log('Mouse move event:', options);
+ // // });
- // 监听鼠标释放事件
- canvas.on('mouse:up', (options) => {
- //判断是点击的哪一个
- if (type == 'defalut') {
- if (imgarr.value[0].index == 0) {
- imgarr.value[0].JSONdata = canvas.toJSON()
- }
- if (imgarr.value[1]?.index == 0) {
- imgarr.value[1].JSONdata = canvas.toJSON()
- }
- } else {
- if (imgarr.value[0].index == 1) {
- imgarr.value[0].JSONdata = canvas.toJSON()
- }
- if (imgarr.value[1]?.index == 1) {
- imgarr.value[1].JSONdata = canvas.toJSON()
- }
- }
- console.log(imgarr.value)
+ // // 监听鼠标释放事件
+ // canvas.on('mouse:up', (options) => {
+ // //判断是点击的哪一个
+ // if (type == 'defalut') {
+ // if (imgarr.value[0].index == 0) {
+ // imgarr.value[0].JSONdata = canvas.toJSON()
+ // }
+ // if (imgarr.value[1]?.index == 0) {
+ // imgarr.value[1].JSONdata = canvas.toJSON()
+ // }
+ // } else {
+ // if (imgarr.value[0].index == 1) {
+ // imgarr.value[0].JSONdata = canvas.toJSON()
+ // }
+ // if (imgarr.value[1]?.index == 1) {
+ // imgarr.value[1].JSONdata = canvas.toJSON()
+ // }
+ // }
+ // console.log(imgarr.value)
- })
+ // })
}
// 保存数据
export function savecanvsStore(imgarr, canvsStore) {
canvsStore.pageArr = mergeAndReplace(canvsStore.pageArr, imgarr.value)
}
// 重显数据
-export function displayData(canvas, canvsStore, canvasobj, fabric, img) {
+export function displayData(FabricVue, canvsStore, canvasobj, fabric, img) {
+
// 初始化
- if (!canvsStore.pageArr.length) {
- fabric.Image.fromURL(img.src, (img) => {
- img.set({
- left: 0,
- top: 0,
- scaleX: canvas.value.width / img.width,
- scaleY: canvas.value.height / img.height
- })
- canvas.value.setBackgroundImage(img, canvas.value.renderAll.bind(canvas.value))
- })
+ const canvas = FabricVue.value.canvas
+ if (!canvas) {
return
}
- canvsStore.pageArr.forEach((item) => {
- //初始化
- if (item.page == canvasobj.page) {
- // canvas.value.clear() // 清除 Canvas
- // console.log(item.JSONdata, '找到一样的数据')
- canvas.value.loadFromJSON(item.JSONdata, () => {
- // 在所有对象加载完成后重新渲染画布
- canvas.value.renderAll.bind(canvas.value)
- canvas.value.renderAll()
- // requestAnimationFrame(() => {
- // // 渲染所有对象
-
- // })
- })
- } else {
- // 使用 requestAnimationFrame 来更新画布,确保在下一帧进行重绘
- // // 清除 Canvas
- canvas.value.clear()
- requestAnimationFrame(function () {
- fabric.Image.fromURL(img.src, (img) => {
- img.set({
- left: 0,
- top: 0,
- scaleX: canvas.value.width / img.width,
- scaleY: canvas.value.height / img.height
- })
- canvas.value.setBackgroundImage(img, canvas.value.renderAll.bind(canvas.value))
+ if (!canvsStore.pageArr.length) {
+ fabric.Image.fromURL(
+ img.src,
+ (image) => {
+ image.set({
+ left: 0,
+ top: 0,
+ scaleX: canvas.width / img.width,
+ scaleY: canvas.height / img.height,
+ erasable: false // 不允许擦拭
+ })
+ // FabricVue.setBackgroundImage(image, FabricVue.renderAll.bind(FabricVue))
+ // setBackgroundImage(image,FabricVue)
+ // canvas.setBackgroundImage(image, canvas.renderAll.bind(canvas));
+
+ canvas.setBackgroundImage(image, () => {
+ canvas.renderAll.bind(canvas)
+ FabricVue.value.render()
})
- // 渲染所有对象
- canvas.value.renderAll.bind(canvas.value)
- canvas.value.renderAll()
- })
- }
+ },
+ {crossOrigin: 'anonymous'}
+ )
+ return
+ }
+
+ const isfind=findObjectByPage(canvsStore.pageArr,canvasobj.page)
+ if(isfind){
+ const canvdata={
+ objects:JSON.parse(isfind.JSONdata),
+ version: "5.3.0"
+ }
+ requestAnimationFrame(function () {
+ canvas.loadFromJSON(canvdata, () => {
+ // 在所有对象加载完成后重新渲染画布
+ // Utils.handleCanvasJSONLoaded(canvas)
+ canvas.requestRenderAll() // 批量重绘
+ })
+ fabric.Image.fromURL(
+ img.src,
+ (image) => {
+ image.set({
+ left: 0,
+ top: 0,
+ scaleX: canvas.width / img.width,
+ scaleY: canvas.height / img.height,
+ selectable: false,
+ evented: false,
+ erasable: false // 不允许擦拭
+ })
+ // canvas.setBackgroundImage(image, canvas.renderAll.bind(canvas));
+ canvas.setBackgroundImage(image, () => {
+ canvas.renderAll.bind(canvas)
+ FabricVue.value.render()
+ })
+ },
+ {crossOrigin: 'anonymous'}
+ )
+ // 渲染所有对象
+ canvas.requestRenderAll() // 批量重绘
})
+ }else{
+ // 使用 requestAnimationFrame 来更新画布,确保在下一帧进行重绘
+ // // 清除 Canvas
+ // canvas.clear()
+ requestAnimationFrame(function () {
+ fabric.Image.fromURL(
+ img.src,
+ (image) => {
+ image.set({
+ left: 0,
+ top: 0,
+ scaleX: canvas.width / img.width,
+ scaleY: canvas.height / img.height,
+ selectable: false,
+ evented: false,
+ erasable: false // 不允许擦拭
+ })
+ // canvas.setBackgroundImage(image, canvas.renderAll.bind(canvas));
+ canvas.setBackgroundImage(image, () => {
+ canvas.renderAll.bind(canvas)
+ FabricVue.value.render()
+ })
+ },
+ {crossOrigin: 'anonymous'}
+ )
+ // 渲染所有对象
+ canvas.requestRenderAll() // 批量重绘
+ })
+ }
+
+ // canvsStore.pageArr.forEach((item) => {
+ // //初始化
+ // if (item.page == canvasobj.page) {
+ // // item.JSONdata
+ // canvas.loadFromJSON(JSON.parse(item.JSONdata), () => {
+ // // 在所有对象加载完成后重新渲染画布
+ // // Utils.handleCanvasJSONLoaded(canvas)
+ // canvas.requestRenderAll() // 批量重绘
+ // })
+ // } else {
+
+ // // 使用 requestAnimationFrame 来更新画布,确保在下一帧进行重绘
+ // // // 清除 Canvas
+ // // canvas.clear()
+ // requestAnimationFrame(function () {
+ // fabric.Image.fromURL(
+ // img.src,
+ // (image) => {
+ // image.set({
+ // left: 0,
+ // top: 0,
+ // scaleX: canvas.width / img.width,
+ // scaleY: canvas.height / img.height,
+ // selectable: false,
+ // evented: false,
+ // erasable: false // 不允许擦拭
+ // })
+ // // canvas.setBackgroundImage(image, canvas.renderAll.bind(canvas));
+ // canvas.setBackgroundImage(image, () => {
+ // canvas.renderAll.bind(canvas)
+ // FabricVue.value.render()
+ // })
+ // },
+ // {crossOrigin: 'anonymous'}
+ // )
+ // // 渲染所有对象
+ // canvas.requestRenderAll() // 批量重绘
+ // })
+ // }
+ // })
+}
+// 找到page一样的
+const findObjectByPage=(array, page)=> {
+ const foundObject = array.find(obj => obj.page === page);
+ return foundObject || false;
}
//page 一样替换
const mergeAndReplace = (arr1, arr2) => {
- // // 用于存储替换后的数组
- // const resultArray = array1.map(item1 => {
- // // 在 array2 中查找 page 相同的对象
- // const replacement = array2.find(item2 => item2.page == item1.page);
- // // 如果找到替换对象,则返回替换对象,否则返回原对象
- // return replacement ? replacement : item1;
- // });
- // // 将 array2 中 page 不在 array1 中的对象追加到结果数组中
- // array2.forEach(item2 => {
- // const existsInArray1 = array1.some(item1 => item1.page == item2.page);
- // if (!existsInArray1) {
- // resultArray.push(item2);
- // }
- // });
-
- // return resultArray;
// 创建一个映射,将 arr2 中的对象按 page 属性存储
let map = new Map(arr2.map((item) => [item.page, item]))
diff --git a/src/renderer/src/utils/tool.js b/src/renderer/src/utils/tool.js
index b51a6bb..09a1fb1 100644
--- a/src/renderer/src/utils/tool.js
+++ b/src/renderer/src/utils/tool.js
@@ -6,14 +6,17 @@
// Remote.app.getAppPath() E:\njys-work\AIx_Smarttalk\dist\win-unpacked\resources\app.asar
// path.join(__dirname) 根目录 E:\njys-work\AIx_Smarttalk\dist\win-unpacked\resources\app.asar\out\renderer
-const path = require('path')
-const Remote = require('@electron/remote')
-const { ipcRenderer } = require('electron')
+const isNode = typeof require !== 'undefined' // 是否支持node函数
+const path = isNode?require('path'):{}
+const Remote = isNode?require('@electron/remote'):{}
+const { ipcRenderer } = isNode?require('electron'):window.electron || {}
// 常用变量
-const BaseUrl = process.env['ELECTRON_RENDERER_URL']+'/#'
-const isDev = process.env.NODE_ENV !== 'production'
+const BaseUrl = isNode?process.env['ELECTRON_RENDERER_URL']+'/#':''
+const isDev = isNode?process.env.NODE_ENV !== 'production':''
+// 暴露Remote中的属性
+export const ipcMain = Remote?.ipcMain || {}
/**
* 获取静态资源,开发和生产环境
* @param {*} url
@@ -39,15 +42,32 @@ export const getStaticUrl = (url = '', type = 'app', exitPath = '', isFile = fal
* url:路由地址,width:窗口宽度,height:窗口高度,option:自定义选项
* @returns
*/
-export function ipcMsgSend(key, data) {
- return new Promise((resolve) => {
- // 返回结果-监听
- ipcRenderer.once(`${key}-reply`, (e, res) => {
- resolve(res)
+export function ipcMsgSend(key, data, type) {
+ if (type == 'old') {
+ return new Promise((resolve) => {
+ // 返回结果-监听
+ ipcRenderer?.once(`${key}-reply`, (e, res) => {
+ resolve(res)
+ })
+ // 发送消息
+ ipcRenderer?.send(key, data)
})
- // 发送消息
- ipcRenderer.send(key, data)
- })
+ } else if (type == 'send') { // 单独发送
+ ipcRenderer?.send(key, data)
+ } else { // 新版本-默认
+ return ipcRenderer?.invoke(key, data)
+ }
+}
+/**
+ * @description 封装ipcRenderer事件监听
+ * @param {*} fn on once handle invoke
+ * @param {*} key
+ * @param {Function} cb 回调函数
+ * @returns
+ */
+export function ipcHandle(fn,key, cb) {
+ return ipcRenderer[fn](key, cb)
+ // return ipcRenderer?.[fn]?.(key, cb)
}
/**
* 创建-窗口 调用该方法
@@ -89,11 +109,13 @@ export const createWindow = async (type, data) => {
resizable: true, // 禁止窗口大小缩放
alwaysOnTop: false, // 窗口是否总是显示在其他窗口之前
}
+ data.isConsole = true // 是否开启控制台
data.option = {...defOption, ...option}
const win = await toolWindow(data)
win.type = type // 唯一标识
win.show()
win.setFullScreen(true) // 设置窗口为全屏
+ // win.webContents.openDevTools() // 打开调试工具
eventHandles(type, win) // 事件监听处理
break
}
@@ -145,7 +167,7 @@ export function toolWindow({url, isConsole, option={}}) {
// 内部监听器-是否打印
if (!!isConsole) {
win.webContents.on('console-message', (e,leve,m,lin,s) => {
- console.log(m)
+ console.log(`[${win.type}]`,m)
})
}
})
@@ -173,13 +195,17 @@ const eventHandles = (type, win) => {
case 'tool-sphere': { // 创建-悬浮球
// 监听设置穿透
const setIgnore = (_, ignore) => {win.setIgnoreMouseEvents(ignore, {forward: true})}
- Remote.ipcMain.on('tool-sphere:set:ignore', setIgnore)
+ Remote.ipcMain.handle('tool-sphere:set:ignore', setIgnore) // 异步
// 关闭窗口
Remote.ipcMain.once('tool-sphere:close', () => { win&&win.destroy() })
// 放大监听-测试
Remote.ipcMain.once('maximize-window', () => {win&&win.destroy()})
const on = {
- onClosed: () => {Remote.ipcMain.off('tool-sphere:set:ignore', setIgnore)}
+ onClosed: () => {
+ Remote.ipcMain.removeHandler('tool-sphere:set:ignore', setIgnore)
+ Remote.ipcMain.removeHandler('tool-sphere:reset')
+ // Remote.ipcMain.removeAllListeners() // 移除所有监听事件
+ }
}
publicMethods(on) // 加载公共方法
break}
diff --git a/src/renderer/src/views/classBegins/index.vue b/src/renderer/src/views/classBegins/index.vue
index 95e59cc..188c790 100644
--- a/src/renderer/src/views/classBegins/index.vue
+++ b/src/renderer/src/views/classBegins/index.vue
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/src/renderer/src/views/tool/directive/ignore.js b/src/renderer/src/views/tool/directive/ignore.js
new file mode 100644
index 0000000..63a3ca3
--- /dev/null
+++ b/src/renderer/src/views/tool/directive/ignore.js
@@ -0,0 +1,45 @@
+/**
+ * 处理元素是否穿透-窗口
+ */
+import { ipcMsgSend } from '@/utils/tool'
+class Ignore {
+ el // 绑定元素
+ binding // 绑定对象(参数)
+ value // 绑定值
+ isAuto // 是否自动控制
+ constructor(el, binding) {
+ this.el = el
+ this.binding = binding
+ this.value = binding.value
+ this.isAuto = !(this.value && this.value instanceof Boolean)
+ }
+ // 设置是否穿透
+ send(bool) {
+ ipcMsgSend('tool-sphere:set:ignore', bool)
+ }
+ // 监听元素移入移出,自动设置
+ mounted() {
+ this.el.addEventListener('mouseenter', e => { // 进入
+ this.send(false) // 元素不穿透,鼠标有效
+ this.changeHandle(e)
+ })
+ this.el.addEventListener('mouseleave', e => { // 离开
+ this.send(true) // 元素穿透,鼠标无效
+ this.changeHandle(e)
+ })
+ }
+ changeHandle(e) {
+ const customEvent = new CustomEvent('ignore-mounted', {detail:{ignore: this, e}})
+ this.el.dispatchEvent(customEvent)
+ }
+}
+export default {
+ mounted(el, binding) {
+ const ignore = new Ignore(el, binding)
+ if (ignore.isAuto) { // 自动控制
+ ignore.mounted()
+ } else { // 手动设置
+ ignore.send(ignore.value)
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/renderer/src/views/tool/sphere.vue b/src/renderer/src/views/tool/sphere.vue
index 546067c..9559937 100644
--- a/src/renderer/src/views/tool/sphere.vue
+++ b/src/renderer/src/views/tool/sphere.vue
@@ -1,9 +1,11 @@