nebula.gl
nebula.gl copied to clipboard
HTML overlay component expects viewport prop
Describe the bug
HTML Overlay component is typed for optional viewport but internal logic relies on viewport.
Actual Result
<HtmlOverlay> <HtmlOverlayItem coordinates={coordinates}>{title}</HtmlOverlayItem> </HtmlOverlay>
This code is from the docs produces the following error
Uncaught TypeError: Cannot read property 'project' of undefined which is from html-overlay.tsx.
Expected Result
Expected html overlay to not produce error and show title on deck gl map.
Reproduce Steps
Add HTML Overlay without viewport value passed as a child of any deck gl layer. i.e.
<DeckGL initialViewState={initialViewState} controller={true}> <StaticMap mapboxApiAccessToken={MAPBOX_ACCESS_TOKEN} /> <HtmlOverlay> <HtmlOverlayItem coordinates={coordinates}>{title}</HtmlOverlayItem> </HtmlOverlay> </DeckGL>
Verify if browser crashes / error is caught.
Possible fixes
The code that is messing up is
getCoords(coordinates: number[]): [number, number] { const pos = this.props.viewport.project(coordinates); if (!pos) return [-1, -1]; return pos; }
Is it possible to add optional chaining so it reads this.props?.viewport.project(coordinates) considering the viewport prop is typed as optional in the HTML Overlay class.
To Do List
Upon further investigation, it seems the issue is from the typescript migration where all the props for HTMLOverlay were marked as optional. See https://github.com/uber/nebula.gl/pull/377/files
I was able to get around this issue by taking out the HTML Overlay from my render and just rendering the HTMLOverlayItem. However, this does feel like a hack because according to the official documentation HtmlOverlayItem must be direct children of HtmlOverlay or HtmlClusterOverlay.
@biniyam17 any chance you could elaborate on how you got HtmlOverlayItem working independently of its required parent?
Without HtmlOverlay, my text becomes incorrectly positioned (sticks to the top-left corner of the map container element).

Putting HtmlOverlay and its HtmlOverlayItem children directly within DeckGL's children works as expected.
<DeckGL //...deckGLprops>
<StaticMap mapboxApiAccessToken={MAPBOX_ACCESS_TOKEN} />
<HtmlOverlay>
<HtmlOverlayItem
style={{ background: "red", padding: 4, color: "white" }}
coordinates={[-122.43, 37.775]}
>
Text sample
</HtmlOverlayItem>
</HtmlOverlay>
</DeckGL>
The second I try to move it out to a custom component, I get the error you described in the original post.
<DeckGL //...deckGLprops>
<StaticMap mapboxApiAccessToken={MAPBOX_ACCESS_TOKEN} />
<LabelsController /> // this breaks with the "Cannot read property 'project' of undefined" error
</DeckGL>
Any ideas as to why this behaviour is occurring? I'm on @nebula.gl/overlays: "0.21.1"
This should work as a solution
<DeckGL //...deckGLprops>
<StaticMap mapboxApiAccessToken={MAPBOX_ACCESS_TOKEN} />
{({ x, y, width, height, viewState, viewport }) => (
<LabelsController viewport={viewport}/>
)}
</DeckGL>
Then in the LabelsController component just extract viewport from the props and pass it into <HtmlOverlay />