diff --git a/css/event.css b/css/event.css
new file mode 100644
index 00000000..19f506bc
--- /dev/null
+++ b/css/event.css
@@ -0,0 +1,56 @@
+#event-switcher {
+ position: fixed;
+ display: none;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ z-index: 1;
+ top: 10px;
+ left: 50%;
+ transform: translateX(-50%);
+ background-color: #e1e1e1;
+ padding: 5px 10px;
+ border-radius: 5px;
+}
+
+.event-switch-arrow {
+ cursor: pointer;
+}
+
+.event-switch-tool {
+ margin: 0 5px;
+}
+
+#selected-event {
+ font-weight: 500;
+ cursor: pointer;
+}
+
+#selected-event:hover {
+ text-decoration: underline;
+ background-color: #d1d1d1;
+}
+
+#event-selector-menu {
+ display: none;
+ position: fixed;
+ top: 32px;
+ flex-direction: column;
+ align-items: center;
+ background-color: #e1e1e1;
+ width: 100px;
+ left: 50%;
+ transform: translateX(-50%);
+ max-height: 175px;
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding: 0 5px;
+}
+
+.event-option {
+ cursor: pointer;
+ border: 1px solid #000;
+ width: 100%;
+ text-align: center;
+ margin: 1px 0;
+}
diff --git a/css/filter.css b/css/filter.css
index b12f8d46..721ef365 100644
--- a/css/filter.css
+++ b/css/filter.css
@@ -2,7 +2,7 @@
min-width: 100px;
position: fixed;
flex-direction: column;
- background-color: #f5f5f5;
+ background-color: #e1e1e1;
border-radius: 5px;
padding: 10px;
top: 10px;
diff --git a/css/main.css b/css/main.css
index 6b7406b1..56011873 100644
--- a/css/main.css
+++ b/css/main.css
@@ -3,6 +3,7 @@ body {
padding: 0;
/* overflow: hidden; */
font-family: sans-serif;
+ font-size: 16px;
}
.manipulation-tool {
diff --git a/css/toggle.css b/css/toggle.css
index 9a173f24..d877a96c 100644
--- a/css/toggle.css
+++ b/css/toggle.css
@@ -33,7 +33,7 @@
left: 0;
right: 0;
bottom: 0;
- background-color: #ccc;
+ background-color: #e1e1e1;
-webkit-transition: 0.4s;
transition: 0.4s;
}
diff --git a/img/left_arrow.svg b/img/left_arrow.svg
new file mode 100644
index 00000000..bbcd50c6
--- /dev/null
+++ b/img/left_arrow.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/img/right_arrow.svg b/img/right_arrow.svg
new file mode 100644
index 00000000..eb45cced
--- /dev/null
+++ b/img/right_arrow.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/index.html b/index.html
index cea0bd9b..a76ce976 100644
--- a/index.html
+++ b/index.html
@@ -12,6 +12,7 @@
+
@@ -34,7 +35,7 @@
-
+
@@ -72,6 +73,17 @@
+
+
+
+
+
+
+
+
+
diff --git a/js/main.js b/js/main.js
index 4f43c2cb..f76ce42e 100644
--- a/js/main.js
+++ b/js/main.js
@@ -1,37 +1,18 @@
import { errorMsg } from "./tools.js";
import { PdgToggle } from "./menu/show-pdg.js";
import { drawAll } from "./draw.js";
-import {
- bits,
- genStatus,
- renderRangeParameters,
- parametersRange,
- getWidthFilterContent,
- renderGenSim,
-} from "./menu/filter/filter.js";
-import {
- mouseDown,
- mouseUp,
- mouseOut,
- mouseMove,
- getVisible,
- onScroll,
-} from "./events.js";
-import { loadObjects } from "./types/load.js";
-import { objectTypes } from "./types/objects.js";
-import { copyObject } from "./lib/copy.js";
+import { getWidthFilterContent } from "./menu/filter/filter.js";
+import { mouseDown, mouseUp, mouseOut, mouseMove, onScroll } from "./events.js";
+import { showEventSwitcher, loadSelectedEvent } from "./menu/event-number.js";
+import { renderEvent } from "./menu/event-number.js";
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
-const manipulationTools = document.getElementsByClassName("manipulation-tool");
-const filter = document.getElementById("filter");
-const filters = document.getElementById("filters");
-
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
-let jsonData = {};
+const jsonData = {};
const dragTools = {
draggedObject: null,
@@ -46,17 +27,9 @@ const currentObjects = {};
const visibleObjects = {};
-function start(currentObjects, visibleObjects) {
- for (const [key, value] of Object.entries(currentObjects)) {
- const classType = objectTypes[key];
- const collection = value.collection;
- classType.setup(collection, canvas);
- }
-
- drawAll(ctx, currentObjects);
-
- getVisible(currentObjects, visibleObjects);
-}
+const selectedObjectTypes = {
+ types: ["edm4hep::MCParticle"],
+};
canvas.onmousedown = (event) => {
mouseDown(event, visibleObjects, dragTools);
@@ -74,14 +47,6 @@ window.onscroll = () => {
onScroll(currentObjects, visibleObjects);
};
-/*
-function showInputModal() {
- const modal = document.getElementById("input-modal");
-
- modal.style.display = "block";
-}
-*/
-
function hideInputModal() {
const modal = document.getElementById("input-modal");
@@ -101,11 +66,37 @@ document.getElementById("input-file").addEventListener("change", (event) => {
const reader = new FileReader();
reader.addEventListener("load", (event) => {
const fileText = event.target.result;
- jsonData = JSON.parse(fileText);
+ jsonData.data = JSON.parse(fileText);
const eventNumberInput = document.getElementById("event-number");
- eventNumberInput.max = Object.keys(jsonData).length - 1;
+ const options = Object.keys(jsonData.data).map((event) =>
+ parseInt(event.replace("Event ", ""))
+ );
+ eventNumberInput.max = Object.keys(options).length - 1;
+ if (options.length === 0) {
+ errorMsg("No events found in the file!");
+ return;
+ }
+ eventNumberInput.value = options[0];
document.getElementById("event-selector").style.display = "block";
+ const eventOptions = document.getElementById("event-number");
+ const eventSelectorMenu = document.getElementById("event-selector-menu");
+ eventOptions.replaceChildren();
+ eventSelectorMenu.replaceChildren();
+ options.forEach((option) => {
+ const optionElement = document.createElement("option");
+ optionElement.appendChild(document.createTextNode(option));
+ eventOptions.appendChild(optionElement);
+
+ const optionElementMenu = document.createElement("div");
+ optionElementMenu.className = "event-option";
+ optionElementMenu.appendChild(document.createTextNode(option));
+ eventSelectorMenu.appendChild(optionElementMenu);
+ optionElementMenu.addEventListener("click", () => {
+ renderEvent(option);
+ eventSelectorMenu.style.display = "none";
+ });
+ });
});
reader.readAsText(file);
break;
@@ -118,42 +109,12 @@ document
event.preventDefault();
const eventNum = document.getElementById("event-number").value;
- const selectedObjectTypes = ["edm4hep::MCParticle"];
- const objects = loadObjects(jsonData, eventNum, selectedObjectTypes);
-
- copyObject(objects, loadedObjects);
- copyObject(objects, currentObjects);
-
- const length = Object.values(loadedObjects)
- .map((obj) => obj.collection.length)
- .reduce((a, b) => a + b, 0);
-
- if (length === 0) {
- errorMsg("Provided file does not contain any MC particle tree!");
- return;
- }
- for (const eventNum in jsonData) {
- delete jsonData[eventNum];
- }
- start(currentObjects, visibleObjects);
hideInputModal();
- window.scroll((canvas.width - window.innerWidth) / 2, 0);
+ showEventSwitcher(eventNum);
+ loadSelectedEvent();
- for (const tool of manipulationTools) {
- tool.style.display = "flex";
- }
-
- const mcObjects = loadedObjects["edm4hep::MCParticle"].collection;
- mcObjects.forEach((mcObject) => {
- genStatus.add(mcObject.generatorStatus);
- });
- genStatus.setCheckBoxes();
- renderRangeParameters(filters, parametersRange);
const width = getWidthFilterContent();
filter.style.width = width;
-
- renderGenSim(bits, genStatus, filters);
-
const pdgToggle = new PdgToggle("show-pdg");
pdgToggle.init(() => {
pdgToggle.toggle(currentObjects, () => {
@@ -162,4 +123,12 @@ document
});
});
-export { canvas, ctx, loadedObjects, currentObjects, visibleObjects };
+export {
+ canvas,
+ ctx,
+ loadedObjects,
+ currentObjects,
+ visibleObjects,
+ jsonData,
+ selectedObjectTypes,
+};
diff --git a/js/menu/event-number.js b/js/menu/event-number.js
new file mode 100644
index 00000000..273a817e
--- /dev/null
+++ b/js/menu/event-number.js
@@ -0,0 +1,135 @@
+import { loadObjects } from "../types/load.js";
+import { copyObject } from "../lib/copy.js";
+import {
+ loadedObjects,
+ currentObjects,
+ visibleObjects,
+ canvas,
+ ctx,
+} from "../main.js";
+import { getVisible } from "../events.js";
+import {
+ bits,
+ genStatus,
+ renderRangeParameters,
+ parametersRange,
+ renderGenSim,
+} from "./filter/filter.js";
+import { drawAll } from "../draw.js";
+import { objectTypes } from "../types/objects.js";
+import { jsonData, selectedObjectTypes } from "../main.js";
+
+const filters = document.getElementById("filters");
+const eventSwitcher = document.getElementById("event-switcher");
+const eventNumber = document.getElementById("selected-event");
+const previousEvent = document.getElementById("previous-event");
+const nextEvent = document.getElementById("next-event");
+const manipulationTools = document.getElementsByClassName("manipulation-tool");
+
+let currentEvent;
+
+const scrollLocation = {};
+
+function updateEventNumber(newEventNumber) {
+ if (eventNumber.firstChild) {
+ eventNumber.removeChild(eventNumber.firstChild);
+ }
+ eventNumber.appendChild(document.createTextNode(`Event: ${newEventNumber}`));
+}
+
+function start(currentObjects, visibleObjects) {
+ for (const [key, value] of Object.entries(currentObjects)) {
+ const classType = objectTypes[key];
+ const collection = value.collection;
+ classType.setup(collection, canvas);
+ }
+
+ drawAll(ctx, currentObjects);
+
+ getVisible(currentObjects, visibleObjects);
+}
+
+export function renderEvent(eventNumber) {
+ const data = jsonData.data[`Event ${eventNumber}`];
+
+ scrollLocation[currentEvent] = {
+ x: window.scrollX,
+ y: window.scrollY,
+ };
+
+ if (data === undefined) {
+ return;
+ } else {
+ currentEvent = eventNumber;
+ loadSelectedEvent(jsonData, selectedObjectTypes.types, eventNumber);
+ updateEventNumber(eventNumber);
+ }
+}
+
+export function showEventSwitcher(initialValue) {
+ eventSwitcher.style.display = "flex";
+ updateEventNumber(initialValue);
+ currentEvent = initialValue;
+}
+
+export function loadSelectedEvent() {
+ const objects = loadObjects(
+ jsonData.data,
+ currentEvent,
+ selectedObjectTypes.types
+ );
+
+ copyObject(objects, loadedObjects);
+ copyObject(objects, currentObjects);
+
+ const length = Object.values(loadedObjects)
+ .map((obj) => obj.collection.length)
+ .reduce((a, b) => a + b, 0);
+
+ if (length === 0) {
+ errorMsg("Event does not contain any objects!");
+ return;
+ }
+
+ start(currentObjects, visibleObjects);
+ if (scrollLocation[currentEvent] === undefined) {
+ scrollLocation[currentEvent] = {
+ x: (canvas.width - window.innerWidth) / 2,
+ y: 0,
+ };
+ }
+
+ window.scroll(scrollLocation[currentEvent].x, scrollLocation[currentEvent].y);
+
+ for (const tool of manipulationTools) {
+ tool.style.display = "flex";
+ }
+
+ const mcObjects = loadedObjects["edm4hep::MCParticle"].collection;
+ genStatus.reset();
+ mcObjects.forEach((mcObject) => {
+ genStatus.add(mcObject.generatorStatus);
+ });
+ genStatus.setCheckBoxes();
+ filters.replaceChildren();
+
+ renderRangeParameters(parametersRange);
+ renderGenSim(bits, genStatus);
+}
+
+previousEvent.addEventListener("click", () => {
+ const newEventNum = `${parseInt(currentEvent) - 1}`;
+ renderEvent(newEventNum);
+});
+nextEvent.addEventListener("click", () => {
+ const newEventNum = `${parseInt(currentEvent) + 1}`;
+ renderEvent(newEventNum);
+});
+eventNumber.addEventListener("click", () => {
+ const eventSelectorMenu = document.getElementById("event-selector-menu");
+ if (eventSelectorMenu.style.display === "flex") {
+ eventSelectorMenu.style.display = "none";
+ } else {
+ eventSelectorMenu.style.display = "flex";
+ }
+});
diff --git a/js/menu/filter/builders.js b/js/menu/filter/builders.js
index 118da614..6f9cf82b 100644
--- a/js/menu/filter/builders.js
+++ b/js/menu/filter/builders.js
@@ -35,6 +35,10 @@ export class CheckboxBuilder {
container.appendChild(section);
this.checkBoxes.forEach((checkbox) => checkbox.render(options));
}
+
+ reset() {
+ this.uniqueValues = new Set();
+ }
}
export class BitFieldBuilder extends CheckboxBuilder {
diff --git a/js/menu/filter/filter.js b/js/menu/filter/filter.js
index febe3cd1..a26e577c 100644
--- a/js/menu/filter/filter.js
+++ b/js/menu/filter/filter.js
@@ -36,7 +36,7 @@ filterButton.addEventListener("click", () => {
}
});
-export function renderRangeParameters(container, rangeParameters) {
+export function renderRangeParameters(rangeParameters) {
const rangeFilters = document.createElement("div");
rangeFilters.id = "range-filters";
rangeFilters.style.display = "grid";
@@ -51,7 +51,7 @@ export function renderRangeParameters(container, rangeParameters) {
parameter.max = undefined;
parameter.render(rangeFilters);
});
- container.appendChild(rangeFilters);
+ filters.appendChild(rangeFilters);
}
export function getWidthFilterContent() {
@@ -63,7 +63,7 @@ export function getWidthFilterContent() {
return `${width}px`;
}
-export function renderGenSim(sim, gen, container) {
+export function renderGenSim(sim, gen) {
const div = document.createElement("div");
div.style.display = "flex";
div.style.flexDirection = "column";
@@ -71,7 +71,7 @@ export function renderGenSim(sim, gen, container) {
div.style.alignItems = "start";
sim.render(div);
gen.render(div);
- container.appendChild(div);
+ filters.appendChild(div);
}
let parametersRange = units.sort((a, b) =>
@@ -129,8 +129,8 @@ function removeFilter(loadedObjects, currentObjects, visibleObjects) {
filters.innerHTML = "";
- renderRangeParameters(filters, parametersRange);
- renderGenSim(bits, genStatus, filters);
+ renderRangeParameters(parametersRange);
+ renderGenSim(bits, genStatus);
}
apply.addEventListener("click", () =>
diff --git a/js/menu/show-pdg.js b/js/menu/show-pdg.js
index eb577d5a..a5333e59 100644
--- a/js/menu/show-pdg.js
+++ b/js/menu/show-pdg.js
@@ -1,4 +1,5 @@
import { Toggle } from "./toggle.js";
+import { selectedObjectTypes } from "../main.js";
export class PdgToggle extends Toggle {
constructor(id) {
@@ -6,18 +7,20 @@ export class PdgToggle extends Toggle {
}
toggle(currentObjects, redraw) {
- const validParticles = ["edm4hep::MCParticle"];
+ const validObjects = selectedObjectTypes.types;
if (this.isSliderActive) {
- for (const objectType of validParticles) {
+ for (const objectType of validObjects) {
const collection = currentObjects[objectType].collection;
+ if (collection[0].PDG === undefined) return;
for (const object of collection) {
object.updateTexImg(`${object.PDG}`);
}
}
} else {
- for (const objectType of validParticles) {
+ for (const objectType of validObjects) {
const collection = currentObjects[objectType].collection;
+ if (collection[0].PDG === undefined) return;
for (const object of collection) {
object.updateTexImg(`${object.name}`);
}