0
点赞
收藏
分享

微信扫一扫

2021-03-03 基于canvas操作像素点,获取目标数据

独孤凌雪 2021-10-09 阅读 85

文章更新于 2021-03-03

实现过程主要用到的Canvas API

1.创建主画布,确定大小,位置等
2.创建与主画布相同大小的虚拟图层画布,绘制内容,返回toDataURL()
3.虚拟图层合并渲染到主画布,将图像以此渲染到主画布drawImage()
4.通过鼠标位置,获取虚拟图层像素值,存在像素则进行下一步
5.通过鼠标位置与图层数据源计算,获取目标数据
6.通过鼠标位置+地图div到窗口的顶部(左部)位置,绝对定位绘制提示信息框
7.动画展示信息框

//主函数
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;//点数据源
        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);//初始化动画事件
        interPlay.play();//首次自动播放
        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) === '暂无数据') {
            that.mapOverview = false;
            interPlay.stop();//暂停播放
          } else {
            getEntity(x, y);
            setTimeout(interPlay.play(),3000);//延迟启动播放
          }
        };
      }
//往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;
        });
 }
// 绘制点图层,返回图层图像数据
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();
      }
//通过距离计算,获取点数据
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;//复制点数据
            let map = document.getElementsByClassName('map-container')[0];
            let node = document.getElementsByClassName('map-overview')[0];
            let {t, l} = that.getOffset(map);//计算map div距离浏览器的像素数
            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)': '暂无数据'
        };
        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(',');
        };
      }
//计算div距离浏览器的像素数
getOffset(obj) {
        let t = obj.offsetTop;
        let l = obj.offsetLeft; 
        // 判断是否有父容器,如果存在则累加其边距
        while (obj = obj.offsetParent) {
          t += obj.offsetTop; 
          l += obj.offsetLeft; 
        }
        return { t, l};
      }
//设置动画,轮播信息框
 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};
      }
举报

相关推荐

0 条评论