Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

TypeError: Cannot read properties of undefined (reading 'HeatmapLayer') #1235

Open
@kirillleogky

Description

@kirillleogky

How to open the Heatmap on the first load on the page?

When I open the page with Heatmap, I got this error
TypeError: Cannot read properties of undefined (reading 'HeatmapLayer')


After reading the page, Heatmap appears and seems to be working as it should



Components:
CommunityMap.tsx

export const CommunityMap: React.FC<Props> = ({ expandMap = false, ...community }) => {  const [page] = useQueryState('tab', 'here');  const [tripId] = useQueryState('trip');  const router = useRouter();  const { isMobile } = React.useContext(LayoutContext);  const [selectedDate, setSelectedDate] = React.useState<number>(0);  // Generate the array of dates for the next 30 days  const dates = Array.from({ length: 30 }, (_, i) => addDays(new Date(), i));  // Get the display label for the marks  // const marks = dates.map((date, index) => ({  //   value: index,  //   label: format(date, 'MMM dd'),  // }));  const handleSliderChange = React.useCallback((event: any, newValue: any) => {    setSelectedDate(newValue);  }, []);  const { user } = React.useContext(UserContext);  const { openDialog } = React.useContext(DialogContext);  const [showHeatmap, setShowHeatmap] = React.useState(false);  const { trips } = useTrips({    user: user?.id,  });  const currTripIdx = React.useMemo(() => {    if (tripId) {      return findIndex(trips, trip => trip.id === parseInt(tripId, 10));    }  }, [trips, tripId]);  const currTrip = React.useMemo(() => {    if (currTripIdx !== undefined) {      return trips[currTripIdx];    }  }, [trips, currTripIdx]);  const prevTrip = React.useMemo(() => {    if (currTripIdx !== undefined) {      return trips[currTripIdx - 1];    }  }, [trips, currTripIdx]);  const nextTrip = React.useMemo(() => {    if (currTripIdx !== undefined) {      return trips[currTripIdx + 1];    }  }, [trips, currTripIdx]);  const { members: communityMembers, status: communityMembersStatus } = useMembers({    communityId: community.id.toString(),    dateGte: showHeatmap ? startOfDay(dates[selectedDate]) : currTrip?.arrivalDatetime,    dateLte: showHeatmap ? endOfDay(dates[selectedDate]) : currTrip?.departureDatetime,  });  const showHeatToggle = React.useMemo(() => {    if (isBeta || (user?.id && [13, 15, 241, 223, 11, 5, 166, 1781].includes(user.id))) {      return true;    }    return false;  }, [user]);  const members = React.useMemo(() => {    return communityMembers.filter(user => user.status === 'active');  }, [communityMembers]);    const [map, setMap] = React.useState<any>();  const coords: Coordinates = React.useMemo(() => {    const boundaries = members.reduce((prev, curr) => {      const bounds = { ...prev };      // @ts-ignore      const userLocation = curr.trip?.location || curr.baseLocation || curr.location;      if (userLocation && userLocation.latitude && userLocation.longitude) {        if (userLocation.latitude < bounds.minLat) {          bounds.minLat = userLocation.latitude;        }        if (userLocation.latitude > bounds.maxLat) {          bounds.maxLat = userLocation.latitude;        }        if (userLocation.longitude < bounds.minLng) {          bounds.minLng = userLocation.longitude;        }        if (userLocation.longitude > bounds.maxLng) {          bounds.maxLng = userLocation.longitude;        }      }      return bounds;    }, {      minLat: user?.baseLocation?.latitude || 0,      minLng: user?.baseLocation?.longitude || 0,      maxLat: user?.baseLocation?.latitude || 0,      maxLng: user?.baseLocation?.longitude || 0,    });    const distance = calculateDistance(boundaries.minLat, boundaries.minLng, boundaries.maxLat, boundaries.maxLng);    const coords = currTrip ? {      lat: currTrip.location.latitude,      lng: currTrip.location.longitude,    } : {      // If all users located too close to each other (less than 100 km) - increase zoom out distance      minLat: distance < 100 ? boundaries.minLat - 0.4 : boundaries.minLat,      minLng: distance < 100 ? boundaries.minLng - 0.4 : boundaries.minLng,      maxLat: distance < 100 ? boundaries.maxLat + 0.4 : boundaries.maxLat,      maxLng: distance < 100 ? boundaries.maxLng + 0.4 : boundaries.maxLng,      lat: (boundaries.minLat + boundaries.maxLat) / 2,      lng: (boundaries.minLng + boundaries.maxLng) / 2,    };    return coords;  }, [currTrip, members, user?.baseLocation]);  const points = React.useMemo(() => {    const points: Locations.Location[] = [];    const dateFrom = currTrip?.arrivalDatetime;    const dateTo = currTrip?.departureDatetime;      members.forEach(user => {      const travelInterval = dateFrom && dateTo ? { start: dateFrom, end: dateTo } : null;      let daysWithoutTravel = travelInterval ? eachDayOfInterval(travelInterval).length : 1;      if (!travelInterval && user.trips.length > 0) {        daysWithoutTravel = 0;      }      user.trips.forEach(trip => {        points.push(trip.location);        if (travelInterval) {          const overlappingDays = getOverlappingDaysInIntervals(            travelInterval,            { start: trip.arrivalDatetime, end: trip.departureDatetime },          );          daysWithoutTravel -= overlappingDays;        }      });      const baseLocation = user.baseLocation;      if (baseLocation && daysWithoutTravel) {        points.push(baseLocation);      }    });    return points;  }, [members, currTrip]);  const topCities = React.useMemo(() => {    const cityCounts = points.reduce((acc, location) => {      const city = location.title;      if (city) {        if (!acc[city]) {          acc[city] = 0;        }        acc[city]++;      }      return acc;    }, {} as any);      const sortedCities = Object.entries(cityCounts).sort((a: any, b: any) => b[1] - a[1]);    return sortedCities.slice(0, 5).map(([city, count]) => ({      city,      count,      percentage: ((count as number / points.length) * 100).toFixed(0),    }));  }, [points]);  const setView = React.useCallback((tab: string) => {    if (tab === 'here') {      router.communities.view(community.handle || community.id).go({ tab: 'here', trip: undefined, lat: undefined, lng: undefined }, true);    }    if (tab === 'there') {      router.communities.view(community.handle || community.id).go({ tab: 'there', trip: trips[0].id, lat: undefined, lng: undefined }, true);    }  }, [community.handle, community.id, router.communities, trips]);  const toggleHeatMap = React.useCallback(() => {    setShowHeatmap(state => !state);  }, []);  React.useEffect(() => {    if (!page) {      router.communities.view(community.handle || community.id).go({ tab: 'here' }, true);    }  }, [community.handle, community.id, page, router]);  React.useEffect(() => {    if (!expandMap) {      if (page !== 'here') {        setView('here');      }      if (showHeatmap) {        setShowHeatmap(false);      }    }  }, [expandMap, setView, setShowHeatmap, page, showHeatmap]);  React.useEffect(() => {    if (page === 'here' && isBoundaryCoordinates(coords)) {      setTimeout(() => {        map?.fitBounds({          north: coords.maxLat,          east: coords.maxLng,          south: coords.minLat,          west: coords.minLng,        });      }, 500);    }  }, [expandMap, map, coords, page]);  if (communityMembersStatus === 'error' || !communityMembers) {    return <MessageFeedbackView height="100%"/>;  }  return (    <>      {communityMembersStatus === 'loading' && (        <Box zIndex={1} position="absolute" sx={theme => ({ opacity: 0.8, backgroundColor: theme.palette.mode === 'light' ? theme.palette.grey[100] : theme.palette.primary.dark })} height="100%" width="100%">          <BodyLoading height={700} />        </Box>      )}      <Stack height="100%">        <Box height="100%">          {showHeatmap ? (            <UsersHeatmap              coords={coords}              users={members}              // contacts={filteredContacts}              draggable={expandMap}              // We have expanding map              // By default map will not raise onChange event if parent size has changed              // To change such behavior add resetBoundsOnResize = {true} property              resetBoundsOnResize              onGoogleApiLoaded={(data) => {                setMap(data.map);              }}              dateFrom={currTrip?.arrivalDatetime}              dateTo={currTrip?.departureDatetime}            />          ) : (            <UsersMap              coords={coords}              users={members}              // contacts={filteredContacts}              draggable={expandMap}              // We have expanding map              // By default map will not raise onChange event if parent size has changed              // To change such behavior add resetBoundsOnResize = {true} property              resetBoundsOnResize              onGoogleApiLoaded={(data) => {                setMap(data.map);              }}              dateFrom={currTrip?.arrivalDatetime}              dateTo={currTrip?.departureDatetime}            />          )}        </Box>      </Stack>    </>  );};

'@modules/Users/components/UsersMap/HeatMap'

import React from 'react';import { eachDayOfInterval, getOverlappingDaysInIntervals } from 'date-fns';import { ChangeEventValue, Props as GoogleMapProps } from 'google-map-react';import { Map } from '@shared/components/Map/Map';import { googleMapsApiKey } from '@shared/config';import { ClusterPoint } from './ClusterPin';export const isBoundaryCoordinates = (coords: Coordinates): coords is BoundaryCoordinates => {  return ('minLat' in coords) && !!coords.minLat && !!coords.minLng && !!coords.maxLat && !!coords.maxLng;};export type SimpleCoordinates = {  lat: number;  lng: number;}export type BoundaryCoordinates = {  lat: number;  lng: number;  minLat: number;  minLng: number;  maxLat: number;  maxLng: number;}export type Coordinates = SimpleCoordinates | BoundaryCoordinates;interface Props extends Omit<GoogleMapProps, 'heatmap' | 'heatmapLibrary'> {  coords: Coordinates;  defaultZoom?: number;  draggable?: boolean;  users: Users.User[],  contacts?: Contacts.Contact[],  onChange?: (values: ChangeEventValue) => void;  dateFrom?: Date;  dateTo?: Date;}export const UsersHeatmap: React.FC<Props> = ({  coords,  defaultZoom = 7,  draggable = true,  users,  contacts = [],  onChange,  dateFrom,  dateTo,  ...props}) => {  const [map, setMap] = React.useState<any>();  const [zoom, setZoom] = React.useState<number>(defaultZoom);  const clusterPoints = React.useMemo(() => {    const clusterPoints: ClusterPoint[] = [];    users.forEach(user => {      const travelInterval = dateFrom && dateTo ? { start: dateFrom, end: dateTo } : null;      let daysWithoutTravel = travelInterval ? eachDayOfInterval(travelInterval).length : 1;      // User has a trip but there is no travel interval, meaning he has a trip today.      if (!travelInterval && user.trips.length > 0) {        daysWithoutTravel = 0;      }      user.trips.forEach(trip => {        clusterPoints.push({          type: 'Feature',          properties: {            cluster: false,            user: {              ...user,              trips: [trip],            },          },          geometry: {            type: 'Point',            coordinates: [trip.location.longitude, trip.location.latitude],          },        });        if (travelInterval) {          const overlappingDays = getOverlappingDaysInIntervals(            travelInterval,            { start: trip.arrivalDatetime, end: trip.departureDatetime },          );          daysWithoutTravel -= overlappingDays;        }      });      const baseLocation = user.baseLocation;      if (baseLocation && daysWithoutTravel) {        clusterPoints.push({          type: 'Feature',          properties: {            cluster: false,            user: {              ...user,              trips: [],            },          },          geometry: {            type: 'Point',            coordinates: [baseLocation?.longitude, baseLocation?.latitude],          },        });      }    });    contacts.forEach(contact => {      const location = contact.location;      if (location) {        clusterPoints.push({          type: 'Feature',          properties: { cluster: false, contact },          geometry: {            type: 'Point',            coordinates: [location?.longitude, location?.latitude],          },        });      }    });    return clusterPoints;  }, [users, contacts, dateFrom, dateTo]);  const onMapChange = React.useCallback((props: ChangeEventValue) => {    const { zoom } = props;    setZoom(zoom);    onChange && onChange(props);  }, [onChange]);  React.useEffect(() => {    if (isBoundaryCoordinates(coords)) {      map?.fitBounds({        north: coords.maxLat,         east: coords.maxLng,         south: coords.minLat,         west: coords.minLng,      });    }  }, [users, coords, map]);  return (    <Map      {...props}      options={{ zoomControl: false }}      lat={coords.lat}      lng={coords.lng}      defaultZoom={defaultZoom}      zoom={zoom}      center={{ lat: coords.lat, lng: coords.lng }}      onChange={onMapChange}      draggable={draggable}      onGoogleApiLoaded={(data) => {        setMap(data.map);        props.onGoogleApiLoaded && props.onGoogleApiLoaded(data);      }}      bootstrapURLKeys={{        key: googleMapsApiKey,        // https://stackoverflow.com/a/27054207/12347085        libraries: ['visualization'],      }}      heatmap={{            positions: clusterPoints.map(point => ({          lat: point.geometry.coordinates[1],          lng: point.geometry.coordinates[0],        })),        options: {             radius: 30,             opacity: 0.6,        },      }}    />  );};

'@shared/components/Map/Map'

import React, { ComponentClass, FC, ReactElement } from 'react';import { useTheme } from '@mui/material';import GoogleMap, { Props as GoogleMapProps } from 'google-map-react';import noop from 'lodash/noop';import { googleMapsApiKey } from '@shared/config';import { dark } from './Map.dark.styles';import { light } from './Map.light.styles';const ReactGoogleMap = GoogleMap as ComponentClass<GoogleMapProps>;interface MarkerProps {  lat: number,  lng: number,  children: ReactElement<any, any>,}export const Marker: FC<MarkerProps> = ({ children }) => children;export const Map: FC<{ lat: number, lng: number } & GoogleMapProps> = ({  lat,  lng,  children,  defaultZoom = 14,  onChange = noop,  ...props}) => {  const theme = useTheme();  const styles = theme.palette.mode === 'dark' ? dark : light;  return (    <ReactGoogleMap      bootstrapURLKeys={{ key: googleMapsApiKey }}      center={{ lat, lng }}      defaultCenter={props.defaultCenter}      defaultZoom={defaultZoom}      {...props}      onChange={onChange}      options={{        styles,        fullscreenControl: false,        ...props.options,      }}      yesIWantToUseGoogleMapApiInternals    >      {children}    </ReactGoogleMap>  );};

**Screenshots 🖥**![CleanShot 2024-09-26 at 14 58 38@2x](https://github.com/user-attachments/assets/6ab7eea7-0c90-434d-b6e4-fd418695393f)

Environment:

  "dependencies": {    "@byteowls/capacitor-sms": "5.0.0",    "@capacitor-community/contacts": "5.0.5",    "@capacitor-community/fcm": "6.0.0",    "@capacitor-firebase/authentication": "6.0.0",    "@capacitor/android": "6.1.0",    "@capacitor/app": "6.0.0",    "@capacitor/browser": "6.0.1",    "@capacitor/clipboard": "^6.0.1",    "@capacitor/core": "6.1.0",    "@capacitor/geolocation": "6.0.0",    "@capacitor/ios": "6.1.0",    "@capacitor/keyboard": "6.0.1",    "@capacitor/push-notifications": "6.0.1",    "@capacitor/share": "6.0.1",    "@capawesome/capacitor-badge": "6.0.0",    "@emotion/react": "11.11.3",    "@emotion/styled": "11.11.0",    "@hotjar/browser": "1.0.9",    "@mui/icons-material": "5.16.5",    "@mui/lab": "5.0.0-alpha.122",    "@mui/material": "5.11.12",    "@mui/x-date-pickers-pro": "7.11.1",    "@react-spring/web": "^9.7.4",    "@sandstreamdev/react-swipeable-list": "^1.0.2",    "@sentry/react": "7.102.0",    "@sentry/vite-plugin": "2.16.1",    "@talkjs/react": "0.1.7",    "@tanstack/react-query": "4.26.1",    "@tanstack/react-virtual": "3.0.1",    "@types/google-libphonenumber": "^7.4.30",    "@types/google-map-react": "^2.1.10",    "axios": "1.3.4",    "capacitor-native-settings": "6.0.0",    "capacitor-plugin-app-tracking-transparency": "2.0.5",    "chalk": "4.1.2",    "clear": "0.1.0",    "date-fns": "2.29.3",    "date-fns-tz": "2.0.1",    "figlet": "1.5.2",    "firebase": "9.17.2",    "framer-motion": "^11.3.30",    "geojson": "0.5.0",    "google-libphonenumber": "^3.2.34",    "google-map-react": "^2.2.1",    "inquirer": "8.0.0",    "jsdom": "21.1.1",    "lodash": "4.17.21",    "query-string": "8.1.0",    "react": "18.3.1",    "react-device-detect": "2.2.3",    "react-dom": "18.3.1",    "react-facebook-pixel": "1.0.4",    "react-firebase-hooks": "5.1.1",    "react-hook-form": "7.43.5",    "react-international-phone": "^4.2.9",    "react-markdown": "9.0.1",    "react-qr-code": "^2.0.15",    "react-router": "6.9.0",    "react-router-dom": "6.9.0",    "react-spinners": "0.13.8",    "react-text-loop": "^2.3.0",    "react-tinder-card": "^1.6.4",    "react-use": "17.4.0",    "rimraf": "4.4.0",    "sanitize-html": "2.10.0",    "supercluster": "8.0.1",    "talkjs": "0.18.0",    "use-supercluster": "1.1.0",    "web-vitals": "3.3.0"  }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions


      [8]ページ先頭

      ©2009-2025 Movatter.jp