Refactor Element Functions (#233)
* Remove `generatedraw` from element object - Create a function that renders a single element - Refactor rendering selected elements * Replace getElementAbsoluteXY with getElementAbsoluteCoords
This commit is contained in:
parent
85365e5bcb
commit
829a65b8cb
67
src/element/bounds.test.ts
Normal file
67
src/element/bounds.test.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { getElementAbsoluteCoords } from "./bounds";
|
||||||
|
import { ExcalidrawElement } from "./types";
|
||||||
|
|
||||||
|
const _ce = ({ x, y, w, h }: { x: number; y: number; w: number; h: number }) =>
|
||||||
|
({
|
||||||
|
type: "test",
|
||||||
|
strokeColor: "#000",
|
||||||
|
backgroundColor: "#000",
|
||||||
|
fillStyle: "solid",
|
||||||
|
strokeWidth: 1,
|
||||||
|
roughness: 1,
|
||||||
|
opacity: 1,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
width: w,
|
||||||
|
height: h
|
||||||
|
} as ExcalidrawElement);
|
||||||
|
|
||||||
|
describe("getElementAbsoluteCoords", () => {
|
||||||
|
it("test x1 coordinate if width is positive or zero", () => {
|
||||||
|
const [x1] = getElementAbsoluteCoords(_ce({ x: 10, y: 0, w: 10, h: 0 }));
|
||||||
|
expect(x1).toEqual(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test x1 coordinate if width is negative", () => {
|
||||||
|
const [x1] = getElementAbsoluteCoords(_ce({ x: 20, y: 0, w: -10, h: 0 }));
|
||||||
|
expect(x1).toEqual(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test x2 coordinate if width is positive or zero", () => {
|
||||||
|
const [, , x2] = getElementAbsoluteCoords(
|
||||||
|
_ce({ x: 10, y: 0, w: 10, h: 0 })
|
||||||
|
);
|
||||||
|
expect(x2).toEqual(20);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test x2 coordinate if width is negative", () => {
|
||||||
|
const [, , x2] = getElementAbsoluteCoords(
|
||||||
|
_ce({ x: 10, y: 0, w: -10, h: 0 })
|
||||||
|
);
|
||||||
|
expect(x2).toEqual(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test y1 coordinate if height is positive or zero", () => {
|
||||||
|
const [, y1] = getElementAbsoluteCoords(_ce({ x: 0, y: 10, w: 0, h: 10 }));
|
||||||
|
expect(y1).toEqual(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test y1 coordinate if height is negative", () => {
|
||||||
|
const [, y1] = getElementAbsoluteCoords(_ce({ x: 0, y: 20, w: 0, h: -10 }));
|
||||||
|
expect(y1).toEqual(10);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test y2 coordinate if height is positive or zero", () => {
|
||||||
|
const [, , , y2] = getElementAbsoluteCoords(
|
||||||
|
_ce({ x: 0, y: 10, w: 0, h: 10 })
|
||||||
|
);
|
||||||
|
expect(y2).toEqual(20);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("test y2 coordinate if height is negative", () => {
|
||||||
|
const [, , , y2] = getElementAbsoluteCoords(
|
||||||
|
_ce({ x: 0, y: 10, w: 0, h: -10 })
|
||||||
|
);
|
||||||
|
expect(y2).toEqual(10);
|
||||||
|
});
|
||||||
|
});
|
@ -5,17 +5,13 @@ import { rotate } from "../math";
|
|||||||
// This set of functions retrieves the absolute position of the 4 points.
|
// This set of functions retrieves the absolute position of the 4 points.
|
||||||
// We can't just always normalize it since we need to remember the fact that an arrow
|
// We can't just always normalize it since we need to remember the fact that an arrow
|
||||||
// is pointing left or right.
|
// is pointing left or right.
|
||||||
export function getElementAbsoluteX1(element: ExcalidrawElement) {
|
export function getElementAbsoluteCoords(element: ExcalidrawElement) {
|
||||||
return element.width >= 0 ? element.x : element.x + element.width;
|
return [
|
||||||
}
|
element.width >= 0 ? element.x : element.x + element.width, // x1
|
||||||
export function getElementAbsoluteX2(element: ExcalidrawElement) {
|
element.height >= 0 ? element.y : element.y + element.height, // y1
|
||||||
return element.width >= 0 ? element.x + element.width : element.x;
|
element.width >= 0 ? element.x + element.width : element.x, // x2
|
||||||
}
|
element.height >= 0 ? element.y + element.height : element.y // y2
|
||||||
export function getElementAbsoluteY1(element: ExcalidrawElement) {
|
];
|
||||||
return element.height >= 0 ? element.y : element.y + element.height;
|
|
||||||
}
|
|
||||||
export function getElementAbsoluteY2(element: ExcalidrawElement) {
|
|
||||||
return element.height >= 0 ? element.y + element.height : element.y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDiamondPoints(element: ExcalidrawElement) {
|
export function getDiamondPoints(element: ExcalidrawElement) {
|
||||||
|
@ -2,12 +2,9 @@ import { distanceBetweenPointAndSegment } from "../math";
|
|||||||
|
|
||||||
import { ExcalidrawElement } from "./types";
|
import { ExcalidrawElement } from "./types";
|
||||||
import {
|
import {
|
||||||
getElementAbsoluteX1,
|
|
||||||
getElementAbsoluteX2,
|
|
||||||
getElementAbsoluteY1,
|
|
||||||
getElementAbsoluteY2,
|
|
||||||
getArrowPoints,
|
getArrowPoints,
|
||||||
getDiamondPoints
|
getDiamondPoints,
|
||||||
|
getElementAbsoluteCoords
|
||||||
} from "./bounds";
|
} from "./bounds";
|
||||||
|
|
||||||
export function hitTest(
|
export function hitTest(
|
||||||
@ -55,10 +52,7 @@ export function hitTest(
|
|||||||
|
|
||||||
return Math.hypot(a * tx - px, b * ty - py) < lineThreshold;
|
return Math.hypot(a * tx - px, b * ty - py) < lineThreshold;
|
||||||
} else if (element.type === "rectangle") {
|
} else if (element.type === "rectangle") {
|
||||||
const x1 = getElementAbsoluteX1(element);
|
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
||||||
const x2 = getElementAbsoluteX2(element);
|
|
||||||
const y1 = getElementAbsoluteY1(element);
|
|
||||||
const y2 = getElementAbsoluteY2(element);
|
|
||||||
|
|
||||||
// (x1, y1) --A-- (x2, y1)
|
// (x1, y1) --A-- (x2, y1)
|
||||||
// |D |B
|
// |D |B
|
||||||
@ -109,10 +103,7 @@ export function hitTest(
|
|||||||
distanceBetweenPointAndSegment(x, y, x4, y4, x2, y2) < lineThreshold
|
distanceBetweenPointAndSegment(x, y, x4, y4, x2, y2) < lineThreshold
|
||||||
);
|
);
|
||||||
} else if (element.type === "text") {
|
} else if (element.type === "text") {
|
||||||
const x1 = getElementAbsoluteX1(element);
|
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
||||||
const x2 = getElementAbsoluteX2(element);
|
|
||||||
const y1 = getElementAbsoluteY1(element);
|
|
||||||
const y2 = getElementAbsoluteY2(element);
|
|
||||||
|
|
||||||
return x >= x1 && x <= x2 && y >= y1 && y <= y2;
|
return x >= x1 && x <= x2 && y >= y1 && y <= y2;
|
||||||
} else if (element.type === "selection") {
|
} else if (element.type === "selection") {
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
export { newElement } from "./newElement";
|
export { newElement } from "./newElement";
|
||||||
export {
|
export {
|
||||||
getElementAbsoluteX1,
|
getElementAbsoluteCoords,
|
||||||
getElementAbsoluteX2,
|
|
||||||
getElementAbsoluteY1,
|
|
||||||
getElementAbsoluteY2,
|
|
||||||
getDiamondPoints,
|
getDiamondPoints,
|
||||||
getArrowPoints
|
getArrowPoints
|
||||||
} from "./bounds";
|
} from "./bounds";
|
||||||
@ -11,5 +8,4 @@ export {
|
|||||||
export { handlerRectangles } from "./handlerRectangles";
|
export { handlerRectangles } from "./handlerRectangles";
|
||||||
export { hitTest } from "./collision";
|
export { hitTest } from "./collision";
|
||||||
export { resizeTest } from "./resizeTest";
|
export { resizeTest } from "./resizeTest";
|
||||||
export { generateDraw } from "./generateDraw";
|
|
||||||
export { isTextElement } from "./typeChecks";
|
export { isTextElement } from "./typeChecks";
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
import { RoughCanvas } from "roughjs/bin/canvas";
|
|
||||||
|
|
||||||
import { SceneState } from "../scene/types";
|
|
||||||
import { randomSeed } from "../random";
|
import { randomSeed } from "../random";
|
||||||
|
|
||||||
export function newElement(
|
export function newElement(
|
||||||
@ -17,24 +14,19 @@ export function newElement(
|
|||||||
height = 0
|
height = 0
|
||||||
) {
|
) {
|
||||||
const element = {
|
const element = {
|
||||||
type: type,
|
type,
|
||||||
x: x,
|
x,
|
||||||
y: y,
|
y,
|
||||||
width: width,
|
width,
|
||||||
height: height,
|
height,
|
||||||
|
strokeColor,
|
||||||
|
backgroundColor,
|
||||||
|
fillStyle,
|
||||||
|
strokeWidth,
|
||||||
|
roughness,
|
||||||
|
opacity,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
strokeColor: strokeColor,
|
seed: randomSeed()
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
fillStyle: fillStyle,
|
|
||||||
strokeWidth: strokeWidth,
|
|
||||||
roughness: roughness,
|
|
||||||
opacity: opacity,
|
|
||||||
seed: randomSeed(),
|
|
||||||
draw(
|
|
||||||
rc: RoughCanvas,
|
|
||||||
context: CanvasRenderingContext2D,
|
|
||||||
sceneState: SceneState
|
|
||||||
) {}
|
|
||||||
};
|
};
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { ExcalidrawElement } from "./element/types";
|
import { ExcalidrawElement } from "./element/types";
|
||||||
import { generateDraw } from "./element";
|
|
||||||
|
|
||||||
class SceneHistory {
|
class SceneHistory {
|
||||||
private recording: boolean = true;
|
private recording: boolean = true;
|
||||||
@ -27,7 +26,6 @@ class SceneHistory {
|
|||||||
const newElements = JSON.parse(entry);
|
const newElements = JSON.parse(entry);
|
||||||
elements.splice(0, elements.length);
|
elements.splice(0, elements.length);
|
||||||
newElements.forEach((newElement: ExcalidrawElement) => {
|
newElements.forEach((newElement: ExcalidrawElement) => {
|
||||||
generateDraw(newElement);
|
|
||||||
elements.push(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
|
// When restoring, we shouldn't add an history entry otherwise we'll be stuck with it and can't go back
|
||||||
|
@ -4,9 +4,8 @@ import rough from "roughjs/bin/wrappers/rough";
|
|||||||
|
|
||||||
import { moveOneLeft, moveAllLeft, moveOneRight, moveAllRight } from "./zindex";
|
import { moveOneLeft, moveAllLeft, moveOneRight, moveAllRight } from "./zindex";
|
||||||
import { randomSeed } from "./random";
|
import { randomSeed } from "./random";
|
||||||
import { newElement, resizeTest, generateDraw, isTextElement } from "./element";
|
import { newElement, resizeTest, isTextElement } from "./element";
|
||||||
import {
|
import {
|
||||||
renderScene,
|
|
||||||
clearSelection,
|
clearSelection,
|
||||||
getSelectedIndices,
|
getSelectedIndices,
|
||||||
deleteSelectedElements,
|
deleteSelectedElements,
|
||||||
@ -26,6 +25,8 @@ import {
|
|||||||
getElementAtPosition,
|
getElementAtPosition,
|
||||||
createScene
|
createScene
|
||||||
} from "./scene";
|
} from "./scene";
|
||||||
|
|
||||||
|
import { renderScene } from "./renderer";
|
||||||
import { AppState } from "./types";
|
import { AppState } from "./types";
|
||||||
import { ExcalidrawElement, ExcalidrawTextElement } from "./element/types";
|
import { ExcalidrawElement, ExcalidrawTextElement } from "./element/types";
|
||||||
|
|
||||||
@ -267,7 +268,6 @@ class App extends React.Component<{}, AppState> {
|
|||||||
element.fillStyle = pastedElement?.fillStyle;
|
element.fillStyle = pastedElement?.fillStyle;
|
||||||
element.opacity = pastedElement?.opacity;
|
element.opacity = pastedElement?.opacity;
|
||||||
element.roughness = pastedElement?.roughness;
|
element.roughness = pastedElement?.roughness;
|
||||||
generateDraw(element);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
@ -303,7 +303,6 @@ class App extends React.Component<{}, AppState> {
|
|||||||
elements.forEach(element => {
|
elements.forEach(element => {
|
||||||
if (element.isSelected) {
|
if (element.isSelected) {
|
||||||
callback(element);
|
callback(element);
|
||||||
generateDraw(element);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -697,7 +696,6 @@ class App extends React.Component<{}, AppState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
generateDraw(element);
|
|
||||||
elements.push(element);
|
elements.push(element);
|
||||||
if (this.state.elementType === "text") {
|
if (this.state.elementType === "text") {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -805,7 +803,6 @@ class App extends React.Component<{}, AppState> {
|
|||||||
|
|
||||||
el.x = element.x;
|
el.x = element.x;
|
||||||
el.y = element.y;
|
el.y = element.y;
|
||||||
generateDraw(el);
|
|
||||||
});
|
});
|
||||||
lastX = x;
|
lastX = x;
|
||||||
lastY = y;
|
lastY = y;
|
||||||
@ -856,8 +853,6 @@ class App extends React.Component<{}, AppState> {
|
|||||||
? Math.abs(width) * Math.sign(height)
|
? Math.abs(width) * Math.sign(height)
|
||||||
: height;
|
: height;
|
||||||
|
|
||||||
generateDraw(draggingElement);
|
|
||||||
|
|
||||||
if (this.state.elementType === "selection") {
|
if (this.state.elementType === "selection") {
|
||||||
setSelection(elements, draggingElement);
|
setSelection(elements, draggingElement);
|
||||||
}
|
}
|
||||||
@ -932,7 +927,6 @@ class App extends React.Component<{}, AppState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
generateDraw(element);
|
|
||||||
elements.push(element);
|
elements.push(element);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -989,7 +983,6 @@ class App extends React.Component<{}, AppState> {
|
|||||||
parsedElement.x = dx ? parsedElement.x + dx : 10 - this.state.scrollX;
|
parsedElement.x = dx ? parsedElement.x + dx : 10 - this.state.scrollX;
|
||||||
parsedElement.y = dy ? parsedElement.y + dy : 10 - this.state.scrollY;
|
parsedElement.y = dy ? parsedElement.y + dy : 10 - this.state.scrollY;
|
||||||
parsedElement.seed = randomSeed();
|
parsedElement.seed = randomSeed();
|
||||||
generateDraw(parsedElement);
|
|
||||||
elements.push(parsedElement);
|
elements.push(parsedElement);
|
||||||
});
|
});
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
|
1
src/renderer/index.ts
Normal file
1
src/renderer/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export { renderScene } from "./renderScene";
|
@ -2,17 +2,23 @@ import rough from "roughjs/bin/wrappers/rough";
|
|||||||
|
|
||||||
import { withCustomMathRandom } from "../random";
|
import { withCustomMathRandom } from "../random";
|
||||||
|
|
||||||
import { ExcalidrawElement } from "./types";
|
import { ExcalidrawElement } from "../element/types";
|
||||||
import { isTextElement } from "./typeChecks";
|
import { isTextElement } from "../element/typeChecks";
|
||||||
import { getDiamondPoints, getArrowPoints } from "./bounds";
|
import { getDiamondPoints, getArrowPoints } from "../element/bounds";
|
||||||
|
import { RoughCanvas } from "roughjs/bin/canvas";
|
||||||
|
import { SceneState } from "../scene/types";
|
||||||
|
|
||||||
// Casting second argument (DrawingSurface) to any,
|
// Casting second argument (DrawingSurface) to any,
|
||||||
// because it is requred by TS definitions and not required at runtime
|
// because it is requred by TS definitions and not required at runtime
|
||||||
const generator = rough.generator(null, null as any);
|
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") {
|
if (element.type === "selection") {
|
||||||
element.draw = (rc, context, { scrollX, scrollY }) => {
|
|
||||||
const fillStyle = context.fillStyle;
|
const fillStyle = context.fillStyle;
|
||||||
context.fillStyle = "rgba(0, 0, 255, 0.10)";
|
context.fillStyle = "rgba(0, 0, 255, 0.10)";
|
||||||
context.fillRect(
|
context.fillRect(
|
||||||
@ -22,7 +28,6 @@ export function generateDraw(element: ExcalidrawElement) {
|
|||||||
element.height
|
element.height
|
||||||
);
|
);
|
||||||
context.fillStyle = fillStyle;
|
context.fillStyle = fillStyle;
|
||||||
};
|
|
||||||
} else if (element.type === "rectangle") {
|
} else if (element.type === "rectangle") {
|
||||||
const shape = withCustomMathRandom(element.seed, () => {
|
const shape = withCustomMathRandom(element.seed, () => {
|
||||||
return generator.rectangle(0, 0, element.width, element.height, {
|
return generator.rectangle(0, 0, element.width, element.height, {
|
||||||
@ -33,13 +38,12 @@ export function generateDraw(element: ExcalidrawElement) {
|
|||||||
roughness: element.roughness
|
roughness: element.roughness
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
element.draw = (rc, context, { scrollX, scrollY }) => {
|
|
||||||
context.globalAlpha = element.opacity / 100;
|
context.globalAlpha = element.opacity / 100;
|
||||||
context.translate(element.x + scrollX, element.y + scrollY);
|
context.translate(element.x + scrollX, element.y + scrollY);
|
||||||
rc.draw(shape);
|
rc.draw(shape);
|
||||||
context.translate(-element.x - scrollX, -element.y - scrollY);
|
context.translate(-element.x - scrollX, -element.y - scrollY);
|
||||||
context.globalAlpha = 1;
|
context.globalAlpha = 1;
|
||||||
};
|
|
||||||
} else if (element.type === "diamond") {
|
} else if (element.type === "diamond") {
|
||||||
const shape = withCustomMathRandom(element.seed, () => {
|
const shape = withCustomMathRandom(element.seed, () => {
|
||||||
const [
|
const [
|
||||||
@ -68,13 +72,11 @@ export function generateDraw(element: ExcalidrawElement) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
element.draw = (rc, context, { scrollX, scrollY }) => {
|
|
||||||
context.globalAlpha = element.opacity / 100;
|
context.globalAlpha = element.opacity / 100;
|
||||||
context.translate(element.x + scrollX, element.y + scrollY);
|
context.translate(element.x + scrollX, element.y + scrollY);
|
||||||
rc.draw(shape);
|
rc.draw(shape);
|
||||||
context.translate(-element.x - scrollX, -element.y - scrollY);
|
context.translate(-element.x - scrollX, -element.y - scrollY);
|
||||||
context.globalAlpha = 1;
|
context.globalAlpha = 1;
|
||||||
};
|
|
||||||
} else if (element.type === "ellipse") {
|
} else if (element.type === "ellipse") {
|
||||||
const shape = withCustomMathRandom(element.seed, () =>
|
const shape = withCustomMathRandom(element.seed, () =>
|
||||||
generator.ellipse(
|
generator.ellipse(
|
||||||
@ -91,13 +93,12 @@ export function generateDraw(element: ExcalidrawElement) {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
element.draw = (rc, context, { scrollX, scrollY }) => {
|
|
||||||
context.globalAlpha = element.opacity / 100;
|
context.globalAlpha = element.opacity / 100;
|
||||||
context.translate(element.x + scrollX, element.y + scrollY);
|
context.translate(element.x + scrollX, element.y + scrollY);
|
||||||
rc.draw(shape);
|
rc.draw(shape);
|
||||||
context.translate(-element.x - scrollX, -element.y - scrollY);
|
context.translate(-element.x - scrollX, -element.y - scrollY);
|
||||||
context.globalAlpha = 1;
|
context.globalAlpha = 1;
|
||||||
};
|
|
||||||
} else if (element.type === "arrow") {
|
} else if (element.type === "arrow") {
|
||||||
const [x1, y1, x2, y2, x3, y3, x4, y4] = getArrowPoints(element);
|
const [x1, y1, x2, y2, x3, y3, x4, y4] = getArrowPoints(element);
|
||||||
const options = {
|
const options = {
|
||||||
@ -115,16 +116,13 @@ export function generateDraw(element: ExcalidrawElement) {
|
|||||||
generator.line(x4, y4, x2, y2, options)
|
generator.line(x4, y4, x2, y2, options)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
element.draw = (rc, context, { scrollX, scrollY }) => {
|
|
||||||
context.globalAlpha = element.opacity / 100;
|
context.globalAlpha = element.opacity / 100;
|
||||||
context.translate(element.x + scrollX, element.y + scrollY);
|
context.translate(element.x + scrollX, element.y + scrollY);
|
||||||
shapes.forEach(shape => rc.draw(shape));
|
shapes.forEach(shape => rc.draw(shape));
|
||||||
context.translate(-element.x - scrollX, -element.y - scrollY);
|
context.translate(-element.x - scrollX, -element.y - scrollY);
|
||||||
context.globalAlpha = 1;
|
context.globalAlpha = 1;
|
||||||
};
|
|
||||||
return;
|
return;
|
||||||
} else if (isTextElement(element)) {
|
} else if (isTextElement(element)) {
|
||||||
element.draw = (rc, context, { scrollX, scrollY }) => {
|
|
||||||
context.globalAlpha = element.opacity / 100;
|
context.globalAlpha = element.opacity / 100;
|
||||||
const font = context.font;
|
const font = context.font;
|
||||||
context.font = element.font;
|
context.font = element.font;
|
||||||
@ -138,7 +136,6 @@ export function generateDraw(element: ExcalidrawElement) {
|
|||||||
context.fillStyle = fillStyle;
|
context.fillStyle = fillStyle;
|
||||||
context.font = font;
|
context.font = font;
|
||||||
context.globalAlpha = 1;
|
context.globalAlpha = 1;
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Unimplemented type " + element.type);
|
throw new Error("Unimplemented type " + element.type);
|
||||||
}
|
}
|
@ -1,18 +1,17 @@
|
|||||||
import { RoughCanvas } from "roughjs/bin/canvas";
|
import { RoughCanvas } from "roughjs/bin/canvas";
|
||||||
|
|
||||||
import { ExcalidrawElement } from "../element/types";
|
import { ExcalidrawElement } from "../element/types";
|
||||||
import {
|
import { getElementAbsoluteCoords, handlerRectangles } from "../element";
|
||||||
getElementAbsoluteX1,
|
|
||||||
getElementAbsoluteX2,
|
|
||||||
getElementAbsoluteY1,
|
|
||||||
getElementAbsoluteY2,
|
|
||||||
handlerRectangles
|
|
||||||
} from "../element";
|
|
||||||
|
|
||||||
import { roundRect } from "./roundRect";
|
import { roundRect } from "../scene/roundRect";
|
||||||
import { SceneState } from "./types";
|
import { SceneState } from "../scene/types";
|
||||||
import { getScrollBars, SCROLLBAR_COLOR, SCROLLBAR_WIDTH } from "./scrollbars";
|
import {
|
||||||
import { getSelectedIndices } from "./selection";
|
getScrollBars,
|
||||||
|
SCROLLBAR_COLOR,
|
||||||
|
SCROLLBAR_WIDTH
|
||||||
|
} from "../scene/scrollbars";
|
||||||
|
|
||||||
|
import { renderElement } from "./renderElement";
|
||||||
|
|
||||||
export function renderScene(
|
export function renderScene(
|
||||||
elements: ExcalidrawElement[],
|
elements: ExcalidrawElement[],
|
||||||
@ -44,8 +43,6 @@ export function renderScene(
|
|||||||
}
|
}
|
||||||
context.fillStyle = fillStyle;
|
context.fillStyle = fillStyle;
|
||||||
|
|
||||||
const selectedIndices = getSelectedIndices(elements);
|
|
||||||
|
|
||||||
sceneState = {
|
sceneState = {
|
||||||
...sceneState,
|
...sceneState,
|
||||||
scrollX: typeof offsetX === "number" ? offsetX : sceneState.scrollX,
|
scrollX: typeof offsetX === "number" ? offsetX : sceneState.scrollX,
|
||||||
@ -53,14 +50,21 @@ export function renderScene(
|
|||||||
};
|
};
|
||||||
|
|
||||||
elements.forEach(element => {
|
elements.forEach(element => {
|
||||||
element.draw(rc, context, sceneState);
|
renderElement(element, rc, context, sceneState);
|
||||||
if (renderSelection && element.isSelected) {
|
});
|
||||||
|
|
||||||
|
if (renderSelection) {
|
||||||
|
const selectedElements = elements.filter(el => el.isSelected);
|
||||||
|
|
||||||
|
selectedElements.forEach(element => {
|
||||||
const margin = 4;
|
const margin = 4;
|
||||||
|
|
||||||
const elementX1 = getElementAbsoluteX1(element);
|
const [
|
||||||
const elementX2 = getElementAbsoluteX2(element);
|
elementX1,
|
||||||
const elementY1 = getElementAbsoluteY1(element);
|
elementY1,
|
||||||
const elementY2 = getElementAbsoluteY2(element);
|
elementX2,
|
||||||
|
elementY2
|
||||||
|
] = getElementAbsoluteCoords(element);
|
||||||
const lineDash = context.getLineDash();
|
const lineDash = context.getLineDash();
|
||||||
context.setLineDash([8, 4]);
|
context.setLineDash([8, 4]);
|
||||||
context.strokeRect(
|
context.strokeRect(
|
||||||
@ -70,15 +74,15 @@ export function renderScene(
|
|||||||
elementY2 - elementY1 + margin * 2
|
elementY2 - elementY1 + margin * 2
|
||||||
);
|
);
|
||||||
context.setLineDash(lineDash);
|
context.setLineDash(lineDash);
|
||||||
|
});
|
||||||
|
|
||||||
if (element.type !== "text" && selectedIndices.length === 1) {
|
if (selectedElements.length === 1 && selectedElements[0].type !== "text") {
|
||||||
const handlers = handlerRectangles(element, sceneState);
|
const handlers = handlerRectangles(selectedElements[0], sceneState);
|
||||||
Object.values(handlers).forEach(handler => {
|
Object.values(handlers).forEach(handler => {
|
||||||
context.strokeRect(handler[0], handler[1], handler[2], handler[3]);
|
context.strokeRect(handler[0], handler[1], handler[2], handler[3]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
if (renderScrollbars) {
|
if (renderScrollbars) {
|
||||||
const scrollBars = getScrollBars(
|
const scrollBars = getScrollBars(
|
@ -2,15 +2,9 @@ import rough from "roughjs/bin/wrappers/rough";
|
|||||||
|
|
||||||
import { ExcalidrawElement } from "../element/types";
|
import { ExcalidrawElement } from "../element/types";
|
||||||
|
|
||||||
import {
|
import { getElementAbsoluteCoords } from "../element";
|
||||||
getElementAbsoluteX1,
|
|
||||||
getElementAbsoluteX2,
|
|
||||||
getElementAbsoluteY1,
|
|
||||||
getElementAbsoluteY2,
|
|
||||||
generateDraw
|
|
||||||
} from "../element";
|
|
||||||
|
|
||||||
import { renderScene } from "./render";
|
import { renderScene } from "../renderer";
|
||||||
import { AppState } from "../types";
|
import { AppState } from "../types";
|
||||||
|
|
||||||
const LOCAL_STORAGE_KEY = "excalidraw";
|
const LOCAL_STORAGE_KEY = "excalidraw";
|
||||||
@ -94,10 +88,11 @@ export function exportAsPNG(
|
|||||||
let subCanvasY2 = 0;
|
let subCanvasY2 = 0;
|
||||||
|
|
||||||
elements.forEach(element => {
|
elements.forEach(element => {
|
||||||
subCanvasX1 = Math.min(subCanvasX1, getElementAbsoluteX1(element));
|
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
||||||
subCanvasX2 = Math.max(subCanvasX2, getElementAbsoluteX2(element));
|
subCanvasX1 = Math.min(subCanvasX1, x1);
|
||||||
subCanvasY1 = Math.min(subCanvasY1, getElementAbsoluteY1(element));
|
subCanvasY1 = Math.min(subCanvasY1, y1);
|
||||||
subCanvasY2 = Math.max(subCanvasY2, getElementAbsoluteY2(element));
|
subCanvasX2 = Math.max(subCanvasX2, x2);
|
||||||
|
subCanvasY2 = Math.max(subCanvasY2, y2);
|
||||||
});
|
});
|
||||||
|
|
||||||
function distance(x: number, y: number) {
|
function distance(x: number, y: number) {
|
||||||
@ -155,8 +150,6 @@ function restore(
|
|||||||
element.opacity === null || element.opacity === undefined
|
element.opacity === null || element.opacity === undefined
|
||||||
? 100
|
? 100
|
||||||
: element.opacity;
|
: element.opacity;
|
||||||
|
|
||||||
generateDraw(element);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
export { isOverScrollBars } from "./scrollbars";
|
export { isOverScrollBars } from "./scrollbars";
|
||||||
export { renderScene } from "./render";
|
|
||||||
export {
|
export {
|
||||||
clearSelection,
|
clearSelection,
|
||||||
getSelectedIndices,
|
getSelectedIndices,
|
||||||
|
@ -1,10 +1,5 @@
|
|||||||
import { ExcalidrawElement } from "../element/types";
|
import { ExcalidrawElement } from "../element/types";
|
||||||
import {
|
import { getElementAbsoluteCoords } from "../element";
|
||||||
getElementAbsoluteX1,
|
|
||||||
getElementAbsoluteX2,
|
|
||||||
getElementAbsoluteY1,
|
|
||||||
getElementAbsoluteY2
|
|
||||||
} from "../element";
|
|
||||||
|
|
||||||
const SCROLLBAR_MIN_SIZE = 15;
|
const SCROLLBAR_MIN_SIZE = 15;
|
||||||
const SCROLLBAR_MARGIN = 4;
|
const SCROLLBAR_MARGIN = 4;
|
||||||
@ -24,10 +19,11 @@ export function getScrollBars(
|
|||||||
let maxY = 0;
|
let maxY = 0;
|
||||||
|
|
||||||
elements.forEach(element => {
|
elements.forEach(element => {
|
||||||
minX = Math.min(minX, getElementAbsoluteX1(element));
|
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
|
||||||
maxX = Math.max(maxX, getElementAbsoluteX2(element));
|
minX = Math.min(minX, x1);
|
||||||
minY = Math.min(minY, getElementAbsoluteY1(element));
|
minY = Math.min(minY, y1);
|
||||||
maxY = Math.max(maxY, getElementAbsoluteY2(element));
|
maxX = Math.max(maxX, x2);
|
||||||
|
maxY = Math.max(maxY, y2);
|
||||||
});
|
});
|
||||||
|
|
||||||
minX += scrollX;
|
minX += scrollX;
|
||||||
|
@ -1,24 +1,23 @@
|
|||||||
import { ExcalidrawElement } from "../element/types";
|
import { ExcalidrawElement } from "../element/types";
|
||||||
import {
|
import { getElementAbsoluteCoords } from "../element";
|
||||||
getElementAbsoluteX1,
|
|
||||||
getElementAbsoluteX2,
|
|
||||||
getElementAbsoluteY1,
|
|
||||||
getElementAbsoluteY2
|
|
||||||
} from "../element";
|
|
||||||
|
|
||||||
export function setSelection(
|
export function setSelection(
|
||||||
elements: ExcalidrawElement[],
|
elements: ExcalidrawElement[],
|
||||||
selection: ExcalidrawElement
|
selection: ExcalidrawElement
|
||||||
) {
|
) {
|
||||||
const selectionX1 = getElementAbsoluteX1(selection);
|
const [
|
||||||
const selectionX2 = getElementAbsoluteX2(selection);
|
selectionX1,
|
||||||
const selectionY1 = getElementAbsoluteY1(selection);
|
selectionY1,
|
||||||
const selectionY2 = getElementAbsoluteY2(selection);
|
selectionX2,
|
||||||
|
selectionY2
|
||||||
|
] = getElementAbsoluteCoords(selection);
|
||||||
elements.forEach(element => {
|
elements.forEach(element => {
|
||||||
const elementX1 = getElementAbsoluteX1(element);
|
const [
|
||||||
const elementX2 = getElementAbsoluteX2(element);
|
elementX1,
|
||||||
const elementY1 = getElementAbsoluteY1(element);
|
elementY1,
|
||||||
const elementY2 = getElementAbsoluteY2(element);
|
elementX2,
|
||||||
|
elementY2
|
||||||
|
] = getElementAbsoluteCoords(element);
|
||||||
element.isSelected =
|
element.isSelected =
|
||||||
element.type !== "selection" &&
|
element.type !== "selection" &&
|
||||||
selectionX1 <= elementX1 &&
|
selectionX1 <= elementX1 &&
|
||||||
|
Loading…
x
Reference in New Issue
Block a user