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)},

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

 

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【go】go初始化命令总结

包初始化 test项目目录下执行 go mod init test go mod tidy生成二进制可执行文件 go build -o test .\main.go

apache集合工具类ListUtils

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><version>4.4</version> </dependency>判断两集合是否相等 List<String> list1 Arrays.asList("1", &qu…

C#唯一进程的处理Winform/WPF

C#唯一进程的处理 1.使用进程&#xff08;Process&#xff09;判断winformWPF执行效果&#xff1a; 2.使用互斥体&#xff08;Metux&#xff09;实现winformWPF实现效果&#xff1a; 在C#客户端&#xff08;Winform/WPF&#xff09;开发过程中&#xff0c;有的情况需要确保程序…

三分钟搞懂AI Agent是什么!

点击下方“JavaEdge”&#xff0c;选择“设为星标” 第一时间关注技术干货&#xff01; 免责声明~ 任何文章不要过度深思&#xff01; 万事万物都经不起审视&#xff0c;因为世上没有同样的成长环境&#xff0c;也没有同样的认知水平&#xff0c;更「没有适用于所有人的解决方案…

mindmapper17软件最新版下载-MindMapper17(思维导图软件)下载附加详细安装步骤

​​MindMapper​​​是一款专业的可视化思维导图软件&#xff0c;通过智能绘图方法&#xff0c;在管理信息和处理工作流程中&#xff0c;帮助提高组织、审查、合作、分享和交流能力。《思维导图三招十八式》作者也一直力荐 MindMapper这款软件。思维导图是表达发射性思维的有效…

《详解》如何在ROS中建立MQTT通信

观前提醒&#xff1a;本期主要内容为ROS中MQTT通信节点的编程&#xff0c;和ROS部分底层通信机制的浅析 一、复习一下&#xff1a;ROS通信机制&MQTT通信异同点 ROS通信机制概述 ROS中的主要通信机制有以下几种&#xff1a; 话题 (Topics) 发布/订阅模型&#xff08;Pu…

Android 断点续传基础之单线程下载

**遇到的问题&#xff1a;**在这因为返回值的问题烦躁了一下&#xff0c;有可能出现空指针的异常&#xff0c;已经提出成文章了 请参考http://blog.csdn.net/qq_27489007/article/details/53523378 文件关系图 断点续传流程图 开始撸代码(主要代码) /** 普通断点续传 */ …

AI 生成文本工具推荐(AI 对话/AI 聊天机器人/AI 写作)

① boardmix AI boardmix AI&#xff0c;是一个在线的智能 AI 对话 App&#xff0c;打开浏览器即可在线使用&#xff0c;支持 AI 多轮连续对话&#xff0c;提供 AI 角色切换、AI 多语言翻译、一键唤出、可视化表达及多人协作功能。 boardmix AI 预置了多个不同的 AI 角色&…

代码随想录训练营第十二天

第一题&#xff1a; 原题链接&#xff1a;150. 逆波兰表达式求值 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 定义一个栈 stack<int> st&#xff1b; 当我们遇到 - * / 的时候就需要将栈中的最后两个元素取出来&#xff0c;然后进行对应的操作并将结果…

⭐Unity 控制任意UI的渐隐渐显

使用脚本之前先给要控制的UI加上CanvasGroup组件 解释: 这个脚本使用协程来逐渐改变CanvasGroup的alpha值&#xff0c;从而实现渐隐和渐显的效果。 Mathf.Lerp函数用于在指定的时间内平滑地从当前透明度过渡到目标透明度。 通过调用FadeIn和FadeOut方法&#xff0c;你可以在任…

eNSP学习——配置DHCP中继

目录 主要命令 原理概述 实验目的 实验内容 实验拓扑 实验编址 实验步骤 1、基本配置 2、搭建OSPF网络 3、配置DHCP服务器 4、配置DHCP中继 5、配置PC获取地址方式为DHCP 主要命令 //配置指定DHCP服务器的方法 //方法一&#xff1a;在面向PC的接口下直接配置DHCP服…

CP AUTOSAR标准之LargeDataCOM(AUTOSAR_CP_SWS_LargeDataCOM)(更新中……)

1 简介和功能概述 该规范描述了AUTOSAR基础软件模块LdCom的功能、API和配置。   在AUTOSAR分层架构中,AUTOSAR LdCom模块位于RTE/SwCluC_LdComProxy和PDU路由之间,参见[1,EXP LayeredSoftwareArchitecture]。   AUTOSAR LdCom模块提供了一种替代的交互层机制。通过专注于…

Ubuntu 使用Vscode的一些技巧 ROS

Ubuntu VSCode的一些设置&#xff08;ROS&#xff09; 导入工作空间 推荐只导入工作空间下的src目录 如果将整个工作空间导入VSCode&#xff0c;那么这个src就变成了次级目录&#xff0c;容易在写程序的时候把本应该添加到具体工程src目录里的代码文件给误添加到这个catkin_w…

MySQL(5)

聚合函数 GROUP BY 的使用 需求&#xff1a;查询各个部门的平均工资&#xff0c;最高工资SELECT department_id,AVG(salary),SUM(salary)FROM employeesGROUP BY department_id;需求&#xff1a;查询各个job_id的平均工资SELECT job_id,AVG(salary)FROM employeesGROUP BY jo…

HTTP/3 协议学习

前一篇&#xff1a; HTTP/2 协议学习-CSDN博客 HTTP/3 协议介绍 HTTP/3 是互联网上用于传输超文本的协议 HTTP 的第三个主要版本。它是 HTTP/2 的后继者&#xff0c;旨在进一步提高网络性能和安全性。HTTP/3 与前两个版本的主要区别在于它使用了一个完全不同的底层传输协议—…

stringstream的使用

std::stringstream 是C标准库中的一个类&#xff0c;用于在内存中操作字符串流。它提供了一种方便的方式来格式化和解析字符串数据&#xff0c;类似于文件流&#xff08;如 std::ifstream 和 std::ofstream&#xff09;但针对字符串。std::stringstream 属于 <sstream> 头…

基于协同过滤算法的电影推荐

基于协同过滤算法的电影推荐 电影推荐系统使用了基于**协同过滤&#xff08;Collaborative Filtering&#xff09;的算法来生成推荐。具体来说&#xff0c;使用了基于用户的协同过滤&#xff08;User-Based Collaborative Filtering&#xff09;**算法&#xff0c;步骤如下&am…

Selenium等待方式详解:原理、用法与应用场景

在自动化测试中&#xff0c;等待是一个非常重要的概念。正确地使用等待可以提高测试用例的可靠性和稳定性。本文将详细介绍Selenium中的三种等待方式&#xff1a;线程阻塞等待、隐式等待和显式等待&#xff0c;分析它们的原理、用法和应用场景。 1. 线程阻塞等待 线程阻塞等待…

XLM-RoBERTa 是一种多语言版本的 RoBERTa 模型

XLM-RoBERTa 是一种多语言版本的 RoBERTa 模型&#xff0c;由 Facebook AI 开发。它是为了处理多种语言的自然语言理解任务而设计的。 XLM-RoBERTa 的主要特性&#xff1a; 多语言能力&#xff1a;在使用 CommonCrawl 数据集的 100 种语言上进行训练&#xff0c;XLM-RoBERTa …

【SCAU数据挖掘】数据挖掘期末总复习题库应用题及解析

1. 给定圆的半径为e &#xff0c;令 MinPts3&#xff0c;考虑下面两幅图。 &#xff08;1&#xff09;哪些对象是核心对象? m,p,o,r(因为这些核心对象在半径e的范围内都至少包含MinPts3个对象) &#xff08;2&#xff09;哪些对象是直接密度可达的? 对象q是…