hospital-management/templates/radiology/study_comparison.html
2025-08-12 13:33:25 +03:00

1123 lines
45 KiB
HTML

{% extends 'base.html' %}
{% load static %}
{% block title %}Study Comparison - Radiology{% endblock %}
{% block content %}
<div class="content">
<div class="container-fluid">
<!-- Page Header -->
<div class="row">
<div class="col-12">
<div class="page-header">
<div class="page-title">
<h4>Study Comparison</h4>
<h6>Compare current and prior imaging studies for comprehensive analysis</h6>
</div>
<div class="page-btn">
<div class="btn-group">
<button type="button" class="btn btn-primary" onclick="loadStudyForComparison()">
<i class="fa fa-plus"></i> Add Study
</button>
<button type="button" class="btn btn-info" onclick="syncViewports()">
<i class="fa fa-sync"></i> Sync Views
</button>
<button type="button" class="btn btn-success" onclick="generateComparisonReport()">
<i class="fa fa-file-alt"></i> Generate Report
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Study Selection -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="card-title">Study Selection & Information</h5>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-sm btn-outline-primary" onclick="swapStudies()">
<i class="fa fa-exchange-alt"></i> Swap
</button>
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="resetComparison()">
<i class="fa fa-undo"></i> Reset
</button>
</div>
</div>
</div>
<div class="card-body">
<div class="row">
<!-- Current Study -->
<div class="col-md-6">
<div class="study-panel current-study">
<div class="study-header">
<h6 class="text-primary">Current Study</h6>
<span class="badge bg-primary">{{ current_study.study_date|default:"Jan 15, 2024" }}</span>
</div>
<div class="study-info">
<div class="row">
<div class="col-6">
<p><strong>Patient:</strong> {{ current_study.patient_name|default:"John Smith" }}</p>
<p><strong>MRN:</strong> {{ current_study.patient_mrn|default:"123456" }}</p>
<p><strong>Study Date:</strong> {{ current_study.study_date|default:"Jan 15, 2024" }}</p>
<p><strong>Modality:</strong> {{ current_study.modality|default:"CT" }}</p>
</div>
<div class="col-6">
<p><strong>Body Part:</strong> {{ current_study.body_part|default:"Chest" }}</p>
<p><strong>Protocol:</strong> {{ current_study.protocol|default:"Chest CT with Contrast" }}</p>
<p><strong>Accession:</strong> {{ current_study.accession|default:"ACC123456" }}</p>
<p><strong>Series:</strong> {{ current_study.series_count|default:3 }}</p>
</div>
</div>
</div>
</div>
</div>
<!-- Prior Study -->
<div class="col-md-6">
<div class="study-panel prior-study">
<div class="study-header">
<h6 class="text-success">Prior Study</h6>
<span class="badge bg-success">{{ prior_study.study_date|default:"Dec 10, 2023" }}</span>
</div>
<div class="study-info">
<div class="row">
<div class="col-6">
<p><strong>Patient:</strong> {{ prior_study.patient_name|default:"John Smith" }}</p>
<p><strong>MRN:</strong> {{ prior_study.patient_mrn|default:"123456" }}</p>
<p><strong>Study Date:</strong> {{ prior_study.study_date|default:"Dec 10, 2023" }}</p>
<p><strong>Modality:</strong> {{ prior_study.modality|default:"CT" }}</p>
</div>
<div class="col-6">
<p><strong>Body Part:</strong> {{ prior_study.body_part|default:"Chest" }}</p>
<p><strong>Protocol:</strong> {{ prior_study.protocol|default:"Chest CT with Contrast" }}</p>
<p><strong>Accession:</strong> {{ prior_study.accession|default:"ACC098765" }}</p>
<p><strong>Series:</strong> {{ prior_study.series_count|default:3 }}</p>
</div>
</div>
</div>
<div class="study-actions">
<button class="btn btn-sm btn-outline-success" onclick="selectPriorStudy()">
<i class="fa fa-search"></i> Select Different Study
</button>
</div>
</div>
</div>
</div>
<!-- Time Interval -->
<div class="row mt-3">
<div class="col-12">
<div class="time-interval-info text-center">
<div class="interval-display">
<i class="fa fa-clock text-warning"></i>
<strong>Time Interval: {{ time_interval|default:"36 days" }}</strong>
<small class="text-muted">({{ interval_details|default:"5 weeks, 1 day" }})</small>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Comparison Viewer -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="card-title">Image Comparison</h5>
<div class="card-tools">
<div class="btn-group">
<button type="button" class="btn btn-sm btn-outline-primary active" data-layout="side-by-side" onclick="changeLayout('side-by-side')">
<i class="fa fa-columns"></i> Side by Side
</button>
<button type="button" class="btn btn-sm btn-outline-primary" data-layout="overlay" onclick="changeLayout('overlay')">
<i class="fa fa-layer-group"></i> Overlay
</button>
<button type="button" class="btn btn-sm btn-outline-primary" data-layout="flicker" onclick="changeLayout('flicker')">
<i class="fa fa-exchange-alt"></i> Flicker
</button>
<button type="button" class="btn btn-sm btn-outline-primary" data-layout="quad" onclick="changeLayout('quad')">
<i class="fa fa-th"></i> Quad View
</button>
</div>
</div>
</div>
<div class="card-body p-0">
<div class="comparison-container" id="comparisonContainer">
<!-- Side by Side Layout (Default) -->
<div class="layout-side-by-side" id="sideBySideLayout">
<div class="row g-0">
<div class="col-md-6">
<div class="viewport-container current-viewport">
<div class="viewport-header">
<h6>Current Study - {{ current_study.study_date|default:"Jan 15, 2024" }}</h6>
<div class="viewport-controls">
<button class="btn btn-sm btn-outline-light" onclick="resetCurrentView()">
<i class="fa fa-home"></i>
</button>
<button class="btn btn-sm btn-outline-light" onclick="fitCurrentToWindow()">
<i class="fa fa-expand-arrows-alt"></i>
</button>
</div>
</div>
<div class="viewport-content">
<canvas id="currentCanvas" width="600" height="500"></canvas>
<div class="viewport-overlay">
<div class="overlay-info top-left">
<div>{{ current_study.patient_name|default:"Smith, John" }}</div>
<div>{{ current_study.study_date|default:"2024-01-15" }}</div>
<div>Series: <span id="currentSeries">1</span></div>
</div>
<div class="overlay-info bottom-right">
<div>Image: <span id="currentImage">60</span>/120</div>
<div>W: <span id="currentWindow">400</span></div>
<div>L: <span id="currentLevel">40</span></div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="viewport-container prior-viewport">
<div class="viewport-header">
<h6>Prior Study - {{ prior_study.study_date|default:"Dec 10, 2023" }}</h6>
<div class="viewport-controls">
<button class="btn btn-sm btn-outline-light" onclick="resetPriorView()">
<i class="fa fa-home"></i>
</button>
<button class="btn btn-sm btn-outline-light" onclick="fitPriorToWindow()">
<i class="fa fa-expand-arrows-alt"></i>
</button>
</div>
</div>
<div class="viewport-content">
<canvas id="priorCanvas" width="600" height="500"></canvas>
<div class="viewport-overlay">
<div class="overlay-info top-left">
<div>{{ prior_study.patient_name|default:"Smith, John" }}</div>
<div>{{ prior_study.study_date|default:"2023-12-10" }}</div>
<div>Series: <span id="priorSeries">1</span></div>
</div>
<div class="overlay-info bottom-right">
<div>Image: <span id="priorImage">60</span>/115</div>
<div>W: <span id="priorWindow">400</span></div>
<div>L: <span id="priorLevel">40</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Overlay Layout -->
<div class="layout-overlay" id="overlayLayout" style="display: none;">
<div class="overlay-viewport">
<div class="viewport-header">
<h6>Overlay Comparison</h6>
<div class="overlay-controls">
<label class="form-label">Opacity:</label>
<input type="range" class="form-range" id="overlayOpacity" min="0" max="100" value="50" onchange="updateOverlayOpacity(this.value)">
<span id="opacityValue">50%</span>
</div>
</div>
<div class="viewport-content">
<canvas id="overlayCanvas" width="800" height="600"></canvas>
</div>
</div>
</div>
<!-- Flicker Layout -->
<div class="layout-flicker" id="flickerLayout" style="display: none;">
<div class="flicker-viewport">
<div class="viewport-header">
<h6>Flicker Comparison</h6>
<div class="flicker-controls">
<button class="btn btn-sm btn-outline-primary" id="flickerBtn" onclick="toggleFlicker()">
<i class="fa fa-play"></i> Start Flicker
</button>
<label class="form-label">Speed:</label>
<input type="range" class="form-range" id="flickerSpeed" min="100" max="2000" value="500" onchange="updateFlickerSpeed(this.value)">
</div>
</div>
<div class="viewport-content">
<canvas id="flickerCanvas" width="800" height="600"></canvas>
<div class="flicker-indicator">
<span id="flickerStatus">Current Study</span>
</div>
</div>
</div>
</div>
<!-- Quad View Layout -->
<div class="layout-quad" id="quadLayout" style="display: none;">
<div class="row g-1">
<div class="col-6">
<div class="quad-viewport">
<div class="quad-header">Current - Axial</div>
<canvas id="quadCanvas1" width="400" height="300"></canvas>
</div>
</div>
<div class="col-6">
<div class="quad-viewport">
<div class="quad-header">Prior - Axial</div>
<canvas id="quadCanvas2" width="400" height="300"></canvas>
</div>
</div>
<div class="col-6">
<div class="quad-viewport">
<div class="quad-header">Current - Coronal</div>
<canvas id="quadCanvas3" width="400" height="300"></canvas>
</div>
</div>
<div class="col-6">
<div class="quad-viewport">
<div class="quad-header">Prior - Coronal</div>
<canvas id="quadCanvas4" width="400" height="300"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Navigation and Tools -->
<div class="row">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h6 class="card-title">Navigation Controls</h6>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<h6>Current Study Navigation</h6>
<div class="navigation-controls">
<div class="btn-group mb-2">
<button class="btn btn-sm btn-outline-primary" onclick="currentFirstImage()">
<i class="fa fa-step-backward"></i>
</button>
<button class="btn btn-sm btn-outline-primary" onclick="currentPreviousImage()">
<i class="fa fa-backward"></i>
</button>
<button class="btn btn-sm btn-outline-primary" onclick="currentNextImage()">
<i class="fa fa-forward"></i>
</button>
<button class="btn btn-sm btn-outline-primary" onclick="currentLastImage()">
<i class="fa fa-step-forward"></i>
</button>
</div>
<input type="range" class="form-range" id="currentSlider" min="1" max="120" value="60" onchange="goToCurrentImage(this.value)">
<div class="text-center">
<small>Image <span id="currentImageNum">60</span> of 120</small>
</div>
</div>
</div>
<div class="col-md-6">
<h6>Prior Study Navigation</h6>
<div class="navigation-controls">
<div class="btn-group mb-2">
<button class="btn btn-sm btn-outline-success" onclick="priorFirstImage()">
<i class="fa fa-step-backward"></i>
</button>
<button class="btn btn-sm btn-outline-success" onclick="priorPreviousImage()">
<i class="fa fa-backward"></i>
</button>
<button class="btn btn-sm btn-outline-success" onclick="priorNextImage()">
<i class="fa fa-forward"></i>
</button>
<button class="btn btn-sm btn-outline-success" onclick="priorLastImage()">
<i class="fa fa-step-forward"></i>
</button>
</div>
<input type="range" class="form-range" id="priorSlider" min="1" max="115" value="60" onchange="goToPriorImage(this.value)">
<div class="text-center">
<small>Image <span id="priorImageNum">60</span> of 115</small>
</div>
</div>
</div>
</div>
<div class="row mt-3">
<div class="col-12">
<div class="sync-controls text-center">
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="syncScroll" checked onchange="toggleSyncScroll()">
<label class="form-check-label" for="syncScroll">Sync Scrolling</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="syncWindow" checked onchange="toggleSyncWindow()">
<label class="form-check-label" for="syncWindow">Sync Window/Level</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" id="syncZoom" checked onchange="toggleSyncZoom()">
<label class="form-check-label" for="syncZoom">Sync Zoom/Pan</label>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h6 class="card-title">Comparison Tools</h6>
</div>
<div class="card-body">
<div class="tool-group mb-3">
<h6>Measurements</h6>
<button class="btn btn-sm btn-outline-primary w-100 mb-2" onclick="addMeasurement()">
<i class="fa fa-ruler"></i> Add Measurement
</button>
<button class="btn btn-sm btn-outline-info w-100 mb-2" onclick="compareMeasurements()">
<i class="fa fa-chart-line"></i> Compare Measurements
</button>
</div>
<div class="tool-group mb-3">
<h6>Annotations</h6>
<button class="btn btn-sm btn-outline-warning w-100 mb-2" onclick="addAnnotation()">
<i class="fa fa-comment"></i> Add Annotation
</button>
<button class="btn btn-sm btn-outline-secondary w-100 mb-2" onclick="linkAnnotations()">
<i class="fa fa-link"></i> Link Annotations
</button>
</div>
<div class="tool-group">
<h6>Analysis</h6>
<button class="btn btn-sm btn-outline-success w-100 mb-2" onclick="calculateChanges()">
<i class="fa fa-calculator"></i> Calculate Changes
</button>
<button class="btn btn-sm btn-outline-info w-100" onclick="generateChangeMap()">
<i class="fa fa-map"></i> Generate Change Map
</button>
</div>
</div>
</div>
<!-- Findings Summary -->
<div class="card mt-3">
<div class="card-header">
<h6 class="card-title">Comparison Findings</h6>
</div>
<div class="card-body">
<div class="findings-list">
<div class="finding-item mb-2">
<div class="finding-header">
<span class="badge bg-warning">Changed</span>
<small class="text-muted">Nodule size</small>
</div>
<div class="finding-details">
<small>Previous: 8.2 mm → Current: 9.1 mm</small><br>
<small class="text-warning">+11% increase</small>
</div>
</div>
<div class="finding-item mb-2">
<div class="finding-header">
<span class="badge bg-success">Stable</span>
<small class="text-muted">Cardiac size</small>
</div>
<div class="finding-details">
<small>No significant change</small>
</div>
</div>
<div class="finding-item">
<div class="finding-header">
<span class="badge bg-info">New</span>
<small class="text-muted">Ground glass opacity</small>
</div>
<div class="finding-details">
<small>New finding in right lower lobe</small>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Comparison Report -->
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h5 class="card-title">Comparison Report</h5>
<div class="card-tools">
<button type="button" class="btn btn-sm btn-outline-primary" onclick="saveComparison()">
<i class="fa fa-save"></i> Save
</button>
<button type="button" class="btn btn-sm btn-outline-success" onclick="exportComparison()">
<i class="fa fa-download"></i> Export
</button>
</div>
</div>
<div class="card-body">
<textarea class="form-control" rows="6" placeholder="Enter comparison findings and analysis...">COMPARISON:
Current study ({{ current_study.study_date|default:"January 15, 2024" }}) compared to prior study ({{ prior_study.study_date|default:"December 10, 2023" }}).
INTERVAL CHANGES:
1. The previously identified 8.2 mm nodule in the right upper lobe has increased in size to 9.1 mm, representing an 11% increase.
2. New ground glass opacity in the right lower lobe, measuring approximately 15 mm.
3. Cardiac silhouette remains stable in size and configuration.
4. No new pleural effusions or pneumothorax.
IMPRESSION:
1. Interval growth of right upper lobe nodule - recommend follow-up in 3 months or consider tissue sampling.
2. New ground glass opacity in right lower lobe - clinical correlation recommended.</textarea>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
let currentLayout = 'side-by-side';
let syncScroll = true;
let syncWindow = true;
let syncZoom = true;
let flickerInterval;
let isFlickering = false;
let currentImageIndex = 60;
let priorImageIndex = 60;
document.addEventListener('DOMContentLoaded', function() {
initializeCanvases();
setupEventListeners();
});
function initializeCanvases() {
// Initialize all canvases with placeholder images
const canvases = ['currentCanvas', 'priorCanvas', 'overlayCanvas', 'flickerCanvas', 'quadCanvas1', 'quadCanvas2', 'quadCanvas3', 'quadCanvas4'];
canvases.forEach(canvasId => {
const canvas = document.getElementById(canvasId);
if (canvas) {
const ctx = canvas.getContext('2d');
drawPlaceholderImage(ctx, canvasId.includes('prior') || canvasId.includes('2') || canvasId.includes('4'));
}
});
}
function drawPlaceholderImage(ctx, isPrior = false) {
const canvas = ctx.canvas;
// Clear canvas
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw simulated medical image
ctx.fillStyle = isPrior ? '#2a2a2a' : '#333333';
ctx.fillRect(50, 50, canvas.width - 100, canvas.height - 100);
// Add some simulated anatomical structures
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;
// Main structure
ctx.fillStyle = isPrior ? '#555555' : '#666666';
ctx.beginPath();
ctx.arc(centerX, centerY, 60, 0, 2 * Math.PI);
ctx.fill();
// Smaller structures
ctx.fillStyle = isPrior ? '#777777' : '#999999';
ctx.beginPath();
ctx.arc(centerX - 30, centerY - 20, isPrior ? 15 : 20, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.arc(centerX + 25, centerY + 25, isPrior ? 12 : 18, 0, 2 * Math.PI);
ctx.fill();
// Add study identifier
ctx.fillStyle = '#00ff00';
ctx.font = '12px monospace';
ctx.fillText(isPrior ? 'PRIOR' : 'CURRENT', 10, 20);
}
function setupEventListeners() {
// Canvas mouse events for synchronized interaction
const currentCanvas = document.getElementById('currentCanvas');
const priorCanvas = document.getElementById('priorCanvas');
if (currentCanvas && priorCanvas) {
currentCanvas.addEventListener('wheel', (e) => handleCanvasWheel(e, 'current'));
priorCanvas.addEventListener('wheel', (e) => handleCanvasWheel(e, 'prior'));
}
}
function handleCanvasWheel(e, viewport) {
e.preventDefault();
if (viewport === 'current') {
if (e.deltaY > 0) {
currentNextImage();
} else {
currentPreviousImage();
}
} else {
if (syncScroll) {
if (e.deltaY > 0) {
priorNextImage();
} else {
priorPreviousImage();
}
}
}
}
function changeLayout(layout) {
// Hide all layouts
document.querySelectorAll('[class^="layout-"]').forEach(el => {
el.style.display = 'none';
});
// Show selected layout
document.getElementById(layout.replace('-', '') + 'Layout').style.display = 'block';
// Update active button
document.querySelectorAll('[data-layout]').forEach(btn => {
btn.classList.remove('active');
});
document.querySelector(`[data-layout="${layout}"]`).classList.add('active');
currentLayout = layout;
console.log(`Changed layout to: ${layout}`);
// Initialize layout-specific functionality
if (layout === 'overlay') {
updateOverlayView();
} else if (layout === 'flicker') {
updateFlickerView();
} else if (layout === 'quad') {
updateQuadView();
}
}
function updateOverlayView() {
const canvas = document.getElementById('overlayCanvas');
const ctx = canvas.getContext('2d');
// Draw overlay comparison
drawPlaceholderImage(ctx, false);
// Add overlay effect
ctx.globalAlpha = 0.5;
drawPlaceholderImage(ctx, true);
ctx.globalAlpha = 1.0;
}
function updateOverlayOpacity(value) {
document.getElementById('opacityValue').textContent = value + '%';
updateOverlayView();
console.log(`Overlay opacity set to: ${value}%`);
}
function updateFlickerView() {
const canvas = document.getElementById('flickerCanvas');
const ctx = canvas.getContext('2d');
drawPlaceholderImage(ctx, false);
}
function toggleFlicker() {
const flickerBtn = document.getElementById('flickerBtn');
if (isFlickering) {
clearInterval(flickerInterval);
flickerBtn.innerHTML = '<i class="fa fa-play"></i> Start Flicker';
isFlickering = false;
} else {
const speed = document.getElementById('flickerSpeed').value;
flickerInterval = setInterval(() => {
const canvas = document.getElementById('flickerCanvas');
const ctx = canvas.getContext('2d');
const status = document.getElementById('flickerStatus');
if (status.textContent === 'Current Study') {
drawPlaceholderImage(ctx, true);
status.textContent = 'Prior Study';
} else {
drawPlaceholderImage(ctx, false);
status.textContent = 'Current Study';
}
}, parseInt(speed));
flickerBtn.innerHTML = '<i class="fa fa-pause"></i> Stop Flicker';
isFlickering = true;
}
}
function updateFlickerSpeed(value) {
if (isFlickering) {
clearInterval(flickerInterval);
toggleFlicker(); // Restart with new speed
}
}
function updateQuadView() {
const canvases = ['quadCanvas1', 'quadCanvas2', 'quadCanvas3', 'quadCanvas4'];
canvases.forEach((canvasId, index) => {
const canvas = document.getElementById(canvasId);
const ctx = canvas.getContext('2d');
drawPlaceholderImage(ctx, index % 2 === 1);
});
}
// Navigation functions
function currentFirstImage() {
currentImageIndex = 1;
updateCurrentImage();
}
function currentPreviousImage() {
if (currentImageIndex > 1) {
currentImageIndex--;
updateCurrentImage();
if (syncScroll) priorPreviousImage();
}
}
function currentNextImage() {
if (currentImageIndex < 120) {
currentImageIndex++;
updateCurrentImage();
if (syncScroll) priorNextImage();
}
}
function currentLastImage() {
currentImageIndex = 120;
updateCurrentImage();
}
function priorFirstImage() {
priorImageIndex = 1;
updatePriorImage();
}
function priorPreviousImage() {
if (priorImageIndex > 1) {
priorImageIndex--;
updatePriorImage();
}
}
function priorNextImage() {
if (priorImageIndex < 115) {
priorImageIndex++;
updatePriorImage();
}
}
function priorLastImage() {
priorImageIndex = 115;
updatePriorImage();
}
function goToCurrentImage(imageNum) {
currentImageIndex = parseInt(imageNum);
updateCurrentImage();
if (syncScroll) {
priorImageIndex = Math.min(parseInt(imageNum), 115);
updatePriorImage();
}
}
function goToPriorImage(imageNum) {
priorImageIndex = parseInt(imageNum);
updatePriorImage();
}
function updateCurrentImage() {
document.getElementById('currentImageNum').textContent = currentImageIndex;
document.getElementById('currentSlider').value = currentImageIndex;
document.getElementById('currentImage').textContent = currentImageIndex;
// Redraw canvas with new image
const canvas = document.getElementById('currentCanvas');
const ctx = canvas.getContext('2d');
drawPlaceholderImage(ctx, false);
}
function updatePriorImage() {
document.getElementById('priorImageNum').textContent = priorImageIndex;
document.getElementById('priorSlider').value = priorImageIndex;
document.getElementById('priorImage').textContent = priorImageIndex;
// Redraw canvas with new image
const canvas = document.getElementById('priorCanvas');
const ctx = canvas.getContext('2d');
drawPlaceholderImage(ctx, true);
}
// Sync functions
function toggleSyncScroll() {
syncScroll = document.getElementById('syncScroll').checked;
console.log(`Sync scrolling: ${syncScroll}`);
}
function toggleSyncWindow() {
syncWindow = document.getElementById('syncWindow').checked;
console.log(`Sync window/level: ${syncWindow}`);
}
function toggleSyncZoom() {
syncZoom = document.getElementById('syncZoom').checked;
console.log(`Sync zoom/pan: ${syncZoom}`);
}
// Viewport control functions
function resetCurrentView() {
console.log('Reset current view');
updateCurrentImage();
}
function resetPriorView() {
console.log('Reset prior view');
updatePriorImage();
}
function fitCurrentToWindow() {
console.log('Fit current to window');
}
function fitPriorToWindow() {
console.log('Fit prior to window');
}
// Study management functions
function loadStudyForComparison() {
console.log('Loading study for comparison...');
alert('Study browser would open here to select a study for comparison.');
}
function selectPriorStudy() {
console.log('Selecting different prior study...');
alert('Prior study selection interface would open here.');
}
function swapStudies() {
console.log('Swapping current and prior studies...');
alert('Studies have been swapped. Current is now prior and vice versa.');
}
function resetComparison() {
if (confirm('Reset comparison? This will clear all annotations and measurements.')) {
console.log('Resetting comparison...');
alert('Comparison has been reset.');
}
}
function syncViewports() {
console.log('Synchronizing viewports...');
alert('Viewports synchronized. Both studies are now showing the same slice level and window/level settings.');
}
// Tool functions
function addMeasurement() {
console.log('Adding measurement...');
alert('Measurement tool activated. Click and drag on either image to create a measurement.');
}
function compareMeasurements() {
console.log('Comparing measurements...');
alert('Measurement comparison table would be displayed here.');
}
function addAnnotation() {
console.log('Adding annotation...');
alert('Annotation tool activated. Click on either image to add an annotation.');
}
function linkAnnotations() {
console.log('Linking annotations...');
alert('Select annotations on both studies to link them for comparison.');
}
function calculateChanges() {
console.log('Calculating changes...');
alert('Automated change detection is analyzing the studies. Results will be displayed shortly.');
}
function generateChangeMap() {
console.log('Generating change map...');
alert('Change map is being generated. This will highlight areas of difference between the studies.');
}
// Report functions
function generateComparisonReport() {
console.log('Generating comparison report...');
alert('Automated comparison report is being generated based on the findings and measurements.');
}
function saveComparison() {
console.log('Saving comparison...');
alert('Comparison session saved successfully.');
}
function exportComparison() {
const format = prompt('Export format:\n1. PDF Report\n2. DICOM with annotations\n3. Image snapshots\n\nEnter number:');
if (format && ['1', '2', '3'].includes(format)) {
const formats = {
'1': 'PDF Report',
'2': 'DICOM with annotations',
'3': 'Image snapshots'
};
console.log(`Exporting comparison as: ${formats[format]}`);
alert(`Comparison exported as ${formats[format]}.`);
}
}
</script>
<style>
.study-panel {
border: 2px solid #dee2e6;
border-radius: 8px;
padding: 1rem;
margin-bottom: 1rem;
}
.current-study {
border-color: #007bff;
background-color: #f8f9ff;
}
.prior-study {
border-color: #28a745;
background-color: #f8fff8;
}
.study-header {
display: flex;
justify-content: between;
align-items: center;
margin-bottom: 1rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid #dee2e6;
}
.study-info p {
margin-bottom: 0.25rem;
font-size: 0.9rem;
}
.time-interval-info {
background-color: #fff3cd;
border: 1px solid #ffeaa7;
border-radius: 6px;
padding: 1rem;
}
.interval-display {
font-size: 1.1rem;
}
.comparison-container {
min-height: 600px;
background-color: #000;
}
.viewport-container {
position: relative;
height: 500px;
border: 1px solid #333;
}
.viewport-header {
background-color: #333;
color: white;
padding: 0.5rem;
display: flex;
justify-content: between;
align-items: center;
}
.viewport-header h6 {
margin: 0;
font-size: 0.9rem;
}
.viewport-controls {
display: flex;
gap: 0.25rem;
}
.viewport-content {
position: relative;
height: calc(100% - 40px);
background-color: #000;
}
.viewport-content canvas {
width: 100%;
height: 100%;
object-fit: contain;
}
.viewport-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
pointer-events: none;
}
.overlay-info {
position: absolute;
color: #00ff00;
font-family: monospace;
font-size: 11px;
background-color: rgba(0, 0, 0, 0.7);
padding: 4px;
border-radius: 2px;
}
.overlay-info.top-left {
top: 8px;
left: 8px;
}
.overlay-info.bottom-right {
bottom: 8px;
right: 8px;
}
.overlay-info div {
margin-bottom: 2px;
}
.overlay-viewport, .flicker-viewport {
position: relative;
height: 600px;
background-color: #000;
}
.overlay-controls, .flicker-controls {
display: flex;
align-items: center;
gap: 1rem;
}
.flicker-indicator {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(0, 0, 0, 0.8);
color: white;
padding: 0.5rem 1rem;
border-radius: 4px;
font-weight: bold;
}
.quad-viewport {
position: relative;
height: 300px;
border: 1px solid #333;
background-color: #000;
}
.quad-header {
background-color: #333;
color: white;
padding: 0.25rem 0.5rem;
font-size: 0.8rem;
text-align: center;
}
.quad-viewport canvas {
width: 100%;
height: calc(100% - 28px);
object-fit: contain;
}
.navigation-controls {
text-align: center;
}
.sync-controls {
background-color: #f8f9fa;
padding: 1rem;
border-radius: 6px;
}
.tool-group {
border-bottom: 1px solid #dee2e6;
padding-bottom: 1rem;
margin-bottom: 1rem;
}
.tool-group:last-child {
border-bottom: none;
margin-bottom: 0;
}
.tool-group h6 {
font-size: 0.9rem;
font-weight: 600;
margin-bottom: 0.5rem;
color: #6c757d;
}
.finding-item {
border: 1px solid #dee2e6;
border-radius: 4px;
padding: 0.5rem;
background-color: #f8f9fa;
}
.finding-header {
display: flex;
justify-content: between;
align-items: center;
margin-bottom: 0.25rem;
}
.finding-details {
font-size: 0.85rem;
}
@media (max-width: 768px) {
.viewport-header {
flex-direction: column;
gap: 0.5rem;
}
.overlay-controls, .flicker-controls {
flex-direction: column;
gap: 0.5rem;
}
.sync-controls .form-check-inline {
display: block;
margin-bottom: 0.5rem;
}
.comparison-container {
min-height: 400px;
}
.viewport-container {
height: 400px;
}
}
</style>
{% endblock %}