Введение
Перво-наперво: эта статья очень длинная, и рекомендуетсяНравится и нравится (лайк равен обучению).
Введение в Fabric.js
Fabric.jsявляется мощным и простым в использованииJavascript HTML5 canvasБиблиотека инструментов.
если вам нужно использоватьcanvasДелайте спецэффекты, тогда рекомендую использоватьFabric.js,потому чтоFabric.jsСинтаксис проще и удобнее в использовании, а также предоставляет множество интерактивных классов.api.
Fabric.jsУпростил многоеCanvasПонятие в коде также выглядит более семантичным.
Fabric.jsЧто может быть сделано?
можно открыть"Официальный сайт Fabric.js Главная"Пример прямого просмотра, вы также можете увидеть"Демонстрации Fabric.js"Посмотрите еще интересные примеры.
Введение в эту статью
если0 базачитатели, я надеюсь, что вы сможете прочитать его от начала до конца, и хотя бы знать оFabric.jsКакие функции есть.
Эта статья написана в соответствии с моим процессом обучения. Если вы будете следовать этой статье шаг за шагом, вы сможете начать работу.Fabric.js , а также улучшить качество сна, решить проблемы с чрезмерным количеством волос и многое другое.
Так как я используюFabric.jsВремени осталось не много, содержание этой заметки в каждом звене знаний точно недостаточно исчерпывающее и может быть не совсем корректным. Если читатели найдут какие-либо неточности в этой статье, пожалуйста, укажите, и я исправлю ее~
Эта статья подходит для толпы:
- Разработчики с родным трехкомпонентным фундаментом
- желательно иметь
canvasОсновы (это плюс, не беда, если у вас его вообще нет)
В этой статье в основном объясняетсяFabric.js Основание,включать:
- Основные операции с холстом
- Основные методы рисования графики (прямоугольник, круг, треугольник, эллипс, многоугольник, отрезок и т.д.)
- Использование изображений и фильтров
- Текст и текстовые поля
- анимация
- группировка и разбивка групп
- базовое событие
- бесплатная живопись
- обрезать
- Сериализация и десериализация
- ...
Кроме того, некоторыеПередовойНебольшая операция, например:
- Настройте стили и состояния углов действий
- пользовательский контроль
- Скопируйте и вставьте графику
- Управление графиками и группами с помощью событий
- ...
В дополнение к вышесказанному, я также разберу более распространенные и интересные операции, основанные на моей будущей работе.Эта статья предназначена для того, чтобы узнать о встрече на складе.Нерегулярно обновляется! ! !
Ссылки по теме
🎁Онлайн превью кейса в этой статье
Настройка среды разработки
Среда и примечания к выпуску
-
В этой статье используется
Fabric.jsВерсия4.6. -
Среда разработки для этой статьи должна использовать
ViteпостроенVue 3.2проект.
нетViteа такжеVue3.2Базовым студентам не нужно бояться, потому чтоViteДействительно достаточно просто.
Цель этой статьи — объяснитьFabric.js, поэтому используйтеVue 3.2На самом деле мест очень мало, и я подробно объясню, когда буду их использовать.
Если вы не собираетесь использоватьViteа такжеVue 3.2не важно,Соберите проект так, как вам нравится.
Теперь просто следуйте инструкциям ниже, чтобы построить проект.
Настройка окружения (Vite + Vue3)
Если вы не хотите использоватьVite + Vue3Если это так, вы можете пропустить этот раздел.
Я также рекомендую вам учиться напрямую, используя нативный (HTML+CSS+JS) способFabric.js, потому что это самый быстрый способ начать работу.
1. Создайте проект Vite
npm init @vitejs/app
2. Дайте проекту имя и выберите Vue.
Тогда вы выберетеvueилиvue + ts,Я выбралvue,вам решать.
почему бы не выбратьts? Потому что используется практический проект, разработанный одним человеком.tsЭто небольшая потеря.
3. Инициализируйте проект
На самом деле, после выполнения предыдущего шага будет выдано приглашение (3 команды), и вы сможете запустить проект, набрав его.
# 进入项目目录
cd fabric-demo
# 初始化项目
npm install
# 运行项目
npm run dev
еслиnpmЕсли это слишком медленно, вы можете использоватьcnpm.
Если вы не знаетеcnpmКак это сделать, пожалуйста, Baidu.
Установите Fabric.js
Способ 1: CDN
<script src="https://unpkg.com/fabric@4.6.0/dist/fabric.min.js"></script>
Вы можете использовать метод CDN для импорта, потому что это самый быстрый способ обучения.
Способ 2: нпм
В этой статье используется этот метод! ! !
npm i fabric --save
После установкиpackage.jsonПоявится строка кода, на которую указывает стрелка.
Начало
только что3 операцииМожет что-то показать.
1. Создайте новую страницу и импортируйте Fabric.js
Если это нативный проект, используйте<script>Метки можно импортировать:
<script src="https://unpkg.com/fabric@4.6.0/dist/fabric.min.js"></script>
В этой статье используетсяViteвстроенный проект, поэтому вы можете использоватьimportпредставлять
import { fabric } from 'fabric'
2. Создайте контейнер холста
существуетHTMLсоздан в<canvas>и установите контейнерidа также宽高,width/height
<canvas width="400" height="400" id="c" style="border: 1px solid #ccc;"></canvas>
Создано здесьcanvasконтейнер,id="c".
Указанная длина и ширина400px, стоит отметить, что нет необходимости добавлятьpxэтот блок.
style="border: 1px solid #ccc;"На самом деле это предложение можно опустить, это просто посмотреть в браузереcanvasГде элемент.
3. Используйте ткань, чтобы взять контейнер и нарисовать прямоугольник
существуетJSэкземпляр вfabric, то вы можете использоватьfabricизapiуправлятьcanvas.
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric' // 引入 fabric
function init() {
const canvas = new fabric.Canvas('c') // 这里传入的是canvas的id
// 创建一个长方形
const rect = new fabric.Rect({
top: 30, // 距离容器顶部 30px
left: 30, // 距离容器左侧 30px
width: 100, // 宽 100px
height: 60, // 高 60px
fill: 'red' // 填充 红色
})
// 在canvas画布中加入矩形(rect)。add是“添加”的意思
canvas.add(rect)
}
// 需要在页面容器加载完才能开始初始化(页面加载完才找到 canvas 元素)
// onMounted 是 Vue3 提供的一个页面生命周期函数:实例被挂载后调用。
// onMounted 官方文档说明:https://v3.cn.vuejs.org/guide/composition-api-lifecycle-hooks.html
onMounted(() => {
init() // 执行初始化函数
})
</script>
Подробности смотрите в комментариях к каждой строке кода.
<script setup>даVue 3.2Новый синтаксис для обычных проектов для прямого использования<script>Вот и все.
Даже если я не пишу записку, я вижу, чтоFabric.jsКод очень семантический, и вы, вероятно, можете догадаться об эффекте кода, взглянув на слова.
Если использовать оригиналcanvasСпособ писать, студенты, которые этого не поняли, не могут понять, что они пишут.
холст
Fabric.jsРаботоспособность холста очень сильна.Здесь я перечислю несколько распространенных примеров.Для других операций вы можете проверить официальную документацию.
«Манипуляции с холстом Fabric.js — Документация»
🎁 Онлайн превью кейса в этом разделе - Канвас
🎁 Репозиторий Code для этого раздела
Базовая версия (интерактивная)
Базовая версия — это пример, описанный в главе «Начало работы».
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric' // 引入 fabric
function init() {
const canvas = new fabric.Canvas('canvas') // 这里传入的是canvas元素的id
// 创建一个长方形
const rect = new fabric.Rect({
top: 100, // 距离容器顶部 100px
left: 100, // 距离容器左侧 100px
width: 30, // 矩形宽度 30px
height: 30, // 矩形高度 30px
fill: 'red' // 填充 红色
})
canvas.add(rect) // 将矩形添加到 canvas 画布里
}
onMounted(() => {
init()
})
</script>
Не интерактивный
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric' // 引入 fabric
function init() {
// 使用 StaticCanvas 创建一个不可操作的画布
const canvas = new fabric.StaticCanvas('canvas') // 这里传入的是canvas元素的id
// 创建一个长方形
const rect = new fabric.Rect({
top: 100, // 距离容器顶部 100px
left: 100, // 距离容器左侧 100px
width: 30, // 矩形宽度 30px
height: 30, // 矩形高度 30px
fill: 'red' // 填充 红色
})
canvas.add(rect) // 将矩形添加到 canvas 画布里
}
onMounted(() => {
init()
})
</script>
Чтобы создать неинтерактивный холст, вам нужно всего лишь поставитьnew fabric.Canvasизменить наnew fabric.StaticCanvasВот и все.
Установить параметры холста в js
<template>
<canvas id="canvas"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric' // 引入 fabric
function init() {
const canvas = new fabric.Canvas('canvas', {
width: 300, // 画布宽度
height: 300, // 画布高度
backgroundColor: '#eee' // 画布背景色
})
// 圆形
const circle = new fabric.Circle({
radius: 30, // 圆的半径
top: 20, // 距离容器顶部 20px
left: 20, // 距离容器左侧 20px
fill: 'pink' // 填充 粉色
})
canvas.add(circle) // 将圆形添加到 canvas 画布里
}
onMounted(() => {
init()
})
</script>
new fabric.CanvasВторой параметр используется для установки основной функции холста. Дополнительные параметры конфигурации можно просмотреть«Официальная документация».
Используйте фоновое изображение
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 设置背景图
// 参数1:背景图资源(可以引入本地,也可以使用网络图)
// 参数2:设置完背景图执行以下重新渲染canvas的操作,这样背景图就会展示出来了
canvas.setBackgroundImage(
'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27d1b4e5f8824198b6d51a2b1c2d0d75~tplv-k3u1fbpfcp-zoom-crop-mark:400:400:400:400.awebp',
canvas.renderAll.bind(canvas)
)
}
onMounted(() => {
init()
})
</script>
setBackgroundImageЭто легко понять, установив фоновое изображение.
Следует отметить, что вFabric.jsиспользуется вgifТолько первый кадр будет визуализирован.
Повернуть фоновое изображение
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 设置背景图
// 参数1:背景图资源(可以引入本地,也可以使用网络图)
// 参数2:设置完背景图执行以下重新渲染canvas的操作,这样背景图就会展示出来了
canvas.setBackgroundImage(
'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27d1b4e5f8824198b6d51a2b1c2d0d75~tplv-k3u1fbpfcp-zoom-crop-mark:400:400:400:400.awebp',
canvas.renderAll.bind(canvas),
{
angle: 15 // 旋转背景图
}
)
}
onMounted(() => {
init()
})
</script>
setBackgroundImageЕсть третий параметр, эй эй эй я не ожидал
Кроме поворота можно задать и третий параметрscaleX,scaleYтакие операции.
Дополнительные настройки можно посмотреть"документ".
Но есть проблема с этим примером, если размер изображения неcanvasЕсли контейнер большой, его нельзя заполнить, иначе он переполнится (отображается только часть изображения).
См. следующий случай для решения.
растянуть фон
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// fabric.Image.fromURL:加载图片的api
// 第一个参数:图片地址(可以是本地的,也可以是网络图)
// 第二个参数:图片加载的回调函数
fabric.Image.fromURL(
'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27d1b4e5f8824198b6d51a2b1c2d0d75~tplv-k3u1fbpfcp-zoom-crop-mark:400:400:400:400.awebp',
(img) => {
// 设置背景图
canvas.setBackgroundImage(
img,
canvas.renderAll.bind(canvas),
{
scaleX: canvas.width / img.width, // 计算出图片要拉伸的宽度
scaleY: canvas.height / img.height // 计算出图片要拉伸的高度
}
)
}
)
}
onMounted(() => {
init()
})
</script>
В этом примере используетсяfabric.Image.fromURLэтоapiДля загрузки изображения первым параметром является адрес изображения, а вторым параметром — функция обратного вызова.
Получите параметры картинки и ширину и высоту холста для расчета, чтобы картинка занимала весь экран.
Повторить фоновое изображение
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
canvas.setBackgroundColor({
source: 'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/27d1b4e5f8824198b6d51a2b1c2d0d75~tplv-k3u1fbpfcp-zoom-crop-mark:40:40:40:40.awebp',
repeat: 'repeat'
}, canvas.renderAll.bind(canvas))
}
onMounted(() => {
init()
})
</script>
Размер изображения, используемого в этом примере, относительно мал, поэтому вsetBackgroundColorустанавливается в 3-м параметреrepeat: 'repeat', что означает повторную визуализацию изображения.
наложение изображения
<template>
<canvas width="400" height="375" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
import jailCellBars from '@/assets/images/jail_cell_bars.png' // 引入背景图
function init() {
const canvas = new fabric.Canvas('canvas')
canvas.add(
new fabric.Circle({
radius: 30, // 圆形半径
fill: '#f55',
top: 70,
left: 70
})
)
// 设置覆盖图像的画布
canvas.setOverlayImage( // setOverlayImage(image, callback, optionsopt)
jailCellBars, // 图片,script开头import进来的
canvas.renderAll.bind(canvas)
)
}
onMounted(() => {
init()
})
</script>
Стоит отметить 2 момента:
- использовать
canvas.setOverlayImageзаменить оригиналcanvas.setBackgroundImage. - Используемая картинка желательно с прозрачным слоем
png, демонстрирующий эффект, показанный в примере, с фоновым изображением, наложенным поверх элемента узора.
🎁 URL-адрес изображения, используемый в этом примере
базовая графика
Fabric.jsПредусмотрены следующие основные графики:
🎁 Онлайн превью кейса в этом разделе - базовая графика
🎁 Репозиторий кода для этого раздела
прямоугольник
<template>
<canvas width="400" height="375" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas') // 绑定canvas,传入id
const rect = new fabric.Rect({
top: 100, // 距离容器顶部 100px
left: 100, // 距离容器左侧 100px
fill: 'orange', // 填充 橙色
width: 100, // 宽度 100px
height: 100 // 高度 100px
})
// 将矩形添加到画布中
canvas.add(rect)
}
onMounted(() => {
init()
})
</script>
использоватьnew fabric.RectСоздайтепрямоугольник.
Прямоугольник с закругленными углами
<template>
<canvas width="400" height="375" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas') // 绑定canvas,传入id
const rect = new fabric.Rect({
top: 100, // 距离容器顶部 100px
left: 100, // 距离容器左侧 100px
fill: 'orange', // 填充 橙色
width: 100, // 宽度 100px
height: 100, // 高度 100px
rx: 20, // x轴的半径
ry: 20 // y轴的半径
})
// 将矩形添加到画布中
canvas.add(rect)
}
onMounted(() => {
init()
})
</script>
Чтобы нарисовать прямоугольник со скругленными углами, вам нужно добавитьrxа такжеry, значения этих двух свойств могут быть разными, если знатьcssПринцип скругления углов на самом деле веренrxа такжеryНе сложно понять.
Измените эти два значения самостоятельно, чтобы увидеть эффект и понять его глубже.
круглый
<template>
<canvas width="400" height="375" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const circle = new fabric.Circle({
top: 100,
left: 100,
radius: 50, // 圆的半径 50
fill: 'green'
})
canvas.add(circle)
}
onMounted(() => {
init()
})
</script>
использоватьnew fabric.CircleСоздайтекруглый.
нужно использовать круглыйradiusУстановите размер радиуса.
Овал
<template>
<canvas width="400" height="375" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const ellipse = new fabric.Ellipse({
top: 20,
left: 20,
rx: 70,
ry: 30,
fill: 'hotpink'
})
canvas.add(ellipse)
}
onMounted(() => {
init()
})
</script>
Нужно использоватьnew fabric.EllipseСоздайтеовал.
В отличие от кругов, эллипсы задавать не нужно.radius, но установитьrxа такжеry.
- когда
rx>ry: эллипс горизонтальный - когда
rx<ry: эллипс вертикальный - когда
rx=ry: похоже на круг
треугольник
<template>
<canvas width="400" height="375" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const triangle = new fabric.Triangle({
top: 100,
left: 100,
width: 80, // 底边长度
height: 100, // 底边到对角的距离
fill: 'blue'
})
canvas.add(triangle)
}
onMounted(() => {
init()
})
</script>
использовать
new fabric.TriangleЧтобы создать треугольник, треугольнику нужно задать «основание и высоту».
отрезок
<template>
<canvas width="400" height="375" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const line = new fabric.Line(
[
10, 10, // 起始点坐标
200, 300 // 结束点坐标
],
{
stroke: 'red', // 笔触颜色
}
)
canvas.add(line)
}
onMounted(() => {
init()
})
</script>
использоватьnew fabric.LineСоздание сегментов линии.
new fabric.LineВам нужно передать 2 параметра.
-
Первый параметрмножество, массив должен передать 4 значения,Первые 2 значения — это x и y начальной координаты, последние 2 значения — это x и y конечной координаты.
-
Второй параметрстиль сегмента линии, чтобы задать цвет сегмента линии, нужно использовать
stroke.
Полилиния
<template>
<canvas width="400" height="375" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const polyline = new fabric.Polyline([
{x: 30, y: 30},
{x: 150, y: 140},
{x: 240, y: 150},
{x: 100, y: 30}
], {
fill: 'transparent', // 如果画折线,需要填充透明
stroke: '#6639a6', // 线段颜色:紫色
strokeWidth: 5 // 线段粗细 5
})
canvas.add(polyline)
}
onMounted(() => {
init()
})
</script>
использоватьnew fabric.PolylineСоздайтеотрезок.
new fabric.PolylineВам нужно передать 2 параметра.
- Первый параметр — это массив, описывающий каждую точку отрезка.
- Второй параметр используется для описания стиля сегмента линии.
должны знать о том,fillЕсли установлено значение «Прозрачность», оно будет отображаться в виде сегмента линии, если не задано, то по умолчанию оно будет заполнено черным цветом, как показано на следующем рисунке:
Вы также можете заполнить свой любимый цвет,new fabric.Polylineне будет автоматическиОтправная точкаа такжеконечная точкаавтоматически закрывается.
многоугольник
<template>
<canvas width="400" height="375" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const polygon = new fabric.Polygon([
{x: 30, y: 30},
{x: 150, y: 140},
{x: 240, y: 150},
{x: 100, y: 30}
], {
fill: '#ffd3b6', // 填充色
stroke: '#6639a6', // 线段颜色:紫色
strokeWidth: 5 // 线段粗细 5
})
canvas.add(polygon)
}
onMounted(() => {
init()
})
</script>
использоватьnew fabric.Polygonрисование полигонов, использование иnew fabric.PolylineПочти то же самое, но самая большая разница в том, чтоnew fabric.PolygonАвтоматическиотправная точкаа такжеконечная точкасоедините их.
рисовать путь
"Путь пути Fabric.js — документация"
🎁 Онлайн превью кейса в этом разделе - рисование пути
🎁 Репозиторий кода для этого раздела
<template>
<canvas width="400" height="375" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 绘制路径
const path = new fabric.Path('M 0 0 L 200 100 L 170 200 z')
path.set({
top: 50, // 距离容器顶部距离 50px
left: 50, // 距离容器左侧距离 50px
fill: 'hotpink', // 填充 亮粉色
opacity: 0.5, // 不透明度 50%
stroke: 'black', // 描边颜色 黑色
strokeWidth: 10 // 描边粗细 10px
})
canvas.add(path)
}
onMounted(() => {
init()
})
</script>
использоватьnew fabric.PathСоздайте путь.
- M: можно понимать как новую начальную точку с координатами x, y.
- L: x,y координаты каждой вершины
- z: Автоматически закрывать (автоматически соединять конечную точку и начальную точку)
текст
Fabric.jsЕсть 3 категории, связанные с текстомapi.
-
обычный текст
-
редактируемый текст
-
текстовое окно
обычный текст
«Текст Fabric.js — Документация»
🎁 Онлайн превью кейса в этом разделе - обычный текст
🎁 Репозиторий кода для этого раздела
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const text = new fabric.Text('雷猴啊')
canvas.add(text)
}
onMounted(() => {
init()
})
</script>
использоватьnew fabric.TextЧтобы создать текст, первым передаваемым параметром является текстовое содержимое.
new fabric.TextОн также поддерживает второй параметр, который может установить стиль текста, который будет рассмотрен в следующей главе, и вы можете увидеть его, пролистнув страницу вниз.
Редактируемый текст IText
«Редактируемый текст Fabric.js — Документация»
🎁 Онлайн превью кейса этого раздела - редактируемый текст
🎁 Репозиторий кода для этого раздела
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const itext = new fabric.IText('雷猴啊')
canvas.add(itext)
}
onMounted(() => {
init()
})
</script>
использоватьnew fabric.ITextможет создатьредактируемый текст, использование иnew fabric.TextТакой же.
ITextСравниватьTextВ первой букве есть лишняя заглавная «И».
Текстовое поле Текстовое поле
«Текстовое поле Fabric.js — Документация»
🎁 Онлайн превью кейса в этом разделе - текстовое поле
🎁 Репозиторий кода для этого раздела
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const textbox = new fabric.Textbox('Lorum ipsum dolor sit amet', {
width: 250
})
canvas.add(textbox)
}
onMounted(() => {
init()
})
</script>
использоватьnew fabric.TextboxТекстовые поля могут быть созданы.
new fabric.TextboxВторой параметр - это объект, используйтеwidthШирину текстового поля можно установить, и текстовое содержимое будет автоматически переноситься, если ширина превышает установленную ширину.
new fabric.TextboxСодержание такжередактируемыйиз.
основной стиль
общие стили графики
На самом деле атрибутов стиля очень много, здесь перечислены только часто используемые атрибуты, остальные атрибуты вы можете посмотреть самостоятельно в официальных документах.
В этом примере в качестве примера используется круг (не обращайте внимания на соответствие цветов, я просто введу цвет для демонстрации)
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const circle = new fabric.Circle({
top: 100,
left: 100,
radius: 50, // 半径:50px
backgroundColor: 'green', // 背景色:绿色
fill: 'orange', // 填充色:橙色
stroke: '#f6416c', // 边框颜色:粉色
strokeWidth: 5, // 边框粗细:5px
strokeDashArray: [20, 5, 14], // 边框虚线规则:填充20px 空5px 填充14px 空20px 填充5px ……
shadow: '10px 20px 6px rgba(10, 20, 30, 0.4)', // 投影:向右偏移10px,向下偏移20px,羽化6px,投影颜色及透明度
transparentCorners: false, // 选中时,角是被填充了。true 空心;false 实心
borderColor: '#16f1fc', // 选中时,边框颜色:天蓝
borderScaleFactor: 5, // 选中时,边的粗细:5px
borderDashArray: [20, 5, 10, 7], // 选中时,虚线边的规则
cornerColor: "#a1de93", // 选中时,角的颜色是 青色
cornerStrokeColor: 'pink', // 选中时,角的边框的颜色是 粉色
cornerStyle: 'circle', // 选中时,叫的属性。默认rect 矩形;circle 圆形
cornerSize: 20, // 选中时,角的大小为20
cornerDashArray: [10, 2, 6], // 选中时,虚线角的规则
selectionBackgroundColor: '#7f1300', // 选中时,选框的背景色:朱红
padding: 40, // 选中时,选择框离元素的内边距:40px
borderOpacityWhenMoving: 0.6, // 当对象活动和移动时,对象控制边界的不透明度
})
canvas.add(circle)
}
onMounted(() => {
init()
})
</script>
Стиль приведенного выше примера делится нанормальное состояниеа такжевыбранное состояние, подробности см. в комментариях к коду.
общие стили текста
🎁 в этом разделе Stories Online Preview - Text Styles
🎁 Репозиторий кода для этого раздела
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const text = new fabric.Text('雷猴', {
top: 40,
left: 40,
fontSize: 120,
backgroundColor: 'green', // 背景色:绿色
fill: 'orange', // 填充色:橙色
stroke: '#f6416c', // 边框颜色:粉色
strokeWidth: 3, // 边框粗细:3px
strokeDashArray: [20, 5, 14], // 边框虚线规则:填充20px 空5px 填充14px 空20px 填充5px ……
shadow: '10px 20px 6px rgba(10, 20, 30, 0.4)', // 投影:向右偏移10px,向下偏移20px,羽化6px,投影颜色及透明度
transparentCorners: false, // 选中时,角是被填充了。true 空心;false 实心
borderColor: '#16f1fc', // 选中时,边框颜色:天蓝
borderScaleFactor: 5, // 选中时,边的粗细:5px
borderDashArray: [20, 5, 10, 7], // 选中时,虚线边的规则
cornerColor: "#a1de93", // 选中时,角的颜色是 青色
cornerStrokeColor: 'pink', // 选中时,角的边框的颜色是 粉色
cornerStyle: 'circle', // 选中时,叫的属性。默认rect 矩形;circle 圆形
cornerSize: 20, // 选中时,角的大小为20
cornerDashArray: [10, 2, 6], // 选中时,虚线角的规则
selectionBackgroundColor: '#7f1300', // 选中时,选框的背景色:朱红
padding: 40, // 选中时,选择框离元素的内边距:40px
borderOpacityWhenMoving: 0.6, // 当对象活动和移动时,对象控制边界的不透明度
})
canvas.add(text)
}
onMounted(() => {
init()
})
</script>
Кроме того, вы можете настроитьзачеркивать,подчеркивать,зачеркнутый,Выровнять по левому краю,Выровнять вправо,выравнивание по центру,Межстрочный интервалЖдать.
<template>
<canvas width="600" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 上划线
const overline = new fabric.Text('上划线', {
top: 30,
left: 10,
fontSize: 20,
overline: true, // 上划线
})
// 下划线
const underline = new fabric.Text('下划线', {
top: 30,
left: 100,
fontSize: 20,
underline: true, // 下划线
})
// 删除线
const linethrough = new fabric.Text('删除线', {
top: 30,
left: 200,
fontSize: 20,
linethrough: true, // 删除线
})
// 左对齐
const msg1 = '左\n左左\n左对齐'
const left = new fabric.Text(msg1, {
top: 100,
left: 10,
fontSize: 16,
textAlign: 'left', // 左对齐
})
// 居中对齐
const msg2 = '中\n中中\n居中对齐'
const center = new fabric.Text(msg2, {
top: 100,
left: 100,
fontSize: 16,
textAlign: 'center',// 居中对齐
})
// 右对齐
const msg3 = '右\n右右\n右对齐'
const right = new fabric.Text(msg3, {
top: 100,
left: 200,
fontSize: 16,
textAlign: 'right', // 右对齐
})
// 文本内容
const msg4 = "Lorem ipsum dolor sit amet,\nconsectetur adipisicing elit,\nsed do eiusmod tempor incididunt\nut labo"
const lineHeight1 = new fabric.Text(msg4, {
top: 250,
left: 10,
fontSize: 16,
lineHeight: 1, // 行高
})
const lineHeight2 = new fabric.Text(msg4, {
top: 250,
left: 300,
fontSize: 16,
lineHeight: 2, // 行高
})
canvas.add(
overline,
underline,
linethrough,
left,
center,
right,
lineHeight1,
lineHeight2
)
}
onMounted(() => {
init()
})
</script>
Вышеупомянутая конфигурация надчеркивания, подчеркивания и зачеркивания может использоваться одновременно.
Градиент
«Градиенты Fabric.js — Документация»
🎁 Онлайн превью кейса в этом разделе - Градиент
🎁 Репозиторий кода для этого раздела
Линейный градиент
<template>
<canvas width="600" height="600" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
let canvas = new fabric.Canvas('canvas') // 实例化fabric,并绑定到canvas元素上
// 圆
let circle = new fabric.Circle({
left: 100,
top: 100,
radius: 50,
})
// 线性渐变
let gradient = new fabric.Gradient({
type: 'linear', // linear or radial
gradientUnits: 'pixels', // pixels or pencentage 像素 或者 百分比
coords: { x1: 0, y1: 0, x2: circle.width, y2: 0 }, // 至少2个坐标对(x1,y1和x2,y2)将定义渐变在对象上的扩展方式
colorStops:[ // 定义渐变颜色的数组
{ offset: 0, color: 'red' },
{ offset: 0.2, color: 'orange' },
{ offset: 0.4, color: 'yellow' },
{ offset: 0.6, color: 'green' },
{ offset: 0.8, color: 'blue' },
{ offset: 1, color: 'purple' },
]
})
circle.set('fill', gradient);
canvas.add(circle)
}
onMounted(() => {
init()
})
</script>
радиальный градиент
<template>
<canvas width="600" height="600" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
let canvas = new fabric.Canvas('canvas') // 实例化fabric,并绑定到canvas元素上
// 圆
let circle = new fabric.Circle({
left: 100,
top: 100,
radius: 50,
})
let gradient = new fabric.Gradient({
type: 'radial',
coords: {
r1: 50, // 该属性仅径向渐变可用,外圆半径
r2: 0, // 该属性仅径向渐变可用,外圆半径
x1: 50, // 焦点的x坐标
y1: 50, // 焦点的y坐标
x2: 50, // 中心点的x坐标
y2: 50, // 中心点的y坐标
},
colorStops: [
{ offset: 0, color: '#fee140' },
{ offset: 1, color: '#fa709a' }
]
})
circle.set('fill', gradient);
canvas.add(circle)
}
onMounted(() => {
init()
})
</script>
r1,r2,x1,y1,x2,y2Вы можете изменить значения этих параметров самостоятельно и увидеть эффект, если вы измените его самостоятельно, вы поймете это более глубоко.
использовать картинки
«Изображение Fabric.js — Документация»
🎁 Онлайн превью кейса в этом разделе - с использованием картинок
🎁 Репозиторий кода для этого раздела
Способ 1: Изображения с использованием HTML
<template>
<div>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
<img src="@/assets/logo.png" id="logo">
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const imgElement = document.getElementById('logo')
imgElement.onload = function() {
let imgInstance = new fabric.Image(imgElement, {
left: 100,
top: 100,
width: 200,
height: 200,
angle: 50, // 旋转
})
canvas.add(imgInstance)
}
}
onMounted(() => {
init()
})
</script>
<style>
#logo {
display: none;
}
</style>
Нужно использоватьonloadМетод отслеживает, загружено изображение или нет.
Только когда изображение полностью загружено, а затем добавлено на холст, оно может отображаться.
Используйте этот метод, если вы не хотите отображать изображение за пределами холста, вам нужно использоватьdisplay: none;Скрыть картинки.
Способ 2: импортировать с помощью js
<template>
<div>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
import logo from '@/assets/logo.png' // 引入图片
function init() {
const canvas = new fabric.Canvas('canvas')
fabric.Image.fromURL(logo, oImg => {
oImg.scale(0.5) // 缩放
canvas.add(oImg) // 将图片加入到画布
})
}
onMounted(() => {
init()
})
</script>
использоватьfabric.Image.fromURLЗагрузить изображение.
Первый параметр — это ресурс изображения, который может быть помещен в локальный образ или сетевой образ;
Второй параметр — это функция обратного вызова, которую можно использовать с объектом изображения после загрузки изображения.
фильтр изображений
«Tabric.js image Path - документация»
🎁 Онлайн превью кейса в этом разделе - фильтр картинок
🎁 Репозиторий кода для этого раздела
<template>
<div>
<canvas width="500" height="500" id="canvas" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
import gwen from '@/assets/images/gwen-spider-verse-ah.jpg'
function init() {
const canvas = new fabric.Canvas('canvas')
fabric.Image.fromURL(gwen, img => {
img.scale(0.5) // 图片缩小50%
canvas.add(img)
})
// 单个滤镜
fabric.Image.fromURL(gwen, img => {
img.scale(0.5) // 图片缩小50%
img.left = 250
// 添加滤镜
img.filters.push(new fabric.Image.filters.Grayscale())
// 图片加载完成之后,应用滤镜效果
img.applyFilters()
canvas.add(img)
})
// 叠加滤镜
// “filters”属性是一个数组,我们可以用数组方法执行任何所需的操作:移除滤镜(pop,splice,shift),添加滤镜(push,unshift,splice),甚至可以组合多个滤镜。当我们调用 applyFilters 时,“filters”数组中存在的任何滤镜将逐个应用,所以让我们尝试创建一个既色偏又明亮(Brightness)的图像。
fabric.Image.fromURL(gwen, img => {
img.scale(0.5) // 图片缩小50%
// 添加滤镜
img.filters.push(
new fabric.Image.filters.Grayscale(),
new fabric.Image.filters.Sepia(), //色偏
new fabric.Image.filters.Brightness({ brightness: 0.2 }) //亮度
)
// 图片加载完成之后,应用滤镜效果
img.applyFilters()
img.set({
left: 250,
top: 250,
})
canvas.add(img)
})
}
onMounted(() => {
init()
})
</script>
добавлять фильтры к картинкам,fabric.Image.fromURLОбъект изображения возвращается в функции обратного вызова , и объект изображения может использоватьсяfiltersДобавьте фильтры.
Ткань встроенный фильтр
-
Базовый фильтр BaseFilter
-
Размытие
-
Яркость
-
Цветовая матрица ColorMatrix
-
Контраст
-
Свернутая свертка
-
Гамма
-
Оттенки серого
-
HueRotation Поворот оттенка
-
инвертировать
-
Шум
-
Пикселизация
-
RemoveColor удалить цвет
-
изменить размер изменить размер
-
Насыщенность
-
Цветовой оттенок сепия
конвертировать
угол поворота
<template>
<div>
<canvas width="500" height="500" id="canvas" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
let triangle = new fabric.Triangle({
top: 100,
left: 100,
width: 80,
height: 100,
fill: 'blue',
angle: 30 // 旋转30度
})
canvas.add(triangle)
}
onMounted(() => {
init()
})
</script>
шкала шкалыX и шкалыY
<template>
<div>
<canvas width="500" height="500" id="canvas" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
let triangle = new fabric.Triangle({
top: 100,
left: 100,
width: 80,
height: 100,
fill: 'blue',
scaleX: 2, // x轴方向放大2倍
scaleY: 2 // y轴方向放大2倍
})
canvas.add(triangle)
}
onMounted(() => {
init()
})
</script>
Инвертировать масштабX и масштабY
<template>
<div>
<canvas width="500" height="500" id="canvas" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
let triangle = new fabric.Triangle({
top: 100,
left: 100,
width: 80,
height: 100,
fill: 'blue',
scaleY: -1 // scale是负数时,图形会反转
})
canvas.add(triangle)
}
onMounted(() => {
init()
})
</script>
панорамирование сверху и слева
Элементы могут быть установлены непосредственноtopа такжеleftпанорамировать.
См. предыдущий пример.
группировка
"Fabric.js Group - Документация"
сформировать группу
🎁 Онлайн превью кейса в этом разделе - формирование группы и работа
🎁 Репозиторий кода для этого раздела
<template>
<div>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 椭圆
const ellipse = new fabric.Ellipse({
top: 20,
left: 20,
rx: 100,
ry: 50,
fill: '#ddd',
originX: 'center', // 旋转x轴:left, right, center
originY: 'center' // 旋转y轴:top, bottom, center
})
// 文本
const text = new fabric.Text('Hello World', {
top: 40,
left: 20,
fontSize: 20,
originX: "center",
originY: "center"
})
// 建组
const group = new fabric.Group([ellipse, text], {
top: 50, // 整组距离顶部100
left: 100, // 整组距离左侧100
angle: -10, // 整组旋转-10deg
})
canvas.add(group)
}
onMounted(() => {
init()
})
</script>
new fabric.Group Вы можете создать группу (фактически немного похожую на группу в Photoshop, поместив несколько слоев в одну группу для достижения синхронизированных операций, таких как перетаскивание, масштабирование и т. д.).
Группа действий
🎁 Онлайн превью кейса в этом разделе - формирование группы и работа
🎁 Репозиторий кода для этого раздела
Fabric.jsГруппа предоставляет множество методов, вот некоторые из наиболее часто используемых:
-
getObjects()Возвращает массив всех объектов в наборе -
size()Количество всех объектов -
contains()Проверить, находится ли конкретный объект вgroupсередина -
item()элементы в группе -
forEachObject()Перебирать объекты в группе -
add()добавить объект элемента -
remove()удалить объект элемента -
fabric.util.object.clone()клон
В качестве примера возьму один из них:item()
На основе предыдущего примера измените эллипс на красный, а «Hello World» на «Thunder Monkey, World».
<template>
<div>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 椭圆
const ellipse = new fabric.Ellipse({
top: 20,
left: 20,
rx: 100,
ry: 50,
fill: '#ddd',
originX: 'center', // 旋转x轴:left, right, center
originY: 'center' // 旋转y轴:top, bottom, center
})
// 文本
const text = new fabric.Text('Hello World', {
top: 40,
left: 20,
fontSize: 20,
originX: "center",
originY: "center"
})
// 建组
const group = new fabric.Group([ellipse, text], {
top: 50, // 整组距离顶部100
left: 100, // 整组距离左侧100
angle: -10, // 整组旋转-10deg
})
// 控制第一个元素(椭圆)
group.item(0).set('fill', '#ea5455')
// 控制第二个元素(文本)
group.item(1).set({
text: '雷猴,世界',
fill: '#fff'
})
canvas.add(group)
}
onMounted(() => {
init()
})
</script>
распустить группу
🎁 Онлайн превью кейса в этом разделе - Формирование и расформирование групп
🎁 Репозиторий кода для этого раздела
<template>
<div>
<button @click="ungroup">取消组</button>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
let canvas = null
// 初始化
function init() {
canvas = new fabric.Canvas('canvas')
// 椭圆
const ellipse = new fabric.Ellipse({
top: 20,
left: 20,
rx: 100,
ry: 50,
fill: '#ddd',
originX: 'center', // 旋转x轴:left, right, center
originY: 'center' // 旋转y轴:top, bottom, center
})
// 文本
const text = new fabric.Text('Hello World', {
top: 40,
left: 20,
fontSize: 20,
originX: "center",
originY: "center"
})
// 建组
const group = new fabric.Group([ellipse, text], {
top: 50, // 整组距离顶部100
left: 100, // 整组距离左侧100
angle: -10, // 整组旋转-10deg
})
canvas.add(group)
}
// 取消组
function ungroup() {
// 判断当前有没有选中元素,如果没有就不执行任何操作
if (!canvas.getActiveObject()) {
return
}
// 判断当前是否选中组,如果不是,就不执行任何操作
if (canvas.getActiveObject().type !== 'group') {
return
}
// 先获取当前选中的对象,然后打散
canvas.getActiveObject().toActiveSelection()
}
onMounted(() => {
init()
})
</script>
использоватьcanvas.getActiveObject()Вы можете получить текущий выбранный объект на холсте, а затем передатьtoActiveSelection()Разбить группу.
анимация
"Fabric.js анимация - Документация"
🎁 Онлайн превью кейса в этом разделе - анимация
🎁 Репозиторий кода для этого раздела
Анимация абсолютного значения
не волнует绝对值动画а также相对值动画, Такие, как успешное завершение этого раздела, а затем посмотреть вниз, чтобы знать.
Этот раздел является основным использованием анимации.
<template>
<div>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
// 初始化
function init() {
const canvas = new fabric.Canvas('canvas')
const rect = new fabric.Rect({
left: 100,
top: 100,
width: 100,
height: 100,
fill: 'red'
})
// 设置矩形动画
rect.animate('angle', "-50", {
onChange:canvas.renderAll.bind(canvas), // 每次刷新的时候都会执行
})
canvas.add(rect)
}
onMounted(() => {
init()
})
</script>
каждыйFabricобъект имеетanimateметод, который анимирует объект.
Применение:animate(动画属性, 动画的结束值, [画的详细信息])
первый параметресть свойство оживлять.
второй параметрявляется конечным значением анимации.
третий параметрэто объект, который включает в себя:
{
rom:允许指定可设置动画的属性的起始值(如果我们不希望使用当前值)。
duration:默认为500(ms)。可用于更改动画的持续时间。
onComplete:在动画结束时调用的回调。
easing:缓动功能。
}
Анимация относительного значения
<template>
<div>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
// 初始化
function init() {
const canvas = new fabric.Canvas('canvas')
const rect = new fabric.Rect({
left: 100,
top: 100,
width: 100,
height: 100,
fill: 'red'
})
// 请注意第二个参数:+=360
rect.animate('angle', '+=360', {
onChange:canvas.renderAll.bind(canvas), // 每次刷新的时候都会执行
duration: 2000, // 执行时间
easing: fabric.util.ease.easeOutBounce, // 缓冲效果
})
canvas.add(rect)
}
onMounted(() => {
init()
})
</script>
В этом примере используетсяfabric.util.ease.easeOutBounceбуферный эффект.
фактически绝对值动画а также相对值动画Использование аналогично, за исключениемвторой параметрИспользование отличается.
相对值动画Это дляanimateизменить, чтобы принестиоператорзначение, поэтому расчет будет производиться на исходной основе.
мероприятие
🎁 Онлайн-превью кейса в этом разделе - событие
🎁 Репозиторий кода для этого раздела
Fabric.jsПредоставляет очень удобную систему событий, мы можем использоватьonметод для инициализации прослушивателей событий с помощьюoffМетоды для его удаления.
<template>
<div>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
<button @click="addClickEvent">添加画布点击事件</button>
<button @click="removeClickEvent">移除画布点击事件</button>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
let canvas = null
// 初始化画布
function init() {
canvas = new fabric.Canvas('canvas')
const rect = new fabric.Rect({
top: 20,
left: 20,
width: 100,
height: 50,
fill: '#9896f1'
})
// 给矩形添加一个选中事件
rect.on('selected', options => {
console.log('选中矩形啦', options)
})
canvas.add(rect)
addClickEvent()
}
// 移除画布点击事件
function removeClickEvent() {
canvas.off('mouse:down')
}
// 添加画布点击事件
function addClickEvent() {
removeClickEvent() // 在添加事件之前先把该事件清除掉,以免重复添加
canvas.on('mouse:down', options => {
console.log(`x轴坐标: ${options.e.clientX}; y轴坐标: ${options.e.clientY}`)
})
}
onMounted(() => {
init()
})
</script>
Fabric.jsТакже предоставляет ряд событий, вы можете просмотреть деталиОфициальный случай
бесплатная живопись
«Бесплатное рисование Fabric.js — Документация»
🎁 Онлайн превью корпуса в этом разделе - бесплатная покраска
🎁 Репозиторий кода для этого раздела
<template>
<div>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
// 初始化
function init() {
const canvas = new fabric.Canvas('canvas', {
isDrawingMode: true, // 开启绘图模式
})
// 设置画笔颜色
canvas.freeDrawingBrush.color = '#11999e'
// 设置画笔粗细
canvas.freeDrawingBrush.width = 10
// 画笔投影
canvas.freeDrawingBrush.shadow = new fabric.Shadow({
blur: 10,
offsetX: 10,
offsetY: 10,
affectStroke: true,
color: '#30e3ca',
})
}
onMounted(() => {
init()
})
</script>
В использованииnew fabric.CanvasПри создании холста установитеisDrawingMode: trueВы можете начать свободный режим рисования.
canvas.freeDrawingBrushСуществует множество свойств для установки стиля кисти.
Некоторые операции запрещены
🎁 Онлайн просмотр кейса в этом разделе - некоторые операции запрещены
🎁 Репозиторий кода для этого раздела
Горизонтальное движение запрещено
<template>
<div>
<canvas id="canvas" width="400" height="400" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
// 初始化画布
function init() {
const canvas = new fabric.Canvas('canvas')
const rect = new fabric.Rect({
top: 100,
left: 100,
width: 100,
height: 50,
fill: '#ffde7d'
})
// 不允许水平移动
rect.lockMovementX = true
canvas.add(rect)
}
onMounted(() => {
init()
})
</script>
использоватьlockMovementXОбъектам запрещено двигаться по горизонтали.
вертикальное движение запрещено
<template>
<div>
<canvas id="canvas" width="400" height="400" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
// 初始化画布
function init() {
const canvas = new fabric.Canvas('canvas')
const rect = new fabric.Rect({
top: 100,
left: 100,
width: 100,
height: 50,
fill: '#f6416c'
})
// 不允许垂直移动
rect.lockMovementY = true
canvas.add(rect)
}
onMounted(() => {
init()
})
</script>
использоватьlockMovementYОбъектам запрещено двигаться по вертикали.
нет вращения
<template>
<div>
<canvas id="canvas" width="400" height="400" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
// 初始化画布
function init() {
const canvas = new fabric.Canvas('canvas')
const rect = new fabric.Rect({
top: 100,
left: 100,
width: 100,
height: 50,
fill: '#3490de'
})
// 禁止旋转
rect.lockRotation = true
canvas.add(rect)
}
onMounted(() => {
init()
})
</script>
использоватьlockRotationВращение объекта запрещено.
Отключить горизонтальное масштабирование
<template>
<div>
<canvas id="canvas" width="400" height="400" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
// 初始化画布
function init() {
const canvas = new fabric.Canvas('canvas')
const rect = new fabric.Rect({
top: 100,
left: 100,
width: 100,
height: 50,
fill: '#ff9a3c'
})
// 禁止水平缩放
rect.lockScalingX = true
canvas.add(rect)
}
onMounted(() => {
init()
})
</script>
использоватьlockScalingXОтключает горизонтальное масштабирование объектов.
Отключить вертикальное масштабирование
<template>
<div>
<canvas id="canvas" width="400" height="400" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
// 初始化画布
function init() {
const canvas = new fabric.Canvas('canvas')
const rect = new fabric.Rect({
top: 100,
left: 100,
width: 100,
height: 50,
fill: '#f95959'
})
// 禁止垂直缩放
rect.lockScalingY = true
canvas.add(rect)
}
onMounted(() => {
init()
})
</script>
использоватьlockScalingYОтключите вертикальное масштабирование объектов.
Масштабирование и панорамирование холста
🎁 Онлайн-предварительный просмотр кейса в этом разделе - панорамирование и масштабирование холста
🎁 Репозиторий кода для этого раздела
увеличить холст
Масштабирование холста вокруг начала координат
Чтобы увеличить холст, вы фактически прослушиваете события мыши.
Вот событие колеса прокрутки мыши:mouse:wheel.
<template>
<div>
<canvas id="canvas" width="400" height="400" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
// 初始化画布
const canvas = new fabric.Canvas('canvas')
// 矩形(参照物)
const rect = new fabric.Rect({
top: 10,
left: 10,
width: 40,
height: 40,
fill: 'orange'
})
// 圆形(参照物)
const circle = new fabric.Circle({
top: 30,
left: 30,
radius: 50,
fill: 'green'
})
canvas.add(rect, circle) // 将矩形和圆形添加到画布中
// 监听鼠标滚轮事件
canvas.on('mouse:wheel', opt => {
let delta = opt.e.deltaY // 滚轮向上滚一下是 -100,向下滚一下是 100
let zoom = canvas.getZoom() // 获取画布当前缩放值
// 控制缩放范围在 0.01~20 的区间内
zoom *= 0.999 ** delta
if (zoom > 20) zoom = 20
if (zoom < 0.01) zoom = 0.01
// 设置画布缩放比例
canvas.setZoom(zoom)
})
}
onMounted(() => {
init()
})
</script>
Указатель мыши в качестве контрольной массы холста
<template>
<div>
<canvas id="canvas" width="400" height="400" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
// 初始化画布
const canvas = new fabric.Canvas('canvas')
// 矩形(参照物)
const rect = new fabric.Rect({
top: 130,
left: 130,
width: 40,
height: 40,
fill: 'orange'
})
// 圆形(参照物)
const circle = new fabric.Circle({
top: 150,
left: 150,
radius: 50,
fill: 'green'
})
canvas.add(rect, circle) // 将矩形和圆形添加到画布中
// 监听鼠标滚轮事件
canvas.on('mouse:wheel', opt => {
let delta = opt.e.deltaY // 滚轮向上滚一下是 -100,向下滚一下是 100
let zoom = canvas.getZoom() // 获取画布当前缩放值
// 控制缩放范围在 0.01~20 的区间内
zoom *= 0.999 ** delta
if (zoom > 20) zoom = 20
if (zoom < 0.01) zoom = 0.01
// 设置画布缩放比例
// 关键点!!!
// 参数1:将画布的所放点设置成鼠标当前位置
// 参数2:传入缩放值
canvas.zoomToPoint(
{
x: opt.e.offsetX, // 鼠标x轴坐标
y: opt.e.offsetY // 鼠标y轴坐标
},
zoom // 最后要缩放的值
)
})
}
onMounted(() => {
init()
})
</script>
Панорамировать холст
В этом примере требуется нажать
alt键Только после этого может сработать функция перемещения полотна.
В соответствии с этим требованием задачу можно разбить на 3 этапа:
- Щелчок мышью (только что нажал)
- движение мыши
- релиз мыши
щелчок мыши мышью: вниз
-
Этот шаг использует
mouse:downможно контролировать. -
В функции обратного вызова слушайте нажатие
alt键. -
если нажать
alt键, установить значение записи开启移动状态. -
записать, где в данный момент находится мышь
xа такжеyкоординаты оси.
движение мыши мышь: двигаться
- Определите, нужно ли вам двигаться (третий шаг щелчка мыши).
- Для перемещения мгновенно переключайте режим просмотра холста
- переместить холст в
鼠标x和y轴坐标.
мышь отпустить мышь:вверх
- Заморозьте холст в координатах, где была отпущена мышь.
-
关闭移动状态(шаговый щелчок мышью)
<template>
<div>
<canvas id="canvas" width="400" height="400" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
// 初始化画布
const canvas = new fabric.Canvas('canvas')
// 矩形(参照物)
const rect = new fabric.Rect({
top: 130,
left: 130,
width: 40,
height: 40,
fill: 'orange'
})
// 圆形(参照物)
const circle = new fabric.Circle({
top: 150,
left: 150,
radius: 50,
fill: 'green'
})
canvas.add(rect, circle) // 将矩形和圆形添加到画布中
canvas.on('mouse:down', opt => { // 鼠标按下时触发
let evt = opt.e
if (evt.altKey === true) { // 是否按住alt
canvas.isDragging = true // isDragging 是自定义的,开启移动状态
canvas.lastPosX = evt.clientX // lastPosX 是自定义的
canvas.lastPosY = evt.clientY // lastPosY 是自定义的
}
})
canvas.on('mouse:move', opt => { // 鼠标移动时触发
if (canvas.isDragging) {
let evt = opt.e
let vpt = canvas.viewportTransform // 聚焦视图的转换
vpt[4] += evt.clientX - canvas.lastPosX
vpt[5] += evt.clientY - canvas.lastPosY
canvas.requestRenderAll() // 重新渲染
canvas.lastPosX = evt.clientX
canvas.lastPosY = evt.clientY
}
})
canvas.on('mouse:up', opt => { // 鼠标松开时触发
canvas.setViewportTransform(canvas.viewportTransform) // 设置此画布实例的视口转换
canvas.isDragging = false // 关闭移动状态
})
}
onMounted(() => {
init()
})
</script>
Выберите штат
🎁 Онлайн превью кейса в этом разделе - выбранное состояние
🎁 Репозиторий кода для этого раздела
Fabric.jsСоздаваемые элементы (графика, картинки, группы и т.д.) могут быть выбраны по умолчанию.
Можно ли его выбрать.
Могу ли я выбрать пустое место?
Выбранный стиль.
Отключить выбор
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const rect = new fabric.Rect({
top: 100,
left: 100,
width: 200,
height: 100,
fill: 'red'
})
// 元素禁止选中
rect.selectable = false
canvas.add(rect)
}
onMounted(() => {
init()
})
</script>
Невозможно выбрать элемент по пробелу
Синий треугольник можно выбрать, только полностью поместив мышь
<template>
<canvas width="400" height="400" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 三角形
const triangle1 = new fabric.Triangle({
top: 100,
left: 50,
width: 80, // 底边宽度
height: 100, // 底边到定点的距离
fill: 'blue',
})
// 选择三角形空白位置的时候无法选中,当perPixelTargetFind设为false后可以选中。默认值是false
triangle1.perPixelTargetFind = true
// 三角形
const triangle2 = new fabric.Triangle({
top: 100,
left: 200,
width: 80, // 底边宽度
height: 100, // 底边到定点的距离
fill: 'green',
})
canvas.add(triangle1, triangle2)
canvas.selectionFullyContained = true // 只选择完全包含在拖动选择矩形中的形状
}
onMounted(() => {
init()
})
</script>
Стиль выбора холста
<template>
<canvas width="200" height="200" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 圆形
const circle = new fabric.Circle({
radius: 30,
fill: '#f55',
top: 70,
left: 70
})
canvas.add(circle)
canvas.selection = true // 画布是否可选中。默认true;false 不可选中
canvas.selectionColor = 'rgba(106, 101, 216, 0.3)' // 画布鼠标框选时的背景色
canvas.selectionBorderColor = "#1d2786" // 画布鼠标框选时的边框颜色
canvas.selectionLineWidth = 6 // 画布鼠标框选时的边框厚度
canvas.selectionDashArray = [30, 4, 10] // 画布鼠标框选时边框虚线规则
canvas.selectionFullyContained = true // 只选择完全包含在拖动选择矩形中的形状
}
onMounted(() => {
init()
})
</script>
Пользовательские стили краев и углов управления
<template>
<canvas width="200" height="200" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 圆形
const circle = new fabric.Circle({
radius: 30,
fill: '#f55',
top: 70,
left: 70
})
circle.set({
borderColor: 'red', // 边框颜色
cornerColor: 'green', // 控制角颜色
cornerSize: 10, // 控制角大小
transparentCorners: false // 控制角填充色不透明
})
canvas.add(circle)
canvas.setActiveObject(circle) // 选中圆
}
onMounted(() => {
init()
})
</script>
Прозрачный угол управления
<template>
<canvas width="200" height="200" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 圆形
const circle = new fabric.Circle({
radius: 30,
fill: '#f55',
top: 70,
left: 70
})
circle.set({
borderColor: 'gray', // 边框颜色
cornerColor: 'black', // 控制角颜色
cornerSize: 12, // 控制角大小
transparentCorners: true // 控制角填充色透明
})
canvas.add(circle)
canvas.setActiveObject(circle) // 选中第一项
}
onMounted(() => {
init()
})
</script>
Настроить выбранный цвет фона
<template>
<canvas width="200" height="200" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 圆形
const circle = new fabric.Circle({
radius: 30,
fill: '#f55',
top: 70,
left: 70
})
circle.set({
selectionBackgroundColor: 'orange' // 选中后,背景色变橙色
})
canvas.add(circle)
canvas.setActiveObject(circle) // 选中第一项
}
onMounted(() => {
init()
})
</script>
без границ
<template>
<canvas width="200" height="200" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 圆形
const circle = new fabric.Circle({
radius: 30,
fill: '#f55',
top: 70,
left: 70
})
circle.hasBorders = false // 取消边框
canvas.add(circle)
canvas.setActiveObject(circle) // 选中第一项
}
onMounted(() => {
init()
})
</script>
нет угла управления
Отсутствие управляющих углов означало бы, что масштабированием и вращением нельзя напрямую управлять с помощью мыши, разрешены только манипуляции с перемещением.
<template>
<canvas width="200" height="200" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 圆形
const circle = new fabric.Circle({
radius: 30,
fill: '#f55',
top: 70,
left: 70
})
circle.hasControls = false // 禁止控制角
canvas.add(circle)
canvas.setActiveObject(circle) // 选中第一项
}
onMounted(() => {
init()
})
</script>
Пользовательский курсор наводится на объекты
В этом примере задается «указатель ожидания», который появляется, когда указатель мыши находится над элементом.
<template>
<canvas width="200" height="200" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 圆形
const circle = new fabric.Circle({
radius: 30,
fill: '#f55',
top: 70,
left: 70
})
canvas.hoverCursor = 'wait' // 设置等待指针
canvas.add(circle)
}
onMounted(() => {
init()
})
</script>
стиль при перемещении элемента
<template>
<canvas width="200" height="200" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 圆形
const circle = new fabric.Circle({
radius: 30,
fill: '#f55',
top: 70,
left: 70
})
circle.hasBorders = circle.hasControls = false
canvas.add(circle)
function animate(e, dir) {
if (e.target) {
fabric.util.animate({
startValue: e.target.get('angle'),
endValue: e.target.get('angle') + (dir ? 10 : -10),
duration: 100
})
fabric.util.animate({
startValue: e.target.get('scaleX'),
endValue: e.target.get('scaleX') + (dir ? 0.2 : -0.2),
duration: 100,
onChange: function(value) {
e.target.scale(value)
canvas.renderAll()
},
onComplete: function() {
e.target.setCoords()
}
})
}
}
canvas.on('mouse:down', function(e) { animate(e, 1) })
canvas.on('mouse:up', function(e) { animate(e, 0) })
}
onMounted(() => {
init()
})
</script>
Выбор коробки не разрешен
Выбор блока на холсте не разрешен, но разрешен выбор элемента.
<template>
<canvas width="200" height="200" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 圆形
const circle = new fabric.Circle({
radius: 30,
fill: '#f55',
top: 70,
left: 70
})
canvas.add(circle)
canvas.selection = false // 不允许直接从画布框选
}
onMounted(() => {
init()
})
</script>
обрезать
«Fabric.js обрезает исходный текст 1»
«Fabric.js обрезает исходный текст 2»
🎁 Онлайн-превью кейса раздела - обрезка
🎁 Репозиторий кода для этого раздела
Обрезать один рисунок
<template>
<canvas width="300" height="300" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 裁剪的图形
// clipPath从对象的中心开始定位,对象originX和originY不起任何作用,而clipPath originX和originY起作用。定位逻辑与fabric.Group相同
const clipPath = new fabric.Circle({
radius: 40,
left: -40,
top: -40
})
// 矩形
const rect = new fabric.Rect({
width: 200,
height: 100,
fill: 'red'
})
// 裁剪矩形
rect.clipPath = clipPath
canvas.add(rect)
}
onMounted(() => {
init()
})
</script>
обрезать группу
<template>
<canvas width="300" height="300" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
// 裁剪的图形
// clipPath从对象的中心开始定位,对象originX和originY不起任何作用,而clipPath originX和originY起作用。定位逻辑与fabric.Group相同
const clipPath = new fabric.Circle({
radius: 40,
left: -40,
top: -40
})
const group = new fabric.Group([
new fabric.Rect({ width: 100, height: 100, fill: 'red' }),
new fabric.Rect({ width: 100, height: 100, fill: 'yellow', left: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: 'blue', top: 100 }),
new fabric.Rect({
width: 100,
height: 100,
fill: 'green',
left: 100,
top: 100
})
])
// 裁剪一个组
group.clipPath = clipPath
canvas.add(group)
}
onMounted(() => {
init()
})
</script>
Объединить клипы
<template>
<canvas width="300" height="300" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const clipPath = new fabric.Group(
[
new fabric.Circle({ radius: 70, top: -70, left: -70 }),
new fabric.Circle({ radius: 40, top: -95, left: -95 }),
new fabric.Circle({ radius: 40, top: 15, left: 15 })
],
{ left: -95, top: -95 }
)
const group = new fabric.Group([
new fabric.Rect({ width: 100, height: 100, fill: 'red' }),
new fabric.Rect({ width: 100, height: 100, fill: 'yellow', left: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: 'blue', top: 100 }),
new fabric.Rect({
width: 100,
height: 100,
fill: 'green',
left: 100,
top: 100
})
])
group.clipPath = clipPath
canvas.add(group)
}
onMounted(() => {
init()
})
</script>
Вырезать и снова вырезать (комбинированные клипы)
<template>
<canvas width="300" height="300" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const clipPath = new fabric.Circle({ radius: 70, top: -50, left: -50 })
const innerClipPath = new fabric.Circle({ radius: 70, top: -90, left: -90 })
clipPath.clipPath = innerClipPath
const group = new fabric.Group([
new fabric.Rect({ width: 100, height: 100, fill: 'red' }),
new fabric.Rect({ width: 100, height: 100, fill: 'yellow', left: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: 'blue', top: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: 'green', left: 100, top: 100 }),
])
group.clipPath = clipPath
canvas.add(group)
}
onMounted(() => {
init()
})
</script>
Вложенные клипы в группы
<template>
<canvas width="300" height="300" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const clipPath = new fabric.Circle({ radius: 100, top: -100, left: -100 })
const small = new fabric.Circle({ radius: 50, top: -50, left: -50 })
const group = new fabric.Group([
new fabric.Rect({ width: 100, height: 100, fill: "red", clipPath: small }),
new fabric.Rect({ width: 100, height: 100, fill: "yellow", left: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: "blue", top: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: "green", left: 100, top: 100 }),
])
group.clipPath = clipPath
canvas.add(group)
}
onMounted(() => {
init()
})
</script>
обрезать с текстом
<template>
<canvas width="300" height="300" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas')
const clipPath = new fabric.Text(
'Hi I\'m the \nnew ClipPath!\nI hope we\'ll\nbe friends',
{ top: -100, left: -100 }
)
const group = new fabric.Group([
new fabric.Rect({ width: 100, height: 100, fill: "red" }),
new fabric.Rect({ width: 100, height: 100, fill: "yellow", left: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: "blue", top: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: "green", left: 100, top: 100 }),
])
group.clipPath = clipPath
canvas.add(group)
}
onMounted(() => {
init()
})
</script>
Обрезать холст
<template>
<canvas width="300" height="300" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas', {
backgroundColor: "#ddd"
})
const group = new fabric.Group([
new fabric.Rect({ width: 100, height: 100, fill: "red" }),
new fabric.Rect({ width: 100, height: 100, fill: "yellow", left: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: "blue", top: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: "green", left: 100, top: 100 }),
])
const clipPath = new fabric.Circle({ radius: 100, top: 0, left: 50 })
canvas.clipPath = clipPath
canvas.add(group)
}
onMounted(() => {
init()
})
</script>
Обрезать холст, но не элементы управления
<template>
<canvas width="300" height="300" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas', {
backgroundColor: "#ddd"
})
const group = new fabric.Group([
new fabric.Rect({ width: 100, height: 100, fill: "red" }),
new fabric.Rect({ width: 100, height: 100, fill: "yellow", left: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: "blue", top: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: "green", left: 100, top: 100 }),
])
// 裁剪区之外控件可见
canvas.controlsAboveOverlay = true
const clipPath = new fabric.Circle({ radius: 100, top: 0, left: 50 })
canvas.clipPath = clipPath
canvas.add(group)
}
onMounted(() => {
init()
})
</script>
анимация
<template>
<canvas width="300" height="300" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas('canvas', {
backgroundColor: "#ddd"
})
const clipPath = new fabric.Rect({ width: 100, height: 100, top: 0, left: 0 })
function animateLeft(){
clipPath.animate({
left: 200,
},{
duration: 900,
onChange: canvas.requestRenderAll.bind(canvas),
onComplete: animateRight
})
}
function animateRight(){
clipPath.animate({
left: 0,
},{
duration: 1200,
onChange: canvas.requestRenderAll.bind(canvas),
onComplete: animateLeft
})
}
function animateDown(){
clipPath.animate({
top: 100,
},{
duration: 500,
onChange: canvas.requestRenderAll.bind(canvas),
onComplete: animateUp
})
}
function animateUp(){
clipPath.animate({
top: 0,
},{
duration: 400,
onChange: canvas.requestRenderAll.bind(canvas),
onComplete: animateDown
})
}
const group = new fabric.Group([
new fabric.Rect({ width: 100, height: 100, fill: "red" }),
new fabric.Rect({ width: 100, height: 100, fill: "yellow", left: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: "blue", top: 100 }),
new fabric.Rect({ width: 100, height: 100, fill: "green", left: 100, top: 100 }),
], {
scale: 1.5
})
canvas.controlsAboveOverlay = true
animateLeft()
animateDown()
canvas.clipPath = clipPath
canvas.add(group)
}
onMounted(() => {
init()
})
</script>
Обрезка с абсолютным позиционированием
<template>
<canvas width="300" height="300" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas("canvas")
const clipPath = new fabric.Rect({ width: 300, height: 300, top: 0, left: 0, absolutePositioned: true })
const clipPath2 = new fabric.Rect({ width: 300, height: 300, top: 0, left: 0, absolutePositioned: true })
fabric.Image.fromURL("http://fabricjs.com/assets/dragon.jpg", function(img){
img.clipPath = clipPath
img.scaleToWidth(300)
canvas.add(img)
})
fabric.Image.fromURL("http://fabricjs.com/assets/dragon2.jpg", function(img){
img.clipPath =clipPath2
img.scaleToWidth(300)
img.top = 150
canvas.add(img)
})
}
onMounted(() => {
init()
})
</script>
Инвертированные пути клипа
<template>
<canvas width="300" height="300" id="canvas" style="border: 1px solid #ccc;"></canvas>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const canvas = new fabric.Canvas("canvas")
const clipPath = new fabric.Circle({ radius: 100, top: -200, left: -220 })
const clipPath2 = new fabric.Circle({ radius: 100, top: 0, left: -20 })
const clipPath3 = new fabric.Circle({ radius: 100, top: 0, left: -220 })
const clipPath4 = new fabric.Circle({ radius: 100, top: -200, left: -20 })
const g = new fabric.Group([ clipPath, clipPath2, clipPath3, clipPath4 ])
g.inverted = true // 颠倒裁剪
fabric.Image.fromURL("http://fabricjs.com/assets/dragon.jpg", function(img) {
img.clipPath = g
img.scaleToWidth(500)
canvas.add(img)
})
}
onMounted(() => {
init()
})
</script>
Сериализация
🎁 Онлайн превью кейса в разделе - Сериализация
🎁 Репозиторий кода для этого раздела
Так называемая сериализация на самом деле предназначена для преобразования содержимого холста вJSON, для удобства хранения.
ноFabric.jsПомимо преобразования холста в строку, вы также можете выводитьbase64а такжеsvg.
вывод JSON
<template>
<div>
<canvas id="canvas" width="200" height="200" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
// 初始化画布
const canvas = new fabric.Canvas('canvas')
console.log('canvas stringify ', JSON.stringify(canvas))
console.log('canvas toJSON', canvas.toJSON())
console.log('canvas toObject', canvas.toObject())
}
onMounted(() => {
init()
})
</script>
Откройте консоль, чтобы увидеть вывод.
Этот пример используется отдельноJSON.stringify(),canvas.toJSON()а такжеcanvas.toObject()Сериализировать пустой холст.
Fabric.jsпри условииtoJSONа такжеtoObjectДва метода преобразования холста и содержимого вJSON.
Поскольку выход этого примера является пустой холст, поэтому в выходном контентеobjectsПоле представляет собой пустой массив.
Если есть такие элементы, как фон и графика,objectsСоответствующие данные появятся в объекте.
Подробности можно посмотреть🎁 Онлайн превью кейса в разделе - Сериализация
вывод png (версия base64)
<template>
<div>
<canvas id="canvas" width="200" height="200" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
// 初始化画布
const canvas = new fabric.Canvas('canvas', {
backgroundColor: '#a5dee5'
})
const rect = new fabric.Rect({
left: 50,
top: 50,
height: 20,
width: 20,
fill: 'green'
})
const circle = new fabric.Circle({
left: 80,
top: 80,
radius: 40,
fill: "red"
})
canvas.add(rect, circle)
console.log('toPng', canvas.toDataURL('png')) // 在控制台输出 png(base64)
canvas.requestRenderAll()
}
onMounted(() => {
init()
})
</script>
использоватьcanvas.toDataURL('png')может выводитьpngкартина. Но эта операция может прерватьcanvas, поэтому выполните следующееcanvas.requestRenderAll().
Выведите следующий контент, вы можете скопировать этот абзац на адрес браузера, чтобы открыть его
data:image/png;base64,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
вывод SVG
<template>
<div>
<canvas id="canvas" width="200" height="200" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
// 初始化画布
const canvas = new fabric.Canvas('canvas', {
backgroundColor: '#a5dee5'
})
const rect = new fabric.Rect({
left: 50,
top: 50,
height: 20,
width: 20,
fill: 'green'
})
const circle = new fabric.Circle({
left: 80,
top: 80,
radius: 40,
fill: "red"
})
canvas.add(rect, circle)
console.log(canvas.toSVG()) // 输出 SVG
}
onMounted(() => {
init()
})
</script>
выходSVGОчень просто, звоните напрямуюcanvas.toSVG()Вот и все.
выход:
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="200" height="200" viewBox="0 0 200 200" xml:space="preserve">
<desc>Created with Fabric.js 4.6.0</desc>
<defs>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="#a5dee5"></rect>
<g transform="matrix(1 0 0 1 60.5 60.5)" >
<rect style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,128,0); fill-rule: nonzero; opacity: 1;" x="-10" y="-10" rx="0" ry="0" width="20" height="20" />
</g>
<g transform="matrix(1 0 0 1 120.5 120.5)" >
<circle style="stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(255,0,0); fill-rule: nonzero; opacity: 1;" cx="0" cy="0" r="40" />
</g>
</svg>
десериализовать
🎁 Онлайн превью кейса в этом разделе - десериализация
🎁 Репозиторий кода для этого раздела
Десериализация — этоJSONДанные отображаются на холсте.
Обычно данные, запрашиваемые из фона, отображаются на холсте.
<template>
<div>
<canvas id="canvas" width="200" height="200" style="border: 1px solid #ccc;"></canvas>
</div>
</template>
<script setup>
import { onMounted } from 'vue'
import { fabric } from 'fabric'
function init() {
const str = '{"version":"4.6.0","objects":[{"type":"rect","version":"4.6.0","originX":"left","originY":"top","left":50,"top":50,"width":20,"height":20,"fill":"green","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"rx":0,"ry":0},{"type":"circle","version":"4.6.0","originX":"left","originY":"top","left":80,"top":80,"width":80,"height":80,"fill":"red","stroke":null,"strokeWidth":1,"strokeDashArray":null,"strokeLineCap":"butt","strokeDashOffset":0,"strokeLineJoin":"miter","strokeUniform":false,"strokeMiterLimit":4,"scaleX":1,"scaleY":1,"angle":0,"flipX":false,"flipY":false,"opacity":1,"shadow":null,"visible":true,"backgroundColor":"","fillRule":"nonzero","paintFirst":"fill","globalCompositeOperation":"source-over","skewX":0,"skewY":0,"radius":40,"startAngle":0,"endAngle":6.283185307179586}],"background":"#ddd"}'
// 初始化画布
const canvas = new fabric.Canvas('canvas')
// 反序列化
canvas.loadFromJSON(str)
}
onMounted(() => {
init()
})
</script>
использоватьcanvas.loadFromJSON()Его можно десериализовать и передать вJSON格式Строка .
Этот вариантstrСохранить А.Fabric.jsэкспортированные данные.