Spaces:
Running
Running
manual box value fix
Browse files
comic_panel_extractor/static/annotator.html
CHANGED
|
@@ -453,6 +453,46 @@
|
|
| 453 |
height: calc(100vh - 372px);
|
| 454 |
}
|
| 455 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 456 |
</style>
|
| 457 |
</head>
|
| 458 |
|
|
@@ -554,8 +594,74 @@
|
|
| 554 |
<span class="info-value" id="selectedBoxInfo">None</span>
|
| 555 |
</div>
|
| 556 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 557 |
</div>
|
| 558 |
|
|
|
|
| 559 |
<!-- Quick Actions -->
|
| 560 |
<div class="sidebar-section">
|
| 561 |
<div class="section-title">Actions</div>
|
|
@@ -720,6 +826,26 @@
|
|
| 720 |
// Keyboard events
|
| 721 |
document.addEventListener('keydown', (e) => this.onKeyDown(e));
|
| 722 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 723 |
// Make canvas focusable for keyboard events
|
| 724 |
this.canvas.tabIndex = 0;
|
| 725 |
}
|
|
@@ -1835,6 +1961,11 @@
|
|
| 1835 |
this.drawCanvas();
|
| 1836 |
return;
|
| 1837 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1838 |
if (!this.currentImage || this.selectedBoxIndex < 0) return;
|
| 1839 |
|
| 1840 |
const resizeDistance = 5; // Fixed resize distance
|
|
@@ -1972,16 +2103,196 @@
|
|
| 1972 |
}
|
| 1973 |
}
|
| 1974 |
|
|
|
|
| 1975 |
updateSelectedBoxInfo() {
|
| 1976 |
const selectedBoxInfo = document.getElementById('selectedBoxInfo');
|
|
|
|
|
|
|
| 1977 |
if (this.selectedBoxIndex >= 0) {
|
| 1978 |
-
const
|
| 1979 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1980 |
} else {
|
| 1981 |
selectedBoxInfo.textContent = 'None';
|
|
|
|
| 1982 |
}
|
| 1983 |
}
|
| 1984 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1985 |
getMousePos(e) {
|
| 1986 |
const rect = this.canvas.getBoundingClientRect();
|
| 1987 |
const scaleX = this.canvas.width / rect.width;
|
|
|
|
| 453 |
height: calc(100vh - 372px);
|
| 454 |
}
|
| 455 |
}
|
| 456 |
+
|
| 457 |
+
.form-input-sm {
|
| 458 |
+
padding: 4px 6px;
|
| 459 |
+
font-size: 11px;
|
| 460 |
+
height: auto;
|
| 461 |
+
}
|
| 462 |
+
|
| 463 |
+
.point-edit-row {
|
| 464 |
+
display: flex;
|
| 465 |
+
align-items: center;
|
| 466 |
+
gap: 4px;
|
| 467 |
+
margin-bottom: 4px;
|
| 468 |
+
padding: 4px;
|
| 469 |
+
background: #f8fafc;
|
| 470 |
+
border-radius: 4px;
|
| 471 |
+
}
|
| 472 |
+
|
| 473 |
+
.point-edit-input {
|
| 474 |
+
flex: 1;
|
| 475 |
+
padding: 2px 4px;
|
| 476 |
+
font-size: 10px;
|
| 477 |
+
border: 1px solid #d1d5db;
|
| 478 |
+
border-radius: 3px;
|
| 479 |
+
width: 50px;
|
| 480 |
+
}
|
| 481 |
+
|
| 482 |
+
.point-delete-btn {
|
| 483 |
+
background: #f56565;
|
| 484 |
+
color: white;
|
| 485 |
+
border: none;
|
| 486 |
+
border-radius: 3px;
|
| 487 |
+
padding: 2px 6px;
|
| 488 |
+
font-size: 10px;
|
| 489 |
+
cursor: pointer;
|
| 490 |
+
min-width: 20px;
|
| 491 |
+
}
|
| 492 |
+
|
| 493 |
+
.point-delete-btn:hover {
|
| 494 |
+
background: #e53e3e;
|
| 495 |
+
}
|
| 496 |
</style>
|
| 497 |
</head>
|
| 498 |
|
|
|
|
| 594 |
<span class="info-value" id="selectedBoxInfo">None</span>
|
| 595 |
</div>
|
| 596 |
</div>
|
| 597 |
+
|
| 598 |
+
<!-- Enhanced Edit Panel for Selected Annotation -->
|
| 599 |
+
<div id="annotationEditPanel" style="display: none; margin-top: 16px;">
|
| 600 |
+
<div class="section-title">Edit Selected</div>
|
| 601 |
+
<div class="info-card">
|
| 602 |
+
<div class="form-field" style="margin-bottom: 12px;">
|
| 603 |
+
<label class="form-label">Type</label>
|
| 604 |
+
<span class="info-value" id="editType">-</span>
|
| 605 |
+
</div>
|
| 606 |
+
|
| 607 |
+
<div class="form-field" style="margin-bottom: 12px;">
|
| 608 |
+
<label class="form-label">Class ID</label>
|
| 609 |
+
<input type="number" class="form-input form-input-sm" id="editClassId" min="0" max="100"
|
| 610 |
+
style="padding: 6px 8px; font-size: 12px;">
|
| 611 |
+
</div>
|
| 612 |
+
|
| 613 |
+
<!-- Bbox-specific controls -->
|
| 614 |
+
<div id="bboxEditControls" style="display: none;">
|
| 615 |
+
<div class="form-field" style="margin-bottom: 8px;">
|
| 616 |
+
<label class="form-label">Position (X, Y)</label>
|
| 617 |
+
<div style="display: flex; gap: 8px;">
|
| 618 |
+
<input type="number" class="form-input form-input-sm" id="editLeft" min="0"
|
| 619 |
+
style="flex: 1; padding: 4px 6px; font-size: 11px;">
|
| 620 |
+
<input type="number" class="form-input form-input-sm" id="editTop" min="0"
|
| 621 |
+
style="flex: 1; padding: 4px 6px; font-size: 11px;">
|
| 622 |
+
</div>
|
| 623 |
+
</div>
|
| 624 |
+
<div class="form-field" style="margin-bottom: 12px;">
|
| 625 |
+
<label class="form-label">Size (W × H)</label>
|
| 626 |
+
<div style="display: flex; gap: 8px;">
|
| 627 |
+
<input type="number" class="form-input form-input-sm" id="editWidth" min="10"
|
| 628 |
+
style="flex: 1; padding: 4px 6px; font-size: 11px;">
|
| 629 |
+
<input type="number" class="form-input form-input-sm" id="editHeight" min="10"
|
| 630 |
+
style="flex: 1; padding: 4px 6px; font-size: 11px;">
|
| 631 |
+
</div>
|
| 632 |
+
</div>
|
| 633 |
+
</div>
|
| 634 |
+
|
| 635 |
+
<!-- Polygon-specific controls -->
|
| 636 |
+
<div id="polygonEditControls" style="display: none;">
|
| 637 |
+
<div class="form-field" style="margin-bottom: 8px;">
|
| 638 |
+
<label class="form-label">Points (<span id="pointCount">0</span>)</label>
|
| 639 |
+
<div id="pointsList" style="max-height: 120px; overflow-y: auto;
|
| 640 |
+
border: 1px solid #e2e8f0; border-radius: 4px; padding: 8px;">
|
| 641 |
+
<!-- Points will be populated here -->
|
| 642 |
+
</div>
|
| 643 |
+
</div>
|
| 644 |
+
</div>
|
| 645 |
+
|
| 646 |
+
<div style="display: flex; gap: 8px; margin-top: 12px;">
|
| 647 |
+
<button class="btn btn-success btn-sm" id="applyEditBtn"
|
| 648 |
+
style="flex: 1; padding: 6px 8px; font-size: 11px;">
|
| 649 |
+
✓ Apply
|
| 650 |
+
</button>
|
| 651 |
+
<button class="btn btn-secondary btn-sm" id="cancelEditBtn"
|
| 652 |
+
style="flex: 1; padding: 6px 8px; font-size: 11px;">
|
| 653 |
+
✗ Cancel
|
| 654 |
+
</button>
|
| 655 |
+
<button class="btn btn-danger btn-sm" id="deleteEditBtn"
|
| 656 |
+
style="padding: 6px 8px; font-size: 11px;">
|
| 657 |
+
🗑️
|
| 658 |
+
</button>
|
| 659 |
+
</div>
|
| 660 |
+
</div>
|
| 661 |
+
</div>
|
| 662 |
</div>
|
| 663 |
|
| 664 |
+
|
| 665 |
<!-- Quick Actions -->
|
| 666 |
<div class="sidebar-section">
|
| 667 |
<div class="section-title">Actions</div>
|
|
|
|
| 826 |
// Keyboard events
|
| 827 |
document.addEventListener('keydown', (e) => this.onKeyDown(e));
|
| 828 |
|
| 829 |
+
// Edit panel buttons
|
| 830 |
+
document.getElementById('applyEditBtn').addEventListener('click', () => this.applyEdits());
|
| 831 |
+
document.getElementById('cancelEditBtn').addEventListener('click', () => this.cancelEdits());
|
| 832 |
+
document.getElementById('deleteEditBtn').addEventListener('click', () => this.deleteSelectedBox());
|
| 833 |
+
|
| 834 |
+
// Real-time bbox updates
|
| 835 |
+
document.getElementById('editLeft').addEventListener('input', () => this.updateBboxFromInputs());
|
| 836 |
+
document.getElementById('editTop').addEventListener('input', () => this.updateBboxFromInputs());
|
| 837 |
+
document.getElementById('editWidth').addEventListener('input', () => this.updateBboxFromInputs());
|
| 838 |
+
document.getElementById('editHeight').addEventListener('input', () => this.updateBboxFromInputs());
|
| 839 |
+
|
| 840 |
+
// Class ID real-time update
|
| 841 |
+
document.getElementById('editClassId').addEventListener('input', (e) => {
|
| 842 |
+
if (this.selectedBoxIndex >= 0) {
|
| 843 |
+
this.annotations[this.selectedBoxIndex].classId = parseInt(e.target.value) || 0;
|
| 844 |
+
this.annotations[this.selectedBoxIndex].saved = false;
|
| 845 |
+
}
|
| 846 |
+
});
|
| 847 |
+
|
| 848 |
+
|
| 849 |
// Make canvas focusable for keyboard events
|
| 850 |
this.canvas.tabIndex = 0;
|
| 851 |
}
|
|
|
|
| 1961 |
this.drawCanvas();
|
| 1962 |
return;
|
| 1963 |
}
|
| 1964 |
+
if (e.key === 'Enter') {
|
| 1965 |
+
e.preventDefault();
|
| 1966 |
+
this.onDoubleClick()
|
| 1967 |
+
return;
|
| 1968 |
+
}
|
| 1969 |
if (!this.currentImage || this.selectedBoxIndex < 0) return;
|
| 1970 |
|
| 1971 |
const resizeDistance = 5; // Fixed resize distance
|
|
|
|
| 2103 |
}
|
| 2104 |
}
|
| 2105 |
|
| 2106 |
+
// Enhanced updateSelectedBoxInfo method
|
| 2107 |
updateSelectedBoxInfo() {
|
| 2108 |
const selectedBoxInfo = document.getElementById('selectedBoxInfo');
|
| 2109 |
+
const editPanel = document.getElementById('annotationEditPanel');
|
| 2110 |
+
|
| 2111 |
if (this.selectedBoxIndex >= 0) {
|
| 2112 |
+
const annotation = this.annotations[this.selectedBoxIndex];
|
| 2113 |
+
|
| 2114 |
+
if (annotation.type === 'segmentation') {
|
| 2115 |
+
const bounds = this.getPolygonBounds(annotation.points);
|
| 2116 |
+
const pointCount = annotation.points.length;
|
| 2117 |
+
selectedBoxInfo.textContent = `#${this.selectedBoxIndex + 1} Polygon (${pointCount} points, ${Math.round(bounds.left)}, ${Math.round(bounds.top)}, ${Math.round(bounds.width)}×${Math.round(bounds.height)})`;
|
| 2118 |
+
} else {
|
| 2119 |
+
selectedBoxInfo.textContent = `#${this.selectedBoxIndex + 1} BBox (${Math.round(annotation.left)}, ${Math.round(annotation.top)}, ${Math.round(annotation.width)}×${Math.round(annotation.height)})`;
|
| 2120 |
+
}
|
| 2121 |
+
|
| 2122 |
+
// Show and populate edit panel
|
| 2123 |
+
this.showEditPanel(annotation);
|
| 2124 |
+
editPanel.style.display = 'block';
|
| 2125 |
} else {
|
| 2126 |
selectedBoxInfo.textContent = 'None';
|
| 2127 |
+
editPanel.style.display = 'none';
|
| 2128 |
}
|
| 2129 |
}
|
| 2130 |
|
| 2131 |
+
// New method to show edit panel
|
| 2132 |
+
showEditPanel(annotation) {
|
| 2133 |
+
const editType = document.getElementById('editType');
|
| 2134 |
+
const editClassId = document.getElementById('editClassId');
|
| 2135 |
+
const bboxControls = document.getElementById('bboxEditControls');
|
| 2136 |
+
const polygonControls = document.getElementById('polygonEditControls');
|
| 2137 |
+
|
| 2138 |
+
// Set common fields
|
| 2139 |
+
editType.textContent = annotation.type === 'segmentation' ? 'Polygon' : 'Bounding Box';
|
| 2140 |
+
editClassId.value = annotation.classId || 0;
|
| 2141 |
+
|
| 2142 |
+
if (annotation.type === 'bbox') {
|
| 2143 |
+
// Show bbox controls
|
| 2144 |
+
bboxControls.style.display = 'block';
|
| 2145 |
+
polygonControls.style.display = 'none';
|
| 2146 |
+
|
| 2147 |
+
document.getElementById('editLeft').value = Math.round(annotation.left);
|
| 2148 |
+
document.getElementById('editTop').value = Math.round(annotation.top);
|
| 2149 |
+
document.getElementById('editWidth').value = Math.round(annotation.width);
|
| 2150 |
+
document.getElementById('editHeight').value = Math.round(annotation.height);
|
| 2151 |
+
|
| 2152 |
+
// Set max values based on current position
|
| 2153 |
+
document.getElementById('editLeft').max = this.originalWidth - annotation.width;
|
| 2154 |
+
document.getElementById('editTop').max = this.originalHeight - annotation.height;
|
| 2155 |
+
document.getElementById('editWidth').max = this.originalWidth - annotation.left;
|
| 2156 |
+
document.getElementById('editHeight').max = this.originalHeight - annotation.top;
|
| 2157 |
+
} else {
|
| 2158 |
+
// Show polygon controls
|
| 2159 |
+
bboxControls.style.display = 'none';
|
| 2160 |
+
polygonControls.style.display = 'block';
|
| 2161 |
+
|
| 2162 |
+
this.populatePolygonPointsList(annotation.points);
|
| 2163 |
+
}
|
| 2164 |
+
}
|
| 2165 |
+
|
| 2166 |
+
// New method to populate polygon points list
|
| 2167 |
+
populatePolygonPointsList(points) {
|
| 2168 |
+
const pointsList = document.getElementById('pointsList');
|
| 2169 |
+
const pointCount = document.getElementById('pointCount');
|
| 2170 |
+
|
| 2171 |
+
pointCount.textContent = points.length;
|
| 2172 |
+
pointsList.innerHTML = '';
|
| 2173 |
+
|
| 2174 |
+
points.forEach((point, index) => {
|
| 2175 |
+
const row = document.createElement('div');
|
| 2176 |
+
row.className = 'point-edit-row';
|
| 2177 |
+
row.innerHTML = `
|
| 2178 |
+
<span style="font-size: 10px; color: #4a5568; min-width: 15px;">${index + 1}:</span>
|
| 2179 |
+
<input type="number" class="point-edit-input" value="${Math.round(point.x)}"
|
| 2180 |
+
data-index="${index}" data-coord="x" min="0" max="${this.originalWidth}">
|
| 2181 |
+
<input type="number" class="point-edit-input" value="${Math.round(point.y)}"
|
| 2182 |
+
data-index="${index}" data-coord="y" min="0" max="${this.originalHeight}">
|
| 2183 |
+
<button class="point-delete-btn" data-index="${index}"
|
| 2184 |
+
${points.length <= 3 ? 'disabled title="Cannot delete - minimum 3 points required"' : ''}>
|
| 2185 |
+
×
|
| 2186 |
+
</button>
|
| 2187 |
+
`;
|
| 2188 |
+
pointsList.appendChild(row);
|
| 2189 |
+
});
|
| 2190 |
+
|
| 2191 |
+
// Add event listeners for point inputs
|
| 2192 |
+
pointsList.querySelectorAll('.point-edit-input').forEach(input => {
|
| 2193 |
+
input.addEventListener('change', (e) => this.updatePolygonPoint(e));
|
| 2194 |
+
});
|
| 2195 |
+
|
| 2196 |
+
// Add event listeners for delete buttons
|
| 2197 |
+
pointsList.querySelectorAll('.point-delete-btn').forEach(btn => {
|
| 2198 |
+
btn.addEventListener('click', (e) => this.deletePolygonPoint(e));
|
| 2199 |
+
});
|
| 2200 |
+
}
|
| 2201 |
+
|
| 2202 |
+
// New method to update polygon point
|
| 2203 |
+
updatePolygonPoint(e) {
|
| 2204 |
+
const index = parseInt(e.target.dataset.index);
|
| 2205 |
+
const coord = e.target.dataset.coord;
|
| 2206 |
+
const value = parseInt(e.target.value);
|
| 2207 |
+
|
| 2208 |
+
if (this.selectedBoxIndex >= 0) {
|
| 2209 |
+
const annotation = this.annotations[this.selectedBoxIndex];
|
| 2210 |
+
if (annotation.type === 'segmentation' && annotation.points[index]) {
|
| 2211 |
+
annotation.points[index][coord] = Math.max(0,
|
| 2212 |
+
Math.min(coord === 'x' ? this.originalWidth : this.originalHeight, value));
|
| 2213 |
+
annotation.saved = false;
|
| 2214 |
+
this.drawCanvas();
|
| 2215 |
+
}
|
| 2216 |
+
}
|
| 2217 |
+
}
|
| 2218 |
+
|
| 2219 |
+
// New method to delete polygon point
|
| 2220 |
+
deletePolygonPoint(e) {
|
| 2221 |
+
const index = parseInt(e.target.dataset.index);
|
| 2222 |
+
|
| 2223 |
+
if (this.selectedBoxIndex >= 0) {
|
| 2224 |
+
const annotation = this.annotations[this.selectedBoxIndex];
|
| 2225 |
+
if (annotation.type === 'segmentation' && annotation.points.length > 3) {
|
| 2226 |
+
annotation.points.splice(index, 1);
|
| 2227 |
+
annotation.saved = false;
|
| 2228 |
+
this.populatePolygonPointsList(annotation.points);
|
| 2229 |
+
this.updateSelectedBoxInfo();
|
| 2230 |
+
this.drawCanvas();
|
| 2231 |
+
}
|
| 2232 |
+
}
|
| 2233 |
+
}
|
| 2234 |
+
|
| 2235 |
+
// Method to apply edits
|
| 2236 |
+
applyEdits() {
|
| 2237 |
+
if (this.selectedBoxIndex >= 0) {
|
| 2238 |
+
const annotation = this.annotations[this.selectedBoxIndex];
|
| 2239 |
+
const newClassId = parseInt(document.getElementById('editClassId').value) || 0;
|
| 2240 |
+
|
| 2241 |
+
// Update class ID
|
| 2242 |
+
annotation.classId = newClassId;
|
| 2243 |
+
|
| 2244 |
+
if (annotation.type === 'bbox') {
|
| 2245 |
+
// Update bbox properties
|
| 2246 |
+
const newLeft = parseInt(document.getElementById('editLeft').value);
|
| 2247 |
+
const newTop = parseInt(document.getElementById('editTop').value);
|
| 2248 |
+
const newWidth = parseInt(document.getElementById('editWidth').value);
|
| 2249 |
+
const newHeight = parseInt(document.getElementById('editHeight').value);
|
| 2250 |
+
|
| 2251 |
+
// Apply boundary constraints
|
| 2252 |
+
annotation.left = Math.max(0, Math.min(this.originalWidth - newWidth, newLeft));
|
| 2253 |
+
annotation.top = Math.max(0, Math.min(this.originalHeight - newHeight, newTop));
|
| 2254 |
+
annotation.width = Math.max(10, Math.min(this.originalWidth - annotation.left, newWidth));
|
| 2255 |
+
annotation.height = Math.max(10, Math.min(this.originalHeight - annotation.top, newHeight));
|
| 2256 |
+
}
|
| 2257 |
+
|
| 2258 |
+
annotation.saved = false;
|
| 2259 |
+
this.updateSelectedBoxInfo();
|
| 2260 |
+
this.drawCanvas();
|
| 2261 |
+
this.showAlert('Annotation updated', 'success');
|
| 2262 |
+
}
|
| 2263 |
+
}
|
| 2264 |
+
|
| 2265 |
+
// Method to cancel edits
|
| 2266 |
+
cancelEdits() {
|
| 2267 |
+
// Just refresh the edit panel with current values
|
| 2268 |
+
if (this.selectedBoxIndex >= 0) {
|
| 2269 |
+
this.showEditPanel(this.annotations[this.selectedBoxIndex]);
|
| 2270 |
+
}
|
| 2271 |
+
}
|
| 2272 |
+
// Method for real-time bbox updates
|
| 2273 |
+
updateBboxFromInputs() {
|
| 2274 |
+
if (this.selectedBoxIndex >= 0) {
|
| 2275 |
+
const annotation = this.annotations[this.selectedBoxIndex];
|
| 2276 |
+
if (annotation.type === 'bbox') {
|
| 2277 |
+
const newLeft = parseInt(document.getElementById('editLeft').value) || 0;
|
| 2278 |
+
const newTop = parseInt(document.getElementById('editTop').value) || 0;
|
| 2279 |
+
const newWidth = parseInt(document.getElementById('editWidth').value) || 10;
|
| 2280 |
+
const newHeight = parseInt(document.getElementById('editHeight').value) || 10;
|
| 2281 |
+
|
| 2282 |
+
// Apply constraints and update
|
| 2283 |
+
annotation.left = Math.max(0, Math.min(this.originalWidth - newWidth, newLeft));
|
| 2284 |
+
annotation.top = Math.max(0, Math.min(this.originalHeight - newHeight, newTop));
|
| 2285 |
+
annotation.width = Math.max(10, Math.min(this.originalWidth - annotation.left, newWidth));
|
| 2286 |
+
annotation.height = Math.max(10, Math.min(this.originalHeight - annotation.top, newHeight));
|
| 2287 |
+
|
| 2288 |
+
annotation.saved = false;
|
| 2289 |
+
this.drawCanvas();
|
| 2290 |
+
}
|
| 2291 |
+
}
|
| 2292 |
+
}
|
| 2293 |
+
|
| 2294 |
+
|
| 2295 |
+
|
| 2296 |
getMousePos(e) {
|
| 2297 |
const rect = this.canvas.getBoundingClientRect();
|
| 2298 |
const scaleX = this.canvas.width / rect.width;
|