文章更新于 2021-03-03
實(shí)現(xiàn)過程主要用到的Canvas API
繪制圖像: drawImage()
獲取圖像數(shù)據(jù): getImageData()
重寫圖像數(shù)據(jù): putImageData()
導(dǎo)出圖像: toDataURL()

效果圖
1.創(chuàng)建主畫布,確定大小,位置等
2.創(chuàng)建與主畫布相同大小的虛擬圖層畫布,繪制內(nèi)容,返回toDataURL()
3.虛擬圖層合并渲染到主畫布,將圖像以此渲染到主畫布drawImage()
4.通過鼠標(biāo)位置,獲取虛擬圖層像素值,存在像素則進(jìn)行下一步
5.通過鼠標(biāo)位置與圖層數(shù)據(jù)源計(jì)算,獲取目標(biāo)數(shù)據(jù)
6.通過鼠標(biāo)位置+地圖div到窗口的頂部(左部)位置,絕對(duì)定位繪制提示信息框
7.動(dòng)畫展示信息框
1、獲取目標(biāo)數(shù)據(jù)的另一種思路是,在構(gòu)建點(diǎn)、線、面entity數(shù)據(jù)時(shí),利用gco獲取單獨(dú)entity虛擬圖層數(shù)據(jù)與屬性一起歸類保存。
2、利用鼠標(biāo)坐標(biāo)點(diǎn)數(shù)據(jù),索引entity虛擬圖層數(shù)據(jù),如果存在像素值,則說明命中此數(shù)據(jù)。
//主函數(shù)
drawCanvas() {
let that = this;
let canvas = document.getElementById('map');
canvas.setAttribute('width', canvas.offsetWidth);
canvas.setAttribute('height', canvas.offsetHeight);
canvas.className = 'scanning-dashed-circle';
let context = canvas.getContext('2d');
await this.drawImage(require('../img/base.png'), canvas);
let map = {//base地圖原始大小
width: 662,
height: 366
};
let points = this.basePool;//點(diǎn)數(shù)據(jù)源
let dataUrl = await this.drawPointLayer(require('../img/location.svg'), canvas, points, map);
await this.drawImage(dataUrl, canvas);
let getEntity = this.getLayerEntity(canvas, map, points);
let getColor = this.getLayerPixel(canvas, dataUrl);
let interPlay = this.setIntervalShow(points,getEntity);//初始化動(dòng)畫事件
interPlay.play();//首次自動(dòng)播放
canvas.onclick = function(e) {
let x = e.offsetX === undefined ? e.layerX : e.offsetX;
let y = e.offsetY === undefined ? e.layerY : e.offsetY;
if (getColor2(x, y) === '暫無數(shù)據(jù)') {
that.mapOverview = false;
interPlay.stop();//暫停播放
} else {
getEntity(x, y);
setTimeout(interPlay.play(),3000);//延遲啟動(dòng)播放
}
};
}
//往canvas中繪制圖片
drawImage(src, canvas, x = 0, y = 0, width = canvas.width, height = canvas.height) {
return new Promise(resolve => {
let context = canvas.getContext('2d');
let img = new Image();
img.onload = function() {
resolve(context.drawImage(this, x, y, width, height));
};
img.src = src;
});
}
// 繪制點(diǎn)圖層,返回圖層圖像數(shù)據(jù)
async drawPointLayer(src, canvas, ps = [], map) {
let layer = document.createElement("canvas");
layer.width = canvas.width;
layer.height = canvas.height;
let ctx = layer.getContext("2d");
let lineWidth = 5;
for (const item of ps) {
let x = Math.abs(canvas.width / map.width * item.x);
let y = Math.abs(canvas.height / map.height * item.y);
item.x_ = x;
item.y_ = y;
await this.drawImage(require('../img/location.svg'), layer, x - 16, y - 32, 32, 40).then(res => {
//畫筆繪制其他信息
// ctx.lineWidth = 1;
// ctx.strokeStyle = 'rgba(1,70,194,.5)';
// ctx.beginPath();
// ctx.arc(x, y, lineWidth + 1, 0, Math.PI * 2);
// ctx.closePath();
// ctx.stroke();
// ctx.fillStyle = 'rgba(30,199,230,.8)';
// ctx.beginPath();
// ctx.arc(x, y, lineWidth, 0, Math.PI * 2);
// ctx.closePath();
// ctx.fill();
});
}
return layer.toDataURL();
}
//通過距離計(jì)算,獲取點(diǎn)數(shù)據(jù)
getLayerEntity(canvas, map, data) {
let that = this;
let wScale = canvas.width / map.width;
let hScale = canvas.height / map.height;
return function(x, y) {
// 求最短距離
let dis = 9999999;
let target = null;
data.forEach(item => {
let x_ = Math.abs(wScale * item.x);
let y_ = Math.abs(hScale * item.y);
let {x_, y_} = item;
let dis_ = Math.sqrt(Math.pow((x_ - x), 2) + Math.pow((y_ - y), 2));
if (dis > dis_ && dis_ < 50) {
dis = dis_;
target = item;
}
});
if (target) {
that.mapOverview = true;//顯示信息框
that.clickPoint = target;//復(fù)制點(diǎn)數(shù)據(jù)
let map = document.getElementsByClassName('map-container')[0];
let node = document.getElementsByClassName('map-overview')[0];
let {t, l} = that.getOffset(map);//計(jì)算map div距離瀏覽器的像素?cái)?shù)
if (node) {
node.style.top = (t + target.y_ - 40*4) + 'px';
node.style.left = (l + target.x_ + 32) + 'px';
}
} else {
that.mapOverview = false;//隱藏信息框
}
return target;
};
}
//虛擬圖層中獲取像素值
getLayerPixel(canvas, imgsrc, target) {
target = target || {
'rgba(0, 0, 0, 0)': '暫無數(shù)據(jù)'
};
let layer = document.createElement("canvas");
layer.width = canvas.width;
layer.height = canvas.height;
let ctx = layer.getContext("2d");
let img = new Image();
let pixelDataSet = [];
img.onload = function() {
ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
pixelDataSet = ctx.getImageData(0, 0, layer.width, layer.height).data;
};
img.src = imgsrc;
return function(x, y) {
let start = 4 * (x + (layer.width * y));
let output = target[`rgba(${pixelDataSet[start]}, ${pixelDataSet[start + 1]}, ${pixelDataSet[start + 2]}, ${pixelDataSet[start + 3]})`];
return output || [pixelDataSet[start], pixelDataSet[start + 1], pixelDataSet[start + 2], pixelDataSet[start + 3]].join(',');
};
}
//計(jì)算div距離瀏覽器的像素?cái)?shù)
getOffset(obj) {
let t = obj.offsetTop;
let l = obj.offsetLeft;
// 判斷是否有父容器,如果存在則累加其邊距
while (obj = obj.offsetParent) {
t += obj.offsetTop;
l += obj.offsetLeft;
}
return { t, l};
}
//設(shè)置動(dòng)畫,輪播信息框
setIntervalShow(obj, fun) {
let i = 1;
let inter = null;
let play = function () {
inter = setInterval(() => {
if (i === obj.length) {
i = 0;
}
let {x_, y_} = obj[i];
fun.call({}, x_, y_);
i++;
}, 3000);
};
let stop = function () {
clearInterval(inter);
};
return {play, stop};
}