-
Notifications
You must be signed in to change notification settings - Fork 71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/reduce bundle size #106
base: master
Are you sure you want to change the base?
Changes from 22 commits
78fa2fc
7b95d18
bb32e8d
971eb20
fd2f65b
66fd770
d178edb
fd9e0e9
f53cc02
9af7154
c10bfd4
2f5ccd4
f0c087e
429a4a9
195cb69
ffc108a
da2d6f5
5ad2a60
057a30d
1f40226
c077bf2
f9b9bb6
7d9f154
3dea501
a4c652a
84d7856
30a110c
edeb6e3
a51f61f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,12 @@ | ||
import React from "react" | ||
import { BrowserRouter as Router, Route, Switch } from "react-router-dom" | ||
import { BrowserRouter as Router, Route, Switch, Redirect } from "react-router-dom" | ||
import ReactGA from "react-ga" | ||
import { VirtualHexapod, getNewPlotParams } from "./hexapod" | ||
import * as defaults from "./templates" | ||
import { SECTION_NAMES, PATHS } from "./components/vars" | ||
import { | ||
PoseTable, | ||
Nav, | ||
NavDetailed, | ||
HexapodPlot, | ||
DimensionsWidget, | ||
AlertBox, | ||
} from "./components" | ||
import { | ||
ForwardKinematicsPage, | ||
InverseKinematicsPage, | ||
LandingPage, | ||
LegPatternPage, | ||
WalkingGaitsPage, | ||
} from "./components/pages" | ||
import { SECTION_NAMES, PATH_LINKS } from "./components/vars" | ||
import { Nav } from "./components" | ||
|
||
import Routes from "./routes" | ||
|
||
ReactGA.initialize("UA-170794768-1", { | ||
//debug: true, | ||
|
@@ -28,9 +16,7 @@ ReactGA.initialize("UA-170794768-1", { | |
|
||
class App extends React.Component { | ||
state = { | ||
currentPage: SECTION_NAMES.LandingPage, | ||
inHexapodPage: false, | ||
showPoseMessage: true, | ||
showPoseMessage: false, | ||
showInfo: false, | ||
info: {}, | ||
|
||
|
@@ -53,25 +39,29 @@ class App extends React.Component { | |
|
||
onPageLoad = pageName => { | ||
ReactGA.pageview(window.location.pathname + window.location.search) | ||
this.setState({ currentPage: pageName }) | ||
|
||
if (pageName === SECTION_NAMES.landingPage) { | ||
this.setState({ | ||
inHexapodPage: false, | ||
return this.setState({ | ||
showInfo: false, | ||
showPoseMessage: false, | ||
}) | ||
return | ||
} | ||
|
||
this.setState({ | ||
inHexapodPage: true, | ||
showInfo: false, | ||
showPoseMessage: false, | ||
hexapodParams: { ...this.state.hexapodParams, pose: defaults.DEFAULT_POSE }, | ||
}) | ||
|
||
this.updatePlot(this.state.hexapodParams.dimensions, defaults.DEFAULT_POSE) | ||
return this.setState( | ||
{ | ||
showInfo: false, | ||
showPoseMessage: false, | ||
hexapodParams: { | ||
...this.state.hexapodParams, | ||
pose: defaults.DEFAULT_POSE, | ||
}, | ||
}, | ||
() => | ||
this.updatePlot( | ||
this.state.hexapodParams.dimensions, | ||
defaults.DEFAULT_POSE | ||
) | ||
) | ||
} | ||
|
||
/* * * * * * * * * * * * * * | ||
|
@@ -80,7 +70,7 @@ class App extends React.Component { | |
|
||
updatePlot = (dimensions, pose) => { | ||
const newHexapodModel = new VirtualHexapod(dimensions, pose) | ||
this.updatePlotWithHexapod(newHexapodModel) | ||
return this.updatePlotWithHexapod(newHexapodModel) | ||
} | ||
|
||
updatePlotWithHexapod = hexapod => { | ||
|
@@ -89,7 +79,7 @@ class App extends React.Component { | |
} | ||
|
||
const [data, layout] = getNewPlotParams(hexapod, this.state.plot.latestCameraView) | ||
this.setState({ | ||
return this.setState({ | ||
plot: { | ||
...this.state.plot, | ||
data, | ||
|
@@ -106,7 +96,7 @@ class App extends React.Component { | |
logCameraView = relayoutData => { | ||
const newCameraView = relayoutData["scene.camera"] | ||
const plot = { ...this.state.plot, latestCameraView: newCameraView } | ||
this.setState({ ...this.state, plot: plot }) | ||
return this.setState({ ...this.state, plot: plot }) | ||
} | ||
|
||
/* * * * * * * * * * * * * * | ||
|
@@ -115,7 +105,7 @@ class App extends React.Component { | |
|
||
updateIk = (hexapod, updatedStateParams) => { | ||
this.updatePlotWithHexapod(hexapod) | ||
this.setState({ ...updatedStateParams }) | ||
return this.setState({ ...updatedStateParams }) | ||
} | ||
|
||
updateDimensions = dimensions => | ||
|
@@ -124,101 +114,34 @@ class App extends React.Component { | |
updatePose = pose => this.updatePlot(this.state.hexapodParams.dimensions, pose) | ||
|
||
/* * * * * * * * * * * * * * | ||
* Control display of widgets | ||
* Layout | ||
* * * * * * * * * * * * * */ | ||
|
||
mightShowMessage = () => | ||
this.state.showInfo ? <AlertBox info={this.state.info} /> : null | ||
|
||
mightShowDetailedNav = () => (this.state.inHexapodPage ? <NavDetailed /> : null) | ||
|
||
mightShowPoseTable = () => { | ||
if (this.state.showPoseMessage) { | ||
return <PoseTable pose={this.state.hexapodParams.pose} /> | ||
render() { | ||
const { plot, ...rest } = this.state | ||
const routeProps = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could there be a better way to structure this than pushing about 15 props on route? Maybe using contexts ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I actually a branch where I've built the Provider pattern, so that'll come up next. I just needed to understand correctly which pieces of state are running through the App. For instance in that branch I have it divided as hexapod params, plot data, and the rest of settings. And that results in 3 context providers. Edit |
||
...rest, | ||
...plot, | ||
revision: plot.revisionCounter, | ||
onRelayout: this.logCameraView, | ||
updatePose: this.updatePose, | ||
updateIk: this.updateIk, | ||
updateDimensions: this.updateDimensions, | ||
} | ||
return ( | ||
<Router> | ||
<Nav /> | ||
<Switch> | ||
<Route path={PATH_LINKS.map(({ path }) => path)} exact> | ||
<Routes {...routeProps} onPageLoad={this.onPageLoad} /> | ||
</Route> | ||
<Route> | ||
<Redirect to="/" /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💯 👍 |
||
</Route> | ||
</Switch> | ||
</Router> | ||
) | ||
} | ||
|
||
mightShowDimensions = () => { | ||
if (this.state.inHexapodPage) { | ||
return ( | ||
<DimensionsWidget | ||
params={{ dimensions: this.state.hexapodParams.dimensions }} | ||
onUpdate={this.updateDimensions} | ||
/> | ||
) | ||
} | ||
} | ||
|
||
mightShowPlot = () => ( | ||
<div className={this.state.inHexapodPage ? "plot border" : "no-display"}> | ||
<HexapodPlot | ||
data={this.state.plot.data} | ||
layout={this.state.plot.layout} | ||
onRelayout={this.logCameraView} | ||
revision={this.state.plot.revisionCounter} | ||
/> | ||
</div> | ||
) | ||
|
||
/* * * * * * * * * * * * * * | ||
* Pages | ||
* * * * * * * * * * * * * */ | ||
|
||
showPage = () => ( | ||
<Switch> | ||
<Route path="/" exact> | ||
<LandingPage onMount={this.onPageLoad} /> | ||
</Route> | ||
<Route path={PATHS.forwardKinematics.path}> | ||
<ForwardKinematicsPage | ||
params={{ pose: this.state.hexapodParams.pose }} | ||
onUpdate={this.updatePose} | ||
onMount={this.onPageLoad} | ||
/> | ||
</Route> | ||
<Route path={PATHS.inverseKinematics.path}> | ||
<InverseKinematicsPage | ||
params={{ | ||
dimensions: this.state.hexapodParams.dimensions, | ||
}} | ||
onUpdate={this.updateIk} | ||
onMount={this.onPageLoad} | ||
/> | ||
</Route> | ||
<Route path={PATHS.legPatterns.path}> | ||
<LegPatternPage onUpdate={this.updatePose} onMount={this.onPageLoad} /> | ||
</Route> | ||
<Route path={PATHS.walkingGaits.path}> | ||
<WalkingGaitsPage | ||
params={{ | ||
dimensions: this.state.hexapodParams.dimensions, | ||
}} | ||
onUpdate={this.updatePose} | ||
onMount={this.onPageLoad} | ||
/> | ||
</Route> | ||
</Switch> | ||
) | ||
|
||
/* * * * * * * * * * * * * * | ||
* Layout | ||
* * * * * * * * * * * * * */ | ||
|
||
render = () => ( | ||
<Router> | ||
<Nav /> | ||
<div className="main content"> | ||
<div className="sidebar column-container cell"> | ||
{this.mightShowDimensions()} | ||
{this.showPage()} | ||
{this.mightShowPoseTable()} | ||
{this.mightShowMessage()} | ||
</div> | ||
{this.mightShowPlot()} | ||
</div> | ||
{this.mightShowDetailedNav()} | ||
</Router> | ||
) | ||
} | ||
|
||
export default App |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
import React from "react" | ||
|
||
const createPlotlyComponent = () => ({ style }) => <div style={style}></div> | ||
const createPlotlyComponent = () => ({ style, testId }) => ( | ||
<div style={style} data-testid={testId}></div> | ||
) | ||
|
||
export default createPlotlyComponent |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,72 @@ | ||
import React from "react" | ||
import Plotly from "plotly.js-gl3d-dist-min" | ||
import React, { useCallback, useLayoutEffect, useState, useRef } from "react" | ||
import createPlotlyComponent from "react-plotly.js/factory" | ||
const Plot = createPlotlyComponent(Plotly) | ||
|
||
const HexapodPlot = props => { | ||
import { sleep } from "../utils" | ||
|
||
const PlotlyPromise = () => | ||
import("plotly.js-gl3d-dist-min").then(Plotly => Plotly.default) | ||
|
||
export const HexapodPlot = ({ data, layout, onRelayout, revision, promise }) => { | ||
const ref = useRef() | ||
const loadingRef = useRef() | ||
const promiseRef = useRef(promise) | ||
const [ready, setReady] = useState(false) | ||
const [error, setError] = useState(false) | ||
|
||
const loader = useCallback(() => { | ||
setError(false) | ||
|
||
promiseRef | ||
.current() | ||
.then(Plotly => { | ||
ref.current = createPlotlyComponent(Plotly) | ||
}) | ||
.then(sleep(250)) | ||
.then(() => { | ||
if (loadingRef.current) { | ||
setReady(true) | ||
} | ||
}) | ||
.catch(() => setError(true)) | ||
}, []) | ||
|
||
useLayoutEffect(() => { | ||
loader() | ||
}, [loader]) | ||
|
||
if (error) { | ||
return ( | ||
<> | ||
<h2>Error Loading Plotly</h2> | ||
<button className="button" onClick={loader}> | ||
Retry | ||
</button> | ||
</> | ||
) | ||
} | ||
|
||
if (!ready) { | ||
return <h2 ref={loadingRef}>Loading...</h2> | ||
} | ||
|
||
const Plot = ref.current | ||
|
||
return ( | ||
<Plot | ||
data={props.data} | ||
layout={props.layout} | ||
data={data} | ||
layout={layout} | ||
useResizeHandler={true} | ||
style={{ height: "100%", width: "100%" }} | ||
config={{ displaylogo: false, responsive: true }} | ||
onRelayout={props.onRelayout} | ||
revision={props.revision} | ||
onRelayout={onRelayout} | ||
revision={revision} | ||
testId="plot" | ||
/> | ||
) | ||
} | ||
|
||
export default HexapodPlot | ||
const HexapodPlotWithPlotlyPromise = props => ( | ||
<HexapodPlot {...props} promise={PlotlyPromise} /> | ||
) | ||
|
||
export default HexapodPlotWithPlotlyPromise |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for bumping this up 👍 💯