Stack Overflow Asked on November 12, 2021
How can I create elements outside of a Mapbox map object that can be dragged into it? For example, let’s say I want to render a list of locations on a page. Each location is a React component with a custom marker or icon.
Next to this list of locations is a Mapbox map. The list of locations is not rendered inside the map. While I know it’s possible to make these individual location components draggable, is it possible to drag and drop them into a Mapbox map and have it recognized as actual markers with latitude/longitude coordinates on the map? If so, how can I do this?
Here are the relevant source files in my code that I have tried:
index.js
import dynamic from "next/dynamic";
import { useSelector } from "react-redux";
import Plant from "../../components/Plant";
const MapboxMap = dynamic(() => import("../../components/MapboxGLMap"), {
ssr: false,
});
const Blueprint = () => {
const plants = useSelector((state) => state.plants);
const showPlants = () => {
return (
<React.Fragment>
{plants.map((plant) => (
<Plant plant={plant} />
))}
</React.Fragment>
);
};
return (
<React.Fragment>
<div className="ui container centered grid blueprint">
<div className="three wide column scrollable">
<div className="ui link one cards">{showPlants()}</div>
</div>
<div className="twelve wide column">
<MapboxMap />
</div>
<style jsx>{`
.scrollable {
height: calc(100vh);
overflow-x: auto;
}
`}</style>
</React.Fragment>
);
};
export default Blueprint;
Plant.jsx
import React from "react";
import { useDrag } from "react-dnd";
const ItemTypes = {
PLANT: "plant",
};
const Plant = ({ plant }) => {
const [{ isDragging }, drag] = useDrag({
item: { type: ItemTypes.PLANT },
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
});
return (
<div
ref={drag}
style={{
opacity: isDragging ? 0.1 : 1,
cursor: "move",
}}
key={plant.id}
className="card"
>
<div className="image">
<img src="/white-image.png" />
</div>
<div className="content">
<div className="center aligned">{plant.common_name}</div>
</div>
</div>
);
};
export default Plant;
MapboxGLMap.jsx
import React, { useEffect, useRef, useState } from "react";
import mapboxgl from "mapbox-gl";
import MapboxGeocoder from "@mapbox/mapbox-gl-geocoder";
import MapboxDraw from "@mapbox/mapbox-gl-draw";
const MAPBOX_TOKEN = "xxx";
const styles = {
width: "100%",
height: "100%",
position: "absolute",
};
const MapboxGLMap = () => {
const [map, setMap] = useState(null);
const [lng, setLng] = useState(null);
const [lat, setLat] = useState(null);
const [plant, setPlant] = useState(null);
const mapContainer = useRef(null);
useEffect(() => {
mapboxgl.accessToken = MAPBOX_TOKEN;
const initializeMap = ({ setMap, mapContainer }) => {
const map = new mapboxgl.Map({
container: mapContainer.current,
style: "mapbox://styles/mapbox/satellite-v9", // stylesheet location
center: [0, 0],
zoom: 5,
});
map.on("load", () => {
setMap(map);
map.resize();
});
map.on("click", (e) => {});
map.addControl(
new MapboxGeocoder({
accessToken: MAPBOX_TOKEN,
mapboxgl: mapboxgl,
})
);
const draw = new MapboxDraw({
displayControlsDefault: false,
controls: {
polygon: true,
trash: true,
},
});
map.addControl(draw);
map.on("draw.create", (e) => {
console.log("e =>", e);
console.log("draw.getAll()", draw.getAll());
});
map.on("mousemove", (e) => {
// console.log(e.point);
setLng(e.lngLat.wrap().lng);
setLat(e.lngLat.wrap().lat);
});
};
if (!map) initializeMap({ setMap, mapContainer });
}, [map]);
return <div ref={(el) => (mapContainer.current = el)} style={styles} />;
};
export default MapboxGLMap;
Actually, based on your related tags I imagine that you wanna drag and drop something like pin from outside to the map area. you use reactjs
tags, it means you wanna do it by using ReactJS.
For this, you should install Mapbox by npm or yarn:
npm install mapbox-gl --save
or
yarn add mapbox-gl
Then you should wrap the Mapbox area in a drop zone. for this, you could use react-dropzone
. install it by the following command:
npm install react-dropzone --save
or
yarn add react-dropzone
Add the following line to HTML template:
<link href='https://api.tiles.mapbox.com/mapbox-gl-js/v1.11.1/mapbox-gl.css' rel='stylesheet' />
Then use it like below:
import React from 'react';
import Dropzone from 'react-dropzone';
import mapboxgl from 'mapbox-gl';
mapboxgl.accessToken = 'MAPBOX_ACCESS_TOKEN';
class MapComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
lng: 5,
lat: 34,
zoom: 2,
};
}
componentDidMount() {
const map = new mapboxgl.Map({
container: this.mapContainer,
style: 'mapbox://styles/mapbox/streets-v11',
center: [this.state.lng, this.state.lat],
zoom: this.state.zoom,
});
map.on('move', () => {
this.setState({
lng: map.getCenter().lng.toFixed(4),
lat: map.getCenter().lat.toFixed(4),
zoom: map.getZoom().toFixed(2),
});
});
}
render() {
return (
<Dropzone>
{({ getRootProps, getInputProps }) => (
<section>
<div {...getRootProps()}>
<input {...getInputProps()} />
<div
ref={el => {
this.mapContainer = el;
}}
/>
</div>
</section>
)}
</Dropzone>
);
}
}
By using this method you can drop some images and got it and based on the drop position show it on the map.
Note: reduce the file type catching to image file type like jpg
/png
Answered by AmerllicA on November 12, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP