diff --git a/examples/deckgl-overlay/src/app.tsx b/examples/deckgl-overlay/src/app.tsx index 1c0046c99..7dc5a25af 100644 --- a/examples/deckgl-overlay/src/app.tsx +++ b/examples/deckgl-overlay/src/app.tsx @@ -1,34 +1,42 @@ import * as React from 'react'; import {render} from 'react-dom'; -import DeckGL, {ArcLayer} from 'deck.gl'; -import Map from 'react-map-gl'; +import {ArcLayer} from 'deck.gl'; +import {MapboxLayer} from '@deck.gl/mapbox'; +import Map, {Layer, MapboxMap} from 'react-map-gl'; +import ControlPanel from './control-panel'; const TOKEN = ''; // Set your mapbox token here export default function App() { - const arcLayer = new ArcLayer({ - data: 'https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/bart-segments.json', - getSourcePosition: d => d.from.coordinates, - getTargetPosition: d => d.to.coordinates, - getSourceColor: [255, 200, 0], - getTargetColor: [0, 140, 255], - getWidth: 12 - }); + const [overLabels, setOverLabels] = React.useState(true); + const layer = React.useMemo(() => { + return new MapboxLayer({ + id: 'arcs', + type: ArcLayer, + data: 'https://raw.githubusercontent.com/visgl/deck.gl-data/master/website/bart-segments.json', + getSourcePosition: d => d.from.coordinates, + getTargetPosition: d => d.to.coordinates, + getSourceColor: [255, 200, 0], + getTargetColor: [0, 140, 255], + getWidth: 12 + }); + }, []); return ( - - - + <> + + + + + ); } diff --git a/examples/deckgl-overlay/src/control-panel.tsx b/examples/deckgl-overlay/src/control-panel.tsx new file mode 100644 index 000000000..48d1f1e96 --- /dev/null +++ b/examples/deckgl-overlay/src/control-panel.tsx @@ -0,0 +1,32 @@ +import React from 'react'; + +function Checkbox({name, value, onChange}) { + return ( +
+ + onChange(name, evt.target.checked)} /> +
+ ); +} + +function ControlPanel({ + overLabels, + setOverLabels +}: { + overLabels: boolean; + setOverLabels: (v: boolean) => void; +}) { + return ( +
+

Deck.gl layer

+

A deck.gl overlay can be used and inserted inside the Mapbox layers.

+ setOverLabels(v)} + /> +
+ ); +} + +export default ControlPanel; diff --git a/src/components/layer.ts b/src/components/layer.ts index 5c17c224e..4d343ec75 100644 --- a/src/components/layer.ts +++ b/src/components/layer.ts @@ -5,14 +5,21 @@ import {deepEqual} from '../utils/deep-equal'; import type {MapboxMap, AnyLayer} from '../types'; -export type LayerProps = AnyLayer & { +export type DeprecatedLayerProps = AnyLayer & { id?: string; /** If set, the layer will be inserted before the specified layer */ beforeId?: string; }; +export type LayerProps = + | { + layer: AnyLayer; + beforeId?: string; + } + | DeprecatedLayerProps; + /* eslint-disable complexity, max-statements */ -function updateLayer(map: MapboxMap, id: string, props: LayerProps, prevProps: LayerProps) { +function updateLayer(map: MapboxMap, id: string, props: AnyLayer, prevProps: AnyLayer) { assert(props.id === prevProps.id, 'layer id changed'); assert(props.type === prevProps.type, 'layer type changed'); @@ -20,11 +27,8 @@ function updateLayer(map: MapboxMap, id: string, props: LayerProps, prevProps: L return; } - const {layout = {}, paint = {}, filter, minzoom, maxzoom, beforeId} = props; + const {layout = {}, paint = {}, filter, minzoom, maxzoom} = props; - if (beforeId !== prevProps.beforeId) { - map.moveLayer(id, beforeId); - } if (layout !== prevProps.layout) { const prevLayout = prevProps.layout || {}; for (const key in layout) { @@ -59,14 +63,16 @@ function updateLayer(map: MapboxMap, id: string, props: LayerProps, prevProps: L } } -function createLayer(map: MapboxMap, id: string, props: LayerProps) { +function isMapStyleLoaded(map: MapboxMap) { // @ts-ignore - if (map.style && map.style._loaded && (!('source' in props) || map.getSource(props.source))) { - const options: LayerProps = {...props, id}; - delete options.beforeId; + return map.style && map.style._loaded; +} +function createLayer(map: MapboxMap, id: string, layerProps: LayerProps, beforeId: string) { + // @ts-ignore + if (isMapStyleLoaded(map) && (!('source' in layerProps) || map.getSource(layerProps.source))) { // @ts-ignore - map.addLayer(options, props.beforeId); + map.addLayer(layerProps, beforeId); } } @@ -74,12 +80,23 @@ function createLayer(map: MapboxMap, id: string, props: LayerProps) { let layerCounter = 0; -function Layer(props: LayerProps) { +function Layer(props: LayerProps & {layer?: AnyLayer}) { const map: MapboxMap = useContext(MapContext).map.getMap(); - const propsRef = useRef(props); + + const layerProps = useMemo(() => { + if (props.layer) { + return props.layer; + } + const res = {...props}; + delete res.beforeId; + return res as DeprecatedLayerProps; + }, [props.layer, props]); + + const layerPropsRef = useRef(layerProps); const [, setStyleLoaded] = useState(0); + const beforeId = props.beforeId; - const id = useMemo(() => props.id || `jsx-layer-${layerCounter++}`, []); + const id = useMemo(() => layerProps.id || `jsx-layer-${layerCounter++}`, []); useEffect(() => { if (map) { @@ -102,16 +119,22 @@ function Layer(props: LayerProps) { const layer = map && map.style && map.getLayer(id); if (layer) { try { - updateLayer(map, id, props, propsRef.current); + updateLayer(map, id, layerProps, layerPropsRef.current); } catch (error) { console.warn(error); // eslint-disable-line } } else { - createLayer(map, id, props); + createLayer(map, id, layerProps, beforeId); } + useEffect(() => { + if (beforeId && isMapStyleLoaded(map)) { + map.moveLayer(id, beforeId); + } + }, [beforeId]); + // Store last rendered props - propsRef.current = props; + layerPropsRef.current = layerProps; return null; }