mark elements params as readonly & remove unnecessary copying

This commit is contained in:
dwelle 2020-01-09 11:59:59 +01:00
parent 88006ab426
commit 332fc518b7
9 changed files with 41 additions and 34 deletions

View file

@ -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
) { ) {

View file

@ -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();

View file

@ -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;

View file

@ -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,

View file

@ -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
) { ) {

View file

@ -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 };
}; };

View file

@ -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));

View file

@ -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,

View file

@ -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(