当前位置: 首页 > news >正文

Fabric 画布缩放、拖动、初始化大小

作为自己项目的基础功能之一,自然是需要第一个回顾记录的了!

1.拖动画布
2.缩放画布
3.监听窗口大小变化,从而初始化画布位置、大小


涉及相关API:键盘快捷键功能、滚轮功能、监听窗口变化、fabric.js相关事件及API;

示例说明:

  1. 拖动画布:按住空格键,然后点击鼠标左键拖动画布;(在操作过程中,需要处理fabric.js图形的相关控制项,避免影响拖动操作!)
  2. 缩放画布:以鼠标当前位置为中心,进行画布内容的整体缩放;
  3. 初始化大小:设定一个舞台与画布之间的大小比例,当窗口大小变化时,对舞台进行居中且缩放至自己所设定的比例大小!

以下代码仅作为功能的完整示例;未进行相关模块划分、封装,实际开发中自行处理这些即可!

<template><div class="cdie" id="cdie"><canvas id="c" ref="canvas"></canvas></div>
</template><script setup lang="ts">
import { ref, onMounted, reactive } from "vue";
import { fabric } from "fabric";
import hotkeys from 'hotkeys-js';
let isDragMode = false
let f = null
function getAllValidObjects() {const objs = f.getObjects().filter(e => !e.death)return objs;
}
function setDragState(selectable) {const alls = getAllValidObjects();alls?.forEach((selection) => {selection.selectable = selectable;selection.evented = selectable;// 禁掉图形事件,避免hover时覆盖鼠标样式});
}
function initHotkey() {hotkeys('space', {keydown: true,keyup: true,}, (event, handler) => {if (event.type === 'keydown') {f.discardActiveObject();isDragMode = truesetDragState(false)f.selection = false;f.defaultCursor = 'grab';f.setCursor('grab');} else {drag = falseisDragMode = falsesetDragState(true)f.selection = true;f.defaultCursor = 'default';f.setCursor('default');}event.preventDefault();});
}
let canvas = ref();
window.fabric = fabric
onMounted(() => {const stageWidth = 400const stageHeight = 300window.canvas = f = new fabric.Canvas(canvas.value, {backgroundColor: "grey",minZoom: 0.5, // 最小缩放比例maxZoom: 10, // 最大缩放比例width: 1000,height: 500,});function resize() {f.setWidth(canvas.value.clientWidth);f.setHeight(canvas.value.clientHeight);const canvasW = f.getWidth();const canvasH = f.getHeight();const screenRatio = stageWidth / stageHeight; // 计算舞台的宽高比const sreenW = canvasW * 0.8; // 计算舞台将要缩放至最大的宽高值const sreenH = canvasH * 0.8;const ratioW = sreenW / stageWidth; // 计算对应最大宽高值与舞台对应宽高值的比例const ratioH = sreenH / stageHeight;let absoluteP: fabric.Point;let ratio; // 哪个边放大的比例小,就取哪个边的比例,例如高度只需要1.333倍就能达到对应边的80%,则宽度同样放大1.333倍即可。if (ratioW < ratioH) { absoluteP = new fabric.Point(-(canvasW - sreenW) / 2, -(canvasH - sreenW / screenRatio) / 2);ratio = ratioW;} else {// absoluteP = new fabric.Point(-(canvasW - sreenH * screenRatio) / 2, -(canvasH - sreenH) / 2); absoluteP = new fabric.Point(-(canvasW - stageWidth * ratioH) / 2, -(canvasH - sreenH) / 2); // 这种计算规则更容易理解点。。。ratio = ratioH;}// absoluteP = new fabric.Point(0,0)f.setZoom(ratio); // 设置画布的缩放比例,根据画布元素的左上角为参考点进行缩放的; 此案例为舞台长的那边等比缩放至画布对应边的 80% 大小时的比例。f.absolutePan(absoluteP); // 平移视口,根据画布元素左上角作为参考点进行平移,负数xy就是向右下平移。}window.addEventListener('resize', resize);f.upperCanvasEl.addEventListener('wheel', function (e: WheelEvent) {const point = f.getPointer(e, true);const oldZoom = f.getZoom();let newZoomif (e.deltaY < 0) {// console.log('放大');newZoom = oldZoom * 1.1newZoom > f.maxZoom && (newZoom = f.maxZoom)} else {// console.log('缩小');newZoom = oldZoom / 1.1;newZoom < f.minZoom && (newZoom = f.minZoom)}f.zoomToPoint(point, newZoom); // 基于画布html元素的左上角的相对坐标进行缩放。e.preventDefault();});initHotkey()setInterval(() => {f.renderAll(); // 懒得在测试代码renderAll, 统一这里处理了;}, 1)// 解决矢量图放大过程中模糊 ; 缓存相关,性能好坏影响程度暂不确定;fabric.Object.prototype.objectCaching = false;// fabric.Object.prototype.originX = fabric.Object.prototype.originY = "center";const stage = new fabric.Rect({ // 创建舞台,还可给舞台添加网格,便于用户参考坐标位置等。left: 0,top: 0,width: stageWidth,height: stageHeight,fill: '#30b980',stroke: 'red',strokeWidth: 0,strokeUniform: true,selectable: false,evented: false,death: true // 随便声明个变量,表示该图形为非活动图形;});f.add(stage);const relativeP = new fabric.Point((1000 - stageWidth) / 2,(500 - stageHeight) / 2,);f.relativePan(relativeP);// 相对当前位置进行视点平移 > 将舞台移动至居中;后续新图形的起始点也从该点位开始。let line = new fabric.Line([0, 0, 100, 100], {stroke: "blue",});f.add(line);let line2 = new fabric.Line([220, 220, 311, 311], {stroke: "red",});f.add(line2);initEvent(f)resize()
});
let drag = false
function initEvent(canvas) {canvas.on('mouse:down', (IEvent) => {// console.log(IEvent);// IEvent.absolutePointer 是鼠标点击的相对于起始点的偏移坐标。// IEvent.pointer 是相对于fabric画布左上角的偏移坐标。window.selected = IEvent?.target // 当点击选择到有可选图形时,会获得图形的数据。if (isDragMode) {drag = true}}).on('mouse:up', (e) => {drag = falseif (isDragMode) {f.defaultCursor = 'grab';f.setCursor('grab');}}).on('mouse:move', (IEvent: fabric.IEvent<MouseEvent>) => {if (isDragMode) {if (drag) {f.defaultCursor = 'grab';f.setCursor('grab');const { e } = IEvent// console.log(e.movementX, e.movementY); // 表示鼠标相对于上一次触发鼠标事件时的移动距离。const point = new fabric.Point(e.movementX, e.movementY);f.relativePan(point);}}}).on('mouse:dblclick', (e) => {})
}</script><style scoped lang="less">.cdie {width: 100%;text-align: center;display: flex;justify-content: center;
}
</style>

相关文章:

  • kubernetes的服务发现(二)
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • 【S32DS报错】-3-提示J-Link GDB Server failed:Device name ‘S32K344‘ not recognised错误
  • 【CSP】202303-2_垦田计划Python实现
  • 图论——最小生成树
  • 黑马头条数据管理平台项目总结
  • Gateway:微服务架构中的关键组件
  • IntelliJ idea卡顿解决,我遇到的比较管用的方案
  • MindOpt APL:一款适合优化问题数学建模的编程语言
  • 集简云 x 零售企业丨快速集成有赞商城和微盛企微管家,实现私域运营自动化
  • Vue2学习(组件的使用)
  • 如何选择合适的运筹优化求解器?
  • JPA对数据库修改注意点
  • 界面控件DevExpress中文教程 - 如何用Office File API组件填充PDF表单
  • chrome安装jsonview
  • 3.7、@ResponseBody 和 @RestController
  • C# 免费离线人脸识别 2.0 Demo
  • Docker: 容器互访的三种方式
  • HTTP请求重发
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • Linux快速复制或删除大量小文件
  • Material Design
  • PHP CLI应用的调试原理
  • Swift 中的尾递归和蹦床
  • WebSocket使用
  • windows下mongoDB的环境配置
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 工作中总结前端开发流程--vue项目
  • 手机app有了短信验证码还有没必要有图片验证码?
  • 做一名精致的JavaScripter 01:JavaScript简介
  • Unity3D - 异步加载游戏场景与异步加载游戏资源进度条 ...
  • ​一帧图像的Android之旅 :应用的首个绘制请求
  • $.ajax()方法详解
  • (04)odoo视图操作
  • (1)Nginx简介和安装教程
  • (6)【Python/机器学习/深度学习】Machine-Learning模型与算法应用—使用Adaboost建模及工作环境下的数据分析整理
  • (深度全面解析)ChatGPT的重大更新给创业者带来了哪些红利机会
  • (四)Controller接口控制器详解(三)
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • .chm格式文件如何阅读
  • .NET CORE 2.0发布后没有 VIEWS视图页面文件
  • .NET 表达式计算:Expression Evaluator
  • .Net的DataSet直接与SQL2005交互
  • .Net多线程总结
  • /usr/bin/python: can't decompress data; zlib not available 的异常处理
  • /var/log/cvslog 太大
  • @取消转义
  • [23] 4K4D: Real-Time 4D View Synthesis at 4K Resolution
  • [BUG] Authentication Error
  • [C# WPF] DataGrid选中行或选中单元格的背景和字体颜色修改
  • [C++] new和delete
  • [CentOs7]iptables防火墙安装与设置
  • [elastic 8.x]java客户端连接elasticsearch与操作索引与文档
  • [IE6 only]关于Flash/Flex,返回数据产生流错误Error #2032的解决方式