Перейти к содержимому

HeadPaint API

Методы editorAPI.headPaint: регистрация инструментов, обработчики рисования, цвет, прозрачность, палитра и ограничения истории изменений.

editorAPI.headPaint расширяет панель HeadPaint. Объект появляется после подготовки интерфейса, непосредственно перед bde:started. При запуске установленного плагина дождитесь этого момента; при ручном запуске кода в уже готовом редакторе он доступен сразу. Порядок запуска описан в справке о событиях.

Все три метода синхронные и возвращают undefined. Они меняют общие настройки HeadPaint, которыми пользуются редактор и другие плагины.

addTool: регистрация инструмента

editorAPI.headPaint.addTool(tool);

Метод добавляет кнопку в набор инструментов HeadPaint и обновляет панель. Инструмент с таким же id заменяется новым описанием и перемещается в конец списка пользовательских инструментов. Используйте собственный префикс, например my-plugin-picker, и не занимайте имена встроенных инструментов.

Поле tool Назначение
id Строковый идентификатор. Без объекта или строкового id регистрация игнорируется. Используйте непустое значение.
icon Один CSS-класс иконки, например icon-pipette. По умолчанию icon-box.
nameHide Текст подсказки. Если отсутствует, используется name, затем id.
name Запасное название инструмента.
hoverTitle Заголовок подсказки. По умолчанию заголовок группы инструментов.
onSelect({ headPaint, editor }) Необязательный обработчик нажатия кнопки после выбора инструмента. Передаются внутренние объекты редактора.
onPaint(data) Необязательный обработчик попадания по текстуре при рисовании. Должен синхронно выполнить действие и вернуть результат.

Передавайте функции в обработчики. async-обработчик не ожидается: возвращённый Promise будет обработан как обычный результат, а изменение текстуры может произойти уже после обновления отображения.

Поля аргумента onPaint:

Поле Значение
head Объект головы, на которой выполняется действие.
canvas, context Canvas текстуры и его CanvasRenderingContext2D. Изменения рисует сам обработчик.
x, y Исходные координаты попадания по развёртке текстуры.
drawX, drawY Координаты пикселя на Canvas с учётом выбранного слоя и направления оси Y. Для записи пикселя используйте их.
localX Координата X внутри половины развёртки, от 0 до 31.
faceName Имя грани.
color Текущий цвет в строковом HEX-формате.
opacity Альфа от 0 до 255.
outerLayer Выбран ли внешний слой головы.
blendMode Текущий режим смешивания HeadPaint.
replacePixel true, если blendMode === 'replace'.
smartGrid Включена ли умная сетка.

Сам факт передачи blendMode, opacity или smartGrid не применяет их к вашим операциям Canvas. Плагин должен реализовать нужное смешивание и размер мазка. Например, context.putImageData() записывает RGBA напрямую и не использует globalAlpha.

Возврат из onPaint определяет обработку результата:

Результат Поведение
false Пропустить последующее обновление текстуры и событие рисования. Уже выполненные записи в Canvas не отменяются.
Массив объектов [{ drawX, drawY }, ...] Сообщить, какие пиксели обработаны. Координаты округляются вниз, пиксели за пределами Canvas и повторы в текущем мазке пропускаются.
Другой результат, в том числе undefined Считать обработанным один пиксель с исходными drawX, drawY.

Если остались допустимые новые пиксели, редактор отправляет bde:headPaint:paint для каждого и вызывает head.updatePaintTexture(). Возвращённые координаты сами по себе ничего не рисуют. Объекты head, headPaint и editor дают доступ к внутренним возможностям, устройство которых может меняться между версиями.

setColor: цвет и прозрачность

editorAPI.headPaint.setColor(color, opacity = null);

color принимает только строку #RGB или #RRGGBB. Пробелы по краям удаляются, короткая запись разворачивается, итоговое значение сохраняется в верхнем регистре. Имена CSS-цветов, rgb(), THREE.Color и HEX с альфой не поддерживаются.

