Skip to content

Commit 7be9565

Browse files
committed
fix + smooth magnify image
1 parent cb8459e commit 7be9565

File tree

2 files changed

+107
-53
lines changed

2 files changed

+107
-53
lines changed

scripts/content-scripts/ufs_global.js

Lines changed: 93 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const UfsGlobal = {
1717
closest,
1818
addLoadingAnimation,
1919
addLoadingAnimationAtPos,
20+
addEventListener,
2021
enableDragAndZoom,
2122
getContentClientRect,
2223
dataURLToCanvas,
@@ -46,6 +47,7 @@ export const UfsGlobal = {
4647
getWatchingVideoSrc,
4748
},
4849
Utils: {
50+
lerp,
4951
getNumberFormatter,
5052
deepClone,
5153
debounce,
@@ -276,11 +278,20 @@ function addLoadingAnimation(
276278
if (element) element.classList.remove("ufs-loading-" + id);
277279
};
278280
}
281+
function addEventListener(target, event, callback, options) {
282+
target.addEventListener(event, callback, options);
283+
return () => target.removeEventListener(event, callback, options);
284+
}
279285
function enableDragAndZoom(element, container, callback) {
280286
// set style
281-
element.style.cssText += `
287+
const className = "ufs-drag-and-zoom";
288+
element.classList.add(className);
289+
290+
let style = document.createElement("style");
291+
style.textContent = `
292+
.${className} {
282293
cursor: grab;
283-
position: relative;
294+
position: relative !important;
284295
-webkit-user-select: none !important;
285296
-moz-user-select: none !important;
286297
-ms-user-select: none !important;
@@ -291,85 +302,122 @@ function enableDragAndZoom(element, container, callback) {
291302
min-width: unset !important;
292303
min-height: unset !important;
293304
-webkit-user-drag: none !important;
294-
`;
305+
}`;
306+
(container || element).appendChild(style);
295307

296-
// Variables to track the current position
297-
let lastX = 0;
298-
let lastY = 0;
308+
// config
299309
let dragging = false;
300-
let mouse = { x: 0, y: 0 };
310+
const lerpSpeed = 0.3;
311+
const last = { x: 0, y: 0 };
312+
const mouse = { x: 0, y: 0 };
313+
const animTarget = {
314+
left: parseFloat(element.style.left),
315+
top: parseFloat(element.style.top),
316+
width: parseFloat(element.style.width),
317+
height: parseFloat(element.style.height),
318+
};
319+
320+
let animationId;
321+
function animate() {
322+
for (let prop in animTarget) {
323+
element.style[prop] =
324+
lerp(parseFloat(element.style[prop]), animTarget[prop], lerpSpeed) +
325+
"px";
326+
}
327+
328+
animationId = requestAnimationFrame(animate);
329+
}
330+
331+
animate();
301332

302333
// Mouse down event listener
303-
(container || element).addEventListener("mousedown", function (e) {
334+
let _down = addEventListener(container || element, "mousedown", function (e) {
304335
e.preventDefault();
305336
dragging = true;
306-
lastX = e.clientX;
307-
lastY = e.clientY;
337+
last.x = e.clientX;
338+
last.y = e.clientY;
308339
element.style.cursor = "grabbing";
309340
});
310341

311342
// Mouse move event listener
312-
document.addEventListener("mousemove", function (e) {
313-
mouse = { x: e.clientX, y: e.clientY };
343+
let _move = addEventListener(document, "mousemove", function (e) {
344+
mouse.x = e.clientX;
345+
mouse.y = e.clientY;
314346
if (dragging) {
315-
let x = e.clientX - lastX + element.offsetLeft;
316-
let y = e.clientY - lastY + element.offsetTop;
347+
let delX = e.clientX - last.x;
348+
let delY = e.clientY - last.y;
317349

318-
element.style.left = x + "px";
319-
element.style.top = y + "px";
320-
callback?.({ x, y, type: "move" });
350+
animTarget.left += delX;
351+
animTarget.top += delY;
352+
callback?.({ ...animTarget, type: "move" });
321353

322-
lastX = e.clientX;
323-
lastY = e.clientY;
354+
last.x = e.clientX;
355+
last.y = e.clientY;
324356
}
325357
});
326358

327359
// Mouse up event listener
328-
document.addEventListener("mouseup", function () {
360+
let _up = addEventListener(document, "mouseup", function () {
329361
dragging = false;
330362
element.style.cursor = "grab";
331363
});
332364

333365
// Mouse leave event listener
334-
document.addEventListener("mouseleave", function () {
366+
let _leave = addEventListener(document, "mouseleave", function () {
335367
dragging = false;
336368
element.style.cursor = "grab";
337369
});
338370

339371
// Mouse wheel event listener for zooming
340-
(container || element).addEventListener("wheel", function (e) {
372+
let _wheel = addEventListener(container || element, "wheel", function (e) {
341373
e.preventDefault();
342374

343375
let curScale = parseFloat(element.style.width) / element.width;
344376
let delta = -e.wheelDeltaY || -e.wheelDelta;
345-
let factor = Math.abs((0.1 * delta) / 120);
346-
let scale = delta > 0 ? curScale * (1 - factor) : curScale * (1 + factor);
377+
let factor = Math.abs((0.3 * delta) / 120);
378+
let newScale =
379+
delta > 0 ? curScale * (1 - factor) : curScale * (1 + factor);
347380

348-
// Adjust scale at mouse position
349-
let offsetX = mouse.x - element.offsetLeft;
350-
let offsetY = mouse.y - element.offsetTop;
381+
let newWidth = element.width * newScale;
382+
let newHeight = element.height * newScale;
351383

352-
let newWidth = element.width * scale;
353-
let newHeight = element.height * scale;
354-
355-
if (newWidth < 3 || newHeight < 3) {
384+
if (newWidth < 10 || newHeight < 10) {
356385
return;
357386
}
358387

359-
let newLeft =
360-
element.offsetLeft -
361-
(newWidth - element.width) * (offsetX / element.width);
388+
let left = parseFloat(element.style.left);
389+
let top = parseFloat(element.style.top);
390+
let offsetX = mouse.x - left;
391+
let offsetY = mouse.y - top;
392+
393+
let newLeft = left - (newWidth - element.width) * (offsetX / element.width);
362394
let newTop =
363-
element.offsetTop -
364-
(newHeight - element.height) * (offsetY / element.height);
395+
top - (newHeight - element.height) * (offsetY / element.height);
365396

366-
element.style.width = newWidth + "px";
367-
element.style.height = newHeight + "px";
368-
element.style.left = newLeft + "px";
369-
element.style.top = newTop + "px";
397+
animTarget.left = newLeft;
398+
animTarget.top = newTop;
399+
animTarget.width = newWidth;
400+
animTarget.height = newHeight;
370401

371402
callback?.({ type: "scale" });
372403
});
404+
405+
let listeners = [_down, _move, _up, _leave, _wheel];
406+
407+
return {
408+
animateTo: (x, y, w, h) => {
409+
animTarget.left = x;
410+
animTarget.top = y;
411+
animTarget.width = w;
412+
animTarget.height = h;
413+
},
414+
destroy: () => {
415+
cancelAnimationFrame(animationId);
416+
style.remove();
417+
element.classList.remove(className);
418+
listeners.forEach((l) => l?.());
419+
},
420+
};
373421
}
374422
// prettier-ignore
375423
function getContentClientRect(target) {
@@ -859,6 +907,11 @@ function getWatchingVideoSrc() {
859907
// #endregion
860908

861909
// #region Utils
910+
911+
function lerp(from, to, speed) {
912+
return from + (to - from) * speed;
913+
}
914+
862915
const numberFormatCached = {};
863916
/**
864917
* Get number formatter

scripts/magnify_image.js

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -628,14 +628,14 @@ function createPreview(
628628
// container
629629
let overlay = document.createElement("div");
630630
overlay.id = id;
631-
overlay.onclick = (e) => {
632-
e.preventDefault();
631+
overlay.addEventListener("click", (e) => {
633632
if (e.target == overlay) {
634633
overlay.remove();
635634
overlay = null;
635+
destroy();
636636
onClose?.();
637637
}
638-
};
638+
});
639639
document.body.appendChild(overlay);
640640

641641
// animation div: a rect that represent image scaled up from original position (mouse position)
@@ -710,6 +710,16 @@ function createPreview(
710710
};
711711
overlay.appendChild(img);
712712

713+
let { destroy, animateTo } = UfsGlobal.DOM.enableDragAndZoom(
714+
img,
715+
overlay,
716+
(data) => {
717+
if (data?.type === "scale") {
718+
updateZoom();
719+
}
720+
}
721+
);
722+
713723
// toolbar
714724
let toolbar = document.createElement("div");
715725
toolbar.classList.add("ufs-toolbar");
@@ -760,10 +770,7 @@ function createPreview(
760770
h = newSize.height;
761771
}
762772

763-
img.style.width = w + "px";
764-
img.style.height = h + "px";
765-
img.style.left = window.innerWidth / 2 + "px";
766-
img.style.top = window.innerHeight / 2 + "px";
773+
animateTo(window.innerWidth / 2, window.innerHeight / 2, w, h);
767774

768775
updateZoom();
769776
};
@@ -927,12 +934,6 @@ function createPreview(
927934
desc
928935
);
929936

930-
UfsGlobal.DOM.enableDragAndZoom(img, overlay, (data) => {
931-
if (data?.type === "scale") {
932-
updateZoom();
933-
}
934-
});
935-
936937
// auto get largest image
937938
let loadingRef,
938939
notiRef = UfsGlobal.DOM.notify({

0 commit comments

Comments
 (0)