Remove drawScene (#58)
This commit is contained in:
parent
4c94976527
commit
a5b0e192b4
511
src/index.tsx
511
src/index.tsx
@ -134,70 +134,70 @@ function exportAsPNG({
|
|||||||
// deselect & rerender
|
// deselect & rerender
|
||||||
|
|
||||||
clearSelection();
|
clearSelection();
|
||||||
drawScene();
|
ReactDOM.render(<App />, rootElement, () => {
|
||||||
|
// calculate visible-area coords
|
||||||
|
|
||||||
// calculate visible-area coords
|
let subCanvasX1 = Infinity;
|
||||||
|
let subCanvasX2 = 0;
|
||||||
|
let subCanvasY1 = Infinity;
|
||||||
|
let subCanvasY2 = 0;
|
||||||
|
|
||||||
let subCanvasX1 = Infinity;
|
elements.forEach(element => {
|
||||||
let subCanvasX2 = 0;
|
subCanvasX1 = Math.min(subCanvasX1, getElementAbsoluteX1(element));
|
||||||
let subCanvasY1 = Infinity;
|
subCanvasX2 = Math.max(subCanvasX2, getElementAbsoluteX2(element));
|
||||||
let subCanvasY2 = 0;
|
subCanvasY1 = Math.min(subCanvasY1, getElementAbsoluteY1(element));
|
||||||
|
subCanvasY2 = Math.max(subCanvasY2, getElementAbsoluteY2(element));
|
||||||
|
});
|
||||||
|
|
||||||
elements.forEach(element => {
|
// create temporary canvas from which we'll export
|
||||||
subCanvasX1 = Math.min(subCanvasX1, getElementAbsoluteX1(element));
|
|
||||||
subCanvasX2 = Math.max(subCanvasX2, getElementAbsoluteX2(element));
|
|
||||||
subCanvasY1 = Math.min(subCanvasY1, getElementAbsoluteY1(element));
|
|
||||||
subCanvasY2 = Math.max(subCanvasY2, getElementAbsoluteY2(element));
|
|
||||||
});
|
|
||||||
|
|
||||||
// create temporary canvas from which we'll export
|
const tempCanvas = document.createElement("canvas");
|
||||||
|
const tempCanvasCtx = tempCanvas.getContext("2d")!;
|
||||||
const tempCanvas = document.createElement("canvas");
|
tempCanvas.style.display = "none";
|
||||||
const tempCanvasCtx = tempCanvas.getContext("2d")!;
|
document.body.appendChild(tempCanvas);
|
||||||
tempCanvas.style.display = "none";
|
tempCanvas.width = exportVisibleOnly
|
||||||
document.body.appendChild(tempCanvas);
|
|
||||||
tempCanvas.width = exportVisibleOnly
|
|
||||||
? subCanvasX2 - subCanvasX1 + exportPadding * 2
|
|
||||||
: canvas.width;
|
|
||||||
tempCanvas.height = exportVisibleOnly
|
|
||||||
? subCanvasY2 - subCanvasY1 + exportPadding * 2
|
|
||||||
: canvas.height;
|
|
||||||
|
|
||||||
if (exportBackground) {
|
|
||||||
tempCanvasCtx.fillStyle = viewBgColor;
|
|
||||||
tempCanvasCtx.fillRect(0, 0, canvas.width, canvas.height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy our original canvas onto the temp canvas
|
|
||||||
tempCanvasCtx.drawImage(
|
|
||||||
canvas, // source
|
|
||||||
exportVisibleOnly // sx
|
|
||||||
? subCanvasX1 - exportPadding
|
|
||||||
: 0,
|
|
||||||
exportVisibleOnly // sy
|
|
||||||
? subCanvasY1 - exportPadding
|
|
||||||
: 0,
|
|
||||||
exportVisibleOnly // sWidth
|
|
||||||
? subCanvasX2 - subCanvasX1 + exportPadding * 2
|
? subCanvasX2 - subCanvasX1 + exportPadding * 2
|
||||||
: canvas.width,
|
: canvas.width;
|
||||||
exportVisibleOnly // sHeight
|
tempCanvas.height = exportVisibleOnly
|
||||||
? subCanvasY2 - subCanvasY1 + exportPadding * 2
|
? subCanvasY2 - subCanvasY1 + exportPadding * 2
|
||||||
: canvas.height,
|
: canvas.height;
|
||||||
0, // dx
|
|
||||||
0, // dy
|
|
||||||
exportVisibleOnly ? tempCanvas.width : canvas.width, // dWidth
|
|
||||||
exportVisibleOnly ? tempCanvas.height : canvas.height // dHeight
|
|
||||||
);
|
|
||||||
|
|
||||||
// create a temporary <a> elem which we'll use to download the image
|
if (exportBackground) {
|
||||||
const link = document.createElement("a");
|
tempCanvasCtx.fillStyle = viewBgColor;
|
||||||
link.setAttribute("download", "excalibur.png");
|
tempCanvasCtx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
link.setAttribute("href", tempCanvas.toDataURL("image/png"));
|
}
|
||||||
link.click();
|
|
||||||
|
|
||||||
// clean up the DOM
|
// copy our original canvas onto the temp canvas
|
||||||
link.remove();
|
tempCanvasCtx.drawImage(
|
||||||
if (tempCanvas !== canvas) tempCanvas.remove();
|
canvas, // source
|
||||||
|
exportVisibleOnly // sx
|
||||||
|
? subCanvasX1 - exportPadding
|
||||||
|
: 0,
|
||||||
|
exportVisibleOnly // sy
|
||||||
|
? subCanvasY1 - exportPadding
|
||||||
|
: 0,
|
||||||
|
exportVisibleOnly // sWidth
|
||||||
|
? subCanvasX2 - subCanvasX1 + exportPadding * 2
|
||||||
|
: canvas.width,
|
||||||
|
exportVisibleOnly // sHeight
|
||||||
|
? subCanvasY2 - subCanvasY1 + exportPadding * 2
|
||||||
|
: canvas.height,
|
||||||
|
0, // dx
|
||||||
|
0, // dy
|
||||||
|
exportVisibleOnly ? tempCanvas.width : canvas.width, // dWidth
|
||||||
|
exportVisibleOnly ? tempCanvas.height : canvas.height // dHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
// create a temporary <a> elem which we'll use to download the image
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.setAttribute("download", "excalibur.png");
|
||||||
|
link.setAttribute("href", tempCanvas.toDataURL("image/png"));
|
||||||
|
link.click();
|
||||||
|
|
||||||
|
// clean up the DOM
|
||||||
|
link.remove();
|
||||||
|
if (tempCanvas !== canvas) tempCanvas.remove();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function rotate(x1: number, y1: number, x2: number, y2: number, angle: number) {
|
function rotate(x1: number, y1: number, x2: number, y2: number, angle: number) {
|
||||||
@ -396,11 +396,11 @@ class App extends React.Component<{}, AppState> {
|
|||||||
|
|
||||||
if (event.key === "Escape") {
|
if (event.key === "Escape") {
|
||||||
clearSelection();
|
clearSelection();
|
||||||
drawScene();
|
this.forceUpdate();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
} else if (event.key === "Backspace") {
|
} else if (event.key === "Backspace") {
|
||||||
deleteSelectedElements();
|
deleteSelectedElements();
|
||||||
drawScene();
|
this.forceUpdate();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
} else if (
|
} else if (
|
||||||
event.key === "ArrowLeft" ||
|
event.key === "ArrowLeft" ||
|
||||||
@ -417,13 +417,13 @@ class App extends React.Component<{}, AppState> {
|
|||||||
else if (event.key === "ArrowDown") element.y += step;
|
else if (event.key === "ArrowDown") element.y += step;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
drawScene();
|
this.forceUpdate();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
} else if (event.key === "a" && event.metaKey) {
|
} else if (event.key === "a" && event.metaKey) {
|
||||||
elements.forEach(element => {
|
elements.forEach(element => {
|
||||||
element.isSelected = true;
|
element.isSelected = true;
|
||||||
});
|
});
|
||||||
drawScene();
|
this.forceUpdate();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -443,7 +443,7 @@ class App extends React.Component<{}, AppState> {
|
|||||||
onChange={() => {
|
onChange={() => {
|
||||||
this.setState({ elementType: type });
|
this.setState({ elementType: type });
|
||||||
clearSelection();
|
clearSelection();
|
||||||
drawScene();
|
this.forceUpdate();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
@ -453,7 +453,50 @@ class App extends React.Component<{}, AppState> {
|
|||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return (
|
return (
|
||||||
<>
|
<div
|
||||||
|
onCut={e => {
|
||||||
|
e.clipboardData.setData(
|
||||||
|
"text/plain",
|
||||||
|
JSON.stringify(elements.filter(element => element.isSelected))
|
||||||
|
);
|
||||||
|
deleteSelectedElements();
|
||||||
|
this.forceUpdate();
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
onCopy={e => {
|
||||||
|
e.clipboardData.setData(
|
||||||
|
"text/plain",
|
||||||
|
JSON.stringify(elements.filter(element => element.isSelected))
|
||||||
|
);
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
onPaste={e => {
|
||||||
|
const paste = e.clipboardData.getData("text");
|
||||||
|
let parsedElements;
|
||||||
|
try {
|
||||||
|
parsedElements = JSON.parse(paste);
|
||||||
|
} catch (e) {}
|
||||||
|
if (
|
||||||
|
Array.isArray(parsedElements) &&
|
||||||
|
parsedElements.length > 0 &&
|
||||||
|
parsedElements[0].type // need to implement a better check here...
|
||||||
|
) {
|
||||||
|
clearSelection();
|
||||||
|
parsedElements.forEach(parsedElement => {
|
||||||
|
parsedElement.x += 10;
|
||||||
|
parsedElement.y += 10;
|
||||||
|
generateDraw(
|
||||||
|
parsedElement,
|
||||||
|
this.state.itemStrokeColor,
|
||||||
|
this.state.itemBackgroundColor
|
||||||
|
);
|
||||||
|
elements.push(parsedElement);
|
||||||
|
});
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Shapes</legend>
|
<legend>Shapes</legend>
|
||||||
{this.renderOption({ type: "rectangle", children: "Rectangle" })}
|
{this.renderOption({ type: "rectangle", children: "Rectangle" })}
|
||||||
@ -462,218 +505,171 @@ class App extends React.Component<{}, AppState> {
|
|||||||
{this.renderOption({ type: "text", children: "Text" })}
|
{this.renderOption({ type: "text", children: "Text" })}
|
||||||
{this.renderOption({ type: "selection", children: "Selection" })}
|
{this.renderOption({ type: "selection", children: "Selection" })}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<div
|
|
||||||
onCut={e => {
|
<canvas
|
||||||
e.clipboardData.setData(
|
id="canvas"
|
||||||
"text/plain",
|
width={window.innerWidth}
|
||||||
JSON.stringify(elements.filter(element => element.isSelected))
|
height={window.innerHeight - 200}
|
||||||
);
|
onMouseDown={e => {
|
||||||
deleteSelectedElements();
|
const x = e.clientX - (e.target as HTMLElement).offsetLeft;
|
||||||
drawScene();
|
const y = e.clientY - (e.target as HTMLElement).offsetTop;
|
||||||
e.preventDefault();
|
const element = newElement(this.state.elementType, x, y);
|
||||||
}}
|
let isDraggingElements = false;
|
||||||
onCopy={e => {
|
const cursorStyle = document.documentElement.style.cursor;
|
||||||
e.clipboardData.setData(
|
if (this.state.elementType === "selection") {
|
||||||
"text/plain",
|
const hitElement = elements.find(element => {
|
||||||
JSON.stringify(elements.filter(element => element.isSelected))
|
return hitTest(element, x, y);
|
||||||
);
|
|
||||||
e.preventDefault();
|
|
||||||
}}
|
|
||||||
onPaste={e => {
|
|
||||||
const paste = e.clipboardData.getData("text");
|
|
||||||
let parsedElements;
|
|
||||||
try {
|
|
||||||
parsedElements = JSON.parse(paste);
|
|
||||||
} catch (e) {}
|
|
||||||
if (
|
|
||||||
Array.isArray(parsedElements) &&
|
|
||||||
parsedElements.length > 0 &&
|
|
||||||
parsedElements[0].type // need to implement a better check here...
|
|
||||||
) {
|
|
||||||
clearSelection();
|
|
||||||
parsedElements.forEach(parsedElement => {
|
|
||||||
parsedElement.x += 10;
|
|
||||||
parsedElement.y += 10;
|
|
||||||
generateDraw(
|
|
||||||
parsedElement,
|
|
||||||
this.state.itemStrokeColor,
|
|
||||||
this.state.itemBackgroundColor
|
|
||||||
);
|
|
||||||
elements.push(parsedElement);
|
|
||||||
});
|
});
|
||||||
drawScene();
|
|
||||||
}
|
|
||||||
e.preventDefault();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<canvas
|
|
||||||
id="canvas"
|
|
||||||
width={window.innerWidth}
|
|
||||||
height={window.innerHeight - 200}
|
|
||||||
onMouseDown={e => {
|
|
||||||
const x = e.clientX - (e.target as HTMLElement).offsetLeft;
|
|
||||||
const y = e.clientY - (e.target as HTMLElement).offsetTop;
|
|
||||||
const element = newElement(this.state.elementType, x, y);
|
|
||||||
let isDraggingElements = false;
|
|
||||||
const cursorStyle = document.documentElement.style.cursor;
|
|
||||||
if (this.state.elementType === "selection") {
|
|
||||||
const hitElement = elements.find(element => {
|
|
||||||
return hitTest(element, x, y);
|
|
||||||
});
|
|
||||||
|
|
||||||
// If we click on something
|
// If we click on something
|
||||||
if (hitElement) {
|
if (hitElement) {
|
||||||
if (hitElement.isSelected) {
|
if (hitElement.isSelected) {
|
||||||
// If that element is not already selected, do nothing,
|
// If that element is not already selected, do nothing,
|
||||||
// we're likely going to drag it
|
// we're likely going to drag it
|
||||||
} else {
|
|
||||||
// We unselect every other elements unless shift is pressed
|
|
||||||
if (!e.shiftKey) {
|
|
||||||
clearSelection();
|
|
||||||
}
|
|
||||||
// No matter what, we select it
|
|
||||||
hitElement.isSelected = true;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// If we don't click on anything, let's remove all the selected elements
|
// We unselect every other elements unless shift is pressed
|
||||||
clearSelection();
|
if (!e.shiftKey) {
|
||||||
}
|
clearSelection();
|
||||||
|
}
|
||||||
isDraggingElements = elements.some(
|
// No matter what, we select it
|
||||||
element => element.isSelected
|
hitElement.isSelected = true;
|
||||||
);
|
|
||||||
|
|
||||||
if (isDraggingElements) {
|
|
||||||
document.documentElement.style.cursor = "move";
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// If we don't click on anything, let's remove all the selected elements
|
||||||
|
clearSelection();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTextElement(element)) {
|
isDraggingElements = elements.some(element => element.isSelected);
|
||||||
const text = prompt("What text do you want?");
|
|
||||||
if (text === null) {
|
if (isDraggingElements) {
|
||||||
|
document.documentElement.style.cursor = "move";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTextElement(element)) {
|
||||||
|
const text = prompt("What text do you want?");
|
||||||
|
if (text === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
element.text = text;
|
||||||
|
element.font = "20px Virgil";
|
||||||
|
const font = context.font;
|
||||||
|
context.font = element.font;
|
||||||
|
const {
|
||||||
|
actualBoundingBoxAscent,
|
||||||
|
actualBoundingBoxDescent,
|
||||||
|
width
|
||||||
|
} = context.measureText(element.text);
|
||||||
|
element.actualBoundingBoxAscent = actualBoundingBoxAscent;
|
||||||
|
context.font = font;
|
||||||
|
const height = actualBoundingBoxAscent + actualBoundingBoxDescent;
|
||||||
|
// Center the text
|
||||||
|
element.x -= width / 2;
|
||||||
|
element.y -= actualBoundingBoxAscent;
|
||||||
|
element.width = width;
|
||||||
|
element.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateDraw(
|
||||||
|
element,
|
||||||
|
this.state.itemStrokeColor,
|
||||||
|
this.state.itemBackgroundColor
|
||||||
|
);
|
||||||
|
elements.push(element);
|
||||||
|
if (this.state.elementType === "text") {
|
||||||
|
this.setState({
|
||||||
|
draggingElement: null,
|
||||||
|
elementType: "selection"
|
||||||
|
});
|
||||||
|
element.isSelected = true;
|
||||||
|
} else {
|
||||||
|
this.setState({ draggingElement: element });
|
||||||
|
}
|
||||||
|
|
||||||
|
let lastX = x;
|
||||||
|
let lastY = y;
|
||||||
|
|
||||||
|
const onMouseMove = (e: MouseEvent) => {
|
||||||
|
const target = e.target;
|
||||||
|
if (!(target instanceof HTMLElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isDraggingElements) {
|
||||||
|
const selectedElements = elements.filter(el => el.isSelected);
|
||||||
|
if (selectedElements.length) {
|
||||||
|
const x = e.clientX - target.offsetLeft;
|
||||||
|
const y = e.clientY - target.offsetTop;
|
||||||
|
selectedElements.forEach(element => {
|
||||||
|
element.x += x - lastX;
|
||||||
|
element.y += y - lastY;
|
||||||
|
});
|
||||||
|
lastX = x;
|
||||||
|
lastY = y;
|
||||||
|
this.forceUpdate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
element.text = text;
|
|
||||||
element.font = "20px Virgil";
|
|
||||||
const font = context.font;
|
|
||||||
context.font = element.font;
|
|
||||||
const {
|
|
||||||
actualBoundingBoxAscent,
|
|
||||||
actualBoundingBoxDescent,
|
|
||||||
width
|
|
||||||
} = context.measureText(element.text);
|
|
||||||
element.actualBoundingBoxAscent = actualBoundingBoxAscent;
|
|
||||||
context.font = font;
|
|
||||||
const height =
|
|
||||||
actualBoundingBoxAscent + actualBoundingBoxDescent;
|
|
||||||
// Center the text
|
|
||||||
element.x -= width / 2;
|
|
||||||
element.y -= actualBoundingBoxAscent;
|
|
||||||
element.width = width;
|
|
||||||
element.height = height;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
let width = e.clientX - target.offsetLeft - draggingElement.x;
|
||||||
|
let height = e.clientY - target.offsetTop - draggingElement.y;
|
||||||
|
draggingElement.width = width;
|
||||||
|
// Make a perfect square or circle when shift is enabled
|
||||||
|
draggingElement.height = e.shiftKey ? width : height;
|
||||||
|
|
||||||
generateDraw(
|
generateDraw(
|
||||||
element,
|
draggingElement,
|
||||||
this.state.itemStrokeColor,
|
this.state.itemStrokeColor,
|
||||||
this.state.itemBackgroundColor
|
this.state.itemBackgroundColor
|
||||||
);
|
);
|
||||||
elements.push(element);
|
|
||||||
if (this.state.elementType === "text") {
|
if (this.state.elementType === "selection") {
|
||||||
this.setState({
|
setSelection(draggingElement);
|
||||||
draggingElement: null,
|
}
|
||||||
elementType: "selection"
|
this.forceUpdate();
|
||||||
});
|
};
|
||||||
element.isSelected = true;
|
|
||||||
} else {
|
const onMouseUp = (e: MouseEvent) => {
|
||||||
this.setState({ draggingElement: element });
|
const { draggingElement, elementType } = this.state;
|
||||||
|
|
||||||
|
window.removeEventListener("mousemove", onMouseMove);
|
||||||
|
window.removeEventListener("mouseup", onMouseUp);
|
||||||
|
|
||||||
|
document.documentElement.style.cursor = cursorStyle;
|
||||||
|
|
||||||
|
// if no element is clicked, clear the selection and redraw
|
||||||
|
if (draggingElement === null) {
|
||||||
|
clearSelection();
|
||||||
|
this.forceUpdate();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let lastX = x;
|
if (elementType === "selection") {
|
||||||
let lastY = y;
|
|
||||||
|
|
||||||
const onMouseMove = (e: MouseEvent) => {
|
|
||||||
const target = e.target;
|
|
||||||
if (!(target instanceof HTMLElement)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDraggingElements) {
|
if (isDraggingElements) {
|
||||||
const selectedElements = elements.filter(el => el.isSelected);
|
isDraggingElements = false;
|
||||||
if (selectedElements.length) {
|
|
||||||
const x = e.clientX - target.offsetLeft;
|
|
||||||
const y = e.clientY - target.offsetTop;
|
|
||||||
selectedElements.forEach(element => {
|
|
||||||
element.x += x - lastX;
|
|
||||||
element.y += y - lastY;
|
|
||||||
});
|
|
||||||
lastX = x;
|
|
||||||
lastY = y;
|
|
||||||
drawScene();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
elements.pop();
|
||||||
|
} else {
|
||||||
|
draggingElement.isSelected = true;
|
||||||
|
}
|
||||||
|
|
||||||
// It is very important to read this.state within each move event,
|
this.setState({
|
||||||
// otherwise we would read a stale one!
|
draggingElement: null,
|
||||||
const draggingElement = this.state.draggingElement;
|
elementType: "selection"
|
||||||
if (!draggingElement) return;
|
});
|
||||||
let width = e.clientX - target.offsetLeft - draggingElement.x;
|
this.forceUpdate();
|
||||||
let height = e.clientY - target.offsetTop - draggingElement.y;
|
};
|
||||||
draggingElement.width = width;
|
|
||||||
// Make a perfect square or circle when shift is enabled
|
|
||||||
draggingElement.height = e.shiftKey ? width : height;
|
|
||||||
|
|
||||||
generateDraw(
|
window.addEventListener("mousemove", onMouseMove);
|
||||||
draggingElement,
|
window.addEventListener("mouseup", onMouseUp);
|
||||||
this.state.itemStrokeColor,
|
|
||||||
this.state.itemBackgroundColor
|
|
||||||
);
|
|
||||||
|
|
||||||
if (this.state.elementType === "selection") {
|
this.forceUpdate();
|
||||||
setSelection(draggingElement);
|
}}
|
||||||
}
|
/>
|
||||||
drawScene();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onMouseUp = (e: MouseEvent) => {
|
|
||||||
const { draggingElement, elementType } = this.state;
|
|
||||||
|
|
||||||
window.removeEventListener("mousemove", onMouseMove);
|
|
||||||
window.removeEventListener("mouseup", onMouseUp);
|
|
||||||
|
|
||||||
document.documentElement.style.cursor = cursorStyle;
|
|
||||||
|
|
||||||
// if no element is clicked, clear the selection and redraw
|
|
||||||
if (draggingElement === null) {
|
|
||||||
clearSelection();
|
|
||||||
drawScene();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elementType === "selection") {
|
|
||||||
if (isDraggingElements) {
|
|
||||||
isDraggingElements = false;
|
|
||||||
}
|
|
||||||
elements.pop();
|
|
||||||
} else {
|
|
||||||
draggingElement.isSelected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
draggingElement: null,
|
|
||||||
elementType: "selection"
|
|
||||||
});
|
|
||||||
drawScene();
|
|
||||||
};
|
|
||||||
|
|
||||||
window.addEventListener("mousemove", onMouseMove);
|
|
||||||
window.addEventListener("mouseup", onMouseUp);
|
|
||||||
|
|
||||||
drawScene();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>Colors</legend>
|
<legend>Colors</legend>
|
||||||
<label>
|
<label>
|
||||||
@ -752,9 +748,10 @@ class App extends React.Component<{}, AppState> {
|
|||||||
/>
|
/>
|
||||||
px)
|
px)
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
const fillStyle = context.fillStyle;
|
const fillStyle = context.fillStyle;
|
||||||
context.fillStyle = this.state.viewBgColor;
|
context.fillStyle = this.state.viewBgColor;
|
||||||
@ -794,8 +791,4 @@ const context = canvas.getContext("2d")!;
|
|||||||
// https://stackoverflow.com/questions/13879322/drawing-a-1px-thick-line-in-canvas-creates-a-2px-thick-line/13879402#comment90766599_13879402
|
// https://stackoverflow.com/questions/13879322/drawing-a-1px-thick-line-in-canvas-creates-a-2px-thick-line/13879402#comment90766599_13879402
|
||||||
context.translate(0.5, 0.5);
|
context.translate(0.5, 0.5);
|
||||||
|
|
||||||
function drawScene() {
|
ReactDOM.render(<App />, rootElement);
|
||||||
ReactDOM.render(<App />, rootElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
drawScene();
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user