Skip to content

Commit bec6223

Browse files
committed
delay loading and rendering gui
- Create the scratch renderer earlier in the GUI container/HOC stack - Delay loading and rendering GUI component until after project assets have been fetched
1 parent 0b40daf commit bec6223

File tree

2 files changed

+79
-2
lines changed

2 files changed

+79
-2
lines changed

src/components/gui/gui.jsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,11 @@ const GUIComponent = props => {
129129
};
130130

131131
if (isRendererSupported === null) {
132-
isRendererSupported = Renderer.isSupported();
132+
if (vm.renderer) {
133+
isRendererSupported = true;
134+
} else {
135+
isRendererSupported = Renderer.isSupported();
136+
}
133137
}
134138

135139
return (<MediaQuery minWidth={layout.fullSizeMinWidth}>{isFullSize => {

src/containers/gui.jsx

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,13 @@ import storage from '../lib/storage';
3535
import vmListenerHOC from '../lib/vm-listener-hoc.jsx';
3636
import vmManagerHOC from '../lib/vm-manager-hoc.jsx';
3737
import cloudManagerHOC from '../lib/cloud-manager-hoc.jsx';
38+
import Loader from '../components/loader/loader.jsx';
3839

39-
import GUIComponent from '../components/gui/gui.jsx';
40+
// import GUIComponent from '../components/gui/gui.jsx';
4041
import {setIsScratchDesktop} from '../lib/isScratchDesktop.js';
4142

43+
import VideoProvider from '../lib/video/video-provider';
44+
4245
const messages = defineMessages({
4346
defaultProjectTitle: {
4447
id: 'gui.gui.defaultProjectTitle',
@@ -52,6 +55,22 @@ class GUI extends React.Component {
5255
setIsScratchDesktop(this.props.isScratchDesktop);
5356
this.setReduxTitle(this.props.projectTitle);
5457
this.props.onStorageInit(storage);
58+
59+
// Use setTimeout. Do not use requestAnimationFrame or a resolved
60+
// Promise. We want this work delayed until after the data request is
61+
// made.
62+
setTimeout(this.ensureRenderer.bind(this));
63+
64+
// Once the GUI component has been rendered, always render GUI and do
65+
// not revert back to a Loader in this component.
66+
//
67+
// This makes GUI container not a pure component. We don't want to use
68+
// state for this. That would possibly cause a full second render of GUI
69+
// after the first one.
70+
const {fontsLoaded, fetchingProject, isLoading} = this.props;
71+
this.isAfterGUI = this.isAfterGUI || (
72+
fontsLoaded && !fetchingProject && !isLoading
73+
);
5574
}
5675
componentDidUpdate (prevProps) {
5776
if (this.props.projectId !== prevProps.projectId && this.props.projectId !== null) {
@@ -65,6 +84,17 @@ class GUI extends React.Component {
6584
// At this time the project view in www doesn't need to know when a project is unloaded
6685
this.props.onProjectLoaded();
6786
}
87+
88+
// Once the GUI component has been rendered, always render GUI and do
89+
// not revert back to a Loader in this component.
90+
//
91+
// This makes GUI container not a pure component. We don't want to use
92+
// state for this. That would possibly cause a full second render of GUI
93+
// after the first one.
94+
const {fontsLoaded, fetchingProject, isLoading} = this.props;
95+
this.isAfterGUI = this.isAfterGUI || (
96+
fontsLoaded && !fetchingProject && !isLoading
97+
);
6898
}
6999
setReduxTitle (newTitle) {
70100
if (newTitle === null || typeof newTitle === 'undefined') {
@@ -75,6 +105,36 @@ class GUI extends React.Component {
75105
this.props.onUpdateReduxProjectTitle(newTitle);
76106
}
77107
}
108+
ensureRenderer () {
109+
if (this.props.vm.renderer) {
110+
return;
111+
}
112+
113+
// Wait to load svg-renderer and render after the data request. This
114+
// way the data request is made earlier.
115+
const Renderer = require('scratch-render');
116+
const {
117+
SVGRenderer: V2SVGAdapter,
118+
BitmapAdapter: V2BitmapAdapter
119+
} = require('scratch-svg-renderer');
120+
121+
const vm = this.props.vm;
122+
this.canvas = document.createElement('canvas');
123+
this.renderer = new Renderer(this.canvas);
124+
vm.attachRenderer(this.renderer);
125+
126+
vm.attachV2SVGAdapter(new V2SVGAdapter());
127+
vm.attachV2BitmapAdapter(new V2BitmapAdapter());
128+
129+
// Only attach a video provider once because it is stateful
130+
vm.setVideoProvider(new VideoProvider());
131+
132+
// Calling draw a single time before any project is loaded just
133+
// makes the canvas white instead of solid black–needed because it
134+
// is not possible to use CSS to style the canvas to have a
135+
// different default color
136+
vm.renderer.draw();
137+
}
78138
render () {
79139
if (this.props.isError) {
80140
throw new Error(
@@ -85,6 +145,7 @@ class GUI extends React.Component {
85145
assetHost,
86146
cloudHost,
87147
error,
148+
fontsLoaded,
88149
isError,
89150
isScratchDesktop,
90151
isShowingProject,
@@ -102,6 +163,16 @@ class GUI extends React.Component {
102163
loadingStateVisible,
103164
...componentProps
104165
} = this.props;
166+
167+
if (!this.isAfterGUI && (
168+
!fontsLoaded || fetchingProject || isLoading
169+
)) {
170+
// Make sure a renderer exists.
171+
if (fontsLoaded && !fetchingProject) this.ensureRenderer();
172+
return <Loader />;
173+
}
174+
175+
const GUIComponent = require('../components/gui/gui.jsx').default;
105176
return (
106177
<GUIComponent
107178
loading={fetchingProject || isLoading || loadingStateVisible}
@@ -119,6 +190,7 @@ GUI.propTypes = {
119190
cloudHost: PropTypes.string,
120191
error: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
121192
fetchingProject: PropTypes.bool,
193+
fontsLoaded: PropTypes.bool,
122194
intl: intlShape,
123195
isError: PropTypes.bool,
124196
isLoading: PropTypes.bool,
@@ -157,6 +229,7 @@ const mapStateToProps = state => {
157229
costumeLibraryVisible: state.scratchGui.modals.costumeLibrary,
158230
costumesTabVisible: state.scratchGui.editorTab.activeTabIndex === COSTUMES_TAB_INDEX,
159231
error: state.scratchGui.projectState.error,
232+
fontsLoaded: state.scratchGui.fontsLoaded,
160233
isError: getIsError(loadingState),
161234
isFullScreen: state.scratchGui.mode.isFullScreen,
162235
isPlayerOnly: state.scratchGui.mode.isPlayerOnly,

0 commit comments

Comments
 (0)