Fabric

Fabric


Fabric.js是一个非常好用的Javascript HTML5 canvas库,封装了canvas原生较为复杂的api,在canvas元素的顶部提供交互式对象模型,用于实现图片的变形旋转拖拉拽等功能。
在这里插入图片描述

在线demo: 官网链接


下载

npm install fabric --save

yarn add fabric

期间下载到canvas会用时比较长,推荐使用npm,用yarn有时候会安装失败


初始化

如果无需设置图片边框 也可以将canvas.on整个函数删除

<div class="section" :style="{width: `800px`, height: `500px`}" ref="canvasSectionRef"><canvas ref="canvasRef" width="800" height="500" id="fabricCanvas"></canvas>
</div>
// vue3
import {onMounted, onUnmounted, ref} from 'vue';
import {fabric} from 'fabric';const canvasSectionRef = ref(null)  // canvas 父元素引用
const canvasRef = ref(null)  // canvas 的引用
let canvas     // 用于保存fabric canvas 对象, 不能用ref/*** @description 根据 id 在 canvas 对象中查找出对应的图片对象和其索引(索引同时也是显示层级 即 z-index),在callBack中做对应处理* @param id {string} 图片对象的id* @param callBack {(selectedObject: Object, zIndex: number) => any} 查找到对象后的回调* @returns {undefined}*/
const editImageState = (id, callBack) => {const objList = canvas.getObjects()const zIndex = objList.findIndex((obj) => {return obj.customId === id});const selectedObject = objList[zIndex]if (!selectedObject) returncallBack?.(selectedObject, zIndex)
}/*** @description*  初始化fabric canvas 对象 设置边框颜色 和 四个角控制点的样式*  - 点击时显示蓝色虚线边框*  - 锁定时点击为灰色虚线边框*  - 默认没有选中为透明边框*/
const fabricInit = () => {let selectedObjects = {}; // 使用对象来存储不同图片的选中状态 存储方式为 `key - value` -> `id - boolean`canvas = new fabric.Canvas(canvasRef.value);// 自定义控制点样式fabric.Object.prototype.set({cornerStyle: 'square',cornerColor: '#4191fa',cornerSize: 10,transparentCorners: false,cornerStrokeColor: '#fff',cornerStrokeWidth: 2});// 点击时图片添加边框 不需要可以去除 canvas.on('mouse:down', function (options) {// 当前鼠标点击时获取的对象const targetObject = canvas.findTarget(options.e);if (targetObject && targetObject.type === 'image') {// 获取选中图片的id 用于设置边框样式const currentId = targetObject.customId;if (selectedObjects[currentId]) {// 当前点击的图片已经是选中状态,不执行任何操作} else {// 取消显示当前所有图片的边框 (先全部取消 再按id查找当前点击的图片设置为选中)for (const id in selectedObjects) {// 处理取消选中的逻辑if (selectedObjects.hasOwnProperty(id) && selectedObjects[id]) {editImageState(id, (imageItem) => {imageItem.set({stroke: 'transparent',strokeWidth: 2});})}}selectedObjects = {};// 将当前点击的图片设置为选中状态  显示边框selectedObjects[currentId] = true;editImageState(currentId, (imageItem) => {let color = imageItem.selectable ? '#4191fa' : '#ccc'imageItem.set({stroke: color, // 显示边框strokeWidth: 2 // 边框宽度为2});})}} else {// 点击的是画布空白处,清空选中对象for (const id in selectedObjects) {if (selectedObjects.hasOwnProperty(id) && selectedObjects[id]) {editImageState(id, (imageItem) => {imageItem.set({stroke: 'transparent', // 隐藏边框strokeWidth: 2 // 边框宽度为0});})}}selectedObjects = {};}// 处理完成重新渲染 否则不是马上生效canvas.renderAll();});
}onMounted(() => {fabricInit()
});onUnmounted(() => {canvas = null
})

添加图片

添加图片时需要添加唯一id,方便后续根据id对图片进行操作

