docs: 添加文章内容(2013 ~ 2023)
This commit is contained in:
675
docs/content/canvas-library-fabric-js.md
Normal file
675
docs/content/canvas-library-fabric-js.md
Normal file
@@ -0,0 +1,675 @@
|
||||
---
|
||||
title: Fabric.js 简单介绍和使用
|
||||
date: 2025-03-15T22:51:22Z
|
||||
lastmod: 2025-03-15T22:55:55Z
|
||||
tags: [Web 前端,JavaScript,Canvas,Fabric.js]
|
||||
---
|
||||
|
||||
# Fabric.js 简单介绍和使用
|
||||
|
||||
## 参考资料
|
||||
|
||||
- [Fabric.js JSDoc](http://fabricjs.com/docs/)
|
||||
- [Fabric.js Demos - Event inspector](http://fabricjs.com/events)
|
||||
- [Fabric.js 从入门到________](https://juejin.cn/post/7026941253845516324)
|
||||
- [Fabric.js 实用指南](https://blackstarxing.github.io/2019-08-17-fabric-doc.html)
|
||||
|
||||
## 简介
|
||||
|
||||
Fabric.js 是一个功能强大的 Canvas 库,它在原生 Canvas 之上提供了交互式对象模型、多种易用的 API 和 SVG 解析器等,通过简洁的 API 就可以在画布上进行丰富的操作,并且支持多种的事件方法。
|
||||
|
||||
注:本文中使用的 Fabric.js 版本为 v5。
|
||||
|
||||
## 常用的对象、属性和方法
|
||||
|
||||
### 常用对象
|
||||
|
||||
|名称|描述|
|
||||
| ------| ------------------------------|
|
||||
|`ActiveSelection`|选区|
|
||||
|`Group`|分组|
|
||||
|`Image`|图像|
|
||||
|`Line`|线段|
|
||||
|`Rect`|矩形|
|
||||
|`Text`|文本(不可编辑,不换行)|
|
||||
|`IText`|可编辑文本(可编辑,不换行)|
|
||||
|`Textbox`|文本框(可编辑,自动换行)|
|
||||
|
||||
### 常用属性
|
||||
|
||||
|属性|描述|
|
||||
| ------| ---------------------------------------------|
|
||||
|`type`|对象类型|
|
||||
|`data`|用于添加自定义的数据|
|
||||
|`originX`|对象转换的水平原点(left / center / right)|
|
||||
|`originY`|对象转换的垂直原点(top / center / bottom)|
|
||||
|`left`|水平坐标|
|
||||
|`top`|垂直坐标|
|
||||
|`width`|宽度|
|
||||
|`height`|高度|
|
||||
|`angle`|旋转角度|
|
||||
|`scaleX`|水平方向缩放倍数|
|
||||
|`scaleY`|垂直方向缩放倍数|
|
||||
|`stroke`|线段颜色|
|
||||
|`strokeWidth`|线段宽度|
|
||||
|`fill`|填充颜色|
|
||||
|`fontFamily`|文本字体名称|
|
||||
|`fontSize`|文本字体大小|
|
||||
|`opacity`|对象的不透明度|
|
||||
|`borderColor`|选区边框颜色|
|
||||
|`borderDashArray`|选区边框虚线样式|
|
||||
|`borderOpacityWhenMoving`|选区拖拽时的边框透明度|
|
||||
|`cornerColor`|选区 “操作点” 填充颜色|
|
||||
|`cornerSize`|选区 “操作点” 大小|
|
||||
|`cornerStrokeColor`|选区 “操作点” 描边颜色|
|
||||
|`cornerStyle`|选区 “操作点” 样式(circle / rect)|
|
||||
|`transparentCorners`|选区 “操作点” 中心是否透明(只有描边)|
|
||||
|`hasControls`|是否有 “操作点”|
|
||||
|`lockRotation`|是否禁止旋转对象|
|
||||
|`lockMovementX`|是否禁止水平移动对象|
|
||||
|`lockMovementY`|是否禁止垂直移动对象|
|
||||
|`lockScaleX`|是否禁止水平缩放对象|
|
||||
|`lockScaleY`|是否禁止垂直缩放对象|
|
||||
|`selectable`|是否可以被选中|
|
||||
|`hoverCursor`|光标在对象上方时的样式(子对象优先)|
|
||||
|`moveCursor`|光标在可移动对象上方时的样式(子对象优先)|
|
||||
|
||||
### 常用方法
|
||||
|
||||
#### 画布(Canvas)
|
||||
|
||||
|方法|描述|
|
||||
| ------| ------------------------------------|
|
||||
|`add(...object)`|添加对象到画布|
|
||||
|`insertAt(object, index, nonSplicing)`|添加对象到画布指定层级|
|
||||
|`moveTo(object, index)`|更改对象所在的层级|
|
||||
|`remove(...object)`|移除画布上的对象|
|
||||
|`discardActiveObject()`|取消选中对象|
|
||||
|`getActiveObject()`|获取选中的对象|
|
||||
|`setActiveObject()`|更改选中的对象|
|
||||
|`getPointer()`|传递事件对象,获取相对于画布的坐标|
|
||||
|`fire()`|触发画布事件|
|
||||
|`forEachObject()`|遍历画布上的对象|
|
||||
|`getZoom()`|获取画布缩放比例|
|
||||
|`setZoom()`|设置画布缩放比例|
|
||||
|`on()`|监听画布事件|
|
||||
|`requestRenderAll()`|刷新画布|
|
||||
|`set()`|设置画布属性|
|
||||
|
||||
#### 对象(Object)
|
||||
|
||||
|方法|描述|
|
||||
| ------| ------------------------------|
|
||||
|`bringToFront()`|改变对象层级,置顶|
|
||||
|`bringForward()`|改变对象层级,上移|
|
||||
|`sendBackwards()`|改变对象层级,下移|
|
||||
|`sendToBack()`|改变对象层级,置底|
|
||||
|`intersectsWithObject()`|检测两个对象是否相交(重叠)|
|
||||
|`isContainedWithinObject()`|检测对象是在另外一个对象内|
|
||||
|`on()`|监听对象事件|
|
||||
|`set()`|设置对象属性|
|
||||
|`toDataURL()`|转换为 Base64|
|
||||
|
||||
## 创建对象
|
||||
|
||||
### 画布
|
||||
|
||||
```javascript
|
||||
let canvas = new fabric.Canvas({
|
||||
// 画布宽度
|
||||
width: 800,
|
||||
// 画布高度
|
||||
height: 480,
|
||||
// 背景颜色
|
||||
backgroundColor: '#FFFFFF',
|
||||
// 激活对象时不将对象置顶
|
||||
preserveObjectStacking: true,
|
||||
// 选区框样式
|
||||
selectionBorderColor: '#4CAF50',
|
||||
selectionColor: '#4CAF5040',
|
||||
selectionFullyContained: true,
|
||||
selectionLineWidth: 1,
|
||||
// 关闭按比例缩放
|
||||
uniformScaling: false,
|
||||
// 其他配置选项
|
||||
...
|
||||
});
|
||||
```
|
||||
|
||||
### 矩形
|
||||
|
||||
```javascript
|
||||
// 创建对象
|
||||
let el = new fabric.Rect({
|
||||
left: 100, // 相对于画布左侧的距离
|
||||
top: 100, // 相对于画布顶部的距离
|
||||
width: 200, // 对象宽度 100px
|
||||
height: 100, // 对象高度 100px
|
||||
fill: '#FFFFFF', // 填充颜色
|
||||
stroke: '#1E88E5', // 边框颜色
|
||||
strokeWidth: 2, // 边框粗细
|
||||
});
|
||||
// 添加对象
|
||||
canvas.add(el);
|
||||
```
|
||||
|
||||
### 线段
|
||||
|
||||
```javascript
|
||||
// 创建对象
|
||||
let el = new fabric.Line([
|
||||
100, 100, // 起始点坐标
|
||||
200, 100, // 结束点坐标
|
||||
], {
|
||||
stroke: '#1E88E5', // 线段颜色
|
||||
strokeWidth: 2, // 线段粗细
|
||||
});
|
||||
// 添加对象
|
||||
canvas.add(el);
|
||||
```
|
||||
|
||||
```javascript
|
||||
// 创建对象
|
||||
let el = new fabric.Line([], {
|
||||
stroke: '#1E88E5',
|
||||
strokeWidth: 2,
|
||||
});
|
||||
// 设置位置和长度
|
||||
el.set({
|
||||
left: 100,
|
||||
top: 100,
|
||||
width: 100,
|
||||
// 注:因为是线段,高度为 0
|
||||
height: 0,
|
||||
});
|
||||
// 添加对象
|
||||
canvas.add(el);
|
||||
```
|
||||
|
||||
### 图片
|
||||
|
||||
```javascript
|
||||
let img = new Image();
|
||||
|
||||
// 监听图片加载,加载完成后再添加对象
|
||||
img.onload = function() {
|
||||
// 创建对象
|
||||
let el = new fabric.Image(img, {
|
||||
top: 100,
|
||||
left: 100,
|
||||
width: 200,
|
||||
height: 150,
|
||||
});
|
||||
// 添加对象
|
||||
canvas.add(el);
|
||||
};
|
||||
// 设置 crossorigin 属性,开启 CORS 校验
|
||||
// 若不设置,无法将画布或画布上的对象导出为图片。
|
||||
// 值设置为 anonymous,表示对此元素的 CORS 请求将不设置凭据标志。
|
||||
img.setAttribute('crossorigin', 'anonymous');
|
||||
// 设置图片地址
|
||||
img.setAttribute('src', 'http://fabricjs.com/assets/69.svg');
|
||||
```
|
||||
|
||||
### 文本框
|
||||
|
||||
```javascript
|
||||
// 创建对象
|
||||
let el = new fabric.Textbox('文本内容', {
|
||||
top: 100,
|
||||
left: 100,
|
||||
// 设置宽度后,文本内容超出宽度后会自动换行。
|
||||
// 注意:文本只会在空格处自动换行。
|
||||
// 高度为自适应,不需要设置。
|
||||
width: 200,
|
||||
});
|
||||
// 添加对象
|
||||
canvas.add(el);
|
||||
```
|
||||
|
||||
## 场景和实现方法
|
||||
|
||||
### 画布内容撤销、恢复
|
||||
|
||||
主要通过 Fabric.js 画布对象的 `toObject()` 和 `loadFromJSON()` 方法实现。
|
||||
|
||||
为了提高性能,默认情况下 `toObject()` 只会导出对象上**常用**的属性,其他属性(例如 `data`、`selectable`)不会被导出,需要手动在其 `propertiesToInclude` 参数中指定(例如 `canvas.toObject(['data', 'selectable'])`)。
|
||||
|
||||
### 画布内容导出为图片
|
||||
|
||||
将画布(显示区域)或对象导出为图片:
|
||||
|
||||
```javascript
|
||||
toDataURL(options)
|
||||
```
|
||||
|
||||
参数:options(可选)
|
||||
|
||||
|属性名|数据类型|默认值|简介|
|
||||
| ---------------------| ----------| --------| -----------------------------------------|
|
||||
|format|String|png|导出图片的格式,可选值:jpeg、png|
|
||||
|quality|Number|1|图片质量(0 \~ 1),仅 jpeg 格式可用|
|
||||
|multiplier|Number|1|缩放比例|
|
||||
|left|Number||裁剪左偏移量(1.2.14+)|
|
||||
|top|Number||裁剪上偏移量(1.2.14+)|
|
||||
|width|Number||裁剪宽度(1.2.14+)|
|
||||
|height|Number||裁剪高度(1.2.14+)|
|
||||
|enableRetinaScaling|Boolean||为克隆图像启用 Retina 缩放(2.0.0+)|
|
||||
|
||||
用法示例:
|
||||
|
||||
```javascript
|
||||
let dataURL = canvas.toDataURL({
|
||||
format: 'jpeg',
|
||||
quality: 0.8,
|
||||
});
|
||||
```
|
||||
|
||||
```javascript
|
||||
let dataURL = rect.toDataURL({
|
||||
format: 'png',
|
||||
});
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
若导出的对象中包含使用 URL(非 DataURL)加载的图片对象,需要使用 `crossOrigin` 属性解决资源跨域问题,否则会出现以下错误提示:
|
||||
|
||||
```plaintext
|
||||
The canvas has been tainted by cross-origin data.
|
||||
```
|
||||
|
||||
其中一种解决方式是先使用 `new Image()` 设置 `crossorigin` 属性,加载图片,再创建 `fabric.Image` 对象(参考 “创建对象 - 图片”)。
|
||||
|
||||
### 画布自适应父 DOM 元素宽高
|
||||
|
||||
#### 方案一:监听浏览器窗口大小变化事件
|
||||
|
||||
```javascript
|
||||
// 父元素(DOM)
|
||||
let el = vm.$el;
|
||||
// 画布对象
|
||||
let canvas = vm.canvasInstance;
|
||||
// 防抖定时器
|
||||
let debounce = null;
|
||||
|
||||
// 事件处理函数
|
||||
const handler = function () {
|
||||
clearTimeout(debounce);
|
||||
debounce = setTimeout(() => {
|
||||
if (canvas) {
|
||||
// 设置宽高
|
||||
canvas.setWidth(el.clientWidth);
|
||||
canvas.setHeight(el.clientHeight);
|
||||
// 刷新画布(正常情况下设置宽高后会自动刷新)
|
||||
// canvas.requestRenderAll();
|
||||
} else {
|
||||
console.error('处理失败,画布对象不存在!');
|
||||
}
|
||||
}, 500);
|
||||
};
|
||||
|
||||
// 添加事件监听
|
||||
window.addEventListener('resize', handler);
|
||||
|
||||
// 移除事件监听
|
||||
window.removeEventListener('resize', handler);
|
||||
clearTimeout(debounce);
|
||||
```
|
||||
|
||||
#### 方案二:使用 ResizeObserver 监听 DOM 元素大小更改
|
||||
|
||||
参考资料:[ResizeObserver - Web API 接口参考 | MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserver)
|
||||
|
||||
方案优点:在窗口大小不变化的情况下也能实现自适应
|
||||
|
||||
```javascript
|
||||
// 父元素(DOM)
|
||||
let el = vm.$el;
|
||||
// 画布对象
|
||||
let canvas = vm.canvasInstance;
|
||||
// 防抖定时器
|
||||
let debounce = null;
|
||||
|
||||
/**
|
||||
* @desc 观察器回调函数
|
||||
* @type {ResizeObserverCallback}
|
||||
*/
|
||||
const handler = function (entries) {
|
||||
clearTimeout(debounce);
|
||||
debounce = setTimeout(() => {
|
||||
const entry = entries[0];
|
||||
|
||||
if (canvas && entry) {
|
||||
const { width, height } = entry.contentRect;
|
||||
// 设置宽高
|
||||
canvas.setWidth(width);
|
||||
canvas.setHeight(height);
|
||||
// 刷新画布(正常情况下设置宽高后会自动刷新)
|
||||
// canvas.requestRenderAll();
|
||||
} else {
|
||||
console.error('处理失败,Canvas 或 ResizeObserverEntry 不存在!');
|
||||
}
|
||||
}, 500);
|
||||
};
|
||||
|
||||
/**
|
||||
* @desc 观察器配置选项
|
||||
* @type {ResizeObserverOptions}
|
||||
*/
|
||||
const options = {
|
||||
// 设置观察器以哪种盒子模型来观察变化
|
||||
// 可选值:content-box(默认)、border-box、device-pixel-content-box
|
||||
box: 'border-box',
|
||||
};
|
||||
|
||||
// 创建观察器,并传递回调函数
|
||||
const observer = new ResizeObserver(handler);
|
||||
|
||||
// 传递配置选项
|
||||
observer.observe(el, options);
|
||||
|
||||
// 停止观察器
|
||||
observer.disconnect();
|
||||
clearTimeout(debounce);
|
||||
```
|
||||
|
||||
### 解决画布缩放后,对象显示模糊
|
||||
|
||||
把对象的 `objectCaching` 属性设置为 `false`,关闭缓存即可。
|
||||
|
||||
例如:
|
||||
|
||||
```javascript
|
||||
const rect = new fabric.Rect({
|
||||
left: 100,
|
||||
top: 100,
|
||||
width: 200,
|
||||
height: 200,
|
||||
fill: '#FFFFFF',
|
||||
stroke: '#66CCFF',
|
||||
strokeWidth: 2,
|
||||
objectCaching: false,
|
||||
});
|
||||
|
||||
canvas.add(rect);
|
||||
```
|
||||
|
||||
注意:不建议大量使用,以免影响性能。
|
||||
|
||||
### 实现对象溢出隐藏(裁剪)效果
|
||||
|
||||
主要用到了 `clipPath` 功能,设置对象的裁剪路径。
|
||||
|
||||
```javascript
|
||||
// 创建用于作为“容器”的对象
|
||||
const container = new fabric.Rect({
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 800,
|
||||
height: 480,
|
||||
fill: '#FFFFFF',
|
||||
stroke: '#000000',
|
||||
strokeWidth: 2,
|
||||
// 将该属性设置为 true 后,裁剪的区域会动态更新
|
||||
absolutePositioned: true,
|
||||
});
|
||||
|
||||
// 创建子对象
|
||||
const item = new fabric.Rect({
|
||||
left: 100,
|
||||
top: 100,
|
||||
width: 200,
|
||||
height: 100,
|
||||
fill: '#FFFFFF',
|
||||
stroke: '#66CCFF',
|
||||
strokeWidth: 2,
|
||||
// 将 container 对象设为该对象的 clipPath
|
||||
clipPath: container,
|
||||
});
|
||||
```
|
||||
|
||||
**关于** **`absolutePositioned`** **属性:**
|
||||
|
||||
仅当对象作为 `clipPath` 使用时才有意义。如果为 `true`,`clipPath` 的位置将会相对于画布,且不受对象变换影响。([JSDoc: Class: Object#absolutePositioned](http://fabricjs.com/docs/fabric.Object.html#absolutePositioned))
|
||||
|
||||
**注意:**
|
||||
|
||||
后续通过 `.set()` 更新对象的 `clipPath` 属性时,建议同时将其 `dirty` 属性设置为 `true`,以便清除缓存,防止裁剪区域没有更新。([JSDoc: Class: Object#dirty](http://fabricjs.com/docs/fabric.Object.html#dirty))
|
||||
|
||||
```javascript
|
||||
item.set({ clipPath: null, dirty: true });
|
||||
```
|
||||
|
||||
### 鼠标滚轮缩放画布
|
||||
|
||||
主要用到了画布的鼠标事件(`mouse:wheel`)以及调用画布的 `zoomToPoint()` 方法改变视图缩放。
|
||||
|
||||
```javascript
|
||||
// 监听事件:鼠标滚轮
|
||||
canvas.on('mouse:wheel', function (ev) {
|
||||
|
||||
const evt = ev.e;
|
||||
const cursorX = evt.offsetX;
|
||||
const cursorY = evt.offsetY;
|
||||
|
||||
// 若按下 Ctrl 键,则为缩放
|
||||
if (evt.ctrlKey) {
|
||||
evt.preventDefault();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// 若按下 Alt 键,则为重置缩放
|
||||
if (evt.altKey) {
|
||||
canvas.zoomToPoint({
|
||||
x: cursorX,
|
||||
y: cursorY,
|
||||
}, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
// 正数:向下滚动
|
||||
// 负数:向上滚动
|
||||
const delta = evt.deltaY;
|
||||
|
||||
// 画布当前缩放值
|
||||
let zoom = canvas.getZoom();
|
||||
let min = 0.1;
|
||||
let max = 10;
|
||||
|
||||
zoom += zoom * (delta > 0 ? -0.2 : 0.2);
|
||||
|
||||
// 限制缩放范围
|
||||
(zoom < min) && (zoom = min);
|
||||
(zoom > max) && (zoom = max);
|
||||
|
||||
// 设置画布缩放比例
|
||||
// 参数1:将画布的缩放点设置为鼠标当前位置
|
||||
// 参数2:传入缩放值
|
||||
canvas.zoomToPoint({
|
||||
x: cursorX,
|
||||
y: cursorY,
|
||||
}, zoom);
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
### 鼠标拖拽移动画布
|
||||
|
||||
主要用到了画布的鼠标事件(`mouse:down`、`mouse:move` 和 `mouse:up`)以及调用画布的 `setViewportTransform()` 方法改变视图偏移量。
|
||||
|
||||
注意:在拖拽前,若鼠标选中了对象,需要将对象的 `lockMovementX` 和 `lockMovementY` 属性设置为 `true`,锁定对象的移动,否则拖拽后对象的位置会变化。
|
||||
|
||||
```javascript
|
||||
// 监听事件:鼠标按下
|
||||
canvas.on('mouse:down', function ({ e: evt, target }) {
|
||||
|
||||
// 仅在按下了 Ctrl 键时为拖拽画布
|
||||
if (!evt.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (target) {
|
||||
if (target.lockMovementX || target.lockMovementY) {
|
||||
// 记录原始锁定状态
|
||||
target.isLock = true;
|
||||
} else {
|
||||
// 记录原始锁定状态
|
||||
target.isLock = false;
|
||||
// 锁定对象的移动
|
||||
target.set({
|
||||
lockMovementX: true,
|
||||
lockMovementY: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
canvas.set({
|
||||
// 关闭选区框
|
||||
selection: false,
|
||||
// 自定义属性,标记拖拽状态
|
||||
isDragCanvas: true,
|
||||
// 自定义属性,记录起始位置
|
||||
startPosX: evt.clientX,
|
||||
startPosY: evt.clientY,
|
||||
startVpt: [...canvas.viewportTransform],
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// 监听事件:鼠标移动
|
||||
canvas.on('mouse:move', function (ev) {
|
||||
// 检测是否为拖拽画布模式
|
||||
if (canvas.isDragCanvas) {
|
||||
const evt = ev.e;
|
||||
const vptOld = canvas.startVpt;
|
||||
const vptNew = [...vptOld];
|
||||
|
||||
// 计算新的偏移量
|
||||
vptNew[4] += (evt.clientX - canvas.startPosX);
|
||||
vptNew[5] += (evt.clientY - canvas.startPosY);
|
||||
|
||||
// 更新视图偏移量
|
||||
canvas.setViewportTransform(vptNew);
|
||||
}
|
||||
});
|
||||
|
||||
// 监听事件:鼠标松开
|
||||
canvas.on('mouse:up', function ({ target }) {
|
||||
// 解锁对象的移动(如果可以)
|
||||
if (target && !target.isLock) {
|
||||
target.set({
|
||||
lockMovementX: false,
|
||||
lockMovementY: false,
|
||||
});
|
||||
}
|
||||
// 更新画布属性
|
||||
canvas.set({
|
||||
// 开启选区框
|
||||
selection: true,
|
||||
// 自定义属性,标记拖拽状态
|
||||
isDragCanvas: false,
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### 鼠标事件中获取分组(Group)内的目标对象
|
||||
|
||||
默认情况下,对于分组,`ev.target` 只能获取到整个分组,并不能具体到其中的对象。
|
||||
|
||||
在创建分组时,将 `subTargetCheck` 属性设置为 `true`,即可通过 `ev.subTargets` 获取触发事件时的子对象。
|
||||
|
||||
对于支持该功能的事件(`mouse:down`、`mouse:up`、`mouse:move` 等),该属性为 `fabric.Object` 数组;
|
||||
|
||||
对于不支持该功能的事件,该属性为 `undefined`。
|
||||
|
||||
例如:
|
||||
|
||||
```javascript
|
||||
const group = new fabric.Group([obj1, obj2], {
|
||||
subTargetCheck: true,
|
||||
...
|
||||
});
|
||||
|
||||
canvas.add(group);
|
||||
|
||||
canvas.on('mouse:down', function (ev) {
|
||||
console.log(ev.subTargets);
|
||||
});
|
||||
```
|
||||
|
||||
### 文本框强制自动换行
|
||||
|
||||
Fabeic.js 的文本框对象(Textbox)默认支持文本自动换行,但只能在**空格**处换行,对于类似中文句子这种不带空格的字符串并不会换行,且文本框的宽度会自动被撑开。
|
||||
|
||||
在 Fabric.js 2.6.0 版本中,新增了一个 `splitByGrapheme` 属性,将其设置为 `true` 即可启用在任意字符之间自动换行(参考:[JSDoc: Global](http://fabricjs.com/docs/global.html#splitByGrapheme)),例如:
|
||||
|
||||
```javascript
|
||||
const textbox = new fabric.Textbox('文本框', {
|
||||
left: 100,
|
||||
top: 100,
|
||||
width: 200,
|
||||
splitByGrapheme: true,
|
||||
});
|
||||
|
||||
canvas.add(textbox);
|
||||
```
|
||||
|
||||
### 选中并聚焦对象(将对象置于视图的中心)
|
||||
|
||||
```javascript
|
||||
// 获取对象的中心点坐标
|
||||
// 坐标值相对于画布左上角起始点
|
||||
// 坐标值不受缩放比例影响
|
||||
const {
|
||||
x: elCenterX,
|
||||
y: elCenterY,
|
||||
} = el.getCenterPoint();
|
||||
|
||||
// 获取画布当前的缩放比例
|
||||
const zoom = canvas.getZoom();
|
||||
|
||||
// 计算新的视图坐标
|
||||
// 中心点坐标值需要与画布缩放比例相乘,与视图统一
|
||||
// 画布坐标的起始点在左上角,坐标值需要减去画布宽高的一半
|
||||
const point = {
|
||||
x: elCenterX * zoom - canvas.width / 2,
|
||||
y: elCenterY * zoom - canvas.height / 2,
|
||||
};
|
||||
|
||||
// 移动视图
|
||||
canvas.absolutePan(point);
|
||||
// 选中对象
|
||||
canvas.setActiveObject(el);
|
||||
```
|
||||
|
||||
### 选中多个对象,创建选区
|
||||
|
||||
主要用到了 Fabric.js 的 `ActiveSelection` 对象,手动创建选区:
|
||||
|
||||
```javascript
|
||||
// 画布对象
|
||||
const canvas = this.canvasInstance;
|
||||
|
||||
// 选区中包含的对象
|
||||
const items = [a, b, c, ...];
|
||||
|
||||
// 新建一个选区对象
|
||||
const sel = new fabric.ActiveSelection(items, {
|
||||
// 选区所属的画布
|
||||
// 必须包含该参数,否则会出现奇怪的问题(不会报错)
|
||||
canvas,
|
||||
// 其他配置选项,例如:
|
||||
// borderColor,
|
||||
// borderDashArray,
|
||||
// opacity,
|
||||
// hasControls,
|
||||
...
|
||||
});
|
||||
|
||||
// 使选区生效
|
||||
canvas.setActiveObject(sel);
|
||||
```
|
||||
|
||||
|
Reference in New Issue
Block a user