Thanks to earlier help, I was able to bring my notebook into a React component.
However, the component renders at the dimensions of the viewport, plus some additional pixels, leading to vertical and horizontal scrollbars being shown that hide content. The internal dimensions are not calculated correctly, which also leads to some unwanted vertical space between the two top panels and the bottom one:
In my notebook, I have two variables mutable viewportWidth
and mutable viewportHeight
which rely on the value of width
to set up, size and render the genomeSpace
cell within the Observablehq notebook environment.
I would like to use standard React routines to resize this notebook component before it is rendered in a React application.
Custom sizing will allow me to try to integrate the notebook component with other React components and UI widgets.
I am attempting to glue the instantiation routine here to a resize
event:
import React, {Component} from "react";
import {Runtime, Inspector, Library} from "@observablehq/runtime";
import notebook from "0f7b50a23d98b321";
class App extends Component {
constructor(props) {
super(props);
this.state = {
width: 0,
height: 0
};
this.genomeSpaceRef = React.createRef();
this.viewportWidth = {};
this.viewportHeight = {};
}
componentDidMount() {
const genomeSpace = this.genomeSpaceRef.current;
const library = new Library();
const runtime = new Runtime();
const main = runtime.module(notebook, name => {
if (name === "viewof genomeSpace") {
return new Inspector(genomeSpace);
}
if (name === "mutable viewportWidth") {
return {fulfilled: (value) => {
this.viewportWidth = value;
}};
}
if (name === "mutable viewportHeight") {
return {fulfilled: (value) => {
this.viewportHeight = value;
}};
}
});
main.redefine("width", library.Generators.observe(notify => {
let width = notify(genomeSpace.clientWidth);
function resized() {
let newWidth = genomeSpace.clientWidth;
if (newWidth !== width) {
notify(width = newWidth)
}
}
window.addEventListener("resize", resized);
return () => window.removeEventListener("resize", resized);
}));
window.addEventListener('resize', this.updateDimensions);
setTimeout(() => {
window.dispatchEvent(new Event('resize'));
}, 2500);
}
componentWillUnmount() {
window.removeEventListener('resize', this.updateDimensions);
}
componentDidUpdate(nextProps, nextState) {}
updateDimensions = () => {
this.setState({
width: window.innerWidth,
height: window.innerHeight
}, () => {
this.viewportWidth.value = parseInt(this.state.width);
this.viewportHeight.value = parseInt(this.state.height);
});
};
render() {
return (
<div id="parent" className="parent">
<div ref={this.genomeSpaceRef} className="genomeSpace"></div>
</div>
);
}
}
export default App;
While updateDimensions
will be called as a result of dispatching a resize
event via window.dispatchEvent(new Event('resize'))
, the problem is that the notebook does not always redraw correctly. Sometimes it works, sometimes it doesnāt.
When it does redraw correctly, there is a delay of 2.5 sec (give or take) before that redraw occurs.
What I would like to do is size the notebook viewof genomeSpace
cell before it is drawn, by setting the mutable viewportWidth
and mutable viewportHeight
values via this.setState(...)
.
What is the correct and reliable way to dynamically resize a notebook component to whatever is set in application state?