diff --git a/js/events.js b/js/events.js index 9c6a0043..8eb2e169 100644 --- a/js/events.js +++ b/js/events.js @@ -1,4 +1,4 @@ -import { canvas } from "./main.js"; +import { canvas, ctx } from "./main.js"; import { drawAll, drawVisible } from "./draw.js"; const mouseDown = function (event, visibleObjects, dragTools) { @@ -44,14 +44,38 @@ const mouseOut = function (event, dragTools) { }; const mouseMove = function (event, visibleObjects, dragTools) { - if (!dragTools.isDragging) { - return; - } - const boundigClientRect = canvas.getBoundingClientRect(); const mouseX = parseInt(event.clientX - boundigClientRect.x); const mouseY = parseInt(event.clientY - boundigClientRect.y); + const allObjects = Object.values(visibleObjects.datatypes) + .map((datatype) => datatype.collection) + .flat(); + + let someHovered = false; + for (const object of allObjects) { + if (object.isHere(mouseX, mouseY)) { + if (dragTools.hoveredObject !== object) { + dragTools.hoveredObject = object; + drawVisible(visibleObjects); + object.showObjectTip(ctx); + } + someHovered = true; + document.body.style.cursor = "pointer"; + break; + } + } + + if (!someHovered) { + document.body.style.cursor = "default"; + dragTools.hoveredObject = null; + drawVisible(visibleObjects); + } + + if (!dragTools.isDragging) { + return; + } + const dx = mouseX - dragTools.prevMouseX; const dy = mouseY - dragTools.prevMouseY; diff --git a/js/lib/getName.js b/js/lib/getName.js index edfbc1f5..599fb792 100644 --- a/js/lib/getName.js +++ b/js/lib/getName.js @@ -1,4 +1,4 @@ -import { mappings } from "../../data/particles.js"; +import { mappings } from "../../mappings/particles.js"; export function getName(pdg) { const particle = mappings[pdg]; diff --git a/js/lib/graphic-primitives.js b/js/lib/graphic-primitives.js index f8426ad5..a09cf63f 100644 --- a/js/lib/graphic-primitives.js +++ b/js/lib/graphic-primitives.js @@ -131,3 +131,18 @@ export function drawObjectHeader(ctx, object) { } ctx.restore(); } + +export function drawObjectInfoTip(ctx, x, y, ...args) { + ctx.save(); + ctx.font = "bold 12px sans-serif"; + const lines = args.length; + const height = 20 * lines; + const maxWidth = Math.max(...args.map((arg) => ctx.measureText(arg).width)); + ctx.fillStyle = "rgba(225, 225, 225, 1)"; + ctx.fillRect(x, y, maxWidth + 10, height + 10); + ctx.fillStyle = "black"; + for (const [i, arg] of args.entries()) { + ctx.fillText(arg, x + 5, y + 20 + i * 20); + } + ctx.restore(); +} diff --git a/js/menu/filter/filter.js b/js/menu/filter/filter.js index 60724f6a..abcc5807 100644 --- a/js/menu/filter/filter.js +++ b/js/menu/filter/filter.js @@ -5,6 +5,7 @@ import { reconnect } from "./reconnect.js"; import { getVisible } from "../../events.js"; import { units } from "../../types/units.js"; import { copyObject } from "../../lib/copy.js"; +import { SimStatusBitFieldDisplayValues } from "../../../mappings/sim-status.js"; const filterButton = document.getElementById("filter-button"); const openFilter = document.getElementById("open-filter"); @@ -60,17 +61,6 @@ let parametersRange = units.sort((a, b) => parametersRange = parametersRange.map((parameter) => new Range(parameter)); -const SimStatusBitFieldDisplayValues = { - 23: "Overlay", - 24: "Stopped", - 25: "LeftDetector", - 26: "DecayedInCalorimeter", - 27: "DecayedInTracker", - 28: "VertexIsNotEndpointOfParent", - 29: "Backscatter", - 30: "CreatedInSimulation", -}; - const bits = new BitFieldBuilder( "simulatorStatus", "Simulation status", diff --git a/js/types/load.js b/js/types/load.js index b9ee63d7..201602e4 100644 --- a/js/types/load.js +++ b/js/types/load.js @@ -21,13 +21,19 @@ function loadEmptyRelations(object, relations) { } } -export function loadPlainObject(collection, datatype, collectionId) { +export function loadPlainObject( + collection, + datatype, + collectionId, + collectionName +) { const objects = []; for (const [index, particle] of collection.entries()) { const newObject = new objectTypes[datatype](); newObject.index = index; newObject.collectionId = collectionId; + newObject.collectionName = collectionName; loadMembers(newObject, particle, datatypes[datatype].members); loadEmptyRelations(newObject, datatypes[datatype]); @@ -66,7 +72,7 @@ export function loadObjects(jsonData, event, objectsToLoad) { }); for (const datatype of datatypesToLoad) { - Object.values(eventData).forEach((element) => { + Object.entries(eventData).forEach(([key, element]) => { const collectionName = `${datatype}Collection`; if (element.collType === collectionName) { const collection = element.collection; @@ -74,7 +80,8 @@ export function loadObjects(jsonData, event, objectsToLoad) { const objectCollection = loadPlainObject( collection, datatype, - collectionId + collectionId, + key ); objects.datatypes[datatype].collection.push(...objectCollection); } diff --git a/js/types/objects.js b/js/types/objects.js index e52006d9..5e47ed73 100644 --- a/js/types/objects.js +++ b/js/types/objects.js @@ -3,10 +3,12 @@ import { drawRoundedRect, drawTextLines, drawObjectHeader, + drawObjectInfoTip, } from "../lib/graphic-primitives.js"; import { getName } from "../lib/getName.js"; import { linkTypes } from "./links.js"; import { parseCharge } from "../lib/parseCharge.js"; +import { getSimStatusDisplayValuesFromBit } from "../../mappings/sim-status.js"; const TOP_MARGIN = 45; @@ -53,6 +55,13 @@ class EDMObject { y < this.y + this.height ); } + + showObjectTip(ctx) { + const x = this.x; + const y = this.y - 10; + const collectionName = "Collection: " + this.collectionName; + drawObjectInfoTip(ctx, x, y, collectionName); + } } export class MCParticle extends EDMObject { @@ -106,7 +115,17 @@ export class MCParticle extends EDMObject { const topLines = []; topLines.push("ID: " + this.index); topLines.push("Gen. stat.: " + this.generatorStatus); - topLines.push("Sim. stat.: " + this.simulatorStatus); + const simulatorStatus = getSimStatusDisplayValuesFromBit( + this.simulatorStatus + ); + const simulatorStatusFirstLetter = simulatorStatus + .map((s) => s[0]) + .join(""); + const simulatorStatusString = + simulatorStatusFirstLetter !== "" + ? simulatorStatusFirstLetter + : this.simulatorStatus; + topLines.push("Sim. stat.: " + simulatorStatusString); const bottomY = this.y + this.height * 0.65; const bottomLines = []; @@ -121,6 +140,17 @@ export class MCParticle extends EDMObject { drawTextLines(ctx, bottomLines, boxCenterX, bottomY, 22); } + showObjectTip(ctx) { + const x = this.x; + const y = this.y - 10; + const collectionName = "Collection: " + this.collectionName; + const simulatorStatus = getSimStatusDisplayValuesFromBit( + this.simulatorStatus + ); + + drawObjectInfoTip(ctx, x, y, collectionName, ...simulatorStatus); + } + static setup(mcCollection) { for (const mcParticle of mcCollection) { const parentLength = mcParticle.oneToManyRelations["parents"].length; diff --git a/data/particles.js b/mappings/particles.js similarity index 100% rename from data/particles.js rename to mappings/particles.js diff --git a/mappings/sim-status.js b/mappings/sim-status.js new file mode 100644 index 00000000..db438605 --- /dev/null +++ b/mappings/sim-status.js @@ -0,0 +1,34 @@ +export const SimStatusBitFieldDisplayValues = { + 23: "Overlay", + 24: "Stopped", + 25: "LeftDetector", + 26: "DecayedInCalorimeter", + 27: "DecayedInTracker", + 28: "VertexIsNotEndpointOfParent", + 29: "Backscatter", + 30: "CreatedInSimulation", +}; + +export function parseBits(bit) { + const bits = []; + + for (let i = 0; i < 32; i++) { + if (bit & (1 << i)) { + bits.push(i); + } + } + + return bits; +} + +export function getSimStatusDisplayValues(bits) { + return bits.map((bit) => + SimStatusBitFieldDisplayValues[bit] !== undefined + ? SimStatusBitFieldDisplayValues[bit] + : `Bit ${bit}` + ); +} + +export function getSimStatusDisplayValuesFromBit(bit) { + return getSimStatusDisplayValues(parseBits(bit)); +}