diff --git a/thrimbletrimmer/edit.html b/thrimbletrimmer/edit.html
index 03e82d9..3916f3c 100644
--- a/thrimbletrimmer/edit.html
+++ b/thrimbletrimmer/edit.html
@@ -267,7 +267,7 @@
Update Source Images
-
+
-
+
+
+
+
+ Aspect Ratio
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{
templateImageElement.src = `/thrimshim/template/${imageTemplate}.png`;
templateImageElement.classList.remove("hidden");
+ const aspectRatioControls = document.getElementById("video-info-thumbnail-aspect-ratio-controls");
+ aspectRatioControls.classList.remove("hidden");
+
createTemplateCropWidgets();
});
@@ -302,6 +305,36 @@ window.addEventListener("DOMContentLoaded", async (event) => {
document.getElementById("video-info-thumbnail-location-2").addEventListener("input", updateTemplateCropWidgets);
document.getElementById("video-info-thumbnail-location-3").addEventListener("input", updateTemplateCropWidgets);
+ document.getElementById("video-info-thumbnail-lock-aspect-ratio").addEventListener("change", updateTemplateCropAspectRatio);
+
+ document.getElementById("video-info-thumbnail-aspect-ratio-match-right").addEventListener("click", function(){
+ // Calculate and copy the aspect ratio from the video field to the template
+ const videoFieldX1 = document.getElementById("video-info-thumbnail-crop-0");
+ const videoFieldY1 = document.getElementById("video-info-thumbnail-crop-1");
+ const videoFieldX2 = document.getElementById("video-info-thumbnail-crop-2");
+ const videoFieldY2 = document.getElementById("video-info-thumbnail-crop-3");
+ const videoFieldAspectRatio = (videoFieldX2.value-videoFieldX1.value)/(videoFieldY2.value-videoFieldY1.value);
+
+ templateStage.setOptions({aspectRatio: videoFieldAspectRatio});
+
+ // Re-apply the locked/unlocked status
+ updateTemplateCropAspectRatio();
+ });
+
+ document.getElementById("video-info-thumbnail-aspect-ratio-match-left").addEventListener("click", function(){
+ // Calculate and copy the aspect ratio from the template to the video field
+ const templateFieldX1 = document.getElementById("video-info-thumbnail-location-0");
+ const templateFieldY1 = document.getElementById("video-info-thumbnail-location-1");
+ const templateFieldX2 = document.getElementById("video-info-thumbnail-location-2");
+ const templateFieldY2 = document.getElementById("video-info-thumbnail-location-3");
+ const templateFieldAspectRatio = (templateFieldX2.value-templateFieldX1.value)/(templateFieldY2.value-templateFieldY1.value);
+
+ videoFrameStage.setOptions({aspectRatio: templateFieldAspectRatio});
+
+ // Re-apply the locked/unlocked status
+ updateTemplateCropAspectRatio();
+ });
+
document
.getElementById("video-info-thumbnail-template-preview-generate")
.addEventListener("click", async (_event) => {
@@ -2214,29 +2247,37 @@ function createTemplateCropWidgets() {
const fieldX2 = document.getElementById("video-info-thumbnail-crop-2");
const fieldY2 = document.getElementById("video-info-thumbnail-crop-3");
// 640x320 -> 1920x1080
- fieldX1.value = pos.x*3;
- fieldY1.value = pos.y*3;
- fieldX2.value = (pos.x+pos.w)*3;
- fieldY2.value = (pos.y+pos.h)*3;
+ fieldX1.value = Math.round(pos.x*3);
+ fieldY1.value = Math.round(pos.y*3);
+ fieldX2.value = Math.round((pos.x+pos.w)*3);
+ fieldY2.value = Math.round((pos.y+pos.h)*3);
+ });
+ videoFrameStage.listen('crop.change',function(widget,e){
+ // This only fires when the user is finished dragging, not every time the size
+ // of the cropped area updates. This avoids the template area updating every
+ // instant due to minute changes in the aspect ratio, which causes it to shrink
+ // while resizing.
+ updateTemplateCropAspectRatio();
});
}
if (templateStage == null) {
templateStage = Jcrop.attach('video-info-thumbnail-template-overlay-image');
- templateStage.listen('crop.change',function(widget,e){
+ templateStage.listen('crop.update',function(widget,e){
const pos = widget.pos;
const fieldX1 = document.getElementById("video-info-thumbnail-location-0");
const fieldY1 = document.getElementById("video-info-thumbnail-location-1");
const fieldX2 = document.getElementById("video-info-thumbnail-location-2");
const fieldY2 = document.getElementById("video-info-thumbnail-location-3");
// 640x320 -> 1280x720
- fieldX1.value = pos.x*2;
- fieldY1.value = pos.y*2;
- fieldX2.value = (pos.x+pos.w)*2;
- fieldY2.value = (pos.y+pos.h)*2;
+ fieldX1.value = Math.round(pos.x*2);
+ fieldY1.value = Math.round(pos.y*2);
+ fieldX2.value = Math.round((pos.x+pos.w)*2);
+ fieldY2.value = Math.round((pos.y+pos.h)*2);
});
}
updateTemplateCropWidgets();
+ updateTemplateCropAspectRatio();
}
/**
@@ -2269,4 +2310,22 @@ function updateTemplateCropWidgets() {
templateStage.active.pos = templateRect;
templateStage.active.render();
}
+
+ updateTemplateCropAspectRatio();
+}
+
+function updateTemplateCropAspectRatio() {
+ const aspectRatioCheckbox = document.getElementById("video-info-thumbnail-lock-aspect-ratio");
+ if (aspectRatioCheckbox.checked) {
+ const videoFieldX1 = document.getElementById("video-info-thumbnail-crop-0");
+ const videoFieldY1 = document.getElementById("video-info-thumbnail-crop-1");
+ const videoFieldX2 = document.getElementById("video-info-thumbnail-crop-2");
+ const videoFieldY2 = document.getElementById("video-info-thumbnail-crop-3");
+ const videoFieldAspectRatio = (videoFieldX2.value-videoFieldX1.value)/(videoFieldY2.value-videoFieldY1.value);
+ videoFrameStage.setOptions({aspectRatio: videoFieldAspectRatio});
+ templateStage.setOptions({aspectRatio: videoFieldAspectRatio});
+ } else {
+ videoFrameStage.setOptions({aspectRatio: null});
+ templateStage.setOptions({aspectRatio: null});
+ }
}
diff --git a/thrimbletrimmer/styles/thrimbletrimmer.css b/thrimbletrimmer/styles/thrimbletrimmer.css
index e170b97..005381a 100644
--- a/thrimbletrimmer/styles/thrimbletrimmer.css
+++ b/thrimbletrimmer/styles/thrimbletrimmer.css
@@ -381,6 +381,18 @@ input.range-definition-chapter-marker-description {
.video-info-thumbnail-advanced-crop-flex-wrapper {
display: flex;
+ align-items: center;
+}
+
+.video-info-thumbnail-advanced-crop-flex-column {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+}
+
+.video-info-thumbnail-advanced-crop-flex-column div {
+ margin: 0.5em;
}
.submission-response-error {