canvas实现按轨迹运动(我们的回忆)功能

效果图如下:

实现功能:根据后台数据按轨迹点亮心形,点亮字母,并添加点亮日期,两个人的头像跟随轨迹平行移动,

(移动到第几个字母、日期、头像均通过后台获取,测试时需要自定义才能显示出来)

附加功能:移动端播放声音,H5移动端交互方法

直接上代码(后再详细解说)

<!DOCTYPE html>
<html>
 <head>
 <meta charset="UTF-8">

 <title>first line</title>
 <style type="text/css">
 * {margin: 0;padding: 0;}
    html,body{
      width: 100%;
      height: 100%;
      background: #F6F2FF;
      overflow-y: auto;
      cursor: pointer;
      -webkit-tap-highlight-color: rgba(0,0,0,0);
    }
    .canvas {
      display: block;
      width: 100%;
      height: 100%;
      cursor: pointer;
    }
    .canvas canvas {
      position:absolute;
      left:0px;
      top:0px;
      border: none;
      cursor: pointer;
    }
    .voice{
      position: fixed;
      right: 60px;
      top: 100px;
    }
    .audio{
      display: none;
    }
 </style>
 </head>
 <body>
 <div class="canvas">
      <canvas id="cvs" width="600" height="800"></canvas>
      <canvas id="arcXY" width="600" height="800"></canvas>
      <canvas id="arcXY1" width="600" height="800"></canvas>
      <canvas id="arc-little-yellow" width="600" height="800"></canvas>
      <img class="voice" id="myvoice" src="cpMemoryImages/voice@3x.png" width="100" height="100" onclick="play();" />
      <audio class="audio" id="myaudio" controls="controls" loop></audio>
      <iframe id="myframe" allow="autoplay" style="display:none;" src="http://www.baidu.com/"></iframe>
    
 </div>
 <script src="http://wechatfe.github.io/vconsole/lib/vconsole.min.js?v=3.2.0"></script>
 <script src="script/jquery.min.js"></script>
 <script type="text/javascript">
    var vConsole = new VConsole();
    var yourMusicUrl = '';    
    var url = yourMusicUrl;
    var flag = true;
    var isOnload = false;
    var myaudio = document.getElementById('myaudio');
    var myvoice = document.getElementById('myvoice');
    var myframe = document.getElementById('myframe');

    //声音播放
    window.onload = function (e) {
      myaudio.src = url;
      myaudio.oncanplay = function () {
        if(!isOnload) play()
      };
    };

    if(ismobile() == '0') audioAutoPlay()

    function audioAutoPlay() {
      var play = function () {
          myaudio.play();
          document.removeEventListener("touchstart", play, false);
        };
      myaudio.play();
      document.addEventListener("WeixinJSBridgeReady", function () {
        play();
      }, false);
      document.addEventListener('YixinJSBridgeReady', function () {
        play();
      }, false);
      document.addEventListener("touchstart", play, false);
    }

    function play(){
      isOnload = true;
      if(flag){
        myaudio.play();
        flag = false;
        myvoice.src = "cpMemoryImages/voice@3x.png";
      }else{
        myaudio.pause();
        myaudio.load();
        flag = true;
        myvoice.src = "cpMemoryImages/quiet@3x.png";
      }
    }

    /**
   * [isMobile 判断平台]
   * @param test: 0:iPhone    1:Android
   */
    function ismobile() {
      var u = navigator.userAgent, app = navigator.appVersion;
      if (/AppleWebKit.*Mobile/i.test(navigator.userAgent) || (/MIDP|SymbianOS|NOKIA|SAMSUNG|LG|NEC|TCL|Alcatel|BIRD|DBTEL|Dopod|PHILIPS|HAIER|LENOVO|MOT-|Nokia|SonyEricsson|SIE-|Amoi|ZTE/.test(navigator.userAgent))) {
        if (window.location.href.indexOf("?mobile") < 0) {
          try {
            if (/iPhone|mac|iPod|iPad/i.test(navigator.userAgent)) {
              return '0';
            } else {
              return '1';
            }
          } catch (e) { }
        }
      } else if (u.indexOf('iPad') > -1) {
        return '0';
      } else {
        return '1';
      }
    };

    const isIphonex = () => {  // X XS, XS Max, XR
      const xSeriesConfig = [
        {
          devicePixelRatio: 3,
          width: 375,
          height: 812,
        },
        {
          devicePixelRatio: 3,
          width: 414,
          height: 896,
        },
        {
          devicePixelRatio: 2,
          width: 414,
          height: 896,
        },
      ];  // h5
      if (typeof window !== 'undefined' && window) {
        const isIOS = /iphone/gi.test(window.navigator.userAgent);
        if (!isIOS) return false;
        const { devicePixelRatio, screen } = window;
        const { width, height } = screen;
        return xSeriesConfig.some(item => item.devicePixelRatio === devicePixelRatio && item.width === width && item.height === height);
      }
      return false;
    }

    //画图开始
    var canvas = document.querySelector('canvas'),
        context = canvas.getContext('2d');
      
    var startx = 140,     //起始点x轴坐标
        starty = 0,       //起始点y轴坐标
        r = 200,          //弯道半径
        lineHeight = 200, //起始点竖线长度
        lineWidth = 300,  //弯道之间直线距离长度
        y = 0,
        step = 0,
        serverData = {};  //从服务器端获取的数据

        if(isIphonex()){
          lineHeight = 280;
        }

    var w, h, w1, h1;
        w = canvas.width = window.innerWidth;
        h = canvas.height = lineHeight + 14 * r + 800;
    var interVal;

    context.fillStyle = "#F6F2FF";

    context.font = "normal 600 50px 苹方-简";//绘制文字
    context.fillStyle = "#333333";// 设置颜色
    context.textAlign = "center";// 设置水平对齐方式
    context.textBaseline = "middle";// 设置垂直对齐方式
    context.fillText("我们的回忆", 480, lineHeight - 120);// 绘制文字(参数:要写的字,x坐标,y坐标)
 
    //画点亮后的日期
    function lightDate(date, x, y) {
      context.font = "normal 500 40px 苹方-简";
      context.fillStyle = "#898FA3";
      context.textAlign = "center";
      context.textBaseline = "middle";
      context.fillText(date, parseInt(x), parseInt(y));
    }

    //画点亮后的文字
    function lightText(text, x, y){
      context.font = "normal 500 40px 苹方-简";
      context.fillStyle = "#8B63FF";
      context.textAlign = "center";
      context.textBaseline = "middle";
      context.fillText(text, parseInt(x), parseInt(y));
    }

    //加载图片
    var img_mine  = new Image(),
    img_mycp      = new Image(),
    img_tree      = new Image(),
    img_plan      = new Image(),
    img_people1   = new Image(),
    img_people2   = new Image(),
    img_mew       = new Image(),
    img_t         = new Image(),
    img_t_        = new Image(),
    img_h         = new Image(),
    img_h_        = new Image(),
    img_e         = new Image(),
    img_e_        = new Image(),
    img_o         = new Image(),
    img_o_        = new Image(),
    img_n         = new Image(),
    img_n_        = new Image(),
    img_cp        = new Image(),
    img_cp_       = new Image();
    img_gocp      = new Image();
    img_gocp_     = new Image();
    // img_mine.src   = serverData.icon; 
    // img_cp.src = serverData.cpIcon; 
    img_tree.src    = 'cpMemoryImages/tree@3x.png'; 
    img_plan.src    = 'cpMemoryImages/plan@3x.png';
    img_people1.src = 'cpMemoryImages/people1@3x.png';
    img_people2.src = 'cpMemoryImages/people2@3x.png';
    img_mew.src     = 'cpMemoryImages/mew@3x.png';
    img_t.src       = 'cpMemoryImages/t_s@3x.png';
    img_t_.src      = 'cpMemoryImages/t_d@3x.png';
    img_h.src       = 'cpMemoryImages/h_s@3x.png';
    img_h_.src      = 'cpMemoryImages/h_d@3x.png';
    img_e.src       = 'cpMemoryImages/e_s@3x.png';
    img_e_.src      = 'cpMemoryImages/e_d@3x.png';
    img_o.src       = 'cpMemoryImages/o_s@3x.png';
    img_o_.src      = 'cpMemoryImages/o_d@3x.png';
    img_n.src       = 'cpMemoryImages/n_s@3x.png';
    img_n_.src      = 'cpMemoryImages/n_d@3x.png';
    img_cp.src      = 'cpMemoryImages/cp_s@3x.png';
    img_cp_.src     = 'cpMemoryImages/cp_d@3x.png';
    img_gocp.src    = 'cpMemoryImages/Rectangle@3x.png';
    img_gocp_.src   = 'cpMemoryImages/Rectangle_@3x.png';

    //图片加载完后,将其显示在canvas中
    img_gocp.onload = function () {

      context.drawImage(img_plan, 400, lineHeight - 50);// context.drawImage(this, 0, 0, 1080, 980)改变图片大小到1080*980

      context.drawImage(img_tree, 800, lineHeight - 50);
      context.drawImage(img_tree, 30, lineHeight + 150);
      context.drawImage(img_tree, 800, lineHeight + 1600);
      context.drawImage(img_tree, 30, lineHeight + 2750);
      context.drawImage(img_mew, 750, lineHeight + 900);
      context.drawImage(img_people1, 850, lineHeight + 550);
      context.drawImage(img_people2, 30, lineHeight + 1800);

      context.font = "normal 600 50px 苹方 粗体";
      context.fillStyle = "#333333";
      context.textAlign = "center";
      context.textBaseline = "middle";
      context.fillText("那么,一起走吧?", 495, lineHeight + 3130);

      context.drawImage(img_gocp, 30, lineHeight + 3200);
      context.font = "normal 400 50px 苹方-港";
      context.fillStyle = "#640000";
      context.textAlign = "center";
      context.textBaseline = "middle";
      context.fillText("进入CP空间", 475, lineHeight + 3270);

      context.drawImage(img_t_, 480, lineHeight + 250, 1.5 * r, 1.8 * r);
      context.drawImage(img_h_, 190, lineHeight + 650, 1.5 * r, 1.8 * r);
      context.drawImage(img_e_, 480, lineHeight + 1050, 1.5 * r, 1.8 * r);
      context.drawImage(img_o_, 190, lineHeight + 1450, 1.5 * r, 1.8 * r);
      context.drawImage(img_n_, 480, lineHeight + 1850, 1.5 * r, 1.8 * r);
      context.drawImage(img_e_, 190, lineHeight + 2250, 1.5 * r, 1.8 * r);
      context.drawImage(img_cp_, 480, lineHeight + 2650, 1.5 * r, 1.8 * r);
    }

    function mousePosition(e) {
      if (e.pageX && e.pageY) {
        return {
          x: e.pageX,
          y: e.pageY
        };
      }
      var scrollElem = (document.compatMode && document.compatMode != "BackCompat") ? document.documentElement : document.body;
      return {
        x: e.clientX + scrollElem.scrollLeft,
        y: e.clientY + scrollElem.scrollTop
      };
    }

    onclick = ()=>{
      var allowX = mousePosition(event).x,
          allowY = mousePosition(event).y;
      if(allowX > 60 && allowX < 950 && allowY > (lineHeight + 3200) && allowY < (lineHeight + 3350)) goCp();
    }

    document.body.addEventListener('touchstart', function () {
      var allowX = mousePosition(event).x,
          allowY = mousePosition(event).y;
      if (allowX > 60 && allowX < 950 && allowY > (lineHeight + 3200) && allowY < (lineHeight + 3350)) goCp();
    });

    //画路径尽头的黄色圆圈(弧线)arc-little-yellow
    function movePhotoArcLittleYellow(x0, y0, r, a0) {

      var sins = Math.sin(2 * Math.PI / 360 * a0);
      var coss = Math.cos(2 * Math.PI / 360 * a0);

      var centerX = coss * r + x0;//圆弧中间点坐标x
      var centerY = sins * r + y0;//圆弧中间点坐标y

      var cas = document.getElementById('arc-little-yellow');
      var ctx = cas.getContext('2d');
      cas.width = window.innerWidth;
      cas.height = lineHeight + 14 * r + 800;
      ctx.fillStyle = "#000000";
      //ctx.fillRect(x0, y0, 100, 100);
      ctx.arc(centerX, centerY, 30, 0, Math.PI * 2, false);
    }

    //画路径尽头的黄色圆圈(弧线)
    function movePhotoLineLittleYellow(x0, y0) {

      var cas = document.getElementById('arc-little-yellow');
      var ctx = cas.getContext('2d');
      cas.width = window.innerWidth;
      cas.height = lineHeight + 14 * r + 800;
      ctx.fillStyle = "#000000";
      //ctx.fillRect(x0, y0, 100, 100);
      context.arc(x0, y0, 30, 0, Math.PI * 2, false);

    }
    
    //已知圆心,半径,角度,求圆上的点坐标,并画出移动头像
    var arrXY = [], arrXY1 = [];
    function movePhotoArc(x0, y0, r, a0) {

      var sins = Math.sin(2 * Math.PI / 360 * a0);
      var coss = Math.cos(2 * Math.PI / 360 * a0);

      var centerX = coss * r + x0;//圆弧中间点坐标x
      var centerY = sins * r + y0;//圆弧中间点坐标y
      var cas = document.getElementById('arcXY');
      var ctx = cas.getContext('2d');

      cas.width = window.innerWidth;
      cas.height = lineHeight + 14 * r + 800;
      ctx.fillStyle = "rgba(0,0,0,0)";
      if (arrXY.length != 0) {
        ctx.clearRect(arrXY[0], arrXY[1], 100, 100);
      }
      ctx.fillRect(centerX, centerY, 100, 100);

      // ctx.clearRect(0, 0, width, height);
      //开始路径画圆,剪切处理
      //ctx.save();

      ctx.beginPath();
      ctx.arc(centerX + 30, centerY + 30, 30, 0, Math.PI * 2, false);
      ctx.clip(); //剪切路径
      ctx.drawImage(img_mine, centerX, centerY, 60, 60);

      arrXY = [centerX, centerY];
      
      if (centerY >= window.innerHeight / 2) {
        scrollTo(300, centerY - window.innerHeight / 2);
      }

    }

    function movePhotoArc1(x0, y0, r, a0) {

        var sins = Math.sin(2 * Math.PI / 360 * a0);
        var coss = Math.cos(2 * Math.PI / 360 * a0);

        var centerX = coss * r + x0;//圆弧中间点坐标x
        var centerY = sins * r + y0;//圆弧中间点坐标y
        var cas1 = document.getElementById('arcXY1');
        var ctx1 = cas1.getContext('2d');

        cas1.width = window.innerWidth;
        cas1.height = lineHeight + 14 * r + 800
        ;
        ctx1.fillStyle = "rgba(0,0,0,0)";
        if (arrXY1.length != 0) {
          ctx1.clearRect(arrXY1[0] + 60, arrXY1[1], 100, 100);
        }
        ctx1.fillRect(centerX + 60, centerY, 100, 100);
        ctx1.beginPath();
        ctx1.arc(centerX + 90, centerY + 30, 30, 0, Math.PI * 2, false);
        ctx1.clip(); //剪切路径
        ctx1.drawImage(img_mycp, centerX + 60, centerY, 60, 60);
        arrXY1 = [centerX + 60, centerY];

      }

    //画头像1运动轨迹
    function movePhotoLine(x0, y0){

      var cas = document.getElementById('arcXY');
      var ctx = cas.getContext('2d');
      cas.width = window.innerWidth;
      cas.height = lineHeight + 14 * r + 800;
      ctx.fillStyle = "rgba(0,0,0,0)";
      if (arrXY.length != 0) {
        ctx.clearRect(arrXY[0], arrXY[1], 100, 100);
      }
      ctx.fillRect(x0, y0, 100, 100);

      ctx.arc(x0+30, y0+30, 30, 0, Math.PI * 2, false);
      ctx.clip(); //剪切路径
      ctx.drawImage(img_mine, x0, y0, 60, 60);

      arrXY = [x0, y0];

      if (y0 >= window.innerHeight / 2) {
        scrollTo(300, y0 - window.innerHeight / 2);
      }
    }

    //画头像2运动轨迹
    function movePhotoLine1(x0, y0) {

      var cas1 = document.getElementById('arcXY1');
      var ctx1 = cas1.getContext('2d');
      cas1.width = window.innerWidth;
      cas1.height = lineHeight + 14 * r + 800;
      ctx1.fillStyle = "rgba(0,0,0,0)";
      if (arrXY1.length != 0) {
        ctx1.clearRect(arrXY1[0] + 60, arrXY1[1], 100, 100);
      }
      ctx1.fillRect(x0 + 60, y0, 100, 100);

      ctx1.arc(x0 + 90, y0 + 30, 30, 0, Math.PI * 2, false);
      ctx1.clip(); //剪切路径
      ctx1.drawImage(img_mycp, x0 + 60, y0, 60, 60);
      arrXY1 = [x0 + 60, y0];

    }

    //日期格式化
    function timestampToTime(timestamp) {
      var date = new Date(timestamp);//时间戳为10位需*1000,时间戳为13位的话不需乘1000
      Y = date.getFullYear();
      M = (date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1);
      D = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
      return Y + '年' + M + '月' + D + '日';
    }

    //画白线
    function drawWhiteLine() {

        // img_t_.onload = function () {
        //   context.drawImage(img_t_, 480, lineHeight + 250, 1.5 * r, 1.8 * r);
        //   context.drawImage(img_h_, 190, lineHeight + 650, 1.5 * r, 1.8 * r);
        //   context.drawImage(img_e_, 480, lineHeight + 1050, 1.5 * r, 1.8 * r);
        //   context.drawImage(img_o_, 190, lineHeight + 1450, 1.5 * r, 1.8 * r);
        //   context.drawImage(img_n_, 480, lineHeight + 1850, 1.5 * r, 1.8 * r);
        //   context.drawImage(img_e_, 190, lineHeight + 2250, 1.5 * r, 1.8 * r);
        //   context.drawImage(img_cp_, 480, lineHeight + 2650, 1.5 * r, 1.8 * r);
        // }

        context.beginPath();
        context.moveTo(startx, starty);
        context.lineTo(startx, lineHeight);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.arc(startx + r, lineHeight, r, Math.PI * 1, Math.PI * 1 - (Math.PI * 0.5), true);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.moveTo(startx + r, lineHeight + r);
        context.lineTo(startx + r + lineWidth, lineHeight + r);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.arc(startx + r + lineWidth, lineHeight + 2 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1), false);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.moveTo(startx + r + lineWidth, lineHeight + 3 * r);
        context.lineTo(startx + r, lineHeight + 3 * r);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.arc(startx + r, lineHeight + 4 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1), true);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.moveTo(startx + r, lineHeight + 5 * r);
        context.lineTo(startx + r + lineWidth, lineHeight + 5 * r);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.arc(startx + r + lineWidth, lineHeight + 6 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1), false);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.moveTo(startx + r + lineWidth, lineHeight + 7 * r);
        context.lineTo(startx + r, lineHeight + 7 * r);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.arc(startx + r, lineHeight + 8 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1), true);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.moveTo(startx + r, lineHeight + 9 * r);
        context.lineTo(startx + r + lineWidth, lineHeight + 9 * r);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.arc(startx + r + lineWidth, lineHeight + 10 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1), false);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.moveTo(startx + r + lineWidth, lineHeight + 11 * r);
        context.lineTo(startx + r, lineHeight + 11 * r);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.arc(startx + r, lineHeight + 12 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1), true);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.moveTo(startx + r, lineHeight + 13 * r);
        context.lineTo(startx + r + lineWidth, lineHeight + 13 * r);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.arc(startx + r + lineWidth, lineHeight + 14 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1), false);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();

        context.beginPath();
        context.moveTo(startx + r + lineWidth, lineHeight + 15 * r);
        context.lineTo(0, lineHeight + 15 * r);
        context.strokeStyle = "#FFFFFF";
        context.lineWidth = 60;
        context.stroke();
        context.closePath();
    }

    //画灰线
    function drawStep() {
      interVal = window.requestAnimationFrame(drawStep, canvas);
       if (lineHeight >= y && y >= 0) {//起始竖线
          movePhotoLineLittleYellow(startx, y += 10);
          movePhotoLine(startx, y += 10);
          movePhotoLine1(startx, y += 10);
          context.beginPath();
          context.moveTo(startx, starty);
          context.lineTo(startx, y += 10);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashLine(startx, starty, startx, y += 10);

       }else if((lineHeight + 100) >= y && y > lineHeight){//第一道直角弯

          y += 5;
          movePhotoArcLittleYellow(startx + r, lineHeight, r, (1 - 0.5 * ((y - lineHeight) / 100)) * 180);
          movePhotoArc(startx + r, lineHeight, r, (1 - 0.5 * ((y - lineHeight) / 100)) * 180)
          movePhotoArc1(startx + r, lineHeight, r, (1 - 0.5 * ((y - lineHeight) / 100)) * 180)
          context.beginPath();
          context.arc(startx + r, lineHeight, r, Math.PI * 1, Math.PI * 1 - (Math.PI * 0.5)  *  ((y - lineHeight) / 100) , true);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashArc(startx + r, lineHeight, r, Math.PI * 1, Math.PI * 1 - (Math.PI * 0.5) * ((y - lineHeight) / 100), true);

       } else if((lineHeight + 400) >= y && y > (lineHeight + 100)){//第一条从左到右直线

          y += 10;
          movePhotoLine(startx + r + (y - (lineHeight + 100)), lineHeight + r);
          movePhotoLine1(startx + r + (y - (lineHeight + 100)), lineHeight + r);
          context.beginPath();
          context.moveTo(startx + r, lineHeight + r);
          context.lineTo(startx + r + (y - (lineHeight + 100)), lineHeight + r);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashLine(startx + r, lineHeight + r, startx + r + (y - (lineHeight + 100)), lineHeight + r);

       } else if ((lineHeight + 500) >= y && y > (lineHeight + 400)) {//第一道顺时针半圆弯

          y += 2.5;
          movePhotoArc(startx + r + lineWidth, lineHeight + 2 * r, r, (1.5 + (y - (lineHeight + 400)) / 100) * 180);
          movePhotoArc1(startx + r + lineWidth, lineHeight + 2 * r, r, (1.5 + (y - (lineHeight + 400)) / 100) * 180);
          context.beginPath();
          context.arc(startx + r + lineWidth, lineHeight + 2 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 400)) / 100), false);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashArc(startx + r + lineWidth, lineHeight + 2 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 400)) / 100), false);

       } else if ((lineHeight + 800) >= y && y > (lineHeight + 500)) {//第一条从右到左直线

          y += 10;
          movePhotoLine(startx + r + lineWidth - (y - (lineHeight + 500)), lineHeight + 3 * r);
          movePhotoLine1(startx + r + lineWidth - (y - (lineHeight + 500)), lineHeight + 3 * r);
          context.beginPath();
          context.moveTo(startx + r + lineWidth, lineHeight + 3 * r);
          context.lineTo(startx + r + lineWidth - (y - (lineHeight + 500)), lineHeight + 3 * r);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashLine(startx + r + lineWidth, lineHeight + 3 * r, startx + r + lineWidth - (y - (lineHeight + 500)), lineHeight + 3 * r);

          if (y >= (lineHeight + 510)) {
            if (y == (lineHeight + 512.5)) {
              lightDate(timestampToTime(serverData.memory["1"].timestamp), 320, 600);
              lightText(serverData.memory["1"].content, 320, 650);
              if (step == 1) y = 99999;
            }
            context.drawImage(img_t, 480, lineHeight + 250, 1.5 * r, 1.8 * r);//点亮T
          }

       } else if ((lineHeight + 900) >= y && y > (lineHeight + 800)) {//第一道逆时针半圆弯

          y += 2.5;
          movePhotoArc(startx + r, lineHeight + 4 * r, r, (1.5 - (y - (lineHeight + 800)) / 100) * 180);
          movePhotoArc1(startx + r, lineHeight + 4 * r, r, (1.5 - (y - (lineHeight + 800)) / 100) * 180);
          context.beginPath();
          context.arc(startx + r, lineHeight + 4 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1) * ((y - (lineHeight + 800)) / 100), true);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashArc(startx + r, lineHeight + 4 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1) * ((y - (lineHeight + 800)) / 100), true);

       } else if ((lineHeight + 1200) >= y && y > (lineHeight + 900)) {//第二道从左到右直线

          y += 10;
          movePhotoLine(startx + r + (y - (lineHeight + 900)), lineHeight + 5 * r);
          movePhotoLine1(startx + r + (y - (lineHeight + 900)), lineHeight + 5 * r);
          context.beginPath();
          context.moveTo(startx + r, lineHeight + 5 * r);
          context.lineTo(startx + r + (y - (lineHeight + 900)), lineHeight + 5 * r);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashLine(startx + r, lineHeight + 5 * r, startx + r + (y - (lineHeight + 900)), lineHeight + 5 * r);

          if (y >= (lineHeight + 910)) {
            if (y == (lineHeight + 912.5)) {
              lightDate(timestampToTime(serverData.memory["2"].timestamp), 650, 1000);
              lightText(serverData.memory["2"].content, 650, 1050);
              if (step == 2) y = 99999;
            }
            context.drawImage(img_h, 190, lineHeight + 650, 1.5 * r, 1.8 * r);//点亮H
          }

       } else if ((lineHeight + 1300) >= y && y > (lineHeight + 1200)) {//第二道顺时针半圆弯

          y += 2.5;
          movePhotoArc(startx + r + lineWidth, lineHeight + 6 * r, r, (1.5 + (y - (lineHeight + 1200)) / 100) * 180);
          movePhotoArc1(startx + r + lineWidth, lineHeight + 6 * r, r, (1.5 + (y - (lineHeight + 1200)) / 100) * 180);
          context.beginPath();
          context.arc(startx + r + lineWidth, lineHeight + 6 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 1200)) / 100), false);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashArc(startx + r + lineWidth, lineHeight + 6 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 1200)) / 100), false);

       }  else if ((lineHeight + 1600) >= y && y > (lineHeight + 1300)) {//第二条从右到左直线

          y += 10;
          movePhotoLine(startx + r + lineWidth - (y - (lineHeight + 1300)), lineHeight + 7 * r);
          movePhotoLine1(startx + r + lineWidth - (y - (lineHeight + 1300)), lineHeight + 7 * r);
          context.beginPath();
          context.moveTo(startx + r + lineWidth, lineHeight + 7 * r);
          context.lineTo(startx + r + lineWidth - (y - (lineHeight + 1300)), lineHeight + 7 * r);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashLine(startx + r + lineWidth, lineHeight + 7 * r, startx + r + lineWidth - (y - (lineHeight + 1300)), lineHeight + 7 * r);

          if (y >= (lineHeight + 1310)) {
            if (y == (lineHeight + 1312.5)) {
              lightDate(timestampToTime(serverData.memory["3"].timestamp), 320, 1400);
              lightText(serverData.memory["3"].content, 320, 1450);
              if (step == 3) y = 99999;
            }
            context.drawImage(img_e, 480, lineHeight + 1050, 1.5 * r, 1.8 * r);//点亮E
          }

       } else if ((lineHeight + 1700) >= y && y > (lineHeight + 1600)) {//第二道逆时针弯

          y += 2.5;
          movePhotoArc(startx + r, lineHeight + 8 * r, r, (1.5 - (y - (lineHeight + 1600)) / 100) * 180);
          movePhotoArc1(startx + r, lineHeight + 8 * r, r, (1.5 - (y - (lineHeight + 1600)) / 100) * 180);
          context.beginPath();
          context.arc(startx + r, lineHeight + 8 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1) * ((y - (lineHeight + 1600)) / 100), true);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashArc(startx + r, lineHeight + 8 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1) * ((y - (lineHeight + 1600)) / 100), true);

       } else if ((lineHeight + 2000) >= y && y > (lineHeight + 1700)) {//第三条从左到右直线

          y += 10;
          movePhotoLine(startx + r + (y - (lineHeight + 1700)), lineHeight + 9 * r);
          movePhotoLine1(startx + r + (y - (lineHeight + 1700)), lineHeight + 9 * r);
          context.beginPath();
          context.moveTo(startx + r, lineHeight + 9 * r);
          context.lineTo(startx + r + (y - (lineHeight + 1700)), lineHeight + 9 * r);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashLine(startx + r, lineHeight + 9 * r, startx + r + (y - (lineHeight + 1700)), lineHeight + 9 * r);

          if (y >= (lineHeight + 1710)) {
            if (y == (lineHeight + 1712.5)) {
              lightDate(timestampToTime(serverData.memory["4"].timestamp), 650, 1800);
              lightText(serverData.memory["4"].content, 650, 1850);
              if (step == 4) y = 99999;
            }
            context.drawImage(img_o, 190, lineHeight + 1450, 1.5 * r, 1.8 * r);//点亮O
          }

       } else if ((lineHeight + 2100) >= y && y > (lineHeight + 2000)) {//第三道顺时针弯

          y += 2.5;
          movePhotoArc(startx + r + lineWidth, lineHeight + 10 * r, r, (1.5 + (y - (lineHeight + 2000)) / 100) * 180);
          movePhotoArc1(startx + r + lineWidth, lineHeight + 10 * r, r, (1.5 + (y - (lineHeight + 2000)) / 100) * 180);
          context.beginPath();
          context.arc(startx + r + lineWidth, lineHeight + 10 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 2000)) / 100), false);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashArc(startx + r + lineWidth, lineHeight + 10 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 2000)) / 100), false);

       } else if ((lineHeight + 2400) >= y && y > (lineHeight + 2100)) {//第三条从右到左直线

          y += 10;
          movePhotoLine(startx + r + lineWidth - (y - (lineHeight + 2100)), lineHeight + 11 * r);
          movePhotoLine1(startx + r + lineWidth - (y - (lineHeight + 2100)), lineHeight + 11 * r);
          context.beginPath();
          context.moveTo(startx + r + lineWidth, lineHeight + 11 * r);
          context.lineTo(startx + r + lineWidth - (y - (lineHeight + 2100)), lineHeight + 11 * r);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashLine(startx + r + lineWidth, lineHeight + 11 * r, startx + r + lineWidth - (y - (lineHeight + 2100)), lineHeight + 11 * r);

          if (y >= (lineHeight + 2110)) {
            if(y == (lineHeight + 2112.5)){
              lightDate(timestampToTime(serverData.memory["5"].timestamp), 320, 2200);
              lightText(serverData.memory["5"].content, 320, 2250);
              if (step == 5) y = 99999;
            }
            context.drawImage(img_n, 480, lineHeight + 1850, 1.5 * r, 1.8 * r);//点亮N
          }

       } else if ((lineHeight + 2500) >= y && y > (lineHeight + 2400)) {//第三道逆时针弯

          y += 2.5;
          movePhotoArc(startx + r, lineHeight + 12 * r, r, (1.5 - (y - (lineHeight + 2400)) / 100) * 180);
          movePhotoArc1(startx + r, lineHeight + 12 * r, r, (1.5 - (y - (lineHeight + 2400)) / 100) * 180);
          context.beginPath();
          context.arc(startx + r, lineHeight + 12 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1) * ((y - (lineHeight + 2400)) / 100), true);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashArc(startx + r, lineHeight + 12 * r, r, Math.PI * 1.5, Math.PI * 1.5 - (Math.PI * 1) * ((y - (lineHeight + 2400)) / 100), true);

       } else if ((lineHeight + 2800) >= y && y > (lineHeight + 2500)) {//第四条从左到右直线

          y += 10;
          movePhotoLine(startx + r + (y - (lineHeight + 2500)), lineHeight + 13 * r);
          movePhotoLine1(startx + r + (y - (lineHeight + 2500)), lineHeight + 13 * r);
          context.beginPath();
          context.moveTo(startx + r, lineHeight + 13 * r);
          context.lineTo(startx + r + (y - (lineHeight + 2500)), lineHeight + 13 * r);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashLine(startx + r, lineHeight + 13 * r, startx + r + (y - (lineHeight + 2500)), lineHeight + 13 * r);

          if (y >= (lineHeight + 2510)) {
            if(y == (lineHeight + 2512.5)){
              lightDate(timestampToTime(serverData.memory["6"].timestamp), 650, 2600);
              lightText(serverData.memory["6"].content, 650, 2650);
              if (step == 6) y = 99999;
            }
            context.drawImage(img_e, 190, lineHeight + 2250, 1.5 * r, 1.8 * r);//点亮E
          }

       } else if ((lineHeight + 2900) >= y && y > (lineHeight + 2800)) {//第四道顺时针弯

          y += 2.5;
          movePhotoArc(startx + r + lineWidth, lineHeight + 14 * r, r, (1.5 + (y - (lineHeight + 2800)) / 100) * 180);
          movePhotoArc1(startx + r + lineWidth, lineHeight + 14 * r, r, (1.5 + (y - (lineHeight + 2800)) / 100) * 180);
          context.beginPath();
          context.arc(startx + r + lineWidth, lineHeight + 14 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 2800)) / 100), false);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashArc(startx + r + lineWidth, lineHeight + 14 * r, r, Math.PI * 1.5, Math.PI * 1.5 + (Math.PI * 1) * ((y - (lineHeight + 2800)) / 100), false);

       } else if ((lineHeight + 2950) >= y && y > (lineHeight + 2900)) {//第四条从左到右直线

          y += 10;
          movePhotoLine(startx + r + lineWidth - (y - (lineHeight + 2900)), lineHeight + 15 * r);
          movePhotoLine1(startx + r + lineWidth - (y - (lineHeight + 2900)), lineHeight + 15 * r);
          context.beginPath();
          context.moveTo(startx + r + lineWidth, lineHeight + 15 * r);
          context.lineTo(startx + r + lineWidth - (y - (lineHeight + 2900)), lineHeight + 15 * r);
          context.strokeStyle = "#898FA3";
          context.lineWidth = 60;
          context.stroke();
          context.closePath();

          drawDashLine(startx + r + lineWidth, lineHeight + 15 * r, startx + r + lineWidth - (y - (lineHeight + 2900)), lineHeight + 15 * r);

          if (y >= (lineHeight + 2910)) {
            if(y == (lineHeight + 2912.5)){
              lightDate(timestampToTime(serverData.memory["7"].timestamp), 320, 3000);
              lightText("成为专属CP", 320, 3050); 

              context.drawImage(img_gocp_, 30, lineHeight + 3200);
              context.font = "normal 400 50px 苹方-港";
              context.fillStyle = "#640000";
              context.textAlign = "center";
              context.textBaseline = "middle";
              context.fillText("进入CP空间", 475, lineHeight + 3270);

              if (step == 7) y = 99999;
            }
            context.drawImage(img_cp, 480, lineHeight + 2650, 1.5 * r, 1.8 * r);//点亮cp
          }

       }else{

          window.cancelAnimationFrame(interVal);

       }
    }

    //画虚线圆弧
    /**
    * @param x0: 起始点x轴坐标
    * @param y0: 起始点y轴坐标
    * @param r: 半径
    * @param angleStart: 起始角
    * @param angleEnd: 结束角
    * @param anticlockwise: 是否逆时针
    **/
    function drawDashArc(x0, y0, r, angleStart, angleEnd, anticlockwise) {
      context.setLineDash([20, 20]);
      context.lineWidth = 6;
      context.strokeStyle = '#FFFFFF';
      context.beginPath();
      context.arc(x0, y0, r, angleStart, angleEnd, anticlockwise);
      context.stroke();
      context.setLineDash([]); 
    }

    //画虚线
    /**
    * @param x0: 起始点x轴坐标
    * @param y0: 起始点y轴坐标
    * @param x1: 结束点x轴坐标
    * @param y1: 结束点y轴坐标
    * @param lineWidth: 线的宽度
    * @param strokeStyle: 线的颜色
    * @param dashArray: 虚线的样式数组
    **/
    function drawDashLine(x0, y0, x1, y1) {
      context.setLineDash([20, 20]);
      context.lineWidth = 6;
      context.strokeStyle = '#FFFFFF';
      context.beginPath();
      context.moveTo(x0, y0);
      context.lineTo(x1, y1);
      context.stroke();
      context.setLineDash([]);
    }

    //移动端对接
    function setupWebViewJavascriptBridge(callback) {
      var ua = navigator.userAgent,
      android = ua.indexOf('Android') > -1 ? true : false,
      ipad = ua.indexOf('iPad') > -1 ? true : false,
      ipod = ua.indexOf('iPod') > -1 ? true : false,
      iphone = !ipad && ua.indexOf('iPhone') > -1 ? true : false;
      //android使用
      if(android){
        if (window.WebViewJavascriptBridge) {
          callback(window.WebViewJavascriptBridge)
        } else {
          document.addEventListener(
            'WebViewJavascriptBridgeReady'
            , function () {
              callback(window.WebViewJavascriptBridge)
            },
            false
          );
        }
      }else if(ipad || ipod || iphone){
        //ios使用
        if (window.WebViewJavascriptBridge) {
          return callback(WebViewJavascriptBridge);
        }
        if (window.WVJBCallbacks) {
          return window.WVJBCallbacks.push(callback);
        }
        window.WVJBCallbacks = [callback];
        var WVJBIframe = document.createElement('iframe');
        WVJBIframe.style.display = 'none';
        WVJBIframe.src = 'wvjbscheme://__BRIDGE_LOADED__';
        document.documentElement.appendChild(WVJBIframe);
        setTimeout(function () {
          document.documentElement.removeChild(WVJBIframe)
        }, 0)
      }else{}
    }
    
    //移动端交互
    let appData = {};
    var ua = navigator.userAgent,
        android = ua.indexOf('Android') > -1 ? true : false,
        ipad = ua.indexOf('iPad') > -1 ? true : false,
        ipod = ua.indexOf('iPod') > -1 ? true : false,
        iphone = !ipad && ua.indexOf('iPhone') > -1 ? true : false,
        language = (navigator.browserLanguage || navigator.language).toLowerCase();
    function getAppData() {
      if (ipad || ipod || iphone) {
        setupWebViewJavascriptBridge(function (bridge) {
          bridge.callHandler('getToken', function (responseData) {
            getUserInfo(responseData.token, responseData.i);
          });
        })
      }else if(android){
        setupWebViewJavascriptBridge(function (bridge) {
          bridge.callHandler('getToken', '', function (responseData) {
            getUserInfo(JSON.parse(responseData).token, JSON.parse(responseData).i);
          });
        })
      }else{}
    }

    function goCp() {
      if (ipad || ipod || iphone) {
        setupWebViewJavascriptBridge(function (bridge) {
          bridge.callHandler('jumpToCpSpace');
        })
      }else if(android){
        setupWebViewJavascriptBridge(function (bridge) {
          bridge.callHandler('jumpToCpSpace');
        })
      }else{}
    }

    let yourUrl = '';
    //ajax调后台数据
    function getUserInfo(token, i){
      $.ajax({
        url: yourUrl
        type: 'POST',
        data: { i: i },
        dataType: 'json',
        success: function (res) {
          serverData = res.data;
          let sp;
          for(var key in serverData.memory){
            sp = parseInt(key);
          }
          step = sp;//运动到第几个字母
          img_mine.src = serverData.icon;//头像1
          img_mycp.src = serverData.cpIcon;//头像2
          drawWhiteLine();//画线
          context.moveTo(startx, starty);//切换起始点
          drawStep();//画路径
        },
        beforeSend: function (XMLHttpRequest) {
          XMLHttpRequest.setRequestHeader('token', token);
          XMLHttpRequest.setRequestHeader('source', 'h5');
          XMLHttpRequest.setRequestHeader('lang', 'CHS');
        },
        error: function (err) {
          console.log("err", JSON.stringify(err))
        }
      });
    }
    
    //按需运行方法
    //getAppData();//正式方法
    step = 7;                      //测试方法 自定义运行到第几个字母
    drawWhiteLine();               //测试方法
    context.moveTo(startx, starty);//测试方法
    drawStep();                    //测试方法
    //todo:自定义头像、自定义每个子母被点亮时的日期
 </script>
 </body>
</html>

(此文原创,转载请注明出处)

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

厉害坤坤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值