使用canvas画迁徙线并加上动态效果与小飞机图标

首先在页面中放上地图图片,并建立三个canvas标签,分别用于点、迁徙线、动态效果

   <div class="mapBox">
      <div class="map">
        <img src="@/assets/shanxi.svg" alt="">
      </div>
            <!-- 线 -->
      <canvas id="canvas" class="canvas"></canvas>
      <!---->
      <canvas id="canvasPoint" class="canvas"></canvas>
      <!-- 动态效果 -->
      <canvas id="canvasMove" class="canvas"></canvas>
    </div>

在这里插入图片描述
初始化canvas

初始化时,需要给各个canvas画布一个确定的宽高,否则画布会使用固定的宽300高150,这时如果另外使用的css给canvas画布制定宽高样式,会导致画布被拉伸,里面内容也会跟着被拉伸

  data() {
   
    return {
   
      canvas: null,
      canvasPoint: null,
      canvasMove: null,
      center: {
   }, // 迁徙线起点位置
      directionArr: [], // 迁徙线终点位置
      endKeep: [], // 保存一下各个迁徙线起点
      end: [], // 运动中的各迁徙线时间p时所在位置
      p: 0, // 时间记录,每到1时变为0
      step: 0.005, // 时间每次递增量
      animationSpeed: 0.03, // 点动画效果圆圈每次增加量
      dotNumber: 25, // 动画迁徙线 动态的线的部分由多少个点组成
      rate: 1.053, // 1.033 贝塞尔曲线计算时用到的参数
      requestAnimationFrameName: '',
      compareData: [ // 用于临时计算各终点位置的参数
        {
    x: 0.65, y: 0.89 },
        {
    x: 0.094, y: 0.76 },
        {
    x: 0.95, y: 0.28 },
        {
    x: 0.19, y: 0.19 },
        {
    x: 0.49, y: 0.08 }
      ]
    };
  },
  mounted() {
   
    this.init();
  },
  methods: {
   
    init() {
   
      // 获取需要画布达到的宽高数据
      const mapBox = document.getElementsByClassName('mapBox')[0];
      const width = mapBox.offsetWidth;
      const height = mapBox.offsetHeight;
      // 拿到三个画布,给定宽高
      const canvas = document.getElementById('canvas');
      const canvasPoint = document.getElementById('canvasPoint');
      const canvasMove = document.getElementById('canvasMove');
      canvas.width = width;
      canvas.height = height;
      canvasPoint.width = width;
      canvasPoint.height = height;
      canvasMove.width = width;
      canvasMove.height = height;
      this.canvas = canvas.getContext('2d');
      this.canvasPoint = canvasPoint.getContext('2d');
      this.canvasMove = canvasMove.getContext('2d');
      // 找到所有迁徙线起点,项目中我的起点是太原,所以大概找到一下
      this.center = {
   
        x: Math.ceil(width * 0.52),
        y: Math.ceil(height * 0.48)
      };
      // 各线终点 以下仅为参考,具体以项目要求为准
      for (let i = 0; i<= 4; i++) {
   
        this.directionArr[i] = {
   
          x: Math.ceil(width * compareData[index].x),
          y: Math.ceil(height * compareData[index].y)
        }
        this.endKeep[index] = {
   
          x: this.center.x,
          y: this.center.y
        };
      }
      this.end = JSON.parse(JSON.stringify(this.endKeep));
    },

画布一:固定的迁徙线画布

drawAllLine() {
   
  // 根据每个点分别画线
  this.directionArr.forEach(item => {
   
    this.drawLine(item);
  });
},
drawLine({
    x, y }) {
   
      this.canvas.beginPath();
      this.canvas.moveTo(this.center.x, this.center.y); // 起始点(x,y)
      // 计算贝塞尔曲线控制点位置
      const coord = this.calcCp([x, y], [this.center.x, this.center.y]);
      this.canvas.quadraticCurveTo(coord.x, coord.y, x, y); //创建二次贝塞尔曲线
      // 线宽1
      this.canvas.lineWidth = 1;
      // 线颜色
      this.canvas.strokeStyle = '#5cb85c';
      this.canvas.stroke();
      this.canvas.closePath();
},
/*
 * num: 要被转换的数字
 * exnum: 当前中心坐标 不一定是x还是y
 */
calcCp(start, end) {
   
  let middleX = 0;
  let middleY = 0;
  if (start[0] > end[0] && start[1] > end[1]) {
   
    middleX = ((start[0] + end[0]) / 2) * this.rate;
    middleY = ((start[1] + end[1]) / 2) * (2 - this.rate);
  }
  if (start[0] > end[0] && start[1] < end[1]) {
   
    middleX = ((start[0] + end[0]) / 2) * this.rate;
    middleY = ((start[1] + end[1]) / 2) * this.rate;
  }
  if (start[0] < end[0] && start[1] > end[1]) {
   
    middleX = ((start[0] + end[0]) / 2) * (2 - this.rate);
    middleY = ((start[1] + end[1]) / 2) * (2 - this.rate);
  }
  if (start[0] < end[0] && start[1] < end[1]) {
   
    middleX = ((start[0] + end[0]) / 2) * (2 - this.rate);
    middleY = ((start[1] + end[1]) / 2) * this.rate;
  }
  return {
   
    x: middleX,
    y: middleY
  };
},

在这里插入图片描述

画布二:各终点效果

data中增加关于点的一些参数

      radius: 1, // 航路点半径
      radiusRing: 1,
      radiusRingMin: 1,
      radiusRingMax: 25, // 最大设为25时,涟漪消失的不会很突兀
      dotColor: '243,254,193',
      ringColor: 'rgba(236,210,32,0.5)'

还需要增加控制动画执行的方法

    drawPoint(x1, y1) {
   
      // 最里圈小圆
      this.canvasPoint.fillStyle = `rgba(${
     this.dotColor}, 1)`;
      this.canvasPoint.beginPath();
      this.canvasPoint.arc(x1, y1, this.radius, 0, 2 * Math.PI);
      this.canvasPoint.closePath();
      this.canvasPoint.fill();

      // 外层小圆
      this.canvasPoint.fillStyle = `rgba(${
     this.dotColor}, 0.3)`;
      this.canvasPoint.beginPath();
      this
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值