diff --git a/src/admin/gallery/script.js b/src/admin/gallery/script.js index fab0a39..769625e 100644 --- a/src/admin/gallery/script.js +++ b/src/admin/gallery/script.js @@ -1,97 +1,18 @@ const devicePixelRatio = window.devicePixelRatio || 1; -class ImageCropper { - - constructor(canvas) { - if (!(canvas instanceof HTMLCanvasElement)) { - throw TypeError('canvas must be a HTMLCanvasElement'); - } - this._preview = canvas; - this._preview_ctx = canvas.getContext('2d'); - this._preview_ctx.reset(); - - const dimensions = this._preview.getBoundingClientRect(); - console.log(dimensions); - console.log(this._preview.width, this._preview.height); - - this._preview.width = dimensions.width * devicePixelRatio; - this._preview.height = dimensions.height * devicePixelRatio; - this._preview_ctx.setTransform(devicePixelRatio, 0, 0, devicePixelRatio, 0, 0); - } - - showImage(image_src) { - this._image = new Image(); - this._image.src = image_src; - - this._image.addEventListener('load', (e) => { - - const dimensions = this._preview.getBoundingClientRect(); - - const scale = { - x: dimensions.width / this._image.naturalWidth, - y: dimensions.height / this._image.naturalHeight - } - const ratio = Math.min(scale.x, scale.y); - - const position = { - x: (dimensions.width - this._image.naturalWidth * ratio) / 2, - y: (dimensions.height - this._image.naturalHeight * ratio) / 2, - }; - - this._preview_ctx.drawImage(this._image, position.x, position.y, this._image.naturalWidth * ratio, this._image.naturalHeight * ratio); - }) - } - - doCrop() { - this._shadow = document.createElement('canvas'); - this._shadow.style.display = 'none'; - this._shadow_ctx = canvas.getContext('2d'); - } +function clamp(n, min, max) { + return Math.max(Math.min(n, max), min) } -/*jQuery(document).ready( ($) => { - - let wp_file_selector_frame; - let image_cropper; - - $('#theatergf-select-image').on('click', (event) => { - - // don't open browser file select - event.preventDefault(); - - if (wp_file_selector_frame) { - wp_file_selector_frame.open(); - } - - wp_file_selector_frame = wp.media({ - title: 'Select Image', - button: { - text: 'Use Image' - }, - multiple: false - }); - - wp_file_selector_frame.on('select', () => { - const file = wp_file_selector_frame.state().get('selection').first().toJSON(); - - image_cropper = new ImageCropper(document.getElementById('theatergf-image-editor')); - //image_cropper.showImage('http://localhost:8000/wp-content/uploads/2026/03/Kishon002.jpg'); - - image_cropper.showImage(file.url); - //document.getElementById('theatergf-image-preview').src = file.url; - - }); - - wp_file_selector_frame.open(); - }); -});*/ - - +function getOffsetRect(element) { + return new DOMRect(element.offsetLeft, element.offsetTop, element.offsetWidth, element.offsetHeight); +} class ResizableBox { - constructor(element, aspectRatio = null) { + constructor(element, bounding, aspectRatio = null) { this.element = element; + this.bounding = bounding; this.aspectRatio = aspectRatio; this.mouseStart = { @@ -99,16 +20,7 @@ class ResizableBox { y: 0 } - this.elemStart = { - left: 0, - top: 0, - width: element.style.width, - height: element.style.height, - corner_pos: { - x: 0, - y: 0 - } - }; + this.elemStart = new DOMRect() this.direction = undefined; @@ -124,13 +36,20 @@ class ResizableBox { if (this.direction && aspectRatio) { - const {anchor, sign} = (() => { + const handle = this.element.querySelector('.handle') + const handle_size = getOffsetRect(handle) + + const { anchor, corner_pos, sign} = (() => { switch (this.direction) { case 'nw': return { anchor: { - x: this.elemStart.left + this.elemStart.width, - y: this.elemStart.top + this.elemStart.height + x: this.elemStart.right, + y: this.elemStart.bottom + }, + corner_pos: { + x: this.elemStart.left, + y: this.elemStart.top }, sign: { x: -1, @@ -141,7 +60,11 @@ class ResizableBox { return { anchor: { x: this.elemStart.left, - y: this.elemStart.top + this.elemStart.height + y: this.elemStart.bottom + }, + corner_pos: { + x: this.elemStart.right, + y: this.elemStart.top }, sign: { x: +1, @@ -151,9 +74,13 @@ class ResizableBox { case 'sw': return { anchor: { - x: this.elemStart.left + this.elemStart.width, + x: this.elemStart.right, y: this.elemStart.top }, + corner_pos: { + x: this.elemStart.left, + y: this.elemStart.bottom + }, sign: { x: -1, y: +1 @@ -165,6 +92,10 @@ class ResizableBox { x: this.elemStart.left, y: this.elemStart.top }, + corner_pos: { + x: this.elemStart.right, + y: this.elemStart.bottom + }, sign: { x: +1, y: +1 @@ -173,8 +104,8 @@ class ResizableBox { } })() - const px = this.elemStart.corner_pos.x + offset.x - const py = this.elemStart.corner_pos.y + offset.y + const px = corner_pos.x + offset.x + const py = corner_pos.y + offset.y const dx = sign.x * (px - anchor.x) const dy = sign.y * (py - anchor.y) @@ -187,38 +118,52 @@ class ResizableBox { const s = (dv > dh) ? sv : sh - delta.x = sign.x * (s * this.elemStart.width - this.elemStart.width) - delta.y = sign.y * (s * this.elemStart.height - this.elemStart.height) + const sMaxX = (sign.x === +1) + ? (this.bounding.right - anchor.x) / this.elemStart.width + : (anchor.x - this.bounding.left) / this.elemStart.width + const sMaxY = (sign.y === +1) + ? (this.bounding.bottom - anchor.y) / this.elemStart.height + : (anchor.y - this.bounding.top) / this.elemStart.height + + const sMin = Math.max(2*handle_size.width / this.elemStart.width, 2*handle_size.height / this.elemStart.height) + + const sClamped = Math.max(Math.min(s, sMaxX, sMaxY), sMin) + + delta.x = sign.x * (sClamped * this.elemStart.width - this.elemStart.width) + delta.y = sign.y * (sClamped * this.elemStart.height - this.elemStart.height) } switch(this.direction) { case 'nw': - this.element.style.left = (this.elemStart.left + delta.x) + "px"; - this.element.style.top = (this.elemStart.top + delta.y) + "px"; - this.element.style.width = (this.elemStart.width - delta.x) + "px"; - this.element.style.height = (this.elemStart.height - delta.y) + "px"; + this.element.style.left = this.elemStart.left + delta.x+ "px"; + this.element.style.top = this.elemStart.top + delta.y + "px"; + this.element.style.width = this.elemStart.width - delta.x+ "px"; + this.element.style.height = this.elemStart.height - delta.y + "px"; break; case 'ne': - this.element.style.top = (this.elemStart.top + delta.y) + "px"; - this.element.style.width = (this.elemStart.width + delta.x) + "px"; - this.element.style.height = (this.elemStart.height - delta.y) + "px"; + this.element.style.top = this.elemStart.top + delta.y + "px"; + this.element.style.width = this.elemStart.width + delta.x + "px"; + this.element.style.height = this.elemStart.height - delta.y + "px"; break; case 'sw': - this.element.style.left = (this.elemStart.left + delta.x) + "px"; - this.element.style.width = (this.elemStart.width - delta.x) + "px"; - this.element.style.height = (this.elemStart.height + delta.y) + "px"; + this.element.style.left = this.elemStart.left + delta.x+ "px"; + this.element.style.width = this.elemStart.width - delta.x+ "px"; + this.element.style.height = this.elemStart.height + delta.y + "px"; break; case 'se': - this.element.style.width = (this.elemStart.width + delta.x) + "px"; - this.element.style.height = (this.elemStart.height + delta.y) + "px"; + this.element.style.width = this.elemStart.width + delta.x+ "px"; + this.element.style.height = this.elemStart.height + delta.y + "px"; break; // moving is the default default: - this.element.style.left = (this.elemStart.left + offset.x) + "px"; - this.element.style.top = (this.elemStart.top + offset.y) + "px"; + this.element.style.left = clamp(this.elemStart.left + offset.x, this.bounding.left, this.bounding.right - this.elemStart.width) + "px"; + this.element.style.top = clamp(this.elemStart.top + offset.y, this.bounding.top, this.bounding.bottom - this.elemStart.height) + "px"; } + + console.log(this.bounding) + console.log(this.elemStart) } @@ -235,32 +180,10 @@ class ResizableBox { this.mouseStart.x = event.clientX; this.mouseStart.y = event.clientY; - this.elemStart.left = this.element.offsetLeft; - this.elemStart.top = this.element.offsetTop; - this.elemStart.width = this.element.offsetWidth; - this.elemStart.height = this.element.offsetHeight; + this.elemStart = getOffsetRect(this.element) this.direction = [...event.target.classList].find(c => ["nw","ne","sw","se"].includes(c)); - switch (this.direction) { - case 'nw': - this.elemStart.corner_pos.x = this.element.offsetLeft; - this.elemStart.corner_pos.y = this.element.offsetTop; - break; - case 'ne': - this.elemStart.corner_pos.x = this.element.offsetLeft + this.element.offsetWidth; - this.elemStart.corner_pos.y = this.element.offsetTop; - break; - case 'sw': - this.elemStart.corner_pos.x = this.element.offsetLeft; - this.elemStart.corner_pos.y = this.element.offsetTop + this.element.offsetHeight; - break; - case 'se': - this.elemStart.corner_pos.x = this.element.offsetLeft + this.element.offsetWidth; - this.elemStart.corner_pos.y = this.element.offsetTop + this.element.offsetHeight; - break; - } - this.element.classList.add('moving'); document.addEventListener('mousemove', dragMouseMove); @@ -296,9 +219,6 @@ class ResizableBox { this.element.appendChild(swHandle); } - getRect() { - return new DOMRect(this.element.offsetLeft, this.element.offsetTop, this.element.offsetWidth, this.element.offsetHeight); - } } @@ -307,45 +227,57 @@ class Editor { constructor(editorElement, aspectRatio) { this._editor = editorElement; this.aspectRatio = aspectRatio; + + this._imgElement = undefined } loadImage(url) { - const imgElement = new Image() - imgElement.classList.add("editor-image"); - imgElement.src = url; + this._imgElement = new Image() + this._imgElement.classList.add("editor-image"); + this._imgElement.src = url; - this._editor.replaceChildren(imgElement); + this._editor.replaceChildren(this._imgElement); const that = this; - imgElement.addEventListener('load', (_) => { + this._imgElement.addEventListener('load', (_) => { - const size = { - width: imgElement.offsetWidth, - height: imgElement.offsetHeight - }; + this._imgElement.style.left = (this._editor.clientWidth - this._imgElement.offsetWidth) / 2 + "px"; + this._imgElement.style.top = (this._editor.clientHeight - this._imgElement.offsetHeight) / 2 + "px"; - if (size.width > size.height * that.aspectRatio) { - size.width = size.height * that.aspectRatio; + const selector_pos = new DOMRect(0, 0, this._imgElement.offsetWidth, this._imgElement.offsetHeight); + + console.log(selector_pos) + + if (selector_pos.width > selector_pos.height * that.aspectRatio) { + selector_pos.width = selector_pos.height * that.aspectRatio; + selector_pos.x = this._imgElement.offsetLeft + selector_pos.y = (this._editor.clientHeight - selector_pos.height) / 2 } else { - size.height = size.width / that.aspectRatio; + selector_pos.height = selector_pos.width / that.aspectRatio; + selector_pos.x = (this._editor.clientWidth - selector_pos.width) / 2 + selector_pos.y = this._imgElement.offsetTop } - that._createSelectionBox(size.width, size.height); + console.log(selector_pos) + + that._createSelectionBox(selector_pos); }); } - _createSelectionBox(width, height) { + _createSelectionBox(selector_pos) { const selector = document.createElement('div'); selector.classList.add('selector'); - selector.style.width = (width - 1) + "px"; - selector.style.height = (height - 1) + "px"; + selector.style.left = selector_pos.left + "px", + selector.style.top = selector_pos.top + "px" + selector.style.width = (selector_pos.width - 1) + "px"; + selector.style.height = (selector_pos.height - 1) + "px"; this._cutSelector = selector; this._editor.appendChild(selector); - this._cutArea = new ResizableBox(selector, width/height); + this._cutArea = new ResizableBox(selector, getOffsetRect(this._imgElement), selector_pos.width/selector_pos.height); } } diff --git a/src/admin/gallery/style.css b/src/admin/gallery/style.css index 36813ca..6e3184b 100644 --- a/src/admin/gallery/style.css +++ b/src/admin/gallery/style.css @@ -15,9 +15,6 @@ max-height: 100%; position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); background-color: white; }