Skip to content

Commit b27be3e

Browse files
committed
stable html -- more naming consistency and put back count param
1 parent 048282c commit b27be3e

File tree

2 files changed

+50
-21
lines changed

2 files changed

+50
-21
lines changed

src/packages/frontend/jupyter/cell-list.tsx

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
// React component that renders the ordered list of cells
77

88
declare const $: any;
9-
9+
import useResizeObserver from "use-resize-observer";
1010
import { delay } from "awaiting";
1111
import * as immutable from "immutable";
1212
import { debounce } from "lodash";
@@ -37,7 +37,7 @@ import { Cell } from "./cell";
3737
import HeadingTagComponent from "./heading-tag";
3838
interface StableHtmlContextType {
3939
cellListDivRef?: MutableRefObject<any>;
40-
htmlOnScrolls?: { [key: string]: () => void };
40+
scrollOrResize?: { [key: string]: () => void };
4141
}
4242
const StableHtmlContext = createContext<StableHtmlContextType>({});
4343
export const useStableHtmlContext: () => StableHtmlContextType = () => {
@@ -506,8 +506,8 @@ export const CellList: React.FC<CellListProps> = (props: CellListProps) => {
506506
...scrollState,
507507
id: cellListRef.current?.get(scrollState.index),
508508
};
509-
for (const key in htmlOnScrolls) {
510-
htmlOnScrolls[key]();
509+
for (const key in scrollOrResize) {
510+
scrollOrResize[key]();
511511
}
512512
},
513513
scrollerRef: handleCellListRef,
@@ -540,13 +540,13 @@ export const CellList: React.FC<CellListProps> = (props: CellListProps) => {
540540
});
541541
}, [cell_list]);
542542

543-
const htmlOnScrolls = useMemo(() => {
543+
const scrollOrResize = useMemo(() => {
544544
return {};
545545
}, []);
546546
useEffect(() => {
547547
if (!use_windowed_list) return;
548-
for (const key in htmlOnScrolls) {
549-
htmlOnScrolls[key]();
548+
for (const key in scrollOrResize) {
549+
scrollOrResize[key]();
550550
}
551551
}, [cells]);
552552

@@ -556,10 +556,19 @@ export const CellList: React.FC<CellListProps> = (props: CellListProps) => {
556556

557557
const cellListDivRef = useRef<HTMLDivElement>(null);
558558
const virtuosoHeightsRef = useRef<{ [index: number]: number }>({});
559+
560+
const cellListResize = useResizeObserver({ ref: cellListDivRef });
561+
useEffect(() => {
562+
if (!use_windowed_list) return;
563+
for (const key in scrollOrResize) {
564+
scrollOrResize[key]();
565+
}
566+
}, [cellListResize]);
567+
559568
if (use_windowed_list) {
560569
body = (
561570
<StableHtmlContext.Provider
562-
value={{ cellListDivRef, htmlOnScrolls }}
571+
value={{ cellListDivRef, scrollOrResize }}
563572
>
564573
<div ref={cellListDivRef} className="smc-vfill">
565574
<Virtuoso

src/packages/frontend/jupyter/output-messages/stable-unsafe-html.tsx

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,18 @@ const MAX_ELEMENTS = 500; // max items
4040
const SCROLL_WIDTH = 30;
4141
// we have to put the html on top of the notebook to be visible. This is the z-index we use.
4242
const Z_INDEX = 1;
43-
// no matter what when the html is in the REACT dom, it will have its position updated this frequently.
44-
// it also gets updated on scroll of the cell list.
45-
const POSITION_WHEN_MOUNTED_INTERVAL_MS = 500;
43+
44+
// POSITION_WHEN_MOUNTED_INTERVAL_MS: No matter what when the html is in the REACT
45+
// dom, it will have its position updated this frequently.
46+
// it also gets updated on scroll of the cell list. This also serves to
47+
// ensure that this item has a recent ttl so it isn't cleared from the ttl cache.
48+
// It should NOT ever actually be needed, since we always update the position on
49+
// resize and scroll events.
50+
const POSITION_WHEN_MOUNTED_INTERVAL_MS = 10000;
51+
52+
// Scroll actively this many frames after each update, due to throttling of onscroll
53+
// and other events. This is to eliminate lag.
54+
const SCROLL_COUNT = 30;
4655

4756
const cache = new TTL<string, any>({
4857
ttl: IDLE_TIMEOUT_S * 1000,
@@ -121,7 +130,7 @@ export default function StableUnsafeHtml({
121130
// }px`;
122131

123132
// clip our immortal html so it isn't visible outside the parent
124-
const parent = $(stableHtmlContext.cellListDivRef?.current)[0];
133+
const parent = stableHtmlContext.cellListDivRef?.current;
125134
if (parent != null) {
126135
const parentRect = parent.getBoundingClientRect();
127136
// Calculate the overlap area
@@ -151,8 +160,8 @@ export default function StableUnsafeHtml({
151160
// Apply clip-path to elt to make it visible only inside of parentRect:
152161
elt.style.clipPath = `polygon(${left}px ${top}px, ${right}px ${top}px, ${right}px ${bottom}px, ${left}px ${bottom}px)`;
153162

154-
// Set widht, so it possible to scroll horizontally and see whatever widget is in the output.
155-
const w = $(divRef.current).width();
163+
// Set width, so it possible to scroll horizontally and see whatever widget is in the output.
164+
const w = divRef.current.offsetWidth;
156165
if (w) {
157166
elt.style.width = `${w}px`;
158167
}
@@ -212,24 +221,35 @@ export default function StableUnsafeHtml({
212221
}, [isVisible]);
213222

214223
useEffect(() => {
215-
// TOOD: can we get rid of interval by using a resize observer on
216-
// this stableHtmlContext.cellListDivRef?
217224
intervalRef.current = setInterval(
218225
position,
219226
POSITION_WHEN_MOUNTED_INTERVAL_MS,
220227
);
221-
if (stableHtmlContext.htmlOnScrolls != null) {
222-
stableHtmlContext.htmlOnScrolls[globalKey] = async () => {
223-
position();
224-
await new Promise(requestAnimationFrame);
228+
if (stableHtmlContext.scrollOrResize != null) {
229+
let count = 0;
230+
stableHtmlContext.scrollOrResize[globalKey] = async () => {
231+
if (count > 0) {
232+
return;
233+
}
234+
// We run position a lot whenever there is a scroll
235+
// in order to make it so the iframe doesn't appear
236+
// to just get "dragged along" nearly as much, as
237+
// onScroll is throttled.
238+
count = SCROLL_COUNT;
239+
while (count > 0) {
240+
position();
241+
await new Promise(requestAnimationFrame);
242+
count -= 1;
243+
}
244+
// throw in an update when we're done.
225245
position();
226246
};
227247
}
228248
position();
229249
setTimeout(position, 0);
230250

231251
return () => {
232-
delete stableHtmlContext.htmlOnScrolls?.[globalKey];
252+
delete stableHtmlContext.scrollOrResize?.[globalKey];
233253
if (intervalRef.current) {
234254
clearInterval(intervalRef.current);
235255
}

0 commit comments

Comments
 (0)