带有反应传单的自定义标记图标

问题描述 投票:0回答:8

我尝试了在网络、Stackoverflow 和 Github 上找到的所有内容,但仍然无法成功。

我想用自定义图标制作自定义标记,但是使用下面的代码我总是收到错误:“TypeError:options.icon.createIcon 不是函数”

这是我的代码(文件夹路径没有错误,所有内容都在 src/js 或 src/img 中)

图标.js

import L from 'leaflet';

const iconPerson = L.Icon.extend({
  options: {
    iconUrl: require('../img/marker-pin-person.svg'),
    iconRetinaUrl: require('../img/marker-pin-person.svg'),
    iconAnchor: null,
    popupAnchor: null,
    shadowUrl: null,
    shadowSize: null,
    shadowAnchor: null,
    iconSize: new L.Point(60, 75),
    className: 'leaflet-div-icon'
  }
});

export { iconPerson };

标记PinPerson

import React from 'react';
import { Marker } from 'react-leaflet';
import {  iconPerson  } from './Icons';


export default class MarkerPinPerson extends React.Component {

  render() {

    return (
      <Marker
        position={this.props.markerPosition}
        icon={ iconPerson }
        >
      </Marker>
      );
  }
}

真心寻求您的帮助!

icons maps leaflet marker react-leaflet
8个回答
55
投票

我终于找到了 Icon.js 文件的正确代码:

import L from 'leaflet';

const iconPerson = new L.Icon({
    iconUrl: require('../img/marker-pin-person.svg'),
    iconRetinaUrl: require('../img/marker-pin-person.svg'),
    iconAnchor: null,
    popupAnchor: null,
    shadowUrl: null,
    shadowSize: null,
    shadowAnchor: null,
    iconSize: new L.Point(60, 75),
    className: 'leaflet-div-icon'
});

export { iconPerson };

10
投票

我也遇到同样的问题。 这是我的工作解决方案:

`import L from 'leaflet';
import marker from '../assets/placer.svg';
const myIcon = new L.Icon({
    iconUrl: marker,
    iconRetinaUrl: marker,
    popupAnchor:  [-0, -0],
    iconSize: [32,45],     
});`

7
投票

我在尝试弄清楚如何渲染自定义图标服务器端(使用react-leaflet-universal)时被带到这里。我想我应该发布这篇文章,以防将来有人因为同样的原因发现自己在这里。就像react-leaflet-markercluster 的情况一样,我可以通过在返回函数中要求传单来实现此功能,例如:

<Map center={this.props.center}
             zoom={zoom}
             className={leafletMapContainerClassName}
             scrollWheelZoom={false}
             maxZoom={18}
             preferCanvas={false}
        >
            {() => {
                const MarkerClusterGroup = require('react-leaflet-markercluster').default;
                const L = require('leaflet');

                const myIcon = L.icon({
                    iconUrl: require('../assets/marker.svg'),
                    iconSize: [64,64],
                    iconAnchor: [32, 64],
                    popupAnchor: null,
                    shadowUrl: null,
                    shadowSize: null,
                    shadowAnchor: null
                });

                return (
                    <React.Fragment>
                        <TileLayer
                            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                            attribution=''
                            setParams={true}
                        />
                        <MarkerClusterGroup>
                            {coordArray.map(item => {
                                return (
                                    <Marker icon={myIcon} key={item.toString()} position={[item.lat, item.lng]}>
                                        {item.title && <Popup>
                                            <span>{item.title}</span>
                                        </Popup>}
                                    </Marker>
                                )
                            })}
                        </MarkerClusterGroup>
                    </React.Fragment>
                );
            }}
        </Map>

5
投票

在react-leaflet v3中,这对我来说非常有效: 首先我制作了一个 SVG 图标,然后用

