mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
mark elements params as readonly & remove unnecessary copying
This commit is contained in:
parent
88006ab426
commit
332fc518b7
9 changed files with 41 additions and 34 deletions
|
@ -34,7 +34,7 @@ export function resizeTest(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getElementWithResizeHandler(
|
export function getElementWithResizeHandler(
|
||||||
elements: ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
{ x, y }: { x: number; y: number },
|
{ x, y }: { x: number; y: number },
|
||||||
{ scrollX, scrollY }: SceneScroll
|
{ scrollX, scrollY }: SceneScroll
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ class SceneHistory {
|
||||||
private stateHistory: string[] = [];
|
private stateHistory: string[] = [];
|
||||||
private redoStack: string[] = [];
|
private redoStack: string[] = [];
|
||||||
|
|
||||||
generateCurrentEntry(elements: ExcalidrawElement[]) {
|
generateCurrentEntry(elements: readonly ExcalidrawElement[]) {
|
||||||
return JSON.stringify(
|
return JSON.stringify(
|
||||||
elements.map(element => ({ ...element, isSelected: false }))
|
elements.map(element => ({ ...element, isSelected: false }))
|
||||||
);
|
);
|
||||||
|
@ -37,7 +37,7 @@ class SceneHistory {
|
||||||
this.redoStack.splice(0, this.redoStack.length);
|
this.redoStack.splice(0, this.redoStack.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
redoOnce(elements: ExcalidrawElement[]) {
|
redoOnce(elements: readonly ExcalidrawElement[]) {
|
||||||
const currentEntry = this.generateCurrentEntry(elements);
|
const currentEntry = this.generateCurrentEntry(elements);
|
||||||
const entryToRestore = this.redoStack.pop();
|
const entryToRestore = this.redoStack.pop();
|
||||||
if (entryToRestore !== undefined) {
|
if (entryToRestore !== undefined) {
|
||||||
|
@ -48,7 +48,7 @@ class SceneHistory {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
undoOnce(elements: ExcalidrawElement[]) {
|
undoOnce(elements: readonly ExcalidrawElement[]) {
|
||||||
const currentEntry = this.generateCurrentEntry(elements);
|
const currentEntry = this.generateCurrentEntry(elements);
|
||||||
let entryToRestore = this.stateHistory.pop();
|
let entryToRestore = this.stateHistory.pop();
|
||||||
|
|
||||||
|
|
|
@ -157,7 +157,7 @@ export class App extends React.Component<{}, AppState> {
|
||||||
if (isInputLike(event.target)) return;
|
if (isInputLike(event.target)) return;
|
||||||
|
|
||||||
if (event.key === KEYS.ESCAPE) {
|
if (event.key === KEYS.ESCAPE) {
|
||||||
elements = clearSelection([...elements]);
|
elements = clearSelection(elements);
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
} else if (event.key === KEYS.BACKSPACE || event.key === KEYS.DELETE) {
|
} else if (event.key === KEYS.BACKSPACE || event.key === KEYS.DELETE) {
|
||||||
|
@ -416,7 +416,7 @@ export class App extends React.Component<{}, AppState> {
|
||||||
activeTool={this.state.elementType}
|
activeTool={this.state.elementType}
|
||||||
onToolChange={value => {
|
onToolChange={value => {
|
||||||
this.setState({ elementType: value });
|
this.setState({ elementType: value });
|
||||||
elements = clearSelection([...elements]);
|
elements = clearSelection(elements);
|
||||||
document.documentElement.style.cursor =
|
document.documentElement.style.cursor =
|
||||||
value === "text" ? "text" : "crosshair";
|
value === "text" ? "text" : "crosshair";
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
|
@ -670,7 +670,7 @@ export class App extends React.Component<{}, AppState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!element.isSelected) {
|
if (!element.isSelected) {
|
||||||
elements = clearSelection([...elements]);
|
elements = clearSelection(elements);
|
||||||
element.isSelected = true;
|
element.isSelected = true;
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
}
|
}
|
||||||
|
@ -772,7 +772,7 @@ export class App extends React.Component<{}, AppState> {
|
||||||
} else {
|
} else {
|
||||||
// We unselect every other elements unless shift is pressed
|
// We unselect every other elements unless shift is pressed
|
||||||
if (!e.shiftKey) {
|
if (!e.shiftKey) {
|
||||||
elements = clearSelection([...elements]);
|
elements = clearSelection(elements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// No matter what, we select it
|
// No matter what, we select it
|
||||||
|
@ -783,7 +783,9 @@ export class App extends React.Component<{}, AppState> {
|
||||||
...elements,
|
...elements,
|
||||||
...elements.reduce((duplicates, element) => {
|
...elements.reduce((duplicates, element) => {
|
||||||
if (element.isSelected) {
|
if (element.isSelected) {
|
||||||
duplicates.push(duplicateElement(element));
|
duplicates = duplicates.concat(
|
||||||
|
duplicateElement(element)
|
||||||
|
);
|
||||||
element.isSelected = false;
|
element.isSelected = false;
|
||||||
}
|
}
|
||||||
return duplicates;
|
return duplicates;
|
||||||
|
@ -792,7 +794,7 @@ export class App extends React.Component<{}, AppState> {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If we don't click on anything, let's remove all the selected elements
|
// If we don't click on anything, let's remove all the selected elements
|
||||||
elements = clearSelection([...elements]);
|
elements = clearSelection(elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
isDraggingElements = someElementIsSelected(elements);
|
isDraggingElements = someElementIsSelected(elements);
|
||||||
|
@ -991,7 +993,7 @@ export class App extends React.Component<{}, AppState> {
|
||||||
: height;
|
: height;
|
||||||
|
|
||||||
if (this.state.elementType === "selection") {
|
if (this.state.elementType === "selection") {
|
||||||
elements = setSelection([...elements], draggingElement);
|
elements = setSelection(elements, draggingElement);
|
||||||
}
|
}
|
||||||
// We don't want to save history when moving an element
|
// We don't want to save history when moving an element
|
||||||
history.skipRecording();
|
history.skipRecording();
|
||||||
|
@ -1009,7 +1011,7 @@ export class App extends React.Component<{}, AppState> {
|
||||||
|
|
||||||
// if no element is clicked, clear the selection and redraw
|
// if no element is clicked, clear the selection and redraw
|
||||||
if (draggingElement === null) {
|
if (draggingElement === null) {
|
||||||
elements = clearSelection([...elements]);
|
elements = clearSelection(elements);
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1061,7 +1063,9 @@ export class App extends React.Component<{}, AppState> {
|
||||||
let textY = e.clientY;
|
let textY = e.clientY;
|
||||||
|
|
||||||
if (elementAtPosition && isTextElement(elementAtPosition)) {
|
if (elementAtPosition && isTextElement(elementAtPosition)) {
|
||||||
elements.splice(elements.indexOf(elementAtPosition), 1);
|
elements = elements.filter(
|
||||||
|
element => element !== elementAtPosition
|
||||||
|
);
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
|
|
||||||
Object.assign(element, elementAtPosition);
|
Object.assign(element, elementAtPosition);
|
||||||
|
@ -1165,7 +1169,7 @@ export class App extends React.Component<{}, AppState> {
|
||||||
parsedElements.length > 0 &&
|
parsedElements.length > 0 &&
|
||||||
parsedElements[0].type // need to implement a better check here...
|
parsedElements[0].type // need to implement a better check here...
|
||||||
) {
|
) {
|
||||||
elements = clearSelection([...elements]);
|
elements = clearSelection(elements);
|
||||||
|
|
||||||
if (x == null) x = 10 - this.state.scrollX;
|
if (x == null) x = 10 - this.state.scrollX;
|
||||||
if (y == null) y = 10 - this.state.scrollY;
|
if (y == null) y = 10 - this.state.scrollY;
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {
|
||||||
import { renderElement } from "./renderElement";
|
import { renderElement } from "./renderElement";
|
||||||
|
|
||||||
export function renderScene(
|
export function renderScene(
|
||||||
elements: ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
rc: RoughCanvas,
|
rc: RoughCanvas,
|
||||||
canvas: HTMLCanvasElement,
|
canvas: HTMLCanvasElement,
|
||||||
sceneState: SceneState,
|
sceneState: SceneState,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { ExcalidrawElement } from "../element/types";
|
||||||
import { hitTest } from "../element/collision";
|
import { hitTest } from "../element/collision";
|
||||||
import { getElementAbsoluteCoords } from "../element";
|
import { getElementAbsoluteCoords } from "../element";
|
||||||
|
|
||||||
export const hasBackground = (elements: ExcalidrawElement[]) =>
|
export const hasBackground = (elements: readonly ExcalidrawElement[]) =>
|
||||||
elements.some(
|
elements.some(
|
||||||
element =>
|
element =>
|
||||||
element.isSelected &&
|
element.isSelected &&
|
||||||
|
@ -11,7 +11,7 @@ export const hasBackground = (elements: ExcalidrawElement[]) =>
|
||||||
element.type === "diamond")
|
element.type === "diamond")
|
||||||
);
|
);
|
||||||
|
|
||||||
export const hasStroke = (elements: ExcalidrawElement[]) =>
|
export const hasStroke = (elements: readonly ExcalidrawElement[]) =>
|
||||||
elements.some(
|
elements.some(
|
||||||
element =>
|
element =>
|
||||||
element.isSelected &&
|
element.isSelected &&
|
||||||
|
@ -21,11 +21,11 @@ export const hasStroke = (elements: ExcalidrawElement[]) =>
|
||||||
element.type === "arrow")
|
element.type === "arrow")
|
||||||
);
|
);
|
||||||
|
|
||||||
export const hasText = (elements: ExcalidrawElement[]) =>
|
export const hasText = (elements: readonly ExcalidrawElement[]) =>
|
||||||
elements.some(element => element.isSelected && element.type === "text");
|
elements.some(element => element.isSelected && element.type === "text");
|
||||||
|
|
||||||
export function getElementAtPosition(
|
export function getElementAtPosition(
|
||||||
elements: ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
x: number,
|
x: number,
|
||||||
y: number
|
y: number
|
||||||
) {
|
) {
|
||||||
|
@ -42,7 +42,7 @@ export function getElementAtPosition(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getElementContainingPosition(
|
export function getElementContainingPosition(
|
||||||
elements: ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
x: number,
|
x: number,
|
||||||
y: number
|
y: number
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { ExcalidrawElement } from "../element/types";
|
import { ExcalidrawElement } from "../element/types";
|
||||||
|
|
||||||
export const createScene = () => {
|
export const createScene = () => {
|
||||||
const elements = Array.of<ExcalidrawElement>();
|
const elements: readonly ExcalidrawElement[] = [];
|
||||||
return { elements };
|
return { elements };
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,11 +23,14 @@ function saveFile(name: string, data: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DataState {
|
interface DataState {
|
||||||
elements: ExcalidrawElement[];
|
elements: readonly ExcalidrawElement[];
|
||||||
appState: any;
|
appState: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveAsJSON(elements: ExcalidrawElement[], name: string) {
|
export function saveAsJSON(
|
||||||
|
elements: readonly ExcalidrawElement[],
|
||||||
|
name: string
|
||||||
|
) {
|
||||||
const serialized = JSON.stringify({
|
const serialized = JSON.stringify({
|
||||||
version: 1,
|
version: 1,
|
||||||
source: window.location.origin,
|
source: window.location.origin,
|
||||||
|
@ -74,7 +77,7 @@ export function loadFromJSON() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function exportAsPNG(
|
export function exportAsPNG(
|
||||||
elements: ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
canvas: HTMLCanvasElement,
|
canvas: HTMLCanvasElement,
|
||||||
{
|
{
|
||||||
exportBackground,
|
exportBackground,
|
||||||
|
@ -140,7 +143,7 @@ export function exportAsPNG(
|
||||||
}
|
}
|
||||||
|
|
||||||
function restore(
|
function restore(
|
||||||
savedElements: ExcalidrawElement[],
|
savedElements: readonly ExcalidrawElement[],
|
||||||
savedState: any
|
savedState: any
|
||||||
): DataState {
|
): DataState {
|
||||||
return {
|
return {
|
||||||
|
@ -185,7 +188,7 @@ export function restoreFromLocalStorage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveToLocalStorage(
|
export function saveToLocalStorage(
|
||||||
elements: ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
state: AppState
|
state: AppState
|
||||||
) {
|
) {
|
||||||
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(elements));
|
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(elements));
|
||||||
|
|
|
@ -7,7 +7,7 @@ export const SCROLLBAR_WIDTH = 6;
|
||||||
export const SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
|
export const SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
|
||||||
|
|
||||||
export function getScrollBars(
|
export function getScrollBars(
|
||||||
elements: ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
canvasWidth: number,
|
canvasWidth: number,
|
||||||
canvasHeight: number,
|
canvasHeight: number,
|
||||||
scrollX: number,
|
scrollX: number,
|
||||||
|
@ -76,7 +76,7 @@ export function getScrollBars(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isOverScrollBars(
|
export function isOverScrollBars(
|
||||||
elements: ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
canvasWidth: number,
|
canvasWidth: number,
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { ExcalidrawElement } from "../element/types";
|
||||||
import { getElementAbsoluteCoords } from "../element";
|
import { getElementAbsoluteCoords } from "../element";
|
||||||
|
|
||||||
export function setSelection(
|
export function setSelection(
|
||||||
elements: ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
selection: ExcalidrawElement
|
selection: ExcalidrawElement
|
||||||
) {
|
) {
|
||||||
const [
|
const [
|
||||||
|
@ -29,7 +29,7 @@ export function setSelection(
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clearSelection(elements: ExcalidrawElement[]) {
|
export function clearSelection(elements: readonly ExcalidrawElement[]) {
|
||||||
elements.forEach(element => {
|
elements.forEach(element => {
|
||||||
element.isSelected = false;
|
element.isSelected = false;
|
||||||
});
|
});
|
||||||
|
@ -37,11 +37,11 @@ export function clearSelection(elements: ExcalidrawElement[]) {
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteSelectedElements(elements: ExcalidrawElement[]) {
|
export function deleteSelectedElements(elements: readonly ExcalidrawElement[]) {
|
||||||
return elements.filter(el => !el.isSelected);
|
return elements.filter(el => !el.isSelected);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getSelectedIndices(elements: ExcalidrawElement[]) {
|
export function getSelectedIndices(elements: readonly ExcalidrawElement[]) {
|
||||||
const selectedIndices: number[] = [];
|
const selectedIndices: number[] = [];
|
||||||
elements.forEach((element, index) => {
|
elements.forEach((element, index) => {
|
||||||
if (element.isSelected) {
|
if (element.isSelected) {
|
||||||
|
@ -51,11 +51,11 @@ export function getSelectedIndices(elements: ExcalidrawElement[]) {
|
||||||
return selectedIndices;
|
return selectedIndices;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const someElementIsSelected = (elements: ExcalidrawElement[]) =>
|
export const someElementIsSelected = (elements: readonly ExcalidrawElement[]) =>
|
||||||
elements.some(element => element.isSelected);
|
elements.some(element => element.isSelected);
|
||||||
|
|
||||||
export function getSelectedAttribute<T>(
|
export function getSelectedAttribute<T>(
|
||||||
elements: ExcalidrawElement[],
|
elements: readonly ExcalidrawElement[],
|
||||||
getAttribute: (element: ExcalidrawElement) => T
|
getAttribute: (element: ExcalidrawElement) => T
|
||||||
): T | null {
|
): T | null {
|
||||||
const attributes = Array.from(
|
const attributes = Array.from(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue