Skip to content

Commit

Permalink
Prevent initial rendering of DoenetML when it is hidden (#279)
Browse files Browse the repository at this point in the history
  • Loading branch information
dqnykamp authored Jan 20, 2025
1 parent 908c6e7 commit 6fa1de1
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 13 deletions.
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion packages/doenetml-iframe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@doenet/doenetml-iframe",
"type": "module",
"description": "A renderer for DoenetML contained in an iframe",
"version": "0.7.0-alpha25",
"version": "0.7.0-alpha26",
"license": "AGPL-3.0-or-later",
"homepage": "https://github.com/Doenet/DoenetML#readme",
"private": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/doenetml/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@doenet/doenetml",
"type": "module",
"description": "Semantic markup for building interactive web activities",
"version": "0.7.0-alpha25",
"version": "0.7.0-alpha26",
"license": "AGPL-3.0-or-later",
"homepage": "https://github.com/Doenet/DoenetML#readme",
"private": true,
Expand Down
29 changes: 22 additions & 7 deletions packages/doenetml/src/doenetml.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import "./DoenetML.css";
// @ts-ignore
import { prng_alea } from "esm-seedrandom";
import React, { useCallback, useRef, useState } from "react";
import React, { useCallback, useEffect, useRef, useState } from "react";
import { DocViewer } from "./Viewer/DocViewer";
import { RecoilRoot } from "recoil";
import { MathJaxContext } from "better-react-mathjax";
Expand All @@ -12,6 +12,7 @@ import { Box, ChakraProvider, extendTheme } from "@chakra-ui/react";
import "@doenet/virtual-keyboard/style.css";
import { EditorViewer } from "./EditorViewer/EditorViewer.js";
import VariantSelect from "./EditorViewer/VariantSelect";
import { useIsOnPage } from "./utils/isVisible";

export const version: string = DOENETML_VERSION;

Expand Down Expand Up @@ -101,7 +102,6 @@ export function DoenetViewer({
userId,
attemptNumber = 1,
render = true,
hidden = false,
requestedVariantIndex,
updateCreditAchievedCallback,
setIsInErrorState,
Expand Down Expand Up @@ -129,7 +129,6 @@ export function DoenetViewer({
userId?: string;
attemptNumber?: number;
render?: boolean;
hidden?: boolean;
requestedVariantIndex?: number;
updateCreditAchievedCallback?: Function;
setIsInErrorState?: Function;
Expand Down Expand Up @@ -160,6 +159,20 @@ export function DoenetViewer({

const variantIndex = useRef(1);

// Start off hidden and then unhide once the viewer is visible.
// This is needed to delay the initialization of JSXgraph
// until it is no longer hidden.
// Otherwise, the graphs are often displayed in a garbled fashion
// with the bounded calculated incorrectly
const ref = useRef<HTMLDivElement>(null);
const isOnPage = useIsOnPage(ref);
const [hidden, setHidden] = useState(true);
useEffect(() => {
if (isOnPage) {
setHidden(false);
}
}, [isOnPage]);

const flags: DoenetMLFlags = { ...defaultFlags, ...specifiedFlags };

if (userId) {
Expand Down Expand Up @@ -270,10 +283,12 @@ export function DoenetViewer({
>
<RecoilRoot>
<MathJaxContext version={3} config={mathjaxConfig}>
{variantSelector}
{viewer}
<div className="before-keyboard" />
{keyboard}
<div ref={ref}>
{variantSelector}
{viewer}
<div className="before-keyboard" />
{keyboard}
</div>
</MathJaxContext>
</RecoilRoot>
</ChakraProvider>
Expand Down
52 changes: 52 additions & 0 deletions packages/doenetml/src/utils/isVisible.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { RefObject, useEffect, useState } from "react";

/**
* Returns `true` if the any portion of the element referenced by `ref`
* is visible in the browser's viewport
*
* From: https://dev.to/jmalvarez/check-if-an-element-is-visible-with-react-hooks-27h8
*/
export function useIsVisible(ref: RefObject<HTMLElement>) {
const [isIntersecting, setIntersecting] = useState(false);

useEffect(() => {
const observer = new IntersectionObserver(([entry]) =>
setIntersecting(entry.isIntersecting),
);

if (ref.current) {
observer.observe(ref.current);
}
return () => {
observer.disconnect();
};
}, [ref]);

return isIntersecting;
}

/**
* Returns true if the element referenced by `ref` is anywhere on the page
* (more precisely, within 1000000px of the browser's viewport).
*
* Used to approximately detect if the element is not hidden.
*/
export function useIsOnPage(ref: RefObject<HTMLElement>) {
const [isIntersecting, setIntersecting] = useState(false);

useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => setIntersecting(entry.isIntersecting),
{ rootMargin: "1000000px" },
);

if (ref.current) {
observer.observe(ref.current);
}
return () => {
observer.disconnect();
};
}, [ref]);

return isIntersecting;
}
2 changes: 1 addition & 1 deletion packages/standalone/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@doenet/standalone",
"type": "module",
"description": "Standalone renderer for DoenetML suitable for being included in a web page",
"version": "0.7.0-alpha25",
"version": "0.7.0-alpha26",
"license": "AGPL-3.0-or-later",
"homepage": "https://github.com/Doenet/DoenetML#readme",
"private": true,
Expand Down

0 comments on commit 6fa1de1

Please sign in to comment.