<template>
  <div class="drag-verify-container">
    <div :style="dragVerifyImgStyle">
      <img ref="checkImg" crossOrigin="anonymous" :src="imgsrc" @load="checkimgLoaded" style="width:100%" alt="">
      <canvas ref="maincanvas" class="main-canvas"></canvas>
      <canvas ref="movecanvas" :class="{goFirst:isOk, goKeep:isKeep}" class="move-canvas"></canvas>
      <div class="refresh" v-if="showRefresh && !isPassing">
        <i :class="refreshIcon" @click="refreshimg"></i>
      </div>
      <div class="tips success" v-if="showTips && isPassing">{{successTip}}</div>
      <div class="tips danger" v-if="showTips && !isPassing && showErrorTip">{{failTip}}</div>
    </div>
    <div ref="dragVerify" class="drag_verify" :style="dragVerifyStyle" @mousemove="dragMoving" @mouseup="dragFinish"
      @mouseleave="dragFinish" @touchmove.prevent="dragMoving" @touchend.prevent="dragFinish">

      <div class="dv_progress_bar" :class="{goFirst2:isOk}" ref="progressBar" :style="progressBarStyle">
        {{successMessage}}
      </div>
      <div class="dv_text" :style="textStyle" ref="message">
        {{message}}
      </div>

      <div class="dv_handler dv_handler_bg" :class="{goFirst:isOk}" @mousedown="dragStart" @touchstart.prevent="dragStart"
        ref="handler" :style="handlerStyle">
        <i :class="handlerIcon"></i>
      </div>
    </div>
  </div>
</template>

<script  lang="ts">
export default {
  name: "dragVerifyImgChip",
  props: {
    isPassing: {
      type: Boolean,
      default: false
    },
    width: {
      type: Number,
      default: 250
    },
    height: {
      type: Number,
      default: 40
    },
    text: {
      type: String,
      default: "swiping to the right side"
    },
    successText: {
      type: String,
      default: "success"
    },
    background: {
      type: String,
      default: "#eee"
    },
    progressBarBg: {
      type: String,
      default: "#76c61d"
    },
    completedBg: {
      type: String,
      default: "#76c61d"
    },
    circle: {
      type: Boolean,
      default: false
    },
    radius: {
      type: String,
      default: "4px"
    },
    handlerIcon: {
      type: String
    },
    successIcon: {
      type: String
    },
    handlerBg: {
      type: String,
      default: "#fff"
    },
    textSize: {
      type: String,
      default: "14px"
    },
    textColor: {
      type: String,
      default: "#333"
    },
    imgsrc: {
      type: String
    },
    barWidth: {
      type: Number,
      default: 40
    },
    barRadius: {
      type: Number,
      default: 8
    },
    showRefresh: {
      type: Boolean,
      default: false
    },
    refreshIcon: {
      type: String
    },
    showTips: {
      type: Boolean,
      default: true
    },
    successTip: {
      type: String,
      default: "验证通过，超过80%用户"
    },
    failTip: {
      type: String,
      default: "验证未通过，拖动滑块将悬浮图像正确合并"
    },
    diffWidth: {
      type: Number,
      default: 20
    }
  },
  mounted: function () {
    const dragEl = this.$refs.dragVerify;
    dragEl.style.setProperty("--textColor", this.textColor);
    dragEl.style.setProperty("--width", Math.floor(this.width / 2) + "px");
    dragEl.style.setProperty("--pwidth", -Math.floor(this.width / 2) + "px");
  },
  computed: {
    handlerStyle: function () {
      return {
        width: this.height + "px",
        height: this.height + "px",
        background: this.handlerBg
      };
    },
    message: function () {
      return this.isPassing ? "" : this.text;
    },
    successMessage: function () {
      return this.isPassing ? this.successText : "";
    },
    dragVerifyStyle: function () {
      return {
        width: this.width + "px",
        height: this.height + "px",
        lineHeight: this.height + "px",
        background: this.background,
        borderRadius: this.circle ? this.height / 2 + "px" : this.radius
      };
    },
    dragVerifyImgStyle: function () {
      return {
        width: this.width + "px",
        position: "relative",
        overflow: "hidden"
      };
    },
    progressBarStyle: function () {
      return {
        background: this.progressBarBg,
        height: this.height + "px",
        borderRadius: this.circle
          ? this.height / 2 + "px 0 0 " + this.height / 2 + "px"
          : this.radius
      };
    },
    textStyle: function () {
      return {
        height: this.height + "px",
        width: this.width + "px",
        fontSize: this.textSize
      };
    }
  },
  data() {
    return {
      isMoving: false,
      x: 0,
      isOk: false,
      isKeep: false,
      clipBarx: 0,
      showErrorTip: false
    };
  },
  methods: {
    draw: function (ctx, x, y, operation) {
      var l = this.barWidth;
      var r = this.barRadius;
      const PI = Math.PI;
      ctx.beginPath();
      ctx.moveTo(x, y);
      ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI);
      ctx.lineTo(x + l, y);
      ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI);
      ctx.lineTo(x + l, y + l);
      ctx.lineTo(x, y + l);
      ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true);
      ctx.lineTo(x, y);
      ctx.lineWidth = 2;
      ctx.fillStyle = "rgba(255, 255, 255, 0.8)";
      ctx.strokeStyle = "rgba(255, 255, 255, 0.8)";
      ctx.stroke();
      ctx[operation]();
      ctx.globalCompositeOperation = "destination-over";
    },
    checkimgLoaded: function () {
      // 生成图片缺失位置
      var barWidth = this.barWidth;
      var imgHeight = this.$refs.checkImg.height;
      var imgWidth = this.$refs.checkImg.width;
      var halfWidth = Math.floor(this.width / 2);
      var refreshHeigth = 25;
      var tipHeight = 20;
      var x = halfWidth + Math.ceil(Math.random() * (halfWidth - barWidth - this.barRadius - 5));
      var y =
        refreshHeigth +
        Math.floor(
          Math.random() * (imgHeight - barWidth - refreshHeigth - tipHeight)
        );
      this.$refs.maincanvas.setAttribute("width", imgWidth);
      this.$refs.maincanvas.setAttribute("height", imgHeight);
      this.$refs.maincanvas.style.display = "block";
      var canvasCtx = this.$refs.maincanvas.getContext("2d");
      this.draw(canvasCtx, x, y, "fill");
      this.clipBarx = x;

      var moveCanvas = this.$refs.movecanvas;
      moveCanvas.setAttribute("width", imgWidth);
      moveCanvas.setAttribute("height", imgHeight);
      this.$refs.movecanvas.style.display = "block";
      const L = barWidth + this.barRadius * 2 + 3; //实际宽度
      var moveCtx = this.$refs.movecanvas.getContext("2d");
      moveCtx.clearRect(0, 0, imgWidth, imgHeight);
      this.draw(moveCtx, x, y, "clip");
      moveCtx.drawImage(this.$refs.checkImg, 0, 0, imgWidth, imgHeight);
      var y = y - this.barRadius * 2 - 1;
      const ImageData = moveCtx.getImageData(x, y, L, L);
      moveCanvas.setAttribute("width", L);
      moveCanvas.setAttribute("height", imgHeight);
      moveCtx.putImageData(ImageData, 0, y);
    },
    dragStart: function (e) {
      if (!this.isPassing) {
        this.isMoving = true;
        this.x =
          (e.pageX || e.touches[0].pageX)
      }
      this.showBar = true;
      this.showErrorTip = false;
      this.$emit("handlerMove");
    },
    dragMoving: function (e) {
      if (this.isMoving && !this.isPassing) {
        var _x = (e.pageX || e.touches[0].pageX) - this.x;
        var handler = this.$refs.handler;
        handler.style.left = _x + "px";
        this.$refs.progressBar.style.width = _x + this.height / 2 + "px";
        this.$refs.movecanvas.style.left = _x + "px";
      }
    },
    dragFinish: function (e) {
      if (this.isMoving && !this.isPassing) {
        var _x = (e.pageX || e.changedTouches[0].pageX) - this.x;
        if (Math.abs(_x - this.clipBarx) > this.diffWidth) {
          this.isOk = true;
          var that = this;
          setTimeout(function () {
            that.$refs.handler.style.left = "0";
            that.$refs.progressBar.style.width = "0";
            that.$refs.movecanvas.style.left = "0";
            that.isOk = false;
          }, 500);
          this.$emit("passfail");
          this.showErrorTip = true;
        } else {
          this.passVerify();
        }
        this.isMoving = false;
      }
    },
    passVerify: function () {
      this.$emit("update:isPassing", true);
      this.isMoving = false;
      var handler = this.$refs.handler;
      handler.children[0].className = this.successIcon;
      this.$refs.progressBar.style.background = this.completedBg;
      this.$refs.message.style["-webkit-text-fill-color"] = "unset";
      this.$refs.message.style.animation = "slidetounlock2 3s infinite";
      this.$refs.progressBar.style.color = "#fff";
      this.$refs.progressBar.style.fontSize = this.textSize;
      this.isKeep = true;
      setTimeout(() => {
        this.$refs.movecanvas.style.left = this.clipBarx + "px";
        setTimeout(() => {
          this.isKeep = false;
          this.$refs.maincanvas.style.display = "none";
          this.$refs.movecanvas.style.display = "none";
        }, 200);
      }, 100);
      this.$emit("passcallback");
    },
    reset: function () {
      this.reImg();
      this.checkimgLoaded();
    },
    reImg: function () {
      this.$emit("update:isPassing", false);
      const oriData = this.$options.data();
      for (const key in oriData) {
        if (Object.prototype.hasOwnProperty.call(oriData, key)) {
          this[key] = oriData[key]
        }
      }
      var handler = this.$refs.handler;
      var message = this.$refs.message;
      handler.style.left = "0";
      this.$refs.progressBar.style.width = "0";
      handler.children[0].className = this.handlerIcon;
      message.style["-webkit-text-fill-color"] = "transparent";
      message.style.animation = "slidetounlock 3s infinite";
      message.style.color = this.background;
      this.$refs.movecanvas.style.left = "0px";
    },
    refreshimg: function () {
      this.$emit("refresh");
    }
  },
  watch: {
    imgsrc: {
      immediate: false,
      handler: function () {
        this.reImg();
      }
    }
  }
};
</script>
<style scoped>
.drag_verify {
  position: relative;
  background-color: #e8e8e8;
  text-align: center;
  overflow: hidden;
}

