Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/assets/left-curve-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/right-curve-arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ViewGraph } from "./types/graphs/viewgraph";
import {
loadFromLocalStorage,
saveToLocalStorage,
urManager,
} from "./types/viewportManager";
import { Layer } from "./types/devices/device";
import { IpAddress, IpAddressGenerator } from "./packets/ip";
Expand Down Expand Up @@ -40,6 +41,7 @@ export class GlobalContext {
this.setNetwork(datagraph, layer);
this.setupAutoSave();
saveToLocalStorage(this);
urManager.reset();
}

getViewport() {
Expand Down
20 changes: 19 additions & 1 deletion src/graphics/renderables/device_info.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { Device } from "../../types/devices";
import { DeviceType } from "../../types/devices/device";
import { CreateDevice } from "../../types/devices/utils";
import { RoutingTableEntry } from "../../types/graphs/datagraph";
import { ViewGraph } from "../../types/graphs/viewgraph";
import { sendPacket } from "../../types/packet";
import { RemoveDeviceMove } from "../../types/undo-redo";
import { urManager } from "../../types/viewportManager";
import {
createDropdown,
createToggleTable,
Expand Down Expand Up @@ -38,7 +41,22 @@ export class DeviceInfo extends StyledInfo {
),
createRightBarButton(
"Delete device",
() => this.device.delete(),
() => {
const deviceData: CreateDevice = {
id: this.device.id,
type: this.device.getType(),
x: this.device.x,
y: this.device.y,
ip: this.device.ip.toString(),
mask: this.device.ipMask.toString(),
};
const move = new RemoveDeviceMove(
deviceData,
this.device.getConnections(),
);
this.device.delete();
urManager.push(move);
},
"right-bar-delete-button",
),
);
Expand Down
2 changes: 2 additions & 0 deletions src/index.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
<div class="canvas-container">
<canvas id="canvas"></canvas>
<button id="pause-button" class="pause-button" title="Pause"></button>
<i id="undo-button" class="undo-button" title="Undo"></i>
<i id="redo-button" class="redo-button" title="Redo"></i>
<select id="layer-select" class="dropdown-menu">
<option value="application">App Layer</option>
<option value="transport">Transport Layer</option>
Expand Down
66 changes: 66 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
loadFromFile,
loadFromLocalStorage,
saveToFile,
urManager,
} from "./types/viewportManager";
import { DataGraph } from "./types/graphs/datagraph";
import { Packet } from "./types/packet";
Expand All @@ -21,6 +22,8 @@ import RouterSvg from "./assets/router.svg";
import ComputerSvg from "./assets/pc.svg";
import PlaySvg from "./assets/play-icon.svg";
import PauseSvg from "./assets/pause-icon.svg";
import UndoSvg from "./assets/left-curve-arrow.svg";
import RedoSvg from "./assets/right-curve-arrow.svg";

// IIFE to avoid errors
(async () => {
Expand Down Expand Up @@ -118,6 +121,69 @@ import PauseSvg from "./assets/pause-icon.svg";
saveButton.onclick = () => saveToFile(ctx);
loadButton.onclick = () => loadFromFile(ctx);

// Undo button’s logic
const undoButton = document.getElementById(
"undo-button",
) as HTMLButtonElement;

const undoIcon = document.createElement("img");
undoIcon.src = UndoSvg;
undoIcon.alt = "Undo Icon";
undoButton.appendChild(undoIcon);

console.log(undoIcon.style.filter);
urManager.suscribe(() => {
undoButton.disabled = !urManager.canUndo();
undoIcon.style.opacity = urManager.canUndo() ? "1" : "0.5"; // Full opacity for active, reduced for inactive
});

const triggerUndo = () => {
if (urManager.canUndo()) {
urManager.undo(ctx.getViewGraph());
}
};

undoButton.onclick = triggerUndo;

// Redo button’s logic
const redoButton = document.getElementById(
"redo-button",
) as HTMLButtonElement;
const redoIcon = document.createElement("img");
redoIcon.src = RedoSvg;
redoIcon.alt = "Redo Icon";
redoButton.appendChild(redoIcon);

urManager.suscribe(() => {
redoButton.disabled = !urManager.canRedo();
redoIcon.style.opacity = urManager.canRedo() ? "1" : "0.5"; // Full opacity for active, reduced for inactive
});

const triggerRedo = () => {
if (urManager.canRedo()) {
urManager.redo(ctx.getViewGraph());
}
};

redoButton.onclick = triggerRedo;

// Add keyboard shortcuts for Undo (Ctrl+Z) and Redo (Ctrl+Y)
document.addEventListener("keydown", (event) => {
if (event.ctrlKey) {
switch (event.key) {
case "z": // Ctrl+Z for Undo
event.preventDefault(); // Prevent default browser action (like undo in text inputs)
triggerUndo();
break;
case "y": // Ctrl+Y for Redo
event.preventDefault(); // Prevent default browser action
triggerRedo();
break;
}
}
});

// Pause button’s logic
const pauseButton = document.getElementById("pause-button");
let paused = false;

Expand Down
28 changes: 28 additions & 0 deletions src/styles/canvas.css
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@
justify-content: center; /* Horizontally centers content */
transition: background-color 0.3s ease; /* Smooth color transition */
position: absolute; /* Permite colocarlo sobre el canvas */
}

.pause-button {
top: 10px; /* Separación desde el borde superior */
left: 15px; /* Separación desde el borde derecho */
}
Expand All @@ -85,7 +88,32 @@
background-color: #006400; /* Darker forest green on hover */
}

