[Not for commit] Undo

This commit is contained in:
Christopher Chedeau 2020-01-02 15:39:15 -08:00
parent 3b919f3235
commit 8d587bcb21

View file

@ -13,6 +13,27 @@ type ExcaliburTextElement = ExcaliburElement & {
actualBoundingBoxAscent: number; actualBoundingBoxAscent: number;
}; };
const history: ExcaliburElement[] = [[]];
function pushHistoryCurrentEntry() {
const newEntry = elements.map(element => ({ ...element }));
if (
history.length > 0 &&
JSON.stringify(history[history.length - 1]) === JSON.stringify(newEntry)
) {
// If the last entry is the same as this one, ignore it
return;
}
history.push(newEntry);
}
function restoreHistoryEntry(entry: ExcaliburElement[]) {
const newElements = entry;
elements.splice(0, elements.length);
newElements.forEach((newElement: ExcaliburElement) => {
elements.push(newElement);
});
drawScene();
}
var elements = Array.of<ExcaliburElement>(); var elements = Array.of<ExcaliburElement>();
// https://stackoverflow.com/a/6853926/232122 // https://stackoverflow.com/a/6853926/232122
@ -240,18 +261,18 @@ function getArrowPoints(element: ExcaliburElement) {
function generateDraw(element: ExcaliburElement) { function generateDraw(element: ExcaliburElement) {
if (element.type === "selection") { if (element.type === "selection") {
element.draw = (rc, context) => { element.draw = function(rc, context) {
const fillStyle = context.fillStyle; const fillStyle = context.fillStyle;
context.fillStyle = "rgba(0, 0, 255, 0.10)"; context.fillStyle = "rgba(0, 0, 255, 0.10)";
context.fillRect(element.x, element.y, element.width, element.height); context.fillRect(this.x, this.y, this.width, this.height);
context.fillStyle = fillStyle; context.fillStyle = fillStyle;
}; };
} else if (element.type === "rectangle") { } else if (element.type === "rectangle") {
const shape = generator.rectangle(0, 0, element.width, element.height); const shape = generator.rectangle(0, 0, element.width, element.height);
element.draw = (rc, context) => { element.draw = function(rc, context) {
context.translate(element.x, element.y); context.translate(this.x, this.y);
rc.draw(shape); rc.draw(shape);
context.translate(-element.x, -element.y); context.translate(-this.x, -this.y);
}; };
} else if (element.type === "ellipse") { } else if (element.type === "ellipse") {
const shape = generator.ellipse( const shape = generator.ellipse(
@ -260,10 +281,10 @@ function generateDraw(element: ExcaliburElement) {
element.width, element.width,
element.height element.height
); );
element.draw = (rc, context) => { element.draw = function(rc, context) {
context.translate(element.x, element.y); context.translate(this.x, this.y);
rc.draw(shape); rc.draw(shape);
context.translate(-element.x, -element.y); context.translate(-this.x, -this.y);
}; };
} else if (element.type === "arrow") { } else if (element.type === "arrow") {
const [x1, y1, x2, y2, x3, y3, x4, y4] = getArrowPoints(element); const [x1, y1, x2, y2, x3, y3, x4, y4] = getArrowPoints(element);
@ -276,20 +297,20 @@ function generateDraw(element: ExcaliburElement) {
generator.line(x4, y4, x2, y2) generator.line(x4, y4, x2, y2)
]; ];
element.draw = (rc, context) => { element.draw = function(rc, context) {
context.translate(element.x, element.y); context.translate(this.x, this.y);
shapes.forEach(shape => rc.draw(shape)); shapes.forEach(shape => rc.draw(shape));
context.translate(-element.x, -element.y); context.translate(-this.x, -this.y);
}; };
return; return;
} else if (isTextElement(element)) { } else if (isTextElement(element)) {
element.draw = (rc, context) => { element.draw = function(rc, context) {
const font = context.font; const font = context.font;
context.font = element.font; context.font = this.font;
context.fillText( context.fillText(
element.text, this.text,
element.x, this.x,
element.y + element.actualBoundingBoxAscent this.y + this.actualBoundingBoxAscent
); );
context.font = font; context.font = font;
}; };
@ -403,12 +424,17 @@ class App extends React.Component<{}, AppState> {
}); });
drawScene(); drawScene();
event.preventDefault(); event.preventDefault();
} else if (event.key === "a" && event.metaKey) { } else if (event.metaKey && event.key === "a") {
elements.forEach(element => { elements.forEach(element => {
element.isSelected = true; element.isSelected = true;
}); });
drawScene(); drawScene();
event.preventDefault(); event.preventDefault();
} else if (event.metaKey && event.key === "z") {
const lastEntry = history.pop();
restoreHistoryEntry(lastEntry || []);
drawScene();
event.preventDefault();
} }
}; };
@ -659,6 +685,7 @@ class App extends React.Component<{}, AppState> {
// if no element is clicked, clear the selection and redraw // if no element is clicked, clear the selection and redraw
if (draggingElement === null) { if (draggingElement === null) {
clearSelection(); clearSelection();
pushHistoryCurrentEntry();
drawScene(); drawScene();
return; return;
} }
@ -676,6 +703,7 @@ class App extends React.Component<{}, AppState> {
draggingElement: null, draggingElement: null,
elementType: "selection" elementType: "selection"
}); });
pushHistoryCurrentEntry();
drawScene(); drawScene();
}; };