Skip to content

Commit 0bca177

Browse files
authored
Merge branch 'main' into text_annotations_pt2
2 parents a7d6849 + 8b009c6 commit 0bca177

11 files changed

Lines changed: 1050 additions & 1692 deletions

.DS_Store

-2 KB
Binary file not shown.

package-lock.json

Lines changed: 430 additions & 1432 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@
3030
"eslint": "^9.24.0",
3131
"jest": "^29.7.0",
3232
"jest-environment-jsdom": "^29.7.0",
33-
"live-server": "^1.2.2",
33+
"live-server": "^1.2.0",
3434
"supertest": "^7.1.4"
3535
},
3636
"directories": {
3737
"test": "tests"
3838
}
39-
}
39+
}

templates/boneset.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ <h2 style="color: #003366; text-align: center; margin-bottom: 25px; border-botto
247247
<script type="module" src="js/main.js"></script>
248248
<script type="module" src="js/imageDisplay.js"></script>
249249
<script type="module" src="js/annotationOverlay.js"></script>
250+
<script type="module" src="js/imageCaptions.js"></script>
250251

251252
<!-- Simple Escape Key Handler -->
252253
<script>
@@ -268,4 +269,4 @@ <h2 style="color: #003366; text-align: center; margin-bottom: 25px; border-botto
268269
</script>
269270
</body>
270271

271-
</html>
272+
</html>

