:::warning 聚合实现逻辑:在数据源中开启聚合效果,图层通过筛选是否存在point_count值,分别展示不同效果。 :::

一、地图展示效果

mapbox坐标点位聚合 - 图1

二、聚合效果初步实现

1、添加数据源

  1. export const addCluster = async (map,list) => {
  2. let features = []
  3. features = list.map((item) => {
  4. return {
  5. type: 'Feature',
  6. geometry: {
  7. type: 'Point',
  8. coordinates: item.lnglat, // 点位经纬度[lng,lat]
  9. },
  10. properties: item,
  11. }
  12. })
  13. map.addSource(`test_points`, {
  14. type: 'geojson', // geojson类型资源
  15. data: {
  16. /* geojson数据 */
  17. type: 'FeatureCollection',
  18. features: features,
  19. },
  20. cluster: true, // 是否开启聚合
  21. clusterMaxZoom: 15, //最大缩放到聚合
  22. clusterRadius: 100, // 每一组点的半径,默认50
  23. })
  24. }

2、添加图标

  1. export const addImages = async (map) => {
  2. // 注册图标
  3. let icon = require('@/assets/images/icon_ranks_warehouse@2x.png') // 图标地址,可自定义,也可传值
  4. map.loadImage(icon, (err, imgIcon) => {
  5. map.addImage(`test-icon`, imgIcon)
  6. })
  7. }

3、添加图层

  1. export const addLayers = async (map) => {
  2. // 外围有数字的圆圈,加晕染(聚合点)
  3. map.addLayer({
  4. id: 'cluster-point-layer',
  5. type: 'circle',
  6. // minzoom: 12,
  7. source: 'test_points',
  8. filter: ['has', 'point_count'], // 筛选已聚合的点
  9. paint: {
  10. 'circle-color': '#ff9969', // 圆圈颜色
  11. 'circle-radius': 20, // 圆圈
  12. 'circle-stroke-color': 'rgba(255, 153, 105,0.5)',// 光晕颜色
  13. 'circle-stroke-width': 7, // 光晕大小,单位px
  14. },
  15. })
  16. // 聚合图圆圈中的数字
  17. map.addLayer({
  18. id: 'cluster-count-layer',
  19. type: 'symbol',
  20. source: 'test_points',
  21. filter: ['has', 'point_count'], // 筛选已聚合的点
  22. layout: {
  23. 'text-field': '{point_count_abbreviated}',
  24. 'text-size': 11,
  25. },
  26. // 文字样式属性
  27. paint: {
  28. 'text-color': '#fff',
  29. 'text-opacity': 1,
  30. },
  31. })
  32. // 离散在外部的图标
  33. map.addLayer({
  34. id: `discrete-ponit-layer`,
  35. type: 'symbol',
  36. source: `test_points`,
  37. filter: ['!', ['has', 'point_count']],
  38. layout: {
  39. 'text-field': `{label}`,
  40. 'text-size': 12,
  41. 'icon-image': `test-icon`,
  42. 'icon-size': 0.25,
  43. 'icon-offset': [0, 0],
  44. 'text-offset': [0, 1],
  45. 'text-anchor': 'top',
  46. 'icon-allow-overlap': true,
  47. 'icon-ignore-placement': true,
  48. 'text-allow-overlap': true, // 是否允许文本重叠(可选,默认值为 false。当值为 true 时,文本即使和其他符号触碰也会显示)
  49. 'text-ignore-placement': false, // 是否忽略文本位置(可选,默认值为 false。当值为 true 时,其他符号即使与此文本触碰也会显示)
  50. 'text-optional': false, // 文本是否可不显示(可选,默认值为 false。当值为 true 时,如果文本与图标碰撞,则显示图标)
  51. },
  52. paint: {
  53. 'text-color': 'rgba(255,255,255,0)',
  54. },
  55. })
  56. // 聚合图标点击效果,下探一层
  57. map.on('click', 'cluster-point-layer', (e) => {
  58. var features = map.queryRenderedFeatures(e.point, {
  59. layers: ['cluster-point-layer'],
  60. })
  61. var clusterId = features[0].properties.cluster_id
  62. map.getSource('test_points').getClusterExpansionZoom(clusterId, function (err, zoom) {
  63. if (err) return
  64. map.easeTo({
  65. center: features[0].geometry.coordinates,
  66. zoom: zoom,
  67. })
  68. })
  69. })
  70. }
  71. }

三、权重效果添加

方法1,利用step进行范围筛选

