diff --git a/src/index.tsx b/src/index.tsx index 69dad2e8..45d3f788 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -254,6 +254,10 @@ function newElement( y: number, strokeColor: string, backgroundColor: string, + fillStyle: string, + strokeWidth: number, + roughness: number, + opacity: number, width = 0, height = 0 ) { @@ -266,6 +270,10 @@ function newElement( isSelected: false, strokeColor: strokeColor, backgroundColor: backgroundColor, + fillStyle: fillStyle, + strokeWidth: strokeWidth, + roughness: roughness, + opacity: opacity, seed: randomSeed(), draw( rc: RoughCanvas, @@ -761,13 +769,18 @@ function generateDraw(element: ExcalidrawElement) { const shape = withCustomMathRandom(element.seed, () => { return generator.rectangle(0, 0, element.width, element.height, { stroke: element.strokeColor, - fill: element.backgroundColor + fill: element.backgroundColor, + fillStyle: element.fillStyle, + strokeWidth: element.strokeWidth, + 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, () => { @@ -790,14 +803,19 @@ function generateDraw(element: ExcalidrawElement) { ], { stroke: element.strokeColor, - fill: element.backgroundColor + fill: element.backgroundColor, + fillStyle: element.fillStyle, + strokeWidth: element.strokeWidth, + 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 === "ellipse") { const shape = withCustomMathRandom(element.seed, () => @@ -806,33 +824,56 @@ function generateDraw(element: ExcalidrawElement) { element.height / 2, element.width, element.height, - { stroke: element.strokeColor, fill: element.backgroundColor } + { + stroke: element.strokeColor, + fill: element.backgroundColor, + fillStyle: element.fillStyle, + strokeWidth: element.strokeWidth, + 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 === "arrow") { const [x1, y1, x2, y2, x3, y3, x4, y4] = getArrowPoints(element); const shapes = withCustomMathRandom(element.seed, () => [ // \ - generator.line(x3, y3, x2, y2, { stroke: element.strokeColor }), + generator.line(x3, y3, x2, y2, { + stroke: element.strokeColor, + strokeWidth: element.strokeWidth, + roughness: element.roughness + }), // ----- - generator.line(x1, y1, x2, y2, { stroke: element.strokeColor }), + generator.line(x1, y1, x2, y2, { + stroke: element.strokeColor, + strokeWidth: element.strokeWidth, + roughness: element.roughness + }), // / - generator.line(x4, y4, x2, y2, { stroke: element.strokeColor }) + generator.line(x4, y4, x2, y2, { + stroke: element.strokeColor, + strokeWidth: element.strokeWidth, + roughness: element.roughness + }) ]); 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; const fillStyle = context.fillStyle; @@ -844,6 +885,7 @@ function generateDraw(element: ExcalidrawElement) { ); context.fillStyle = fillStyle; context.font = font; + context.globalAlpha = 1; }; } else { throw new Error("Unimplemented type " + element.type); @@ -1064,6 +1106,91 @@ function getSelectedIndices() { const someElementIsSelected = () => elements.some(element => element.isSelected); +const someElementIsSelectedIsRectangleOrEllipseOrDiamond = () => + elements.some( + element => + element.isSelected && + (element.type === "rectangle" || + element.type === "ellipse" || + element.type === "diamond") + ); + +const someElementIsSelectedIsRectangleOrEllipseOrDiamondOrArrow = () => + elements.some( + element => + element.isSelected && + (element.type === "rectangle" || + element.type === "ellipse" || + element.type === "diamond" || + element.type === "arrow") + ); + +function getSelectedFillStyles() { + const fillStyles = Array.from( + new Set( + elements + .filter(element => element.isSelected) + .map(element => element.fillStyle) + ) + ); + return fillStyles.length === 1 ? fillStyles[0] : ""; +} + +function getSelectedStrokeWidth() { + const strokeWidth = Array.from( + new Set( + elements + .filter(element => element.isSelected) + .map(element => `${element.strokeWidth}`) + ) + ); + return strokeWidth.length === 1 ? +strokeWidth[0] : ""; +} + +function getSelectedRoughness() { + const roughness = Array.from( + new Set( + elements + .filter(element => element.isSelected) + .map(element => `${element.roughness}`) + ) + ); + return roughness.length === 1 ? +roughness[0] : ""; +} + +function getSelectedOpacity() { + const opacity = Array.from( + new Set( + elements + .filter(element => element.isSelected) + .map(element => `${element.opacity}`) + ) + ); + return opacity.length === 1 ? +opacity[0] : ""; +} + +function getSelectedStrokeColor() { + const strokeColors = Array.from( + new Set( + elements + .filter(element => element.isSelected) + .map(element => element.strokeColor) + ) + ); + return strokeColors.length === 1 ? strokeColors[0] : null; +} + +function getSelectedBackgroundColor() { + const backgroundColors = Array.from( + new Set( + elements + .filter(element => element.isSelected) + .map(element => element.backgroundColor) + ) + ); + return backgroundColors.length === 1 ? backgroundColors[0] : null; +} + const ELEMENT_SHIFT_TRANSLATE_AMOUNT = 5; const ELEMENT_TRANSLATE_AMOUNT = 1; @@ -1228,6 +1355,43 @@ class App extends React.Component<{}, AppState> { this.setState({ name }); } + private changeProperty = (callback: (element: ExcalidrawElement) => void) => { + elements.forEach(element => { + if (element.isSelected) { + callback(element); + generateDraw(element); + } + }); + + this.forceUpdate(); + }; + + private changeFillStyle = (style: string) => { + this.changeProperty(element => (element.fillStyle = style)); + }; + + private changeStrokeWidth = (event: React.ChangeEvent) => { + this.changeProperty(element => (element.strokeWidth = +event.target.value)); + }; + + private changeRoughness = (event: React.ChangeEvent) => { + this.changeProperty(element => (element.roughness = +event.target.value)); + }; + + private changeOpacity = (event: React.ChangeEvent) => { + this.changeProperty(element => (element.opacity = +event.target.value)); + }; + + private changeStrokeColor = (color: string) => { + this.changeProperty(element => (element.strokeColor = color)); + this.setState({ currentItemStrokeColor: color }); + }; + + private changeBackgroundColor = (color: string) => { + this.changeProperty(element => (element.backgroundColor = color)); + this.setState({ currentItemBackgroundColor: color }); + }; + public render() { const canvasWidth = window.innerWidth - CANVAS_WINDOW_OFFSET_LEFT; const canvasHeight = window.innerHeight - CANVAS_WINDOW_OFFSET_TOP; @@ -1353,85 +1517,6 @@ class App extends React.Component<{}, AppState> { } /> -
Shape Stroke Color
-
-
+ {someElementIsSelected() && ( + <> + <> +

Colors

+
+
Shape Stroke Color
+
+
+ + {someElementIsSelectedIsRectangleOrEllipseOrDiamond() && ( +
+
Shape Background Color
+
+
+ )} + + + {someElementIsSelectedIsRectangleOrEllipseOrDiamond() && ( + <> +

Fill

+
+ {/* */} +
+ + )} + + {someElementIsSelectedIsRectangleOrEllipseOrDiamondOrArrow() && ( + <> +

Stroke width

+
+ +
+ +

Roughness

+
+ +
+ + )} + +

Opacity

+ + + )}
{ x, y, this.state.currentItemStrokeColor, - this.state.currentItemBackgroundColor + this.state.currentItemBackgroundColor, + "hachure", + 1, + 1, + 100 ); let resizeHandle: string | false = false; let isDraggingElements = false; diff --git a/src/styles.scss b/src/styles.scss index 0a05831c..a8f7f997 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -110,6 +110,10 @@ input[type="color"] { margin: 2px; } +input[type="range"] { + width: 230px; +} + input { margin-right: 5px; @@ -136,7 +140,7 @@ button { border-color: #d6d4d4; } - &:active { + &:active, &.active { background-color: #bdbebc; border-color: #bdbebc; }