From b8276062336e2a352c96daeb7e16ff0ac358701f Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Wed, 19 Jun 2024 18:48:04 -0500 Subject: [PATCH 1/9] Switch events without reload #37 + auto event select #34 --- css/event.css | 27 +++++++++ img/left_arrow.svg | 1 + img/right_arrow.svg | 1 + index.html | 11 +++- js/main.js | 106 +++++++++------------------------- js/menu/event-number.js | 113 +++++++++++++++++++++++++++++++++++++ js/menu/filter/builders.js | 4 ++ js/menu/filter/filter.js | 12 ++-- js/menu/show-pdg.js | 9 ++- 9 files changed, 196 insertions(+), 88 deletions(-) create mode 100644 css/event.css create mode 100644 img/left_arrow.svg create mode 100644 img/right_arrow.svg create mode 100644 js/menu/event-number.js diff --git a/css/event.css b/css/event.css new file mode 100644 index 00000000..afdc1dbd --- /dev/null +++ b/css/event.css @@ -0,0 +1,27 @@ +#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; + font-size: 1.2em; +} 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 740a66c9..b4ccb88e 100644 --- a/index.html +++ b/index.html @@ -12,6 +12,7 @@ + @@ -72,6 +73,14 @@ +
+ Previous event + + Next event +
+ @@ -79,4 +88,4 @@ - + \ No newline at end of file diff --git a/js/main.js b/js/main.js index 4f43c2cb..1f881e24 100644 --- a/js/main.js +++ b/js/main.js @@ -1,37 +1,17 @@ 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"; 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 +26,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 +46,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,10 +65,18 @@ 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"; }); reader.readAsText(file); @@ -118,42 +90,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); - - for (const tool of manipulationTools) { - tool.style.display = "flex"; - } + showEventSwitcher(eventNum); + loadSelectedEvent(); - 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 +104,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..7dded5e6 --- /dev/null +++ b/js/menu/event-number.js @@ -0,0 +1,113 @@ +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; + +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); +} + +function renderEvent(eventNumber) { + const data = jsonData.data[`Event ${eventNumber}`]; + + if (data === undefined) { + return; + } else { + currentEvent = eventNumber; + updateEventNumber(eventNumber); + loadSelectedEvent(jsonData, selectedObjectTypes.types, 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); + window.scroll((canvas.width - window.innerWidth) / 2, 0); + + 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); +}); 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..53095764 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 (object[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 (object[0].PDG === undefined) return; for (const object of collection) { object.updateTexImg(`${object.name}`); } From 91606b3bed9d9703c4ff6b11318bc20786b5f632 Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Wed, 19 Jun 2024 19:02:52 -0500 Subject: [PATCH 2/9] show events options in dropdown menu --- index.html | 2 +- js/main.js | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index b4ccb88e..ec7fe8d4 100644 --- a/index.html +++ b/index.html @@ -35,7 +35,7 @@
- +

diff --git a/js/main.js b/js/main.js index 1f881e24..66924021 100644 --- a/js/main.js +++ b/js/main.js @@ -78,6 +78,13 @@ document.getElementById("input-file").addEventListener("change", (event) => { } eventNumberInput.value = options[0]; document.getElementById("event-selector").style.display = "block"; + const eventOptions = document.getElementById("event-number"); + eventOptions.replaceChildren(); + options.forEach((option) => { + const optionElement = document.createElement("option"); + optionElement.appendChild(document.createTextNode(option)); + eventOptions.appendChild(optionElement); + }); }); reader.readAsText(file); break; From 0e02996b6f060d1a670ac70200b2c0d6ab5d88ab Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Wed, 19 Jun 2024 20:52:48 -0500 Subject: [PATCH 3/9] show another dropdown menu for facility (not only arrow switcher) --- css/event.css | 22 ++++++++++++++++++++++ index.html | 5 ++++- js/main.js | 12 ++++++++++++ js/menu/event-number.js | 10 +++++++++- js/menu/show-pdg.js | 4 ++-- 5 files changed, 49 insertions(+), 4 deletions(-) diff --git a/css/event.css b/css/event.css index afdc1dbd..03de3398 100644 --- a/css/event.css +++ b/css/event.css @@ -24,4 +24,26 @@ #selected-event { font-weight: 500; font-size: 1.2em; + cursor: pointer; +} + +#event-selector-menu { + display: none; + position: fixed; + top: 32px; + flex-direction: column; + justify-content: center; + align-items: center; + background-color: #e1e1e1; + width: 75px; + left: 50%; + transform: translateX(-50%); +} + +.event-option { + cursor: pointer; + border: 1px solid #000; + width: 100%; + text-align: center; + margin: 1px 0; } diff --git a/index.html b/index.html index ec7fe8d4..6cf47301 100644 --- a/index.html +++ b/index.html @@ -76,7 +76,10 @@
Previous event - +
+ +
+
Next event
diff --git a/js/main.js b/js/main.js index 66924021..8d79439e 100644 --- a/js/main.js +++ b/js/main.js @@ -4,6 +4,7 @@ import { drawAll } from "./draw.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"); @@ -79,11 +80,22 @@ document.getElementById("input-file").addEventListener("change", (event) => { 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", () => { + eventSelectorMenu.style.display = "none"; + renderEvent(option); + }); }); }); reader.readAsText(file); diff --git a/js/menu/event-number.js b/js/menu/event-number.js index 7dded5e6..a8c0a35b 100644 --- a/js/menu/event-number.js +++ b/js/menu/event-number.js @@ -47,7 +47,7 @@ function start(currentObjects, visibleObjects) { getVisible(currentObjects, visibleObjects); } -function renderEvent(eventNumber) { +export function renderEvent(eventNumber) { const data = jsonData.data[`Event ${eventNumber}`]; if (data === undefined) { @@ -111,3 +111,11 @@ 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/show-pdg.js b/js/menu/show-pdg.js index 53095764..a5333e59 100644 --- a/js/menu/show-pdg.js +++ b/js/menu/show-pdg.js @@ -12,7 +12,7 @@ export class PdgToggle extends Toggle { if (this.isSliderActive) { for (const objectType of validObjects) { const collection = currentObjects[objectType].collection; - if (object[0].PDG === undefined) return; + if (collection[0].PDG === undefined) return; for (const object of collection) { object.updateTexImg(`${object.PDG}`); } @@ -20,7 +20,7 @@ export class PdgToggle extends Toggle { } else { for (const objectType of validObjects) { const collection = currentObjects[objectType].collection; - if (object[0].PDG === undefined) return; + if (collection[0].PDG === undefined) return; for (const object of collection) { object.updateTexImg(`${object.name}`); } From 00d318622c7eb0521e6bf9a0c8807508fcabf2d4 Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Fri, 21 Jun 2024 18:48:55 -0500 Subject: [PATCH 4/9] feat: same size fonts, remember scroll, scrollbar for events, 'obvious' clickable event --- css/event.css | 13 ++++++++++--- css/main.css | 1 + js/main.js | 2 +- js/menu/event-number.js | 18 ++++++++++++++++-- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/css/event.css b/css/event.css index 03de3398..19f506bc 100644 --- a/css/event.css +++ b/css/event.css @@ -23,21 +23,28 @@ #selected-event { font-weight: 500; - font-size: 1.2em; cursor: pointer; } +#selected-event:hover { + text-decoration: underline; + background-color: #d1d1d1; +} + #event-selector-menu { display: none; position: fixed; top: 32px; flex-direction: column; - justify-content: center; align-items: center; background-color: #e1e1e1; - width: 75px; + width: 100px; left: 50%; transform: translateX(-50%); + max-height: 175px; + overflow-y: auto; + overflow-x: hidden; + padding: 0 5px; } .event-option { 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/js/main.js b/js/main.js index 8d79439e..f76ce42e 100644 --- a/js/main.js +++ b/js/main.js @@ -93,8 +93,8 @@ document.getElementById("input-file").addEventListener("change", (event) => { optionElementMenu.appendChild(document.createTextNode(option)); eventSelectorMenu.appendChild(optionElementMenu); optionElementMenu.addEventListener("click", () => { - eventSelectorMenu.style.display = "none"; renderEvent(option); + eventSelectorMenu.style.display = "none"; }); }); }); diff --git a/js/menu/event-number.js b/js/menu/event-number.js index a8c0a35b..273a817e 100644 --- a/js/menu/event-number.js +++ b/js/menu/event-number.js @@ -28,6 +28,8 @@ const manipulationTools = document.getElementsByClassName("manipulation-tool"); let currentEvent; +const scrollLocation = {}; + function updateEventNumber(newEventNumber) { if (eventNumber.firstChild) { eventNumber.removeChild(eventNumber.firstChild); @@ -50,12 +52,17 @@ function start(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; - updateEventNumber(eventNumber); loadSelectedEvent(jsonData, selectedObjectTypes.types, eventNumber); + updateEventNumber(eventNumber); } } @@ -85,7 +92,14 @@ export function loadSelectedEvent() { } start(currentObjects, visibleObjects); - window.scroll((canvas.width - window.innerWidth) / 2, 0); + 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"; From fa9db2464c61828d3cc73f76c3b30afcc22d2fbc Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Wed, 19 Jun 2024 18:48:04 -0500 Subject: [PATCH 5/9] Switch events without reload #37 + auto event select #34 --- css/event.css | 27 +++++++++ img/left_arrow.svg | 1 + img/right_arrow.svg | 1 + index.html | 11 +++- js/main.js | 106 +++++++++------------------------- js/menu/event-number.js | 113 +++++++++++++++++++++++++++++++++++++ js/menu/filter/builders.js | 4 ++ js/menu/filter/filter.js | 12 ++-- js/menu/show-pdg.js | 9 ++- 9 files changed, 196 insertions(+), 88 deletions(-) create mode 100644 css/event.css create mode 100644 img/left_arrow.svg create mode 100644 img/right_arrow.svg create mode 100644 js/menu/event-number.js diff --git a/css/event.css b/css/event.css new file mode 100644 index 00000000..afdc1dbd --- /dev/null +++ b/css/event.css @@ -0,0 +1,27 @@ +#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; + font-size: 1.2em; +} 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 740a66c9..b4ccb88e 100644 --- a/index.html +++ b/index.html @@ -12,6 +12,7 @@ + @@ -72,6 +73,14 @@
+
+ Previous event + + Next event +
+ @@ -79,4 +88,4 @@ - + \ No newline at end of file diff --git a/js/main.js b/js/main.js index 4f43c2cb..1f881e24 100644 --- a/js/main.js +++ b/js/main.js @@ -1,37 +1,17 @@ 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"; 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 +26,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 +46,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,10 +65,18 @@ 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"; }); reader.readAsText(file); @@ -118,42 +90,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); - - for (const tool of manipulationTools) { - tool.style.display = "flex"; - } + showEventSwitcher(eventNum); + loadSelectedEvent(); - 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 +104,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..7dded5e6 --- /dev/null +++ b/js/menu/event-number.js @@ -0,0 +1,113 @@ +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; + +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); +} + +function renderEvent(eventNumber) { + const data = jsonData.data[`Event ${eventNumber}`]; + + if (data === undefined) { + return; + } else { + currentEvent = eventNumber; + updateEventNumber(eventNumber); + loadSelectedEvent(jsonData, selectedObjectTypes.types, 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); + window.scroll((canvas.width - window.innerWidth) / 2, 0); + + 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); +}); 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..53095764 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 (object[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 (object[0].PDG === undefined) return; for (const object of collection) { object.updateTexImg(`${object.name}`); } From 4cf479444200c0aecdf6ee28a184b546c2ec104c Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Wed, 19 Jun 2024 19:02:52 -0500 Subject: [PATCH 6/9] show events options in dropdown menu --- index.html | 2 +- js/main.js | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index b4ccb88e..ec7fe8d4 100644 --- a/index.html +++ b/index.html @@ -35,7 +35,7 @@
- +

diff --git a/js/main.js b/js/main.js index 1f881e24..66924021 100644 --- a/js/main.js +++ b/js/main.js @@ -78,6 +78,13 @@ document.getElementById("input-file").addEventListener("change", (event) => { } eventNumberInput.value = options[0]; document.getElementById("event-selector").style.display = "block"; + const eventOptions = document.getElementById("event-number"); + eventOptions.replaceChildren(); + options.forEach((option) => { + const optionElement = document.createElement("option"); + optionElement.appendChild(document.createTextNode(option)); + eventOptions.appendChild(optionElement); + }); }); reader.readAsText(file); break; From 055ca96d0d5781617834676532945825e422cab1 Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Wed, 19 Jun 2024 20:52:48 -0500 Subject: [PATCH 7/9] show another dropdown menu for facility (not only arrow switcher) --- css/event.css | 22 ++++++++++++++++++++++ index.html | 5 ++++- js/main.js | 12 ++++++++++++ js/menu/event-number.js | 10 +++++++++- js/menu/show-pdg.js | 4 ++-- 5 files changed, 49 insertions(+), 4 deletions(-) diff --git a/css/event.css b/css/event.css index afdc1dbd..03de3398 100644 --- a/css/event.css +++ b/css/event.css @@ -24,4 +24,26 @@ #selected-event { font-weight: 500; font-size: 1.2em; + cursor: pointer; +} + +#event-selector-menu { + display: none; + position: fixed; + top: 32px; + flex-direction: column; + justify-content: center; + align-items: center; + background-color: #e1e1e1; + width: 75px; + left: 50%; + transform: translateX(-50%); +} + +.event-option { + cursor: pointer; + border: 1px solid #000; + width: 100%; + text-align: center; + margin: 1px 0; } diff --git a/index.html b/index.html index ec7fe8d4..6cf47301 100644 --- a/index.html +++ b/index.html @@ -76,7 +76,10 @@
Previous event - +
+ +
+
Next event
diff --git a/js/main.js b/js/main.js index 66924021..8d79439e 100644 --- a/js/main.js +++ b/js/main.js @@ -4,6 +4,7 @@ import { drawAll } from "./draw.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"); @@ -79,11 +80,22 @@ document.getElementById("input-file").addEventListener("change", (event) => { 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", () => { + eventSelectorMenu.style.display = "none"; + renderEvent(option); + }); }); }); reader.readAsText(file); diff --git a/js/menu/event-number.js b/js/menu/event-number.js index 7dded5e6..a8c0a35b 100644 --- a/js/menu/event-number.js +++ b/js/menu/event-number.js @@ -47,7 +47,7 @@ function start(currentObjects, visibleObjects) { getVisible(currentObjects, visibleObjects); } -function renderEvent(eventNumber) { +export function renderEvent(eventNumber) { const data = jsonData.data[`Event ${eventNumber}`]; if (data === undefined) { @@ -111,3 +111,11 @@ 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/show-pdg.js b/js/menu/show-pdg.js index 53095764..a5333e59 100644 --- a/js/menu/show-pdg.js +++ b/js/menu/show-pdg.js @@ -12,7 +12,7 @@ export class PdgToggle extends Toggle { if (this.isSliderActive) { for (const objectType of validObjects) { const collection = currentObjects[objectType].collection; - if (object[0].PDG === undefined) return; + if (collection[0].PDG === undefined) return; for (const object of collection) { object.updateTexImg(`${object.PDG}`); } @@ -20,7 +20,7 @@ export class PdgToggle extends Toggle { } else { for (const objectType of validObjects) { const collection = currentObjects[objectType].collection; - if (object[0].PDG === undefined) return; + if (collection[0].PDG === undefined) return; for (const object of collection) { object.updateTexImg(`${object.name}`); } From e4bbac7cac8d40cdc02bfe7a5df564048f8786fe Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Fri, 21 Jun 2024 18:48:55 -0500 Subject: [PATCH 8/9] feat: same size fonts, remember scroll, scrollbar for events, 'obvious' clickable event --- css/event.css | 13 ++++++++++--- css/main.css | 1 + js/main.js | 2 +- js/menu/event-number.js | 18 ++++++++++++++++-- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/css/event.css b/css/event.css index 03de3398..19f506bc 100644 --- a/css/event.css +++ b/css/event.css @@ -23,21 +23,28 @@ #selected-event { font-weight: 500; - font-size: 1.2em; cursor: pointer; } +#selected-event:hover { + text-decoration: underline; + background-color: #d1d1d1; +} + #event-selector-menu { display: none; position: fixed; top: 32px; flex-direction: column; - justify-content: center; align-items: center; background-color: #e1e1e1; - width: 75px; + width: 100px; left: 50%; transform: translateX(-50%); + max-height: 175px; + overflow-y: auto; + overflow-x: hidden; + padding: 0 5px; } .event-option { 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/js/main.js b/js/main.js index 8d79439e..f76ce42e 100644 --- a/js/main.js +++ b/js/main.js @@ -93,8 +93,8 @@ document.getElementById("input-file").addEventListener("change", (event) => { optionElementMenu.appendChild(document.createTextNode(option)); eventSelectorMenu.appendChild(optionElementMenu); optionElementMenu.addEventListener("click", () => { - eventSelectorMenu.style.display = "none"; renderEvent(option); + eventSelectorMenu.style.display = "none"; }); }); }); diff --git a/js/menu/event-number.js b/js/menu/event-number.js index a8c0a35b..273a817e 100644 --- a/js/menu/event-number.js +++ b/js/menu/event-number.js @@ -28,6 +28,8 @@ const manipulationTools = document.getElementsByClassName("manipulation-tool"); let currentEvent; +const scrollLocation = {}; + function updateEventNumber(newEventNumber) { if (eventNumber.firstChild) { eventNumber.removeChild(eventNumber.firstChild); @@ -50,12 +52,17 @@ function start(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; - updateEventNumber(eventNumber); loadSelectedEvent(jsonData, selectedObjectTypes.types, eventNumber); + updateEventNumber(eventNumber); } } @@ -85,7 +92,14 @@ export function loadSelectedEvent() { } start(currentObjects, visibleObjects); - window.scroll((canvas.width - window.innerWidth) / 2, 0); + 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"; From 6371ca061621172e4d4fccfffc0cf36461dfae34 Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Tue, 25 Jun 2024 16:27:32 -0500 Subject: [PATCH 9/9] change to single grey color --- css/filter.css | 2 +- css/toggle.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/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; }