[ui] custom canvas-based image fragment rendering (allow resizing)
parent
5051ac25c6
commit
04615b3682
|
@ -39,6 +39,7 @@
|
|||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
|
|
|
@ -204,10 +204,10 @@
|
|||
min-height: 0;
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-image {
|
||||
margin: auto;
|
||||
.preview-image {
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.r6o-editor {
|
||||
|
|
|
@ -43,24 +43,20 @@ export function xywh(mediaItem: HTMLImageElement | HTMLVideoElement) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Applies the media fragment when the image has loaded. We need the image's
|
||||
* original width and height.
|
||||
* Applies the media fragment when the image has loaded.
|
||||
*/
|
||||
function addImageLoadListener(mediaFragment: MediaFragment) {
|
||||
// Base64-encoded transparent 1x1 pixel GIF
|
||||
const TRANSPARENT_GIF =
|
||||
"data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
|
||||
const mediaItem = mediaFragment.mediaItem;
|
||||
const onload = function () {
|
||||
// Prevent onload firing when the 1x1 pixel GIF loads; but still react when `src`
|
||||
// is changed programatically.
|
||||
if (mediaItem.src !== TRANSPARENT_GIF) {
|
||||
// Prevent onload firing when the fragment loads; but still react when `src`
|
||||
// is changed programatically.
|
||||
let lastSrc: string;
|
||||
function onload() {
|
||||
if (mediaItem.src !== lastSrc) {
|
||||
// Required on reloads because of size calculations.
|
||||
mediaItem.style.cssText = "";
|
||||
applyFragment(mediaFragment);
|
||||
mediaItem.src = TRANSPARENT_GIF;
|
||||
lastSrc = mediaItem.src;
|
||||
}
|
||||
};
|
||||
}
|
||||
mediaItem.addEventListener("load", onload);
|
||||
}
|
||||
|
||||
|
@ -86,34 +82,26 @@ function addVideoLoadListener(mediaFragment: MediaFragment) {
|
|||
* 2D transformation according to the fragment's x and y values.
|
||||
*/
|
||||
function applyFragment(fragment: MediaFragment) {
|
||||
let x: string, y: string, w: string, h: string;
|
||||
const originalWidth =
|
||||
fragment.mediaType === "img"
|
||||
? fragment.mediaItem.width
|
||||
: fragment.mediaItem.videoWidth;
|
||||
const originalHeight =
|
||||
fragment.mediaType === "img"
|
||||
? fragment.mediaItem.height
|
||||
: fragment.mediaItem.videoHeight;
|
||||
// Unit is pixel:
|
||||
if (fragment.unit === "pixel:") {
|
||||
const scale =
|
||||
fragment.mediaType === "img"
|
||||
? originalWidth / fragment.mediaItem.naturalWidth
|
||||
: originalWidth / fragment.mediaItem.clientWidth;
|
||||
w = fragment.w * scale + "px";
|
||||
h = fragment.h * scale + "px";
|
||||
x = "-" + fragment.x * scale + "px";
|
||||
y = "-" + fragment.y * scale + "px";
|
||||
// Unit is percent:
|
||||
} else {
|
||||
w = (originalWidth * fragment.w) / 100 + "px";
|
||||
h = (originalHeight * fragment.h) / 100 + "px";
|
||||
x = "-" + (originalWidth * fragment.x) / 100 + "px";
|
||||
y = "-" + (originalHeight * fragment.y) / 100 + "px";
|
||||
}
|
||||
// Media item is a video
|
||||
if (fragment.mediaType === "video") {
|
||||
let x: string, y: string, w: string, h: string;
|
||||
const originalWidth = fragment.mediaItem.videoWidth;
|
||||
const originalHeight = fragment.mediaItem.videoHeight;
|
||||
// Unit is pixel:
|
||||
if (fragment.unit === "pixel:") {
|
||||
const scale = originalWidth / fragment.mediaItem.clientWidth;
|
||||
w = fragment.w * scale + "px";
|
||||
h = fragment.h * scale + "px";
|
||||
x = "-" + fragment.x * scale + "px";
|
||||
y = "-" + fragment.y * scale + "px";
|
||||
// Unit is percent:
|
||||
} else {
|
||||
w = (originalWidth * fragment.w) / 100 + "px";
|
||||
h = (originalHeight * fragment.h) / 100 + "px";
|
||||
x = "-" + (originalWidth * fragment.x) / 100 + "px";
|
||||
y = "-" + (originalHeight * fragment.y) / 100 + "px";
|
||||
}
|
||||
|
||||
const wrapper = document.createElement("div");
|
||||
wrapper.style.cssText +=
|
||||
"overflow:hidden;" +
|
||||
|
@ -148,25 +136,23 @@ function applyFragment(fragment: MediaFragment) {
|
|||
}
|
||||
// Media item is an image
|
||||
} else {
|
||||
fragment.mediaItem.style.cssText +=
|
||||
"width:" +
|
||||
w +
|
||||
";" +
|
||||
"height:" +
|
||||
h +
|
||||
";" +
|
||||
"background:url(" +
|
||||
fragment.mediaItem.src +
|
||||
") " + // background-image
|
||||
"no-repeat " + // background-repeat
|
||||
x +
|
||||
" " +
|
||||
y +
|
||||
"; " + // background-position
|
||||
"background-size: " +
|
||||
originalWidth +
|
||||
"px " +
|
||||
originalHeight +
|
||||
"px;";
|
||||
let x: number, y: number, w: number, h: number;
|
||||
if (fragment.unit === "pixel:") {
|
||||
x = fragment.x;
|
||||
y = fragment.y;
|
||||
w = fragment.w;
|
||||
h = fragment.h;
|
||||
} else {
|
||||
x = (fragment.x / 100) * fragment.mediaItem.naturalWidth;
|
||||
y = (fragment.y / 100) * fragment.mediaItem.naturalHeight;
|
||||
w = (fragment.w / 100) * fragment.mediaItem.naturalWidth;
|
||||
h = (fragment.h / 100) * fragment.mediaItem.naturalHeight;
|
||||
}
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = w;
|
||||
canvas.height = h;
|
||||
const context = canvas.getContext("2d");
|
||||
context.drawImage(fragment.mediaItem, x, y, w, h, 0, 0, w, h);
|
||||
fragment.mediaItem.src = canvas.toDataURL();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue