简体   繁体   English

需要 @react-google-maps/api 中 MarkerClusterer 的动态图标

[英]Need dynamic icon for MarkerClusterer in @react-google-maps/api

TL;DR: In @react-google-maps/api, I want to be able to make dynamic cluster icons/symbol in the style of pie charts, based on the markers in the cluster, but it seems I can only make icons from a static array, and cannot pass the the markers as parameters. TL;DR:在@react-google-maps/api 中,我希望能够根据集群中的标记制作饼图样式的动态集群图标/符号,但似乎我只能从static 数组,并且不能将标记作为参数传递。

Full Description: I am using typescript react with the package @react-google-maps/api, and I'm trying to find a way with the ClustererComponent/MarkerClusterer to take a callback or similar in order to be able to be able to create an svg for each cluster based on the markers in the given cluster.完整描述:我正在使用 typescript 与 package @react-google-maps/api 发生反应,并且我正在尝试使用 ClustererComponent/MarkerClusterer 找到一种方法来进行回调或类似操作,以便能够创建基于给定集群中的标记,每个集群的 svg。

The current issue is that the way I understand it, I am limited to a static array of urls to icons, and thought I can make an svg in those, I have no way to pass parameters into those svgs, as the only way the package allows me to chose a style is thought index in the style array.当前的问题是我理解它的方式,我仅限于一个 static 数组的 url 到图标,并认为我可以在其中制作一个 svg,我无法将参数传递到这些 svgs 中,作为 ZEFE8407A8DZZDEE78A 的唯一方法允许我选择一种样式是样式数组中的思想索引。

I have read thought the following material, but have not been able to get find a way to make an icon dynamically based on the markers:我已经阅读了以下材料,但无法找到一种基于标记动态制作图标的方法:

I have found libraries like this: https://github.com/hassanlatif/google-map-chart-marker-clusterer , that should be able to be used as a solution, but they don't seem to work with the @react-google-maps/api, only with earlier versions of google map.我找到了这样的库: https://github.com/hassanlatif/google-map-chart-marker-clusterer ,应该可以用作解决方案,但它们似乎不适用于@react -google-maps/api,仅适用于早期版本的 google map。 If this is not the case, and these can be used directly, then I would be more then happy with an answer describing how to use libraries like the one above with @react-google-maps/api, as that should allow be to make clusters in the same way as the picture below.如果不是这种情况,并且这些可以直接使用,那么我会更满意一个描述如何通过@react-google-maps/api 使用上述库的答案,因为这应该允许以与下图相同的方式进行聚类。

EDIT: as I got reminded in the comments, here is the code I have so far:编辑:正如我在评论中提醒的那样,这是我到目前为止的代码:

What I've tried: I have tried to find any way to set in an svg element instead of a url, but have since just decided to make a url with the svg data, as shown below. What I've tried: I have tried to find any way to set in an svg element instead of a url, but have since just decided to make a url with the svg data, as shown below. I have tried to edit the url of the clusters under the MarkerClusterer thought the callback for onClusteringBegin , onClusteringEnd and onLoad , but so far, no luck.我试图编辑 MarkerClusterer 下集群的 url 认为onClusteringBeginonClusteringEndonLoad的回调,但到目前为止,还没有运气。

How I make the svg into url-data, so it can be used for img src我如何将 svg 制作成 url-data,所以它可以用于 img src

