From 185d36a004f3077df52c6b3c3da55013a515df79 Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Fri, 12 Jul 2024 15:36:17 -0500 Subject: [PATCH 1/5] basic information modal for empty view --- css/empty-view.css | 18 ++++++++++++++++++ img/blue-info.svg | 5 +++++ index.html | 6 ++++++ js/lib/messages.js | 8 ++++++++ 4 files changed, 37 insertions(+) create mode 100644 css/empty-view.css create mode 100644 img/blue-info.svg diff --git a/css/empty-view.css b/css/empty-view.css new file mode 100644 index 00000000..da3d2073 --- /dev/null +++ b/css/empty-view.css @@ -0,0 +1,18 @@ +#empty-view { + display: none; + align-items: center; + background-color: #e1e1e1; + padding: 10px; + position: fixed; + z-index: 2; + height: 30px; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + border-radius: 5px; + border: 1px solid #000; +} + +#empty-view p { + margin-left: 10px; +} diff --git a/img/blue-info.svg b/img/blue-info.svg new file mode 100644 index 00000000..760cf319 --- /dev/null +++ b/img/blue-info.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/index.html b/index.html index 3cb6744e..b415557c 100644 --- a/index.html +++ b/index.html @@ -17,6 +17,7 @@ + @@ -155,6 +156,11 @@
+
+ Empty view +

This view has no elements

