feat(editor): scale video embeddables based on zoom (#11251)

This commit is contained in:
David Luzar
2026-04-28 21:49:40 +02:00
committed by GitHub
parent 43fa4b5602
commit 278cd35772
2 changed files with 58 additions and 25 deletions
+26 -1
View File
@@ -603,6 +603,8 @@ const YOUTUBE_VIDEO_STATES = new Map<
ValueOf<typeof YOUTUBE_STATES> ValueOf<typeof YOUTUBE_STATES>
>(); >();
const MAX_EMBEDDABLE_VIEWPORT_SCALE = 4;
let IS_PLAIN_PASTE = false; let IS_PLAIN_PASTE = false;
let IS_PLAIN_PASTE_TIMER = 0; let IS_PLAIN_PASTE_TIMER = 0;
let PLAIN_PASTE_TOAST_SHOWN = false; let PLAIN_PASTE_TOAST_SHOWN = false;
@@ -1735,6 +1737,18 @@ class App extends React.Component<AppProps, AppState> {
this.state.activeEmbeddable?.element === el && this.state.activeEmbeddable?.element === el &&
this.state.activeEmbeddable?.state === "hover"; this.state.activeEmbeddable?.state === "hover";
// scale video embeds based on zoom (capped) so that smaller embeds
// on canvas when zoomed are still of legible quality
// (note: for some embed types like gdrive, the quality is poor when
// scaling mid playback and works only when you initially start the
// playback at the higher zoom level)
const shouldScaleEmbeddableViewport = src?.type === "video";
const embeddableViewportScale = clamp(
shouldScaleEmbeddableViewport ? scale : 1,
0.75,
MAX_EMBEDDABLE_VIEWPORT_SCALE,
);
return ( return (
<div <div
key={el.id} key={el.id}
@@ -1800,6 +1814,14 @@ class App extends React.Component<AppProps, AppState> {
style={{ style={{
padding: `${el.strokeWidth}px`, padding: `${el.strokeWidth}px`,
}} }}
>
<div
className="excalidraw__embeddable__content"
style={{
width: `${embeddableViewportScale * 100}%`,
height: `${embeddableViewportScale * 100}%`,
transform: `scale(${1 / embeddableViewportScale})`,
}}
> >
{(isEmbeddableElement(el) {(isEmbeddableElement(el)
? this.props.renderEmbeddable?.(el, this.state) ? this.props.renderEmbeddable?.(el, this.state)
@@ -1822,13 +1844,16 @@ class App extends React.Component<AppProps, AppState> {
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen={true} allowFullScreen={true}
sandbox={`${ sandbox={`${
src?.sandbox?.allowSameOrigin ? "allow-same-origin" : "" src?.sandbox?.allowSameOrigin
? "allow-same-origin"
: ""
} allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-downloads`} } allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-downloads`}
/> />
)} )}
</div> </div>
</div> </div>
</div> </div>
</div>
); );
})} })}
</> </>
+8
View File
@@ -814,6 +814,14 @@ body.excalidraw-cursor-resize * {
.excalidraw__embeddable__outer { .excalidraw__embeddable__outer {
width: 100%; width: 100%;
height: 100%; height: 100%;
}
.excalidraw__embeddable__content {
width: 100%;
height: 100%;
transform-origin: top left;
&,
& > * { & > * {
border-radius: var(--embeddable-radius); border-radius: var(--embeddable-radius);
} }