620 lines
24 KiB
JavaScript
620 lines
24 KiB
JavaScript
import { MaskManager } from './mask_manager.js';
|
|
import { BrushManager } from './brush_manager.js';
|
|
import { RemoveBgManager } from './removebg.js';
|
|
import { MagicWandManager } from './magic_wand_manager.js';
|
|
import { MaskPainterManager } from './mask_painter_manager.js';
|
|
|
|
const textIconPath = new Path2D("M5 4v2h5v12h4V6h5V4H5z");
|
|
const maskIconPath = new Path2D("M2 2 H22 V22 H2 Z M12 12 m-6 0 a6 6 0 1 0 12 0 a6 6 0 1 0 -12 0");
|
|
const FONT_LIST = [
|
|
// Sans-serif
|
|
"Arial",
|
|
"Verdana",
|
|
"Tahoma",
|
|
"Trebuchet MS",
|
|
"Impact",
|
|
"Lucida Sans Unicode",
|
|
// Serif
|
|
"Georgia",
|
|
"Times New Roman",
|
|
"Garamond",
|
|
// Monospace
|
|
"Courier New",
|
|
"Lucida Console"
|
|
];
|
|
function ensureToolbarStyles() {
|
|
const styleId = 'contextual-toolbar-styles';
|
|
if (document.getElementById(styleId)) return;
|
|
const style = document.createElement('style');
|
|
style.id = styleId;
|
|
style.innerHTML = `
|
|
#contextual-text-toolbar {
|
|
/* MODIFIÉ : Fond blanc avec 85% d'opacité */
|
|
background-color: rgba(255, 255, 255, 0.5) !important;
|
|
backdrop-filter: blur(8px);
|
|
-webkit-backdrop-filter: blur(8px);
|
|
/* MODIFIÉ : Bordure grise subtile */
|
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px H12px rgba(0,0,0,0.2);
|
|
padding: 2px;
|
|
display: flex;
|
|
gap: 4px;
|
|
}
|
|
#contextual-text-toolbar button {
|
|
background-color: transparent;
|
|
border: none;
|
|
/* MODIFIÉ : Icônes sombres pour la lisibilité sur fond blanc */
|
|
color: #333;
|
|
font-size: 18px;
|
|
cursor: pointer;
|
|
padding: 4px;
|
|
border-radius: 4px;
|
|
transition: background-color 0.2s;
|
|
}
|
|
#contextual-text-toolbar button:hover {
|
|
/* MODIFIÉ : Effet de survol gris très clair */
|
|
background-color: rgba(0, 0, 0, 0.05);
|
|
}
|
|
`;
|
|
document.head.appendChild(style);
|
|
}
|
|
export class Toolbar {
|
|
constructor(node) {
|
|
this.node = node;
|
|
this.width = 40;
|
|
this.activeTool = null;
|
|
this.textElements = [];
|
|
this.activeTextarea = null;
|
|
this.lastClickTime = 0;
|
|
this.lastClickTarget = null;
|
|
this.clickTimeout = null;
|
|
this.tools = [
|
|
{ name: 'text', icon: textIconPath, y: 9 },
|
|
{ name: 'mask', icon: '🎭', y: 45 },
|
|
{ name: 'magic_wand', icon: '☯️', y: 81 },
|
|
{ name: 'brush', icon: '🖌️', y: 117 }
|
|
];
|
|
|
|
this.toolBounds = {};
|
|
this.selectedTextObject = null;
|
|
this.textEditTool = 'move';
|
|
this.contextualToolbar = null;
|
|
this.isTextDragging = false;
|
|
this.dragStart = { x: 0, y: 0 };
|
|
this.initialTextPos = { x: 0, y: 0 };
|
|
this.dragOffset = { x: 0, y: 0 };
|
|
this.boundDragMove = this.handleDragMove.bind(this);
|
|
this.boundDragEnd = this.handleDragEnd.bind(this);
|
|
this.isResizing = false;
|
|
this.resizeSensitivity = 0.5;
|
|
this.colorPicker = null;
|
|
|
|
this.maskManager = new MaskManager(this.node);
|
|
this.removeBgManager = new RemoveBgManager(this.node, this.maskManager);
|
|
this.magicWandManager = new MagicWandManager(this.node);
|
|
this.brushManager = new BrushManager(this.node);
|
|
this.maskPainterManager = new MaskPainterManager(this.node);
|
|
|
|
this.setupColorPicker();
|
|
this.createContextualToolbar();
|
|
this.selectionSubMenu = null;
|
|
this.createSelectionSubMenu();
|
|
}
|
|
createContextualToolbar() {
|
|
ensureToolbarStyles();
|
|
if (this.contextualToolbar) this.contextualToolbar.remove();
|
|
const toolbar = document.createElement("div");
|
|
toolbar.id = 'contextual-text-toolbar';
|
|
this.contextualToolbar = toolbar;
|
|
Object.assign(toolbar.style, {
|
|
position: 'fixed', display: 'none', zIndex: '10001',
|
|
});
|
|
|
|
const fontSelect = document.createElement("select");
|
|
fontSelect.className = 'font-select';
|
|
Object.assign(fontSelect.style, {
|
|
backgroundColor: 'transparent',
|
|
border: '1px solid rgba(0, 0, 0, 0.1)',
|
|
borderRadius: '4px',
|
|
color: '#333',
|
|
padding: '3px',
|
|
margin: '0 2px'
|
|
});
|
|
FONT_LIST.forEach(fontName => {
|
|
const option = document.createElement("option");
|
|
option.value = fontName;
|
|
option.textContent = fontName;
|
|
option.style.fontFamily = fontName;
|
|
fontSelect.appendChild(option);
|
|
});
|
|
fontSelect.addEventListener('change', () => {
|
|
if (this.selectedTextObject) {
|
|
this.selectedTextObject.fontFamily = fontSelect.value;
|
|
this.node.redrawPreviewCanvas();
|
|
this.node.updatePropertiesJSON();
|
|
}
|
|
});
|
|
toolbar.appendChild(fontSelect);
|
|
|
|
const icons = {
|
|
'move': '↔️', 'edit': '✏️', 'resize': '🔍', 'color': '🎨', 'delete': '🗑️', 'close': '❌'
|
|
};
|
|
for (const action in icons) {
|
|
const button = document.createElement("button");
|
|
button.innerHTML = icons[action];
|
|
|
|
button.addEventListener('click', () => {
|
|
if (!this.selectedTextObject) return;
|
|
this.isTextDragging = false;
|
|
this.isResizing = false;
|
|
this.node.previewCanvas.style.setProperty('cursor', 'default', 'important');
|
|
Array.from(event.currentTarget.parentElement.children).forEach(btn => {
|
|
btn.style.backgroundColor = 'transparent';
|
|
});
|
|
switch(action) {
|
|
case 'resize':
|
|
this.isResizing = true;
|
|
this.node.previewCanvas.style.setProperty('cursor', 'ns-resize', 'important');
|
|
event.currentTarget.style.backgroundColor = 'rgba(0, 0, 0, 0.1)';
|
|
break;
|
|
case 'move':
|
|
this.isTextDragging = true;
|
|
this.node.previewCanvas.style.setProperty('cursor', 'move', 'important');
|
|
event.currentTarget.style.backgroundColor = 'rgba(0, 0, 0, 0.1)';
|
|
break;
|
|
case 'edit':
|
|
this.node.editTextElement(this.selectedTextObject);
|
|
event.currentTarget.style.backgroundColor = 'rgba(0, 0, 0, 0.1)';
|
|
break;
|
|
case 'delete':
|
|
const index = this.textElements.findIndex(el => el.id === this.selectedTextObject.id);
|
|
if (index > -1) {
|
|
this.textElements.splice(index, 1);
|
|
this.hideContextualToolbar();
|
|
this.node.updatePropertiesJSON();
|
|
}
|
|
break;
|
|
case 'close':
|
|
this.hideContextualToolbar();
|
|
break;
|
|
case 'color':
|
|
event.currentTarget.style.backgroundColor = 'rgba(0, 0, 0, 0.1)';
|
|
if (this.selectedTextObject && this.colorPicker) {
|
|
this.colorPicker.value = this.selectedTextObject.color || '#FFFFFF';
|
|
this.colorPicker.click();
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
toolbar.appendChild(button);
|
|
}
|
|
document.body.appendChild(toolbar);
|
|
}
|
|
getTexts() {
|
|
return this.textElements;
|
|
}
|
|
draw(ctx) {
|
|
const canvas = this.node.previewCanvas;
|
|
if (!canvas) return;
|
|
const x = 0;
|
|
ctx.save();
|
|
ctx.fillStyle = '#282828';
|
|
ctx.fillRect(x, 0, this.width, canvas.height);
|
|
ctx.strokeStyle = '#111111';
|
|
ctx.lineWidth = 1;
|
|
ctx.strokeRect(x, 0, this.width, canvas.height);
|
|
ctx.restore();
|
|
this.tools.forEach(tool => {
|
|
const iconSize = 24;
|
|
const iconX_start = (this.width - iconSize) / 2;
|
|
const iconY_start = tool.y;
|
|
|
|
this.toolBounds[tool.name] = {
|
|
x: iconX_start,
|
|
y: iconY_start,
|
|
size: iconSize
|
|
};
|
|
|
|
const isActive = this.activeTool === tool.name ||
|
|
(tool.name === 'magic_wand' && this.selectionSubMenu?.style.display === 'flex');
|
|
|
|
if (isActive) {
|
|
ctx.fillStyle = "rgba(255, 221, 255, 0.6)";
|
|
const padding = 2;
|
|
ctx.fillRect(iconX_start - padding, iconY_start - padding, iconSize + (padding * 2), iconSize + (padding * 2));
|
|
}
|
|
|
|
ctx.save();
|
|
if (tool.icon instanceof Path2D) {
|
|
ctx.translate(iconX_start, iconY_start);
|
|
ctx.scale(iconSize / 24, iconSize / 24);
|
|
ctx.strokeStyle = (this.activeTool === tool.name) ? "#FFD700" : "#FFFFFF";
|
|
ctx.lineWidth = 2;
|
|
ctx.stroke(tool.icon);
|
|
} else {
|
|
ctx.font = `${iconSize}px sans-serif`;
|
|
ctx.textAlign = 'center';
|
|
ctx.textBaseline = 'middle';
|
|
ctx.fillText(tool.icon, iconX_start + iconSize / 2, iconY_start + iconSize / 2);
|
|
}
|
|
|
|
ctx.restore();
|
|
});
|
|
}
|
|
getConversionRatio() {
|
|
if (!this.node.basePreviewImage || !this.node.previewCanvas || (this.node.previewCanvas.width - this.width) <= 0) {
|
|
return 1.0;
|
|
}
|
|
const baseImageWidth = this.node.basePreviewImage.naturalWidth;
|
|
const previewImageAreaWidth = this.node.previewCanvas.width - this.width;
|
|
return baseImageWidth / previewImageAreaWidth;
|
|
}
|
|
drawTextElements(ctx) {
|
|
if (!this.node.previewCanvas || !this.node.basePreviewImage) return;
|
|
const ratio = this.getConversionRatio();
|
|
if (ratio === 1.0 && this.textElements.length > 0) return;
|
|
const inverseRatio = 1 / ratio;
|
|
const previewImageAreaWidth = this.node.previewCanvas.width - this.width;
|
|
const previewCenterX = previewImageAreaWidth / 2;
|
|
const previewCenterY = this.node.previewCanvas.height / 2;
|
|
ctx.save();
|
|
this.textElements.forEach(textEl => {
|
|
const preview_offset_x = textEl.offset_x * inverseRatio;
|
|
const preview_offset_y = textEl.offset_y * inverseRatio;
|
|
const preview_size = textEl.size * inverseRatio;
|
|
const preview_x = this.width + previewCenterX + preview_offset_x;
|
|
const preview_y = previewCenterY + preview_offset_y;
|
|
ctx.fillStyle = textEl.color;
|
|
ctx.font = `${preview_size}px ${textEl.fontFamily || 'Arial'}`;
|
|
ctx.textBaseline = 'top';
|
|
ctx.fillText(textEl.text, preview_x, preview_y);
|
|
});
|
|
ctx.restore();
|
|
}
|
|
|
|
handleClick(e, mouseX, mouseY) {
|
|
const clickedTool = this.tools.find(tool => {
|
|
const bounds = this.toolBounds[tool.name];
|
|
if (!bounds) return false;
|
|
return mouseX >= bounds.x && mouseX < (bounds.x + bounds.size) &&
|
|
mouseY >= bounds.y && mouseY < (bounds.y + bounds.size);
|
|
});
|
|
|
|
if (clickedTool) {
|
|
const toolName = clickedTool.name;
|
|
const isDeactivating = this.activeTool === toolName ||
|
|
(toolName === 'magic_wand' && this.selectionSubMenu?.style.display === 'flex');
|
|
|
|
this.activeTool = null;
|
|
this.maskManager.hide();
|
|
this.magicWandManager.hide();
|
|
this.brushManager.hide();
|
|
this.maskPainterManager.hide();
|
|
if (this.selectionSubMenu) {
|
|
this.selectionSubMenu.style.display = 'none';
|
|
}
|
|
|
|
if (!isDeactivating) {
|
|
if (toolName !== 'magic_wand') {
|
|
this.activeTool = toolName;
|
|
}
|
|
|
|
switch (toolName) {
|
|
case 'mask':
|
|
this.maskManager.show();
|
|
break;
|
|
case 'magic_wand':
|
|
if (this.selectionSubMenu) {
|
|
this.selectionSubMenu.style.display = 'flex';
|
|
this.positionSelectionSubMenu();
|
|
}
|
|
break;
|
|
case 'brush':
|
|
this.brushManager.show();
|
|
break;
|
|
case 'text':
|
|
break;
|
|
}
|
|
}
|
|
if (clickedTool || this.activeTool) {
|
|
this.node.movingLayer = null;
|
|
|
|
}
|
|
this.node.refreshUI();
|
|
}
|
|
}
|
|
|
|
handleCanvasClick(e) {
|
|
if (this.activeTool !== 'text') {
|
|
return;
|
|
}
|
|
|
|
if (this.selectedTextObject) {
|
|
const clickedText = this.node.findTextElementAtPos(e.offsetX, e.offsetY);
|
|
if (clickedText && clickedText.id === this.selectedTextObject.id) {
|
|
this.handleDragStart(e);
|
|
} else {
|
|
this.hideContextualToolbar();
|
|
}
|
|
return;
|
|
}
|
|
|
|
const now = Date.now();
|
|
const clickedTextForSelection = this.node.findTextElementAtPos(e.offsetX, e.offsetY);
|
|
|
|
if (clickedTextForSelection && (now - this.lastClickTime < 300) && this.lastClickTarget === clickedTextForSelection.id) {
|
|
if (this.clickTimeout) { clearTimeout(this.clickTimeout); this.clickTimeout = null; }
|
|
this.showContextualToolbar(clickedTextForSelection, e);
|
|
this.lastClickTime = 0;
|
|
return;
|
|
}
|
|
this.lastClickTime = now;
|
|
this.lastClickTarget = clickedTextForSelection ? clickedTextForSelection.id : null;
|
|
if (!clickedTextForSelection) {
|
|
this.clickTimeout = setTimeout(() => {
|
|
if (this.activeTextarea) this.activeTextarea.remove();
|
|
|
|
const textInput = document.createElement("div");
|
|
this.activeTextarea = textInput;
|
|
textInput.contentEditable = true;
|
|
Object.assign(textInput.style, {
|
|
position: 'fixed', left: `${e.clientX}px`, top: `${e.clientY}px`,
|
|
border: '2px solid #FFD700', background: 'rgba(20,20,20,0.9)',
|
|
color: 'white', zIndex: '9999', fontFamily: 'Arial',
|
|
fontSize: '16px', padding: '5px', minWidth: '100px',
|
|
resize: 'both', overflow: 'auto', whiteSpace: 'pre-wrap'
|
|
});
|
|
document.body.appendChild(textInput);
|
|
textInput.focus();
|
|
document.execCommand('selectAll', false, null);
|
|
const onFinish = () => {
|
|
if (textInput.innerText.trim() !== "") {
|
|
const ratio = this.getConversionRatio();
|
|
const previewImageAreaWidth = this.node.previewCanvas.width - this.width;
|
|
const previewCenterX = previewImageAreaWidth / 2;
|
|
const previewCenterY = this.node.previewCanvas.height / 2;
|
|
const click_x_in_preview_area = e.offsetX - this.width;
|
|
const click_y_in_preview_area = e.offsetY;
|
|
const newTextElement = {
|
|
id: `text_${Date.now()}`,
|
|
text: textInput.innerText,
|
|
offset_x: (click_x_in_preview_area - previewCenterX) * ratio,
|
|
offset_y: (click_y_in_preview_area - previewCenterY) * ratio,
|
|
size: 24 * ratio,
|
|
color: '#FFFFFF',
|
|
fontFamily: 'Arial',
|
|
};
|
|
this.textElements.push(newTextElement);
|
|
this.node.updatePropertiesJSON();
|
|
this.node.redrawPreviewCanvas();
|
|
}
|
|
if (textInput.parentElement) textInput.parentElement.removeChild(textInput);
|
|
this.activeTextarea = null;
|
|
};
|
|
|
|
textInput.addEventListener('blur', onFinish);
|
|
textInput.addEventListener('keydown', (evt) => {
|
|
evt.stopPropagation();
|
|
if (evt.key === 'Enter' && !evt.shiftKey) {
|
|
evt.preventDefault();
|
|
onFinish();
|
|
}
|
|
});
|
|
}, 250);
|
|
}
|
|
}
|
|
showContextualToolbar(textElement, event) {
|
|
this.selectedTextObject = textElement;
|
|
this.contextualToolbar.style.display = 'flex';
|
|
this.node.redrawPreviewCanvas();
|
|
this.setDefaultMode();
|
|
|
|
const fontSelect = this.contextualToolbar.querySelector('.font-select');
|
|
if (fontSelect && this.selectedTextObject.fontFamily) {
|
|
fontSelect.value = this.selectedTextObject.fontFamily;
|
|
}
|
|
|
|
this.updateContextualToolbarPosition();
|
|
}
|
|
handleDragStart(e) {
|
|
if (!this.selectedTextObject) return;
|
|
|
|
this.initialTextData = {
|
|
offset_x: this.selectedTextObject.offset_x,
|
|
offset_y: this.selectedTextObject.offset_y,
|
|
size: this.selectedTextObject.size
|
|
};
|
|
|
|
this.dragStart = { x: e.clientX, y: e.clientY };
|
|
|
|
if (this.isResizing) {
|
|
window.addEventListener('mousemove', this.boundDragMove, true);
|
|
window.addEventListener('mouseup', this.boundDragEnd, true);
|
|
return;
|
|
}
|
|
|
|
this.isTextDragging = true;
|
|
window.addEventListener('mousemove', this.boundDragMove, true);
|
|
window.addEventListener('mouseup', this.boundDragEnd, true);
|
|
}
|
|
updateContextualToolbarPosition() {
|
|
if (!this.selectedTextObject || !this.node.previewCanvas || !this.node.getTextPreviewMetrics) return;
|
|
const metrics = this.node.getTextPreviewMetrics(this.selectedTextObject);
|
|
if (!metrics) return;
|
|
const canvasRect = this.node.previewCanvas.getBoundingClientRect();
|
|
|
|
let zoom = 1.0;
|
|
const unscaledWidth = this.node.previewCanvas.width;
|
|
if (unscaledWidth > 0 && canvasRect.width > 0) {
|
|
zoom = canvasRect.width / unscaledWidth;
|
|
}
|
|
const anchorX = canvasRect.left + (metrics.x + metrics.width / 2) * zoom;
|
|
const anchorY = canvasRect.top + metrics.y * zoom;
|
|
const toolbarEl = this.contextualToolbar;
|
|
if (!toolbarEl) return;
|
|
|
|
toolbarEl.style.left = `${anchorX}px`;
|
|
toolbarEl.style.top = `${anchorY}px`;
|
|
|
|
const margin = 60;
|
|
toolbarEl.style.transform = `translate(-50%, -100%) translateY(-${margin}px)`;
|
|
}
|
|
handleDragMove(e) {
|
|
if (!this.selectedTextObject) return;
|
|
|
|
const dx = e.clientX - this.dragStart.x;
|
|
const dy = e.clientY - this.dragStart.y;
|
|
const ratio = this.getConversionRatio();
|
|
if (this.isResizing) {
|
|
const delta_size_final = -(dy * this.resizeSensitivity) * ratio;
|
|
const newSize = this.initialTextData.size + delta_size_final;
|
|
this.selectedTextObject.size = Math.max(5 * ratio, newSize);
|
|
}
|
|
else if (this.isTextDragging) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
const delta_x_final = dx * ratio;
|
|
const delta_y_final = dy * ratio;
|
|
this.selectedTextObject.offset_x = this.initialTextData.offset_x + delta_x_final;
|
|
this.selectedTextObject.offset_y = this.initialTextData.offset_y + delta_y_final;
|
|
}
|
|
|
|
this.node.redrawPreviewCanvas();
|
|
}
|
|
handleDragEnd(e) {
|
|
window.removeEventListener('mousemove', this.boundDragMove, true);
|
|
window.removeEventListener('mouseup', this.boundDragEnd, true);
|
|
|
|
this.node.updatePropertiesJSON();
|
|
this.node.redrawPreviewCanvas();
|
|
if (this.isResizing) {
|
|
}
|
|
else if (this.isTextDragging) {
|
|
this.isTextDragging = false;
|
|
this.updateContextualToolbarPosition();
|
|
}
|
|
}
|
|
|
|
createSelectionSubMenu() {
|
|
this.selectionSubMenu = document.createElement("div");
|
|
Object.assign(this.selectionSubMenu.style, {
|
|
position: 'fixed',
|
|
display: 'none',
|
|
zIndex: '10002',
|
|
backgroundColor: 'rgba(30, 30, 30, 0.9)',
|
|
border: '1px solid #555',
|
|
borderRadius: '8px',
|
|
padding: '4px',
|
|
flexDirection: 'column',
|
|
gap: '4px',
|
|
});
|
|
|
|
const createEmojiButton = (emoji, title) => {
|
|
const button = document.createElement("button");
|
|
button.innerText = emoji;
|
|
button.title = title;
|
|
Object.assign(button.style, {
|
|
backgroundColor: '#444',
|
|
color: 'white',
|
|
border: '1px solid #666',
|
|
padding: '0',
|
|
borderRadius: '5px',
|
|
cursor: 'pointer',
|
|
width: '26px',
|
|
height: '26px',
|
|
fontSize: '16px',
|
|
textAlign: 'center',
|
|
lineHeight: '26px',
|
|
});
|
|
button.onmouseover = () => button.style.backgroundColor = '#5E5E5E';
|
|
button.onmouseout = () => button.style.backgroundColor = '#444';
|
|
return button;
|
|
};
|
|
|
|
const wandButton = createEmojiButton("🪄", "Baguette Magique");
|
|
wandButton.onclick = () => {
|
|
this.activeTool = 'magic_wand';
|
|
this.magicWandManager.show();
|
|
this.selectionSubMenu.style.display = 'none';
|
|
};
|
|
|
|
const paintMaskButton = createEmojiButton("🖌️", "Paint Mask");
|
|
|
|
if (this.maskPainterManager) {
|
|
this.maskPainterManager.show();
|
|
}
|
|
this.selectionSubMenu.style.display = 'none';
|
|
};
|
|
|
|
this.selectionSubMenu.append(wandButton, paintMaskButton);
|
|
document.body.appendChild(this.selectionSubMenu);
|
|
}
|
|
|
|
positionSelectionSubMenu() {
|
|
if (!this.selectionSubMenu || this.selectionSubMenu.style.display === 'none') {
|
|
return;
|
|
}
|
|
|
|
const bounds = this.toolBounds['magic_wand'];
|
|
if (!bounds || !this.node.previewCanvas) return;
|
|
|
|
const canvasRect = this.node.previewCanvas.getBoundingClientRect();
|
|
|
|
this.selectionSubMenu.style.left = `${canvasRect.left + bounds.x + bounds.size}px`;
|
|
this.selectionSubMenu.style.top = `${canvasRect.top + bounds.y - 40}px`;
|
|
}
|
|
|
|
hideContextualToolbar() {
|
|
this.selectedTextObject = null;
|
|
this.contextualToolbar.style.display = 'none';
|
|
this.isResizing = false;
|
|
this.isTextDragging = false;
|
|
|
|
if (this.node.previewCanvas) {
|
|
this.node.previewCanvas.style.setProperty('cursor', 'default', 'important');
|
|
}
|
|
this.node.redrawPreviewCanvas();
|
|
}
|
|
setupColorPicker() {
|
|
const picker = document.createElement('input');
|
|
picker.type = 'color';
|
|
Object.assign(picker.style, {
|
|
position: 'fixed',
|
|
opacity: 0,
|
|
pointerEvents: 'none',
|
|
left: '-100px',
|
|
top: '-100px'
|
|
});
|
|
picker.addEventListener('input', () => {
|
|
if (this.selectedTextObject) {
|
|
this.selectedTextObject.color = picker.value;
|
|
this.node.redrawPreviewCanvas();
|
|
}
|
|
});
|
|
picker.addEventListener('change', () => {
|
|
if (this.selectedTextObject) {
|
|
this.setDefaultMode();
|
|
this.node.updatePropertiesJSON();
|
|
}
|
|
});
|
|
document.body.appendChild(picker);
|
|
this.colorPicker = picker;
|
|
}
|
|
setDefaultMode() {
|
|
this.isTextDragging = true;
|
|
this.isResizing = false;
|
|
this.node.previewCanvas.style.setProperty('cursor', 'move', 'important');
|
|
if (!this.contextualToolbar) return;
|
|
Array.from(this.contextualToolbar.children).forEach(button => {
|
|
button.style.backgroundColor = 'transparent';
|
|
if (button.innerHTML === '↔️') {
|
|
button.style.backgroundColor = 'rgba(0, 0, 0, 0.1)';
|
|
}
|
|
});
|
|
}
|
|
isClickOnToolbar(mouseX, mouseY) {
|
|
const canvas = this.node.previewCanvas;
|
|
return canvas && mouseX < this.width;
|
|
}
|
|
}
|