mapboxGL中多颜色图标的实现

概述

mapboxGL中图标可以通过配置sprite,也可通过map.addImage添加。但在实际工作中,sprite多用于底图图标的配置,通过map.addImage对于图标较多的情况下,由于图片的异步导致使用起来比较麻烦。本文讲述如何结合OffscreenCanvas在mapboxGL中实现多颜色的图标的展示。

效果

实现

1. 分析

map.addImage添加的是一个ImageBitmap,可通过OffscreenCanvastransferToImageBitmapcanvas转换为ImageBitmap

图标分为两个部分:底部背景,根据不同的业务属性展示不同的颜色,可通过修改ImageData实现颜色的修改;叠加的图标,如果是多个图片,可通过sprite合成一张图片,再通过drawImage绘制对应的图标,如果是一个就直接绘制就可。

2. 实现

添加测试数据源

const features = res.map(({lon, lat, name}) => {
  const type = Math.round(Math.random() * 3).toString()
  return new Point({name, type}, [lon, lat])
})
map.addSource('vector-source', {
  type: 'geojson',
  data: new Geojson(features)
})

加载背景图片和图标图片,并添加图层

const imgBg = new Image()
imgBg.src = bgIcon
imgBg.onload = () => { // 加载背景图片
  const img = new Image()
  img.src = icon
  img.onload = () => { // 加载图标图片
    // 根据业务值获取图标
    const getIcon = (type, color) => {
      const [r, g, b] = hex2rgb(color)  // 将16进制颜色转换为rgb
      const canvas = new OffscreenCanvas(imgBg.width, imgBg.height)
      const ctx = canvas.getContext('2d')
      ctx.drawImage(imgBg, 0, 0)
      const imageD = ctx.getImageData(0, 0, imgBg.width, imgBg.height);
      const pdata = imageD.data;
      for (let j = 0; j < pdata.length; j+=4) {
        pdata[j] = r;
        pdata[j + 1] = g;
        pdata[j + 2] = b;
      }
      ctx.putImageData(imageD, 0, 0);
      const scale = 0.52
      const w = img.width * scale, h = img.height * scale
      ctx.drawImage(img, img.width * 0.24, img.height * 0.12, w, h)
      const imgId = 'icon-' + type
      map.addImage(imgId, canvas.transferToImageBitmap())
      return imgId
    }
    const colorDict = {
      '1': '#e30404',
      '0': '#0863e5'
    }
    let icons = [
          'match',
          ['get', 'type']
    ]
    for (const k in colorDict) {
      icons.push(k)
      icons.push(getIcon(k, colorDict[k]))
    }
    icons.push(getIcon('default', '#0aaf1b'))
    map.addLayer({
      id: 'vector-source',
      type: 'symbol',
      source: 'vector-source',
      layout: {
        'icon-image': icons,
        'icon-size': 0.8,
        'icon-allow-overlap': true
      }
    })
  }
}

16进制转换为rgb的方法

function hex2rgb(hex) {
  if (typeof hex !== "string") return;
  hex = hex.toLowerCase();
  const reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/;
  if (hex && reg.test(hex)) {
    if (hex.length === 4) {
      let hexNew = "#";
      for (var i = 1; i < 4; i += 1) {
        hexNew += hex.slice(i, i + 1).concat(hex.slice(i, i + 1));
      }
      hex = hexNew;
    }
    let hexChange = [];
    for (let i = 1; i < 7; i += 2) {
      hexChange.push(parseInt("0x" + hex.slice(i, i + 2)));
    }
    return hexChange
  }
  return hex;
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在 React 中删除多个 Mapbox GL popups 可以按照以下步骤进行: 1. 给每个 popup 添加一个唯一的 ID,可以使用 uuid 库生成一个唯一的 ID。 2. 将所有的 popups 存储在一个数组中,数组中每个元素都包含一个唯一的 ID 和 popup 的信息。 3. 当需要删除某个 popup 时,可以根据其唯一的 ID 找到相应的 popup。 4. 使用 Mapbox GL 的 `remove` 方法将该 popup 从地图中删除。 5. 在数组中删除该 popup 的信息。 以下是示例代码: ```javascript import React, { useState, useEffect } from "react"; import mapboxgl from "mapbox-gl"; import { v4 as uuidv4 } from "uuid"; mapboxgl.accessToken = "your-mapbox-token"; function Map() { const [map, setMap] = useState(null); const [popups, setPopups] = useState([]); useEffect(() => { const newMap = new mapboxgl.Map({ container: "map", style: "mapbox://styles/mapbox/streets-v11", center: [-122.4194, 37.7749], zoom: 12, }); setMap(newMap); return () => { newMap.remove(); }; }, []); const addPopup = () => { const popup = new mapboxgl.Popup({ closeButton: false, closeOnClick: false, }) .setLngLat([-122.4194, 37.7749]) .setHTML("<h1>Hello World!</h1>") .addTo(map); const id = uuidv4(); setPopups([...popups, { id, popup }]); }; const removePopup = (id) => { const popupInfo = popups.find((popup) => popup.id === id); if (popupInfo) { popupInfo.popup.remove(); setPopups(popups.filter((popup) => popup.id !== id)); } }; return ( <div> <button onClick={addPopup}>Add Popup</button> <div id="map" style={{ width: "100%", height: "400px" }}></div> </div> ); } export default Map; ``` 在上面的示例代码中,我们使用 uuid 库生成唯一的 ID,将每个 popup 的 ID 和 popup 对象存储在一个数组中。当需要删除某个 popup 时,调用 `removePopup` 方法,并传入该 popup 的唯一 ID,该方法会根据该 ID 找到相应的 popup 并从地图中删除。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛老师讲GIS

感谢老板支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值