.undo-button,
.redo-button {
cursor: pointer; /* Changes cursor to pointer on hover */
width: 45px; /* Fixed width for the circular button */
height: 45px; /* Fixed height for the circular button */
border-radius: 50%; /* Makes the button circular */
display: flex; /* Uses flexbox for centering */
align-items: center; /* Vertically centers content */
justify-content: center; /* Horizontally centers content */
transition: background-color 0.3s ease; /* Smooth color transition */
position: absolute; /* Permite colocarlo sobre el canvas */
}

.undo-button {
top: 10px;
left: 70px;
}

.redo-button {
top: 10px;
left: 110px;
}

/* Icon inside the pause button */
.undo-button img,
.redo-button img,
.pause-button img {
width: 60%; /* Scales the icon to fit the button */
height: 60%; /* Scales the icon to fit the button */
Expand Down
50 changes: 47 additions & 3 deletions src/types/devices/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import {
deselectElement,
refreshElement,
selectElement,
urManager,
} from "./../viewportManager";
import { RightBar } from "../../graphics/right_bar";
import { Colors, ZIndexLevels } from "../../utils";
import { Position } from "../common";
import { DeviceInfo } from "../../graphics/renderables/device_info";
import { IpAddress } from "../../packets/ip";
import { DeviceId } from "../graphs/datagraph";
import { DragDeviceMove, EdgeData, AddEdgeMove } from "../undo-redo";

export const DEVICE_SIZE = 20;

Expand All @@ -42,6 +44,7 @@ export abstract class Device extends Sprite {

static dragTarget: Device | null = null;
static connectionTarget: Device | null = null;
static startPosition: Position | null = null;

ip: IpAddress;
ipMask: IpAddress;
Expand Down Expand Up @@ -117,6 +120,8 @@ export abstract class Device extends Sprite {
// Clear connections
this.connections.clear();
deselectElement();
console.log(`Device ${this.id} deleted`);
this.destroy();
}

onPointerDown(event: FederatedPointerEvent): void {
Expand All @@ -125,6 +130,9 @@ export abstract class Device extends Sprite {
selectElement(this);
}
Device.dragTarget = this;

// Guardar posición inicial
Device.startPosition = { x: this.x, y: this.y };
event.stopPropagation();

// Listen to global pointermove and pointerup events
Expand All @@ -141,6 +149,15 @@ export abstract class Device extends Sprite {
const adyacentDevice = this.viewgraph.getDevice(adyacentId);
this.addConnection(edgeId, adyacentId);
adyacentDevice.addConnection(edgeId, this.id);

// Register move
const moveData: EdgeData = {
edgeId,
connectedNodes: { n1: this.id, n2: adyacentId },
};
const move = new AddEdgeMove(moveData);
urManager.push(move);

return true;
}
return false;
Expand Down Expand Up @@ -225,7 +242,6 @@ export abstract class Device extends Sprite {
}

function onPointerMove(event: FederatedPointerEvent): void {
console.log("Entered onPointerMove");
if (Device.dragTarget) {
Device.dragTarget.parent.toLocal(
event.global,
Expand All @@ -239,8 +255,36 @@ function onPointerMove(event: FederatedPointerEvent): void {
}

function onPointerUp(): void {
console.log("Entered onPointerUp");
if (Device.dragTarget) {
if (Device.dragTarget && Device.startPosition) {
const endPosition: Position = {
x: Device.dragTarget.x,
y: Device.dragTarget.y,
};
console.log("Finalizing move for device:", {
id: Device.dragTarget.id,
startPosition: Device.startPosition,
endPosition,
});

if (
Device.startPosition.x === endPosition.x &&
Device.startPosition.y === endPosition.y
) {
console.log(
`No movement detected for device ID ${Device.dragTarget.id}. Move not registered.`,
);
} else {
const move = new DragDeviceMove(
Device.dragTarget.id,
Device.startPosition,
endPosition,
);
urManager.push(move);
}

// Resetear variables estáticas
Device.startPosition = null;

// Remove global pointermove and pointerup events
Device.dragTarget.parent.off("pointermove", onPointerMove);
Device.dragTarget.parent.off("pointerup", onPointerUp);
Expand Down
3 changes: 1 addition & 2 deletions src/types/devices/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ export function createDevice(
deviceInfo: CreateDevice,
viewgraph: ViewGraph,
): Device {
const { x, y } = deviceInfo;
const position = { x, y };
const position: { x: number; y: number } = deviceInfo;
const ip = IpAddress.parse(deviceInfo.ip);
const mask = IpAddress.parse(deviceInfo.mask);

Expand Down
35 changes: 14 additions & 21 deletions src/types/edge.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Graphics, Point } from "pixi.js";
import { EdgeId, ViewGraph } from "./graphs/viewgraph";
import { Device } from "./devices/index"; // Import the Device class
import { deselectElement, selectElement } from "./viewportManager";
import { deselectElement, selectElement, urManager } from "./viewportManager";
import { RightBar, StyledInfo } from "../graphics/right_bar";
import { Colors, ZIndexLevels } from "../utils";
import { Packet } from "./packet";
import { RemoveEdgeMove } from "./undo-redo";
import { DeviceId } from "./graphs/datagraph";

export interface EdgeEdges {
Expand Down Expand Up @@ -117,7 +118,16 @@ export class Edge extends Graphics {
// Adds the delete button using addButton
this.rightbar.addButton(
"Delete Edge",
() => this.delete(),
() => {
// obtener info
const move = new RemoveEdgeMove({
edgeId: this.id,
connectedNodes: this.connectedNodes,
});
this.delete();
urManager.push(move);
// registrar movimiento
},
"right-bar-delete-button",
);
}
Expand All @@ -127,8 +137,9 @@ export class Edge extends Graphics {
// Remove the edge from the viewgraph and datagraph
deselectElement();
this.viewgraph.removeEdge(this.id);
this.destroy();

console.log(`Edge with ID ${this.id} deleted.`);
console.log(`Edge ${this.id} deleted.`);
}

public updatePosition(device1: Device, device2: Device) {
Expand All @@ -152,22 +163,4 @@ export class Edge extends Graphics {

this.drawEdge(newStartPos, newEndPos, Colors.Lightblue);
}

public remove() {
const { n1, n2 } = this.connectedNodes;
const device1 = this.viewgraph.getDevice(n1);
const device2 = this.viewgraph.getDevice(n2);

// Remove the connection from each connected device
if (device1) device1.connections.delete(this.id);
if (device2) device2.connections.delete(this.id);

// Remove the edge from the viewport
this.viewgraph.getViewport().removeChild(this);
this.destroy();

console.log(
`Edge with ID ${this.id} removed between devices ${n1} and ${n2}.`,
);
}
}
2 changes: 2 additions & 0 deletions src/types/graphs/datagraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@ export class DataGraph {
const connectedDevice = this.devices.get(connectedId);
if (connectedDevice) {
connectedDevice.connections.delete(id);
} else {
console.warn(`Connected device ${connectedId} does not exist`);
}
});

Expand Down
Loading
Loading