1{ 2 class CropBox { 3 constructor(id, netObjectReference) { 4 this.id = id; 5 this.netObject = netObjectReference; 6 const container = document.getElementById(id); 7 this.container = container; // OpenSeadragon container 8 9 this.startX = 0; 10 this.startY = 0; 11 12 this.initialize_overlay(); 13 } 14 15 initialize_overlay() { 16 const overlay = document.createElement('canvas'); 17 overlay.classList.add('cropbox-overlay'); 18 overlay.style.position = 'absolute'; 19 overlay.style.top = '0'; 20 overlay.style.left = '0'; 21 overlay.style.width = '100%'; 22 overlay.style.height = '100%'; 23 overlay.style.cursor = 'crosshair'; 24 overlay.style.pointerEvents = 'auto'; 25 26 overlay.addEventListener('pointerdown', pointer_down); 27 overlay.addEventListener('pointermove', pointer_move); 28 overlay.addEventListener('pointerup', pointer_up); 29 overlay.addEventListener('pointercancel', cancel_cropbox); 30 31 this.container.appendChild(overlay); 32 requestAnimationFrame(() => { 33 overlay.classList.add('visible'); 34 }); 35 36 const rect = this.container.getBoundingClientRect(); 37 overlay.width = rect.width; 38 overlay.height = rect.height; 39 40 this.overlay = overlay; 41 this.context = overlay.getContext('2d'); 42 43 // Draw styling 44 this.context.fillStyle = 'rgba(0, 0, 0, 0.4)'; 45 this.context.strokeStyle = 'rgba(215, 215, 215, 0.5)'; 46 47 // Fill overlay 48 this.context.fillRect(0, 0, overlay.width, overlay.height); 49 } 50 51 remove_overlay() { 52 if (this.overlay) { 53 this.overlay.removeEventListener('pointerdown', pointer_down); 54 this.overlay.removeEventListener('pointermove', pointer_move); 55 this.overlay.removeEventListener('pointerup', pointer_up); 56 this.overlay.removeEventListener('pointercancel', cancel_cropbox); 57 58 this.overlay.classList.remove('visible'); 59 60 setTimeout(() => { 61 this.container.removeChild(this.overlay); 62 this.overlay = null; 63 this.isDragging = false; 64 }, 250); 65 } 66 } 67 68 69 pointer_down(x, y) { 70 if (this.overlay) { 71 const rect = this.container.getBoundingClientRect(); 72 this.startX = x - rect.left; 73 this.startY = y - rect.top; 74 75 this.isDragging = true; 76 } 77 } 78 79 pointer_move(x, y) { 80 if (this.isDragging) { 81 const rect = this.overlay.getBoundingClientRect(); 82 const currentX = x - rect.left; 83 const currentY = y - rect.top; 84 85 this.boxX = Math.min(this.startX, currentX); 86 this.boxY = Math.min(this.startY, currentY); 87 this.boxWidth = Math.abs(currentX - this.startX); 88 this.boxHeight = Math.abs(currentY - this.startY); 89 90 this.context.clearRect(0, 0, rect.width, rect.height); 91 this.context.fillRect(0, 0, rect.width, rect.height); 92 93 this.context.clearRect(this.boxX, this.boxY, this.boxWidth, this.boxHeight); 94 this.context.strokeRect(this.boxX, this.boxY, this.boxWidth, this.boxHeight); 95 } 96 } 97 98 pointer_up() { 99 if (this.isDragging) { 100 this.isDragging = false; 101 102 const viewer = OpenSeadragon.getViewer(this.id); 103 if (viewer) { 104 const endX = this.boxX + this.boxWidth; 105 const endY = this.boxY + this.boxHeight; 106 107 // Directly use client coordinates and convert via OSD 108 const start = viewer.viewport.pointFromPixel(new OpenSeadragon.Point(this.boxX, this.boxY)); 109 const end = viewer.viewport.pointFromPixel(new OpenSeadragon.Point(endX, endY)); 110 111 const imageStart = viewer.viewport.viewportToImageCoordinates(start); 112 const imageEnd = viewer.viewport.viewportToImageCoordinates(end); 113 114 const imageX = Math.min(imageStart.x, imageEnd.x); 115 const imageY = Math.min(imageStart.y, imageEnd.y); 116 const imageW = Math.abs(imageEnd.x - imageStart.x); 117 const imageH = Math.abs(imageEnd.y - imageStart.y); 118 119 const tiledImage = viewer.world.getItemAt(0);
120 const imageSize = tiledImage.getContentSize(); 121 122 const clamp = (v) => Math.max(0, Math.min(100, v)); 123 124 const leftPercent = clamp(Math.round((imageX / imageSize.x) * 100)); 125 const topPercent = clamp(Math.round((imageY / imageSize.y) * 100)); 126 const widthPercent = clamp(Math.round((imageW / imageSize.x) * 100)); 127 const heightPercent = clamp(Math.round((imageH / imageSize.y) * 100)); 128 129 this.remove_overlay(); 130 131 if (this.netObject && widthPercent > 0 && heightPercent > 0) { 132 this.netObject.invokeMethodAsync( 133 'FinishCrop', 134 leftPercent, 135 topPercent, 136 widthPercent, 137 heightPercent 138 ); 139 } 140 } 141 } 142 } 143 } 144 145 window.InitializeCropBox = function (obj_ref, id) { 146 cancel_cropbox(); 147 148 cropbox = new CropBox(id, obj_ref); 149 cropbox.container.addEventListener('keydown', key_down); 150 window.addEventListener('pointerdown', cancel_cropbox); 151 } 152 153 function cancel_cropbox() { 154 if (cropbox) { 155 cropbox.remove_overlay(); 156 cropbox.container.removeEventListener('keydown', key_down); 157 158 window.removeEventListener('pointerdown', cancel_cropbox); 159 cropbox = null; 160 } 161 } 162 163 function pointer_down(event) { 164 event.stopPropagation(); 165 166 if (event.pointerType === 'touch' || event.pointerType === 'mouse' || event.pointerType === 'pen') { 167 cropbox.overlay.setPointerCapture(event.pointerId); 168 cropbox.pointer_down(event.clientX, event.clientY); 169 } 170 } 171 172 function pointer_move(event) { 173 if (!cropbox || !cropbox.isDragging) { 174 return; 175 } 176 177 event.stopPropagation(); 178 cropbox.pointer_move(event.clientX, event.clientY); 179 } 180 181 function pointer_up(event) { 182 if (!cropbox) { 183 return; 184 } 185 186 event.stopPropagation(); 187 188 if (cropbox.overlay) { 189 try { 190 cropbox.overlay.releasePointerCapture(event.pointerId); 191 } 192 catch { /* ignore if not captured */ } 193 } 194 cropbox.pointer_up(); 195 } 196 197 function key_down(event) { 198 if (event.key === "Escape") { 199 cancel_cropbox(); 200 } 201 } 202 203 var cropbox; 204}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.