|
|
|
|
@ -221,7 +221,9 @@ export class App extends React.Component<any, AppState> {
@@ -221,7 +221,9 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
private onCut = (e: ClipboardEvent) => { |
|
|
|
|
if (isInputLike(e.target) && !isToolIcon(e.target)) return; |
|
|
|
|
if (isInputLike(e.target) && !isToolIcon(e.target)) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
e.clipboardData?.setData( |
|
|
|
|
"text/plain", |
|
|
|
|
JSON.stringify( |
|
|
|
|
@ -235,7 +237,9 @@ export class App extends React.Component<any, AppState> {
@@ -235,7 +237,9 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
e.preventDefault(); |
|
|
|
|
}; |
|
|
|
|
private onCopy = (e: ClipboardEvent) => { |
|
|
|
|
if (isInputLike(e.target) && !isToolIcon(e.target)) return; |
|
|
|
|
if (isInputLike(e.target) && !isToolIcon(e.target)) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
e.clipboardData?.setData( |
|
|
|
|
"text/plain", |
|
|
|
|
JSON.stringify( |
|
|
|
|
@ -247,7 +251,9 @@ export class App extends React.Component<any, AppState> {
@@ -247,7 +251,9 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
e.preventDefault(); |
|
|
|
|
}; |
|
|
|
|
private onPaste = (e: ClipboardEvent) => { |
|
|
|
|
if (isInputLike(e.target) && !isToolIcon(e.target)) return; |
|
|
|
|
if (isInputLike(e.target) && !isToolIcon(e.target)) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
const paste = e.clipboardData?.getData("text") || ""; |
|
|
|
|
this.addElementsFromPaste(paste); |
|
|
|
|
e.preventDefault(); |
|
|
|
|
@ -339,7 +345,9 @@ export class App extends React.Component<any, AppState> {
@@ -339,7 +345,9 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
private onKeyDown = (event: KeyboardEvent) => { |
|
|
|
|
if (isInputLike(event.target) && event.key !== KEYS.ESCAPE) return; |
|
|
|
|
if (isInputLike(event.target) && event.key !== KEYS.ESCAPE) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const actionResult = this.actionManager.handleKeyDown( |
|
|
|
|
event, |
|
|
|
|
@ -349,7 +357,9 @@ export class App extends React.Component<any, AppState> {
@@ -349,7 +357,9 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
|
|
|
|
|
if (actionResult) { |
|
|
|
|
this.syncActionResult(actionResult); |
|
|
|
|
if (actionResult) return; |
|
|
|
|
if (actionResult) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const shape = findShapeByKey(event.key); |
|
|
|
|
@ -361,10 +371,15 @@ export class App extends React.Component<any, AppState> {
@@ -361,10 +371,15 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
elements = elements.map(el => { |
|
|
|
|
if (el.isSelected) { |
|
|
|
|
const element = { ...el }; |
|
|
|
|
if (event.key === KEYS.ARROW_LEFT) element.x -= step; |
|
|
|
|
else if (event.key === KEYS.ARROW_RIGHT) element.x += step; |
|
|
|
|
else if (event.key === KEYS.ARROW_UP) element.y -= step; |
|
|
|
|
else if (event.key === KEYS.ARROW_DOWN) element.y += step; |
|
|
|
|
if (event.key === KEYS.ARROW_LEFT) { |
|
|
|
|
element.x -= step; |
|
|
|
|
} else if (event.key === KEYS.ARROW_RIGHT) { |
|
|
|
|
element.x += step; |
|
|
|
|
} else if (event.key === KEYS.ARROW_UP) { |
|
|
|
|
element.y -= step; |
|
|
|
|
} else if (event.key === KEYS.ARROW_DOWN) { |
|
|
|
|
element.y += step; |
|
|
|
|
} |
|
|
|
|
return element; |
|
|
|
|
} |
|
|
|
|
return el; |
|
|
|
|
@ -602,13 +617,14 @@ export class App extends React.Component<any, AppState> {
@@ -602,13 +617,14 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
actionManager={this.actionManager} |
|
|
|
|
syncActionResult={this.syncActionResult} |
|
|
|
|
onExportToPng={(exportedElements, scale) => { |
|
|
|
|
if (this.canvas) |
|
|
|
|
if (this.canvas) { |
|
|
|
|
exportCanvas("png", exportedElements, this.canvas, { |
|
|
|
|
exportBackground: this.state.exportBackground, |
|
|
|
|
name: this.state.name, |
|
|
|
|
viewBackgroundColor: this.state.viewBackgroundColor, |
|
|
|
|
scale, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
}} |
|
|
|
|
onExportToSvg={(exportedElements, scale) => { |
|
|
|
|
if (this.canvas) { |
|
|
|
|
@ -621,16 +637,17 @@ export class App extends React.Component<any, AppState> {
@@ -621,16 +637,17 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
} |
|
|
|
|
}} |
|
|
|
|
onExportToClipboard={(exportedElements, scale) => { |
|
|
|
|
if (this.canvas) |
|
|
|
|
if (this.canvas) { |
|
|
|
|
exportCanvas("clipboard", exportedElements, this.canvas, { |
|
|
|
|
exportBackground: this.state.exportBackground, |
|
|
|
|
name: this.state.name, |
|
|
|
|
viewBackgroundColor: this.state.viewBackgroundColor, |
|
|
|
|
scale, |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
}} |
|
|
|
|
onExportToBackend={exportedElements => { |
|
|
|
|
if (this.canvas) |
|
|
|
|
if (this.canvas) { |
|
|
|
|
exportCanvas( |
|
|
|
|
"backend", |
|
|
|
|
exportedElements.map(element => ({ |
|
|
|
|
@ -640,6 +657,7 @@ export class App extends React.Component<any, AppState> {
@@ -640,6 +657,7 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
this.canvas, |
|
|
|
|
this.state, |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
}} |
|
|
|
|
/> |
|
|
|
|
{this.actionManager.renderAction( |
|
|
|
|
@ -813,7 +831,9 @@ export class App extends React.Component<any, AppState> {
@@ -813,7 +831,9 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
lastMouseUp(e); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (isPanning) return; |
|
|
|
|
if (isPanning) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// pan canvas on wheel button drag or space+drag
|
|
|
|
|
if ( |
|
|
|
|
@ -826,8 +846,8 @@ export class App extends React.Component<any, AppState> {
@@ -826,8 +846,8 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
document.documentElement.style.cursor = CURSOR_TYPE.GRABBING; |
|
|
|
|
let { clientX: lastX, clientY: lastY } = e; |
|
|
|
|
const onMouseMove = (e: MouseEvent) => { |
|
|
|
|
let deltaX = lastX - e.clientX; |
|
|
|
|
let deltaY = lastY - e.clientY; |
|
|
|
|
const deltaX = lastX - e.clientX; |
|
|
|
|
const deltaY = lastY - e.clientY; |
|
|
|
|
lastX = e.clientX; |
|
|
|
|
lastY = e.clientY; |
|
|
|
|
// We don't want to save history when panning around
|
|
|
|
|
@ -857,7 +877,9 @@ export class App extends React.Component<any, AppState> {
@@ -857,7 +877,9 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// only handle left mouse button
|
|
|
|
|
if (e.button !== MOUSE_BUTTON.MAIN) return; |
|
|
|
|
if (e.button !== MOUSE_BUTTON.MAIN) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
// fixes mousemove causing selection of UI texts #32
|
|
|
|
|
e.preventDefault(); |
|
|
|
|
// Preventing the event above disables default behavior
|
|
|
|
|
@ -1080,7 +1102,7 @@ export class App extends React.Component<any, AppState> {
@@ -1080,7 +1102,7 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
const absPx = p1[0] + element.x; |
|
|
|
|
const absPy = p1[1] + element.y; |
|
|
|
|
|
|
|
|
|
let { width, height } = getPerfectElementSize( |
|
|
|
|
const { width, height } = getPerfectElementSize( |
|
|
|
|
"arrow", |
|
|
|
|
mouseX - element.x - p1[0], |
|
|
|
|
mouseY - element.y - p1[1], |
|
|
|
|
@ -1155,8 +1177,9 @@ export class App extends React.Component<any, AppState> {
@@ -1155,8 +1177,9 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
// triggering mousemove)
|
|
|
|
|
if (!draggingOccurred && this.state.elementType === "arrow") { |
|
|
|
|
const { x, y } = viewportCoordsToSceneCoords(e, this.state); |
|
|
|
|
if (distance2d(x, y, originX, originY) < DRAGGING_THRESHOLD) |
|
|
|
|
if (distance2d(x, y, originX, originY) < DRAGGING_THRESHOLD) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (isResizingElements && this.state.resizingElement) { |
|
|
|
|
@ -1432,7 +1455,9 @@ export class App extends React.Component<any, AppState> {
@@ -1432,7 +1455,9 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
// It is very important to read this.state within each move event,
|
|
|
|
|
// otherwise we would read a stale one!
|
|
|
|
|
const draggingElement = this.state.draggingElement; |
|
|
|
|
if (!draggingElement) return; |
|
|
|
|
if (!draggingElement) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const { x, y } = viewportCoordsToSceneCoords(e, this.state); |
|
|
|
|
|
|
|
|
|
@ -1443,8 +1468,12 @@ export class App extends React.Component<any, AppState> {
@@ -1443,8 +1468,12 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
this.state.elementType === "line" || |
|
|
|
|
this.state.elementType === "arrow"; |
|
|
|
|
|
|
|
|
|
if (isLinear && x < originX) width = -width; |
|
|
|
|
if (isLinear && y < originY) height = -height; |
|
|
|
|
if (isLinear && x < originX) { |
|
|
|
|
width = -width; |
|
|
|
|
} |
|
|
|
|
if (isLinear && y < originY) { |
|
|
|
|
height = -height; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (e.shiftKey) { |
|
|
|
|
({ width, height } = getPerfectElementSize( |
|
|
|
|
@ -1453,7 +1482,9 @@ export class App extends React.Component<any, AppState> {
@@ -1453,7 +1482,9 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
!isLinear && y < originY ? -height : height, |
|
|
|
|
)); |
|
|
|
|
|
|
|
|
|
if (!isLinear && height < 0) height = -height; |
|
|
|
|
if (!isLinear && height < 0) { |
|
|
|
|
height = -height; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!isLinear) { |
|
|
|
|
@ -1724,7 +1755,9 @@ export class App extends React.Component<any, AppState> {
@@ -1724,7 +1755,9 @@ export class App extends React.Component<any, AppState> {
|
|
|
|
|
}); |
|
|
|
|
}} |
|
|
|
|
onMouseMove={e => { |
|
|
|
|
if (isHoldingSpace || isPanning) return; |
|
|
|
|
if (isHoldingSpace || isPanning) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
const hasDeselectedButton = Boolean(e.buttons); |
|
|
|
|
if ( |
|
|
|
|
hasDeselectedButton || |
|
|
|
|
|