encodeURIComponent
对其进行编码,最后将其传递给 Marker

    import React, {useEffect} from 'react';
    import {MapContainer, Marker, Popup, TileLayer} from 'react-leaflet';
    import Main from "../publicComponents/main";
    import L from "leaflet";
    
    const position = [35.72428729739558, 51.447000503540046]
    const Red_MARKER = `data:image/svg+xml;utf8,${encodeURIComponent(`<?xml version="1.0" encoding="iso-8859-1"?>
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="36.059" height="36.059" viewBox="0 0 36.059 36.059" style="transform:rotate(${0}deg)">
      <defs>
        <filter id="Path_10080" x="0" y="0" width="36.059" height="36.059" filterUnits="userSpaceOnUse">
          <feOffset input="SourceAlpha"/>
          <feGaussianBlur stdDeviation="2.5" result="blur"/>
          <feFlood flood-opacity="0.161"/>
          <feComposite operator="in" in2="blur"/>
          <feComposite in="SourceGraphic"/>
        </filter>
      </defs>
      <g id="Group_8038" data-name="Group 8038" transform="translate(5719.5 1106.5)">
        <rect id="Rectangle_2670" data-name="Rectangle 2670" width="21" height="21" transform="translate(-5712 -1099)" fill="none"/>
        <g transform="matrix(1, 0, 0, 1, -5719.5, -1106.5)" filter="url(#Path_10080)">
          <path id="Path_10080-2" data-name="Path 10080" d="M15.4,12.766a6.414,6.414,0,0,0,1.781-5.634l-.446-2.55-2.55-.446A6.414,6.414,0,0,0,8.553,5.916L6.746,7.723c.234-.232-.845.866-.626.626l-2.96,2.96a2.644,2.644,0,0,0,0,3.735l3.114,3.114a2.644,2.644,0,0,0,3.735,0l2.96-2.96Z" transform="translate(19.2 2.96) rotate(45)" fill="${"red"}"/>
        </g>
      </g>
    </svg>
    `)}`;

    const BoatIcon = L.icon({
        iconUrl: Red_MARKER,
        iconSize: [40, 40],
        iconAnchor: [12, 12],
        popupAnchor: [0, 0],
    });
    

    const Index = () => {
        return (<Main>
                <MapContainer center={position} zoom={13}
                              style={{width: "100%", height: "calc(100vh - 80px)", overflow: "hidden"}}>
                    <TileLayer
                        attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
                        url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
                    />
                    <Marker position={position} icon={BoatIcon}>
                        <Popup>
                            A pretty CSS3 popup. <br/> Easily customizable.
                        </Popup>
                    </Marker>
                </MapContainer></Main>
        );
    };
    
    export default Index;

4
投票

您不需要使用 require。而不是给 iconUrl = "../assets/name" 你只需要导入你的 png 或 svg 然后你可以给你的 iconUrl 提供源。看下面的例子:

//首先导入你的图片或svg

import heart from "../../images/other/love.svg";

// 提供图标的来源

let loveIcon = L.icon({
  iconUrl: heart,
  iconRetinaUrl: heart,
  iconAnchor: [5, 55],
  popupAnchor: [10, -44],
  iconSize: [25, 55],
});

// 只需将其添加到您的地图中

L.marker([28, 50], {
       icon: loveIcon,
     }).addTo(map);

4
投票

您可以组织不同的文件,并更改 Svg Compoment 属性,如颜色、高度宽度等...

  1. 我们要创建一个函数React Component,注意我们必须将 {...props} 中的spread传递给svg文件,这样我们就可以在执行时更改它:

