|
|
|
@ -279,11 +279,11 @@ function generateDraw(
|
|
|
|
|
const [x1, y1, x2, y2, x3, y3, x4, y4] = getArrowPoints(element);
|
|
|
|
|
const shapes = [
|
|
|
|
|
// \
|
|
|
|
|
generator.line(x3, y3, x2, y2),
|
|
|
|
|
generator.line(x3, y3, x2, y2, { stroke: itemStrokeColor }),
|
|
|
|
|
// -----
|
|
|
|
|
generator.line(x1, y1, x2, y2),
|
|
|
|
|
generator.line(x1, y1, x2, y2, { stroke: itemStrokeColor }),
|
|
|
|
|
// /
|
|
|
|
|
generator.line(x4, y4, x2, y2)
|
|
|
|
|
generator.line(x4, y4, x2, y2, { stroke: itemStrokeColor })
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
element.draw = (rc, context) => {
|
|
|
|
@ -384,9 +384,9 @@ class App extends React.Component<{}, AppState> {
|
|
|
|
|
exportBackground: false,
|
|
|
|
|
exportVisibleOnly: true,
|
|
|
|
|
exportPadding: 10,
|
|
|
|
|
itemStrokeColor: "#000",
|
|
|
|
|
itemBackgroundColor: "#FFF",
|
|
|
|
|
viewBgColor: "#FFF"
|
|
|
|
|
itemStrokeColor: "#000000",
|
|
|
|
|
itemBackgroundColor: "#ffffff",
|
|
|
|
|
viewBgColor: "#ffffff"
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private onKeyDown = (event: KeyboardEvent) => {
|
|
|
|
@ -454,82 +454,15 @@ class App extends React.Component<{}, AppState> {
|
|
|
|
|
public render() {
|
|
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<div className="exportWrapper">
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => {
|
|
|
|
|
exportAsPNG({
|
|
|
|
|
exportBackground: this.state.exportBackground,
|
|
|
|
|
exportVisibleOnly: this.state.exportVisibleOnly,
|
|
|
|
|
exportPadding: this.state.exportPadding,
|
|
|
|
|
viewBgColor: this.state.viewBgColor
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Export to png
|
|
|
|
|
</button>
|
|
|
|
|
<label>
|
|
|
|
|
<input
|
|
|
|
|
type="checkbox"
|
|
|
|
|
checked={this.state.exportBackground}
|
|
|
|
|
onChange={e => {
|
|
|
|
|
this.setState({ exportBackground: e.target.checked });
|
|
|
|
|
}}
|
|
|
|
|
/>{" "}
|
|
|
|
|
background
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<input
|
|
|
|
|
type="color"
|
|
|
|
|
value={this.state.viewBgColor}
|
|
|
|
|
onChange={e => {
|
|
|
|
|
this.setState({ viewBgColor: e.target.value });
|
|
|
|
|
}}
|
|
|
|
|
/>{" "}
|
|
|
|
|
view background color
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<input
|
|
|
|
|
type="color"
|
|
|
|
|
value={this.state.itemStrokeColor}
|
|
|
|
|
onChange={e => {
|
|
|
|
|
this.setState({ itemStrokeColor: e.target.value });
|
|
|
|
|
}}
|
|
|
|
|
/>{" "}
|
|
|
|
|
item stroke color
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<input
|
|
|
|
|
type="color"
|
|
|
|
|
value={this.state.itemBackgroundColor}
|
|
|
|
|
onChange={e => {
|
|
|
|
|
this.setState({ itemBackgroundColor: e.target.value });
|
|
|
|
|
}}
|
|
|
|
|
/>{" "}
|
|
|
|
|
item background color
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<input
|
|
|
|
|
type="checkbox"
|
|
|
|
|
checked={this.state.exportVisibleOnly}
|
|
|
|
|
onChange={e => {
|
|
|
|
|
this.setState({ exportVisibleOnly: e.target.checked });
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
visible area only
|
|
|
|
|
</label>
|
|
|
|
|
(padding:
|
|
|
|
|
<input
|
|
|
|
|
type="number"
|
|
|
|
|
value={this.state.exportPadding}
|
|
|
|
|
onChange={e => {
|
|
|
|
|
this.setState({ exportPadding: Number(e.target.value) });
|
|
|
|
|
}}
|
|
|
|
|
disabled={!this.state.exportVisibleOnly}
|
|
|
|
|
/>
|
|
|
|
|
px)
|
|
|
|
|
</div>
|
|
|
|
|
<fieldset>
|
|
|
|
|
<legend>Shapes</legend>
|
|
|
|
|
{this.renderOption({ type: "rectangle", children: "Rectangle" })}
|
|
|
|
|
{this.renderOption({ type: "ellipse", children: "Ellipse" })}
|
|
|
|
|
{this.renderOption({ type: "arrow", children: "Arrow" })}
|
|
|
|
|
{this.renderOption({ type: "text", children: "Text" })}
|
|
|
|
|
{this.renderOption({ type: "selection", children: "Selection" })}
|
|
|
|
|
</fieldset>
|
|
|
|
|
<div
|
|
|
|
|
style={{ backgroundColor: this.state.viewBgColor }}
|
|
|
|
|
onCut={e => {
|
|
|
|
|
e.clipboardData.setData(
|
|
|
|
|
"text/plain",
|
|
|
|
@ -573,15 +506,10 @@ class App extends React.Component<{}, AppState> {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{this.renderOption({ type: "rectangle", children: "Rectangle" })}
|
|
|
|
|
{this.renderOption({ type: "ellipse", children: "Ellipse" })}
|
|
|
|
|
{this.renderOption({ type: "arrow", children: "Arrow" })}
|
|
|
|
|
{this.renderOption({ type: "text", children: "Text" })}
|
|
|
|
|
{this.renderOption({ type: "selection", children: "Selection" })}
|
|
|
|
|
<canvas
|
|
|
|
|
id="canvas"
|
|
|
|
|
width={window.innerWidth}
|
|
|
|
|
height={window.innerHeight}
|
|
|
|
|
height={window.innerHeight - 200}
|
|
|
|
|
onMouseDown={e => {
|
|
|
|
|
const x = e.clientX - (e.target as HTMLElement).offsetLeft;
|
|
|
|
|
const y = e.clientY - (e.target as HTMLElement).offsetTop;
|
|
|
|
@ -746,9 +674,114 @@ class App extends React.Component<{}, AppState> {
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<fieldset>
|
|
|
|
|
<legend>Colors</legend>
|
|
|
|
|
<label>
|
|
|
|
|
<input
|
|
|
|
|
type="color"
|
|
|
|
|
value={this.state.viewBgColor}
|
|
|
|
|
onChange={e => {
|
|
|
|
|
this.setState({ viewBgColor: e.target.value });
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
Background
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<input
|
|
|
|
|
type="color"
|
|
|
|
|
value={this.state.itemStrokeColor}
|
|
|
|
|
onChange={e => {
|
|
|
|
|
this.setState({ itemStrokeColor: e.target.value });
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
Shape Stroke
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<input
|
|
|
|
|
type="color"
|
|
|
|
|
value={this.state.itemBackgroundColor}
|
|
|
|
|
onChange={e => {
|
|
|
|
|
this.setState({ itemBackgroundColor: e.target.value });
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
Shape Background
|
|
|
|
|
</label>
|
|
|
|
|
</fieldset>
|
|
|
|
|
<fieldset>
|
|
|
|
|
<legend>Export</legend>
|
|
|
|
|
<button
|
|
|
|
|
onClick={() => {
|
|
|
|
|
exportAsPNG({
|
|
|
|
|
exportBackground: this.state.exportBackground,
|
|
|
|
|
exportVisibleOnly: this.state.exportVisibleOnly,
|
|
|
|
|
exportPadding: this.state.exportPadding,
|
|
|
|
|
viewBgColor: this.state.viewBgColor
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
Export to png
|
|
|
|
|
</button>
|
|
|
|
|
<label>
|
|
|
|
|
<input
|
|
|
|
|
type="checkbox"
|
|
|
|
|
checked={this.state.exportBackground}
|
|
|
|
|
onChange={e => {
|
|
|
|
|
this.setState({ exportBackground: e.target.checked });
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
background
|
|
|
|
|
</label>
|
|
|
|
|
<label>
|
|
|
|
|
<input
|
|
|
|
|
type="checkbox"
|
|
|
|
|
checked={this.state.exportVisibleOnly}
|
|
|
|
|
onChange={e => {
|
|
|
|
|
this.setState({ exportVisibleOnly: e.target.checked });
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
visible area only
|
|
|
|
|
</label>
|
|
|
|
|
(padding:
|
|
|
|
|
<input
|
|
|
|
|
type="number"
|
|
|
|
|
value={this.state.exportPadding}
|
|
|
|
|
onChange={e => {
|
|
|
|
|
this.setState({ exportPadding: Number(e.target.value) });
|
|
|
|
|
}}
|
|
|
|
|
disabled={!this.state.exportVisibleOnly}
|
|
|
|
|
/>
|
|
|
|
|
px)
|
|
|
|
|
</fieldset>
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
componentDidUpdate() {
|
|
|
|
|
const fillStyle = context.fillStyle;
|
|
|
|
|
context.fillStyle = this.state.viewBgColor;
|
|
|
|
|
context.fillRect(-0.5, -0.5, canvas.width, canvas.height);
|
|
|
|
|
context.fillStyle = fillStyle;
|
|
|
|
|
|
|
|
|
|
elements.forEach(element => {
|
|
|
|
|
element.draw(rc, context);
|
|
|
|
|
if (element.isSelected) {
|
|
|
|
|
const margin = 4;
|
|
|
|
|
|
|
|
|
|
const elementX1 = getElementAbsoluteX1(element);
|
|
|
|
|
const elementX2 = getElementAbsoluteX2(element);
|
|
|
|
|
const elementY1 = getElementAbsoluteY1(element);
|
|
|
|
|
const elementY2 = getElementAbsoluteY2(element);
|
|
|
|
|
const lineDash = context.getLineDash();
|
|
|
|
|
context.setLineDash([8, 4]);
|
|
|
|
|
context.strokeRect(
|
|
|
|
|
elementX1 - margin,
|
|
|
|
|
elementY1 - margin,
|
|
|
|
|
elementX2 - elementX1 + margin * 2,
|
|
|
|
|
elementY2 - elementY1 + margin * 2
|
|
|
|
|
);
|
|
|
|
|
context.setLineDash(lineDash);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const rootElement = document.getElementById("root");
|
|
|
|
@ -763,29 +796,6 @@ context.translate(0.5, 0.5);
|
|
|
|
|
|
|
|
|
|
function drawScene() {
|
|
|
|
|
ReactDOM.render(<App />, rootElement);
|
|
|
|
|
|
|
|
|
|
context.clearRect(-0.5, -0.5, canvas.width, canvas.height);
|
|
|
|
|
|
|
|
|
|
elements.forEach(element => {
|
|
|
|
|
element.draw(rc, context);
|
|
|
|
|
if (element.isSelected) {
|
|
|
|
|
const margin = 4;
|
|
|
|
|
|
|
|
|
|
const elementX1 = getElementAbsoluteX1(element);
|
|
|
|
|
const elementX2 = getElementAbsoluteX2(element);
|
|
|
|
|
const elementY1 = getElementAbsoluteY1(element);
|
|
|
|
|
const elementY2 = getElementAbsoluteY2(element);
|
|
|
|
|
const lineDash = context.getLineDash();
|
|
|
|
|
context.setLineDash([8, 4]);
|
|
|
|
|
context.strokeRect(
|
|
|
|
|
elementX1 - margin,
|
|
|
|
|
elementY1 - margin,
|
|
|
|
|
elementX2 - elementX1 + margin * 2,
|
|
|
|
|
elementY2 - elementY1 + margin * 2
|
|
|
|
|
);
|
|
|
|
|
context.setLineDash(lineDash);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
drawScene();
|
|
|
|
|