templates/diagnostic-colored-regions.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,10 +246,10 @@ <h2>Step 3: Diagnostic Output</h2>
246246
addLog('info', `Path ${index + 1}: ${name}`, { fill, opacity });
247247
});
248248
} else {
249-
addLog('error', ' No SVG overlay was created');
249+
addLog('error', ' No SVG overlay was created');
250250
resultsDiv.innerHTML = `
251251
<div class="status error">
252-
<strong> No SVG Created</strong><br>
252+
<strong> No SVG Created</strong><br>
253253
The displayColoredRegions function did not create an SVG overlay.<br>
254254
Check the console logs above for details.
255255
</div>

templates/js/coloredRegionsOverlay.js

Lines changed: 214 additions & 190 deletions
Large diffs are not rendered by default.

templates/js/imageCaptions.js

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// js/imageCaptions.js
2+
// Image captions for bone images, extracted from PowerPoint slides
3+
4+
export const imageCaptions = {
5+
// Bony Pelvis (main boneset)
6+
"bony_pelvis": {
7+
image1: "Right Pelvis (lateral aspect)",
8+
image2: "Right Pelvis(medial aspect)"
9+
},
10+
11+
// Ilium and its subbones
12+
"ilium": {
13+
image1: "Right Pelvis (lateral aspect)",
14+
image2: "Right Pelvis(medial aspect)"
15+
},
16+
"iliac_crest": {
17+
image1: "Right Pelvis (lateral aspect)",
18+
image2: "Right Pelvis(medial aspect)"
19+
},
20+
"anterior_iliac_spines": {
21+
image1: "Right Pelvis (lateral aspect)",
22+
image2: "Right Pelvis(medial aspect)"
23+
},
24+
"posterior_iliac_spines": {
25+
image1: "Right Pelvis (lateral aspect)",
26+
image2: "Right Pelvis(medial aspect)"
27+
},
28+
"auricular_surface": {
29+
image1: "Right Pelvis(medial aspect)",
30+
image2: null
31+
},
32+
33+
// Ischium and its subbones
34+
"ischium": {
35+
image1: "Right Pelvis (lateral aspect)",
36+
image2: "Right Pelvis(medial aspect)"
37+
},
38+
"ramus": {
39+
image1: "Right Pelvis (lateral aspect)",
40+
image2: "Right Pelvis(medial aspect)"
41+
},
42+
"ischial_tuberosity": {
43+
image1: "Right Pelvis (lateral aspect)",
44+
image2: "Right Pelvis(medial aspect)"
45+
},
46+
"ischial_spine": {
47+
image1: "Right Pelvis (lateral aspect)",
48+
image2: "Right Pelvis(medial aspect)"
49+
},
50+
"sciatic_notches": {
51+
image1: "Right Pelvis (lateral aspect)",
52+
image2: "Right Pelvis(medial aspect)"
53+
},
54+
55+
// Pubis and its subbones
56+
"pubis": {
57+
image1: "Right Pelvis (lateral aspect)",
58+
image2: "Right Pelvis(medial aspect)"
59+
},
60+
"pubic_rami": {
61+
image1: "Right Pelvis (lateral aspect)",
62+
image2: "Right Pelvis(medial aspect)"
63+
},
64+
"pectineal_line": {
65+
image1: "Right Pelvis(medial aspect)",
66+
image2: null
67+
},
68+
"symphyseal_surface": {
69+
image1: "Right Pelvis(medial aspect)",
70+
image2: null
71+
},
72+
"pubic_tubercle": {
73+
image1: "Right Pelvis (lateral aspect)",
74+
image2: null
75+
}
76+
};

templates/js/imageDisplay.js

Lines changed: 82 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
// Rendering helpers for the image area (no dropdown wiring).
33

44
import { clearAnnotations, loadAndDrawAnnotations } from "./annotationOverlay.js";
5-
import { displayColoredRegions, clearAllColoredRegions } from './coloredRegionsOverlay.js';
5+
import { displayColoredRegions, clearAllColoredRegions } from "./coloredRegionsOverlay.js";
6+
import { imageCaptions } from "./imageCaptions.js";
67

78
// Track the current boneId for colored regions
89
let currentBoneId = null;
@@ -14,6 +15,14 @@ function getImageContainer() {
1415
);
1516
}
1617

18+
/** Helper function to get captions for a boneId */
19+
function getCaptionsForBone(boneId) {
20+
if (!boneId || !imageCaptions[boneId]) {
21+
return { image1: null, image2: null };
22+
}
23+
return imageCaptions[boneId];
24+
}
25+
1726
/** ---- Empty-state / clearing ------------------------------------------- */
1827
export function showPlaceholder() {
1928
const c = getImageContainer();
@@ -28,6 +37,12 @@ export function showPlaceholder() {
2837
clearAllColoredRegions();
2938
currentBoneId = null;
3039

40+
// Remove caption container if it exists
41+
const captionContainer = document.getElementById("caption-container");
42+
if (captionContainer) {
43+
captionContainer.remove();
44+
}
45+
3146
// Remove black background class when showing placeholder
3247
const imagesContent = document.querySelector(".images-content");
3348
if (imagesContent) imagesContent.classList.remove("has-images");
@@ -40,6 +55,13 @@ export function clearImages() {
4055
clearAnnotations(c);
4156
clearAllColoredRegions();
4257
}
58+
59+
// Remove caption container if it exists
60+
const captionContainer = document.getElementById("caption-container");
61+
if (captionContainer) {
62+
captionContainer.remove();
63+
}
64+
4365
currentBoneId = null;
4466
currentIsBonesetSelection = false; // Reset the flag
4567

@@ -49,7 +71,7 @@ export function clearImages() {
4971
}
5072

5173
/** ---- Public entry: render images array --------------------------------
52-
* Optionally pass { annotationsUrl: 'templates/data/annotations/xyz.json', boneId: 'bone_name' }
74+
* Optionally pass { annotationsUrl: "templates/data/annotations/xyz.json", boneId: "bone_name" }
5375
*/
5476
export function displayBoneImages(images, options = {}) {
5577
const container = getImageContainer();
@@ -92,24 +114,39 @@ export function displayBoneImages(images, options = {}) {
92114

93115
//** ---- Single image ------------------------------------------------------ */
94116
function displaySingleImage(image, container, options = {}) {
95-
// 1. CRITICAL FIX: Add the 'single-image' class to the main container.
117+
// 1. CRITICAL FIX: Add the "single-image" class to the main container.
96118
// This CSS class is required for the styles to correctly size the single image layout.
97119
container.className = "single-image";
98120

99-
// 2. Simplification: Use innerHTML to directly create the necessary structure
100-
// (.single-image-wrapper > img), which better aligns with your CSS.
101121
container.innerHTML = `
102122
<div class="single-image-wrapper">
103-
<img
104-
class="bone-image"
105-
src="${image.url || image.src || ""}"
106-
alt="${image.alt || image.filename || "Bone image"}"
107-
>
123+
<div class="image-wrapper">
124+
<img
125+
class="bone-image"
126+
src="${image.url || image.src || ""}"
127+
alt="${image.alt || image.filename || "Bone image"}"
128+
>
129+
</div>
108130
</div>
109131
`;
110132

133+
// Create caption container OUTSIDE the image container if caption exists
134+
if (imageCaptions.image1) {
135+
const captionContainer = document.createElement("div");
136+
captionContainer.id = "caption-container";
137+
captionContainer.className = "single-image";
138+
139+
const caption = document.createElement("div");
140+
caption.className = "caption-box image-caption";
141+
caption.textContent = imageCaptions.image1;
142+
captionContainer.appendChild(caption);
143+
144+
// Insert caption container after the image container
145+
container.parentElement.insertBefore(captionContainer, container.nextSibling);
146+
}
147+
111148
// 3. Get reference to the image element for colored regions and event handlers
112-
const img = container.querySelector('img');
149+
const img = container.querySelector("img");
113150
if (img) {
114151
const loadColoredRegions = () => {
115152
img.classList.add("loaded");
@@ -137,7 +174,7 @@ function displaySingleImage(image, container, options = {}) {
137174
// Check if already loaded (cached) - use setTimeout to let browser process
138175
setTimeout(() => {
139176
if (img.complete && img.naturalHeight !== 0) {
140-
console.log(`[ImageDisplay] Single image was cached, calling loadColoredRegions immediately`);
177+
console.log("[ImageDisplay] Single image was cached, calling loadColoredRegions immediately");
141178
loadColoredRegions();
142179
}
143180
}, 0);
@@ -160,13 +197,20 @@ function applyRotation(imgEl, { rot_deg = 0, flipH = false } = {}) {
160197
}
161198

162199
function displayTwoImages(images, container, options = {}) {
200+
// Get captions for this bone
201+
const captions = getCaptionsForBone(currentBoneId);
202+
163203
// Add the two-images class to the container for CSS styling
164204
container.className = "two-images";
165205

206+
// Create images first
166207
images.slice(0, 2).forEach((image, index) => {
167208
const imgItem = document.createElement("div");
168209
imgItem.className = "image-item";
169210

211+
const imgWrapper = document.createElement("div");
212+
imgWrapper.className = "image-wrapper";
213+
170214
const img = document.createElement("img");
171215
img.alt = image.alt || image.filename || "Bone image";
172216

@@ -191,21 +235,44 @@ function displayTwoImages(images, container, options = {}) {
191235
imgItem.textContent = "Failed to load image.";
192236
});
193237

194-
imgItem.appendChild(img);
238+
imgWrapper.appendChild(img);
239+
imgItem.appendChild(imgWrapper);
195240
container.appendChild(imgItem);
196241

197242
// Set src LAST - this triggers the load
198243
img.src = image.url || image.src || "";
199244

200245
// Check if image is already loaded from cache after setting src
201-
// Use setTimeout to allow the browser to process the src assignment first
202246
setTimeout(() => {
203247
if (img.complete && img.naturalWidth > 0) {
204248
console.log(`[ImageDisplay] Image ${index} was already cached, manually triggering load handler`);
205249
loadColoredRegions();
206250
}
207251
}, 10);
208252
});
253+
254+
// Create caption container AFTER images, OUTSIDE the grid
255+
if (captions.image1 || captions.image2) {
256+
const captionContainer = document.createElement("div");
257+
captionContainer.id = "caption-container";
258+
259+
if (captions.image1) {
260+
const caption1 = document.createElement("div");
261+
caption1.className = "caption-box image-caption";
262+
caption1.textContent = captions.image1;
263+
captionContainer.appendChild(caption1);
264+
}
265+
266+
if (captions.image2) {
267+
const caption2 = document.createElement("div");
268+
caption2.className = "caption-box image-caption";
269+
caption2.textContent = captions.image2;
270+
captionContainer.appendChild(caption2);
271+
}
272+
273+
// Insert caption container after the image container
274+
container.parentElement.insertBefore(captionContainer, container.nextSibling);
275+
}
209276
}
210277

211278
/** ---- 3+ images grid ---------------------------------------------------- */
@@ -230,4 +297,4 @@ function displayMultipleImages(images, container) {
230297
});
231298

232299
container.appendChild(wrapper);
233-
}
300+
}

templates/js/navigation.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ let currentSubboneIndex = -1;
33
let subbones = [];
44

55
export function setupNavigation(prevButton, nextButton, subboneDropdown, updateDescription) {
6+
// Setup Previous/Next button navigation
67
prevButton.addEventListener("click", () => {
78
prevSubbone();
89
updateUI(subboneDropdown, updateDescription);
@@ -14,6 +15,60 @@ export function setupNavigation(prevButton, nextButton, subboneDropdown, updateD
1415
});
1516

1617
disableButtons(prevButton, nextButton);
18+
19+
// Setup Home button functionality
20+
setupHomeButton();
21+
}
22+
23+
/**
24+
* Sets up the Home button to reset the application to initial state
25+
*/
26+
function setupHomeButton() {
27+
const homeButton = document.getElementById("text-button-Home");
28+
29+
if (!homeButton) {
30+
console.warn("Home button not found in DOM");
31+
return;
32+
}
33+
34+
// Add click event listener
35+
homeButton.addEventListener("click", resetToInitialState);
36+
37+
// Add keyboard support (Enter and Space keys)
38+
homeButton.addEventListener("keydown", (event) => {
39+
if (event.key === "Enter" || event.key === " ") {
40+
event.preventDefault();
41+
resetToInitialState();
42+
}
43+
});
44+
45+
// Add visual feedback on hover
46+
homeButton.style.cursor = "pointer";
47+
}
48+
49+
/**
50+
* Resets the entire application to its initial load state
51+
*/
52+
function resetToInitialState() {
53+
// Provide immediate visual feedback
54+
const homeButton = document.getElementById("text-button-Home");
55+
if (homeButton) {
56+
homeButton.style.opacity = "0.6";
57+
setTimeout(() => {
58+
homeButton.style.opacity = "1";
59+
}, 150);
60+
}
61+
62+
// The simplest and most reliable way to reset everything
63+
// This ensures ALL state returns to initial load state:
64+
// - All dropdowns reset
65+
// - Search bar clears
66+
// - Images clear
67+
// - Description clears
68+
// - Sidebar closes
69+
// - Page scrolls to top
70+
// - All navigation state resets
71+
window.location.reload();
1772
}
1873

1974
export function setBoneAndSubbones(bone, boneSubbones) {

templates/js/quiz.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ class QuizManager {
161161
}
162162

163163
/**
164-
* Get image URL for an item
164+
* Get image URL for an item....
165165
*/
166166
getImageUrl(itemId) {
167167
// Use the API endpoint that serves bone images

0 commit comments

Comments
 (0)