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

能否在Mapbox中以标记形式展示自定义环形/饼图/条形图

实现Mapbox指定坐标的统计图表(环形/饼/条形图)

核心思路

Mapbox GL JS本身不支持直接在点位渲染基于多字段的统计图表,我们可以通过「预渲染图表为图片,再作为自定义图标绑定到指定坐标」的方式实现:

  1. 将表格数据转换为标准GeoJSON格式(包含目标坐标与统计字段)
  2. 用Canvas或SVG渲染环形/饼/条形图,转为Data URL格式的图片
  3. 将图片通过Mapbox符号图层添加到对应坐标点位

步骤1:构造GeoJSON数据

把你的满意度表格转换成GeoJSON格式示例:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "Location": "London",
        "Happy": 5,
        "Neutral": 2,
        "Sad": 6
      },
      "geometry": {
        "type": "Point",
        "coordinates": [-0.1276, 51.5074] // 替换为实际经纬度
      }
    }
  ]
}

步骤2:编写图表渲染函数

以下是基于Canvas的三种图表实现,返回可直接用于Mapbox图标的Data URL:

环形图渲染

function renderDoughnutChart(data, width = 60, height = 60) {
  const canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext('2d');
  
  const total = data.Happy + data.Neutral + data.Sad;
  const colors = ['#2ecc71', '#f39c12', '#e74c3c'];
  const values = [data.Happy, data.Neutral, data.Sad];
  
  let startAngle = 0;
  const centerX = width / 2;
  const centerY = height / 2;
  const radius = Math.min(width, height) / 2 - 5;
  const innerRadius = radius * 0.6;
  
  values.forEach((value, index) => {
    const sliceAngle = (value / total) * 2 * Math.PI;
    ctx.beginPath();
    ctx.moveTo(centerX, centerY);
    ctx.arc(centerX, centerY, radius, startAngle, startAngle + sliceAngle);
    ctx.arc(centerX, centerY, innerRadius, startAngle + sliceAngle, startAngle, true);
    ctx.closePath();
    ctx.fillStyle = colors[index];
    ctx.fill();
    startAngle += sliceAngle;
  });
  
  return canvas.toDataURL();
}

饼图渲染

function renderPieChart(data, width = 60, height = 60) {
  const canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext('2d');
  
  const total = data.Happy + data.Neutral + data.Sad;
  const colors = ['#2ecc71', '#f39c12', '#e74c3c'];
  const values = [data.Happy, data.Neutral, data.Sad];
  
  let startAngle = 0;
  const centerX = width / 2;
  const centerY = height / 2;
  const radius = Math.min(width, height) / 2 - 5;
  
  values.forEach((value, index) => {
    const sliceAngle = (value / total) * 2 * Math.PI;
    ctx.beginPath();
    ctx.moveTo(centerX, centerY);
    ctx.arc(centerX, centerY, radius, startAngle, startAngle + sliceAngle);
    ctx.closePath();
    ctx.fillStyle = colors[index];
    ctx.fill();
    startAngle += sliceAngle;
  });
  
  return canvas.toDataURL();
}

条形图渲染

function renderBarChart(data, width = 80, height = 60) {
  const canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext('2d');
  
  const maxValue = Math.max(data.Happy, data.Neutral, data.Sad);
  const barWidth = width / 3 - 5;
  const barSpacing = 5;
  const colors = ['#2ecc71', '#f39c12', '#e74c3c'];
  const values = [data.Happy, data.Neutral, data.Sad];
  
  values.forEach((value, index) => {
    const barHeight = (value / maxValue) * (height - 20);
    const x = index * (barWidth + barSpacing) + barSpacing;
    const y = height - barHeight - 10;
    
    ctx.fillStyle = colors[index];
    ctx.fillRect(x, y, barWidth, barHeight);
    
    // 绘制数值标签
    ctx.fillStyle = '#000';
    ctx.font = '10px Arial';
    ctx.textAlign = 'center';
    ctx.fillText(value, x + barWidth / 2, y - 5);
  });
  
  return canvas.toDataURL();
}

步骤3:在Mapbox中加载数据并添加图表

初始化Mapbox后,加载GeoJSON数据并绑定图表图标:

map.on('load', () => {
  // 添加GeoJSON数据源
  map.addSource('satisfaction-data', {
    type: 'geojson',
    data: 'path/to/your/data.geojson' // 也可直接传入GeoJSON对象
  });
  
  // 为每个特征生成图表并更新属性
  const features = map.getSource('satisfaction-data')._data.features;
  features.forEach(feature => {
    // 选择要渲染的图表类型,注释切换
    feature.properties.chartUrl = renderDoughnutChart(feature.properties);
    // feature.properties.chartUrl = renderPieChart(feature.properties);
    // feature.properties.chartUrl = renderBarChart(feature.properties);
  });
  
  // 更新数据源
  map.getSource('satisfaction-data').setData({
    type: 'FeatureCollection',
    features: features
  });
  
  // 添加符号图层展示图表
  map.addLayer({
    id: 'satisfaction-charts',
    type: 'symbol',
    source: 'satisfaction-data',
    layout: {
      'icon-image': ['get', 'chartUrl'],
      'icon-size': 1.5,
      'icon-allow-overlap': true
    }
  });
});

注意事项

  • 可根据需求调整图表的尺寸、颜色、标签样式
  • 数据量较大时,建议用Web Worker预渲染图表避免阻塞主线程
  • 如需交互(hover显示详情),可结合Mapbox的mouseenter/mouseleave事件读取特征属性展示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 04:06:25