diff --git a/package.json b/package.json
index f8b65c4..578c277 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
"@electron-toolkit/preload": "^3.0.1",
"@electron-toolkit/utils": "^3.0.0",
"@element-plus/icons-vue": "^2.3.1",
+ "@electron/remote": "^2.1.2",
"@vitejs/plugin-vue-jsx": "^4.0.0",
"@vueuse/core": "^10.11.0",
"crypto-js": "^4.2.0",
@@ -44,7 +45,6 @@
},
"devDependencies": {
"@electron-toolkit/eslint-config": "^1.0.2",
- "@electron/remote": "^2.1.2",
"@rushstack/eslint-patch": "^1.10.3",
"@vitejs/plugin-vue": "^5.0.5",
"@vue/eslint-config-prettier": "^9.0.0",
diff --git a/src/main/index.js b/src/main/index.js
index 13e692c..cd543a7 100644
--- a/src/main/index.js
+++ b/src/main/index.js
@@ -1,4 +1,4 @@
-import { app, shell, BrowserWindow, ipcMain, session } from 'electron'
+import { app, shell, BrowserWindow, ipcMain, session, BrowserView } from 'electron'
import { join } from 'path'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import icon from '../../resources/icon.png?asset'
@@ -31,6 +31,7 @@ function createLoginWindow() {
nodeIntegration: true
}
})
+ loginWindow.type = 'login' // 唯一标识
// handleUpdate(loginWindow,ipcMain)
// const loginURL = is.dev ? `http://localhost:5173/#/login` : `file://${__dirname}/index.html/#/login`
// loginWindow.loadURL(loginURL)
@@ -69,12 +70,13 @@ function createMainWindow() {
// webSecurity: false // 跨域关闭
}
})
-
+ mainWindow.type = 'main' // 唯一标识
mainWindow.on('ready-to-show', () => {
mainWindow.show()
})
mainWindow.on('closed', () => {
mainWindow = null
+ app.quit() // 主窗口关闭-结束所有进程
})
mainWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url)
@@ -113,6 +115,7 @@ async function createLinkWin(data) {
contextIsolation: true
}
})
+ linkWindow.type = 'link' // 唯一标识
let cookieDetails = { ...data.cookieData }
await linkWindow.webContents.session.cookies.set(cookieDetails).then(()=>{
console.log('Cookie is successful');
diff --git a/src/renderer/src/components/pdf/index.vue b/src/renderer/src/components/pdf/index.vue
index 3ac1cf6..276aa80 100644
--- a/src/renderer/src/components/pdf/index.vue
+++ b/src/renderer/src/components/pdf/index.vue
@@ -50,8 +50,10 @@ const renderPage = async (canvasobj) => {
const pdf = await pdfjsLib.getDocument(props.pdfObj.pdfUrl).promise
// 渲染当前页
const page = await pdf.getPage(canvasobj.page)
- const viewport = page.getViewport({ scale: 1 })
-
+ 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
@@ -67,34 +69,20 @@ const renderPage = async (canvasobj) => {
img.onload = () => {
// 在这里执行图像加载完成后的操作
// 根据传过来的pdf对象 判断改渲染哪一个fabric
- var screenWidth = window.innerWidth/2-10;
- var screenHeight = window.innerHeight;
- // 计算图像的原始宽度和高度
- var imgWidth = img.width;
- var imgHeight = img.height;
- // 计算图像的缩放比例以适应屏幕
- var widthRatio = screenWidth / imgWidth;
- var heightRatio = screenHeight / imgHeight;
- //选择较小的缩放比例以确保图像完全适应屏幕
- var scaleRatio = Math.min(widthRatio, heightRatio);
- // 计算缩放后的图像尺寸
- var targetWidth = imgWidth * scaleRatio;
- var targetHeight = imgHeight * scaleRatio;
-
if (props.pdfObj.numberOfPdf == 2) {
if (canvasobj.index == 0) {
- fabriccanvas.value.setWidth(targetWidth)
- fabriccanvas.value.setHeight(targetHeight)
+ fabriccanvas.value.setWidth(screenWidth)
+ fabriccanvas.value.setHeight(screenHeight)
displayData(fabriccanvas, canvsStore, canvasobj, fabric, img)
} else {
- fabriccanvas1.value.setWidth(targetWidth)
- fabriccanvas1.value.setHeight(targetHeight)
+ fabriccanvas1.value.setWidth(screenWidth)
+ fabriccanvas1.value.setHeight(screenHeight)
displayData(fabriccanvas1, canvsStore, canvasobj, fabric, img)
}
} else {
- fabriccanvas.value.setWidth(targetWidth)
- fabriccanvas.value.setHeight(targetHeight)
+ fabriccanvas.value.setWidth(screenWidth)
+ fabriccanvas.value.setHeight(screenHeight)
displayData(fabriccanvas, canvsStore, canvasobj, fabric, img)
}
// console.log(imgarr.value)
@@ -121,7 +109,7 @@ const loadPdf = async (canvasobj) => {
const initPdf = async (type = 'default') => {
// 保存数据
- savecanvsStore(imgarr, canvsStore)
+ savecanvsStore(imgarr, canvsStore)
// initcanvasdata(fabriccanvas)
// initcanvasdata(fabriccanvas1)
// 单页模式
@@ -173,8 +161,10 @@ const initPdfone = async () => {
setTimeout(() => {
fabriccanvas1.value = new fabric.Canvas('pdf-fabric1')
fabriccanvas1.value.isDrawingMode = true
- fabriccanvas1.value.freeDrawingBrush.color = 'red'
+ fabriccanvas1.value.freeDrawingBrush.color = '#A33AFE'
+ fabriccanvas1.value.freeDrawingCursor = 'default'
fabriccanvas1.value.setWidth(595)
+ handleevent(fabriccanvas1.value, imgarr, 'two')
}, 0)
initPdf('addOnePage')
}
diff --git a/src/renderer/src/plugins/fabric/test.js b/src/renderer/src/plugins/fabric/test.js
new file mode 100644
index 0000000..7f49554
--- /dev/null
+++ b/src/renderer/src/plugins/fabric/test.js
@@ -0,0 +1,223 @@
+/**
+ * @description 封装fabric js
+ */
+import { fabric } from 'fabric'
+
+// 当前使用到的常量|类型(枚举)
+export class TYPES {
+ static ActionMode = {
+ DRAW: 'draw', // 画笔模式
+ ERASE: 'erase', // 橡皮擦模式
+ SELECT: 'select', // 选择模式
+ Board: 'board' // 画板模式
+ }
+ // 画笔类型
+ static DrawType = {
+ FreeStyle: 'freeStyle',
+ Shape: 'shape'
+ }
+ // 画笔样式
+ static DrawStyle = {
+ Basic: 'basic',
+ Rainbow: 'rainbow',
+ Shape: 'shape',
+ Material: 'material',
+ Pixels: 'pixels',
+ MultiColor: 'multiColor',
+ Text: 'text',
+ MultiLine: 'multiLine',
+ Reticulate: 'reticulate',
+ MultiPoint: 'multiPoint',
+ Wiggle: 'wiggle',
+ Thorn: 'thorn'
+ }
+ // 各种形状
+ static DrawShape = {
+ Bubble: 'bubble',
+ Star: 'star',
+ Love: 'love',
+ Butterfly: 'butterfly',
+ Snow: 'snow',
+ Music: 'music',
+ Sun: 'sun',
+ Moon: 'moon',
+ Leaf: 'leaf',
+ Flower: 'flower'
+ }
+ // 材质类型
+ static MATERIAL_TYPE = {
+ CRAYON: 'crayon',
+ CARBON: 'carbon',
+ CLOTH: 'cloth',
+ OIL: 'oil',
+ CRAYON_DARK: 'crayonDark'
+ }
+ // 多颜色类型
+ static MultiColorType = {
+ COL: 'col',
+ ROW: 'row',
+ CIRCLE: 'circle'
+ }
+ // 画笔元素
+ static FREESTYLE_ELEMENT_CUSTOM_TYPE = {
+ IMAGE: 'image',
+ I_TEXT: 'itext',
+ RAINBOW: 'rainbow',
+ SHAPE: 'shape',
+ PIXELS: 'pixels',
+ DRAW_TEXT: 'drawText',
+ MULTI_LINE: 'multiLine',
+ RETICULATE: 'reticulate',
+ MULTI_POINT: 'multiPoint',
+ WIGGLE: 'wiggle',
+ THORN: 'thorn'
+ }
+ // 形状元素
+ static SHAPE_ELEMENT_CUSTOM_TYPE = {
+ SHAPE_LINE: 'shapeLine',
+ SHAPE_RECT: 'shapeRect',
+ SHAPE_CIRCLE: 'shapeCircle',
+ SHAPE_ELLIPSE: 'shapeEllipse',
+ SHAPE_TRIANGLE: 'shapeTriangle',
+ SHAPE_ARROW_LINE: 'shapeArrowLine',
+ SHAPE_ARROW_OUTLINE: 'shapeArrowOutline',
+ SHAPE_CLOUD: 'shapeCloud',
+ SHAPE_TOOLTIPS: 'shapeTooltips',
+ SHAPE_LIGHTNING: 'shapeLightning',
+ SHAPE_CLOSE: 'shapeClose',
+ SHAPE_CHECK: 'shapeCheck',
+ SHAPE_INFO: 'shapeInfo',
+ SHAPE_BACKSPACE: 'shapeBackspace',
+ SHAPE_BLOCK: 'shapeBlock',
+ SHAPE_SPEAKER: 'shapeSpeaker',
+ SHAPE_SEARCH: 'shapeSearch',
+ SHAPE_INFO_OUTLINE: 'shapeInfoOutline',
+ SHAPE_HEART: 'shapeHeart',
+ SHAPE_ALERT: 'shapeAlert'
+ }
+ // 元素类型
+ static ELEMENT_CUSTOM_TYPE = {
+ ...this.FREESTYLE_ELEMENT_CUSTOM_TYPE,
+ ...this.SHAPE_ELEMENT_CUSTOM_TYPE
+ }
+}
+// 自由绘画 FreeStyle
+// export class FreeStyle {
+// }
+export const FreeStyle = {
+ renderPencilBrush: (canvas) => {
+ const pencilBrush = new fabric.PencilBrush(canvas)
+ canvas.isDrawingMode = true
+ canvas.freeDrawingBrush = pencilBrush
+ canvas.freeDrawingBrush.width = fabricUtils.getDrawWidth()
+ canvas.freeDrawingBrush.color = useDrawStore.drawColors[0]
+ canvas.freeDrawingBrush.shadow = new fabric.Shadow({
+ blur: fabricUtils.getShadowWidth(),
+ offsetX: 0,
+ offsetY: 0,
+ color: useDrawStore.shadowColor
+ })
+ }
+}
+// 封装fabric-canvas
+export class fabricVue {
+ canvas = null // fabric-canvas 对象
+ evnet = null // 事件对象
+ history = null // 历史记录
+ textElement // 文本节点
+ hookFn = [] // 钩子
+ defConfig // 默认配置-canvas
+ drawConfig // 默认配置-画笔
+ boardConfig // 默认配置-画板
+ publicConfig // 公共属性-配置
+
+ /** 构造函数 */
+ constructor() {
+ // this.textElement = new TextElement() // 创建文本节点
+ const initLanguage = ['en', 'en-US', 'en-us'].includes(navigator.language) ? 'en' : 'zh'
+ this.drawConfig = { // 默认配置
+ drawWidth: 1,
+ drawColors: ['#000000'],
+ shadowWidth: 0,
+ shadowColor: '#000000',
+ drawTextValue: 'draw',
+ drawStyle: TYPES.DrawStyle.Basic,
+ drawShapeCount: 2,
+ materialType: TYPES.MATERIAL_TYPE.CRAYON,
+ drawShape: TYPES.DrawShape.Bubble,
+ eraserWidth: 20,
+ multiColorType: TYPES.MultiColorType.COL,
+ textFontFamily: 'Georgia',
+ openAutoDraw: false,
+ fontStyles: [],
+ }
+ this.boardConfig = { // 默认配置
+ mode: TYPES.ActionMode.DRAW,
+ drawType: TYPES.DrawType.FreeStyle,
+ language: initLanguage,
+ canvasWidth: 1,
+ canvasHeight: 1,
+ backgroundColor: 'rgba(255, 255, 255, 1)',
+ backgroundOpacity: 1,
+ hasBackgroundImage: false,
+ backgroundImageOpacity: 1,
+ isObjectCaching: true,
+ openGuideLine: false,
+ }
+ this.defConfig = { // 默认配置-canvas
+ // 它用于指定选中对象时显示的选择框的颜色
+ selectionColor: 'rgba(101, 204, 138, 0.3)',
+ // 用于控制在组合(group)对象时是否保留每个对象的堆叠顺序
+ preserveObjectStacking: true,
+ // 它用于控制是否在高分辨率显示器(例如 Retina 显示器)上启用图像的像素级缩放
+ enableRetinaScaling: true,
+ // 锁定背景,不受缩放影响 false
+ backgroundVpt: false,
+ // 默认全屏模式
+ width: window.innerWidth,
+ height: window.innerHeight,
+ }
+ this.publicConfig = { // 公共属性配置
+ Object: { // 默认配置-对象上
+ // 设置对象边框的颜色(Rect、Circle、Ellipse、Path)
+ borderColor: '#65CC8A',
+ // 设置对象角落的颜色(Rect、RoundRect、Circle 和 Ellipse 类型的对象)
+ cornerColor: '#65CC8A',
+ // 设置角落的形状(Rect、RoundRect、Circle 和 Ellipse 类型的对象)
+ // circle rect round [圆形,直角(默认),圆角]
+ cornerStyle: 'circle',
+ // 设置边框虚线的样式(Rect、Circle、Ellipse、Path)
+ borderDashArray: [3, 3],
+ // 矩形(Rect)、圆角矩形(RoundRect)、圆形(Circle)和椭圆形(Ellipse)对象的角落是否透明
+ transparentCorners: false
+ },
+ Line: {
+ // 设置边缘连接方式为 miter bevel round|尖角(默认) 斜角切割线 圆形连接
+ strokeLineJoin: 'round',
+ // 设置结束连接方式为 butt round square|直角(默认) 圆形 正方形
+ strokeLineCap: 'round'
+ }
+ }
+ }
+ /**
+ * 初始化canvas
+ * @param {*} canvasEl canvas元素
+ * @returns boolean 是否初始化成功
+ */
+ initCanvas(canvasEl, option = {}) {
+ return new Promise(async(resolve) => {
+ if (!canvasEl) resolve(false)
+ this.canvas = new fabric.Canvas(canvasEl, {
+ ...this.defConfig, ...option
+ })
+ // this.evnet = new CanvasEvent() // 创建相关事件
+ // this.history = new History() // 创建历史记录
+ // await this.initCanvasStorage()
+ resolve(true)
+ })
+ }
+
+}
+export const FabricVue = new fabricVue()
+export default FabricVue
+
diff --git a/src/renderer/src/utils/pdfAndFabric.js b/src/renderer/src/utils/pdfAndFabric.js
index f4b0ca9..3807034 100644
--- a/src/renderer/src/utils/pdfAndFabric.js
+++ b/src/renderer/src/utils/pdfAndFabric.js
@@ -14,23 +14,24 @@ export function handleevent(canvas, imgarr, type = 'defalut') {
if (imgarr.value[0].index == 0) {
imgarr.value[0].JSONdata = canvas.toJSON()
}
- if (imgarr.value[1].index == 0) {
+ 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) {
+ 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)
- // console.log(canvsStore.pageArr,22222222222222222222+'存入')
}
// 重显数据
export function displayData(canvas, canvsStore, canvasobj, fabric, img) {
@@ -50,19 +51,21 @@ export function displayData(canvas, canvsStore, canvasobj, fabric, img) {
canvsStore.pageArr.forEach((item) => {
//初始化
if (item.page == canvasobj.page) {
- canvas.value.clear() // 清除 Canvas
+ // canvas.value.clear() // 清除 Canvas
// console.log(item.JSONdata, '找到一样的数据')
canvas.value.loadFromJSON(item.JSONdata, () => {
// 在所有对象加载完成后重新渲染画布
- requestAnimationFrame(() => {
- // 渲染所有对象
- canvas.value.renderAll.bind(canvas.value)
- canvas.value.renderAll()
- })
+ canvas.value.renderAll.bind(canvas.value)
+ canvas.value.renderAll()
+ // requestAnimationFrame(() => {
+ // // 渲染所有对象
+
+ // })
})
} else {
// 使用 requestAnimationFrame 来更新画布,确保在下一帧进行重绘
- canvas.value.clear() // 清除 Canvas
+ // // 清除 Canvas
+ canvas.value.clear()
requestAnimationFrame(function () {
fabric.Image.fromURL(img.src, (img) => {
img.set({
@@ -75,6 +78,7 @@ export function displayData(canvas, canvsStore, canvasobj, fabric, img) {
})
// 渲染所有对象
canvas.value.renderAll.bind(canvas.value)
+ canvas.value.renderAll()
})
}
})
diff --git a/src/renderer/src/utils/tool.js b/src/renderer/src/utils/tool.js
index 2ca72e7..7a56f5e 100644
--- a/src/renderer/src/utils/tool.js
+++ b/src/renderer/src/utils/tool.js
@@ -5,8 +5,9 @@
// import { ipcRenderer } from 'electron' // 渲染器里面可以使用ipcRenderer
-// const path = require('path')
+const path = require('path')
const Remote = require('@electron/remote')
+const { ipcRenderer } = require('electron')
// 常用变量
const BaseUrl = process.env['ELECTRON_RENDERER_URL']+'/#'
@@ -16,11 +17,11 @@ const isDev = process.env.NODE_ENV !== 'production'
/**
* @description 消息发送-nodejs 消息发送
* @form src/main/tool.js 来源
- * @param {*} key 消息key
+ * @param {*} key 消息key
* tool-sphere:create 创建-悬浮球
- * @param {*} data 参数
+ * @param {*} data 参数
* url:路由地址,width:窗口宽度,height:窗口高度,option:自定义选项
- * @returns
+ * @returns
*/
export function ipcMsgSend(key, data) {
return new Promise((resolve) => {
@@ -37,7 +38,7 @@ export function ipcMsgSend(key, data) {
* @param {*} type 类型
* tool-sphere 创建-悬浮球
* @param {*} data 参数
- * @returns
+ * @returns
*/
export const createWindow = async (type, data) => {
if (!type) return console.error('createWindow: type is null')
@@ -54,6 +55,7 @@ export const createWindow = async (type, data) => {
}
data.option = {...defOption, ...option}
const win = await toolWindow(data)
+ win.type = type // 唯一标识
win.show()
win.setFullScreen(true) // 设置窗口为全屏
win.setIgnoreMouseEvents(true, {forward: true}) // 忽略鼠标事件但是事件继续传递给窗口
@@ -72,7 +74,7 @@ export const createWindow = async (type, data) => {
}
data.option = {...defOption, ...option}
const win = await toolWindow(data)
-
+ win.type = type // 唯一标识
win.show()
win.setFullScreen(true) // 设置窗口为全屏
eventHandles(type, win) // 事件监听处理
@@ -97,7 +99,7 @@ export function toolWindow({url, isFile, isConsole, option={}}) {
let height = option?.height || 600
const mainWin = Remote.getCurrentWindow() // 获取主窗口对象
const devUrl = `${BaseUrl}${url}`
- const buildUrl = `file://${__dirname}/index.html${url}`
+ const buildUrl = path.join(__dirname, 'index.html')
const urlAll = isDev ? devUrl : buildUrl
return new Promise((resolve) => {
const config = {
@@ -113,7 +115,7 @@ export function toolWindow({url, isFile, isConsole, option={}}) {
}
// 创建-新窗口
let win = new Remote.BrowserWindow(config)
- if (!!isFile) win.loadFile(urlAll) // 加载文件
+ if (!isDev) win.loadFile(urlAll,{hash: url}) // 加载文件
else win.loadURL(urlAll) // 加载url
win.once('ready-to-show', () => {resolve(win)})
// 主窗口关闭事件
@@ -134,11 +136,17 @@ export function toolWindow({url, isFile, isConsole, option={}}) {
* @param {*} win 窗口对象
*/
const eventHandles = (type, win) => {
+ // const winAll = Remote.BrowserWindow.getAllWindows()
+ // const mainWin = winAll.find(o => o.type == 'main') // 主窗口对象
// 公共方法
- const publicMethods = ({onClosed}) => {
- // 监听关闭事件
- Remote.ipcMain.once('close-window', () => {win.destroy()})
- win.on('closed', () => {!!onClosed && onClosed();win = null})
+ const publicMethods = ({onClosed}={}) => {
+ // 监听主窗口-关闭事件
+ // Remote.ipcMain.on('close-window', () => {console.log('关闭窗口');win.destroy()})
+ // mainWin.once('closed', () => {console.log('关闭窗口');win.destroy()})
+ win.on('closed', () => {
+ if(onClosed) onClosed()
+ win = null
+ })
}
switch(type) {
case 'tool-sphere': { // 创建-悬浮球
@@ -148,10 +156,7 @@ const eventHandles = (type, win) => {
// 关闭窗口
Remote.ipcMain.once('tool-sphere:close', () => { win.destroy() })
// 放大监听-测试
- Remote.ipcMain.once('maximize-window', () => {
- win.destroy()
- console.log('关闭窗口')
- })
+ Remote.ipcMain.once('maximize-window', () => {win.destroy()})
const on = {
onClosed: () => {Remote.ipcMain.off('tool-sphere:set:ignore', setIgnore)}
}
@@ -160,6 +165,7 @@ const eventHandles = (type, win) => {
case 'open-PDF': {
// 最小化窗口 minimize()
Remote.ipcMain.once('open-PDF:minimize', () => {win.destroy()})
+ publicMethods() // 加载公共方法
break}
default:
break
diff --git a/src/renderer/src/views/classBegins/index.vue b/src/renderer/src/views/classBegins/index.vue
index 59a844f..73f62c6 100644
--- a/src/renderer/src/views/classBegins/index.vue
+++ b/src/renderer/src/views/classBegins/index.vue
@@ -36,7 +36,7 @@ import { ref, onMounted, watch, reactive } from 'vue'
import * as pdfjsLib from 'pdfjs-dist/legacy/build/pdf'
pdfjsLib.GlobalWorkerOptions.workerSrc = '/lib/build/pdf.worker.mjs'
import pdfCanvas from '@/components/pdf/index.vue'
-const { ipcRenderer } = require('electron')
+const { ipcRenderer } = window.electron || {}
// 传过去的参数
const pdfObj = reactive({
numberOfPdf: 2, //显示几页
@@ -125,4 +125,4 @@ onMounted(async () => {})
}
}
}
-
\ No newline at end of file
+
diff --git a/src/renderer/src/views/tool/test.vue b/src/renderer/src/views/tool/test.vue
index b3e81a9..153d10c 100644
--- a/src/renderer/src/views/tool/test.vue
+++ b/src/renderer/src/views/tool/test.vue
@@ -1,22 +1,26 @@
-
+