akursat / react-leaflet-cluster

React-leaflet-cluster is a plugin for react-leaflet. A wrapper component of Leaflet.markercluster.
MIT License
104 stars 36 forks source link

Uncaught TypeError: Cannot read properties of undefined (reading '__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED') #28

Open jisuo opened 1 year ago

jisuo commented 1 year ago

I import the library:

import MarkerClusterGroup from 'react-leaflet-cluster'

then use it:

<MapContainer>

      <MarkerClusterGroup chunkedLoading>
        {markerIds.map((markerId) => (
            <Marker key={markerId} markerId={markerId} />
        ))}
      </MarkerClusterGroup>

</MapContainer>

and it works locally with vite

but if I do vite build I get the error after running the app: Uncaught TypeError: Cannot read properties of undefined (reading '__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED')

"vite": "^4.2.1",
"react-leaflet": "^4.2.1",
"react-leaflet-cluster": "^2.1.0",
"leaflet": "^1.9.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
kjoscha commented 1 year ago

same with Gatsby:

  31 | require("./assets/MarkerCluster.css");
  32 | require("./assets/MarkerCluster.Default.css");
> 33 | delete leaflet_1.default.Icon.Default.prototype._getIconUrl;
     | ^
  34 | leaflet_1.default.Icon.Default.mergeOptions({
  35 |     iconRetinaUrl: require('./assets/marker-icon-2x.png').default,
  36 |     iconUrl: require('./assets/marker-icon.png').default,

  WebpackError: TypeError: Cannot read properties of undefined (reading 'Default')

dependencies:


  "dependencies": {
    "@emotion/react": "^11.10.6",
    "@emotion/styled": "^11.10.6",
    "@mui/icons-material": "^5.11.16",
    "@mui/material": "^5.12.0",
    "gatsby": "^5.8.1",
    "gatsby-plugin-image": "^3.8.0",
    "gatsby-plugin-manifest": "^5.8.0",
    "gatsby-plugin-offline": "^6.8.0",
    "gatsby-plugin-react-helmet": "^6.8.0",
    "gatsby-plugin-react-leaflet": "^4.0.3",
    "gatsby-plugin-sass": "^6.8.0",
    "gatsby-plugin-sharp": "^5.8.1",
    "gatsby-plugin-sitemap": "^6.8.0",
    "gatsby-source-filesystem": "^5.8.0",
    "gatsby-source-graphql": "^5.8.0",
    "gatsby-transformer-sharp": "^5.8.0",
    "leaflet": "^1.9.3",
    "leaflet.offline": "^2.1.0",
    "react": "^18.1.0",
    "react-dom": "^18.1.0",
    "react-helmet": "^6.1.0",
    "react-icons": "^4.8.0",
    "react-leaflet": "^4.2.1",
    "react-leaflet-cluster": "^2.1.0",
    "react-slick": "^0.29.0",
    "react-slick-styles": "^1.8.2",
    "sass": "^1.62.0"
  },
``
fraemi commented 1 year ago

Anyone found a way to solve this?

jorisvo2 commented 11 months ago

Any news about this issue ?

jisuo commented 8 months ago

I've used a different clustering solution:

import 'leaflet.markercluster'
import { createPathComponent } from '@react-leaflet/core'
import L, {
  type LayerOptions,
  type PolylineOptions,
  type Icon,
  type Point,
  type DivIcon,
  type Marker,
  type FitBoundsOptions,
  type LatLngBounds,
} from 'leaflet'
import type { PropsWithChildren } from 'react'

export interface MarkerCluster extends Marker {
  /*
   * Recursively retrieve all child markers of this cluster.
   */
  getAllChildMarkers(): Marker[]

  /*
   * Returns the count of how many child markers we have.
   */
  getChildCount(): number

  /*
   * Zoom to the minimum of showing all of the child markers, or the extents of this cluster.
   */
  zoomToBounds(options?: FitBoundsOptions): void

  /*
   * Returns the cluster bounds.
   */
  getBounds(): LatLngBounds

  /*
   * Spiderfies the child markers of this cluster.
   */
  spiderfy(): void

  /*
   * Unspiderfies a cluster (opposite of spiderfy).
   */
  unspiderfy(): void
}

export interface MarkerClusterGroupOptions extends LayerOptions {
  /*
   * The maximum radius that a cluster will cover from the central marker (in pixels). Default 80.
   * Decreasing will make more, smaller clusters. You can also use a function that accepts
   * the current map zoom and returns the maximum cluster radius in pixels
   */
  maxClusterRadius?: number | ((zoom: number) => number) | undefined

  /*
   * Function used to create the cluster icon
   */
  iconCreateFunction?: ((cluster: MarkerCluster) => Icon | DivIcon) | undefined

  /*
   * Map pane where the cluster icons will be added.
   * Defaults to L.Marker's default (currently 'markerPane')
   */
  clusterPane?: string | undefined

  /*
   * When you click a cluster at any zoom level we spiderfy it
   * so you can see all of its markers.
   */
  spiderfyOnEveryZoom?: boolean | undefined

  /*
   * When you click a cluster at the bottom zoom level we spiderfy it
   * so you can see all of its markers.
   */
  spiderfyOnMaxZoom?: boolean | undefined

  /*
   * When you mouse over a cluster it shows the bounds of its markers.
   */
  showCoverageOnHover?: boolean | undefined

  /*
   * When you click a cluster we zoom to its bounds.
   */
  zoomToBoundsOnClick?: boolean | undefined

  /*
   * If set to true, overrides the icon for all added markers to make them appear as a 1 size cluster.
   */
  singleMarkerMode?: boolean | undefined

  /*
   * If set, at this zoom level and below markers will not be clustered. This defaults to disabled.
   */
  disableClusteringAtZoom?: number | undefined

  /*
   * Clusters and markers too far from the viewport are removed from the map
   * for performance.
   */
  removeOutsideVisibleBounds?: boolean | undefined

  /*
   * Smoothly split / merge cluster children when zooming and spiderfying.
   * If L.DomUtil.TRANSITION is false, this option has no effect (no animation is possible).
   */
  animate?: boolean | undefined

  /*
   * If set to true (and animate option is also true) then adding individual markers to the
   * MarkerClusterGroup after it has been added to the map will add the marker and animate it
   * into the cluster. Defaults to false as this gives better performance when bulk adding markers.
   * addLayers does not support this, only addLayer with individual Markers.
   */
  animateAddingMarkers?: boolean | undefined

  /*
   * Custom function to calculate spiderfy shape positions
   */
  spiderfyShapePositions?:
    | ((count: number, centerPoint: Point) => Point[])
    | undefined

  /*
   * Increase from 1 to increase the distance away from the center that spiderfied markers are placed.
   * Use if you are using big marker icons (Default: 1).
   */
  spiderfyDistanceMultiplier?: number | undefined

  /*
   * Allows you to specify PolylineOptions to style spider legs.
   * By default, they are { weight: 1.5, color: '#222', opacity: 0.5 }.
   */
  spiderLegPolylineOptions?: PolylineOptions | undefined

  /*
   * Boolean to split the addLayers processing in to small intervals so that the page does not freeze.
   */
  chunkedLoading?: boolean | undefined

  /*
   * Time delay (in ms) between consecutive periods of processing for addLayers. Default to 50ms.
   */
  chunkDelay?: number | undefined

  /*
   * Time interval (in ms) during which addLayers works before pausing to let the rest of the page process.
   * In particular, this prevents the page from freezing while adding a lot of markers. Defaults to 200ms.
   */
  chunkInterval?: number | undefined

  /*
   * Callback function that is called at the end of each chunkInterval.
   * Typically used to implement a progress indicator. Defaults to null.
   */
  chunkProgress?:
    | ((
        processedMarkers: number,
        totalMarkers: number,
        elapsedTime: number
      ) => void)
    | undefined

  /*
   * Options to pass when creating the L.Polygon(points, options) to show the bounds of a cluster.
   * Defaults to empty
   */
  polygonOptions?: PolylineOptions | undefined
}

type Props = PropsWithChildren<MarkerClusterGroupOptions>

export const LeafletMarkerClusterGroup = createPathComponent<
  L.MarkerClusterGroup,
  Props
>(({ children: _c, ...props }, ctx) => {
  const clusterProps: Record<string, any> = {}
  const clusterEvents: Record<string, any> = {}

  // Splitting props and events to different objects
  Object.entries(props).forEach(([propName, prop]) =>
    propName.startsWith('on')
      ? (clusterEvents[propName] = prop)
      : (clusterProps[propName] = prop)
  )

  // Creating markerClusterGroup Leaflet element
  const markerClusterGroup = L.markerClusterGroup(
    clusterProps as MarkerClusterGroupOptions
  )

  // Initializing event listeners
  Object.entries(clusterEvents).forEach(([eventAsProp, callback]) => {
    const clusterEvent = `cluster${eventAsProp.substring(2).toLowerCase()}`
    markerClusterGroup.on(clusterEvent, callback)
  })

  return {
    instance: markerClusterGroup,
    context: { ...ctx, layerContainer: markerClusterGroup },
  }
})

Used like this:

import { MapContainer, Marker } from 'react-leaflet'

<MapContainer>
      <LeafletMarkerClusterGroup>
              {markers.map((marker) => (
                <Marker key={marker.id} position={marker.latlng} />
              ))}
      </LeafletMarkerClusterGroup>
</MapContainer>
jbogdani commented 15 hours ago

As commented by @kjoscha , Gatsby will not build the site with this component. Same error on my side:

require("./assets/MarkerCluster.css");
require("./assets/MarkerCluster.Default.css");
delete leaflet_1.default.Icon.Default.prototype._getIconUrl;
^
leaflet_1.default.Icon.Default.mergeOptions({
iconRetinaUrl: require('./assets/marker-icon-2x.png').default,
iconUrl: require('./assets/marker-icon.png').default,