canvas实现画布拖拽效果 适配Uniapp和Vue (开箱即用)

本文主要是介绍canvas实现画布拖拽效果 适配Uniapp和Vue (开箱即用),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

需求:我司是做AIGC项目最近和地铁项目有关需要实现海报效果图,并且需要使用画布拖拽和修改上传删除等等功能 当时连续加班花了10个工作日搓出来 实现挺简单的但是Canvas数据处理还是挺麻烦的  大概功能如图下 

首先我们需要引入Fabric.js 这个库封装好了原生的Canvas的Api使用uniapp和vue项目

Fabric.js能做的事情
  • 在Canvas上创建、填充图形(包括图片、文字、规则图形和复杂路径组成图形)。
  • 给图形填充渐变颜色。
  • 组合图形(包括组合图形、图形文字、图片等)。
  • 设置图形动画集用户交互。
  • 生成JSON, SVG数据等。
  • 生成Canvas对象自带拖拉拽功能。

 步骤一:引入Fabric.js库

npm i fabric --save

步骤二:安装less或者sass因为需要更改canvas样式需要用到deep(使用sass注意更改style的lang)

npm i less 
npm i less-loader

步骤三:创建DOM节点 uniapp和纯vue项目的canvas创建是不一样的 (巨坑)

Uniapp的canvas外层会嵌套uniapp-canvas会阻碍到Fabric.js读取但是纯vue项目则不会

因为Canvas代码量比较多 我这边把坑就额外标记出来 建议复制到vscode查看更佳 (下列代码复制即可使用 亲测有效 一定要按照步骤来)

<template><!-- 父级节点 --><view id="card-canvas-content"></view>
</template><script>
import {fabric
} from 'fabric'; // 引入库
let canvas = null // 最好设置成全局的不要定义到data里面
export default {data() {return {}},mounted() {this.createCanvasDom('card-canvas') // 初始化节点this.init() //初始化画布},methods: {// 创建画布createCanvasDom(elID) {var cardContent = document.getElementById('card-canvas-content'); //选取父节点var cardCanvas = document.createElement('canvas'); // 创建canvas标签cardCanvas.setAttribute('id', elID); // 设置canvas的IDcardContent.appendChild(cardCanvas); // 插入canvas到父节点中},// 初始化画布init() {// 画布初始配置canvas = new fabric.Canvas('card-canvas', { // 获取画布节点传入 初始化节点IDwidth: 200, // 后续可以更改height: 200,});}}
}
</script>
<style lang="less" scoped>
/deep/ #card-canvas{border: 1px solid red ;
}
</style>

 步骤四:canvas基础配置(这些配置是可选的可以根据项目情况自行配置)

// 初始化画布init() {// 画布初始配置canvas = new fabric.Canvas('card-canvas', { // 获取画布节点传入 初始化节点IDwidth: 200, // 后续可以更改height: 200,});fabric.Object.prototype.padding = 10;fabric.Object.prototype.controls.mtr.withConnection = false;// 解决动态生成文字模糊问题fabric.Object.prototype.objectCaching = false;fabric.Object.prototype.borderColor = 'dodgerblue';// 修改控制点的形状,默认为`rect`矩形,可选的值还有`circle`圆形fabric.Object.prototype.cornerStyle = 'circle';// 修改控制点的填充色为白色fabric.Object.prototype.cornerColor = 'white';// 修改控制点的大小为10pxfabric.Object.prototype.cornerSize = 10;// 设置控制点不透明,即可以盖住其下的控制线fabric.Object.prototype.transparentCorners = false;// 修改控制点的边框颜色为`gray`灰色fabric.Object.prototype.cornerStrokeColor = 'gray';// 单独修改旋转控制点距离主体的纵向距离为-20pxfabric.Object.prototype.controls.mtr.offsetY = -20;// 单独修改旋转控制点,光标移动到该点上时的样式为`pointer`,一个手的形状fabric.Object.prototype.controls.mtr.cursorStyle = 'pointer';}

