From b18a0efe2cc141a3d9f54b3bcd8abdbbbddbb643 Mon Sep 17 00:00:00 2001 From: Christopher Chedeau Date: Fri, 3 Jan 2020 12:33:52 -0800 Subject: [PATCH] Seed (#73) --- src/index.tsx | 43 ++++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 44492cec..9837a1e3 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -18,6 +18,21 @@ const LOCAL_STORAGE_KEY_STATE = "excalidraw-state"; var elements = Array.of(); +// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript/47593316#47593316 +const LCG = (seed: number) => () => + ((2 ** 31 - 1) & (seed = Math.imul(48271, seed))) / 2 ** 31; + +// Unfortunately, roughjs doesn't support a seed attribute (https://github.com/pshihn/rough/issues/27). +// We can achieve the same result by overriding the Math.random function with a +// pseudo random generator that supports a random seed and swapping it back after. +function withCustomMathRandom(seed: number, cb: () => T): T { + const random = Math.random; + Math.random = LCG(seed); + const result = cb(); + Math.random = random; + return result; +} + // https://stackoverflow.com/a/6853926/232122 function distanceBetweenPointAndSegment( x: number, @@ -126,6 +141,7 @@ function newElement( isSelected: false, strokeColor: strokeColor, backgroundColor: backgroundColor, + seed: Math.floor(Math.random() * 2 ** 31), draw(rc: RoughCanvas, context: CanvasRenderingContext2D) {} }; return element; @@ -307,22 +323,27 @@ function generateDraw(element: ExcalidrawElement) { context.fillStyle = fillStyle; }; } else if (element.type === "rectangle") { - const shape = generator.rectangle(0, 0, element.width, element.height, { - stroke: element.strokeColor, - fill: element.backgroundColor + const shape = withCustomMathRandom(element.seed, () => { + return generator.rectangle(0, 0, element.width, element.height, { + stroke: element.strokeColor, + fill: element.backgroundColor + }); }); + element.draw = (rc, context) => { context.translate(element.x, element.y); rc.draw(shape); context.translate(-element.x, -element.y); }; } else if (element.type === "ellipse") { - const shape = generator.ellipse( - element.width / 2, - element.height / 2, - element.width, - element.height, - { stroke: element.strokeColor, fill: element.backgroundColor } + const shape = withCustomMathRandom(element.seed, () => + generator.ellipse( + element.width / 2, + element.height / 2, + element.width, + element.height, + { stroke: element.strokeColor, fill: element.backgroundColor } + ) ); element.draw = (rc, context) => { context.translate(element.x, element.y); @@ -331,14 +352,14 @@ function generateDraw(element: ExcalidrawElement) { }; } else if (element.type === "arrow") { const [x1, y1, x2, y2, x3, y3, x4, y4] = getArrowPoints(element); - const shapes = [ + const shapes = withCustomMathRandom(element.seed, () => [ // \ generator.line(x3, y3, x2, y2, { stroke: element.strokeColor }), // ----- generator.line(x1, y1, x2, y2, { stroke: element.strokeColor }), // / generator.line(x4, y4, x2, y2, { stroke: element.strokeColor }) - ]; + ]); element.draw = (rc, context) => { context.translate(element.x, element.y);