theatergf-gallery/src/admin/gallery/script.js

385 lines
9.7 KiB
JavaScript
Raw Normal View History

2026-03-21 13:54:23 +01:00
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');
}
}
/*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();
});
});*/
class ResizableBox {
constructor(element, aspectRatio = null) {
this.element = element;
this.aspectRatio = aspectRatio;
this.mouseStart = {
x: 0,
y: 0
}
this.elemStart = {
left: 0,
top: 0,
width: element.style.width,
height: element.style.height,
corner_pos: {
x: 0,
y: 0
}
};
this.direction = undefined;
const dragMouseMove = (event) => {
event.preventDefault();
const offset = {
x: event.clientX - this.mouseStart.x,
y: event.clientY - this.mouseStart.y
};
const delta = {...offset};
if (this.direction && aspectRatio) {
const {anchor, sign} = (() => {
switch (this.direction) {
case 'nw':
return {
anchor: {
x: this.elemStart.left + this.elemStart.width,
y: this.elemStart.top + this.elemStart.height
},
sign: {
x: -1,
y: -1
}
}
case 'ne':
return {
anchor: {
x: this.elemStart.left,
y: this.elemStart.top + this.elemStart.height
},
sign: {
x: +1,
y: -1
}
}
case 'sw':
return {
anchor: {
x: this.elemStart.left + this.elemStart.width,
y: this.elemStart.top
},
sign: {
x: -1,
y: +1
}
}
case 'se':
return {
anchor: {
x: this.elemStart.left,
y: this.elemStart.top
},
sign: {
x: +1,
y: +1
}
}
}
})()
const px = this.elemStart.corner_pos.x + offset.x
const py = this.elemStart.corner_pos.y + offset.y
const dx = sign.x * (px - anchor.x)
const dy = sign.y * (py - anchor.y)
const sh = dx/this.elemStart.width
const sv = dy/this.elemStart.height
const dv = Math.abs(dx - this.elemStart.width)
const dh = Math.abs(dy - this.elemStart.height)
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)
}
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";
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";
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";
break;
case 'se':
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";
}
}
const dragMouseUp = (_) => {
this.element.classList.remove("moving");
this.direction = undefined
document.removeEventListener('mousemove', dragMouseMove);
document.removeEventListener('mouseup', dragMouseUp);
};
const dragMouseDown = (event) => {
event.preventDefault();
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.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);
document.addEventListener('mouseup', dragMouseUp);
};
this.element.addEventListener('mousedown', dragMouseDown);
this.createHandles();
}
createHandles() {
const handles = this.element.querySelectorAll('.handle');
for (const handle of handles) {
this.element.removeChild(handle);
}
const neHandle = document.createElement('div');
neHandle.classList.add('handle', 'ne');
const nwHandle = document.createElement('div');
nwHandle.classList.add('handle', 'nw');
const seHandle = document.createElement('div');
seHandle.classList.add('handle', 'se');
const swHandle = document.createElement('div');
swHandle.classList.add('handle', 'sw');
this.element.appendChild(neHandle);
this.element.appendChild(nwHandle);
this.element.appendChild(seHandle);
this.element.appendChild(swHandle);
}
getRect() {
return new DOMRect(this.element.offsetLeft, this.element.offsetTop, this.element.offsetWidth, this.element.offsetHeight);
}
}
class Editor {
constructor(editorElement, aspectRatio) {
this._editor = editorElement;
this.aspectRatio = aspectRatio;
}
loadImage(url) {
const imgElement = new Image()
imgElement.classList.add("editor-image");
imgElement.src = url;
this._editor.replaceChildren(imgElement);
const that = this;
imgElement.addEventListener('load', (_) => {
const size = {
width: imgElement.offsetWidth,
height: imgElement.offsetHeight
};
if (size.width > size.height * that.aspectRatio) {
size.width = size.height * that.aspectRatio;
} else {
size.height = size.width / that.aspectRatio;
}
that._createSelectionBox(size.width, size.height);
});
}
_createSelectionBox(width, height) {
const selector = document.createElement('div');
selector.classList.add('selector');
selector.style.width = (width - 1) + "px";
selector.style.height = (height - 1) + "px";
this._cutSelector = selector;
this._editor.appendChild(selector);
this._cutArea = new ResizableBox(selector, width/height);
}
}
jQuery(document).ready( ($) => {
let wp_file_selector_frame = null;
let editor = new Editor(document.querySelector("#theatergf-editor"), 4/3);
$("#theatergf-select-image").on("click", (event) => {
event.preventDefault();
if (wp_file_selector_frame) {
wp_file_selector_frame.open();
return;
}
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();
editor.loadImage(file.url);
});
wp_file_selector_frame.open();
})
})