-
-
-
-
-
+
diff --git a/src/admin/gallery/script.js b/src/admin/gallery/script.js
index 769625e..0e1b505 100644
--- a/src/admin/gallery/script.js
+++ b/src/admin/gallery/script.js
@@ -4,25 +4,54 @@ const devicePixelRatio = window.devicePixelRatio || 1;
function clamp(n, min, max) {
return Math.max(Math.min(n, max), min)
}
+function round(n, base = 10) {
+ return Math.round(n / base) * base;
+}
+function floor(n, base = 10) {
+ return Math.floor(n / base) * base;
+}
+function ceil(n, base = 10) {
+ return Math.ceil(n / base) * base;
+}
-function getOffsetRect(element) {
- return new DOMRect(element.offsetLeft, element.offsetTop, element.offsetWidth, element.offsetHeight);
+function getRelativeClientRect(element) {
+ const element_bounds = element.getBoundingClientRect();
+ const parents_bounds = element.parentElement.getBoundingClientRect();
+ return new DOMRect(
+ element_bounds.x - parents_bounds.x,
+ element_bounds.y - parents_bounds.y,
+ element_bounds.width,
+ element_bounds.height
+ );
}
class ResizableBox {
- constructor(element, bounding, aspectRatio = null) {
- this.element = element;
- this.bounding = bounding;
+ constructor(parent, bounding, resolution, aspectRatio = null) {
+
+ this.DIRECTIONS = {
+ nw: { sign: { x: -1, y: -1 }, anchor: 'se' },
+ ne: { sign: { x: +1, y: -1 }, anchor: 'sw' },
+ sw: { sign: { x: -1, y: +1 }, anchor: 'ne' },
+ se: { sign: { x: +1, y: +1 }, anchor: 'nw' }
+ }
+ this.bounding = bounding;
+ this.resolution = resolution;
this.aspectRatio = aspectRatio;
- this.mouseStart = {
- x: 0,
- y: 0
- }
+ this.mouseStart = { x: 0, y: 0 };
+ this.maxDelta = { x: 0, y: 0 };
+ this.minDelta = { x: 0, y: 0 };
- this.elemStart = new DOMRect()
+ this.elemStart = new DOMRect();
+ this.direction = undefined;
+
+ this._constructElement(parent);
+
+ this.res_scale = {
+ x: resolution.x / bounding.width,
+ y: resolution.y / bounding.height
+ };
- this.direction = undefined;
const dragMouseMove = (event) => {
event.preventDefault();
@@ -32,146 +61,20 @@ class ResizableBox {
y: event.clientY - this.mouseStart.y
};
- const delta = {...offset};
-
- if (this.direction && aspectRatio) {
-
- 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.right,
- y: this.elemStart.bottom
- },
- corner_pos: {
- x: this.elemStart.left,
- y: this.elemStart.top
- },
- sign: {
- x: -1,
- y: -1
- }
- }
- case 'ne':
- return {
- anchor: {
- x: this.elemStart.left,
- y: this.elemStart.bottom
- },
- corner_pos: {
- x: this.elemStart.right,
- y: this.elemStart.top
- },
- sign: {
- x: +1,
- y: -1
- }
- }
- case 'sw':
- return {
- anchor: {
- x: this.elemStart.right,
- y: this.elemStart.top
- },
- corner_pos: {
- x: this.elemStart.left,
- y: this.elemStart.bottom
- },
- sign: {
- x: -1,
- y: +1
- }
- }
- case 'se':
- return {
- anchor: {
- x: this.elemStart.left,
- y: this.elemStart.top
- },
- corner_pos: {
- x: this.elemStart.right,
- y: this.elemStart.bottom
- },
- sign: {
- x: +1,
- y: +1
- }
- }
- }
- })()
-
- 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)
-
- 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
-
- 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)
+ if (this.direction) {
+ this.resize(offset, this.direction, this.aspectRatio);
+ } else {
+ this.move(offset);
}
-
- 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 = 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)
}
-
const dragMouseUp = (_) => {
this.element.classList.remove("moving");
- this.direction = undefined
+
+ this.direction = undefined;
+
document.removeEventListener('mousemove', dragMouseMove);
- document.removeEventListener('mouseup', dragMouseUp);
+ document.removeEventListener('mouseup', dragMouseUp);
};
const dragMouseDown = (event) => {
@@ -180,25 +83,142 @@ class ResizableBox {
this.mouseStart.x = event.clientX;
this.mouseStart.y = event.clientY;
- this.elemStart = getOffsetRect(this.element)
+ this.elemStart = getRelativeClientRect(this.element)
this.direction = [...event.target.classList].find(c => ["nw","ne","sw","se"].includes(c));
+ if (this.direction) {
+ const handle_size = getRelativeClientRect(this.element.querySelector(".handle"));
+ this.minDelta.x = -1 * (this.elemStart.width - 2*handle_size.width);
+ this.minDelta.y = -1 * (this.elemStart.height - 2*handle_size.height);
+
+ switch (this.direction) {
+ case 'nw':
+ this.maxDelta.x = this.elemStart.left - this.bounding.left;
+ this.maxDelta.y = this.elemStart.top - this.bounding.top;
+ break;
+ case 'ne':
+ this.maxDelta.x = this.bounding.right - this.elemStart.right;
+ this.maxDelta.y = this.elemStart.top - this.bounding.top;
+ break;
+ case 'sw':
+ this.maxDelta.x = this.elemStart.left - this.bounding.left;
+ this.maxDelta.y = this.bounding.bottom - this.elemStart.bottom;
+ break;
+ case 'se':
+ this.maxDelta.x = this.bounding.right - this.elemStart.right;
+ this.maxDelta.y = this.bounding.bottom - this.elemStart.bottom;
+ break;
+ }
+ }
+
this.element.classList.add('moving');
document.addEventListener('mousemove', dragMouseMove);
- document.addEventListener('mouseup', dragMouseUp);
+ 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);
+ move(delta) {
+ this.element.style.left = clamp(this.elemStart.left + delta.x, this.bounding.left, this.bounding.right - this.elemStart.width) + "px";
+ this.element.style.top = clamp(this.elemStart.top + delta.y, this.bounding.top, this.bounding.bottom - this.elemStart.height) + "px";
+ }
+
+ resize(delta, direction, handle_aspect_ratio = true) {
+
+ console.log(delta)
+
+ const sign = this.DIRECTIONS[direction].sign;
+
+ const normalized = {
+ x: delta.x * sign.x,
+ y: delta.y * sign.y
+ };
+
+ console.log(normalized)
+ console.log(this.minDelta)
+ console.log(this.maxDelta);
+
+ if (handle_aspect_ratio) {
+ //delta = this._applyAspectRatio(delta.x, delta.y, direction)
+
+ if (Math.abs(normalized.x) > Math.abs(normalized.y * this.aspectRatio)) {
+ normalized.x = clamp(normalized.x,
+ Math.max(this.minDelta.x, this.minDelta.y * this.aspectRatio),
+ Math.min(this.maxDelta.x, this.maxDelta.y * this.aspectRatio));
+ normalized.y = normalized.x / this.aspectRatio;
+ } else {
+ normalized.y = clamp(normalized.y,
+ Math.max(this.minDelta.y, this.minDelta.x / this.aspectRatio),
+ Math.min(this.maxDelta.y, this.maxDelta.x / this.aspectRatio));
+ normalized.x = normalized.y * this.aspectRatio;
+ }
+
+ } else {
+
+ normalized.x = clamp(normalized.x, this.minDelta.x, this.maxDelta.x);
+ normalized.y = clamp(normalized.y, this.minDelta.y, this.maxDelta.y);
+
+ }
+
+ delta.x = normalized.x * sign.x;
+ delta.y = normalized.y * sign.y;
+
+ console.log(delta)
+
+ 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;
+ }
+ }
+
+ _constructElement(parent) {
+ parent.querySelector('.selector')?.remove();
+
+ this.element = document.createElement('div');
+ this.element.classList.add('selector');
+
+ if (this.aspectRatio) {
+
+ if (this.bounding.width > this.bounding.height * this.aspectRatio) {
+ this.element.style.width = (this.bounding.height * this.aspectRatio - 2) + "px";
+ this.element.style.height = (this.bounding.height - 2) + "px";
+ this.element.style.left = (this.bounding.width - this.bounding.height * this.aspectRatio) / 2 + this.bounding.left + "px";
+ this.element.style.top = this.bounding.top + "px";
+ } else {
+ this.element.style.width = (this.bounding.width - 2) + "px";
+ this.element.style.height = (this.bounding.width / this.aspectRatio - 2) + "px";
+ this.element.style.left = this.bounding.left + "px";
+ this.element.style.top = (this.bounding.height - this.bounding.width / this.aspectRatio) / 2 + this.bounding.top + "px";
+ }
+
+ } else {
+
+ this.element.style.left = this.bounding.offsetLeft + "px";
+ this.element.style.top = this.bounding.offsetTop + "px";
+ this.element.style.width = this.bounding.clientWidth + "px";
+ this.element.style.height = this.bounding.clientHeight + "px";
+
}
const neHandle = document.createElement('div');
@@ -217,8 +237,54 @@ class ResizableBox {
this.element.appendChild(nwHandle);
this.element.appendChild(seHandle);
this.element.appendChild(swHandle);
+
+ parent.appendChild(this.element);
}
+ _mapCorner(rect, dir) {
+ const map = {
+ nw: { x: rect.left, y: rect.top },
+ ne: { x: rect.right, y: rect.top },
+ sw: { x: rect.left, y: rect.bottom },
+ se: { x: rect.right, y: rect.bottom }
+ };
+
+ return map[dir];
+ }
+
+
+ _applyAspectRatio(dx, dy, direction) {
+
+ const sign = this.DIRECTIONS[direction].sign;
+ const anchor = this._mapCorner(getRelativeClientRect(this.element), this.DIRECTIONS[direction].anchor);
+
+ const handle_size = getRelativeClientRect(this.element.querySelector(".handle"));
+
+ const sh = 1 + dx / this.elemStart.width
+ const sv = 1 + dy / this.elemStart.height
+
+ const dv = Math.abs(dx)
+ const dh = Math.abs(dy)
+
+ const s = (dv > dh) ? sv : sh
+
+ 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);
+
+ return {
+ x: sign.x * (sClamped * this.elemStart.width - this.elemStart.width),
+ y: sign.y * (sClamped * this.elemStart.height - this.elemStart.height)
+ };
+ }
}
@@ -228,56 +294,57 @@ class Editor {
this._editor = editorElement;
this.aspectRatio = aspectRatio;
- this._imgElement = undefined
+ this._imgElement = undefined;
}
loadImage(url) {
- this._imgElement = new Image()
- this._imgElement.classList.add("editor-image");
+ this._imgElement = this._editor.querySelector(".editor-image");
this._imgElement.src = url;
- this._editor.replaceChildren(this._imgElement);
-
const that = this;
this._imgElement.addEventListener('load', (_) => {
this._imgElement.style.left = (this._editor.clientWidth - this._imgElement.offsetWidth) / 2 + "px";
this._imgElement.style.top = (this._editor.clientHeight - this._imgElement.offsetHeight) / 2 + "px";
- 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 {
- selector_pos.height = selector_pos.width / that.aspectRatio;
- selector_pos.x = (this._editor.clientWidth - selector_pos.width) / 2
- selector_pos.y = this._imgElement.offsetTop
- }
-
- console.log(selector_pos)
-
- that._createSelectionBox(selector_pos);
+ this._cutArea = new ResizableBox(this._editor, getRelativeClientRect(this._imgElement), {}, 4/3);
+ document.querySelector("#theatergf-edit-save").style.visibility = "visible";
});
}
- _createSelectionBox(selector_pos) {
- const selector = document.createElement('div');
- selector.classList.add('selector');
+ save() {
- 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";
+ const relative_position = {
+ x: (this._cutSelector.offsetLeft + 1 - this._imgElement.offsetLeft) / this._imgElement.clientWidth,
+ y: (this._cutSelector.offsetTop + 1 - this._imgElement.offsetTop) / this._imgElement.clientHeight,
+ width: (this._cutSelector.clientWidth - 2) / this._imgElement.clientWidth,
+ height: (this._cutSelector.clientHeight - 2) / this._imgElement.clientHeight
+ }
- this._cutSelector = selector;
- this._editor.appendChild(selector);
+ const mapped_region = {
+ x: relative_position.x * this._imgElement.naturalWidth,
+ y: relative_position.y * this._imgElement.naturalHeight,
+ width: relative_position.width * this._imgElement.naturalWidth,
+ height: relative_position.height * this._imgElement.naturalHeight
+ }
- this._cutArea = new ResizableBox(selector, getOffsetRect(this._imgElement), selector_pos.width/selector_pos.height);
+ console.log(mapped_region)
+
+ fetch(wpAPISettings.root + 'theatergf/gallery/v1/crop/new', {
+ method: 'POST',
+ headers: {
+ 'X-WP-Nonce': wpAPISettings.nonce,
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ img_id: 53,
+ x: mapped_region.x,
+ y: mapped_region.y,
+ width: mapped_region.width,
+ height: mapped_region.height
+ })
+ }).then((response) => response.json().then((json) => console.log(json))).catch((error) => console.log(error));
}
}
@@ -285,7 +352,7 @@ class Editor {
jQuery(document).ready( ($) => {
let wp_file_selector_frame = null;
- let editor = new Editor(document.querySelector("#theatergf-editor"), 4/3);
+ let editor = new Editor(document.querySelector("#theatergf-editor"), 2/1);
$("#theatergf-select-image").on("click", (event) => {
event.preventDefault();
@@ -307,10 +374,17 @@ jQuery(document).ready( ($) => {
wp_file_selector_frame.on('select', () => {
const file = wp_file_selector_frame.state().get('selection').first().toJSON();
+ console.log(file)
+
editor.loadImage(file.url);
});
wp_file_selector_frame.open();
})
+ $("#theatergf-edit-save").on("click", (event) => {
+ event.preventDefault();
+
+ editor.save();
+ })
})
diff --git a/src/admin/gallery/style.css b/src/admin/gallery/style.css
index 6e3184b..c23ef11 100644
--- a/src/admin/gallery/style.css
+++ b/src/admin/gallery/style.css
@@ -21,7 +21,8 @@
.selector {
position: absolute;
- border: blue 1px solid;
+ border: lightblue 1px solid;
+ opacity: 50%;
/*top: 50%;
left: 50%;*/
@@ -37,7 +38,7 @@
width: 10px;
height: 10px;
- border: blue 1px solid;
+ border: lightblue 1px solid;
position: absolute;
/*transform: translate(-50%, -50%);*/
@@ -73,19 +74,16 @@
}
}
- .image-edit-wrap {
- aspect-ratio: 2 / 1;
+ .editor-button-row {
+
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+
width: 75%;
- height: 75%;
- background-color: gray;
-
- #theatergf-image-editor {
- width: 100%;
- }
-
- #theatergf-image-editor-shadow {
- display: none;
+ #theatergf-edit-save {
+ visibility: hidden;
}
}
}