Dynamic Mapbox layer update using #urbica/react-map-gl - reactjs

I can’t change the source-layer dynamically in <Layer source-layer={this.state.layer} />. By pressing a button I change state to layer: 'building' or layer: 'road' but changes do not occur inside <Layer source-layer={this.state.layer} />
Code with example: https://codesandbox.io/s/compassionate-brook-l1psj
class App extends React.Component {
state = {
mapStyle: "mapbox://styles/mapbox/light-v9",
viewport: {
latitude: 44.8016,
longitude: -68.7712,
zoom: 15
},
layer: "building"
};
render() {
const { mapStyle } = this.state;
return (
<div className="App">
<div>
<button
onClick={() => {
if (this.state.layer === "road") {
this.setState(state => {
return {
...state,
layer: "building"
};
});
} else {
this.setState(state => {
return {
...state,
layer: "road"
};
});
}
}}
>
Change Style
</button>
</div>
<MapGL
style={{ width: "100%", height: "400px" }}
mapStyle={mapStyle}
accessToken={MAPBOX_ACCESS_TOKEN}
onViewportChange={viewport =>
this.setState(state => {
return {
...state,
viewport
};
})
}
{...this.state.viewport}
>
<Source
id="maine"
type="vector"
url="mapbox://mapbox.mapbox-streets-v8"
/>
{console.log(this.state.layer)} // Here I see that the state is changing
<Layer
id="maine"
type="fill"
source="maine"
source-layer={this.state.layer}
paint={{
"fill-color": "#088",
"fill-opacity": 0.8
}}
/>
</MapGL>
</div>
);
}
}

This issue was resolved. Thanks.
https://github.com/urbica/react-map-gl/issues/273

Related

Get details of all the Markers covered under a drawn polygon or any shape using react-google-maps