(其他代码如二 — addLayers所示)

  1. // 外围有数字的圆圈,加晕染(聚合点)
  2. map.addLayer({
  3. id: 'cluster-point-layer',
  4. type: 'circle',
  5. // minzoom: 12,
  6. source: 'test_points',
  7. filter: ['has', 'point_count'], // 筛选已聚合的点
  8. paint: {
  9. 'circle-color': '#ff9969',
  10. 'circle-radius': [
  11. 'step',
  12. ['get', 'point_count'],
  13. 20, // 当点数小于100时为20px圆
  14. 100, // 筛选条件,点数100以内
  15. 21, // 点计数在100到750之间时为21px圆
  16. 750, //筛选条件,点数750以内
  17. 22, //点计数大于或等于750时为22像素的圆
  18. ],
  19. 'circle-stroke-color': 'rgba(255, 153, 105,0.5)',
  20. 'circle-stroke-width': ['step', ['get', 'point_count'], 5, 100, 6, 750, 7], // 同上'circle-radius'
  21. },
  22. })

方法2:根据mapbox表达式计算

  1. // 外围有数字的圆圈,加晕染(聚合点)
  2. map.addLayer({
  3. id: 'cluster-point-layer',
  4. type: 'circle',
  5. // minzoom: 12,
  6. source: 'test_points',
  7. filter: ['has', 'point_count'], // 筛选已聚合的点
  8. paint: {
  9. 'circle-color': '#ff9969',
  10. 'circle-radius': ['*', 0.5, ['get', 'point_count']], // point_count值*0.5
  11. 'circle-stroke-color': 'rgba(255, 153, 105,0.5)',
  12. 'circle-stroke-width': ['*', 0.1, ['get', 'point_count']], // 同上'circle-radius'
  13. },
  14. })

四、其他效果实现

其他代码与二相同,只替换了 addLayers 方法
mapbox坐标点位聚合 - 图2

  1. export const addLayers = async (mapcountLength) => {
  2. // countLength为图标总数
  3. // 聚合图标(权重、数字)
  4. map.addLayer({
  5. id: 'cluster-point-layer',
  6. type: 'symbol' /* symbol类型layer,一般用来绘制点*/,
  7. source: `test_points`,
  8. filter: ['has', 'point_count'],
  9. layout: {
  10. 'text-field': '{point_count_abbreviated}',
  11. 'text-size': 14,
  12. 'icon-image': `test-icon`,
  13. 'icon-size': ['*', 0.25, ['+', 1, ['/', ['get', 'point_count'], countLength]]],
  14. 'text-offset': {
  15. property: 'point_count', // 属性名(填写后 stops 的输入值就是对应的属性值)
  16. stops: [
  17. // 断点(除了 type 为 identity 外必填,由输入值和输出值为一组,作为数组的元素)
  18. [0, [-0.1, -1.5]], // 属性 point_count 的值为 0 时,text-offset 为 [-0.1, -1.5]
  19. [countLength, [-0.1, -2.2]], // 属性 point_count 的值为 countLength 时,text-offset 为 [-0.1, -2.2]
  20. ],
  21. }, //property function可以限定最大值最小值,对其中的数值进行平滑插入变化
  22. 'icon-allow-overlap': true,
  23. 'icon-ignore-placement': true,
  24. 'text-allow-overlap': true, // 是否允许文本重叠(可选,默认值为 false。当值为 true 时,文本即使和其他符号触碰也会显示)
  25. 'text-ignore-placement': false, // 是否忽略文本位置(可选,默认值为 false。当值为 true 时,其他符号即使与此文本触碰也会显示)
  26. 'text-optional': false, // 文本是否可不显示(可选,默认值为 false。当值为 true 时,如果文本与图标碰撞,则显示图标)
  27. },
  28. paint: {
  29. 'text-color': 'rgba(255,255,255,1)',
  30. 'text-opacity': 1, // 文本的不透明度(可选,取值范围为 0 ~ 1,默认值为 1)
  31. // 'text-color': '#000000', // 文本的颜色(可选,默认值为 #000000)
  32. },
  33. })
  34. // 离散图标
  35. map.addLayer({
  36. id: `discrete-ponit-layer`,
  37. type: 'symbol' /* symbol类型layer,一般用来绘制点*/,
  38. source: `test_points`,
  39. filter: ['!', ['has', 'point_count']],
  40. layout: {
  41. 'icon-image': `ss-icon`,
  42. 'icon-size': 0.25,
  43. 'icon-offset': [0, 0],
  44. 'icon-allow-overlap': true,
  45. 'icon-ignore-placement': true,
  46. },
  47. })