bounded the Resizable box
This commit is contained in:
parent
2ddcf21572
commit
b3b7ec0293
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,6 @@
|
|||
max-height: 100%;
|
||||
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
background-color: white;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue