一、需求
需要自定义配置数据的marker,其中图片内容要灵活可配置自动生成。此处项目用的百度地图。
效果图:
二、思路
用背景图+canvas绘制数字的方式生成icon的图片资源。
再将icon生成对应地图marker。
三、代码
canvasImg.js
<!--
* @description canvasImg.js 背景图+绘制内容生成图片资源
* @author xw
!-->
export function addFontWithBgImg(file, params, callback) {
var ready = new FileReader()
/* 开始读取指定的Blob对象或File对象中的内容. 当读取操作完成时,readyState属性的值会成为DONE,如果设置了onloadend事件处理程序,则调用之.同时,result属性中将包含一个data: URL格式的字符串以表示所读取文件的内容.*/
ready.readAsDataURL(file) // 调用reader.readAsDataURL()方法,把图片转成base64
ready.onload = function () {
var re = this.result
canvasDataURL(re, params, callback)
}
}
/**
* path 背景图资源路径
* params:{ bgImgStyle: 'no-repeat', bgWidth: 35, bgHeight: 48, fontText: 1, fontWidth: 35, fontHeight: 35, font: 'bold 20px PingFangSC', bgc: '#0081FF', fontColor: '#fff' }
* callback
* bgImgStyle = [
"no-repeat", // 不平铺
"repeat-x", // 横向平铺
"repeat-y", // 纵向平铺
"repeat" // 全画布平铺
];
* */
export function canvasDataURL(path, params, callback) {
const defaultOptions = {
bgImgStyle: 'no-repeat',
bgWidth: 45,
bgHeight: 48,
bgc: '#0081FF',
fontText: 1, // 图片正中 大数字
font: 'bold 20px PingFangSC',
fontWidth: 34,
fontHeight: 39,
fontColor: '#0081FF',
fontTwoText: 1, // 右上角 小数字
fontTwo: 'bold 10px PingFangSC',
fontTwoColor: '#fff',
fontTwoPositionX: 35,
fontTwoPositionY: 10,
}
const options = Object.assign(defaultOptions, params)
const { bgImgStyle, bgWidth, bgHeight, fontText, fontWidth, fontHeight, font, bgc, fontColor, fontTwoText, fontTwo, fontTwoColor, fontTwoPositionX, fontTwoPositionY } = options
// console.log('createNumberImg()-options', options)
const img = new Image()
img.src = path
img.onload = function () {
const canvas = document.createElement('canvas');
// document.body.appendChild(canvas); //将画布添加到页面上
// 设置画布大小
canvas.width = bgWidth;
canvas.height = bgHeight;
// context 获取2D上下文
const ctx = canvas.getContext('2d');
// 清空画布内容
ctx.clearRect(0, 0, canvas.width, canvas.height);
// ctx.fillStyle = ctx.createPattern(img, bgImgStyle);
// ctx.fillRect(0, 0, canvas.width, canvas.height);
// ctx.fill();
ctx.drawImage(img, 0, 0, canvas.width, canvas.height) //绘制背景图片
// 背景色 部分,会覆盖背景图, 背景色做背景 和 背景图做背景 二选一
// ctx.fillStyle = bgc
// 背景画布设置完后,绘制第2层内容, 覆盖在背景上的 内容---ctxTwo--fillText
// const ctxTwo = canvas.getContext('2d');
ctx.font = font
ctx.fillStyle = fontColor
ctx.textAlign = 'center' // 水平居中 left center right ,positionX = fontWidth / 2
const positionX = fontWidth / 2
ctx.textBaseline = 'middle' // 垂直居中 top middle bottom, positionY = fontHeight / 2
const positionY = fontHeight / 2
ctx.fillText(String(fontText), positionX, positionY)
ctx.font = fontTwo
ctx.fillStyle = fontTwoColor
ctx.fillText(String(fontTwoText), fontTwoPositionX, fontTwoPositionY)
// 导出为图片数据URL
const imageDataUrl = canvas.toDataURL('image/png', 1); // canvas.toDataURL('image/png', 1)
// console.log("生成的图像资源链接:", imageDataUrl);
callback(imageDataUrl)
}
}
/**
* 将以base64的图片url数据转换为Blob
* @param urlData
* 用url方式表示的base64图片数据
*/
export function convertBase64UrlToBlob(urlData) {
const arr = urlData.split(',')
const mime = arr[0].match(/:(.*?);/)[1]
const bstr = atob(arr[1])
let n = bstr.length
const u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new Blob([u8arr], { type: mime })
}
具体使用
createIconImg() {
// 图片资源 自己找几个bg 在项目里本地引用
const iconNormal = require('@/assets/image/bg/normal.png');
const iconDanger = require('@/assets/image/bg/danger.png');
const iconInfo = require('@/assets/image/bg/info.png');
const userImgMap = {
'0': iconInfo,
'1': iconNormal,
'2': iconNormal,
'3': iconDanger,
}
const fontColorMap = {
'0': '#666',
'1': '#0081FF',
'2': '#0081FF',
'3': 'red',
}
const pointList = [
{ lng: '113.939435', lat: '22.522226', completeStatus: '0', frequency: 1 },
{ lng: '113.947254', lat: '22.524549', completeStatus: '1', frequency: 3 },
{ lng: '113.945889', lat: '22.520798', completeStatus: '2', frequency: 4 },
]
// 设置地图 marker ---此处用的百度地图--BMap--使用 canvasDataURL方法
const markers = []
if (BMap && pointList && pointList.length > 0) {
const mapRef = this.$refs.map
mapRef?.clearOverlays()
// 生成的icon图片bgWidth背景宽高 要和 canvas画布宽高保持一致
const bgWidth = 45
const bgHeight = 48
const iconSize = new BMap.Size(bgWidth, bgHeight)
const iconOptions = { offset: new BMap.Size(25, 50) }
pointList.forEach((em, idx) => {
const userImg = userImgMap[String(em.completeStatus) || '0']
const fontColor = fontColorMap[String(em.completeStatus) || '0']
const params = { bgWidth, bgHeight, fontText: String(idx+1), fontColor, fontTwoText: String(em.frequency)}
// 生成图片资源
canvasDataURL(userImg, params, function (imgUrl) {
const siteMarker = this.createMarker(mapRef, imgUrl, iconSize, iconOptions, item, index)
markers.push(siteMarker)
})
})
setTimeout(() => {
const centerPoint = new BMap.Point(Number(selectRow.pointList[0]?.lng), Number(selectRow.pointList[0]?.lat));
mapRef.centerAndZoom(centerPoint, 15)
}, 300)
}
},
createMarker(mapRef, iconImg, item, index) {
const siteIcon = new BMap.Icon(
iconImg,
iconSize,
iconOptions,
)
const sitePoint = new BMap.Point(Number(item.lng), Number(item.lat));
const siteMarker = new BMap.Marker(sitePoint, {
icon: siteIcon
})
// siteMarker.lisaSiteInfo = item // lisaSiteInfo自定义字段 主要装item信息,在InfoWindow的innerHtml时使用
// const newHtml = '<div class="">我是innerHtml</div>'
// console.log('newHtml', newHtml)
// const infoWindow = new BMap.InfoWindow({
// content: newHtml,
// InfoWindowOptions: {
// width: 400,
// height: 300,
// enableAutoPan: true,
// }
// })
siteMarker.on('click', function () {
alert("carText模拟触发了地图click事件!");
// console.log('mapRef', mapRef)
// mapRef.openInfoWindow(infoWindow, sitePoint); //开启信息窗口
})
mapRef.addOverlay(siteMarker)
return siteMarker
},