forked from Public/pics
Refactor crop editor into a proper class.
This commit is contained in:
parent
909d50efa8
commit
fd84e1c9f8
@ -1,218 +1,220 @@
|
|||||||
function CropEditor(opt) {
|
class CropEditor {
|
||||||
this.opt = opt;
|
constructor(opt) {
|
||||||
|
this.opt = opt;
|
||||||
|
|
||||||
this.edit_crop_button = document.createElement("span");
|
this.edit_crop_button = document.createElement("span");
|
||||||
this.edit_crop_button.className = "btn";
|
this.edit_crop_button.className = "btn";
|
||||||
this.edit_crop_button.innerHTML = "Edit crop";
|
this.edit_crop_button.textContent = "Edit crop";
|
||||||
this.edit_crop_button.addEventListener('click', this.show.bind(this));
|
this.edit_crop_button.addEventListener('click', this.show.bind(this));
|
||||||
|
|
||||||
this.thumbnail_select = document.getElementById(opt.thumbnail_select_id);
|
this.thumbnail_select = document.getElementById(opt.thumbnail_select_id);
|
||||||
this.thumbnail_select.addEventListener('change', this.toggleCropButton.bind(this));
|
this.thumbnail_select.addEventListener('change', this.toggleCropButton.bind(this));
|
||||||
this.thumbnail_select.parentNode.insertBefore(this.edit_crop_button, this.thumbnail_select.nextSibling);
|
this.thumbnail_select.parentNode.insertBefore(this.edit_crop_button, this.thumbnail_select.nextSibling);
|
||||||
|
|
||||||
this.toggleCropButton();
|
this.toggleCropButton();
|
||||||
}
|
|
||||||
|
|
||||||
CropEditor.prototype.buildContainer = function() {
|
|
||||||
this.container = document.createElement("div");
|
|
||||||
this.container.id = "crop_editor";
|
|
||||||
|
|
||||||
this.position = document.createElement("div");
|
|
||||||
this.position.className = "crop_position";
|
|
||||||
this.container.appendChild(this.position);
|
|
||||||
|
|
||||||
var source_x_label = document.createTextNode("Source X:");
|
|
||||||
this.position.appendChild(source_x_label);
|
|
||||||
|
|
||||||
this.source_x = document.createElement("input");
|
|
||||||
this.source_x.addEventListener("keyup", this.positionBoundary.bind(this));
|
|
||||||
this.position.appendChild(this.source_x);
|
|
||||||
|
|
||||||
var source_y_label = document.createTextNode("Source Y:");
|
|
||||||
this.position.appendChild(source_y_label);
|
|
||||||
|
|
||||||
this.source_y = document.createElement("input");
|
|
||||||
this.source_y.addEventListener("keyup", this.positionBoundary.bind(this));
|
|
||||||
this.position.appendChild(this.source_y);
|
|
||||||
|
|
||||||
var crop_width_label = document.createTextNode("Crop width:");
|
|
||||||
this.position.appendChild(crop_width_label);
|
|
||||||
|
|
||||||
this.crop_width = document.createElement("input");
|
|
||||||
this.crop_width.addEventListener("keyup", this.positionBoundary.bind(this));
|
|
||||||
this.position.appendChild(this.crop_width);
|
|
||||||
|
|
||||||
var crop_height_label = document.createTextNode("Crop height:");
|
|
||||||
this.position.appendChild(crop_height_label);
|
|
||||||
|
|
||||||
this.crop_height = document.createElement("input");
|
|
||||||
this.crop_height.addEventListener("keyup", this.positionBoundary.bind(this));
|
|
||||||
this.position.appendChild(this.crop_height);
|
|
||||||
|
|
||||||
this.save_button = document.createElement("span");
|
|
||||||
this.save_button.className = "btn";
|
|
||||||
this.save_button.innerHTML = "Save";
|
|
||||||
this.save_button.addEventListener('click', this.save.bind(this));
|
|
||||||
this.position.appendChild(this.save_button);
|
|
||||||
|
|
||||||
this.abort_button = document.createElement("span");
|
|
||||||
this.abort_button.className = "btn btn-red";
|
|
||||||
this.abort_button.innerHTML = "Abort";
|
|
||||||
this.abort_button.addEventListener('click', this.hide.bind(this));
|
|
||||||
this.position.appendChild(this.abort_button);
|
|
||||||
|
|
||||||
this.image_container = document.createElement("div");
|
|
||||||
this.image_container.className = "crop_image_container";
|
|
||||||
this.container.appendChild(this.image_container);
|
|
||||||
|
|
||||||
this.crop_boundary = document.createElement("div");
|
|
||||||
this.crop_boundary.id = "crop_boundary";
|
|
||||||
this.image_container.appendChild(this.crop_boundary);
|
|
||||||
|
|
||||||
this.original_image = document.createElement("img");
|
|
||||||
this.original_image.id = "original_image";
|
|
||||||
this.original_image.src = this.opt.original_image_src;
|
|
||||||
this.image_container.appendChild(this.original_image);
|
|
||||||
|
|
||||||
this.parent = document.getElementById(this.opt.editor_container_parent_id);
|
|
||||||
this.parent.appendChild(this.container);
|
|
||||||
};
|
|
||||||
|
|
||||||
CropEditor.prototype.setInputValues = function() {
|
|
||||||
var current = this.thumbnail_select.options[this.thumbnail_select.selectedIndex].dataset;
|
|
||||||
|
|
||||||
if (typeof current.crop_region === "undefined") {
|
|
||||||
var source_ratio = this.original_image.naturalWidth / this.original_image.naturalHeight,
|
|
||||||
crop_ratio = current.crop_width / current.crop_height,
|
|
||||||
min_dim = Math.min(this.original_image.naturalWidth, this.original_image.naturalHeight);
|
|
||||||
|
|
||||||
// Cropping from the centre?
|
|
||||||
if (current.crop_method === "c") {
|
|
||||||
// Crop vertically from the centre, using the entire width.
|
|
||||||
if (source_ratio < crop_ratio) {
|
|
||||||
this.crop_width.value = this.original_image.naturalWidth;
|
|
||||||
this.crop_height.value = Math.ceil(this.original_image.naturalWidth / crop_ratio);
|
|
||||||
this.source_x.value = 0;
|
|
||||||
this.source_y.value = Math.ceil((this.original_image.naturalHeight - this.crop_height.value) / 2);
|
|
||||||
}
|
|
||||||
// Crop horizontally from the centre, using the entire height.
|
|
||||||
else {
|
|
||||||
this.crop_width.value = Math.ceil(current.crop_width * this.original_image.naturalHeight / current.crop_height);
|
|
||||||
this.crop_height.value = this.original_image.naturalHeight;
|
|
||||||
this.source_x.value = Math.ceil((this.original_image.naturalWidth - this.crop_width.value) / 2);
|
|
||||||
this.source_y.value = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Cropping a top or bottom slice?
|
|
||||||
else {
|
|
||||||
// Can we actually take a top or bottom slice from the original image?
|
|
||||||
if (source_ratio < crop_ratio) {
|
|
||||||
this.crop_width.value = this.original_image.naturalWidth;
|
|
||||||
this.crop_height.value = Math.floor(this.original_image.naturalHeight / crop_ratio);
|
|
||||||
this.source_x.value = "0";
|
|
||||||
this.source_y.value = current.crop_method.indexOf("t") !== -1 ? "0" : this.original_image.naturalHeight - this.crop_height.value;
|
|
||||||
}
|
|
||||||
// Otherwise, take a vertical slice from the centre.
|
|
||||||
else {
|
|
||||||
this.crop_width.value = Math.floor(this.original_image.naturalHeight * crop_ratio);
|
|
||||||
this.crop_height.value = this.original_image.naturalHeight;
|
|
||||||
this.source_x.value = Math.floor((this.original_image.naturalWidth - this.crop_width.value) / 2);
|
|
||||||
this.source_y.value = "0";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var region = current.crop_region.split(',');
|
|
||||||
this.crop_width.value = region[0];
|
|
||||||
this.crop_height.value = region[1];
|
|
||||||
this.source_x.value = region[2];
|
|
||||||
this.source_y.value = region[3];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
CropEditor.prototype.showContainer = function() {
|
|
||||||
this.container.style.display = "block";
|
|
||||||
this.setInputValues();
|
|
||||||
this.positionBoundary();
|
|
||||||
}
|
|
||||||
|
|
||||||
CropEditor.prototype.save = function() {
|
|
||||||
var current = this.thumbnail_select.options[this.thumbnail_select.selectedIndex].dataset;
|
|
||||||
var payload = {
|
|
||||||
thumb_width: current.crop_width,
|
|
||||||
thumb_height: current.crop_height,
|
|
||||||
crop_method: current.crop_method,
|
|
||||||
crop_width: this.crop_width.value,
|
|
||||||
crop_height: this.crop_height.value,
|
|
||||||
source_x: this.source_x.value,
|
|
||||||
source_y: this.source_y.value
|
|
||||||
};
|
|
||||||
var req = HttpRequest("post", this.opt.submitUrl + "?id=" + this.opt.asset_id + "&updatethumb",
|
|
||||||
"data=" + encodeURIComponent(JSON.stringify(payload)), function(response) {
|
|
||||||
this.opt.after_save(response);
|
|
||||||
this.hide();
|
|
||||||
}.bind(this));
|
|
||||||
};
|
|
||||||
|
|
||||||
CropEditor.prototype.show = function() {
|
|
||||||
if (typeof this.container === "undefined") {
|
|
||||||
this.buildContainer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Defer showing and positioning until image is loaded.
|
buildContainer() {
|
||||||
// !!! TODO: add a spinner in the mean time?
|
this.container = document.createElement("div");
|
||||||
if (this.original_image.naturalWidth > 0) {
|
this.container.id = "crop_editor";
|
||||||
this.showContainer();
|
|
||||||
} else {
|
this.position = document.createElement("div");
|
||||||
this.original_image.addEventListener("load", function() {
|
this.position.className = "crop_position";
|
||||||
|
this.container.appendChild(this.position);
|
||||||
|
|
||||||
|
let source_x_label = document.createTextNode("Source X:");
|
||||||
|
this.position.appendChild(source_x_label);
|
||||||
|
|
||||||
|
this.source_x = document.createElement("input");
|
||||||
|
this.source_x.addEventListener("keyup", this.positionBoundary.bind(this));
|
||||||
|
this.position.appendChild(this.source_x);
|
||||||
|
|
||||||
|
let source_y_label = document.createTextNode("Source Y:");
|
||||||
|
this.position.appendChild(source_y_label);
|
||||||
|
|
||||||
|
this.source_y = document.createElement("input");
|
||||||
|
this.source_y.addEventListener("keyup", this.positionBoundary.bind(this));
|
||||||
|
this.position.appendChild(this.source_y);
|
||||||
|
|
||||||
|
let crop_width_label = document.createTextNode("Crop width:");
|
||||||
|
this.position.appendChild(crop_width_label);
|
||||||
|
|
||||||
|
this.crop_width = document.createElement("input");
|
||||||
|
this.crop_width.addEventListener("keyup", this.positionBoundary.bind(this));
|
||||||
|
this.position.appendChild(this.crop_width);
|
||||||
|
|
||||||
|
let crop_height_label = document.createTextNode("Crop height:");
|
||||||
|
this.position.appendChild(crop_height_label);
|
||||||
|
|
||||||
|
this.crop_height = document.createElement("input");
|
||||||
|
this.crop_height.addEventListener("keyup", this.positionBoundary.bind(this));
|
||||||
|
this.position.appendChild(this.crop_height);
|
||||||
|
|
||||||
|
this.save_button = document.createElement("span");
|
||||||
|
this.save_button.className = "btn";
|
||||||
|
this.save_button.textContent = "Save";
|
||||||
|
this.save_button.addEventListener('click', this.save.bind(this));
|
||||||
|
this.position.appendChild(this.save_button);
|
||||||
|
|
||||||
|
this.abort_button = document.createElement("span");
|
||||||
|
this.abort_button.className = "btn btn-red";
|
||||||
|
this.abort_button.textContent = "Abort";
|
||||||
|
this.abort_button.addEventListener('click', this.hide.bind(this));
|
||||||
|
this.position.appendChild(this.abort_button);
|
||||||
|
|
||||||
|
this.image_container = document.createElement("div");
|
||||||
|
this.image_container.className = "crop_image_container";
|
||||||
|
this.container.appendChild(this.image_container);
|
||||||
|
|
||||||
|
this.crop_boundary = document.createElement("div");
|
||||||
|
this.crop_boundary.id = "crop_boundary";
|
||||||
|
this.image_container.appendChild(this.crop_boundary);
|
||||||
|
|
||||||
|
this.original_image = document.createElement("img");
|
||||||
|
this.original_image.id = "original_image";
|
||||||
|
this.original_image.src = this.opt.original_image_src;
|
||||||
|
this.image_container.appendChild(this.original_image);
|
||||||
|
|
||||||
|
this.parent = document.getElementById(this.opt.editor_container_parent_id);
|
||||||
|
this.parent.appendChild(this.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
setInputValues() {
|
||||||
|
let current = this.thumbnail_select.options[this.thumbnail_select.selectedIndex].dataset;
|
||||||
|
|
||||||
|
if (typeof current.crop_region === "undefined") {
|
||||||
|
let source_ratio = this.original_image.naturalWidth / this.original_image.naturalHeight,
|
||||||
|
crop_ratio = current.crop_width / current.crop_height,
|
||||||
|
min_dim = Math.min(this.original_image.naturalWidth, this.original_image.naturalHeight);
|
||||||
|
|
||||||
|
// Cropping from the centre?
|
||||||
|
if (current.crop_method === "c") {
|
||||||
|
// Crop vertically from the centre, using the entire width.
|
||||||
|
if (source_ratio < crop_ratio) {
|
||||||
|
this.crop_width.value = this.original_image.naturalWidth;
|
||||||
|
this.crop_height.value = Math.ceil(this.original_image.naturalWidth / crop_ratio);
|
||||||
|
this.source_x.value = 0;
|
||||||
|
this.source_y.value = Math.ceil((this.original_image.naturalHeight - this.crop_height.value) / 2);
|
||||||
|
}
|
||||||
|
// Crop horizontally from the centre, using the entire height.
|
||||||
|
else {
|
||||||
|
this.crop_width.value = Math.ceil(current.crop_width * this.original_image.naturalHeight / current.crop_height);
|
||||||
|
this.crop_height.value = this.original_image.naturalHeight;
|
||||||
|
this.source_x.value = Math.ceil((this.original_image.naturalWidth - this.crop_width.value) / 2);
|
||||||
|
this.source_y.value = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Cropping a top or bottom slice?
|
||||||
|
else {
|
||||||
|
// Can we actually take a top or bottom slice from the original image?
|
||||||
|
if (source_ratio < crop_ratio) {
|
||||||
|
this.crop_width.value = this.original_image.naturalWidth;
|
||||||
|
this.crop_height.value = Math.floor(this.original_image.naturalHeight / crop_ratio);
|
||||||
|
this.source_x.value = "0";
|
||||||
|
this.source_y.value = current.crop_method.indexOf("t") !== -1 ? "0" : this.original_image.naturalHeight - this.crop_height.value;
|
||||||
|
}
|
||||||
|
// Otherwise, take a vertical slice from the centre.
|
||||||
|
else {
|
||||||
|
this.crop_width.value = Math.floor(this.original_image.naturalHeight * crop_ratio);
|
||||||
|
this.crop_height.value = this.original_image.naturalHeight;
|
||||||
|
this.source_x.value = Math.floor((this.original_image.naturalWidth - this.crop_width.value) / 2);
|
||||||
|
this.source_y.value = "0";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let region = current.crop_region.split(',');
|
||||||
|
this.crop_width.value = region[0];
|
||||||
|
this.crop_height.value = region[1];
|
||||||
|
this.source_x.value = region[2];
|
||||||
|
this.source_y.value = region[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
showContainer() {
|
||||||
|
this.container.style.display = "block";
|
||||||
|
this.setInputValues();
|
||||||
|
this.positionBoundary();
|
||||||
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
let current = this.thumbnail_select.options[this.thumbnail_select.selectedIndex].dataset;
|
||||||
|
let payload = {
|
||||||
|
thumb_width: current.crop_width,
|
||||||
|
thumb_height: current.crop_height,
|
||||||
|
crop_method: current.crop_method,
|
||||||
|
crop_width: this.crop_width.value,
|
||||||
|
crop_height: this.crop_height.value,
|
||||||
|
source_x: this.source_x.value,
|
||||||
|
source_y: this.source_y.value
|
||||||
|
};
|
||||||
|
let req = HttpRequest("post", this.opt.submitUrl + "?id=" + this.opt.asset_id + "&updatethumb",
|
||||||
|
"data=" + encodeURIComponent(JSON.stringify(payload)), function(response) {
|
||||||
|
this.opt.after_save(response);
|
||||||
|
this.hide();
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
if (typeof this.container === "undefined") {
|
||||||
|
this.buildContainer();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defer showing and positioning until image is loaded.
|
||||||
|
// !!! TODO: add a spinner in the mean time?
|
||||||
|
if (this.original_image.naturalWidth > 0) {
|
||||||
this.showContainer();
|
this.showContainer();
|
||||||
}.bind(this));
|
} else {
|
||||||
|
this.original_image.addEventListener("load", function() {
|
||||||
|
this.showContainer();
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
CropEditor.prototype.hide = function() {
|
hide() {
|
||||||
this.container.style.display = "none";
|
this.container.style.display = "none";
|
||||||
};
|
}
|
||||||
|
|
||||||
CropEditor.prototype.addEvents = function(event) {
|
addEvents(event) {
|
||||||
var drag_target = document.getElementById(opt.drag_target);
|
let drag_target = document.getElementById(opt.drag_target);
|
||||||
drag_target.addEventListener('dragstart', this.dragStart);
|
drag_target.addEventListener('dragstart', this.dragStart);
|
||||||
drag_target.addEventListener('drag', this.drag);
|
drag_target.addEventListener('drag', this.drag);
|
||||||
drag_target.addEventListener('dragend', this.dragEnd);
|
drag_target.addEventListener('dragend', this.dragEnd);
|
||||||
};
|
}
|
||||||
|
|
||||||
CropEditor.prototype.dragStart = function(event) {
|
dragStart(event) {
|
||||||
console.log(event);
|
console.log(event);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
};
|
}
|
||||||
|
|
||||||
CropEditor.prototype.dragEnd = function(event) {
|
dragEnd(event) {
|
||||||
console.log(event);
|
console.log(event);
|
||||||
};
|
}
|
||||||
|
|
||||||
CropEditor.prototype.drag = function(event) {
|
drag(event) {
|
||||||
console.log(event);
|
console.log(event);
|
||||||
};
|
}
|
||||||
|
|
||||||
CropEditor.prototype.toggleCropButton = function() {
|
toggleCropButton() {
|
||||||
var current = this.thumbnail_select.options[this.thumbnail_select.selectedIndex].dataset;
|
let current = this.thumbnail_select.options[this.thumbnail_select.selectedIndex].dataset;
|
||||||
this.edit_crop_button.style.display = typeof current.crop_method === "undefined" ? "none" : "";
|
this.edit_crop_button.style.display = typeof current.crop_method === "undefined" ? "none" : "";
|
||||||
};
|
}
|
||||||
|
|
||||||
CropEditor.prototype.positionBoundary = function(event) {
|
positionBoundary(event) {
|
||||||
var source_x = parseInt(this.source_x.value),
|
let source_x = parseInt(this.source_x.value),
|
||||||
source_y = parseInt(this.source_y.value),
|
source_y = parseInt(this.source_y.value),
|
||||||
crop_width = parseInt(this.crop_width.value),
|
crop_width = parseInt(this.crop_width.value),
|
||||||
crop_height = parseInt(this.crop_height.value),
|
crop_height = parseInt(this.crop_height.value),
|
||||||
real_width = this.original_image.naturalWidth,
|
real_width = this.original_image.naturalWidth,
|
||||||
real_height = this.original_image.naturalHeight,
|
real_height = this.original_image.naturalHeight,
|
||||||
scaled_width = this.original_image.clientWidth,
|
scaled_width = this.original_image.clientWidth,
|
||||||
scaled_height = this.original_image.clientHeight;
|
scaled_height = this.original_image.clientHeight;
|
||||||
|
|
||||||
var width_scale = scaled_width / real_width,
|
let width_scale = scaled_width / real_width,
|
||||||
height_scale = scaled_height / real_height;
|
height_scale = scaled_height / real_height;
|
||||||
|
|
||||||
crop_boundary.style.left = (this.source_x.value) * width_scale + "px";
|
crop_boundary.style.left = (this.source_x.value) * width_scale + "px";
|
||||||
crop_boundary.style.top = (this.source_y.value) * height_scale + "px";
|
crop_boundary.style.top = (this.source_y.value) * height_scale + "px";
|
||||||
crop_boundary.style.width = (this.crop_width.value) * width_scale + "px";
|
crop_boundary.style.width = (this.crop_width.value) * width_scale + "px";
|
||||||
crop_boundary.style.height = (this.crop_height.value) * height_scale + "px";
|
crop_boundary.style.height = (this.crop_height.value) * height_scale + "px";
|
||||||
};
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user