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
1 change: 1 addition & 0 deletions src/index.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

<body>
<div id="top-bar">
<button id="new-button" class="new-button" title="New">New</button>
<button id="save-button" class="save-button" title="Save">Save</button>
<button id="load-button" class="load-button" title="Load">Load</button>
<button id="pause-button" class="pause-button" title="Pause"></button>
Expand Down
88 changes: 40 additions & 48 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import {
AddPc,
AddRouter,
AddServer,
loadGraph,
saveGraph,
loadFromFile,
loadFromLocalStorage,
saveToFile,
saveToLocalStorage,
selectElement,
} from "./types/viewportManager";
import { DataGraph } from "./types/graphs/datagraph";
Expand All @@ -39,6 +41,12 @@ export class GlobalContext {
this.viewgraph = new ViewGraph(this.datagraph, this.viewport);
}

load(datagraph: DataGraph) {
this.datagraph = datagraph;
this.viewport.clear();
this.viewgraph = new ViewGraph(this.datagraph, this.viewport);
}

getViewport() {
return this.viewport;
}
Expand Down Expand Up @@ -90,6 +98,12 @@ export class Viewport extends pixi_viewport.Viewport {
});
}

clear() {
this.removeChildren();
this.addChild(new Background());
this.moveCenter(WORLD_WIDTH / 2, WORLD_HEIGHT / 2);
}

