mapboxGL中多颜色图标的实现

2023-03-31 14:09:20 浏览数 (2)

概述

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

效果

实现

1. 分析

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

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

2. 实现

添加测试数据源

代码语言:javascript复制
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)
})

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

代码语言:javascript复制
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的方法

代码语言:javascript复制
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;
}

0 人点赞