reactjsnode.jsdatabasegoogle-maps-api-3latitude-longitude

My location also moves when dragging the Google Map left and right


I have developed a daycare application, so I want to display the daycare location on Google Maps. I've integrated Google Maps with the React application. When loading the application, it correctly shows the location. However, when dragging or zooming, my location also moves. The location should always remain the same.I am using node.js express as backend

Here's a video of the issue

https://app.screencastify.com/v3/watch/DltGBIYDwrZY0xlJw6v9

This is my code

import React, { useState, useEffect } from "react";
import GoogleMapReact from 'google-map-react';
import { Icon } from "@iconify/react";
import locationIcon from "@iconify/icons-mdi/map-marker";

const LocationPin = ({ name }) => (
    <div className="pin">
        <Icon icon={locationIcon} className="pin-icon" />
        <p className="pin-text">{name}</p>
    </div>
);

const Map = ({ daycares }) => {
    const [latitude, setLatitude] = useState(43.77887);
    const [longitude, setLongitude] = useState(-79.17282);

    useEffect(() => {
        navigator.geolocation.getCurrentPosition(
            (position) => {
                setLatitude(position.coords.latitude);
                setLongitude(position.coords.longitude);
            },
            (error) => {
                console.error(error);
            }
        );
    }, []); // Empty dependency array means this effect runs only once after the initial render

    const renderMap = () => {
        if (!daycares || daycares.length === 0) {
            return null; // Return early if daycares is empty or undefined
        }

        return (
            <div style={{ height: "80vh", width: "100%" }}>
                <GoogleMapReact
                    bootstrapURLKeys={{ key: "AIzaSyAzEQgX_hi-_Qnv6aWWIQDAdcLYnFPqQSQ" }}
                    defaultCenter={{
                        lat: latitude,
                        lng: longitude
                    }}
                    defaultZoom={12}
                >
                    {daycares.map((daycare) => (
                        <LocationPin
                            key={daycare.id}
                            lat={parseFloat(daycare.latitude)}
                            lng={parseFloat(daycare.longitude)}
                            name={daycare.childcare_name}
                        />
                    ))}
                </GoogleMapReact>
            </div>
        );
    };

    return (
        <div>
            {renderMap()}
        </div>
    );
};

export default Map;

const LocationPin = ({ lat, lng, name }) => (
  <div className="pin" style={{ position: 'absolute', transform: 'translate(-50%, -50%)' }}>
    <Icon icon={locationIcon} className="pin-icon" />
    <p className="pin-text">{name}</p>
  </div>
);

export default LocationPin;

The location should always remain the same

My mock Data:

{
  childcare_name: "East Side Preschool",
  address: "458 Fairall Street",
  city: "Ajax",
  region: "Ontario",
  postalcode: " L1S 1R6",
  country: "CANADA",
  latitude: "43.75991",
  longitude: "-79.18827",
  owner_name: "Jessica Lee",
  age_range: "2-6",
  years: "4",
  infant_capacity: "8",
  toddler_capacity: "12",
  preschool_capacity: "18",
  contact_phone: "555-9012",
  contact_email: "jessica@example.com",
},
{
  childcare_name: "Kepalen Angelic Child Care Daycare",
  address: "1301 Neilson Rd",
  city: "Scarborough",
  region: "Ontario",
  postalcode: "M1B 3C2",
  country: "Canada",
  latitude: "43.80716",
  longitude: "-79.21856",
  owner_name: "Nabhila",
  age_range: "0-6",
  years: "3",
  infant_capacity: "15",
  toddler_capacity: "20",
  preschool_capacity: "25",
  contact_phone: "555-1357",
  contact_email: "nabila@example.com",
},

Solution

  • As I have suggested on my comment on your question, you should just use a different library that supports Advanced Markers. Since Advanced Markers allows you to load a marker purely as an HTML element.

    In this case, I'd recommend that you use @vis.gl/react-google-maps and its respective <AdvancedMarker> Component.

    To implement it, you should just follow the documentation of the aforementioned library on how to load a map and an advanced marker.

    Then to use it with your data, you should utilize the array.map() when loading the markers. Which would iterate through your data and use those data to pass into your AdvancedMarker component rendering. Your code should look something like this:

    import React from "react";
    import { createRoot } from "react-dom/client";
    
    import { AdvancedMarker, APIProvider, Map } from "@vis.gl/react-google-maps";
    
    const API_KEY =
      globalThis.GOOGLE_MAPS_API_KEY ?? (process.env.GOOGLE_MAPS_API_KEY as string);
    
    const App = () => {
      var childCareData = [
        {
          childcare_name: "East Side Preschool",
          address: "458 Fairall Street",
          city: "Ajax",
          region: "Ontario",
          postalcode: " L1S 1R6",
          country: "CANADA",
          latitude: "43.75991",
          longitude: "-79.18827",
          owner_name: "Jessica Lee",
          age_range: "2-6",
          years: "4",
          infant_capacity: "8",
          toddler_capacity: "12",
          preschool_capacity: "18",
          contact_phone: "555-9012",
          contact_email: "jessica@example.com",
        },
        {
          childcare_name: "Kepalen Angelic Child Care Daycare",
          address: "1301 Neilson Rd",
          city: "Scarborough",
          region: "Ontario",
          postalcode: "M1B 3C2",
          country: "Canada",
          latitude: "43.80716",
          longitude: "-79.21856",
          owner_name: "Nabhila",
          age_range: "0-6",
          years: "3",
          infant_capacity: "15",
          toddler_capacity: "20",
          preschool_capacity: "25",
          contact_phone: "555-1357",
          contact_email: "nabila@example.com",
        },
      ];
      return (
        <APIProvider apiKey={API_KEY} libraries={["marker"]}>
          <Map
            mapId={"bf51a910020fa25a"}
            defaultZoom={12}
            defaultCenter={{ lat: 43.77887, lng: -79.17282 }}
            gestureHandling={"greedy"}
            disableDefaultUI
          >
            {childCareData &&
              childCareData.map((childCare, key) => {
    
                /* Convert your longitude and latitude into a float first
                 since your data stored it as a string. */
    
                const floatLat = parseFloat(childCare.latitude);
                const floatLng = parseFloat(childCare.longitude);
                return (
                  <AdvancedMarker
                    key={key}
                    position={{ lat: floatLat, lng: floatLng }}
                    title={"AdvancedMarker with custom html content."}
                  >
                    <div
                      style={{
                        width: 16,
                        height: 16,
                        position: "absolute",
                        background: "#1dbe80",
                        border: "2px solid #0e6443",
                        borderRadius: "50%",
                        transform: "translate(-50%, -50%)",
                      }}
                    >
                      <h3
                        style={{
                          padding: 12,
                        }}
                      >
                        {childCare.childcare_name}
                      </h3>
                    </div>
                  </AdvancedMarker>
                );
              })}
          </Map>
        </APIProvider>
      );
    };
    
    export default App;
    
    export function renderToDom(container: HTMLElement) {
      const root = createRoot(container);
    
      root.render(
        <React.StrictMode>
          <App />
        </React.StrictMode>,
      );
    }
    

    Then this should work as expected without the issue of locations following around as you move the map.

    Map with marker sample

    Here's a proof of concept codesandbox that you can try out and check yourself.