|
@@ -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<HTMLSelectElement>) => {
|
|
|
+ this.changeProperty(element => (element.strokeWidth = +event.target.value));
|
|
|
+ };
|
|
|
+
|
|
|
+ private changeRoughness = (event: React.ChangeEvent<HTMLSelectElement>) => {
|
|
|
+ this.changeProperty(element => (element.roughness = +event.target.value));
|
|
|
+ };
|
|
|
+
|
|
|
+ private changeOpacity = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
|
+ 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> {
|
|
|
}
|
|
|
/>
|
|
|
</div>
|
|
|
- <h5>Shape Stroke Color</h5>
|
|
|
- <div>
|
|
|
- <button
|
|
|
- className="swatch"
|
|
|
- style={{
|
|
|
- backgroundColor: this.state.currentItemStrokeColor
|
|
|
- }}
|
|
|
- onClick={() =>
|
|
|
- this.setState(s => ({
|
|
|
- currentColorPicker:
|
|
|
- s.currentColorPicker === ColorPicker.SHAPE_STROKE
|
|
|
- ? null
|
|
|
- : ColorPicker.SHAPE_STROKE
|
|
|
- }))
|
|
|
- }
|
|
|
- />
|
|
|
- {this.state.currentColorPicker === ColorPicker.SHAPE_STROKE ? (
|
|
|
- <div className="popover">
|
|
|
- <div
|
|
|
- className="cover"
|
|
|
- onClick={() => this.setState({ currentColorPicker: null })}
|
|
|
- />
|
|
|
- <SketchPicker
|
|
|
- color={this.state.currentItemStrokeColor}
|
|
|
- onChange={color => {
|
|
|
- this.setState({ currentItemStrokeColor: color.hex });
|
|
|
- }}
|
|
|
- />
|
|
|
- </div>
|
|
|
- ) : null}
|
|
|
- <input
|
|
|
- type="text"
|
|
|
- className="swatch-input"
|
|
|
- value={this.state.currentItemStrokeColor}
|
|
|
- onChange={e => {
|
|
|
- this.setState({ currentItemStrokeColor: e.target.value });
|
|
|
- }}
|
|
|
- />
|
|
|
- </div>
|
|
|
- <h5>Shape Background Color</h5>
|
|
|
- <div>
|
|
|
- <button
|
|
|
- className="swatch"
|
|
|
- style={{
|
|
|
- backgroundColor: this.state.currentItemBackgroundColor
|
|
|
- }}
|
|
|
- onClick={() =>
|
|
|
- this.setState(s => ({
|
|
|
- currentColorPicker:
|
|
|
- s.currentColorPicker === ColorPicker.SHAPE_BACKGROUND
|
|
|
- ? null
|
|
|
- : ColorPicker.SHAPE_BACKGROUND
|
|
|
- }))
|
|
|
- }
|
|
|
- />
|
|
|
- {this.state.currentColorPicker ===
|
|
|
- ColorPicker.SHAPE_BACKGROUND ? (
|
|
|
- <div className="popover">
|
|
|
- <div
|
|
|
- className="cover"
|
|
|
- onClick={() => this.setState({ currentColorPicker: null })}
|
|
|
- />
|
|
|
- <SketchPicker
|
|
|
- color={this.state.currentItemBackgroundColor}
|
|
|
- onChange={color => {
|
|
|
- this.setState({ currentItemBackgroundColor: color.hex });
|
|
|
- }}
|
|
|
- />
|
|
|
- </div>
|
|
|
- ) : null}
|
|
|
- <input
|
|
|
- type="text"
|
|
|
- className="swatch-input"
|
|
|
- value={this.state.currentItemStrokeColor}
|
|
|
- onChange={e => {
|
|
|
- this.setState({ currentItemStrokeColor: e.target.value });
|
|
|
- }}
|
|
|
- />
|
|
|
- </div>
|
|
|
<button
|
|
|
onClick={this.clearCanvas}
|
|
|
title="Clear the canvas & reset background color"
|
|
@@ -1482,6 +1567,231 @@ class App extends React.Component<{}, AppState> {
|
|
|
Load file...
|
|
|
</button>
|
|
|
</div>
|
|
|
+ {someElementIsSelected() && (
|
|
|
+ <>
|
|
|
+ <>
|
|
|
+ <h4>Colors</h4>
|
|
|
+ <div className="panelColumn">
|
|
|
+ <h5>Shape Stroke Color</h5>
|
|
|
+ <div>
|
|
|
+ <button
|
|
|
+ className="swatch"
|
|
|
+ style={{
|
|
|
+ backgroundColor:
|
|
|
+ getSelectedStrokeColor() ||
|
|
|
+ this.state.currentItemStrokeColor
|
|
|
+ }}
|
|
|
+ onClick={() =>
|
|
|
+ this.setState(s => ({
|
|
|
+ currentColorPicker:
|
|
|
+ s.currentColorPicker === ColorPicker.SHAPE_STROKE
|
|
|
+ ? null
|
|
|
+ : ColorPicker.SHAPE_STROKE
|
|
|
+ }))
|
|
|
+ }
|
|
|
+ />
|
|
|
+ {this.state.currentColorPicker ===
|
|
|
+ ColorPicker.SHAPE_STROKE && (
|
|
|
+ <div className="popover">
|
|
|
+ <div
|
|
|
+ className="cover"
|
|
|
+ onClick={() =>
|
|
|
+ this.setState({ currentColorPicker: null })
|
|
|
+ }
|
|
|
+ />
|
|
|
+ <SketchPicker
|
|
|
+ color={this.state.currentItemStrokeColor}
|
|
|
+ onChange={color => this.changeStrokeColor(color.hex)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ <input
|
|
|
+ type="text"
|
|
|
+ className="swatch-input"
|
|
|
+ value={
|
|
|
+ getSelectedStrokeColor() ||
|
|
|
+ this.state.currentItemStrokeColor
|
|
|
+ }
|
|
|
+ onChange={e => this.changeStrokeColor(e.target.value)}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {someElementIsSelectedIsRectangleOrEllipseOrDiamond() && (
|
|
|
+ <div className="panelColumn">
|
|
|
+ <h5>Shape Background Color</h5>
|
|
|
+ <div>
|
|
|
+ <button
|
|
|
+ className="swatch"
|
|
|
+ style={{
|
|
|
+ backgroundColor:
|
|
|
+ getSelectedBackgroundColor() ||
|
|
|
+ this.state.currentItemBackgroundColor
|
|
|
+ }}
|
|
|
+ onClick={() =>
|
|
|
+ this.setState(s => ({
|
|
|
+ currentColorPicker:
|
|
|
+ s.currentColorPicker ===
|
|
|
+ ColorPicker.SHAPE_BACKGROUND
|
|
|
+ ? null
|
|
|
+ : ColorPicker.SHAPE_BACKGROUND
|
|
|
+ }))
|
|
|
+ }
|
|
|
+ />
|
|
|
+ {this.state.currentColorPicker ===
|
|
|
+ ColorPicker.SHAPE_BACKGROUND ? (
|
|
|
+ <div className="popover">
|
|
|
+ <div
|
|
|
+ className="cover"
|
|
|
+ onClick={() =>
|
|
|
+ this.setState({ currentColorPicker: null })
|
|
|
+ }
|
|
|
+ />
|
|
|
+ <SketchPicker
|
|
|
+ color={this.state.currentItemBackgroundColor}
|
|
|
+ onChange={color =>
|
|
|
+ this.changeBackgroundColor(color.hex)
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ ) : null}
|
|
|
+ <input
|
|
|
+ type="text"
|
|
|
+ className="swatch-input"
|
|
|
+ value={
|
|
|
+ getSelectedBackgroundColor() ||
|
|
|
+ this.state.currentItemBackgroundColor
|
|
|
+ }
|
|
|
+ onChange={e =>
|
|
|
+ this.changeBackgroundColor(e.target.value)
|
|
|
+ }
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </>
|
|
|
+
|
|
|
+ {someElementIsSelectedIsRectangleOrEllipseOrDiamond() && (
|
|
|
+ <>
|
|
|
+ <h4>Fill</h4>
|
|
|
+ <div className="panelColumn">
|
|
|
+ {/* <select onChange={this.changeFillStyle} value={getSelectedFillStyles()}> */}
|
|
|
+ <button
|
|
|
+ onClick={() => this.changeFillStyle("hachure")}
|
|
|
+ className={
|
|
|
+ getSelectedFillStyles() === "hachure" ? "active" : ""
|
|
|
+ }
|
|
|
+ >
|
|
|
+ Hachure
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ onClick={() => this.changeFillStyle("solid")}
|
|
|
+ className={
|
|
|
+ getSelectedFillStyles() === "solid" ? "active" : ""
|
|
|
+ }
|
|
|
+ >
|
|
|
+ Solid
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ onClick={() => this.changeFillStyle("zigzag")}
|
|
|
+ className={
|
|
|
+ getSelectedFillStyles() === "zigzag" ? "active" : ""
|
|
|
+ }
|
|
|
+ >
|
|
|
+ Zigzag
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ onClick={() => this.changeFillStyle("cross-hatch")}
|
|
|
+ className={
|
|
|
+ getSelectedFillStyles() === "cross-hatch"
|
|
|
+ ? "active"
|
|
|
+ : ""
|
|
|
+ }
|
|
|
+ >
|
|
|
+ Cross-hatch
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ onClick={() => this.changeFillStyle("dots")}
|
|
|
+ className={
|
|
|
+ getSelectedFillStyles() === "dots" ? "active" : ""
|
|
|
+ }
|
|
|
+ >
|
|
|
+ Dots
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ onClick={() => this.changeFillStyle("sunburst")}
|
|
|
+ className={
|
|
|
+ getSelectedFillStyles() === "sunburst" ? "active" : ""
|
|
|
+ }
|
|
|
+ >
|
|
|
+ Sunburst
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ onClick={() => this.changeFillStyle("dashed")}
|
|
|
+ className={
|
|
|
+ getSelectedFillStyles() === "dashed" ? "active" : ""
|
|
|
+ }
|
|
|
+ >
|
|
|
+ Dashed
|
|
|
+ </button>
|
|
|
+ <button
|
|
|
+ onClick={() => this.changeFillStyle("zigzag-line")}
|
|
|
+ className={
|
|
|
+ getSelectedFillStyles() === "zigzag-line"
|
|
|
+ ? "active"
|
|
|
+ : ""
|
|
|
+ }
|
|
|
+ >
|
|
|
+ Zigzag-line
|
|
|
+ </button>
|
|
|
+ {/* </select> */}
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {someElementIsSelectedIsRectangleOrEllipseOrDiamondOrArrow() && (
|
|
|
+ <>
|
|
|
+ <h4>Stroke width</h4>
|
|
|
+ <div className="panelColumn">
|
|
|
+ <select
|
|
|
+ onChange={this.changeStrokeWidth}
|
|
|
+ value={getSelectedStrokeWidth()}
|
|
|
+ >
|
|
|
+ <option hidden disabled value=""></option>
|
|
|
+ <option value="1">1</option>
|
|
|
+ <option value="2">2</option>
|
|
|
+ <option value="4">4</option>
|
|
|
+ <option value="8">8</option>
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <h4>Roughness</h4>
|
|
|
+ <div className="panelColumn">
|
|
|
+ <select
|
|
|
+ onChange={this.changeRoughness}
|
|
|
+ value={getSelectedRoughness()}
|
|
|
+ >
|
|
|
+ <option hidden disabled value=""></option>
|
|
|
+ <option value="1">1</option>
|
|
|
+ <option value="2">2</option>
|
|
|
+ <option value="4">4</option>
|
|
|
+ <option value="8">8</option>
|
|
|
+ <option value="10">10</option>
|
|
|
+ </select>
|
|
|
+ </div>
|
|
|
+ </>
|
|
|
+ )}
|
|
|
+
|
|
|
+ <h4>Opacity</h4>
|
|
|
+ <input
|
|
|
+ type="range"
|
|
|
+ min="0"
|
|
|
+ max="100"
|
|
|
+ onChange={this.changeOpacity}
|
|
|
+ value={getSelectedOpacity()}
|
|
|
+ />
|
|
|
+ </>
|
|
|
+ )}
|
|
|
</div>
|
|
|
<canvas
|
|
|
id="canvas"
|
|
@@ -1556,7 +1866,11 @@ class App extends React.Component<{}, AppState> {
|
|
|
x,
|
|
|
y,
|
|
|
this.state.currentItemStrokeColor,
|
|
|
- this.state.currentItemBackgroundColor
|
|
|
+ this.state.currentItemBackgroundColor,
|
|
|
+ "hachure",
|
|
|
+ 1,
|
|
|
+ 1,
|
|
|
+ 100
|
|
|
);
|
|
|
let resizeHandle: string | false = false;
|
|
|
let isDraggingElements = false;
|