generated from john/python-template
reworked zooming
This commit is contained in:
@@ -60,16 +60,16 @@ def _register_panzoom_assets() -> None:
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
justify-content: center;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.document-panzoom-media {
|
.document-panzoom-media {
|
||||||
width: auto;
|
width: auto;
|
||||||
height: auto;
|
height: auto;
|
||||||
display: block;
|
display: block;
|
||||||
max-width: none;
|
max-width: 100%;
|
||||||
max-height: none;
|
max-height: 100%;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-drag: none;
|
-webkit-user-drag: none;
|
||||||
}
|
}
|
||||||
@@ -99,79 +99,76 @@ def _attach_panzoom(host_id: str) -> None:
|
|||||||
const media = host.querySelector('[data-panzoom-media]');
|
const media = host.querySelector('[data-panzoom-media]');
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
|
|
||||||
|
const cleanup = () => {{
|
||||||
|
const existing = window.__transcriptionPanzoom[{host_id!r}];
|
||||||
|
if (existing?.resizeObserver) existing.resizeObserver.disconnect();
|
||||||
|
if (existing?.wheelHandler) host.removeEventListener('wheel', existing.wheelHandler);
|
||||||
|
if (existing?.instance) existing.instance.destroy();
|
||||||
|
}};
|
||||||
|
|
||||||
const computeFitScale = () => {{
|
const computeFitScale = () => {{
|
||||||
const hostRect = host.getBoundingClientRect();
|
const hostRect = host.getBoundingClientRect();
|
||||||
if (hostRect.width <= 0 || hostRect.height <= 0) return 1;
|
if (hostRect.width <= 0 || hostRect.height <= 0) return null;
|
||||||
|
|
||||||
if (media && media.tagName === 'IMG') {{
|
|
||||||
if (media.naturalWidth <= 0 || media.naturalHeight <= 0) return 1;
|
|
||||||
return Math.min(
|
|
||||||
hostRect.width / media.naturalWidth,
|
|
||||||
hostRect.height / media.naturalHeight
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
|
|
||||||
if (target.tagName === 'IFRAME') {{
|
|
||||||
const targetRect = target.getBoundingClientRect();
|
|
||||||
if (targetRect.width <= 0 || targetRect.height <= 0) return 1;
|
|
||||||
return hostRect.height / targetRect.height;
|
|
||||||
}}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
const initPanzoom = () => {{
|
const buildInstance = () => {{
|
||||||
if (window.__transcriptionPanzoom[{host_id!r}]) {{
|
cleanup();
|
||||||
window.__transcriptionPanzoom[{host_id!r}].destroy();
|
|
||||||
}}
|
|
||||||
|
|
||||||
if (host.__transcriptionWheelHandler) {{
|
const fitScale = computeFitScale();
|
||||||
host.removeEventListener('wheel', host.__transcriptionWheelHandler);
|
if (fitScale === null) return false;
|
||||||
host.__transcriptionWheelHandler = null;
|
|
||||||
}}
|
|
||||||
|
|
||||||
let fitScale = computeFitScale();
|
const minScale = Math.min(fitScale, 0.01);
|
||||||
|
|
||||||
if (!Number.isFinite(fitScale) || fitScale <= 0) {{
|
|
||||||
fitScale = 1;
|
|
||||||
}}
|
|
||||||
|
|
||||||
const startScale = fitScale;
|
|
||||||
const minScale = 0.01;
|
|
||||||
const instance = Panzoom(target, {{
|
const instance = Panzoom(target, {{
|
||||||
maxScale: 32,
|
startX: 0,
|
||||||
|
startY: 0,
|
||||||
|
startScale: fitScale,
|
||||||
minScale: minScale,
|
minScale: minScale,
|
||||||
startScale: startScale,
|
maxScale: 256,
|
||||||
step: 0.18,
|
step: 0.2,
|
||||||
contain: 'inside',
|
roundPixels: false,
|
||||||
roundPixels: true,
|
panOnlyWhenZoomed: true,
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
}});
|
}});
|
||||||
|
|
||||||
window.__transcriptionPanzoom[{host_id!r}] = instance;
|
const wheelHandler = (event) => instance.zoomWithWheel(event);
|
||||||
|
host.addEventListener('wheel', wheelHandler, {{ passive: false }});
|
||||||
|
|
||||||
requestAnimationFrame(() => {{
|
requestAnimationFrame(() => {{
|
||||||
instance.reset({{ animate: false, force: true }});
|
instance.reset({{ animate: false }});
|
||||||
instance.setOptions({{ contain: undefined }});
|
|
||||||
}});
|
}});
|
||||||
|
|
||||||
const wheelHandler = (event) => instance.zoomWithWheel(event);
|
const resizeObserver = new ResizeObserver(() => {{
|
||||||
host.__transcriptionWheelHandler = wheelHandler;
|
const nextFitScale = computeFitScale();
|
||||||
host.addEventListener('wheel', wheelHandler, {{ passive: false }});
|
if (nextFitScale === null) return;
|
||||||
|
instance.setOptions({{
|
||||||
|
startScale: nextFitScale,
|
||||||
|
minScale: Math.min(nextFitScale, 0.01),
|
||||||
|
}});
|
||||||
|
instance.reset({{ animate: false }});
|
||||||
|
}});
|
||||||
|
resizeObserver.observe(host);
|
||||||
|
|
||||||
|
window.__transcriptionPanzoom[{host_id!r}] = {{
|
||||||
|
instance,
|
||||||
|
wheelHandler,
|
||||||
|
resizeObserver,
|
||||||
|
}};
|
||||||
|
return true;
|
||||||
|
}};
|
||||||
|
|
||||||
|
const initWhenReady = (retries = 15) => {{
|
||||||
|
if (buildInstance()) return;
|
||||||
|
if (retries <= 0) return;
|
||||||
|
requestAnimationFrame(() => initWhenReady(retries - 1));
|
||||||
}};
|
}};
|
||||||
|
|
||||||
if (media && media.tagName === 'IMG' && !media.complete) {{
|
if (media && media.tagName === 'IMG' && !media.complete) {{
|
||||||
media.addEventListener('load', initPanzoom, {{ once: true }});
|
media.addEventListener('load', () => initWhenReady(), {{ once: true }});
|
||||||
return;
|
return;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
if ((media && media.tagName === 'IMG' && (host.clientWidth <= 0 || host.clientHeight <= 0)) ||
|
initWhenReady();
|
||||||
(target.tagName === 'IFRAME' && (host.clientWidth <= 0 || host.clientHeight <= 0))) {{
|
|
||||||
requestAnimationFrame(initPanzoom);
|
|
||||||
return;
|
|
||||||
}}
|
|
||||||
|
|
||||||
initPanzoom();
|
|
||||||
}})();
|
}})();
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
@@ -186,10 +183,11 @@ def render_document_panzoom(*, document: Document, height: str = "640px") -> Non
|
|||||||
document_kind = _document_kind(document)
|
document_kind = _document_kind(document)
|
||||||
|
|
||||||
with ui.card().classes("w-full q-pa-md"):
|
with ui.card().classes("w-full q-pa-md"):
|
||||||
with ui.column().classes("q-gutter-none"):
|
with ui.row().classes("w-full items-center justify-between no-wrap"):
|
||||||
with ui.row().classes("w-full items-center justify-between q-gutter-sm"):
|
|
||||||
ui.label("Document preview").classes("text-subtitle1 text-weight-medium")
|
ui.label("Document preview").classes("text-subtitle1 text-weight-medium")
|
||||||
ui.label(document.filename).classes("text-caption text-grey-4")
|
ui.label(document.filename).classes("text-caption text-grey-4 ellipsis").style(
|
||||||
|
"max-width: 60%; text-align: right;"
|
||||||
|
)
|
||||||
|
|
||||||
with (
|
with (
|
||||||
ui.element("div")
|
ui.element("div")
|
||||||
|
|||||||
Reference in New Issue
Block a user