概述
mapboxGL中图标可以通过配置sprite
,也可通过map.addImage
添加。但在实际工作中,sprite
多用于底图图标的配置,通过map.addImage
对于图标较多的情况下,由于图片的异步导致使用起来比较麻烦。本文讲述如何结合OffscreenCanvas
在mapboxGL中实现多颜色的图标的展示。
效果
实现
1. 分析
map.addImage
添加的是一个ImageBitmap
,可通过OffscreenCanvas
的transferToImageBitmap
将canvas
转换为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;
}