/*
 * Pie Chart SVG Icon in URL form
 *
 * Inspiration taken from: https://medium.com/hackernoon/a-simple-pie-chart-in-svg-dbdd653b6936
 *
 * Note: As of right now, I am identifying the difference in marker types by setting the type-number I use in the title of the marker
 */
    const serializeXmlNode = (xmlNode: any) => {
        if (typeof window.XMLSerializer != "undefined") {
            return (new window.XMLSerializer()).serializeToString(xmlNode);
        } else if (typeof xmlNode.xml != "undefined") {
            return xmlNode.xml;
        }
        return "";
    }

    function getCoordinatesForPercent(percent: number) {
        const x = Math.cos(2 * Math.PI * percent);
        const y = Math.sin(2 * Math.PI * percent);
        return [x, y];
    }

    const makePieChartIcon = (slices: any[]) => {
        const svgNS = 'http://www.w3.org/2000/svg';

        var svg = document.createElementNS(svgNS, 'svg')
        svg.setAttribute('viewBox', '-1.1 -1.1 2.2 2.2')
        svg.setAttribute('style', 'transform: rotate(-90deg)')
        svg.setAttribute('height', '60')

        var circle = document.createElementNS(svgNS, 'circle')
        circle.setAttribute('r', '1.1')
        circle.setAttribute('fill', 'white')
        svg.appendChild(circle);

        let cumulativePercent = 0;

        slices.map((slice: any) => {
            const [startX, startY] = getCoordinatesForPercent(cumulativePercent);
            cumulativePercent += slice.percent;
            const [endX, endY] = getCoordinatesForPercent(cumulativePercent);
            const largeArcFlag = slice.percent > .5 ? 1 : 0;
            const pathData = [
                `M ${startX} ${startY}`, // Move
                `A 1 1 0 ${largeArcFlag} 1 ${endX} ${endY}`, // Arc
                `L 0 0`, // Line
            ].join(' ');
            const path = document.createElementNS(svgNS, 'path');
            path.setAttribute('d', pathData);
            path.setAttribute('fill', slice.color);
            svg.appendChild(path);
        })

        var svgUrl = 'data:image/svg+xml;charset=UTF-8,' + serializeXmlNode(svg)
        return svgUrl
    }

    const makeDynamicClusterIcon = (markers: any[]) => {
        var numMarkers = markers.length;
        var slices = markers.reduce((acc: any, marker: any) => {
            acc[parseInt(marker.title)].percent += 1 / numMarkers;
            return acc;
        }, [
            { percent: 0, color: 'Green' },
            { percent: 0, color: 'Blue' },
            { percent: 0, color: 'Red' },
        ])
        var newIconURL = makePieChartIcon(slices)
        return newIconURL;
    }

How I use the MarkerClusterer Component我如何使用 MarkerClusterer 组件

<MarkerClusterer
    options={{
        averageCenter: true,
        styles: clusterStyles,
    }}
>
    {(clusterer) =>
        markerData.map((marker: any) => (
            <Marker
                key={marker.key}
                title={String(marker.type)}
                position={{ lat: marker.lat, lng: marker.lng }}
                clusterer={clusterer}
            />
        ))
    }
</MarkerClusterer>

Right now, I can only use some static styles, but I have them as the following for testing:目前,我只能使用一些 static styles,但我有如下测试:

const clusterStyles = [
        {
            height: 50, textColor: '#ffffff', width: 50,
            url: 'data:image/svg+xml;charset=UTF-8,%3Csvg xmlns="http://www.w3.org/2000/svg" height="50" width="100"%3E%3Ccircle cx="25" cy="25" r="20" stroke="black" stroke-width="3" fill="green" /%3E%3C/svg%3E',
        },
        {
            height: 50, textColor: '#ffffff', width: 50,
            url: 'data:image/svg+xml;charset=UTF-8,%3Csvg xmlns="http://www.w3.org/2000/svg" height="50" width="100"%3E%3Ccircle cx="25" cy="25" r="20" stroke="black" stroke-width="3" fill="red" /%3E%3C/svg%3E',
        }
    ];

I found a solution, by finding out that the style array for each cluster (ClusterStyles) can be changed, and then I have change it with the data from the specific markers in the given cluster.我找到了一个解决方案,通过发现可以更改每个集群(ClusterStyles)的样式数组,然后我用给定集群中特定标记的数据对其进行了更改。 I ended up doing this in the callback onClusteringEnd, as here:我最终在回调 onClusteringEnd 中执行此操作,如下所示:

{/*  Added to the MarkerClusterer  */}
onClusteringEnd={(clusterer) => {
    clusterer.clusters.map((cluster) => {
        cluster.clusterIcon.styles = makeDynamicClusterIcon(cluster.markers)
    })
}}

And I changed the last line with return of the makeDynamicClusterIcon function I showed above to instead say:我将最后一行更改为返回上面显示的makeDynamicClusterIcon function 改为:

return [{ url: newIconURL, height: 60, width: 60, textColor: '#FFFFFF', textSize: 22 }];

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM