Mapbox: Add controller to Deck.gl component
I'm trying to disable scrollZoom in my DeckGL component. I am, however, having difficulty understanding the documentation for passing Controllers to these objects. My current implementation simplified for brevity is:
new Deck({
controller: { scrollZoom: false },
initialViewState: {
latitude: 42.508108,
longitude: -71.508701,
zoom: 10,
maxZoom: 18,
minZoom: 4,
pitch: 45,
bearing: 0,
},
});
return (
<>
<DeckGL
ContextProvider={MapContext.Provider}
controller={true}
effects={effects}
getTooltip={getTooltip}
initialViewState={INITIAL_VIEW_STATE_AREA}
layers={layers}
onWebGLInitialized={onInitialized}
>
<InteractiveMap
reuseMaps
ref={mapRef}
mapStyle={MAP_STYLE}
preventStyleDiffing={true}
mapboxApiAccessToken={process.env.REACT_APP_MAPBOX_TOKEN}
/>
</DeckGL>
</>
The code above returns a static map. I would've expected the code map to enable you to pan but not scroll.
Is there an example or additional documentation that provides a better understanding of this implementation?
1 answer
-
answered 2021-02-23 16:20
mmz
Ok so
Deck
is the non-React flavor ofDeckGL
. To adapt the example in the documentation you have to pass the controller prop to the DeckGL component. So, for example:<DeckGL ContextProvider={MapContext.Provider} controller={{ scrollZoom: false }} effects={effects} getTooltip={getTooltip} initialViewState={INITIAL_VIEW_STATE_AREA} layers={layers} onWebGLInitialized={onInitialized} > <InteractiveMap reuseMaps ref={mapRef} mapStyle={MAP_STYLE} preventStyleDiffing={true} mapboxApiAccessToken={process.env.REACT_APP_MAPBOX_TOKEN} /> </DeckGL>
This line changed:
controller={{ scrollZoom: false }}
See also questions close to this topic
-
How to Update json.stringify on keystroke with onChange handler in react
I am currently working on a react project.I have a nested json object.E.g
Const tree = {
name:"root",
chidren: [
{ name: "child1",
data: "hello-world"
}
]
}
How can i update its value in real-time while typing. Example output with Json.stringify(tree) {"name":"child-alan","data":"hi-world"}.How do I go about this.Any answer will be really appreciated
-
React Typescript: Optional Functions are not considered undefined
I am building a React Functional Component and my component should offer an optional function prop. If this prop/the function is provided, I want to render something and also enable the clicking on the component.
export type AvatarProps = { onEdit?: () => void; }; const Avatar: FunctionComponent<AvatarProps> = (props: AvatarProps) => { props.onEdit && (console.log("test");
Unfortunately the function is always considered and is never undefined, although I do not provide it.
In the Google Chrome React Add-on it notices the function as onEdit:ƒ actionHandler() {} if no function is provided. If I provide the function, the Add-on notices onEdit : ƒ onEdit() {}
How can I properly check if the function was provided or not.
-
How change gray background by item on another, when he is selected?
<FormControl> <Select value={val} onChange={handleSelect} input={<BootstrapInput />} displayEmpty // classes={{selectMenu: { marginTop: 50 }}} MenuProps={{...menuProps, classes: {paper: classes.paper, selected: classes.root, option: classes.root}}} classes={{ icon: classes.icon, // selectMenu: classes.selectMenu, // select: classes.root }} > <MenuItem value={0} disabled classes={{ root: classes.disabledMenuItem }}> Test </MenuItem> <MenuItem value="" style={{display: 'none'}}>Select</MenuItem> <MenuItem value={10}>Ten</MenuItem> <MenuItem value={20}>Twenty</MenuItem> <MenuItem value={30}>Thirty</MenuItem> </Select> </FormControl>
Me need change background on green instead gray, when user click, and open again dropdown he expected green background but not gray, gray - is default, me need change this background
-
Mapbox destination placename not found
How can I get the place name on the destination while using directions. The retuning object just show the coordinates not the place name. Thank you.
-
How to change center Latitude and Longitude of a mapbox-gl in react js?
I am using Mapbox-gl package for Mapbox. I am rendering the map inside the useEffect and what I want to do is change the centre of Mapbox without completely rerendering the map. for example
const mapContainerRef = useRef(null); const [markerLngLat, setMarkerLngLat] = useState([85.324, 27.7172]); useEffect(() => { const map = new mapboxgl.Map({ container: mapContainerRef.current, style: 'mapbox://styles/lmaps/ckl6t1boq578819qod5v7ynby', center: markerLngLat, zoom: 13, }); },[]); return ( <div> <a onClick={setMarkerLngLat([65.468754, 44.57875])} /> <div className='listing-map-container' ref={mapContainerRef}></div> </div> );
With the click of the button, I want to move the centre of the map from the previous lat long to the newly set Latlong without re-rendering the entire map. Passing markerLngLat in the [] in useEffect works but it completely re-rerenders the map and all other 1000's markers on it, so can't prefer that way. The actual code is much longer and many markers are being marked on the map so I don't want to re-render the map entirely.
-
Plotly Mapbox Topographic Layer
Quick question, does plotly have any built-in topographic map layers? I didn’t see anything in the docs, but wanted to make sure I wasn’t missing a method to add elevation contour lines to a 2D map.
I'm trying to plot a heatmap of a vehicle's energy consumption over a particular route. The code for the plot shown below is simple enough, but I'm not sure if there are additional mapbox_styles available for plotly beyond what is listed in the docs.
fig = px.density_mapbox( df_merge, lat="Latitude", lon="Longitude", z="power", custom_data=["Elevation"], radius=1, mapbox_style="stamen-terrain", ) fig.update_traces( hovertemplate="Power = %{z} kw<br>Latitude = %{lat}<br>Longitude = %{lon}<br>Elevation = %{customdata[0]} m<extra></extra>" )
Appreciate any guidance!
-
Make symbol layer icon-size zoom invariant
I am attempting to place a hexagon (centred over co-ordinates) which I can interact with, hover/onclick. The method I am using is to LoadImage(..._Hexagon.png) and then addLayer. Eventually the idea is to have many hexagons over specific areas.
I have obtained the desired interaction with the shape, but I would like this layer to be invariant under zoom (ie I have the hexagons cover an area of x square km at all times regardless of zoom). Is there an efficient way to do this? Will another method be better? etc
Thank you in advance for any and all advice!
-
Adding A Date Range Slider to a Map to Filter Data, Mapbox GL JS
Hello I'm relatively new to Mapbox and have been working on creating a map for a University Project.
Currently I import a CSV file and convert it to geojson using the csv2geojson() function that Mapbox has created. However, I am having trouble finding an example that matches exactly what I am trying to do.
What I need is to create a Date range slider. For example, The user can set a date range of 01/01/2021 to 03/04/2021. This will then only show data points to have been taken within that date range.
The only examples I have seen has a slider that only shows the exact date or time that is selected. However, I need to include every data point within that date range, not just a single date. I am wondering if anyone has some examples for this or similar to this that can help me or adapt to fit my needs. As I am a little lost on where to start.
Thanks!
-
How to find all Mapbox layers in DeckGL?
I'm following this example that puts Mapbox labels on top of a layer. This seems to be written using the plain Mapbox package. I'm hoping to do the same for a map component in DeckGL.
The relevant code from the example:
const map = new mapboxgl.Map({ container: document.body, style: 'mapbox://styles/mapbox/light-v9', center: [-122.4, 37.79], zoom: 15, pitch: 60 }); map.on('load', () => { const firstLabelLayerId = map.getStyle().layers.find(layer => layer.type === 'symbol').id;
My code using DeckGL is:
<DeckGL initialViewState={INITIAL_VIEW_STATE} layers={layers} onClick={expandTooltip} onViewStateChange={hideTooltip} onWebGLInitialized={onInitialized} views={MAP_VIEW} controller={{ touchRotate: true, inertia: 600, }} > <StaticMap reuseMaps mapStyle={MAP_STYLE} preventStyleDiffing={true} mapboxApiAccessToken={process.env.REACT_APP_MAPBOX_TOKEN} /> </DeckGL>
How can I access
getStyle().layers
in the above components? I tried usinguseRef
, as in this simplified component:const mapRef = useRef(); <DeckGL {...viewport} maxZoom={20} mapboxApiAccessToken={process.env.REACT_APP_MAPBOX_TOKEN} ref={mapRef} >
but found that it doesn't contain information about the component.
-
D3 geoCircle with Deck.gl GeoJsonLayer not filling to map corners
I'm working with deck.gl on making a map, and we want to have a circle where you can customise the radius. This circle is generated using d3 (v5), with the d3.geoCircle function, as this can be easily put onto a deck.gl GeoJsonLayer. The problem is that when the radius gets too large, the circle (now geojson polygon) is not filling to the corners of the map.
As seen here:
The circle is behaving as expected, and how we want, but the fill of the circle isn't. I would expect the circle here to fill to the top-right and top-left corners after wrapping over the north pole, and then the bottom corners too.
I expect this is a problem with trying to use both d3 and deck.gl, which weren't designed to work together.
I think I can get it to work by manually inserting some extra coordinates into the geojson coordinates array, however, I was wondering if d3 already has a way of solving this, or if deck.gl does either.
Manually inserting them I believe will only work if the circle crosses the longitude 180 / -180 edges, as otherwise, they wont line up with the edges to be able to invert from.
I am using the OrthographicView for deck.gl, in order to get the equirectangular projection, however, the problem still happens for the regular Mercator MapView.
Deck.gl version: 8.4.0
d3 version: 5.12.0
-
Deckgl: async add layers with async data to deckgl react
I want to use Deck.gl with adding new layer and data is stream, and this is my code
useEffect(()=> { if (statusSocket) { config_layer.config.visState.layers.map((layer) => { console.log(layer.type) } }, [statusSocket);
-
How to get bounding box for styled data in vector tiles
I have a vector tileset (e.g. all the countries in the world).
Separately, I am running a query that gets a count for each country (e.g. how many times has X occurred in a given country). Using the query response data, I create a choropleth of the result by correlating the country ids in the query with the country ids in the tiles.Oftentimes, only a handful of countries are styled (other countries have a zero count). I would like to initialize the viewport to only those countries that have been styled, however...
I do not know how to obtain the geographic data (e.g. bounding box) of the countries that have been styled. The query only responds with the country codes and a count (no geographic data). As far as I can tell, the tiles only allow querying the attributes inherited from the original shapefile.
Is it possible to get the geographic data from the vector tiles themselves?
-
react-map-gl and using useContext and/or useState to change viewport from another component
I seem to be not understand anything lately and having a tough time grasping useContext and/or useState with React/Nextjs and react-map-gl.
Basically, I have two components. A searchbox utilizing Formik & a Map from react-map-gl. What I want to do is be able to have one of the variables from Formik be able to change the viewport on react-map-gl so it redirects the viewport of the map to the new coordinates. I tried researching and reading about what I can do to make this work but I just can't grasp it. I believe it has to be something simple and I'm just too new to understand. Every time I think I have it I get a error saying I can't actually do that.
For reference here's my current code using useState. Whenever I try to use it and hit the submit button I get " 1 of 1 unhandled error Unhandled Runtime Error
TypeError: setViewport is not a function "
which doesn't seem to make any sense :( . Other times when I can get it to work, I have to click the submit button twice to get the form to register the new setViewport. What am I doing wrong? Thank you for your help!
index.js
import { Grid } from '@material-ui/core'; import { useState } from 'react'; import SearchBox from '../components/searchbox'; import { getAllCampgrounds, getAllCities, getCampgroundsByCity, } from '../lib/api'; import Map from '../components/map'; export default function CampList({ graphCampgrounds, cities, campgroundsbycity, }) { const [viewport, setViewport] = useState({ height: '100vh', latitude: 44.0456, longitude: -71.6706, width: '100vw', zoom: 8, }); return ( <Grid container spacing={3}> <Grid item xs={12} sm={5} md={3} lg={2}> <SearchBox graphCampgrounds={graphCampgrounds} cities={cities} campgroundsbycity={campgroundsbycity} setViewport={() => setViewport} /> </Grid> <Grid item xs={12} sm={7} md={9} lg={10}> <Map campgrounds={graphCampgrounds} viewport={viewport} setViewport={() => setViewport} /> <pre style={{ fontSize: '2.5rem' }}>{}</pre> </Grid> </Grid> ); }
I omitted my getServerSideProps area. Here is my Searchbox.js:
import Link from 'next/link'; import { Form, Formik, Field, useFormik } from 'formik'; import { Paper, Grid, FormControl, InputLabel, Select, MenuItem, Button, } from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; import { useRouter } from 'next/router'; const useStyles = makeStyles(theme => ({ paper: { margin: 'auto', maxWidth: 500, padding: theme.spacing(3), }, })); export default function SearchBox({ graphCampgrounds, cities, campgroundsbycity, viewport, setViewport, }) { const router = useRouter(); const { query } = router; const handleSubmit = async values => { setViewport({ ...viewport, latitude: campgroundsbycity ? parseFloat(campgroundsbycity.nodes[0].acfDetails.latitude.toFixed(4)) : 44.43, longitude: campgroundsbycity ? Math.abs( parseFloat(campgroundsbycity.nodes[0].acfDetails.longitude.toFixed(4)) ) * -1 : -72.352, zoom: 11, }); router.push( { pathname: '/camps', query: { ...values, page: 1 }, }, undefined, { shallow: true } ); }; const classes = useStyles(); const smValue = singleColumn ? 12 : 6; const initialValues = { city: query.city || 'all' }; return ( <Formik initialValues={initialValues} onSubmit={handleSubmit}> {({ values, submitForm }) => ( <Form> <Paper className={classes.paper} elevation={5}> <Grid container spacing={3}> <Grid item xs={12} sm={smValue}> <FormControl fullWidth variant="outlined"> <InputLabel id="search-cities">City</InputLabel> <Field name="city" as={Select} labelId="search-cities" label="Cities" > <MenuItem value="all"> <em>All</em> </MenuItem> {cities.nodes.map(town => { return ( <MenuItem key={town.acfDetails.city} value={town.acfDetails.city} > {town.acfDetails.city} </MenuItem> ); })} </Field> </FormControl> </Grid> <Grid item xs={12}> <Button color="primary" variant="outlined" type="button" fullWidth onClick={submitForm} > Search Campgrounds </Button> </Grid> </Grid> </Paper> </Form> )} </Formik> ); }
And here's my map component:
import { useContext, useMemo } from 'react'; import ReactMapGL, { Marker, MapContext } from 'react-map-gl'; import { ViewportContext } from '../lib/state'; export default function Map({ campgrounds, viewport, setViewport }) { const markers = campgrounds.map(({ node }) => { console.log(node.acfDetails); return ( <Marker key={node.title} longitude={ Math.abs(parseFloat(node.acfDetails.longitude.toFixed(4))) * -1 } latitude={parseFloat(node.acfDetails.latitude.toFixed(4))} > <img src="pin.png" alt={node.title} /> </Marker> ); }); return ( <ReactMapGL mapboxApiAccessToken={process.env.NEXT_PUBLIC_MAPBOX_KEY} mapStyle="mapbox://styles/mapbox/outdoors-v11" {...viewport} onViewportChange={nextViewport => setViewport(nextViewport)} > {markers} </ReactMapGL> ); }
-
react-map-gl not showing in the production
I rendered 10 mapbox in one page. Here is the code to render mapbox.
Production link: http://d5lm5uvph2fbe.cloudfront.net/investigations/nuclear-reconstruction
I can see all 10 mapbox on my local, but there are only 3 mapbox showing on the production(AWS Cloudfront).
It's really weird and struggling for several days but I can't find the reason.
<ReactMapGL {...viewport} onViewportChange={(nextViewport) => setViewport(nextViewport)} mapboxApiAccessToken={accessToken} mapStyle={mapboxPrefix + mapStyle} preserveDrawingBuffer={true} reuseMaps={true} dragRotate={false} scrollZoom={false} > <NavigationControl style={{ right: 15, bottom: 30, }} /> </ReactMapGL>