import React from "react";
export default function PinMoto(props) {
return (
    //its a SVG example, it`s by half, or corrupted, to not occupy large caracter space here, use your SVG file here...
    <svg width="37" height="45" viewBox="0 0 26 34" fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
        <path d="M13 0C6.0974 0 0.481453 5.83195 0.481453 13C0.481453 15.1519 0.999529 17.2855 1.98441 19.1779L12.3154 33.5811C12.4529 33.8397 12.715 34 13 34C13.285 34 13.547 33.8397 13.6846 33.5811L24.0194 19.1715C25.0005 17.2855 25.5185 15.1518 25.5185 12.9999C25.5185 5.83195 19.9026 0 13 0Z" fill="#DC462D" {...props}/>
        <g clip-Path="url(#clip0)">
        <path d="M19.0012 12.7109C17.3488 12.7109 16.0023 14.1322 16.0023 15.8763C16.0023 17.6204 17.3453 19.0417 19.0012 19.0417C20.6535 19.0417 22 17.6242 22 15.8763C22 14.1285 20.6535 12.7109 19.0012 12.7109ZM19.0012 18.2513C17.7602 18.2513 16.7512 17.1863 16.7512 15.8763C16.7512 14.5663 17.7602 13.5013 19.0012 13.5013C20.2422 13.5013 21.2512 14.5663 21.2512 15.8763C21.2512 17.1863 20.2422 18.2513 19.0012 18.2513Z" fill="white" />
            
        </g>
        <defs>
            <clippath id="clip0">
                <rect width="18" height="19" fill="white" transform="translate(4 4)" />
            </clippath>
        </defs>
    </svg>);
}

  1. 将此组件导入到另一个文件 Utils.js 中,在该文件中我们可以找到一个返回实时修改的 React svg 组件的函数:

import PinMoto from '../svg_pins/PinMoto'
import { ReactDOM } from 'react'
import { renderToStaticMarkup } from 'react-dom/server'
import { divIcon } from 'leaflet'

export const getRequiredSVGPinByCategory = (category,  myStyle) => { 
    let pin
    switch (category) {              
        case 'motorcycle':
            pin = <PinMoto {...myStyle}/>
            break;                                 
        case 'truck':
            pin = <PinCaminhao {...myStyle}/>
            break;                                                                
        default:
            //pin = <PinPadrao {...myStyle}/>
            break;
        }
    const iconMarkup = renderToStaticMarkup(
       pin
    )
    const customMarketIcon = divIcon({
        html: iconMarkup
    })
    return customMarketIcon
}

  1. 在主文件中,包含一个MapContainer,我们可以这样使用:

import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import L from 'leaflet';
import   { getRequiredSVGPinByCategory } from '../../utils/util'
    
//your jsx and codes...
    <MapContainer
        center={[-20.268589, -40.290479]}
        zoom={10}
        scrollWheelZoom={true}
        style={{height: 500, width: '100%'}}>
        <TileLayer
            attribution='&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
            url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"/>
            <Marker position={[-20.268589, -40.290479]}
            icon={ getRequiredSVGPinByCategory('motorcycle', {fill: 'orange'} ) }>
            </Marker>
    </MapContainer>
//...

希望这对你们有用。


0
投票

你可以只使用

react-leaflet-marker
npm 包。它支持动态反应组件作为传单标记

npm 我反应传单标记--保存

     <Marker
        position={[55.796391, 49.108891]}
        size={[80, 20]} // required for placement
        // you can use optional `placement`
        placement="center" // "top", "bottom"
    >
        <div style={{
            background: 'red',
            textAlign: 'center'
        }}>
            center react component
        </div>
    </Marker>

0
投票

您的标记可以如下所示:

<Marker
  position={{
    lat: myLatitude,
    lng: myLongitude,
  }}
  icon={
    divIcon({
      html: renderToStaticMarkup(
        <CustomIcon type={myType} />
      ),
      iconSize: [0, 0], 
    })
  }
/>

在你的

global.css
中:

.leaflet-div-icon {
  background: unset !important;
  border: unset !important;
}

iconSize
可以是 CustomIcon 的大小或 [0,0],并在 CustomIcon 内使用负边距顶部/左侧一半

基于这个答案

© www.soinside.com 2019 - 2024. All rights reserved.