.drag_verify .dv_handler {
  position: absolute;
  top: 0px;
  left: 0px;
  cursor: move;
}

.drag_verify .dv_handler i {
  color: #666;
  padding-left: 0;
  font-size: 16px;
}

.drag_verify .dv_handler .el-icon-circle-check {
  color: #6c6;
  margin-top: 9px;
}

.drag_verify .dv_progress_bar {
  position: absolute;
  height: 34px;
  width: 0px;
}

.drag_verify .dv_text {
  position: absolute;
  top: 0px;
  color: transparent;
  -moz-user-select: none;
  -webkit-user-select: none;
  user-select: none;
  -o-user-select: none;
  -ms-user-select: none;
  background: -webkit-gradient(linear,
      left top,
      right top,
      color-stop(0, var(--textColor)),
      color-stop(0.4, var(--textColor)),
      color-stop(0.5, #fff),
      color-stop(0.6, var(--textColor)),
      color-stop(1, var(--textColor)));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  -webkit-text-size-adjust: none;
  animation: slidetounlock 3s infinite;
}

.drag_verify .dv_text * {
  -webkit-text-fill-color: var(--textColor);
}

.goFirst {
  left: 0px !important;
  transition: left 0.5s;
}

.goKeep {
  transition: left 0.2s;
}

.goFirst2 {
  width: 0px !important;
  transition: width 0.5s;
}

.drag-verify-container {
  position: relative;
  line-height: 0;
}

.refresh {
  position: absolute;
  right: 5px;
  top: 5px;
  cursor: pointer;
  font-size: 20px;
  z-index: 200;
}

.tips {
  position: absolute;
  bottom: 0;
  height: 20px;
  line-height: 20px;
  text-align: center;
  width: 100%;
  font-size: 12px;
  z-index: 200;
}

.tips.success {
  background: rgba(255, 255, 255, 0.6);
  color: green;
}

.tips.danger {
  background: rgba(0, 0, 0, 0.6);
  color: yellow;
}

.main-canvas {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

.move-canvas {
  position: absolute;
  top: 0;
  left: 0;
}
</style>
<style>
@-webkit-keyframes slidetounlock {
  0% {
    background-position: var(--pwidth) 0;
  }

  100% {
    background-position: var(--width) 0;
  }
}

@-webkit-keyframes slidetounlock2 {
  0% {
    background-position: var(--pwidth) 0;
  }

  100% {
    background-position: var(--pwidth) 0;
  }
}
</style>