opacity задаётся отдельно, в диапазоне 0-255. Значение преобразуется через Number(), ограничивается диапазоном и округляется до целого. null сохраняет текущую прозрачность. Неверный цвет или нечисловая альфа отменяют весь вызов без ошибки.

editorAPI.headPaint.setColor('#fa0', 128); // #FFAA00, альфа 128
editorAPI.headPaint.setColor('#336699'); // Альфа остаётся прежней.

Метод задаёт цвет для последующего рисования. Он не перекрашивает текстуру, не добавляет цвет в палитру и не вызывает отдельное обновление элементов панели. Отдельного публичного getter для цвета и метода setOpacity нет; обработчик инструмента получает текущие значения в onPaint.

setUpdateColorList: обновление палитры

editorAPI.headPaint.setUpdateColorList(enabled = true);

Передайте false, чтобы отключить автоматическое пополнение палитры там, где встроенные инструменты учитывают этот флаг, или true, чтобы включить его обратно. Метод присваивает флаг без преобразования типа, поэтому передавайте именно boolean.

Это не блокировка палитры: встроенная пипетка и отдельные действия интерфейса могут добавлять цвет независимо от флага. Пользовательский onPaint не пополняет палитру автоматически. В публичном API нет методов чтения, очистки или полной замены палитры.

История, активация и завершение

Регистрация не включает режим HeadPaint и не выбирает новый инструмент. Пользователь открывает HeadPaint и нажимает его кнопку. Публичных selectTool, removeTool, beginStroke или endStroke нет. Повторная регистрация с тем же id обновляет описание, но не является выгрузкой плагина.

Не рассчитывайте на автоматический Undo для собственной кисти. В текущей реализации перед onPaint сохраняется исходное состояние головы, но пользовательская ветка не помечает команду как изменённую. Одного рисования на Canvas и возврата координат недостаточно, чтобы завершённый мазок попал в историю. У встроенных инструментов эта отметка выполняется отдельно. Для полноценной редактирующей кисти требуется отдельная работа с внутренней историей редактора и проверка совместимости.

События HeadPaint отправляются в window как CustomEvent:

Событие Когда возникает
bde:headPaint:started Первое изменение мазка во встроенной ветке рисования.
bde:headPaint:paint Обработанное изменение или пиксель. Пользовательский инструмент добавляет поле customTool со своим id.
bde:headPaint:ended Завершение мазка с изменениями, попавшими в историю.
bde:headPaint:fillStarted, bde:headPaint:fillEnded Начало и конец обычной заливки связанной области. Ветка заливки с модификаторами их не отправляет.

Общие поля event.detail: tool, color, opacity, outerLayer, blendMode. События рисования и заливки дополнительно передают head, x, y, faceName; у paint могут быть drawX, drawY, размеры области и другие сведения конкретного инструмента. У ended координат и head нет. Пользовательская ветка сама по себе не вызывает started и ended, поэтому не используйте их как универсальные границы работы всех расширений.

Минимальный пример

Инструмент ниже считывает RGBA выбранного пикселя. Он меняет текущий цвет, но не редактирует текстуру и не нуждается в записи мазка в историю.

(() => {
function init() {
window.editorAPI.headPaint.addTool({
id: 'sample-plugin-pixel-picker',
icon: 'icon-pipette',
name: 'Цвет пикселя',
onPaint({ context, drawX, drawY }) {
const [r, g, b, a] = context.getImageData(drawX, drawY, 1, 1).data;
const color = '#' + [r, g, b]
.map(value => value.toString(16).padStart(2, '0'))
.join('');
window.editorAPI.headPaint.setColor(color, a);
return false;
},
});
}
if (window.editorAPI?.headPaint) init();
else window.addEventListener('bde:started', init, { once: true });
})();

Подготовка файла, установка и проверка инструмента описаны в руководстве «Добавить инструмент HeadPaint».

Применить на практике