可以根据聚集在一起的图标的属性来对其进行着色。最简单的方法可能是使用htmlwidgets并在地图渲染时调用javascript函数。
但是,在进入htmlwidget之前,您需要为聚类层设置一个clusterId:
addAwesomeMarkers(clusterId = "cluster" ...
现在我们可以在htmlwidget中找到此图层:
function(el, x) {
map = this;
var cluster = map.layerManager.getLayer('cluster','cluster');
在集群层中,我们想要为图标属性iconCreateFunction
创建一个函数:
cluster.options.iconCreateFunction = function(d) {
}
这个函数应该:
- 遍历由聚合标记表示的所有子标记,
- 识别那些子标记中最高的等级
- 返回一个适当的图标
1. 遍历子标记
对于第一步,我们可以在上面的基础上通过以下方式遍历每个子标记:
cluster.options.iconCreateFunction = function(c) {
var markers = c.getAllChildMarkers();
markers.forEach(function(m) {
})
}
我使用c
代表一个群集,m
代表每个单独的子标记。
2. 获取最高排名的标记
在列表中的主要挑战是识别子图标的最高排名 - 因为数据未绑定到图标,我们的选择受到限制。假设图标的颜色对应于数据框中项目的颜色代码,我将使用图标的颜色来确定其优先级/排名。确定最高排名的子项后,我将根据该子项的排名对群集进行着色。
我将按以下方式对群集进行着色(因为我认为这是您想要的结果):
- 如果任何子项图标为红色,则为红色,
- 如果没有红色但有一些橙色子项,则为橙色,
- 如果没有橙色或红色子项,则为绿色。
要获取颜色,我需要访问正确的属性。 (awesome)标记的颜色(填充)位于:
marker.options.icon.options.markerColor
为了比较颜色,我将使用一个对象来表示每种颜色的等级,这将允许简单比较颜色:
var priority = {
'green':0,
'orange':1,
'red':2
}
这允许:
cluster.options.iconCreateFunction = function(c) {
var markers = c.getAllChildMarkers();
var priority = {
'green': 0,
'orange': 1,
'red': 2
};
var highestRank = 0;
markers.forEach(function(m) {
var color = m.options.icon.options.markerColor;
if(priority[color] > highestRank) {
highestRank = priority[color];
}
})
}
3. 返回一个图标
现在我们有了代表颜色的值,可以返回一个图标。Leaflet聚合图标的样式选项有限。它们使用 L.divIcon()
,这在某种程度上限制了选项。当与聚合标签的css样式结合使用时,它们会创建带有绿色、黄色和橙色的熟悉圆形。
这些默认样式具有以下css类:
.marker-cluster-small // green
.marker-cluster-medium // yellow
.marker-cluster-large // orange
如果我们只使用这些类,就可以轻松地为聚类多边形添加样式:
var styles = [
'marker-cluster-small',
'marker-cluster-medium',
'marker-cluster-large'
]
var style = styles[highestRank];
var count = markers.length;
return L.divIcon({ html: '<div><span>'+count+'</span></div>', className: 'marker-cluster ' + style, iconSize: new L.Point(40, 40) });
整个小部件的外观如下:
function(el,x) {
map = this;
var cluster = map.layerManager.getLayer('cluster','cluster');
cluster.options.iconCreateFunction = function(c) {
var markers = c.getAllChildMarkers();
var priority = {
'green': 0,
'orange': 1,
'red': 2
};
var highestRank = 0;
markers.forEach(function(m) {
var color = m.options.icon.options.markerColor;
if(priority[color] > highestRank) {
highestRank = priority[color];
}
})
var styles = [
'marker-cluster-small',
'marker-cluster-medium',
'marker-cluster-large'
]
var style = styles[highestRank];
var count = markers.length;
return L.divIcon({ html: '<div><span>'+count+'</span></div>', className: 'marker-cluster ' + style, iconSize: new L.Point(40, 40) });
}
}
优化图标
更改颜色
您可能希望将高优先级的图标显示为红色。这是可以做到的,但您需要在地图中添加一个css样式。
一种同时更改上面的图标函数和追加页面样式的方法是,在小部件中使用javascript向页面附加样式。您需要创建两个样式,一个用于包含图标的div,另一个用于图标本身,您可以同时完成两个操作:
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '.red, .red div { background-color: rgba(255,0,0,0.6); }';
document.getElementsByTagName('head')[0].appendChild(style);
(来自 https://dev59.com/v3I-5IYBdhLWcg3wsKv9#1720483)
不要忘记在样式数组中更新你正在使用的类:
var styles = [
'marker-cluster-small', // green
'marker-cluster-medium', // yellow
'red' // red
]
在图标中显示更多信息
您不必局限于在图标中显示数字,您可以显示1-3-5,分别代表一个高优先级、三个中等优先级等。您只需要跟踪每个聚类中每个优先级的子图标数量即可:
var children = [0,0,0];
markers.forEach(function(m) {
var color = m.options.icon.options.markerColor;
children[priority[color]]++;
...
然后用以下方式显示:
return L.divIcon({ html: '<div><span>'+children.reverse()+'</span>...
给出类似这样的东西:
![enter image description here](https://istack.dev59.com/ztWZz.webp)
测试示例
这应该是可复制和粘贴的,以展示除图标中的附加文本之外的所有内容(使用这些文档示例中的代码作为基础):
library(leaflet)
# first 20 quakes
df.20 <- quakes[1:50,]
getColor <- function(quakes) {
sapply(quakes$mag, function(mag) {
if(mag <= 4) {
"green"
} else if(mag <= 5) {
"orange"
} else {
"red"
} })
}
icons <- awesomeIcons(
icon = 'ios-close',
iconColor = 'black',
library = 'ion',
markerColor = getColor(df.20)
)
leaflet(df.20) %>% addTiles() %>%
addAwesomeMarkers(~long, ~lat, icon=icons, label=~as.character(mag), clusterOptions = markerClusterOptions(), group = "clustered", clusterId = "cluster") %>%
htmlwidgets::onRender("function(el,x) {
map = this;
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '.red, .red div { background-color: rgba(255,0,0,0.6); }'; // set both at the same time
document.getElementsByTagName('head')[0].appendChild(style);
var cluster = map.layerManager.getLayer('cluster','cluster');
cluster.options.iconCreateFunction = function(c) {
var markers = c.getAllChildMarkers();
var priority = {
'green': 0,
'orange': 1,
'red': 2
};
var highestRank = 0; // defaults to the lowest level to start
markers.forEach(function(m) {
var color = m.options.icon.options.markerColor;
// check each marker to see if it is the highest value
if(priority[color] > highestRank) {
highestRank = priority[color];
}
})
var styles = [
'marker-cluster-small', // green
'marker-cluster-large', // orange
'red' // red
]
var style = styles[highestRank];
var count = markers.length;
return L.divIcon({ html: '<div><span>'+count+'</span></div>', className: 'marker-cluster ' + style, iconSize: new L.Point(40, 40) });
}
}")