第五步:初始化数据建议抽离一个方法出去避免都写在init里面过于冗杂 (在init里面调用放置末尾

init() {this.initDate()
}
// 初始化数据initDate() {//更改画布后续宽高 可以根据后台的图片动态设置canvas大小canvas.setDimensions({width: this.width,height: this.height});// fabric内置的方法 用于重新渲染canvas 在字体以及大小更换 图片替换都需要调用此方法 否则canvas不会更新新数据canvas.renderAll();this.$nextTick(() => {// canvas渲染完成之后最后就会执行一般是处理loading效果的});}

步骤六:导入背景图 (巨坑 当时我研究了贼久 一直报错图片污染导致后续图片无法导出canvas)  

我们需要把远程的背景图片转成base64的格式不然导出canvas会报错 这也是跨域 网上有很多解决方案都没用

代码比较长我就抽离出去写注释 这些方法统一在initDate里面调用 

// 图片转码getURLBase64(url) {//将远程图片下载本地成为base64图片let _this = this;return new Promise((resolve, reject) => {var xhr = new XMLHttpRequest();xhr.open('get', url, true);xhr.responseType = 'blob';xhr.onload = function() {if (this.status === 200) {var blob = this.response;var fileReader = new FileReader();fileReader.onloadend = function(e) {var result = e.target.result;_this.imageUrl = result;resolve(result);};fileReader.readAsDataURL(blob);}};xhr.onerror = function() {reject();};xhr.send();});},

 设置Canvas背景图片

// 设置/修改画布背景图  bgUrl:转码后的背景图片 canvasDOM:canvas的实例变量名setBackgroundImage(bgUrl, canvasDOM) {canvasDOM.setBackgroundImage(bgUrl, canvasDOM.renderAll.bind(canvasDOM), { // canvas实例变量originX: 'left',originY: 'top',left: 0,top: 0,level: 1, // 层级bgUrl // 路径});},

 使用:

async initDate() {//更改画布后续宽高 可以根据后台的图片动态设置canvas大小canvas.setDimensions({width: this.width,height: this.height});// fabric内置的方法 用于重新渲染canvas 在字体以及大小更换 图片替换都需要调用此方法 否则canvas不会更新新数据canvas.renderAll();// 背景地址 自己随便填一个线上的即可let bgUrl = await this.getURLBase64('https://img1.baidu.com/it/u=395218774,2205974617&fm=253&app=138&size=w931&n=0&f=GIF&fmt=auto?sec=1718730000&t=15d143401501c32f552f4157563acaf4');// 设置背景图片this.setBackgroundImage(bgUrl, canvas)},

 此时是页面呈现的样式

 

步骤六:插入文字

// 插入文字 text:文本 canvasDOM:canvas的实例变量名setTextFont(text,canvasDOM) {const textDOM = new fabric.Textbox(text, {top: 0, // 位置left: 0,fontSize: 19, // 文字大小fill: 'red', // 颜色level: 0, // 层级fontFamily: '思源黑体 CN Heavy',splitByGrapheme: true});canvasDOM.add(textDOM); //添加文字canvasDOM.bringToFront(textDOM); //优先级}

使用

async initDate() {//更改画布后续宽高 可以根据后台的图片动态设置canvas大小canvas.setDimensions({width: this.width,height: this.height});// fabric内置的方法 用于重新渲染canvas 在字体以及大小更换 图片替换都需要调用此方法 否则canvas不会更新新数据canvas.renderAll();// 背景地址 自己随便填一个线上的即可let bgUrl = await this.getURLBase64('https://img1.baidu.com/it/u=395218774,2205974617&fm=253&app=138&size=w931&n=0&f=GIF&fmt=auto?sec=1718730000&t=15d143401501c32f552f4157563acaf4');// 设置背景图片this.setBackgroundImage(bgUrl, canvas)// 插入文本this.setTextFont('这是一行文本',canvas)},

 页面效果 此时页面的文字是可以进行拖拽等操作的

 

(内容有点多 先更新三分之一 后面再抽空更新)

这篇关于canvas实现画布拖拽效果 适配Uniapp和Vue (开箱即用)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/1071670

相关文章

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

PyCharm中配置PyQt的实现步骤

《PyCharm中配置PyQt的实现步骤》PyCharm是JetBrains推出的一款强大的PythonIDE,结合PyQt可以进行pythion高效开发桌面GUI应用程序,本文就来介绍一下PyCha... 目录1. 安装China编程PyQt1.PyQt 核心组件2. 基础 PyQt 应用程序结构3. 使用 Q

Python实现批量提取BLF文件时间戳

《Python实现批量提取BLF文件时间戳》BLF(BinaryLoggingFormat)作为Vector公司推出的CAN总线数据记录格式,被广泛用于存储车辆通信数据,本文将使用Python轻松提取... 目录一、为什么需要批量处理 BLF 文件二、核心代码解析:从文件遍历到数据导出1. 环境准备与依赖库

linux下shell脚本启动jar包实现过程

《linux下shell脚本启动jar包实现过程》确保APP_NAME和LOG_FILE位于目录内,首次启动前需手动创建log文件夹,否则报错,此为个人经验,供参考,欢迎支持脚本之家... 目录linux下shell脚本启动jar包样例1样例2总结linux下shell脚本启动jar包样例1#!/bin

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont

Python实现PDF按页分割的技术指南

《Python实现PDF按页分割的技术指南》PDF文件处理是日常工作中的常见需求,特别是当我们需要将大型PDF文档拆分为多个部分时,下面我们就来看看如何使用Python创建一个灵活的PDF分割工具吧... 目录需求分析技术方案工具选择安装依赖完整代码实现使用说明基本用法示例命令输出示例技术亮点实际应用场景扩

java如何实现高并发场景下三级缓存的数据一致性

《java如何实现高并发场景下三级缓存的数据一致性》这篇文章主要为大家详细介绍了java如何实现高并发场景下三级缓存的数据一致性,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 下面代码是一个使用Java和Redisson实现的三级缓存服务,主要功能包括:1.缓存结构:本地缓存:使

如何在Java Spring实现异步执行(详细篇)

《如何在JavaSpring实现异步执行(详细篇)》Spring框架通过@Async、Executor等实现异步执行,提升系统性能与响应速度,支持自定义线程池管理并发,本文给大家介绍如何在Sprin... 目录前言1. 使用 @Async 实现异步执行1.1 启用异步执行支持1.2 创建异步方法1.3 调用