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

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

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

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

步骤一:引入Fabric.js库

javascript 复制代码
npm i fabric --save

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

javascript 复制代码
npm i less 
javascript 复制代码
npm i less-loader

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

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

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

javascript 复制代码
<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的ID
			cardContent.appendChild(cardCanvas); // 插入canvas到父节点中
		},
		// 初始化画布
		init() {
			// 画布初始配置
			canvas = new fabric.Canvas('card-canvas', { // 获取画布节点传入 初始化节点ID
				width: 200, // 后续可以更改
				height: 200,
			});

		}
	}
}
</script>
<style lang="less" scoped>
/deep/ #card-canvas{
	border: 1px solid red ;
}
</style>

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

javascript 复制代码
// 初始化画布
		init() {
			// 画布初始配置
			canvas = new fabric.Canvas('card-canvas', { // 获取画布节点传入 初始化节点ID
				width: 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';
				// 修改控制点的大小为10px
				fabric.Object.prototype.cornerSize = 10;
				// 设置控制点不透明,即可以盖住其下的控制线
				fabric.Object.prototype.transparentCorners = false;
				// 修改控制点的边框颜色为`gray`灰色
				fabric.Object.prototype.cornerStrokeColor = 'gray';
				// 单独修改旋转控制点距离主体的纵向距离为-20px
				fabric.Object.prototype.controls.mtr.offsetY = -20;
				// 单独修改旋转控制点,光标移动到该点上时的样式为`pointer`,一个手的形状
				fabric.Object.prototype.controls.mtr.cursorStyle = 'pointer';

		}

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

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

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

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

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

javascript 复制代码
// 图片转码
			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背景图片

javascript 复制代码
// 设置/修改画布背景图  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 // 路径
			});
		},

使用:

javascript 复制代码
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)
		},

此时是页面呈现的样式

步骤六:插入文字

javascript 复制代码
// 插入文字 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); //优先级
		}

使用

javascript 复制代码
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)
		},

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

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

相关推荐
样子20184 小时前
Uniapp 之renderjs解决swiper+多个video卡顿问题
前端·javascript·css·uni-app·html
fakaifa6 小时前
点大餐饮独立版系统源码v1.0.3+uniapp前端+搭建教程
小程序·uni-app·php·源码下载·点大餐饮·扫码点单
Bug改不动了8 小时前
React Native 与 UniApp 对比
react native·react.js·uni-app
anyup11 小时前
🔥🔥 10 天 Star 破百!uView Pro 文档也开源啦:完全免费、无广告、高效上手
前端·vue.js·uni-app
fakaifa20 小时前
【最新版】CRMEB Pro版v3.4系统源码全开源+PC端+uniapp前端+搭建教程
人工智能·小程序·uni-app·php·crmeb·源码下载·crmebpro
2501_915918411 天前
iOS 应用上架全流程实践,从开发内测到正式发布的多工具组合方案
android·ios·小程序·https·uni-app·iphone·webview
梦里寻码1 天前
自行食用 uniapp 多端 手写签名组件
前端·uni-app
不如摸鱼去2 天前
Trae 辅助下的 uni-app 跨端小程序工程化开发实践分享
微信小程序·小程序·uni-app·aigc·ai编程
小白_ysf3 天前
uniapp 开发微信小程序,获取经纬度并且转化详细地址(单独封装版本)
微信小程序·uni-app
iOS阿玮3 天前
三年期已满,你的产品不再更新将于90天后下架。
uni-app·app·apple