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
+50 -25
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}
@@ -1801,31 +1815,42 @@ class App extends React.Component<AppProps, AppState> {
padding: `${el.strokeWidth}px`, padding: `${el.strokeWidth}px`,
}} }}
> >
{(isEmbeddableElement(el) <div
? this.props.renderEmbeddable?.(el, this.state) className="excalidraw__embeddable__content"
: null) ?? ( style={{
<iframe width: `${embeddableViewportScale * 100}%`,
ref={(ref) => this.cacheEmbeddableRef(el, ref)} height: `${embeddableViewportScale * 100}%`,
className="excalidraw__embeddable" transform: `scale(${1 / embeddableViewportScale})`,
srcDoc={ }}
src?.type === "document" >
? src.srcdoc(this.state.theme) {(isEmbeddableElement(el)
: undefined ? this.props.renderEmbeddable?.(el, this.state)
} : null) ?? (
src={ <iframe
src?.type !== "document" ? src?.link ?? "" : undefined ref={(ref) => this.cacheEmbeddableRef(el, ref)}
} className="excalidraw__embeddable"
// https://stackoverflow.com/q/18470015 srcDoc={
scrolling="no" src?.type === "document"
referrerPolicy="no-referrer-when-downgrade" ? src.srcdoc(this.state.theme)
title="Excalidraw Embedded Content" : undefined
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" }
allowFullScreen={true} src={
sandbox={`${ src?.type !== "document" ? src?.link ?? "" : undefined
src?.sandbox?.allowSameOrigin ? "allow-same-origin" : "" }
} allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-downloads`} // https://stackoverflow.com/q/18470015
/> scrolling="no"
)} referrerPolicy="no-referrer-when-downgrade"
title="Excalidraw Embedded Content"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen={true}
sandbox={`${
src?.sandbox?.allowSameOrigin
? "allow-same-origin"
: ""
} 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);
} }