Remove generatedraw from element object

- Create a function that renders a single element
- Refactor rendering selected elements
This commit is contained in:
Gasim Gasimzada 2020-01-07 17:05:26 +04:00
parent 85365e5bcb
commit 8593273775
9 changed files with 96 additions and 112 deletions

View file

@ -11,5 +11,4 @@ export {
export { handlerRectangles } from "./handlerRectangles";
export { hitTest } from "./collision";
export { resizeTest } from "./resizeTest";
export { generateDraw } from "./generateDraw";
export { isTextElement } from "./typeChecks";

View file

@ -1,6 +1,3 @@
import { RoughCanvas } from "roughjs/bin/canvas";
import { SceneState } from "../scene/types";
import { randomSeed } from "../random";
export function newElement(
@ -17,24 +14,19 @@ export function newElement(
height = 0
) {
const element = {
type: type,
x: x,
y: y,
width: width,
height: height,
type,
x,
y,
width,
height,
strokeColor,
backgroundColor,
fillStyle,
strokeWidth,
roughness,
opacity,
isSelected: false,
strokeColor: strokeColor,
backgroundColor: backgroundColor,
fillStyle: fillStyle,
strokeWidth: strokeWidth,
roughness: roughness,
opacity: opacity,
seed: randomSeed(),
draw(
rc: RoughCanvas,
context: CanvasRenderingContext2D,
sceneState: SceneState
) {}
seed: randomSeed()
};
return element;
}

View file

@ -1,5 +1,4 @@
import { ExcalidrawElement } from "./element/types";
import { generateDraw } from "./element";
class SceneHistory {
private recording: boolean = true;
@ -27,7 +26,6 @@ class SceneHistory {
const newElements = JSON.parse(entry);
elements.splice(0, elements.length);
newElements.forEach((newElement: ExcalidrawElement) => {
generateDraw(newElement);
elements.push(newElement);
});
// When restoring, we shouldn't add an history entry otherwise we'll be stuck with it and can't go back

View file

@ -4,9 +4,8 @@ import rough from "roughjs/bin/wrappers/rough";
import { moveOneLeft, moveAllLeft, moveOneRight, moveAllRight } from "./zindex";
import { randomSeed } from "./random";
import { newElement, resizeTest, generateDraw, isTextElement } from "./element";
import { newElement, resizeTest, isTextElement } from "./element";
import {
renderScene,
clearSelection,
getSelectedIndices,
deleteSelectedElements,
@ -26,6 +25,8 @@ import {
getElementAtPosition,
createScene
} from "./scene";
import { renderScene } from "./renderer";
import { AppState } from "./types";
import { ExcalidrawElement, ExcalidrawTextElement } from "./element/types";
@ -267,7 +268,6 @@ class App extends React.Component<{}, AppState> {
element.fillStyle = pastedElement?.fillStyle;
element.opacity = pastedElement?.opacity;
element.roughness = pastedElement?.roughness;
generateDraw(element);
}
});
this.forceUpdate();
@ -303,7 +303,6 @@ class App extends React.Component<{}, AppState> {
elements.forEach(element => {
if (element.isSelected) {
callback(element);
generateDraw(element);
}
});
@ -697,7 +696,6 @@ class App extends React.Component<{}, AppState> {
}
}
generateDraw(element);
elements.push(element);
if (this.state.elementType === "text") {
this.setState({
@ -805,7 +803,6 @@ class App extends React.Component<{}, AppState> {
el.x = element.x;
el.y = element.y;
generateDraw(el);
});
lastX = x;
lastY = y;
@ -856,8 +853,6 @@ class App extends React.Component<{}, AppState> {
? Math.abs(width) * Math.sign(height)
: height;
generateDraw(draggingElement);
if (this.state.elementType === "selection") {
setSelection(elements, draggingElement);
}
@ -932,7 +927,6 @@ class App extends React.Component<{}, AppState> {
return;
}
generateDraw(element);
elements.push(element);
this.setState({
@ -989,7 +983,6 @@ class App extends React.Component<{}, AppState> {
parsedElement.x = dx ? parsedElement.x + dx : 10 - this.state.scrollX;
parsedElement.y = dy ? parsedElement.y + dy : 10 - this.state.scrollY;
parsedElement.seed = randomSeed();
generateDraw(parsedElement);
elements.push(parsedElement);
});
this.forceUpdate();

1
src/renderer/index.ts Normal file
View file

@ -0,0 +1 @@
export { renderScene } from "./renderScene";

View file

@ -2,17 +2,23 @@ import rough from "roughjs/bin/wrappers/rough";
import { withCustomMathRandom } from "../random";
import { ExcalidrawElement } from "./types";
import { isTextElement } from "./typeChecks";
import { getDiamondPoints, getArrowPoints } from "./bounds";
import { ExcalidrawElement } from "../element/types";
import { isTextElement } from "../element/typeChecks";
import { getDiamondPoints, getArrowPoints } from "../element/bounds";
import { RoughCanvas } from "roughjs/bin/canvas";
import { SceneState } from "../scene/types";
// Casting second argument (DrawingSurface) to any,
// because it is requred by TS definitions and not required at runtime
const generator = rough.generator(null, null as any);
export function generateDraw(element: ExcalidrawElement) {
export function renderElement(
element: ExcalidrawElement,
rc: RoughCanvas,
context: CanvasRenderingContext2D,
{ scrollX, scrollY }: SceneState
) {
if (element.type === "selection") {
element.draw = (rc, context, { scrollX, scrollY }) => {
const fillStyle = context.fillStyle;
context.fillStyle = "rgba(0, 0, 255, 0.10)";
context.fillRect(
@ -22,7 +28,6 @@ export function generateDraw(element: ExcalidrawElement) {
element.height
);
context.fillStyle = fillStyle;
};
} else if (element.type === "rectangle") {
const shape = withCustomMathRandom(element.seed, () => {
return generator.rectangle(0, 0, element.width, element.height, {
@ -33,13 +38,12 @@ export function generateDraw(element: ExcalidrawElement) {
roughness: element.roughness
});
});
element.draw = (rc, context, { scrollX, scrollY }) => {
context.globalAlpha = element.opacity / 100;
context.translate(element.x + scrollX, element.y + scrollY);
rc.draw(shape);
context.translate(-element.x - scrollX, -element.y - scrollY);
context.globalAlpha = 1;
};
} else if (element.type === "diamond") {
const shape = withCustomMathRandom(element.seed, () => {
const [
@ -68,13 +72,11 @@ export function generateDraw(element: ExcalidrawElement) {
}
);
});
element.draw = (rc, context, { scrollX, scrollY }) => {
context.globalAlpha = element.opacity / 100;
context.translate(element.x + scrollX, element.y + scrollY);
rc.draw(shape);
context.translate(-element.x - scrollX, -element.y - scrollY);
context.globalAlpha = 1;
};
} else if (element.type === "ellipse") {
const shape = withCustomMathRandom(element.seed, () =>
generator.ellipse(
@ -91,13 +93,12 @@ export function generateDraw(element: ExcalidrawElement) {
}
)
);
element.draw = (rc, context, { scrollX, scrollY }) => {
context.globalAlpha = element.opacity / 100;
context.translate(element.x + scrollX, element.y + scrollY);
rc.draw(shape);
context.translate(-element.x - scrollX, -element.y - scrollY);
context.globalAlpha = 1;
};
} else if (element.type === "arrow") {
const [x1, y1, x2, y2, x3, y3, x4, y4] = getArrowPoints(element);
const options = {
@ -115,16 +116,13 @@ export function generateDraw(element: ExcalidrawElement) {
generator.line(x4, y4, x2, y2, options)
]);
element.draw = (rc, context, { scrollX, scrollY }) => {
context.globalAlpha = element.opacity / 100;
context.translate(element.x + scrollX, element.y + scrollY);
shapes.forEach(shape => rc.draw(shape));
context.translate(-element.x - scrollX, -element.y - scrollY);
context.globalAlpha = 1;
};
return;
} else if (isTextElement(element)) {
element.draw = (rc, context, { scrollX, scrollY }) => {
context.globalAlpha = element.opacity / 100;
const font = context.font;
context.font = element.font;
@ -138,7 +136,6 @@ export function generateDraw(element: ExcalidrawElement) {
context.fillStyle = fillStyle;
context.font = font;
context.globalAlpha = 1;
};
} else {
throw new Error("Unimplemented type " + element.type);
}

View file

@ -9,10 +9,15 @@ import {
handlerRectangles
} from "../element";
import { roundRect } from "./roundRect";
import { SceneState } from "./types";
import { getScrollBars, SCROLLBAR_COLOR, SCROLLBAR_WIDTH } from "./scrollbars";
import { getSelectedIndices } from "./selection";
import { roundRect } from "../scene/roundRect";
import { SceneState } from "../scene/types";
import {
getScrollBars,
SCROLLBAR_COLOR,
SCROLLBAR_WIDTH
} from "../scene/scrollbars";
import { renderElement } from "./renderElement";
export function renderScene(
elements: ExcalidrawElement[],
@ -44,8 +49,6 @@ export function renderScene(
}
context.fillStyle = fillStyle;
const selectedIndices = getSelectedIndices(elements);
sceneState = {
...sceneState,
scrollX: typeof offsetX === "number" ? offsetX : sceneState.scrollX,
@ -53,8 +56,13 @@ export function renderScene(
};
elements.forEach(element => {
element.draw(rc, context, sceneState);
if (renderSelection && element.isSelected) {
renderElement(element, rc, context, sceneState);
});
if (renderSelection) {
const selectedElements = elements.filter(el => el.isSelected);
selectedElements.forEach(element => {
const margin = 4;
const elementX1 = getElementAbsoluteX1(element);
@ -70,15 +78,15 @@ export function renderScene(
elementY2 - elementY1 + margin * 2
);
context.setLineDash(lineDash);
});
if (element.type !== "text" && selectedIndices.length === 1) {
const handlers = handlerRectangles(element, sceneState);
if (selectedElements.length === 1 && selectedElements[0].type !== "text") {
const handlers = handlerRectangles(selectedElements[0], sceneState);
Object.values(handlers).forEach(handler => {
context.strokeRect(handler[0], handler[1], handler[2], handler[3]);
});
}
}
});
if (renderScrollbars) {
const scrollBars = getScrollBars(

View file

@ -6,11 +6,10 @@ import {
getElementAbsoluteX1,
getElementAbsoluteX2,
getElementAbsoluteY1,
getElementAbsoluteY2,
generateDraw
getElementAbsoluteY2
} from "../element";
import { renderScene } from "./render";
import { renderScene } from "../renderer";
import { AppState } from "../types";
const LOCAL_STORAGE_KEY = "excalidraw";
@ -155,8 +154,6 @@ function restore(
element.opacity === null || element.opacity === undefined
? 100
: element.opacity;
generateDraw(element);
});
}

View file

@ -1,5 +1,4 @@
export { isOverScrollBars } from "./scrollbars";
export { renderScene } from "./render";
export {
clearSelection,
getSelectedIndices,