0

I'm in trouble while implementing the doughnut chart over OpenStreetMap. I'm using react-chartjs2 for the doughnut chart and react-leaflet for Openstreetmap. Like we use the location icon on different coordinates over the map but here I want to use a Doughnut graph over the map instead of the location icon.

I want to achieve something like this enter image description here

As per the react-leaflet documentation, the Marker icon property accepts two types of icons that is icon strings like image URL and divIcon which can be some HTML elements but while I'm rendering react component it does not accept and not showing it.

Here you can check in codesandbox I have added code to make it easy to try

https://codesandbox.io/s/doughnut-chart-over-osm-map-1indvl?file=/src/App.js

1 Answers1

0

For what I know marker Icons can only be static, I use a function to create my only markers based on icons and plain html. Will be hard to do that with a component in your case.

My icon render function

import { divIcon } from "leaflet";
import { ReactElement } from "react";
import { renderToString } from "react-dom/server";

export const createLeafletIcon = (
  icon: ReactElement,
  size: number,
  className?: string,
  width: number = size,
  height: number = size
) => {
  return divIcon({
    html: renderToString(icon),
    iconSize: [width, height],
    iconAnchor: [width / 2, height],
    popupAnchor: [0, -height],
    className: className ? className : "",
  });
};

In your case I would try to cheese it and create blank markers and show the graph in popups instead and just force the popups to alway stay open.

EDIT: Added my custom Marker code below that have some nice options. You can just use the defaultOpen option, and add the graph as a child component to the marker and it will show up in the popup. You can the change the styling of you liking to make it look like the graph is the marker.

import { LatLngLiteral } from "leaflet";
import React, { Children, ReactElement, useEffect, useRef } from "react";
import { Marker, Popup, useMap } from "react-leaflet";
import { MapPin } from "tabler-icons-react";
import { createLeafletIcon } from "./utils";

export interface LeafletMarkerProps {
  position: LatLngLiteral;
  flyToPosition?: boolean;
  size?: number;
  color?: string;
  icon?: ReactElement;
  defaultOpen?: boolean;
  onOpen?: () => void;
  children?: React.ReactNode;
  markerType?: string;
  zIndexOffset?: number;
}

const LeafletMarker: React.FC<LeafletMarkerProps> = ({
  position,
  flyToPosition = false,
  children,
  size = 30,
  color,
  defaultOpen = false,
  onOpen,
  icon = <MapPin size={size} color={color} />,
  markerType,
  zIndexOffset,
}) => {
  const map = useMap();

  const markerRef = useRef(null);
  position && flyToPosition && map.flyTo(position);

  const markerIcon = createLeafletIcon(icon, size, markerType); // Important to not get default styling
  useEffect(() => {
    if (defaultOpen) {
      try {
        // @ts-ignore
        if (markerRef.current !== null && !markerRef.current.isPopupOpen()) {
          // @ts-ignore
          markerRef.current.openPopup();
        }
      } catch (error) {}
    }
  }, [defaultOpen, position.lat, position.lng]);

  return (
    <Marker
      eventHandlers={{
        popupopen: () => onOpen && onOpen(),
      }}
      ref={markerRef}
      icon={markerIcon}
      position={position}
      zIndexOffset={zIndexOffset}
    >
      {/* autoPan important to not have jittering */}
      <Popup autoPan={false}>{children}</Popup>
    </Marker>
  );
};

export default LeafletMarker;
Disco
  • 1,304
  • 1
  • 6
  • 12
  • Dear its working on your end I have tried this but it return me an an empty tag. also im confuse with simple jsx component and a graph component where graph component convert to convas where map convas already there... –  Nov 08 '22 at 05:08
  • Also, I have added codesandbox link if you want a try map and graph are there it will be helpful. thanks –  Nov 08 '22 at 05:12
  • I will not do the work for you, however I have updated my answer and added my custom Marker component, that can show markers with open popups by default. You will have to adjust this code to fit you project. – Disco Nov 08 '22 at 09:35
  • It's not the way to implement it properly I am following the documentation. BTW thank you –  Nov 10 '22 at 06:23
  • Good luck, and if you come up with a better solution post it as an answer. The reason I propose leveraging the popup instead och divIcon is that you can use react component in the popup. divIcon only support HTMLElement and to go from a react component to a HTMLElement will make it static, which is okey on static icons, but will not work on animated or reactive components. – Disco Nov 10 '22 at 08:34