private initializeMovement() {
this.drag()
.pinch()
Expand Down Expand Up @@ -298,31 +312,13 @@ export class RightBar {
RightBar.getInstance();

// Add router button
leftBar.addButton(
RouterSvg,
() => {
AddRouter(ctx);
},
"Add Router",
);
leftBar.addButton(RouterSvg, () => AddRouter(ctx), "Add Router");

// Add server button
leftBar.addButton(
ServerSvg,
() => {
AddServer(ctx);
},
"Add Server",
);
leftBar.addButton(ServerSvg, () => AddServer(ctx), "Add Server");

// Add PC button
leftBar.addButton(
ComputerSvg,
() => {
AddPc(ctx);
},
"Add PC",
);
leftBar.addButton(ComputerSvg, () => AddPc(ctx), "Add PC");

ctx.initialize(viewport);

Expand All @@ -346,31 +342,13 @@ export class RightBar {

window.addEventListener("resize", resize);

const newButton = document.getElementById("new-button");
const loadButton = document.getElementById("load-button");
const saveButton = document.getElementById("save-button");

saveButton.onclick = () => {
saveGraph(ctx);
};

loadButton.onclick = () => {
const input = document.createElement("input");
input.type = "file";
input.accept = ".json";

input.onchange = (event) => {
const file = (event.target as HTMLInputElement).files[0];
const reader = new FileReader();
reader.readAsText(file);

reader.onload = (readerEvent) => {
const jsonData = readerEvent.target.result as string;
loadGraph(jsonData, ctx);
};
};

input.click();
};
newButton.onclick = () => ctx.load(new DataGraph());
saveButton.onclick = () => saveToFile(ctx);
loadButton.onclick = () => loadFromFile(ctx);

const pauseButton = document.getElementById("pause-button");
let paused = false;
Expand All @@ -397,9 +375,7 @@ export class RightBar {
}
};

pauseButton.onclick = () => {
triggerPause();
};
pauseButton.onclick = triggerPause;

document.body.onkeyup = function (e) {
if (e.key === " " || e.code === "Space") {
Expand All @@ -408,5 +384,21 @@ export class RightBar {
}
};

// TODO: load from local storage directly, without first generating a context
loadFromLocalStorage(ctx);

let saveIntervalId: NodeJS.Timeout | null = null;

ctx.getDataGraph().subscribeChanges(() => {
// Wait a bit after the last change to save
if (saveIntervalId) {
clearInterval(saveIntervalId);
}
saveIntervalId = setInterval(() => {
saveToLocalStorage(ctx);
clearInterval(saveIntervalId);
}, 100);
});

console.log("initialized!");
})();
1 change: 1 addition & 0 deletions src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ canvas {
}

/* Styles for save and load buttons */
.new-button,
.save-button,
.load-button {
background-color: #007bff; /* Blue background */
Expand Down
100 changes: 79 additions & 21 deletions src/types/graphs/datagraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,53 @@ export interface GraphNode {
connections: Set<number>;
}

export interface GraphDataNode {
id: number;
x: number;
y: number;
type: string;
connections: number[];
}

export type GraphData = GraphDataNode[];

export class DataGraph {
private devices = new Map<number, GraphNode>();
private idCounter = 1;
private onChanges: (() => void)[] = [];

static fromData(data: GraphData): DataGraph {
const dataGraph = new DataGraph();
data.forEach((nodeData: GraphDataNode) => {
// ADD DATAGRAPH AND EDGES
console.log(nodeData);
const connections = new Set(nodeData.connections);
const graphNode: GraphNode = {
x: nodeData.x,
y: nodeData.y,
type: nodeData.type,
connections: connections,
};
dataGraph.addDevice(nodeData.id, graphNode);
});
return dataGraph;
}

toData(): GraphData {
const graphData: GraphData = [];

// Serialize nodes
this.getDevices().forEach(([id, info]) => {
graphData.push({
id: id,
x: info.x,
y: info.y,
type: info.type, // Save the device type (Router, Server, PC)
connections: Array.from(info.connections.values()),
});
});
return graphData;
}

// Add a new device to the graph
addNewDevice(deviceInfo: { x: number; y: number; type: string }): number {
Expand All @@ -18,20 +62,22 @@ export class DataGraph {
};
this.devices.set(id, graphnode);
console.log(`Device added with ID ${id}`);
this.notifyChanges();
return id;
}

// Add a device to the graph
addDevice(idDevice: number, deviceInfo: GraphNode) {
if (!this.devices.has(idDevice)) {
this.devices.set(idDevice, deviceInfo);
if (this.idCounter <= idDevice) {
this.idCounter = idDevice + 1;
}
console.log(`Device added with ID ${idDevice}`);
} else {
if (this.devices.has(idDevice)) {
console.warn(`Device with ID ${idDevice} already exists in the graph.`);
return;
}
this.devices.set(idDevice, deviceInfo);
if (this.idCounter <= idDevice) {
this.idCounter = idDevice + 1;
}
console.log(`Device added with ID ${idDevice}`);
this.notifyChanges();
}

// Add a connection between two devices
Expand All @@ -40,23 +86,30 @@ export class DataGraph {
console.warn(
`Cannot create a connection between the same device (ID ${n1Id}).`,
);
} else if (!this.devices.has(n1Id)) {
return;
}
if (!this.devices.has(n1Id)) {
console.warn(`Device with ID ${n1Id} does not exist in devices.`);
} else if (!this.devices.has(n2Id)) {
return;
}
if (!this.devices.has(n2Id)) {
console.warn(`Device with ID ${n2Id} does not exist in devices.`);
return;
// Check if an edge already exists between these two devices
} else if (this.devices.get(n1Id).connections.has(n2Id)) {
}
if (this.devices.get(n1Id).connections.has(n2Id)) {
console.warn(
`Connection between ID ${n1Id} and ID ${n2Id} already exists.`,
);
} else {
this.devices.get(n1Id).connections.add(n2Id);
this.devices.get(n2Id).connections.add(n1Id);

console.log(
`Connection created between devices ID: ${n1Id} and ID: ${n2Id}`,
);
return;
}
this.devices.get(n1Id).connections.add(n2Id);
this.devices.get(n2Id).connections.add(n1Id);

console.log(
`Connection created between devices ID: ${n1Id} and ID: ${n2Id}`,
);
this.notifyChanges();
}

updateDevicePosition(id: number, newValues: { x?: number; y?: number }) {
Expand All @@ -66,6 +119,7 @@ export class DataGraph {
return;
}
this.devices.set(id, { ...deviceGraphNode, ...newValues });
this.notifyChanges();
}

getDevice(id: number): GraphNode | undefined {
Expand Down Expand Up @@ -111,6 +165,7 @@ export class DataGraph {
// Remove the node from the graph
this.devices.delete(id);
console.log(`Device with ID ${id} and its connections were removed.`);
this.notifyChanges();
}

// Method to remove a connection (edge) between two devices by their IDs
Expand Down Expand Up @@ -143,11 +198,14 @@ export class DataGraph {
console.log(
`Connection removed between devices ID: ${n1Id} and ID: ${n2Id}`,
);
this.notifyChanges();
}

subscribeChanges(callback: () => void) {
this.onChanges.push(callback);
}

// Clear the graph
clear() {
this.devices.clear();
this.idCounter = 1;
notifyChanges() {
this.onChanges.forEach((callback) => callback());
}
}
13 changes: 1 addition & 12 deletions src/types/graphs/viewgraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class ViewGraph {
this.constructView();
}

constructView() {
private constructView() {
// TODO: Adjust construction based on the selected layer in the future
console.log("Constructing ViewGraph from DataGraph");
const connections = new Set<{ deviceId: number; adyacentId: number }>();
Expand Down Expand Up @@ -180,17 +180,6 @@ export class ViewGraph {
return this.devices.size;
}

// Clear the graph
clear() {
this.devices.forEach((device) => {
device.delete();
});
// no edges should remain to delete
this.devices.clear();
this.edges.clear();
this.idCounter = 1;
}

// Method to remove a device and its connections (edges)
removeDevice(id: number) {
const device = this.devices.get(id);
Expand Down
Loading