<template>
  <view class="vericode">
    <canvas class="canvas" canvas-id="codecanvas" id="codecanvas"> </canvas>
    <canvas class="tcanvas" canvas-id="tcanvas" id="tcanvas"> </canvas>
  </view>
</template>

<script>
export default {
  data() {
    return {
      inDraw: false,
      width: 0,
      height: 0,
      // 每次生成的验证码
      vericode: "",
      // 生成的数字个数
      nums: 4,
      // 混淆线的条数
      drawNums: 1,
      // 混淆线宽度
      lineWidth: 1,
    };
  },
  methods: {
    async drawCode() {
      const self = this;
      if (this.inDraw) {
        return;
      }
      this.inDraw = true;
      const w = this.width;
      const h = this.height;
      let vericode = "";
      const nums = this.nums;
      const xspan = w / (nums + 1);
      const ctx = uni.createCanvasContext("codecanvas", this);
      ctx.clearRect(0, 0, w, h);
      ctx.draw();
      function drawBg() {
        const imageData = Array.from({ length: w * h * 4 });
        for (let i = 0; i < imageData.length; i += 4) {
          imageData[i + 0] = Math.random() * 255;
          imageData[i + 1] = Math.random() * 255;
          imageData[i + 2] = Math.random() * 255;
          imageData[i + 3] = 30;
        }
        uni.canvasPutImageData(
          {
            canvasId: "codecanvas",
            x: 0,
            y: 0,
            width: w,
            data: new Uint8ClampedArray(imageData),
          },
          self
        );
        return new Promise((resolv) => {
          uni.canvasToTempFilePath(
            {
              x: 0,
              y: 0,
              width: w,
              height: h,
              canvasId: "codecanvas",
              success: function (res) {
                ctx.drawImage(res.tempFilePath, 0, 0);
                resolv();
              },
            },
            self
          );
        });
      }

      // 去掉大写 0和o gq和9 1和l 等abcdefhjkmnprstuvwyz
      const source = "23456789";
      const indexArr = Array.prototype.map.call(source, (e, i) => i);
      function getAlpha() {
        const len = indexArr.length - 1 < 0 ? 0 : indexArr.length - 1;
        let i = Math.round(Math.random() * len);
        const ch = source[indexArr[i]];
        indexArr.splice(i, 1);
        return ch;
      }
      const { drawText } = (() => {
        let i = 0;
        let fontbase = Math.round(h * 0.5);
        let fontspan = fontbase / 2;
        let font = Math.round(Math.random() * fontspan) + fontbase;
        const tctx = uni.createCanvasContext("tcanvas", self);
        function drawText() {
          const xpos = (i++ % nums) * xspan;
          font = fontbase + Math.round(fontspan * Math.random());
          const txspan = 2 * xspan;
          tctx.fillStyle = `rgb(${Math.random() * 255},${Math.random() * 255},${
            Math.random() * 255
          })`;
          tctx.setFontSize(font*1.2);
          const ybase = h / 2 + font / 2;
          const xtrans = ((Math.random() - 0.5) * 2) / 5;
          const ytrans = ((Math.random() - 0.5) * 2) / 5;
          tctx.transform(1, xtrans, ytrans, 1, 0, 0);
          const txt = getAlpha();
          tctx.fillText(txt, 0.5 * txspan, ybase);
          tctx.draw();
          vericode += txt;
          return new Promise((resolv) => {
            uni.canvasToTempFilePath(
              {
                x: 0,
                y: 0,
                width: 2 * xspan,
                height: h,
                destWidth: 2 * xspan,
                destHeight: h,
                canvasId: "tcanvas",
                success: function (res) {
                  ctx.drawImage(res.tempFilePath, xpos, 0);
                  tctx.clearRect(0, 0, txspan, h);
                  tctx.draw();
                  resolv();
                },
              },
              self
            );
          });
        }
        return { drawText };
      })();
      function drawLine() {
        const drawnums = self.drawNums;
        for (let i = 0; i < drawnums; i++) {
          ctx.beginPath();
          ctx.lineWidth = self.lineWidth;
          ctx.strokeStyle = `rgba(${Math.random() * 255},${
            Math.random() * 255
          },${Math.random() * 255},0.8)`;
          // 左右非正中区域
          const x1 =
            ((Math.random() > 0.5 ? 1 : -1) * (Math.random() + 1) * w) / 4 +
            w / 2;
          // 上下非正中区域
          const y1 =
            ((Math.random() + 1) * h) / 4 + (Math.random() > 0.5 ? h / 2 : 0);
          const x2 =
            ((Math.random() > 0.5 ? 1 : -1) * (Math.random() + 1) * w) / 4 +
            w / 2;
          const y2 =
            ((Math.random() + 1) * h) / 4 + (Math.random() > 0.5 ? h / 2 : 0);
          ctx.moveTo(x1, y1);
          ctx.lineTo(x2, y2);
          ctx.closePath();
          ctx.stroke();
        }
      }
      await drawBg();
      for (let i = 0; i < nums; i++) {
        await drawText();
      }

      drawLine();
      ctx.draw();
      this.vericode = vericode;
      this.inDraw = false;
    },
  },
  mounted() {
    const self = this;
    const query = uni.createSelectorQuery().in(this);
    query
      .select(".vericode")
      .boundingClientRect((data) => {
        self.width = Math.round(data.width);
        self.height = Math.round(data.height);
        self.drawCode();
      })
      .exec();
  },
};
</script>
<style scoped>
.vericode {
  width: 100%;
  height: 100%;
  position: relative;
  overflow: hidden;
}
.canvas {
  position: absolute;
  left: 0;
  top: 0;
  width: 1000px;
  height: 1000px;
}
.tcanvas {
  position: fixed;
  top: 9999px;
  width: 1000px;
  height: 1000px;
}
</style>
