fix(web): предпросмотр правок работает и без зума
Клиентский предпросмотр был включён только в зуме, поэтому в обычном виде просмотра фото оставалось без правок. Теперь холст рисует ту часть картинки, что попала во вьюпорт, в любом режиме, а под ним лежит неотредактированная версия фото — так правки не применяются дважды.
This commit is contained in:
@@ -77,6 +77,8 @@
|
||||
''
|
||||
);
|
||||
const originalSrc = $derived(fresh?.original_url ?? current?.original_url ?? '');
|
||||
// Базовые (неотредактированные) версии: на них браузер рисует предпросмотр.
|
||||
const basePreviewSrc = $derived(fresh?.preview_url ?? current?.preview_url ?? '');
|
||||
|
||||
// Пока сервер не отрендерил текущие правки, видимую область фото рисует
|
||||
// сам браузер: правки видны сразу, без ожидания рендера.
|
||||
@@ -91,12 +93,15 @@
|
||||
JSON.stringify(edit.params) !== JSON.stringify(savedParams)
|
||||
);
|
||||
const needClientRender = $derived(hasEdits && (pending || !editUrl));
|
||||
const clientPreview = $derived(zoomed && needClientRender);
|
||||
const clientPreview = $derived(needClientRender);
|
||||
|
||||
// Пока браузер рисует правки сам, под ним лежит исходная версия фото.
|
||||
const clientSource = $derived(
|
||||
zoomed ? originalSrc || basePreviewSrc : basePreviewSrc
|
||||
);
|
||||
const displaySrc = $derived(
|
||||
clientPreview
|
||||
? originalSrc || previewSrc
|
||||
? clientSource || previewSrc
|
||||
: zoomed && hiResLoaded && fullSrc
|
||||
? fullSrc
|
||||
: previewSrc
|
||||
@@ -176,7 +181,10 @@
|
||||
let canvas: HTMLCanvasElement | undefined = $state();
|
||||
let viewportFrame: number | null = null;
|
||||
|
||||
/** Рисует видимую область фото с применёнными правками. */
|
||||
/**
|
||||
* Рисует видимую область фото с применёнными правками. Работает и в зуме,
|
||||
* и в обычном виде: берём ту часть картинки, что попала во вьюпорт.
|
||||
*/
|
||||
function renderViewport() {
|
||||
const c = canvas;
|
||||
const img = imgEl;
|
||||
@@ -184,8 +192,20 @@
|
||||
if (!c || !img || !el) return;
|
||||
const natural = img.naturalWidth;
|
||||
if (!natural) return;
|
||||
const ratio = img.clientWidth / natural;
|
||||
if (!ratio) return;
|
||||
const imgRect = img.getBoundingClientRect();
|
||||
const viewRect = el.getBoundingClientRect();
|
||||
if (!imgRect.width || !viewRect.width) return;
|
||||
const ratio = imgRect.width / natural;
|
||||
|
||||
// Видимая часть картинки.
|
||||
const left = Math.max(imgRect.left, viewRect.left);
|
||||
const top = Math.max(imgRect.top, viewRect.top);
|
||||
const right = Math.min(imgRect.right, viewRect.right);
|
||||
const bottom = Math.min(imgRect.bottom, viewRect.bottom);
|
||||
const visibleW = right - left;
|
||||
const visibleH = bottom - top;
|
||||
if (visibleW <= 0 || visibleH <= 0) return;
|
||||
|
||||
const width = el.clientWidth;
|
||||
const height = el.clientHeight;
|
||||
if (!width || !height) return;
|
||||
@@ -195,23 +215,25 @@
|
||||
}
|
||||
c.style.width = `${width}px`;
|
||||
c.style.height = `${height}px`;
|
||||
|
||||
const ctx = c.getContext('2d');
|
||||
if (!ctx) return;
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
ctx.drawImage(
|
||||
img,
|
||||
el.scrollLeft / ratio,
|
||||
el.scrollTop / ratio,
|
||||
width / ratio,
|
||||
height / ratio,
|
||||
0,
|
||||
0,
|
||||
width,
|
||||
height
|
||||
);
|
||||
const data = ctx.getImageData(0, 0, width, height);
|
||||
|
||||
// Исходный кусок в пикселях картинки и его место на холсте.
|
||||
const sx = (left - imgRect.left) / ratio;
|
||||
const sy = (top - imgRect.top) / ratio;
|
||||
const sw = visibleW / ratio;
|
||||
const sh = visibleH / ratio;
|
||||
const dx = Math.round(left - viewRect.left);
|
||||
const dy = Math.round(top - viewRect.top);
|
||||
const dw = Math.round(visibleW);
|
||||
const dh = Math.round(visibleH);
|
||||
|
||||
ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh);
|
||||
const data = ctx.getImageData(dx, dy, dw, dh);
|
||||
applyLight(data.data, liveParams.light);
|
||||
ctx.putImageData(data, 0, 0);
|
||||
ctx.putImageData(data, dx, dy);
|
||||
}
|
||||
|
||||
function scheduleViewport() {
|
||||
@@ -684,6 +706,7 @@
|
||||
src={displaySrc}
|
||||
alt={current.original_filename}
|
||||
draggable="false"
|
||||
onload={scheduleViewport}
|
||||
style={zoomed ? `width: ${baseWidth() * scale}px; height: auto;` : ''}
|
||||
class="m-auto block {zoomed
|
||||
? 'max-w-none shrink-0 select-none'
|
||||
|
||||
Reference in New Issue
Block a user