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
66 changes: 66 additions & 0 deletions src/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Viewport } from "./graphics/viewport";
import { DataGraph } from "./types/graphs/datagraph";
import { ViewGraph } from "./types/graphs/viewgraph";
import {
loadFromLocalStorage,
saveToLocalStorage,
} from "./types/viewportManager";
import { Layer } from "./types/devices/device";

export class GlobalContext {
private viewport: Viewport = null;
private datagraph: DataGraph;
private viewgraph: ViewGraph;
private saveIntervalId: NodeJS.Timeout | null = null;

initialize(viewport: Viewport) {
this.viewport = viewport;
loadFromLocalStorage(this);
}

private setNetWork(datagraph: DataGraph, layer: Layer) {
this.datagraph = datagraph;
this.viewport.clear();
this.viewgraph = new ViewGraph(this.datagraph, this.viewport, layer);
}

load(datagraph: DataGraph, layer: Layer = Layer.Link) {
this.setNetWork(datagraph, layer);
this.setupAutoSave();
saveToLocalStorage(this);
}

getViewport() {
return this.viewport;
}

getViewGraph() {
return this.viewgraph;
}

getDataGraph() {
return this.datagraph;
}

private setupAutoSave() {
this.clearAutoSave();

this.datagraph.subscribeChanges(() => {
if (this.saveIntervalId) {
clearInterval(this.saveIntervalId);
}
this.saveIntervalId = setInterval(() => {
saveToLocalStorage(this);
clearInterval(this.saveIntervalId);
}, 100);
});
}

private clearAutoSave() {
// Limpia el intervalo y evita duplicados
if (this.saveIntervalId) {
clearInterval(this.saveIntervalId);
this.saveIntervalId = null;
}
}
}
25 changes: 25 additions & 0 deletions src/graphics/left_bar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export class LeftBar {
private leftBar: HTMLElement;

constructor(leftBar: HTMLElement) {
this.leftBar = leftBar;
}

static getFrom(document: Document) {
return new LeftBar(document.getElementById("left-bar"));
}

addButton(src: string, onClick: () => void, label: string) {
const button = document.createElement("button");
button.classList.add("icon-button");
button.setAttribute("title", label); // Shows Text

button.onclick = onClick;
this.leftBar.appendChild(button);

const img = document.createElement("img");
img.src = src;
img.classList.add("icon-img");
button.appendChild(img);
}
}
117 changes: 117 additions & 0 deletions src/graphics/right_bar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
export class RightBar {
private static instance: RightBar | null = null; // Unique instance
private rightBar: HTMLElement;

private constructor(rightBar: HTMLElement) {
this.rightBar = rightBar;
this.initializeBaseContent();
}

// Static method to get the unique instance of RightBar
static getInstance() {
// If an instance already exists, return it. If not, create it.
if (!RightBar.instance) {
const rightBarElement = document.getElementById("right-bar");
if (!rightBarElement) {
console.error("Element with ID 'right-bar' not found.");
return null;
}
RightBar.instance = new RightBar(rightBarElement);
}
return RightBar.instance;
}

// Initializes the base title and info container (called only once)
private initializeBaseContent() {
const title = document.createElement("h2");
title.textContent = "Information";
this.rightBar.appendChild(title);

const infoContent = document.createElement("div");
infoContent.id = "info-content";
this.rightBar.appendChild(infoContent);
}

// Method to clear only the content of info-content
clearContent() {
const infoContent = this.rightBar.querySelector("#info-content");
if (infoContent) {
infoContent.innerHTML = ""; // Clears only the content of info-content
}
}

// Shows specific information of an element in info-content
renderInfo(title: string, info: { label: string; value: string }[]) {
this.clearContent(); // Clears before adding new content

const infoContent = document.getElementById("info-content");
if (infoContent) {
const header = document.createElement("h3");
header.textContent = title;
infoContent.appendChild(header);

info.forEach((item) => {
const p = document.createElement("p");
p.innerHTML = `<strong>${item.label}:</strong> ${item.value}`;
infoContent.appendChild(p);
});
}
}

// Adds a standard button to the right-bar
addButton(
text: string,
onClick: () => void,
buttonClass = "right-bar-button",
toggleSelected = false,
) {
const infoContent = document.getElementById("info-content");
if (infoContent) {
const button = document.createElement("button");
button.classList.add(...buttonClass.split(" "));
button.textContent = text;
button.onclick = () => {
onClick();
if (toggleSelected) {
button.classList.toggle("selected-button"); // Changes color on click
}
};
infoContent.appendChild(button);
}
}

// Adds a select dropdown to the right-bar
addDropdown(
label: string,
options: { value: string; text: string }[],
selectId?: string,
) {
const infoContent = document.getElementById("info-content");
const container = document.createElement("div");
container.classList.add("dropdown-container");

const labelElement = document.createElement("label");
labelElement.textContent = label;
labelElement.classList.add("right-bar-label");

const select = document.createElement("select");
select.classList.add("right-bar-select");
if (selectId) select.id = selectId;

options.forEach((optionData) => {
const option = document.createElement("option");
option.value = optionData.value;
option.textContent = optionData.text;
select.appendChild(option);
});

// Default onchange behavior: logs the selected value
select.onchange = () => {
console.log(`Selected ${label}:`, select.value);
};

container.appendChild(labelElement);
container.appendChild(select);
infoContent.appendChild(container);
}
}
75 changes: 75 additions & 0 deletions src/graphics/viewport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Graphics, EventSystem } from "pixi.js";
import * as pixi_viewport from "pixi-viewport";
import { selectElement } from "../types/viewportManager";

const WORLD_WIDTH = 10000;
const WORLD_HEIGHT = 10000;

class Background extends Graphics {
constructor() {
super();
this.rect(0, 0, WORLD_WIDTH, WORLD_HEIGHT).fill(0xe3e2e1);
this.zIndex = 0;
}

resize(width: number, height: number) {
this.width = width;
this.height = height;
}
}

export class Viewport extends pixi_viewport.Viewport {
static usedPlugins = ["drag", "pinch"];

constructor(events: EventSystem) {
super({
worldWidth: WORLD_WIDTH,
worldHeight: WORLD_HEIGHT,
events: events,
});
this.moveCenter(WORLD_WIDTH / 2, WORLD_HEIGHT / 2);
this.sortableChildren = true;
this.initializeMovement();

this.addChild(new Background());

this.on("click", (event) => {
// If the click target is the viewport itself, deselect any selected element
if (event.target === this) {
selectElement(null);
}
});
}

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

private initializeMovement() {
this.drag()
.pinch()
.wheel()
.clamp({ direction: "all" })
// TODO: revisit when all icons are finalized
.clampZoom({
minHeight: 200,
minWidth: 200,
maxWidth: WORLD_WIDTH / 2,
maxHeight: WORLD_HEIGHT / 2,
});
}

enableMovement() {
for (const plugin of Viewport.usedPlugins) {
this.plugins.resume(plugin);
}
}

disableMovement() {
for (const plugin of Viewport.usedPlugins) {
this.plugins.pause(plugin);
}
}
}
Loading