Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"@deck.gl/extensions": "^9.1.14",
"@deck.gl/layers": "^9.1.14",
"@deck.gl/react": "^9.1.14",
"@deck.gl/mapbox": "^9.1.14",
"@geoarrow/deck.gl-layers": "^0.3.1",
"@babel/runtime": "^7.28.4",
"@nextui-org/react": "^2.4.8",
Expand Down
111 changes: 67 additions & 44 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@ import * as React from "react";
import { useEffect, useCallback, useState } from "react";
import { createRender, useModelState, useModel } from "@anywidget/react";
import type { Initialize, Render } from "@anywidget/types";
import Map from "react-map-gl/maplibre";
import DeckGL from "@deck.gl/react";
import Map, {
useControl,
FullscreenControl,
NavigationControl,
ScaleControl,
} from "react-map-gl/maplibre";
import { MapViewState, PickingInfo, type Layer } from "@deck.gl/core";
import { BaseLayerModel, initializeLayer } from "./model/index.js";
import type { WidgetModel } from "@jupyter-widgets/base";
Expand All @@ -13,6 +17,10 @@ import { v4 as uuidv4 } from "uuid";
import { Message } from "./types.js";
import { flyTo } from "./actions/fly-to.js";
import { useViewStateDebounced } from "./state";
import {
MapboxOverlay as DeckOverlay,
MapboxOverlayProps,
} from "@deck.gl/mapbox";

import { MachineContext, MachineProvider } from "./xstate";
import * as selectors from "./xstate/selectors";
Expand All @@ -38,6 +46,13 @@ const DEFAULT_INITIAL_VIEW_STATE = {
const DEFAULT_MAP_STYLE =
"https://basemaps.cartocdn.com/gl/positron-nolabels-gl-style/style.json";

function DeckGLOverlay(props: MapboxOverlayProps) {
const overlay = useControl(() => new DeckOverlay(props));

overlay.setProps(props);
return null;
}
Comment on lines +49 to +54
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the standard way to use DeckOverlay in react? @felixpalmer

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


async function getChildModelState(
childModels: WidgetModel[],
childLayerIds: string[],
Expand Down Expand Up @@ -237,57 +252,65 @@ function App() {
/>
)}
<div className="bg-red-800 h-full w-full relative">
<DeckGL
style={{ width: "100%", height: "100%" }}
<Map
reuseMaps
id={`map-${mapId}`}
initialViewState={
["longitude", "latitude", "zoom"].every((key) =>
Object.keys(initialViewState).includes(key),
)
? initialViewState
: DEFAULT_INITIAL_VIEW_STATE
}
controller={true}
layers={
bboxSelectPolygonLayer
? layers.concat(bboxSelectPolygonLayer)
: layers
}
getTooltip={(showTooltip && getTooltip) || undefined}
getCursor={() => (isDrawingBBoxSelection ? "crosshair" : "grab")}
pickingRadius={pickingRadius}
onClick={onMapClickHandler}
onHover={onMapHoverHandler}
useDevicePixels={
isDefined(useDevicePixels) ? useDevicePixels : true
}
// https://deck.gl/docs/api-reference/core/deck#_typedarraymanagerprops
_typedArrayManagerProps={{
overAlloc: 1,
poolSize: 0,
mapStyle={mapStyle || DEFAULT_MAP_STYLE}
attributionControl={{
customAttribution,
}}
onViewStateChange={(event) => {
const { viewState } = event;

// This condition is necessary to confirm that the viewState is
// of type MapViewState.
if ("latitude" in viewState) {
const { longitude, latitude, zoom, pitch, bearing } = viewState;
setViewState({
longitude,
latitude,
zoom,
pitch,
bearing,
});
}
}}
parameters={parameters || {}}
>
<Map
mapStyle={mapStyle || DEFAULT_MAP_STYLE}
customAttribution={customAttribution}
></Map>
</DeckGL>
<FullscreenControl position="top-left" />
<NavigationControl position="top-left" />
<ScaleControl position="bottom-left" />
<DeckGLOverlay
// interleaved
style={{ width: "100%", height: "100%" }}
layers={
bboxSelectPolygonLayer
? layers.concat(bboxSelectPolygonLayer)
: layers
}
getTooltip={(showTooltip && getTooltip) || undefined}
getCursor={() => (isDrawingBBoxSelection ? "crosshair" : "grab")}
pickingRadius={pickingRadius}
onClick={onMapClickHandler}
onHover={onMapHoverHandler}
useDevicePixels={
isDefined(useDevicePixels) ? useDevicePixels : true
}
// https://deck.gl/docs/api-reference/core/deck#_typedarraymanagerprops
_typedArrayManagerProps={{
overAlloc: 1,
poolSize: 0,
}}
onViewStateChange={(event) => {
const { viewState } = event;

// This condition is necessary to confirm that the viewState is
// of type MapViewState.
if ("latitude" in viewState) {
const { longitude, latitude, zoom, pitch, bearing } =
viewState;
setViewState({
longitude,
latitude,
zoom,
pitch,
bearing,
});
}
}}
Comment on lines +294 to +310
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: I need to check that deck.gl still sends these events even when the view state is managed by maplibre.

For background: This sets the current view state on the model so that it can be updated on the Python side, which can be accessed via Map.view_state.

parameters={parameters || {}}
/>
</Map>
</div>
</div>
</div>
Expand Down