nebula.gl icon indicating copy to clipboard operation
nebula.gl copied to clipboard

HTML overlay component expects viewport prop

Open biniyam17 opened this issue 4 years ago • 4 comments

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

biniyam17 avatar Apr 30 '21 17:04 biniyam17

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

biniyam17 avatar Apr 30 '21 17:04 biniyam17

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 avatar Apr 30 '21 17:04 biniyam17

@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).

Inkedhtml-overlay-error_LI

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"

bishoym avatar Aug 16 '21 23:08 bishoym

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 />

makeupsomething avatar May 17 '22 04:05 makeupsomething