1var __defProp = Object.defineProperty; 2var __name = (target, value) => __defProp(target, "name", { value, configurable: !0 }); 3import { u as uuidv4 } from "../chunks/chunk.dcf-utility.js?v=6.1.6"; 4import { D as DCFCollapsibleFieldsets, U as UNLCollapsibleFieldset } from "../chunks/chunk.unl-collapsible-fieldset.js?v=6.1.6"; 5class DCFImageCropper { 6 static { 7 __name(this, "DCFImageCropper"); 8 } 9 uuid = uuidv4(); 10 cropperElement = null; 11 cropperCanvas = null; 12 cropperCanvasContext = null; 13 imageSource = null; 14 imageToBeCropped = null; 15 statusElement = null; 16 guideFieldsetElement = null; 17 gridGuidesCheckbox = null; 18 gridGuides = !1; 19 centerGuidesCheckbox = null; 20 centerGuides = !1; 21 cropperScaleRange = null; 22 croppedX = -1; 23 croppedY = -1; 24 croppedScale = 100; 25 minCroppedScale = 25; 26 cropperMaxWidth = -1; 27 croppedRatio = 1; 28 canvasSize = 300; 29 croppedImageOutputWidth = 1e3; 30 imagePreviews = []; 31 mouseState = { 32 down: !1, 33 moved: !1, 34 downX: -1, 35 croppedX: -1, 36 downY: -1, 37 croppedY: -1 38 }; 39 constructor(imageCropper, options = {}) { 40 if (this.cropperElement = imageCropper, (this.cropperElement.getAttribute("id") === "" || this.cropperElement.getAttribute("id") === null) && this.cropperElement.setAttribute("id", this.uuid.concat("-image-cropper-container")), this.imageSource = document.getElementById(this.cropperElement.dataset.imageCropperInput), this.imageSource === null) 41 throw new Error("Missing image cropper file input"); 42 switch (this.canvasSize = parseInt(this.cropperElement.dataset.maxCanvasWidth, 10), (this.canvasSize <= 20 || isNaN(this.canvasSize)) && (this.canvasSize = 300), this.croppedImageOutputWidth = parseInt(this.cropperElement.dataset.croppedImageOutputWidth, 10), (this.croppedImageOutputWidth <= 20 || isNaN(this.croppedImageOutputWidth)) && (this.croppedImageOutputWidth = 1e3), this.cropperElement.dataset.ratio) { 43 case "1x1": 44 this.croppedRatio = 1; 45 break; 46 case "16x9": 47 this.croppedRatio = 16 / 9; 48 break; 49 case "9x16": 50 this.croppedRatio = 9 / 16; 51 break; 52 case "3x4": 53 this.croppedRatio = 3 / 4; 54 break; 55 case "4x3": 56 this.croppedRatio = 4 / 3; 57 break; 58 default: 59 this.croppedRatio = 1; 60 } 61 this.#setInnerHTMLCropper(), this.statusElement = document.getElementById(this.uuid.concat("-image-cropper-status")), this.imagePreviews = document.querySelectorAll(`.dcf-image-cropper-preview[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`), this.#setInnerHTMLPreviews(), this.cropperCanvas = document.getElementById(this.uuid.concat("-image-cropper-canvas")), this.cropperCanvasContext = this.cropperCanvas.getContext("2d"), this.cropperScaleRange = document.getElementById(this.uuid.concat("-image-cropper-scale")), this.guideFieldsetElement = document.getElementById(this.uuid.concat("-image-cropper-guides")), this.#setUpEventListeners(), options.collapsibleFieldset === void 0 ? new DCFCollapsibleFieldsets(this.guideFieldsetElement, options) : new options.collapsibleFieldset(this.guideFieldsetElement, options), this.#changeState(), this.cropperElement.classList.add("dcf-image-cropper-initialized"), this.cropperElement.removeAttribute("hidden"), this.imagePreviews.forEach((previewElement) => { 62 previewElement.removeAttribute("hidden"); 63 }), this.cropperElement.dispatchEvent(new CustomEvent(DCFImageCropper.events("imageCropperReady"), { 64 detail: { 65 classInstance: this 66 } 67 })); 68 } 69 // The names of the events to be used easily 70 static events(name) { 71 const events = { 72 imageCropperReady: "imageCropperReady" 73 }; 74 return Object.freeze(events), name in events ? events[name] : void 0; 75 } 76 /** 77 * Sets the inner HTML to the cropped element 78 * @returns { Void } 79 */ 80 #setInnerHTMLCropper() { 81 this.cropperElement.innerHTML = ` 82<div class="dcf-image-cropper-no-image"> 83 <p>No image selected</p> 84</div> 85<section 86 class="dcf-image-cropper-yes-image dcf-d-none" 87 aria-labelledby="${this.uuid.concat("-image-cropper-title")}" 88> 89 <p id="${this.uuid.concat("-image-cropper-title")}" class="dcf-sr-only">Image Cropper Tool</p> 90 <div class="dcf-d-flex dcf-flex-row-rev dcf-flex-wrap dcf-jc-center dcf-ai-center dcf-gap-3 dcf-mb-3"> 91 <div class="dcf-d-flex dcf-flex-col dcf-jc-center dcf-ai-center dcf-mb-3"> 92 <p>Preview</p> 93 <div 94 class="dcf-image-cropper-preview" 95 data-image-cropper-input="${this.cropperElement.dataset.imageCropperIn
95put}" 96 data-max-canvas-width="${this.canvasSize / 3}" 97 hidden 98 ></div> 99 </div> 100 <canvas 101 id="${this.uuid.concat("-image-cropper-canvas")}" 102 class="dcf-b-grey dcf-b-2 dcf-b-solid" 103 height="225" 104 width="300" 105 tabindex="0" 106 aria-label="Image Crop Area Display" 107 role="img" 108 aria-describedby="${this.uuid.concat("-image-cropper-instructions")}" 109 ></canvas> 110 </div> 111 <div id="${this.uuid.concat("-image-cropper-status")}" role="status" aria-live="polite" class="dcf-sr-only"></div> 112 113 <div class="dcf-input-group dcf-col-gap-vw dcf-mb-3"> 114 <label for="${this.uuid.concat("-image-cropper-scale")}">Selection size: </label> 115 <input 116 id="${this.uuid.concat("-image-cropper-scale")}" 117 type="range" min="${this.minCroppedScale}" 118 max="100" 119 value="100" 120 aria-controls="${this.uuid.concat("-image-cropper-canvas")}"> 121 </div> 122 123 <fieldset class="dcf-collapsible-fieldset" data-start-expanded="false" id="${this.uuid.concat("-image-cropper-guides")}"> 124 <legend>Guides</legend> 125 <div class="dcf-d-flex dcf-flex-row dcf-gap-3"> 126 <div class="dcf-input-checkbox"> 127 <input 128 id="${this.uuid.concat("-image-cropper-grid-guides")}" 129 type="checkbox" 130 aria-controls="${this.uuid.concat("-image-cropper-canvas")}" 131 > 132 <label for="${this.uuid.concat("-image-cropper-grid-guides")}">Grid guides </label> 133 </div> 134 <div class="dcf-input-checkbox"> 135 <input 136 id="${this.uuid.concat("-image-cropper-center-guides")}" 137 type="checkbox" 138 aria-controls="${this.uuid.concat("-image-cropper-canvas")}" 139 > 140 <label for="${this.uuid.concat("-image-cropper-center-guides")}">Center guides </label> 141 </div> 142 </div> 143 </fieldset> 144 145 <p id="${this.uuid.concat("-image-cropper-instructions")}" class="dcf-txt-sm dcf-mt-3"> 146 To select a portion of your image, click and drag the cropped area to position 147 it, or use the arrow keys for precise adjustments. Modify the size of the cropped area 148 using the slider or fine-tune with the plus and minus buttons for a personalized fit. 149 Toggle on the guides to help align your cropped area perfectly. 150 </p> 151</section>`; 152 } 153 /** 154 * Sets the inner HTML for all the preview elements 155 * @returns { Void } 156 */ 157 #setInnerHTMLPreviews() { 158 this.imagePreviews.forEach((previewElement, index) => { 159 previewElement.innerHTML = ` 160<div class="dcf-image-cropper-yes-image dcf-d-none"> 161 <canvas 162 id="${this.uuid.concat(`-image-cropper-preview-canvas-${index}`)}" 163 class="dcf-b-grey dcf-b-2 dcf-b-solid" 164 height="225" 165 width="300" 166 aria-label="Cropped Image Preview" 167 role="img"></canvas> 168</div> 169`; 170 }); 171 } 172 /** 173 * Sets up event listeners for the various interactive elements 174 * @returns { Void } 175 */ 176 #setUpEventListeners() { 177 this.imageSource.addEventListener("change", this.#changeState.bind(this)), this.cropperScaleRange.addEventListener("input", () => { 178 this.updateScale(); 179 }), this.guideFieldsetElement.addEventListener("collapsibleFieldsetReady", () => { 180 this.gridGuidesCheckbox = document.getElementById(this.uuid.concat("-image-cropper-grid-guides")), this.gridGuidesCheckbox.addEventListener("change", () => { 181 this.gridGuides = this.gridGuidesCheckbox.checked, this.#draw(); 182 }), this.centerGuidesCheckbox = document.getElementById(this.uuid.concat("-image-cropper-center-guides")), this.centerGuidesCheckbox.addEventListener("change", () => { 183 this.centerGuides = this.centerGuidesCheckbox.checked, this.#draw(); 184 }); 185 }), this.cropperCanvas.addEventListener("mousedown", (event) => { 186 event.preventDefault(), this.mouseState.down = !0, this.mouseState.moved = !1, this.mouseState.downX = event.clientX, this.mouseState.croppedX = this.croppedX, this.mouseState.downY = event.clientY, this.mouseState.croppedY = this.croppedY; 187 }), this.cropperCanvas.addEventListener("mousemove", (event) => { 188 if (!this.mouseState.down) 189 return; 190 event.preventDefault(), this.mouseState.moved = !0; 191 const deltaX = event.clientX - this.mouseState.downX, deltaY = event.clientY - this.mouseState.downY; 192 this.croppedX = this.mouseState.croppedX + deltaX, this.croppedY = this.mouseState.croppedY + deltaY, this.#checkIfBoxIsInBounds(), this.#draw(), this.#syncInputs(), this.mouseState.downX = event.clientX, this.mouseState.croppedX = this.croppedX, this.mouseState.downY = event.clientY, this.mouseState.croppedY = this.croppedY; 193 }), this.cropperCanvas.addEventListener("mouseup", (event) => { 194 if (this.mouseState.down) { 195 if (event.preventDefault(), !this.mouseState.moved) { 196 const boundingRect = this.cropperCanvas.getBoundingClientRect(); 197 this.croppedX = this.mouseState.downX - boundingRect.x, this.croppedY = this.mouseState.downY - boundingRect.y, this.#checkIfBoxIsInBounds(), this.#draw(), this.#syncInputs(); 198 } 199 this.mouseState.down = !1, this.mouseState.moved = !1, this.mouseState.downX = -1, this.mouseState.croppedX = -1, this.mouseState.downY = -1, this.mouseState.croppedY = -1; 200 } 201 }), this.cropperCanvas.addEventListener("mouseleave", () => { 202 this.mouseState.down && (this.mouseState.down = !1, this.mouseState.moved = !1, this.mouseState.downX = -1, this.mouseState.croppedX = -1, this.mouseState.downY = -1, this.mouseState.croppedY = -1); 203 }), this.cropperElement.addEventListener("keydown", (event) => { 204 switch (event.key) { 205 case "ArrowRight": 206 this.moveRight(), event.preventDefault(); 207 break; 208 case "ArrowLeft": 209 this.moveLeft(), event.preventDefault(); 210 break; 211 case "ArrowDown": 212 this.moveDown(), event.preventDefault(); 213 break; 214 case "ArrowUp": 215 this.moveUp(), event.preventDefault(); 216 break; 217 case "+": 218 case "=": 219 this.grow(), event.preventDefault(); 220 break; 221 case "-": 222 case "_": 223 this.shrink(), event.preventDefault(); 224 break; 225 } 226 }); 227 } 228 /** 229 * When the image source changes this will update the component's state 230 * @returns { Void } 231 */ 232 async #changeState() { 233 if (this.imageSource.value === "") { 234 this.cropperElement.querySelector(".dcf-image-cropper-yes-image").classList.add("dcf-d-none"), this.cropperElement.querySelector(".dcf-image-cropper-no-image").classList.remove("dcf-d-none"), this.imagePreviews.forEach((previewElement) => { 235 previewElement.querySelector(".dcf-image-cropper-yes-image").classList.add("dcf-d-none"); 236 }), this.#clearInputs(); 237 return; 238 } 239 this.imageToBeCropped = await this.#getSrcImage(), this.#setUpCanvas(), this.croppedX = 0, this.croppedY = 0, this.croppedScale = 100, this.#draw(), this.cropperElement.querySelector(".dcf-image-cropper-yes-image").classList.remove("dcf-d-none"), this.cropperElement.querySelector(".dcf-image-cropper-no-image").classList.add("dcf-d-none"), this.imagePreviews.forEach((previewElement) => { 240 previewElement.querySelector(".dcf-image-cropper-yes-image").classList.remove("dcf-d-none"); 241 }), this.#syncInputs(); 242 } 243 /** 244 * Update the scale value based on the input range
245 * - This also re-draws canvases and syncs inputs 246 * @returns { Void } 247 */ 248 updateScale() { 249 this.croppedScale = parseInt(this.cropperScaleRange.value, 10), this.#checkIfBoxIsInBounds(), this.#draw(), this.#syncInputs(); 250 } 251 /** 252 * Move the selected area up by inputted amount 253 * - This also re-draws canvases and syncs inputs 254 * @returns { Void } 255 */ 256 moveUp(delta = 5) { 257 this.croppedY -= delta, this.#checkIfBoxIsInBounds(), this.#draw(), this.#syncInputs(); 258 } 259 /** 260 * Move the selected area down by inputted amount 261 * - This also re-draws canvases and syncs inputs 262 * @returns { Void } 263 */ 264 moveDown(delta = 5) { 265 this.croppedY += delta, this.#checkIfBoxIsInBounds(), this.#draw(), this.#syncInputs(); 266 } 267 /** 268 * Move the selected area left by inputted amount 269 * - This also re-draws canvases and syncs inputs 270 * @returns { Void } 271 */ 272 moveLeft(delta = 5) { 273 this.croppedX -= delta, this.#checkIfBoxIsInBounds(), this.#draw(), this.#syncInputs(); 274 } 275 /** 276 * Move the selected area right by inputted amount 277 * - This also re-draws canvases and syncs inputs 278 * @returns { Void } 279 */ 280 moveRight(delta = 5) { 281 this.croppedX += delta, this.#checkIfBoxIsInBounds(), this.#draw(), this.#syncInputs(); 282 } 283 /** 284 * Grows the selected area by inputted amount 285 * - This also re-draws canvases and syncs inputs 286 * @returns { Void } 287 */ 288 grow(delta = 5) { 289 this.croppedScale += delta, this.#checkIfBoxIsInBounds(), this.#draw(), this.#syncInputs(); 290 } 291 /** 292 * Shrinks the selected area by inputted amount 293 * - This also re-draws canvases and syncs inputs 294 * @returns { Void } 295 */ 296 shrink(delta = 5) { 297 this.croppedScale -= delta, this.#checkIfBoxIsInBounds(), this.#draw(), this.#syncInputs(); 298 } 299 /** 300 * Checks and fixes position of the selected area to avoid it going outside the image 301 * @returns { Void } 302 */ 303 #checkIfBoxIsInBounds() { 304 this.croppedScale < this.minCroppedScale && (this.croppedScale = this.minCroppedScale), this.croppedScale > 100 && (this.croppedScale = 100); 305 const croppedWidth = this.cropperMaxWidth * (this.croppedScale / 100), croppedHeight = this.cropperMaxWidth * (this.croppedScale / 100) / this.croppedRatio; 306 this.croppedX > this.cropperCanvas.width - croppedWidth && (this.croppedX = this.cropperCanvas.width - croppedWidth), this.croppedY > this.cropperCanvas.height - croppedHeight && (this.croppedY = this.cropperCanvas.height - croppedHeight), this.croppedY < 0 && (this.croppedY = 0), this.croppedX < 0 && (this.croppedX = 0); 307 } 308 /** 309 * Draw the image, selected area, and preview images on their canvases 310 * @returns { Void } 311 */ 312 #draw() { 313 this.cropperCanvasContext.drawImage( 314 this.imageToBeCropped, 315 0, 316 0, 317 this.cropperCanvas.width, 318 this.cropperCanvas.height 319 ), this.cropperCanvasContext.strokeStyle = "black", this.cropperCanvasContext.lineWidth = 4, this.#drawLines(), this.cropperCanvasContext.strokeStyle = "white", this.cropperCanvasContext.lineWidth = 2, this.#drawLines(); 320 const croppedWidth = this.cropperMaxWidth * (this.croppedScale / 100), croppedHeight = this.cropperMaxWidth * (this.croppedScale / 100) / this.croppedRatio; 321 this.imagePreviews.forEach((previewElement) => { 322 const previewCanvas = previewElement.querySelector("canvas"), previewContext = previewCanvas.getContext("2d"); 323 let previewSize = parseInt(previewElement.dataset.maxCanvasWidth, 10); 324 previewSize <= 20 && (previewSize = this.canvasSize), this.croppedRatio > 1 ? (previewCanvas.width = previewSize, previewCanvas.height = previewSize / this.croppedRatio) : (previewCanvas.width = previewSize / (1 / this.croppedRatio), previewCanvas.height = previewSize); 325 const scaleX = this.imageToBeCropped.width / this.cropperCanvas.width, scaleY = this.imageToBeCropped.height / this.cropperCanvas.height, scaledX = this.croppedX * scaleX, scaledY = this.croppedY * scaleY, scaledWidth = croppedWidth * scaleX, scaledHeight = croppedHeight * scaleY; 326 previewContext.drawImage( 327 this.imageToBeCropped, 328 scaledX, 329 scaledY, 330 scaledWidth, 331 scaledHeight, 332 // source rect (in original image) 333 0, 334 0, 335 previewCanvas.width, 336 previewCanvas.height 337 // destination rect (fit to preview canvas) 338 ); 339 }); 340 } 341 /** 342 * Inner function for #draw which only will draw the lines 343 * This logic is used multiple times for the black and white lines 344 */ 345 #drawLines() { 346 const croppedWidth = this.cropperMaxWidth * (this.croppedScale / 100), croppedHeight = this.cropperMaxWidth * (this.croppedScale / 100) / this.croppedRatio; 347 this.centerGuides && (this.cropperCanvasContext.beginPath(), this.cropperCanvasContext.moveTo(this.croppedX, this.croppedY), this.cropperCanvasContext.lineTo(this.croppedX + croppedWidth, this.croppedY + croppedHeight), this.cropperCanvasContext.moveTo(this.croppedX, this.croppedY + croppedHeight), this.cropperCanvasContext.lineTo(this.croppedX + croppedWidth, this.croppedY), this.cropperCanvasContext.stroke()), this.gridGuides && (this.cropperCanvasContext.beginPath(), this.cropperCanvasContext.moveTo(this.croppedX + croppedWidth / 3, this.croppedY), this.cropperCanvasContext.lineTo(this.croppedX + croppedWidth / 3, this.croppedY + croppedHeight), this.cropperCanvasContext.moveTo(this.croppedX + 2 * croppedWidth / 3, this.croppedY), this.cropperCanvasContext.lineTo(this.croppedX + 2 * croppedWidth / 3, this.croppedY + croppedHeight), this.cropperCanvasContext.moveTo(this.croppedX, this.croppedY + croppedHeight / 3), this.cropperCanvasContext.lineTo(this.croppedX + croppedWidth, this.croppedY + croppedHeight / 3), this.cropperCanvasContext.moveTo(this.croppedX, this.croppedY + 2 * croppedHeight / 3), this.cropperCanvasContext.lineTo(this.croppedX + croppedWidth, this.croppedY + 2 * croppedHeight / 3), this.cropperCanvasContext.stroke()), this.cropperCanvasContext.strokeRect(this.croppedX, this.croppedY, croppedWidth, croppedHeight); 348 } 349 /** 350 * Resets all inputs and status to default state where there is no image 351 * @returns { Void } 352 */ 353 #clearInputs() { 354 this.cropperScaleRange.value = "100", this.statusElement.innerText = "", document.querySelectorAll(`.dcf-image-cropper-x[data-image-cropper-input="${this.cropperElement.dataset.imageCropperIn
354put}"]`).forEach((inputElement) => { 355 inputElement.value = "-1"; 356 }), document.querySelectorAll(`.dcf-image-cropper-x2[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 357 inputElement.value = "-1"; 358 }), document.querySelectorAll(`.dcf-image-cropper-y[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 359 inputElement.value = "-1"; 360 }), document.querySelectorAll(`.dcf-image-cropper-y2[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 361 inputElement.value = "-1"; 362 }), document.querySelectorAll(`.dcf-image-cropper-width[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 363 inputElement.value = "-1"; 364 }), document.querySelectorAll(`.dcf-image-cropper-height[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 365 inputElement.value = "-1"; 366 }), document.querySelectorAll(`.dcf-image-cropper-ratio[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 367 inputElement.value = this.croppedRatio.toFixed(2); 368 }), document.querySelectorAll(`.dcf-image-cropper-ratio-text[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 369 switch (this.croppedRatio.toFixed(2)) { 370 case (3 / 4).toFixed(2): 371 inputElement.value = "3x4"; 372 break; 373 case (4 / 3).toFixed(2): 374 inputElement.value = "4x3"; 375 break; 376 case (9 / 16).toFixed(2): 377 inputElement.value = "9x16"; 378 break; 379 case (16 / 9).toFixed(2): 380 inputElement.value = "16x9"; 381 break; 382 default: 383 inputElement.value = "1x1"; 384 } 385 }), document.querySelectorAll(`.dcf-image-cropper-cropped-image[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 386 inputElement.value = ""; 387 }); 388 } 389 /** 390 * Updates all inputs and status to match the current state of the cropped area 391 * @returns { Void } 392 */ 393 #syncInputs() { 394 this.cropperScaleRange.value = this.croppedScale; 395 const scaleX = this.imageToBeCropped.width / this.cropperCanvas.width, scaleY = this.imageToBeCropped.height / this.cropperCanvas.height, croppedWidth = this.cropperMaxWidth * (this.croppedScale / 100), croppedHeight = this.cropperMaxWidth * (this.croppedScale / 100) / this.croppedRatio, xPos = (scaleX * this.croppedX).toFixed(2), yPos = (scaleY * this.croppedY).toFixed(2), width = (scaleX * croppedWidth).toFixed(2); 396 let aspectRatio = "1x1"; 397 switch (this.croppedRatio.toFixed(2)) { 398 case (3 / 4).toFixed(2): 399 aspectRatio = "3x4"; 400 break; 401 case (4 / 3).toFixed(2): 402 aspectRatio = "4x3"; 403 break; 404 case (9 / 16).toFixed(2): 405 aspectRatio = "9x16"; 406 break; 407 case (16 / 9).toFixed(2): 408 aspectRatio = "16x9"; 409 break; 410 default: 411 aspectRatio = "1x1"; 412 } 413 this.statusElement.innerText = `Cropped area moved to ${xPos}, ${yPos} with a width of ${width} in an aspect ratio of ${aspectRatio}.`, document.querySelectorAll(`.dcf-image-cropper-x[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 414 inputElement.value = xPos; 415 }), document.querySelectorAll(`.dcf-image-cropper-x2[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 416 inputElement.value = (scaleX * (this.croppedX + croppedWidth)).toFixed(2); 417 }), document.querySelectorAll(`.dcf-image-cropper-y[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 418 inputElement.value = yPos; 419 }), document.querySelectorAll(`.dcf-image-cropper-y2[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 420 inputElement.value = (scaleY * (this.croppedY + croppedHeight)).toFixed(2); 421 }), document.querySelectorAll(`.dcf-image-cropper-width[data-image-cropper-input="${this.cropperElement.dataset.imageCropperIn
421put}"]`).forEach((inputElement) => { 422 inputElement.value = width; 423 }), document.querySelectorAll(`.dcf-image-cropper-height[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 424 inputElement.value = (scaleY * croppedHeight).toFixed(2); 425 }), document.querySelectorAll(`.dcf-image-cropper-ratio[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 426 inputElement.value = this.croppedRatio.toFixed(2); 427 }), document.querySelectorAll(`.dcf-image-cropper-ratio-text[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`).forEach((inputElement) => { 428 inputElement.value = aspectRatio; 429 }); 430 const croppedImageInputs = document.querySelectorAll(`.dcf-image-cropper-cropped-image[data-image-cropper-input="${this.cropperElement.dataset.imageCropperInput}"]`); 431 croppedImageInputs.length > 0 && this.#getCroppedImageSrc().then((croppedImageFile) => { 432 croppedImageInputs.forEach((inputElement) => { 433 const dataTransferObj = new DataTransfer(); 434 dataTransferObj.items.add(croppedImageFile), inputElement.files = dataTransferObj.files; 435 }); 436 }); 437 } 438 /** 439 * Sets up the cropper canvas to match the aspect ratio of the of the image to be cropped 440 * @returns { Void } 441 */ 442 #setUpCanvas() { 443 const aspectRatio = this.imageToBeCropped.width / this.imageToBeCropped.height; 444 this.imageToBeCropped.width > this.imageToBeCropped.height ? (this.cropperCanvas.width = this.canvasSize, this.cropperCanvas.height = this.canvasSize / aspectRatio) : (this.cropperCanvas.width = this.canvasSize / (1 / aspectRatio), this.cropperCanvas.height = this.canvasSize), this.cropperCanvas.width / this.croppedRatio > this.cropperCanvas.height ? this.cropperMaxWidth = this.cropperCanvas.height / (1 / this.croppedRatio) : this.cropperMaxWidth = this.cropperCanvas.width; 445 } 446 /** 447 * Gets the image file for the inputted image 448 * @returns { Promise<HTMLImageElement> } 449 */ 450 #getSrcImage() { 451 return new Promise((resolve, reject) => { 452 this.imageSource.files[0] === void 0 && reject(); 453 const imageFile = this.imageSource.files[0], imageFileURL = URL.createObjectURL(imageFile), imageObj = new Image(); 454 imageObj.onload = () => { 455 URL.revokeObjectURL(imageFileURL), resolve(imageObj); 456 }, imageObj.src = imageFileURL; 457 }); 458 } 459 /** 460 * Gets the cropped image file based on the inputted image and the selected area 461 * @async 462 * @returns { Promise<File> } 463 */ 464 async #getCroppedImageSrc() { 465 const hiddenCanvas = document.createElement("canvas"), hiddenCanvasContext = hiddenCanvas.getContext("2d"); 466 hiddenCanvas.width = this.croppedImageOutputWidth, hiddenCanvas.height = this.croppedImageOutputWidth / this.croppedRatio; 467 const croppedWidth = this.cropperMaxWidth * (this.croppedScale / 100), croppedHeight = this.cropperMaxWidth * (this.croppedScale / 100) / this.croppedRatio, scaleX = this.imageToBeCropped.width / this.cropperCanvas.width, scaleY = this.imageToBeCropped.height / this.cropperCanvas.height, scaledX = this.croppedX * scaleX, scaledY = this.croppedY * scaleY, scaledWidth = croppedWidth * scaleX, scaledHeight = croppedHeight * scaleY; 468 hiddenCanvasContext.drawImage( 469 this.imageToBeCropped, 470 scaledX, 471 scaledY, 472 scaledWidth, 473 scaledHeight, 474 // source rect (in original image) 475 0, 476 0, 477 hiddenCanvas.width, 478 hiddenCanvas.height 479 // destination rect (fit to preview canvas) 480 ); 481 const blob = await new Promise((resolve) => hiddenCanvas.toBlob(resolve, this.imageToBeCropped.type)); 482 return new File([blob], "cropped_image", { type: this.imageToBeCropped.type }); 483 } 484} 485class UNLImageCropper extends DCFImageCropper { 486 static { 487 __name(this, "UNLImageCropper"); 488 } 489 constructor(imageCropper, options = {}) { 490 "collapsibleFieldset" in options || (options.collapsibleFieldset = UNLCollapsibleFieldset), super(imageCropper, options), window.UNL = window.UNL || {}, window.UNL.classes = window.UNL.classes || {}, window.UNL.classes[this.cropperElement.getAttribute("id")] = this, this.cropperElement.dispatchEvent(new Event("UNLClassReady")); 491 } 492} 493export { 494 UNLImageCropper as default 495}; 496//# sourceMappingURL=component.image-cropper.js.map
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.