From 5ac36dd569eca39b4fdc3521aade3ea6587fe0c8 Mon Sep 17 00:00:00 2001 From: zdg Date: Fri, 26 Jul 2024 22:15:12 +0800 Subject: [PATCH] =?UTF-8?q?bug=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/index.js | 7 +- src/renderer/src/plugins/fabric/test.js | 223 ++++++++++++++++++++++++ src/renderer/src/utils/tool.js | 33 ++-- src/renderer/src/views/tool/test.vue | 14 +- 4 files changed, 256 insertions(+), 21 deletions(-) create mode 100644 src/renderer/src/plugins/fabric/test.js 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/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/tool.js b/src/renderer/src/utils/tool.js index 3658a44..2933a53 100644 --- a/src/renderer/src/utils/tool.js +++ b/src/renderer/src/utils/tool.js @@ -1,12 +1,13 @@ /** * @description: electron 封装的工具函数 */ -const { ipcRenderer } = window.electron || {} +// const { ipcRenderer } = window.electron || {} // import { ipcRenderer } from 'electron' // 渲染器里面可以使用ipcRenderer const path = require('path') const Remote = require('@electron/remote') +const { ipcRenderer } = require('electron') // 常用变量 const BaseUrl = process.env['ELECTRON_RENDERER_URL']+'/#' @@ -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 = path.join(__dirname, 'index.html#') + const buildUrl = path.join(__dirname, 'index.html') const urlAll = isDev ? devUrl : buildUrl return new Promise((resolve) => { const config = { @@ -113,9 +115,8 @@ export function toolWindow({url, isFile, isConsole, option={}}) { } // 创建-新窗口 let win = new Remote.BrowserWindow(config) - console.log(urlAll) - if (!!isFile) win.loadFile(urlAll+url) // 加载文件 - else win.loadURL(urlAll,{hash: url}) // 加载url + if (!!isFile) win.loadFile(urlAll,{hash: url}) // 加载文件 + else win.loadURL(urlAll) // 加载url win.once('ready-to-show', () => {resolve(win)}) // 主窗口关闭事件 mainWin.once('closed', () => { win.destroy()}) @@ -135,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': { // 创建-悬浮球 @@ -149,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)} } @@ -161,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/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 @@