// 生成唯一的 ID 用于图片升成
function generateUniqueId() {return 'id_' + +new Date();
}/*** @description 根据url地址在canvas对象中添加图片* @param url {string} 图片地址 在线 or 离线*/
const addImg = (url) => {fabric.Image.fromURL(url, function (img) {img.set({selectable: true, // 禁用选中效果 -> true为不禁用 | false为禁用hasControls: true, // 禁用控制点 -> true为不禁用 | false为禁用borderColor: 'transparent', // 边框颜色strokeDashArray: [5, 5],strokeWidth: 2});// 添加唯一idimg.customId = generateUniqueId();canvas.add(img);});
}

新增了addImg这个函数后就可以在onMounted中使用addImg(图片地址),在canvas中就可以看到效果。

锁定 / 解锁图片(不可选中不可移动)

/*** @description 将canvas对象中对应id的图片对象设置为禁用 并设置边框颜色灰色* @param id {string} 图片对象id*/
const lockImg = (id) => {editImageState(id, (imageItem) => {imageItem.set({selectable: false, // 禁用选中效果hasControls: false, // 禁用控制点stroke: '#ccc',});canvas.discardActiveObject()canvas.renderAll()})
}/*** @description 将canvas对象中对应id的图片对象设置取消禁用 并设置边框颜色蓝色* @param id {string} 图片对象id*/
const unLockImg = (id) => {editImageState(id, (imageItem) => {imageItem.set({selectable: true, // 禁用选中效果hasControls: true, // 禁用控制点stroke: '#4191fa'});canvas.renderAll()})
}

删除图片

/*** @description 将canvas对象中对应id的图片对象删除* @param id {string} 图片对象id*/
const deleteImg = (id) => {editImageState(id, (imageItem) => {canvas.remove(imageItem);canvas.renderAll()})
}


获取图片id

根据id进行修改删除图片的方法都有了,然后就是获取图片id的方法

const selectImgId = ref() // 保存点击时的图片id// 判断元素是否为Canvas元素或其子元素
const isCanvasElement = (element) => {return element instanceof HTMLCanvasElement || element.closest('canvas') !== null;
}/*** @description 查找canvas所有生成的对象(图片)中 点击位置上的对象* @param x {number} 鼠标点击的相对于canvas的 x 坐标* @param y {number} 鼠标点击的相对于canvas的 Y 坐标* @returns {Object|null} 点击处的对象 没有则返回null*/
const findClickedObject = (x, y) => {// 遍历Canvas上的所有对象,判断点击位置是否在对象范围内for (let i = canvas.getObjects().length - 1; i >= 0; i--) {const obj = canvas.item(i);if (obj.containsPoint({x: x, y: y})) {return obj;}}return null;
}const getImgId = (event) => {if (isCanvasElement(event.target)) {// 获取鼠标点击位置相对于 Canvas 元素的坐标const canvasRect = canvasSectionRef.value.getBoundingClientRect();const x = event.clientX - canvasRect.left;const y = event.clientY - canvasRect.top;// 查找点击位置上的对象const targetObject = findClickedObject(x, y);if (targetObject && targetObject.type === 'image') {// 选中的图片id保存起来selectImgId.value = targetObject.customId}}
}onMounted(() => {document.addEventListener('click', getImgId);
});

当点击鼠标左键时会获取到图片id并保存在selectImgId变量中,后续需要设置锁定或删除,只需要调用对应的函数传入selectImgId即可。

同时可以通过设置图片对象的索引值更改显示层级,类似cssz-index,这里不过多赘述。

完整示例代码

<template><div class="section" :style="{width: `800px`, height: `500px`}" ref="canvasSectionRef"><canvas ref="canvasRef" width="800" height="500" id="fabricCanvas"></canvas></div>
</template><script setup>
import {onMounted, onUnmounted, ref, watchEffect} from 'vue';
import {fabric} from 'fabric';const canvasSectionRef = ref(null)  // canvas 父元素引用
const canvasRef = ref(null)  // canvas 的引用
let canvas     // 用于保存fabric canvas 对象, 不能用refconst selectImgId = ref() // 保存点击时的图片idwatchEffect(() => {console.log('selectImgId 更改了', selectImgId.value)
})/*** @description 根据 id 在 canvas 对象中查找出对应的图片对象和其索引(索引同时也是显示层级 即 z-index),在callBack中做对应处理* @param id {string} 图片对象的id* @param callBack {(selectedObject: Object, zIndex: number) => any} 查找到对象后的回调* @returns {undefined}*/
const editImageState = (id, callBack) => {const objList = canvas.getObjects()const zIndex = objList.findIndex((obj) => {return obj.customId === id});const selectedObject = objList[zIndex]if (!selectedObject) returncallBack?.(selectedObject, zIndex)
}// 判断元素是否为Canvas元素或其子元素
const isCanvasElement = (element) => {return element instanceof HTMLCanvasElement || element.closest('canvas') !== null;
}/*** @description 查找canvas所有生成的对象(图片)中 点击位置上的对象* @param x {number} 鼠标点击的相对于canvas的 x 坐标* @param y {number} 鼠标点击的相对于canvas的 Y 坐标* @returns {Object|null} 点击处的对象 没有则返回null*/
const findClickedObject = (x, y) => {// 遍历Canvas上的所有对象,判断点击位置是否在对象范围内for (let i = canvas.getObjects().length - 1; i >= 0; i--) {const obj = canvas.item(i);if (obj.containsPoint({x: x, y: y})) {return obj;}}return null;
}const getImgId = (event) => {if (isCanvasElement(event.target)) {// 获取鼠标点击位置相对于 Canvas 元素的坐标const canvasRect = canvasSectionRef.value.getBoundingClientRect();const x = event.clientX - canvasRect.left;const y = event.clientY - canvasRect.top;// 查找点击位置上的对象const targetObject = findClickedObject(x, y);if (targetObject && targetObject.type === 'image') {// 选中的图片id保存起来selectImgId.value = targetObject.customId}}
}/*** @description*  初始化fabric canvas 对象 设置边框颜色 和 四个角控制点的样式*  - 点击时显示蓝色虚线边框*  - 锁定时点击为灰色虚线边框*  - 默认没有选中为透明边框*/
const fabricInit = () => {let selectedObjects = {}; // 使用对象来存储不同图片的选中状态 存储方式为 `key - value` -> `id - boolean`canvas = new fabric.Canvas(canvasRef.value);// 自定义控制点样式fabric.Object.prototype.set({cornerStyle: 'square',cornerColor: '#4191fa',cornerSize: 10,transparentCorners: false,cornerStrokeColor: '#fff',cornerStrokeWidth: 2});// 点击时图片添加边框 不需要可以去除canvas.on('mouse:down', function (options) {// 当前鼠标点击时获取的对象const targetObject = canvas.findTarget(options.e);if (targetObject && targetObject.type === 'image') {// 获取选中图片的id 用于设置边框样式const currentId = targetObject.customId;if (selectedObjects[currentId]) {// 当前点击的图片已经是选中状态,不执行任何操作} else {// 取消显示当前所有图片的边框 (先全部取消 再按id查找当前点击的图片设置为选中)for (const id in selectedObjects) {// 处理取消选中的逻辑if (selectedObjects.hasOwnProperty(id) && selectedObjects[id]) {editImageState(id, (imageItem) => {imageItem.set({stroke: 'transparent',strokeWidth: 2});})}}selectedObjects = {};// 将当前点击的图片设置为选中状态  显示边框selectedObjects[currentId] = true;editImageState(currentId, (imageItem) => {let color = imageItem.selectable ? '#4191fa' : '#ccc'imageItem.set({stroke: color, // 显示边框strokeWidth: 2 // 边框宽度为2});})}} else {// 点击的是画布空白处,清空选中对象for (const id in selectedObjects) {if (selectedObjects.hasOwnProperty(id) && selectedObjects[id]) {editImageState(id, (imageItem) => {imageItem.set({stroke: 'transparent', // 隐藏边框strokeWidth: 2 // 边框宽度为0});})}}selectedObjects = {};}// 处理完成重新渲染 否则不是马上生效canvas.renderAll();});
}// 生成唯一的 ID 用于图片升成
function generateUniqueId() {return 'id_' + +new Date();
}/*** @description 根据url地址在canvas对象中添加图片* @param url {string} 图片地址 在线 or 离线*/
const addImg = (url) => {fabric.Image.fromURL(url, function (img) {img.set({selectable: true, // 禁用选中效果 -> true为不禁用 | false为禁用hasControls: true, // 禁用控制点 -> true为不禁用 | false为禁用borderColor: 'transparent', // 边框颜色strokeDashArray: [5, 5],strokeWidth: 2});// 添加唯一idimg.customId = generateUniqueId();canvas.add(img);});
}onMounted(() => {fabricInit()addImg(new URL('../assets/图片地址.png', import.meta.url).href)document.addEventListener('click', getImgId);
});onUnmounted(() => {canvas = null
})
</script>

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

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

相关文章

模块化原理:source-map

1. webpack打包基本配置 1.安装webpack与webpack-cli npm i webpack webpack-cli 2.配置 "build":"webpack" 3. 新建webpack.config.js const path require(path); module.exports {// mode: "development",// 默认production&#xff08;什么…

微信小程序的项目解构

视频链接 黑马程序员前端微信小程序开发教程&#xff0c;微信小程序从基础到发布全流程_企业级商城实战(含uni-app项目多端部署)_哔哩哔哩_bilibili 接口文档 https://www.escook.cn/docs-uni-shop/mds/1.start.html 1&#xff1a;微信小程序宿主环境 1&#xff1a;常见的宿…

鉴源实验室丨汽车网络安全攻击实例解析(二)

作者 | 田铮 上海控安可信软件创新研究院项目经理 来源 | 鉴源实验室 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” 引言&#xff1a;汽车信息安全事件频发使得汽车行业安全态势愈发紧张。这些汽车网络安全攻击事件&#xff0c;轻则给企业产品发布及产品…

docker菜谱

DockerHub&#xff1a;https://hub.docker.com/ 记录docker常用软件安装&#xff0c;欢迎大家来投稿。&#x1f60e;&#x1f60e;&#x1f60e; 文章目录 1. Redis2. MariaDB 1. Redis dockerhub:https://hub.docker.com/_/redis 1、下载redis镜像&#xff1a; docker pull r…

阿里云二级域名配置

阿里云二级域名配置 首先需要进入阿里云控制台的域名管理 1.选择域名点击解析 2.添加记录 3.选择A类型 4.主机记录设置【可以aa.bb或者aa.bb.cc】 到时候会变成&#xff1a;aa.bb.***.com 5.解析请求来源设置为默认 6.记录值 设置为要解析的服务器的ip地址 7.TTL 默认即…

kube-prometheus 使用blackbox进行icmp 监控

安装kube-prometheus 后默认在monitoring namespace中有创建 blackbox-exporter deployment。但默认没有icmp的module配置&#xff0c;无法执行ping探测。因为即使有icmp module&#xff0c;默认配置也是无法执行ping探测的&#xff08;这篇文章要解决的就是这个问题&#xff0…

Linux ARM64架构 动态替换 altinstructions

文章目录 简介一、altinstructions节1.1 .altinstructions1.2 .rela.altinstructions 二、内核模块重定位源码分析参考资料 简介 在内核开发中&#xff0c;有时需要对内核代码进行修补&#xff0c;以解决bug、优化性能或引入新功能。替代指令&#xff08;altinstructions&…

web集群学习--基于CentOS构建LVS-DR集群、配置nginx负载均衡

基于CentOS构建LVS-DR集群 环境准备 主机名 ip地址 node1 192.168.1.140 client node2 192.168.1.141 LVS node3 192.168.1.142 RS1 node4 192.168.1.143 RS2配置 1.关闭防火墙和SELinux [rootclient~]# systemctl stop firewalld [rootclient~]# systemctl disabl…

K最近邻算法:简单高效的分类和回归方法(三)

文章目录 &#x1f340;引言&#x1f340;训练集和测试集&#x1f340;sklearn中封装好的train_test_split&#x1f340;超参数 &#x1f340;引言 本节以KNN算法为主&#xff0c;简单介绍一下训练集和测试集、超参数 &#x1f340;训练集和测试集 训练集和测试集是机器学习和深…

一文了解 Android Auto 车载开发~

作者&#xff1a;牛蛙点点申请出战 背景 我的的产品作为一个海外音乐播放器&#xff0c;在车载场景听歌是一个很普遍的需求。在用户反馈中&#xff0c;也有很多用户提到希望能在车上播放音乐。同时车载音乐也可以作为提升用户消费时长一个抓手。 出海产品&#xff0c;主要服务…

初中信息技术考试编程题,初中信息技术python教案

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;初中信息技术python编程题库 网盘&#xff0c;初中信息技术python编程教学&#xff0c;今天让我们一起来看看吧&#xff01; ID:12450455 资源大小&#xff1a;934KB 资料简介: 2019-2020学年初中信息技术【轻松备课】P…

svg使用技巧

什么是svg SVG 是一种基于 XML 语法的图像格式&#xff0c;全称是可缩放矢量图&#xff08;Scalable Vector Graphics&#xff09;。其他图像格式都是基于像素处理的&#xff0c;SVG 则是属于对图像的形状描述&#xff0c;所以它本质上是文本文件&#xff0c;体积较小&#xf…