Fabric 画布缩放、拖动、初始化大小
2023-12-13 05:39:38
作为自己项目的基础功能之一,自然是需要第一个回顾记录的了!
1.拖动画布
2.缩放画布
3.监听窗口大小变化,从而初始化画布位置、大小
涉及相关API:键盘快捷键功能、滚轮功能、监听窗口变化、fabric.js相关事件及API;
示例说明:
- 拖动画布:按住空格键,然后点击鼠标左键拖动画布;(在操作过程中,需要处理fabric.js图形的相关控制项,避免影响拖动操作!)
- 缩放画布:以鼠标当前位置为中心,进行画布内容的整体缩放;
- 初始化大小:设定一个舞台与画布之间的大小比例,当窗口大小变化时,对舞台进行居中且缩放至自己所设定的比例大小!
以下代码仅作为功能的完整示例;未进行相关模块划分、封装,实际开发中自行处理这些即可!
<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 = true
setDragState(false)
f.selection = false;
f.defaultCursor = 'grab';
f.setCursor('grab');
} else {
drag = false
isDragMode = false
setDragState(true)
f.selection = true;
f.defaultCursor = 'default';
f.setCursor('default');
}
event.preventDefault();
});
}
let canvas = ref();
window.fabric = fabric
onMounted(() => {
const stageWidth = 400
const stageHeight = 300
window.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 newZoom
if (e.deltaY < 0) {
// console.log('放大');
newZoom = oldZoom * 1.1
newZoom > 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 = false
if (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>
文章来源:https://blog.csdn.net/lijiahui_/article/details/134823651
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!