В первой статье этой серии я рассмотрел причины использования Fabric.js, его объектную модель и иерархию объектов, а также различные типы объектов, доступных в Fabric, — простые фигуры, изображения и сложные пути. Я также описал, как выполнять простые операции с объектами Fabric на холсте. Теперь, когда большинство основ не в порядке, давайте перейдем к забавным вещам.
Анимация
Ни одна респектабельная библиотека canvas не обходится без средств анимации, и Fabric не является исключением. Учитывая мощную объектную модель Fabric и графические возможности, было бы стыдно не иметь встроенных помощников анимации.
Помните, как легко изменить свойство любого объекта? Вы просто вызываете метод set, передавая соответствующие значения:
rect.set («угол», 45);
Анимировать объект так же просто. Каждый объект Fabric имеет одушевленный метод, который … оживляет этот объект.
rect.animate ('angle', 45, { onChange: canvas.renderAll.bind (canvas) });
Первый аргумент — это свойство анимации, а второй аргумент — конечное значение анимации. Если прямоугольник имеет угол -15 °, и вы передаете 45 во втором аргументе, прямоугольник анимируется от -15 ° до 45 °. Третий аргумент — необязательный объект, определяющий более тонкие детали анимации, такие как продолжительность, обратные вызовы, замедление и так далее. Я покажу примеры этого в ближайшее время.
Одна удобная особенность метода animate заключается в том, что он поддерживает относительные значения. Например, если вы хотите анимировать левое свойство объекта на 100 пикселей, вы можете сделать это следующим образом:
rect.animate ('left', '+100', {onChange: canvas.renderAll.bind (canvas)});
Аналогично, вращение объекта на 5 градусов против часовой стрелки может быть выполнено следующим образом:
rect.animate ('angle', '-5', {onChange: canvas.renderAll.bind (canvas)});
Вы можете удивиться, почему я всегда указываю здесь onChange
вызов onChange
. Как я уже упоминал, третий аргумент является необязательным, но вызов canvas.renderAll
для каждого кадра анимации позволяет увидеть фактическую анимацию. Когда вы вызываете метод animate, он только со временем анимирует значение свойства, следуя определенному алгоритму (например, easing
). Таким образом, rect.animate('angle', 45)
изменяет угол объекта, но не будет перерисовывать холст после каждого изменения угла. И, очевидно, вам нужен этот рендеринг, чтобы увидеть анимацию.
Помните, что под поверхностью холста есть целая объектная модель. Объекты имеют свои собственные свойства и отношения, и холст отвечает только за проекцию существования объектов во внешний мир.
Причина, по которой animate не выполняет автоматическую визуализацию холста после каждого изменения, заключается в производительности. В конце концов, вы можете иметь сотни или тысячи объектов анимации на холсте, и было бы неразумно, если бы каждый из них пытался перерисовать экран. В большинстве случаев вам, вероятно, нужно явно указать canvas.renderAll
в качестве обратного вызова onChange
.
Другие варианты, которые вы можете передать animate:
-
from
Позволяет указать начальное значение анимируемого свойства (если вы не хотите использовать текущее значение). -
duration
умолчанию до 500 мс. Эта опция может быть использована для изменения продолжительности анимации. -
onComplete
Обратный вызов, который вызывается в конце анимации. -
easing
Функция ослабления.
Все эти варианты должны быть понятны, кроме, возможно, easing
. Давайте внимательнее посмотрим на это.
По умолчанию animate использует линейную функцию для анимации. Если это не то, что вам нужно, в fabric.util.ease
есть множество вариантов fabric.util.ease
. Например, если вы хотите переместить объект вправо бодрым способом, сделайте это:
rect.animate ('left', 500, { onChange: canvas.renderAll.bind (canvas), продолжительность: 1000, ослабление: fabric.util.ease.easeOutBounce });
Обратите внимание, что fabric.util.ease.easeOutBounce
является опцией ослабления. Другими известными параметрами являются easeInCubic
, easeOutCubic
, easeInElastic
, easeOutElastic
, easeInBounce
и easeOutExpo
.
Просто чтобы дать вам некоторое представление о том, что становится возможным с помощью анимации в Fabric, вы можете анимировать угол объекта, чтобы он вращался; анимируйте левый или верхний свойства, чтобы заставить его двигаться; оживите его ширину и высоту, чтобы он уменьшался и рос; оживить непрозрачность, чтобы заставить его исчезать и исчезать; и так далее.
Фильтры изображений
В первой статье этой серии вы увидели, как работать с изображениями в Fabric. Есть конструктор fabric.Image
который принимает элемент изображения. Также fabric.Image.fromURL
метод fabric.Image.fromURL
, который может создать экземпляр изображения из строки URL. Любое из этих изображений может быть выброшено и отображено на холсте, как и любой другой объект.
Но как бы ни было интересно работать с изображениями, еще круче применить к ним фильтры изображений. По умолчанию Fabric предоставляет несколько фильтров (вы можете просмотреть их здесь ) и упрощает определение собственных фильтров. Некоторые из встроенных фильтров, с которыми вы, возможно, уже знакомы, — это фильтр для удаления белого фона, фильтр в градациях серого или фильтры инверсии или яркости. Другие могут быть немного менее знакомы, такие как прозрачность градиента, сепия или шум.
Каждый экземпляр fabric.Image
имеет свойство filters, представляющее собой простой массив фильтров. Каждый из фильтров в этом массиве является экземпляром одного из фильтров Fabric или экземпляром пользовательского фильтра.
Вот код, который вы используете для создания изображения в градациях серого. Рисунок 1 показывает результаты.
fabric.Image.fromURL ('pug.jpg', function (img) { // добавить фильтр img.filters.push (новая ткань. Image.filters.Grayscale ()); // применяем фильтры и перерисовываем холст, когда закончим img.applyFilters (canvas.renderAll.bind (холст)); // добавить изображение на холст canvas.add (IMG); });
Рисунок 1. Применение фильтра изображения в градациях серого
И вот, как создать версию изображения в сепии, которая приводит к эффектам изображения, показанным на рисунке 2 .
fabric.Image.fromURL ('pug.jpg', function (img) { img.filters.push (новая ткань. Image.filters.Sepia ()); img.applyFilters (canvas.renderAll.bind (холст)); canvas.add (IMG); });
Рисунок 2. Применение фильтра изображения Sepia
Поскольку свойство filters представляет собой простой массив, вы можете выполнить с ним любую операцию, которую хотите, обычным способом — удалить фильтр (с помощью pop, splice или shift), добавить фильтр (с помощью push, splice, unshift) или даже объединить несколько фильтров. Все фильтры, присутствующие в массиве фильтров, будут применяться один за другим при вызове applyFilters
.
Вот как вы можете создать изображение, которое будет и сепией, и ярким. На рисунке 3 показаны результаты.
fabric.Image.fromURL ('pug.jpg', function (img) { img.filters.push ( новая ткань. Image.filters.Sepia (), новая ткань. Image.filters.Brightness ({яркость: 100})); img.applyFilters (canvas.renderAll.bind (холст)); canvas.add (IMG); });
Рисунок 3. Объединение сепии и фильтра ярких изображений
Обратите внимание, что я также передал объект { brightness: 100 }
в фильтр яркости. Это связано с тем, что некоторые фильтры можно применять без какой-либо дополнительной настройки (например, оттенки серого, инвертирование, сепия), а другие обеспечивают более точное управление их поведением. Для фильтра яркости это фактический уровень яркости (0–255)
. Для шумового фильтра это значение шума (0–1000)
. Для фильтра удаления белого это пороговые значения и значения расстояния. И так далее.
Теперь, когда вы знакомы с тканевыми фильтрами, пришло время вырваться из коробки и создать свой собственный. Шаблон для создания фильтра довольно прост. Вам нужно создать класс, а затем определить метод applyTo
. При желании вы можете toJSON
метод toJSON
(поддержка сериализации JSON) или метод initialize
(поддержка необязательных параметров). Ниже приведен пример кода, результаты которого показаны на рисунке 4 .
fabric.Image.filters.Redify = fabric.util.createClass ({ тип: «Redify», applyTo: function (canvasEl) { var context = canvasEl.getContext ('2d'), imageData = context.getImageData (0, 0, canvasEl.width, canvasEl.height), data = imageData.data; для (var i = 0, len = data.length; i <len; i + = 4) { данные [i + 1] = 0; данные [i + 2] = 0; } context.putImageData (imageData, 0, 0); } }); fabric.Image.filters.Redify.fromObject = function (object) { вернуть новый fabric.Image.filters.Redify (object); };
Рисунок 4. Применение пользовательского фильтра изображений
Не углубляясь в этот код, основное действие происходит в цикле, где я заменяю зеленые (data[i+1])
и синие (data[i+2])
компоненты каждого пикселя на 0, по существу удаляя их. Красный компонент стандартных значений RGB остается нетронутым, по существу окрашивая все изображение в красный цвет. Как видите, метод applyTo
передается в основной элемент canvas, представляющий все изображение. Оттуда вы можете перебирать его пиксели (getImageData().data)
, изменяя их по своему усмотрению.
Цвета
Независимо от того, удобнее ли вам работать с шестнадцатеричным, RGB или RGBA-цветом, Fabric предоставляет основу из сплошного цвета, которая поможет вам выразить себя наиболее естественно. Вот несколько способов определения цвета в Fabric:
новая ткань. Цвет ('# f55'); новая ткань. Цвет ('# 123123'); новая ткань. Цвет ('356735'); новая ткань. Цвет ('rgb (100,0,100)'); новая ткань. Цвет ('rgba (10, 20, 30, 0.5)');
Конверсия также проста. Метод toHex()
преобразует экземпляры цветов в шестнадцатеричное представление, toRgb()
в цвета RGB, а toRgba()
в RGB с альфа-каналом.
новая ткань. Цвет ('# f55'). toRgb (); // "rgb (255,85,85)" новая ткань. Цвет ('rgb (100,100,100)'). toHex (); // "646464" новая ткань. Цвет ('fff'). toHex (); // "FFFFFF"
Преобразование — не единственный шаг, который вы можете сделать с цветами. Вы также можете наложить один цвет на другой или превратить его в версию в оттенках серого.
var redish = new fabric.Color ('# f55'); var greenish = new fabric.Color ('# 5f5'); redish.overlayWith (зеленовато) .toHex (); // "AAAA55" . Redish.toGrayscale () toHex (); // "A1A1A1"
Градиенты
Еще более выразительный способ работы с цветами — через градиенты. Градиенты позволяют смешивать один цвет с другим, создавая потрясающие графические эффекты.
Fabric поддерживает градиенты с помощью метода setGradientFill
, который определяется для всех объектов. Вызов setGradientFill
похож на установку значения заливки объекта, за исключением того, что вы заполняете объект градиентом, а не одним цветом. Ниже приведен пример кода с визуальным эффектом, показанным на рисунке 5 .
var circle = new fabric.Circle ({ осталось: 100, верх: 100, радиус: 50 }); circle.setGradientFill ({ х1: 0, у1: 0, х2: 0, у2: круг.высота, colorStops: { 0: «# 000», 1: '#fff' } });
Рисунок 5. Применение градиентной заливки к объекту
В этом примере я создаю круг в местоположении 100,100,
с радиусом 50 пикселей. Затем я устанавливаю его заливку с градиентом от белого к черному, который охватывает всю высоту этого круга.
Аргумент, передаваемый методу, является объектом параметров, который ожидает две пары координат ( x1, y1
и x2, y2
), а также объект colorStops
. Координаты указывают, где начинается градиент и где он заканчивается. Объект colorStops
указывает, из каких цветов сделан градиент. Вы можете задать любое количество остановок цвета, если они варьируются от 0 до 1 (например, 0, 0,1, 0,3, 0,5, 0,75, 1 и т. Д.). Ноль (0) представляет начало градиента, а 1 — его конец.
Вот код, который создает красно-синий градиент слева направо. Рисунок 6 показывает результаты.
circle.setGradientFill ({ х1: 0, y1: circle.height / 2, х2: круговая ширина, у2: круг.высота / 2, colorStops: { 0: "красный", 1: "синий" } });
Рисунок 6. Градиент, созданный с использованием цветовых остановок
В приведенном ниже коде показан пятиступенчатый градиент радуги с цветами, охватывающими даже интервалы в 20 процентов Рисунок 7 показывает результаты.
circle.setGradientFill ({ х1: 0, y1: circle.height / 2, х2: круговая ширина, у2: круг.высота / 2, colorStops: { 0: "красный", 0,2: «апельсин», 0,4: «желтый», 0,6: «зеленый», 0,8: "синий", 1: "фиолетовый" } });
Рисунок 7. Радужный градиент
Какие классные версии вы можете придумать?
Текст
Что если вы хотите отобразить на холсте не только изображения и векторные фигуры, но и текст? Ткань покрыла вас fabric.Text
. fabric.Text
объекты.
Есть две причины для предоставления текстовой абстракции в Fabric. Во-первых, он позволяет работать с текстом объектно-ориентированным способом. Родные методы Canvas, как обычно, позволяют вам заполнять или перемещать текст только на очень низком уровне. fabric.Text
экземпляры fabric.Text
, вы можете работать с текстом точно так же, как вы работаете с любым другим объектом Fabric — перемещать его, масштабировать, изменять его свойства и т. Д.
Вторая причина состоит в том, чтобы предоставить гораздо более богатую функциональность, чем то, что дает нам элемент canvas. Некоторые из дополнений Ткани включают в себя:
Многострочная поддержка. К сожалению, собственные текстовые методы просто игнорируют новые строки.
Выравнивание текста слева, по центру и справа. Полезно при работе с несколькими строками текста.
Фон текста Фон также учитывает выравнивание текста.
Оформление текста Подчеркивание, подчеркивание и зачеркивание.
Высота строки Полезно при работе с несколькими строками текста.
Вот пример «Привет, мир»:
var text = new fabric.Text ('hello world', {слева: 100, сверху: 100}); canvas.add (текст); });
Это верно! Отображать текст на холсте так же просто, как добавить экземпляр fabric.Text
в указанное место. Как видите, единственным обязательным параметром является фактическая текстовая строка. Второй аргумент — это обычный объект параметров, который может иметь любые обычные свойства, такие как left, top, fill, opacity и т. Д.
Но, конечно, текстовые объекты также имеют свои собственные свойства, связанные с текстом. Давайте посмотрим на некоторые из них.
семейство шрифтов
По умолчанию установлено fontFamily
Times New Roman, свойство fontFamily
позволяет изменять семейство шрифтов, используемых для визуализации текстового объекта. Изменение свойства немедленно отображает текст новым шрифтом. На рисунке 8 показаны эффекты, созданные с помощью следующего кода.
var comicSansText = new fabric.Text («Я нахожусь в Comic Sans», { fontFamily: 'Comic Sans' });
Рисунок 8. Изменение свойства fontFamily
размер шрифта
Размер шрифта контролирует размер отображаемого текста. Обратите внимание, что в отличие от других объектов в Fabric, вы не можете напрямую изменять свойства ширины и высоты текстового объекта. Вместо этого вам нужно изменить значение fontSize
чтобы увеличить текстовые объекты, как вы можете видеть на рисунке 9 . (Либо так, либо вы можете использовать свойства scaleX/scaleY
.)
var text40 = new fabric.Text ("Я на fontSize 40", { fontSize: 40 }); var text20 = new fabric.Text ("Я в fontSize 20", { fontSize: 20 });
Рисунок 9. Управление размером шрифта
FontWeight
Вес шрифта позволяет сделать текст более толстым или тонким. Как и в CSS, вы можете использовать ключевые слова (например, обычный или полужирный — см. Рисунок 10 ) или числа (100, 200, 400, 600, 800). Возможность использования определенных весов зависит от наличия этого веса для выбранного шрифта. Если вы используете удаленный шрифт, вы должны быть уверены, что вы предоставили как обычные, так и полужирные (а также любой другой требуемый вес) определения шрифтов.
var normalText = new fabric.Text ("Я обычный текст", { fontWeight: 'normal' }); var boldText = new fabric.Text ("Я выделен жирным шрифтом", { fontWeight: «жирный» });
Рисунок 10. Размер шрифта можно контролировать с помощью ключевых слов или числовых значений
textDecoration
Текстовое оформление используется для добавления подчеркивания, наложения или зачеркивания к тексту. Опять же, это похоже на CSS, но Fabric идет немного дальше и позволяет вам использовать любую комбинацию этих украшений вместе. Таким образом, вы можете иметь подчеркнутый и подчеркнутый текст, подчеркнутый зачеркиванием и т. Д., Как вы можете видеть на рисунке 11 .
var underlineText = new fabric.Text ("Я подчеркнул текст", { textDecoration: 'подчеркивание' }); var strokeThroughText = new fabric.Text ("Я пропущен текст", { textDecoration: «сквозной» }); var overlineText = new fabric.Text ("Я выделен текстом", { textDecoration: «зачеркнуто» });
Рисунок 11. Примеры оформления текста
textShadow
Текстовые тени состоят из четырех компонентов: цвет, горизонтальное смещение, вертикальное смещение и размер размытия. Эти эффекты могут быть очень знакомы, если вы работали с тенями в CSS. Возможны многие комбинации (см. Рисунок 12 ) путем изменения этих значений.
var shadowText1 = new fabric.Text ("Я текст с тенью", { textShadow: 'rgba (0,0,0,0.3) 5px 5px 5px' }); var shadowText2 = new fabric.Text ("И еще одна тень", { textShadow: 'rgba (0,0,0,0.2) 0 0 5px' }); var shadowText3 = new fabric.Text ("Lorem ipsum dolor sit", { textShadow: 'green -5px -5px 3px' });
Рисунок 12. Примеры текстовых теней
стиль шрифта
Стиль шрифта может быть одним из двух значений: обычный или курсив. Это похоже на одноименное свойство CSS. Следующий код показывает несколько примеров использования fontStyle
, а рисунок 13 показывает результаты.
var italicText = new fabric.Text ("Очень необычный текст курсивом", { fontStyle: 'курсив', fontFamily: «Вкусный» }); var anotherItalicText = new fabric.Text ("еще один текст курсивом", { fontStyle: 'курсив', fontFamily: «Текст Hoefler» });
Рисунок 13. Примеры стилей курсивного курсива
strokeStyle и strokeWidth
Комбинируя strokeStyle
(цвет обводки) и strokeWidth
(его ширину), вы можете добиться некоторых интересных текстовых эффектов, как показано на рисунке 14 . Вот пара примеров кода:
var textWithStroke = new fabric.Text ("Текст с обводкой", { strokeStyle: '# ff1318', длина хода: 1 }); var loremIpsumDolor = new fabric.Text ("Lorem ipsum dolor", { fontFamily: «Воздействие», strokeStyle: '# c3bfbf', ход Ширина: 3 });
Рисунок 14. Текстовые эффекты с использованием strokeStyle и strokeWidth
TextAlign
Выравнивание текста полезно при работе с многострочным текстовым объектом. При использовании однострочного текстового объекта ширина ограничивающего прямоугольника всегда соответствует ширине этой линии, поэтому выравнивать нечего.
Допустимые значения для textAlign
: слева, по центру и справа. На рисунке 15 показан текст, выровненный по правому краю.
var text = 'isna multilinentextnaligned right!'; var alignRightText = new fabric.Text (text, { textAlign: 'правильно' });
Рисунок 15. Выровненный справа текст
высота линии
Еще одно свойство, которое может быть знакомо по CSS — это lineHeight
. Это позволяет изменять вертикальный интервал между строками текста в многострочном тексте. В следующем примере для первого фрагмента текста lineHeight
установлено значение 3, а для второго — 1. Результаты, которые вы видите, показаны на рисунке 16 .
var lineHeight3 = new fabric.Text ('Lorem ipsum ...', { lineHeight: 3 }); var lineHeight1 = new fabric.Text ('Lorem ipsum ...', { lineHeight: 1 });
Рисунок 16. Примеры высоты линии
фоновый цвет
Наконец, backgroundColor
— это то, что позволяет дать тексту фон. Обратите внимание, что фон заполняет только пространство, занимаемое символами текста, а не весь ограничивающий прямоугольник, как вы можете видеть на рисунке 17 . Это означает, что выравнивание текста изменяет способ отображения фона текста, как и высота строки, поскольку фон учитывает вертикальный интервал между строками, созданными lineHeight
.
var text = 'this is multilinentextnwithn custom lineheightn & background'; var textWithBackground = new fabric.Text (text, { backgroundColor: 'rgb (0,200,0)' });
Рисунок 17. Фоновые эффекты текста
События
Архитектура, управляемая событиями, является основой для удивительной мощи и гибкости в рамках. Fabric не является исключением и предоставляет обширную систему событий, начиная с низкоуровневых событий мыши и заканчивая объектными событиями высокого уровня.
Эти события позволяют вам использовать различные моменты различных действий, происходящих на холсте. Хотите знать, когда была нажата мышь? Просто наблюдайте за mouse:down
событие mouse:down
. Как насчет того, когда объект был добавлен на холст? В этом случае object:added
для вас. А как насчет того, когда весь холст перерисовывается? Просто используйте after:render
.
API события очень прост и напоминает API jQuery, Underscore.js или других популярных библиотек JS. Есть метод on
для инициализации прослушивателя событий и метод off
для его удаления.
Вот пример:
var canvas = new fabric.Canvas ('...'); canvas.on ('mouse: down', function (options) { console.log (options.e.clientX, options.e.clientY); });
В этом коде я добавляю слушатель события mouse:down
на холст и назначаю ему обработчик событий, который будет записывать координаты того, где произошло событие. Другими словами, обработчик будет регистрировать, где именно на холсте была нажата мышь. Обработчик событий получает объект параметров, который имеет два свойства: e
, которое является исходным событием, и target
, которая является объектом щелчка на холсте, если таковой имеется. Событие присутствует всегда, но цель существует, только если пользователь действительно щелкает объект на холсте. Кроме того, цель передается обработчикам событий только там, где это имеет смысл — например, для mouse:down
но не для after:render
(что означает, что весь холст был перерисован).
canvas.on ('mouse: down', function (options) { if (options.target) { console.log («объект был нажат!», options.target.type); } });
В этом примере будет записано «объект был нажат!», Если щелкнуть объект. Это также добавит тип объекта, по которому щелкнули.
Некоторыми из других событий уровня мыши, доступных в Fabric, являются mouse:move
и mouse:up
. Общие события включают after:render
, а также есть связанные с выбором события: before:selection:created
, selection:created
, selection:cleared
. И, наконец, события объекта включают в себя object:modified
, object:selected
, object:moving
, object:scaling
, object:rotating
и object:added
.
События, подобные object:moving
(или object:scaling
), запускаются непрерывно каждый раз, когда объект перемещается (или масштабируется) даже на пиксель. С другой стороны, такие события, как object:modified
или selection:created
, запускаются только в конце действия (изменение объекта или создание выделения).
Обратите внимание, как события прикрепляются прямо на холст ( canvas.on('mouse:down', ...)
). Как вы можете себе представить, это означает, что все события ограничены экземплярами canvas. Если у вас есть несколько холстов на странице, вы можете прикрепить к каждому из них разных слушателей событий. Все они независимы и уважают только те события, которые им назначены.
Для удобства Fabric продвигает систему событий еще дальше и позволяет подключать слушателей непосредственно к объектам Canvas. Посмотрите на этот код:
var rect = new fabric.Rect ({width: 100, height: 50, fill: 'green'}); rect.on ('selected', function () { console.log ('выделен прямоугольник'); }); var circle = new fabric.Circle ({радиус: 75, заливка: «синий»}); circle.on ('selected', function () { console.log («выбрал круг»); });
Здесь я присоединяю слушателей событий непосредственно к экземплярам прямоугольника и круга. Вместо object:selected
, я использую выбранное событие. Точно так же я мог бы использовать измененное событие ( object:modified
при присоединении к холсту), событие поворота (object:rotating
при прикреплении к холсту) и так далее.
Посмотрите эту демонстрацию событий для более подробного изучения системы событий Fabric.
В следующей статье я перейду к более продвинутым функциям: группам, сериализации (и десериализации) и классам.
Эта статья была первоначально опубликована по адресу http://msdn.microsoft.com/en-us/magazine/jj856929.aspx и воспроизводится здесь с разрешения.