2021-03-03 基于canvas操作像素點(diǎn),獲取目標(biāo)數(shù)據(jù)

文章更新于 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};
      }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容