I am using react-google-maps. I have created map and displayed 3 types of markers in it.
I can now draw polygons on map but not able to get the details of markers covered under the drawn shape.
Any help would be appreciated.
This is my code of map jsx.
I am creating 3 different markers with different icons to identify on map.
When i draw a shape on map, i want to get the details of every sort of marker which comes under the drawn shape.
import React from "react";
import DrawingManager from "react-google-maps/lib/components/drawing/DrawingManager";
import {GoogleMap, InfoWindow, Marker, withGoogleMap, withScriptjs} from "react-google-maps";
import UploadApis from "../../service/rest/upload";
import "./index.scss";
let selectedShape;
function clearSelection() {
if (selectedShape) {
if (selectedShape.type !== 'marker') {
selectedShape.setEditable(false);
}
selectedShape = null;
}
}
function setSelection(shape) {
if (shape.type !== 'marker') {
clearSelection();
shape.setEditable(true);
}
selectedShape = shape;
}
class Map extends React.Component {
constructor(props) {
super(props);
this.shapes = [];
this.state = {
fiberData: [],
subscriberData: [],
sitesData: [],
fetchData: false,
selected: null
};
this.handleOverlayComplete = this.handleOverlayComplete.bind(this);
this.data();
}
handleOverlayComplete(e) {
console.log("overlay",e);
const newShape = e.overlay;
newShape.type = e.type;
if (e.type !== window.google.maps.drawing.OverlayType.MARKER) {
window.google.maps.event.addListener(newShape, 'click', function (e) {
if (e.vertex !== undefined) {
if (newShape.type === window.google.maps.drawing.OverlayType.POLYGON) {
let path = newShape.getPaths().getAt(e.path);
path.removeAt(e.vertex);
if (path.length < 3) {
newShape.setMap(null);
}
}
if (newShape.type === window.google.maps.drawing.OverlayType.POLYLINE) {
let path = newShape.getPath();
path.removeAt(e.vertex);
if (path.length < 2) {
newShape.setMap(null);
}
}
}
setSelection(newShape);
});
setSelection(newShape);
} else {
window.google.maps.event.addListener(newShape, 'click', function (e) {
setSelection(newShape);
});
setSelection(newShape);
}
this.shapes.push(newShape);
}
data = async () => {
let fiberData = await UploadApis.getMetaDataById("fiber",this.props.projectId);
let sitesData = await UploadApis.getMetaDataById("sites",this.props.projectId);
let subscriberData = await UploadApis.getMetaDataById("subscriber",this.props.projectId);
this.setState({fiberData: fiberData, sitesData: sitesData, subscriberData: subscriberData, fetchData: true})
};
deleteSelectedShape = () => {
if (selectedShape) {
selectedShape.setMap(null);
}
};
setSelected(selected) {
this.setState({selected: selected})
}
render() {
return (
<div>
<button className="btn-container" onClick={this.deleteSelectedShape}>Delete Shape
</button>
{this.state.fetchData ?
<div>
<GoogleMap
defaultZoom={6}
defaultCenter={{lat: 22.5106879, lng: 79.9189213}}
>
<DrawingManager
defaultDrawingMode={null}
defaultOptions={{
drawingControl: true,
drawingControlOptions: {
position: window.google.maps.ControlPosition.TOP_CENTER,
drawingModes: [ 'circle', 'polygon', 'polyline', 'rectangle']
},
polygonOptions: {editable: true},
circleOptions: {editable: true},
rectangleOptions: {editable: true},
markerOptions: {editable: true},
polylineOptions: {editable: true}
}}
onOverlayComplete={this.handleOverlayComplete}
/>
{this.state.fiberData.map((fiber) => (
<Marker
key={fiber.id}
position={{lat: fiber.latitude, lng: fiber.longitude}}
onClick={() => {
this.setSelected(fiber);
}}
icon={{
url: "../assets/svg/fiber.png",
scaledSize: new window.google.maps.Size(25, 25)
}}
/>
))}
{this.state.sitesData.map((site) => (
<Marker
key={site.id}
position={{lat: site.latitude, lng: site.longitude}}
onClick={() => {
this.setSelected(site);
}}
icon={{
url: "../assets/svg/tower.png",
scaledSize: new window.google.maps.Size(25, 25)
}}
/>
))}
{this.state.subscriberData.map((subscriber) => (
<Marker
key={subscriber.id}
position={{lat: subscriber.latitude, lng: subscriber.longitude}}
onClick={() => {
this.setSelected(subscriber);
}}
icon={{
url: "../assets/svg/subscriber.svg",
scaledSize: new window.google.maps.Size(25, 25)
}}
/>
))}
{this.state.selected && (
<InfoWindow
position={{lat: this.state.selected.latitude, lng: this.state.selected.longitude}}
onCloseClick={() => {
this.setSelected(null);
}}>
<div>
<h4>{this.state.selected.name}</h4>
<p>{this.state.selected.description}</p>
</div>
</InfoWindow>
)}
</GoogleMap>
</div> : null
}
</div>
);
}
}
export default withScriptjs(withGoogleMap(Map));
This is the first file which i have called. Index file which renders the map is -
import React from "react";
import Map from './map.jsx';
export default class MapContainer extends React.Component {
_projectId="";
constructor(props) {
super(props);
console.log(props);
if(props.location.state.project){
this._projectId = props.location.state.project.id;
}
}
render() {
return (
<div>
<Map
googleMapURL={`https://maps.googleapis.com/maps/api/js?v=3.exp&libraries=geometry,drawing,places&key=API_KEY`}
loadingElement={<div style={{height: `100%`}}/>}
containerElement={<div style={{height: `480px`}}/>}
mapElement={<div style={{height: `100%`}}/>}
projectId ={this._projectId}
/>
</div>
);
}
}```

Connected component doesn't re-render after store changed from another connected component

I am having a problem related to redux.
I have 2 connected components which are:
avatar situated in the navbar which is always visible
profile which is responsible for changing the avatar image in the store
if I am right, when the store change, any connected component will re-render if needed.
In my case, when the action UPDATE_CURRENT_USER update the avatar image, the navbar avatar doesn't get the new image only after I change route or reload page.
I found a solution but many people say it's a hack,
I have put a listener on store changes in the main component and did forceUpdate()
componentDidMount() {
store.subscribe(res => this.forceUpdate());
}
and I don't want to use it since connected components are supposed to re-render on store changes.
user actions:
export const getCurrentUser = () => dispatch => {
axios.get("user").then(user => {
dispatch({
type: GET_CURRENT_USER,
payload: user.data
});
});
};
export const updateCurrentUser = user => dispatch => {
dispatch({
type: UPDATE_CURRENT_USER,
payload: user
})
}
user reducer
const initialState = {
user: {}
}
export default function (state = initialState, action) {
switch (action.type) {
case GET_CURRENT_USER:
return { ...state, user: action.payload };
case UPDATE_CURRENT_USER:
return { ...state, user: action.payload }
default:
return state;
}
}
profile component
class Profile extends Component {
render() {
const { currentUser, updateCurrentUser } = this.props;
return (
<div id="profile-container">
<ProfileSider
currentUser={currentUser}
updateCurrentUser={updateCurrentUser}
/>
<ProfileContent
currentUser={currentUser}
updateCurrentUser={updateCurrentUser}
/>
</div>
);
}
}
const mapStateToProps = state => ({
currentUser: state.userReducer.user
});
export default connect(
mapStateToProps,
{ updateCurrentUser }
)(Profile);
profile sidebar child of profile
class ProfileSider extends Component {
state = { uploading: false };
triggerAvatarInput() {
$("#avatarInput").click();
}
handleChange = async event => {
this.setState({ ...this.state, uploading: true });
const avatarFormData = new FormData();
avatarFormData.append("file", event.target.files[0]);
axios
.post("uploadFile", avatarFormData)
.then(res => {
const avatarURIFormData = new FormData();
avatarURIFormData.append("avatar", res.data.fileDownloadUri);
axios
.put("user/update", avatarURIFormData)
.then(res => {
const { currentUser } = this.props;
currentUser.avatar = res.data.avatar;
this.props.updateCurrentUser(currentUser);
this.setState({
...this.state,
uploading: false,
avatar: currentUser.avatar
});
message.success("Avatar updated successfully", 3);
})
.catch(error => {
this.setState({ ...this.state, uploading: false });
message.error("Updating avatar failed!", 3);
});
})
.catch(error => {
this.setState({ ...this.state, uploading: false });
message.error("Uploading avatar failed!", 3);
});
};
render() {
const { uploading } = this.state;
const { currentUser } = this.props;
return (
<div id="profile-sider">
<div id="profile-sider-info">
<div id="profile-sider-info-avatar">
<div className="container">
<div
className="overlay-uploading"
className={
uploading ? "overlay-uploading" : "overlay-uploading hidden"
}
>
<Icon type="loading" style={{ fontSize: 50, color: "#FFF" }} />
</div>
<div className="overlay" />
<div className="overlay-text" onClick={this.triggerAvatarInput}>
<Icon type="camera" style={{ fontSize: 20 }} />
<span>Update</span>
</div>
<div
className="avatar"
style={{
backgroundImage: "url(" + currentUser.avatar + ")"
}}
></div>
<input
onChange={this.handleChange}
type="file"
accept="image/png, image/jpeg, image/jpg"
id="avatarInput"
/>
</div>
</div>
<h2 style={{ marginTop: 20, textAlign: "center" }}>
{currentUser.fullName}
</h2>
<h4 style={{ textAlign: "center" }}>{currentUser.email}</h4>
</div>
<div id="profile-sider-actions">
<div className="profile-sider-actions-item">
<Link to="/profile/courses" style={{ transition: 0 }}>
<Button type="primary" id="courses-btn">
<Icon type="read" style={{ marginRight: 15 }} />
My Courses
</Button>
</Link>
</div>
<div className="profile-sider-actions-item">
<Link to="/profile/update">
<Button type="primary" id="update-infos-btn">
<Icon type="sync" style={{ marginRight: 15 }} />
Update Infos
</Button>
</Link>
</div>
</div>
</div>
);
}
}
export default ProfileSider;
avatar component situated in navbar
class ProfileAvatar extends Component {
constructor() {
super();
this.handleClick = this.handleClick.bind(this);
this.handleOutsideClick = this.handleOutsideClick.bind(this);
this.state = {
showProfileDropdown: false
};
}
componentDidMount() {
this.props.getCurrentUser();
}
handleLogout = async () => {
try {
await auth.logout();
this.props.onLogout();
notification["success"]({
message: "You have been successfully logged out!"
});
} catch (ex) {}
};
handleClick() {
if (!this.state.showProfileDropdown) {
// attach/remove event handler
document.addEventListener("click", this.handleOutsideClick, false);
} else {
document.removeEventListener("click", this.handleOutsideClick, false);
}
this.setState(prevState => ({
showProfileDropdown: !prevState.showProfileDropdown
}));
}
handleOutsideClick(e) {
// ignore clicks on the component itself
if (this.element && this.element.contains(e.target)) {
return;
}
this.handleClick();
}
render() {
const { currentUser } = this.props;
return (
<div
className="profile-avatar"
ref={element => {
this.element = element;
}}
>
<Avatar
onClick={this.handleClick}
size="large"
style={{ color: "#f56a00", backgroundColor: "#fde3cf" }}
src={currentUser.avatar}
>
{currentUser.fullName ? currentUser.fullName.charAt(0) : null}
</Avatar>
{this.state.showProfileDropdown && (
<div className="profile-dropdown-list">
<List
className="dropdown_list dropdown-shadow "
size="small"
style={{ width: "150px" }}
bordered
itemLayout="vertical"
dataSource={[
<Link to="/profile/update" className="profile-list-item">
<List.Item className="list-item">
<Icon className="profile-icons" type="user" /> My Profile
</List.Item>
</Link>,
<Link to="/profile/courses" className="profile-list-item">
<List.Item className="list-item">
<Icon className="profile-icons" type="container" /> My
Courses
</List.Item>
</Link>,
<List.Item className="list-item">
<Icon className="profile-icons" type="question-circle" /> Ask
for Help
</List.Item>,
<List.Item className="list-item" onClick={this.handleLogout}>
<Icon className="profile-icons" type="logout" /> Log out
</List.Item>
]}
renderItem={item => item}
/>
</div>
)}
</div>
);
}
}
const mapStateToProps = state => ({
currentUser: state.userReducer.user
});
export default connect(
mapStateToProps,
{ getCurrentUser }
)(ProfileAvatar);
image: https://imge.to/i/vywTNj
There are two problems here:
You are mutating the existing object from the store
You are sending that exact same user object back into the store when you dispatch the action.
Specifically, these lines are the cause:
const { currentUser } = this.props;
currentUser.avatar = res.data.avatar;
this.props.updateCurrentUser(currentUser);
currentUser is the user object that's already in the Redux store. This code mutates the object, and inserts it back into the store.
That results in the connected component thinking nothing has actually changed.
The shortest way to fix this is to create a new user object, and insert that:
const {currentUser} = this.props;
const updatedUser = {...currentUser, avatar: res.data.avatar};
this.props.updateCurrentUser(updatedUser);
To avoid this in the future, I strongly encourage you to use the configureStore function from our Redux Starter Kit package, which detects mutations and will throw errors if you mutate.

Hide canvas element for visualSetting in react-mic

I am trying to hide the canvas element in this MyRecorder component:
The element is visible when inspecting the page in browser.
import React, {Component} from 'react';
import { render } from 'react-dom';
import start from '../img/start.svg';
import stop from '../img/stop.svg';
import pause from '../img/pause.svg';
import { ReactMic } from 'react-mic';
class MyRecorder extends Component {
constructor(props){
super(props);
this.state = {
blobObject: null,
isRecording: false,
isPaused: false
}
}
startOrPauseRecording= () => {
const { isPaused, isRecording } = this.state
if(isPaused) {
this.setState({ isPaused: false })
} else if(isRecording) {
this.setState({ isPaused: true })
} else {
this.setState({ isRecording: true })
}
}
stopRecording= () => {
this.setState({ isRecording: false });
}
onStop= (blobObject) => {
this.setState({ blobURL : blobObject.blobURL });
}
render() {
const { blobURL, isRecording, isPaused } = this.state;
const getImage = () => {
if(isRecording && !isPaused) {
return (`url(${pause})`)
}
else {
return (`url(${start})`)
}
}
return(
<div
style={{marginLeft: 15,}}
>
<ReactMic
record={isRecording}
pause={isPaused}
visualSetting="none"
audioBitsPerSecond= {128000}
onStop={this.onStop}
onStart={this.onStart}
onSave={this.onSave}
strokeColor="#000000" />
<audio ref="" controls="controls" src={blobURL}></audio>
<br />
<br />
<button
className="btn btn-light recButton"
style={{
backgroundImage: `url(${isRecording && !isPaused? pause : start})`,
width:40,
height:40,
}}
onClick={this.startOrPauseRecording}>
</button>
<button
className="btn btn-light recButton"
disabled={!isRecording}
style={{
backgroundImage: `url(${stop})`,
width:40,
height:40,
}}
onClick={this.stopRecording}>
</button>
<br />
</div>
);
}
}
export default MyRecorder;
When the visualSetting is:
visualSetting="sinewave"
Sinewaves are shown in the canvas, after changing it to:
visualSetting="none"
The waves go away but the canvas element is still there. Any idea how to get rid of the element?
I was able to find a workaround. In the file node_modules/react-mic/es/components/ReactMic.js
Change line 130 from:
return React.createElement('canvas', { ref: 'visualizer', height: height, width: width, className: this.props.className });
To:
return React.createElement('canvas', { ref: 'visualizer', height: 0, width: 0, className: this.props.className });

Make Search Box Functional

I'm doing a map project in React and using the google-maps-react api. I am able to type characters in the search box, but it doesn't filter my list or markers. How can I make that work?
Here's the code for my App.js. I have the updateQuery which should update with whatever is typed in the search box. filterItems is supposed to filter all the locations. addRealMarkers is supposed to replace with the filtered markers:
var foursquare = require("react-foursquare")({
clientID: "BTMAGTC2Y5G1IXAKA4VN4QN55R2DSN1105Y1XGHB0WZ5THHR",
clientSecret: "4HOKQ0ON1V1XEHKSUSEABQMNRFZGCGPIKIUIE5JMUMWVRG5W",
url: "https://api.foursquare.com/v2/venues/search?"
});
var params = {
ll: "31.462170,-97.195732",
query: "Hewitt"
};
class App extends Component {
/* Basic state object that must be kept at the highest "parent" level per
Doug Brown's training video */
constructor(props) {
super(props);
this.state = {
lat: 31.46217,
lon: -97.195732,
zoom: 13,
items: [],
filtered: null,
open: false,
selectedId: null,
activeMarker: null
};
}
realMarkers = [];
componentDidMount() {
foursquare.venues.getVenues(params).then(res => {
this.setState({ items: res.response.venues });
});
fetch("react-foursquare")
.then(response => response.json())
.then(response => {
const items = json.response.items;
this.setState({
items,
filtered: this.filterItems(items, "")
});
})
.catch(error => {
alert("Foursquare data could not be retrieved");
});
}
//Fetches the locations requested for this map.
/*fetchPlaces(mapProps, map) {
const { google } = mapProps;
const service = new google.maps.places.PlacesService(map);
}
//fetch Foursquare API data and use Axios to catch errors, instructed by
Yahya Elharony.
// Source: https://github.com/foursquare/react-foursquare
getPlaces = () => {
const endPoint = "https://api.foursquare.com/v2/venues/explore?";
const params = {
client_id: "BTMAGTC2Y5G1IXAKA4VN4QN55R2DSN1105Y1XGHB0WZ5THHR",
client_secret: "4HOKQ0ON1V1XEHKSUSEABQMNRFZGCGPIKIUIE5JMUMWVRG5W",
near: "Hewitt",
query: "query",
v: 20181117
};
// axios site: https://www.npmjs.com/package/axios
axios
.get(endPoint + new URLSearchParams(params))
.then(response => {
this.setState(
{
venues: response.data.response.groups[0].items
},
this.fetchPlaces()
);
})
.catch(error => {
console.log("ERROR! " + error);
});
};*/
// Creating the replacement markers that goes with the list. Based on my
1:1 training from Doug Brown
addRealMarker = marker => {
let checkList = this.realMarkers.filter(
m => m.marker.id === marker.marker.id
);
if (!checkList.length) this.realMarkers.push(marker);
};
updateQuery = query => {
this.setState({
selectedIndex: null,
filtered: this.filterItems(this.state.items, query)
});
};
filterItems = (items, query) => {
return items.filter(item =>
item.name.toLowerCase().includes(query.toLowerCase())
);
};
clickListItem = id => {
const marker = this.realMarkers.filter(
marker => marker.marker.id === id
)[0];
this.setState({
selectedId: id,
activeMarker: marker
});
};
/*Google Maps React Component courtesy of
https://www.npmjs.com/package/google-maps-react*/
render() {
const style = {
width: "100%",
height: "100%"
};
return (
<div className="App">
<HewittMap
lat={this.state.lat}
lng={this.state.lng}
zoom={this.state.zoom}
style={style}
items={this.state.items}
addRealMarker={this.addRealMarker}
activeMarker={this.state.activeMarker}
clickListItem={this.clickListItem}
/>
<Sidebar
items={this.state.items}
clickListItem={this.clickListItem}
filterItems={this.updateQuery}
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
export default App;
And here's the Sidebar Code. Added another updateQuery function that's supposed to call the props then you'll see some more code in the InputBase component:
class Sidebar extends Component {
state = {
mobileOpen: false,
query: ""
};
handleDrawerOpen = () => {
this.setState({ open: true });
};
handleDrawerClose = () => {
this.setState({ open: false });
};
updateQuery = newQuery => {
// Save the new query string in state and pass the string up the call
tree
this.setState({ query: newQuery });
this.props.filterItems(newQuery);
};
render() {
const { classes, theme } = this.props;
const { open } = this.state;
const items = this.props.items;
return (
<div className={classes.root}>
<CssBaseline />
<AppBar
position="fixed"
className={classNames(classes.appBar, {
[classes.appBarShift]: open
})}
>
<Toolbar disableGutters={!open}>
<IconButton
color="inherit"
aria-label="Open drawer"
onClick={this.handleDrawerOpen}
className={classNames(classes.menuButton, open && classes.hide)}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" color="inherit" noWrap>
City of Hewitt
</Typography>
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon places={this.state.places} />
</div>
<InputBase
classes={{
root: classes.inputRoot,
input: classes.inputInput
}}
placeholder="Search…"
name="filter"
type="text"
value={this.state.query}
onChange={e => {
this.updateQuery(e.target.value);
}}
/>
</div>
</Toolbar>
</AppBar>
<Drawer
className={classes.drawer}
variant="persistent"
anchor="left"
open={open}
classes={{
paper: classes.drawerPaper
}}
>
<div className={classes.drawerHeader}>
<IconButton onClick={this.handleDrawerClose}>
{theme.direction === "ltr" ? (
<ChevronLeftIcon />
) : (
<ChevronRightIcon />
)}
</IconButton>
</div>
<Divider />
<List>
{this.props.items &&
this.props.items.map((item, index) => {
return (
<ListItem key={item.id}>
<button
key={index}
onClick={e => this.props.clickListItem(item.id)}
>
<ListItemText primary={item.name}> </ListItemText>
</button>
</ListItem>
);
})}
</List>
<Divider />
</Drawer>
<main
className={classNames(classes.content, {
[classes.contentShift]: open
})}
>
<div className={classes.drawerHeader} />
</main>
</div>
);
}
}
Sidebar.propTypes = {
classes: PropTypes.object.isRequired,
// Injected by the documentation to work in an iframe.
// You won't need it on your project.
container: PropTypes.object,
theme: PropTypes.object.isRequired
};
export default withStyles(styles, { withTheme: true })(Sidebar);
You can click in my CodeSandbox to see for yourself.
You are filtering your data and assigning it to filtered but you use items to drive your map, not filtered. It would need more refactoring, but what if you did this?
updateQuery = query => {
this.setState({
selectedIndex: null,
//filtered: this.filterItems(this.state.items, query) // -
items: this.filterItems(this.state.items, query) // +
});
};
You might want an indicator, say isFiltered, that is true when the search bar has a value in it. If true, use the filtered data, else, use the original items

Updating child prop breaks connection with parent state

I'm using react-google-maps to display markers on a map. When I use the SearchBox function in the child component to set props.locations my map Markers appear. However, when I use a button in the parent component to update the state of the locations within MapWithASearchBox the child prop doesn't recognise the change. If I reload the page and just use the button on the parent Component the markers appear correct. I assume I'm breaking the connection between child and parent when I set the prop within the child component.
Path: Parent Component MapPage.jsx
export default class MapPage extends Component {
constructor(props) {
super(props);
this.state = {
companies: []
}
this.handleButtonASXMarketCap = this.handleButtonASXMarketCap.bind(this);
}
handleButtonASXMarketCap(limit, e) {
e.preventDefault();
Meteor.call('getASXTop100', limit, (error, result) => {
if (result) {
this.setStateOfCompanies(result);
}
});
}
setStateOfCompanies(data) {
this.setState({
companies: data
})
}
render() {
return (
<div>
<Button color="primary ml-2" onClick={(e) => this.handleButtonASXMarketCap(100, e)}>Top 100 ASX</Button>
<MapWithASearchBox
locations={this.state.companies}
/>
</div>
);
}
}
Path: Child Component MapWithASearchBox.jsx
const MapWithASearchBox = compose(
withProps({
googleMapURL: "myUrl",
loadingElement: <div style={{ height: `100%` }} />,
containerElement: <div style={{ height: `400px` }} />,
mapElement: <div style={{ height: `100%` }} />,
}),
lifecycle({
componentWillMount() {
const refs = {}
this.setState({
bounds: null,
center: {
lat: -23.696248, lng: 133.880731
},
zoom: 4,
markers: [],
onPlacesChanged: () => {
const places = refs.searchBox.getPlaces();
const bounds = new google.maps.LatLngBounds();
places.forEach(place => {
if (place.geometry.viewport) {
bounds.union(place.geometry.viewport)
} else {
bounds.extend(place.geometry.location)
}
});
const nextMarkers = places.map(place => ({
position: place.geometry.location,
}));
const nextCenter = _.get(nextMarkers, '0.position', this.state.center);
this.setState({
center: nextCenter,
markers: nextMarkers,
zoom: 15
});
const lat = nextMarkers.map(x => x.position.lat());
const lng = nextMarkers.map(x => x.position.lng());
Meteor.call('runMethodTest', lat[0], lng[0], (error, result) => {
if (result) {
this.setState({
locations: result
});
}
});
},
})
},
}),
withScriptjs,
withGoogleMap
)(props =>
<GoogleMap>
<SearchBox
ref={props.onSearchBoxMounted}
bounds={props.bounds}
controlPosition={google.maps.ControlPosition.TOP_LEFT}
onPlacesChanged={props.onPlacesChanged}
>
<input
type="text"
placeholder="Customized your placeholder"
/>
</SearchBox>
{props.locations.map((location, index) => (
<span key={location._id.location.lng}>
<Marker
position={location._id.location}
onClick={() => props.onToggleOpen(index)}
/>
</span>
))}
</GoogleMap>
);

Resources