Mapbox开启地形后circle点位拾取不准确的bug解决方案

问题:最近遇到一个需求,在mapbox项目中开启rgb地形时,需要拾取点位并弹窗展示相关信息,最开始点位绘制采取circle的方案,发现在拾取时存在bug,有时能拾取到,有时又拾取不到;

解决:最后采用symbol图层的方式加载点位解决,用canvas画出点位并保存为png加载到mapbox中,使用symbol图层加载,就能100%正常拾取了。

//使用canvas的方式绘制圆形图标
function _drawCircle({
  radius,
  color,
  strokeColor,
  strokeWidth,
}: {
  radius: number;
  color: string;
  strokeWidth: number;
  strokeColor: string;
}): string {
  const pixelRatio = window.devicePixelRatio || 1;
  const canvas = document.createElement('canvas');
  const size = (radius + strokeWidth) * 2 + 5;
  canvas.width = canvas.height = size * pixelRatio;
  canvas.style.width = canvas.style.height = `${size}px`;

  const context = canvas.getContext('2d');
  if (context) {
    context.scale(pixelRatio, pixelRatio);
    const centerX = radius + strokeWidth / 2;
    const centerY = radius + strokeWidth / 2;

    context.beginPath();
    context.arc(centerX, centerY, radius, 0, 2 * Math.PI);
    context.fillStyle = color;
    context.strokeStyle = strokeColor;
    context.lineWidth = strokeWidth;
    context.fill();
    context.stroke();

    const dataURL = canvas.toDataURL('image/png');
    return dataURL;
  }

  return '';
}

//将绘制的图标加载到mapbox实例中
_addImages() {
        const circle = this._drawCircle({
            radius: 10,
            color: 'red',
            strokeColor: 'yellow',
            strokeWidth: 3
        });
        this.map.loadImage(circle as any, (err, image) => {
            if (err) throw err;
            this.map.addImage('circle', image as any);
        });
    }

//最后以symbol图层的方式加载点位
map.addLayer({
            id,
            type: 'symbol',
            source,
            layout: {
                'icon-image': 'circle',
                'icon-size': 0.6,
                'icon-allow-overlap': true
            }
        });

总结:推测使用circle方式绘制的点位实际是贴在球体上,没有高度,因此当mapbox场景中加入地形后,点位虽然显示在表面上,但实际的位置并没有变动。而使用symbol方式加载的点位图标始终面向屏幕,因此拾取的判断更加简单而准确。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要根据point获取点位信息,可以使用Mapbox的Feature State功能。具体步骤如下: 1. 在Mapbox官网注册账户并创建一个项目。 2. 在项目中添加地图数据源和图层。 3. 在数据源中添加点位信息,并为每个点位设置一个唯一的ID。 4. 在图层中使用数据源中的点位信息,并将点位ID设置为图层的id属性。 5. 在前端代码中监听地图的点击事件,获取点击点的坐标。 6. 使用Mapbox的queryRenderedFeatures方法查询当前点击点下面的点位信息,并获取该点位的ID。 7. 使用Mapbox的setFeatureState方法设置该点位的状态为选中状态。 8. 在前端页面中根据该点位的状态展示对应的信息。 以下是示例代码: ```javascript // 添加地图数据源和图层,其中点位数据源名为 'points',点位图层名为 'points-layer' map.addSource('points', { type: 'geojson', data: { type: 'FeatureCollection', features: [ { type: 'Feature', properties: { name: 'Point 1' }, geometry: { type: 'Point', coordinates: [100, 0] }, id: 'point-1' }, { type: 'Feature', properties: { name: 'Point 2' }, geometry: { type: 'Point', coordinates: [101, 1] }, id: 'point-2' } ] } }); map.addLayer({ id: 'points-layer', type: 'circle', source: 'points', paint: { 'circle-radius': 10, 'circle-color': '#007cbf' } }); // 监听地图点击事件 map.on('click', function(e) { // 获取点击点的坐标 var point = e.point; // 查询当前点击点下面的点位信息,并获取该点位的ID var features = map.queryRenderedFeatures(point, { layers: ['points-layer'] }); var feature = features[0]; var id = feature.properties.id; // 设置该点位的状态为选中状态 map.setFeatureState({ source: 'points', id: id }, { selected: true }); }); // 监听地图移动事件,恢复所有点位的状态为未选中状态 map.on('move', function() { var features = map.queryRenderedFeatures({ layers: ['points-layer'] }); features.forEach(function(feature) { var id = feature.properties.id; map.setFeatureState({ source: 'points', id: id }, { selected: false }); }); }); // 在前端页面中根据点位状态展示对应信息 map.on('click', 'points-layer', function(e) { var name = e.features[0].properties.name; var selected = e.features[0].state.selected; if (selected) { // 展示选中状态的信息 console.log(name + ' is selected'); } else { // 展示未选中状态的信息 console.log(name + ' is not selected'); } }); ``` 需要注意的是,使用Feature State功能需要在代码中设置Mapbox的版本为1.6.0及以上,并且需要在图层中设置state属性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值