mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-09-03 23:57:01 +02:00

* Add points to arrow on double click * Use line generator instead of path to generate line segments * Switch color of the circle when it is on an existing point in the segment * Check point against both ends of the line segment to find collinearity * Keep drawing the arrow based on mouse position until shape is changed * Always select the arrow when in multi element mode * Use curves instead of lines when drawing arrow points * Add basic collision detection with some debug points * Use roughjs shape when performing hit testing * Draw proper handler rectangles for arrows * Add argument to renderScene in export * Globally resize all points on the arrow when bounds are resized * Hide handler rectangles if an arrow has no size - Allow continuing adding arrows when selected element is deleted * Add dragging functionality to arrows * Add SHIFT functionality to two point arrows - Fix arrow positions when scrolling - Revert the element back to selection when not in multi select mode * Clean app state for export (JSON) * Set curve options manually instead of using global options - For some reason, this fixed the flickering issue in all shapes when arrows are rendered * Set proper options for the arrow * Increaase accuracy of hit testing arrows - Additionally, skip testing if point is outside the domain of arrow and each curve * Calculate bounding box of arrow based on roughjs curves - Remove domain check per curve * Change bounding box threshold to 10 and remove unnecessary code * Fix handler rectangles for 2 and multi point arrows - Fix margins of handler rectangles when using arrows - Show handler rectangles in endpoints of 2-point arrows * Remove unnecessary values from app state for export * Use `resetTransform` instead of "retranslating" canvas space after each element rendering * Allow resizing 2-point arrows - Fix position of one of the handler rectangles * refactor variable initialization * Refactored to extract out mult-point generation to the abstracted function * prevent dragging on arrow creation if under threshold * Finalize selection during multi element mode when ENTER or ESC is clicked * Set dragging element to null when finalizing * Remove pathSegmentCircle from code * Check if element is any "non-value" instead of NULL * Show two points on any two point arrow and fix visibility of arrows during scroll * Resume recording when done with drawing - When deleting a multi select element, revert back to selection element type * Resize arrow starting points perfectly * Fix direction of arrow resize based for NW * Resume recording history when there is more than one arrow * Set dragging element to NULL when element is not locked * Blur active element when finalizing * Disable undo/redo for multielement, editingelement, and resizing element - Allow undoing parts of the arrow * Disable element visibility for arrow * Use points array for arrow bounds when bezier curve shape is not available Co-authored-by: David Luzar <luzar.david@gmail.com> Co-authored-by: Preet <833927+pshihn@users.noreply.github.com>
112 lines
3.0 KiB
TypeScript
112 lines
3.0 KiB
TypeScript
export const SVG_NS = "http://www.w3.org/2000/svg";
|
|
|
|
export function getDateTime() {
|
|
const date = new Date();
|
|
const year = date.getFullYear();
|
|
const month = date.getMonth() + 1;
|
|
const day = date.getDate();
|
|
const hr = date.getHours();
|
|
const min = date.getMinutes();
|
|
const secs = date.getSeconds();
|
|
|
|
return `${year}${month}${day}${hr}${min}${secs}`;
|
|
}
|
|
|
|
export function capitalizeString(str: string) {
|
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
}
|
|
|
|
export function isToolIcon(
|
|
target: Element | EventTarget | null,
|
|
): target is HTMLElement {
|
|
return target instanceof HTMLElement && target.className.includes("ToolIcon");
|
|
}
|
|
|
|
export function isInputLike(
|
|
target: Element | EventTarget | null,
|
|
): target is
|
|
| HTMLInputElement
|
|
| HTMLTextAreaElement
|
|
| HTMLSelectElement
|
|
| HTMLDivElement {
|
|
return (
|
|
((target instanceof HTMLElement && target.dataset.type === "wysiwyg") ||
|
|
target instanceof HTMLInputElement ||
|
|
target instanceof HTMLTextAreaElement ||
|
|
target instanceof HTMLSelectElement) &&
|
|
!isToolIcon(target)
|
|
);
|
|
}
|
|
|
|
// https://github.com/grassator/canvas-text-editor/blob/master/lib/FontMetrics.js
|
|
export function measureText(text: string, font: string) {
|
|
const line = document.createElement("div");
|
|
const body = document.body;
|
|
line.style.position = "absolute";
|
|
line.style.whiteSpace = "nowrap";
|
|
line.style.font = font;
|
|
body.appendChild(line);
|
|
// Now we can measure width and height of the letter
|
|
line.innerText = text;
|
|
const width = line.offsetWidth;
|
|
const height = line.offsetHeight;
|
|
// Now creating 1px sized item that will be aligned to baseline
|
|
// to calculate baseline shift
|
|
const span = document.createElement("span");
|
|
span.style.display = "inline-block";
|
|
span.style.overflow = "hidden";
|
|
span.style.width = "1px";
|
|
span.style.height = "1px";
|
|
line.appendChild(span);
|
|
// Baseline is important for positioning text on canvas
|
|
const baseline = span.offsetTop + span.offsetHeight;
|
|
document.body.removeChild(line);
|
|
|
|
return { width, height, baseline };
|
|
}
|
|
|
|
export function debounce<T extends any[]>(
|
|
fn: (...args: T) => void,
|
|
timeout: number,
|
|
) {
|
|
let handle = 0;
|
|
let lastArgs: T;
|
|
const ret = (...args: T) => {
|
|
lastArgs = args;
|
|
clearTimeout(handle);
|
|
handle = window.setTimeout(() => fn(...args), timeout);
|
|
};
|
|
ret.flush = () => {
|
|
clearTimeout(handle);
|
|
fn(...lastArgs);
|
|
};
|
|
return ret;
|
|
}
|
|
|
|
export function selectNode(node: Element) {
|
|
const selection = window.getSelection();
|
|
if (selection) {
|
|
const range = document.createRange();
|
|
range.selectNodeContents(node);
|
|
selection.removeAllRanges();
|
|
selection.addRange(range);
|
|
}
|
|
}
|
|
|
|
export function removeSelection() {
|
|
const selection = window.getSelection();
|
|
if (selection) {
|
|
selection.removeAllRanges();
|
|
}
|
|
}
|
|
|
|
export function distance(x: number, y: number) {
|
|
return Math.abs(x - y);
|
|
}
|
|
|
|
export function distance2d(x1: number, y1: number, x2: number, y2: number) {
|
|
const xd = x2 - x1;
|
|
const yd = y2 - y1;
|
|
return Math.sqrt(xd * xd + yd * yd);
|
|
}
|