You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mapbox GL实现单个点的饼图标记(无需聚类)

可行方案:为单个GeoJSON点绘制饼图标记

直接用circle-color确实做不到饼图效果——因为circle图层是单一的圆形,只能设置单一颜色或单维度的颜色映射,没法拆分出多区块的饼图样式。下面给你两个实用的实现方案:

方案1:动态生成SVG饼图作为标记(适配Mapbox GL JS等支持自定义图标的库)

多数地图库的symbol图层支持自定义SVG图标,我们可以根据每个要素的属性值动态生成饼图SVG,再作为点标记使用。

示例代码(以Mapbox GL JS为例):

// 计算各数值的占比角度
function getPieAngles(properties) {
  const total = properties.value1 + properties.value2 + properties.value3;
  return [
    (properties.value1 / total) * 360,
    (properties.value2 / total) * 360,
    (properties.value3 / total) * 360
  ];
}

// 生成饼图SVG字符串
function buildPieSVG(angles) {
  const radius = 15;
  let startAngle = -90; // 从顶部开始绘制
  const colors = ['#ff4444', '#00C851', '#33b5e5'];
  let svgParts = [`<svg width="${radius*2}" height="${radius*2}" viewBox="0 0 ${radius*2} ${radius*2}">`];

  angles.forEach((angle, idx) => {
    const endAngle = startAngle + angle;
    const largeArc = angle > 180 ? 1 : 0;
    // 计算饼块路径的坐标点
    const startX = radius + radius * Math.cos(startAngle * Math.PI / 180);
    const startY = radius + radius * Math.sin(startAngle * Math.PI / 180);
    const endX = radius + radius * Math.cos(endAngle * Math.PI / 180);
    const endY = radius + radius * Math.sin(endAngle * Math.PI / 180);

    svgParts.push(`
      <path d="M ${radius} ${radius} L ${startX} ${startY} A ${radius} ${radius} 0 ${largeArc} 1 ${endX} ${endY} Z" fill="${colors[idx]}" />
    `);
    startAngle = endAngle;
  });

  svgParts.push('</svg>');
  return svgParts.join('');
}

// 预处理GeoJSON,给每个要素添加饼图SVG的Data URL
const processedFeatures = originalGeoJSON.features.map(feature => {
  const angles = getPieAngles(feature.properties);
  const svg = buildPieSVG(angles);
  // 转成Data URL让Mapbox识别
  feature.properties.pieSvg = `data:image/svg+xml;base64,${btoa(svg)}`;
  return feature;
});

// 添加symbol图层显示饼图标记
map.addLayer({
  id: 'pie-markers',
  type: 'symbol',
  source: 'your-geojson-source',
  layout: {
    'icon-image': ['get', 'pieSvg'],
    'icon-size': 1
  }
});

// 更新数据源
map.getSource('your-geojson-source').setData({
  type: 'FeatureCollection',
  features: processedFeatures
});

方案2:Canvas绘制自定义饼图标记(适合Leaflet)

如果用Leaflet,可以自定义Icon类,在Canvas上直接绘制饼图:

// 自定义饼图Icon类
L.PieIcon = L.Icon.extend({
  createIcon: function(options) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const size = options.size || 30;
    canvas.width = canvas.height = size;

    const { value1, value2, value3 } = options.properties;
    const total = value1 + value2 + value3;
    const angles = [
      (value1 / total) * Math.PI * 2,
      (value2 / total) * Math.PI * 2,
      (value3 / total) * Math.PI * 2
    ];
    const colors = ['#ff4444', '#00C851', '#33b5e5'];

    let startAngle = -Math.PI / 2;
    ctx.translate(size/2, size/2); // 移到画布中心

    colors.forEach((color, idx) => {
      ctx.beginPath();
      ctx.moveTo(0, 0);
      ctx.arc(0, 0, size/2, startAngle, startAngle + angles[idx]);
      ctx.closePath();
      ctx.fillStyle = color;
      ctx.fill();
      startAngle += angles[idx];
    });

    return canvas;
  }
});

// 遍历GeoJSON添加饼图标记
originalGeoJSON.features.forEach(feature => {
  const latlng = L.latLng(feature.geometry.coordinates[1], feature.geometry.coordinates[0]);
  const pieIcon = new L.PieIcon({
    size: 30,
    properties: feature.properties
  });
  L.marker(latlng, { icon: pieIcon }).addTo(map);
});

内容的提问来源于stack exchange,提问作者proquibas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 07:32:47