I'm working on a React/MapboxGL app and I'm having some issue with my marker leaving the bounds of designated map area whenever i move the map around. I feel there may be some other larger underlying React rendering principals that I don't fully understand that is causing this problem for me. Any help would be much appreciated. Thanks!
Additionally I've noticed a blue highlightable border on the map whenever I click on the map which is not present in any of the tutorials/examples I've seen. Which leads me to further believe that it's how I am integrating mapbox-gl with React.
Here are the components I'm using-
Main Component
import React from 'react';
import ReactDOM from 'react-dom';
import List from './List.jsx';
import MapComponent from './Map.jsx';
import Header from './Header.jsx';
const appConstants = require('../constants/appConstants');
const host = 'http://localhost:8020';
const socket = io(host);
let key = 0;
class MainComponent extends React.Component {
constructor() {
super();
this.state = {
events: []
};
}
componentWillMount() {
socket.on('new event', (event) => this._handleStateChange(event));
}
render() {
return (
<div>
<div className="headerContainer">
<Header name={appConstants.appHeader}></Header>
</div>
<div className="flexContainer">
<div className="tabContainer">Tabs on Tabs</div>
<div className="mapContainer">
<MapComponent events={this.state.events} heading={appConstants.mapHeader}></MapComponent>
</div>
<div className="eventContainer">
<List events={this.state.events}></List>
</div>
</div>
</div>
);
}
_handleStateChange(event) {
let newEvent = {
browserName: event.new_val.browserName,
location: event.new_val.location,
osName: event.new_val.osName,
key: key,
eventName: event.new_val.event,
interval: event.new_val.interval
};
key++;
this.state.events.unshift(newEvent);
let events = this.state.events.slice(0, 10);
this.setState({events});
}
}
ReactDOM.render(<MainComponent />, document.getElementById('main'));
Map Component
class MapComponent extends React.Component {
constructor() {
super();
};
componentDidMount() {
/* On first load - center */
map = new mapboxgl.Map({
container: 'map',
style: mapConstants.style,
center: mapConstants.hqCoordinates,
zoom: 11
});
/* on initial load setup the location + icon */
map.on('load', function () {
const el = document.createElement('img');
el.className = 'marker';
el.style.backgroundImage = 'url(./assets/images/banana.png)';
el.style.width = mapConstants.markerWidth;
el.style.height = mapConstants.markerHeight;
new mapboxgl.Marker(el)
.setLngLat(mapConstants.hqCoordinates)
.addTo(map);
});
}
/* called when the props are updated */
componentWillUpdate() {
this._handleEventChange(this.props.events)
}
/* helper functions */
_handleEventChange(events) {
/* get most recent event and fly there */
const mostRecentEvent = events[0];
/* map box coordinates: [lng, lat ] */
const mostRecentLocation = mostRecentEvent.location.split(',').reverse();
map.flyTo({
center: mostRecentLocation,
zoom: 11
});
/* check if data source has been added */
const existingEvent = map.getSource('mostRecentEvent');
/* if data source exists, update the data */
if (existingEvent) {
existingEvent.setData({
"type": "Feature",
"geometry": {
"type": 'Point',
"coordinates": mostRecentLocation
},
"properties": {
"title":helperService.getShortEventName(mostRecentEvent.eventName),
"icon": mostRecentEvent.browserName.toLowerCase()
}
})
} else {
/* otherwise this is the first event and we need to add a source & layer */
map.addSource('mostRecentEvent', {
"type": "geojson",
"data": {
"type": "Feature",
"geometry": {
"type": 'Point',
"coordinates": mostRecentLocation
},
"properties": {
"title": helperService.getShortEventName(mostRecentEvent.eventName),
"icon": mostRecentEvent.browserName.toLowerCase()
}
}
});
map.addLayer({
"id": "mostRecentEvent",
"type": "symbol",
"source": "mostRecentEvent",
"layout": {
"icon-image": "{icon}",
"text-field": "{title}",
"text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
"text-offset": [0, 0.6],
"text-anchor": "top",
"text-allow-overlap": true,
"text-size": 20
},
"paint": {
"text-color": '#FF0080'
}
});
}
}
render() {
return (<div>
<div className="mapHeader">{this.props.heading}</div>
<div id="map" style={styles.map}></div>
</div>);
}
}
let styles = {
map: {
height: '500',
width: '100%',
zIndex: 0
}
};
module.exports = MapComponent;
And a couple images of the issue