+
+ diff --git a/js/lib/messages.js b/js/lib/messages.js index 4b24f73e..0ce67757 100644 --- a/js/lib/messages.js +++ b/js/lib/messages.js @@ -11,3 +11,11 @@ export function errorMsg(msg) { msgDiv.style.color = "red"; msgDiv.innerHTML = "

ERROR: " + msg + "

"; } + +export function emptyViewMessage() { + const msgDiv = document.getElementById("empty-view"); + msgDiv.style.display = "flex"; + setTimeout(() => { + msgDiv.style.display = "none"; + }, 3000); +} From e29441d8f07c8005ce99cb6af6aa04f2f49d4c93 Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Fri, 12 Jul 2024 15:41:39 -0500 Subject: [PATCH 2/5] show info modal when empty --- js/views/clustertree.js | 5 ----- js/views/list.js | 3 ++- js/views/mcparticletree.js | 4 +++- js/views/onewayview.js | 3 ++- js/views/recoclustertrack.js | 3 ++- js/views/recoparticletree.js | 4 ---- js/views/tracktree.js | 5 ----- js/views/tree.js | 6 ++++++ 8 files changed, 15 insertions(+), 18 deletions(-) diff --git a/js/views/clustertree.js b/js/views/clustertree.js index f4ce1ca9..e38432c3 100644 --- a/js/views/clustertree.js +++ b/js/views/clustertree.js @@ -5,11 +5,6 @@ export function clusterTree(viewCurrentObjects) { const clusterCollection = viewCurrentObjects.datatypes["edm4hep::Cluster"].collection ?? []; - if (clusterCollection.length === 0) { - alert("No Clusters found in this event."); - return; - } - buildTree(clusterCollection, "clusters"); } diff --git a/js/views/list.js b/js/views/list.js index 99aa7ce4..d364f09d 100644 --- a/js/views/list.js +++ b/js/views/list.js @@ -1,8 +1,9 @@ import { canvas } from "../main.js"; +import { emptyViewMessage } from "../lib/messages.js"; export function listView(collection) { if (collection.length === 0) { - alert("No objects found!"); + emptyViewMessage(); return; } const width = window.innerWidth; diff --git a/js/views/mcparticletree.js b/js/views/mcparticletree.js index 4b702cc1..74aaf1ea 100644 --- a/js/views/mcparticletree.js +++ b/js/views/mcparticletree.js @@ -1,12 +1,14 @@ import { canvas } from "../main.js"; import { preFilterTree } from "./pre-filter.js"; +import { emptyViewMessage } from "../lib/messages.js"; export function mcParticleTree(viewCurrentObjects) { const mcCollection = viewCurrentObjects.datatypes["edm4hep::MCParticle"].collection ?? []; if (mcCollection.length === 0) { - alert("No MCParticles found in this event."); + emptyViewMessage(); + return; } const getMaxRow = (parentLinks) => { diff --git a/js/views/onewayview.js b/js/views/onewayview.js index 1a6f8683..7e02d2d0 100644 --- a/js/views/onewayview.js +++ b/js/views/onewayview.js @@ -1,4 +1,5 @@ import { canvas } from "../main.js"; +import { emptyViewMessage } from "../lib/messages.js"; export function oneWayView(viewObjects, fromCollectionName, relationName) { const relations = @@ -8,7 +9,7 @@ export function oneWayView(viewObjects, fromCollectionName, relationName) { const toCollection = relations.map((relation) => relation.to); if (fromCollection.length === 0 || toCollection.length === 0) { - alert("No association found!"); + emptyViewMessage(); return; } diff --git a/js/views/recoclustertrack.js b/js/views/recoclustertrack.js index 874f9630..192d988f 100644 --- a/js/views/recoclustertrack.js +++ b/js/views/recoclustertrack.js @@ -1,12 +1,13 @@ import { canvas } from "../main.js"; import { emptyCopyObject } from "../lib/copy.js"; +import { emptyViewMessage } from "../lib/messages.js"; export function recoClusterTrackVertex(viewObjects) { const recoParticles = viewObjects.datatypes["edm4hep::ReconstructedParticle"].collection; if (recoParticles.length === 0) { - alert("No reconstructed particles found!"); + emptyViewMessage(); return; } diff --git a/js/views/recoparticletree.js b/js/views/recoparticletree.js index 26a73e32..a578a90a 100644 --- a/js/views/recoparticletree.js +++ b/js/views/recoparticletree.js @@ -6,10 +6,6 @@ export function recoParticleTree(viewCurrentObjects) { viewCurrentObjects.datatypes["edm4hep::ReconstructedParticle"].collection ?? []; - if (recoCollection.length === 0) { - alert("No ReconstructedParticles found in this event."); - } - buildTree(recoCollection, "particles"); } diff --git a/js/views/tracktree.js b/js/views/tracktree.js index 523441b8..6ff0ff36 100644 --- a/js/views/tracktree.js +++ b/js/views/tracktree.js @@ -5,11 +5,6 @@ export function trackTree(viewCurrentObjects) { const trackCollection = viewCurrentObjects.datatypes["edm4hep::Track"].collection ?? []; - if (trackCollection.length === 0) { - alert("No Tracks found in this event."); - return; - } - buildTree(trackCollection, "tracks"); } diff --git a/js/views/tree.js b/js/views/tree.js index bfe89342..45604abb 100644 --- a/js/views/tree.js +++ b/js/views/tree.js @@ -1,10 +1,16 @@ import { canvas } from "../main.js"; +import { emptyViewMessage } from "../lib/messages.js"; // All particles that are related to itself have an one to many relation export function buildTree(collection, relationOfReference) { const nodes = new Set(); const children = new Set(); + if (collection.length === 0) { + emptyViewMessage(); + return; + } + for (const object of collection) { const objects = object.oneToManyRelations[relationOfReference].map( (link) => link.to From d79f237f2250211af31a8ecedfcd8c8705bfc5e1 Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Fri, 12 Jul 2024 15:44:46 -0500 Subject: [PATCH 3/5] change duration of input modal + show on missing views --- js/lib/messages.js | 2 +- js/views/association-view.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/js/lib/messages.js b/js/lib/messages.js index 0ce67757..310352f4 100644 --- a/js/lib/messages.js +++ b/js/lib/messages.js @@ -17,5 +17,5 @@ export function emptyViewMessage() { msgDiv.style.display = "flex"; setTimeout(() => { msgDiv.style.display = "none"; - }, 3000); + }, 1500); } diff --git a/js/views/association-view.js b/js/views/association-view.js index 5c931c04..249d58c7 100644 --- a/js/views/association-view.js +++ b/js/views/association-view.js @@ -1,4 +1,5 @@ import { canvas } from "../main.js"; +import { emptyViewMessage } from "../lib/messages.js"; // List 1:1 association in a vertical list export function buildAssociationView(viewObjects, associationName) { @@ -6,7 +7,7 @@ export function buildAssociationView(viewObjects, associationName) { const length = associations.length; if (length === 0) { - alert("No association found!"); + emptyViewMessage(); return; } From 2ab2e89a680d8f0bdbd8f96a9ad9fcf642627e06 Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Sat, 13 Jul 2024 18:44:23 -0500 Subject: [PATCH 4/5] improve functionality when checking for empty view --- js/draw.js | 18 +++++++++++++----- js/lib/empty-object.js | 32 ++++++++++++++++++++++++++++++++ js/lib/graphic-primitives.js | 4 ++++ js/lib/messages.js | 8 +++++--- js/views/association-view.js | 6 ------ js/views/list.js | 5 ----- js/views/mcparticletree.js | 6 ------ js/views/onewayview.js | 6 ------ js/views/recoclustertrack.js | 6 ------ js/views/tree.js | 6 ------ js/views/views.js | 13 +++++++++++++ 11 files changed, 67 insertions(+), 43 deletions(-) create mode 100644 js/lib/empty-object.js diff --git a/js/draw.js b/js/draw.js index e5c31903..555d8173 100644 --- a/js/draw.js +++ b/js/draw.js @@ -1,4 +1,5 @@ import { canvas, ctx } from "./main.js"; +import { updateCanvas } from "./lib/graphic-primitives.js"; function draw(objects) { const datatypes = objects.datatypes; @@ -32,19 +33,26 @@ function draw(objects) { } export function drawAll(loadedObjects) { - ctx.clearRect(0, 0, canvas.width, canvas.height); - + emptyCanvas(); draw(loadedObjects); } export function drawVisible(visibleObjects) { + emptyVisibleCanvas(); + draw(visibleObjects); +} + +export function emptyCanvas() { + updateCanvas(ctx, 0, 0, canvas.width, canvas.height); +} + +function emptyVisibleCanvas() { const boundigClientRect = canvas.getBoundingClientRect(); - ctx.clearRect( + updateCanvas( + ctx, 0 - boundigClientRect.x, 0 - boundigClientRect.y, window.innerWidth, window.innerHeight ); - - draw(visibleObjects); } diff --git a/js/lib/empty-object.js b/js/lib/empty-object.js new file mode 100644 index 00000000..8b24aecd --- /dev/null +++ b/js/lib/empty-object.js @@ -0,0 +1,32 @@ +const updateEmpty = (empty, length) => { + if (length === 0) { + empty.value = empty.value && true; + } else { + empty.value = false; + } +}; + +export function checkEmptyObject(obj) { + const datatypes = obj.datatypes; + const associations = obj.associations; + + let empty = { value: true }; + + Object.values(datatypes).forEach((datatype) => { + updateEmpty(empty, datatype.collection.length); + + Object.values(datatype.oneToMany).forEach((oneToMany) => { + updateEmpty(empty, oneToMany.length); + }); + + Object.values(datatype.oneToOne).forEach((oneToOne) => { + updateEmpty(empty, oneToOne.length); + }); + }); + + Object.values(associations).forEach((association) => { + updateEmpty(empty, association.length); + }); + + return empty.value; +} diff --git a/js/lib/graphic-primitives.js b/js/lib/graphic-primitives.js index 2e3438f5..248b9498 100644 --- a/js/lib/graphic-primitives.js +++ b/js/lib/graphic-primitives.js @@ -107,3 +107,7 @@ export function drawStraightLink(ctx, link) { ctx.stroke(); ctx.restore(); } + +export function updateCanvas(ctx, x, y, width, height) { + ctx.clearRect(x, y, width, height); +} diff --git a/js/lib/messages.js b/js/lib/messages.js index 310352f4..495bb3b9 100644 --- a/js/lib/messages.js +++ b/js/lib/messages.js @@ -15,7 +15,9 @@ export function errorMsg(msg) { export function emptyViewMessage() { const msgDiv = document.getElementById("empty-view"); msgDiv.style.display = "flex"; - setTimeout(() => { - msgDiv.style.display = "none"; - }, 1500); +} + +export function hideEmptyViewMessage() { + const msgDiv = document.getElementById("empty-view"); + msgDiv.style.display = "none"; } diff --git a/js/views/association-view.js b/js/views/association-view.js index 249d58c7..4f04bf03 100644 --- a/js/views/association-view.js +++ b/js/views/association-view.js @@ -1,16 +1,10 @@ import { canvas } from "../main.js"; -import { emptyViewMessage } from "../lib/messages.js"; // List 1:1 association in a vertical list export function buildAssociationView(viewObjects, associationName) { const associations = viewObjects.associations[associationName]; const length = associations.length; - if (length === 0) { - emptyViewMessage(); - return; - } - const fromWidth = associations[0].from.width; const toWidth = associations[0].to.width; const fromHorizontalGap = 0.3 * fromWidth; diff --git a/js/views/list.js b/js/views/list.js index d364f09d..a6806249 100644 --- a/js/views/list.js +++ b/js/views/list.js @@ -1,11 +1,6 @@ import { canvas } from "../main.js"; -import { emptyViewMessage } from "../lib/messages.js"; export function listView(collection) { - if (collection.length === 0) { - emptyViewMessage(); - return; - } const width = window.innerWidth; canvas.width = width; diff --git a/js/views/mcparticletree.js b/js/views/mcparticletree.js index 74aaf1ea..7f4ec1cf 100644 --- a/js/views/mcparticletree.js +++ b/js/views/mcparticletree.js @@ -1,16 +1,10 @@ import { canvas } from "../main.js"; import { preFilterTree } from "./pre-filter.js"; -import { emptyViewMessage } from "../lib/messages.js"; export function mcParticleTree(viewCurrentObjects) { const mcCollection = viewCurrentObjects.datatypes["edm4hep::MCParticle"].collection ?? []; - if (mcCollection.length === 0) { - emptyViewMessage(); - return; - } - const getMaxRow = (parentLinks) => { let maxRow = -1; for (const parentLink of parentLinks) { diff --git a/js/views/onewayview.js b/js/views/onewayview.js index 7e02d2d0..c69bddaa 100644 --- a/js/views/onewayview.js +++ b/js/views/onewayview.js @@ -1,5 +1,4 @@ import { canvas } from "../main.js"; -import { emptyViewMessage } from "../lib/messages.js"; export function oneWayView(viewObjects, fromCollectionName, relationName) { const relations = @@ -8,11 +7,6 @@ export function oneWayView(viewObjects, fromCollectionName, relationName) { const fromCollection = relations.map((relation) => relation.from); const toCollection = relations.map((relation) => relation.to); - if (fromCollection.length === 0 || toCollection.length === 0) { - emptyViewMessage(); - return; - } - const fromWidth = fromCollection[0].width; const toWidth = toCollection[0].width; const fromHorizontalGap = 0.3 * fromWidth; diff --git a/js/views/recoclustertrack.js b/js/views/recoclustertrack.js index 192d988f..d9fd30ea 100644 --- a/js/views/recoclustertrack.js +++ b/js/views/recoclustertrack.js @@ -1,16 +1,10 @@ import { canvas } from "../main.js"; import { emptyCopyObject } from "../lib/copy.js"; -import { emptyViewMessage } from "../lib/messages.js"; export function recoClusterTrackVertex(viewObjects) { const recoParticles = viewObjects.datatypes["edm4hep::ReconstructedParticle"].collection; - if (recoParticles.length === 0) { - emptyViewMessage(); - return; - } - const findFirstObject = (relationName) => { const object = recoParticles.find((particle) => { const relation = particle.oneToManyRelations[relationName]; diff --git a/js/views/tree.js b/js/views/tree.js index 45604abb..bfe89342 100644 --- a/js/views/tree.js +++ b/js/views/tree.js @@ -1,16 +1,10 @@ import { canvas } from "../main.js"; -import { emptyViewMessage } from "../lib/messages.js"; // All particles that are related to itself have an one to many relation export function buildTree(collection, relationOfReference) { const nodes = new Set(); const children = new Set(); - if (collection.length === 0) { - emptyViewMessage(); - return; - } - for (const object of collection) { const objects = object.oneToManyRelations[relationOfReference].map( (link) => link.to diff --git a/js/views/views.js b/js/views/views.js index ce655a2a..d40beadd 100644 --- a/js/views/views.js +++ b/js/views/views.js @@ -1,5 +1,6 @@ import { currentObjects, currentEvent } from "../event-number.js"; import { copyObject } from "../lib/copy.js"; +import { checkEmptyObject } from "../lib/empty-object.js"; import { getVisible } from "../events.js"; import { drawAll } from "../draw.js"; import { canvas } from "../main.js"; @@ -11,6 +12,8 @@ import { mouseMove, onScroll, } from "../events.js"; +import { emptyViewMessage, hideEmptyViewMessage } from "../lib/messages.js"; +import { emptyCanvas } from "../draw.js"; const currentView = {}; @@ -55,6 +58,16 @@ const drawView = (view) => { const viewVisibleObjects = {}; preFilterFunction(currentObjects, viewObjects); + const isEmpty = checkEmptyObject(viewObjects); + + if (isEmpty) { + emptyCanvas(); + emptyViewMessage(); + return; + } else { + hideEmptyViewMessage(); + } + viewFunction(viewObjects); copyObject(viewObjects, viewCurrentObjects); From 4910729360be78e88dca9e37629738be00b18553 Mon Sep 17 00:00:00 2001 From: Braulio Rivas Abad Date: Sat, 13 Jul 2024 19:25:47 -0500 Subject: [PATCH 5/5] simplify if statement --- js/views/views.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/js/views/views.js b/js/views/views.js index d40beadd..f74cb3ba 100644 --- a/js/views/views.js +++ b/js/views/views.js @@ -64,9 +64,8 @@ const drawView = (view) => { emptyCanvas(); emptyViewMessage(); return; - } else { - hideEmptyViewMessage(); } + hideEmptyViewMessage(); viewFunction(viewObjects); copyObject(viewObjects, viewCurrentObjects);