首页 前端知识 用户横屏签名并生成旋转后的签名图片 vue_h5

用户横屏签名并生成旋转后的签名图片 vue_h5

2024-02-09 20:02:24 前端知识 前端哥 665 957 我要收藏
<!DOCTYPE html>
<html lang="zh-CN">

<head>
  <title>test</title>
  <meta charset="utf-8" />
  <meta http-equiv="pragram" content="no-cache">
  <meta http-equiv="cache-control" content="no-cache, no-store, must-revalidate">
  <meta http-equiv="expires" content="0">
  <meta name="viewport" content="width=device-width, user-scalable=no" />
  <script src="https://unpkg.com/vue@2.6/dist/vue.min.js"></script>
  <script src="https://unpkg.com/vant@2.12/lib/vant.min.js"></script>
  <style>
    .signature,
    #sign,
    .signature button {
      box-sizing: border-box;
    }

    #sign {
      position: relative;
    }

    .signBtn {
      flex-shrink: 0;
      height: 70px;
      display: flex;
      align-items: center;
      justify-content: space-around;
    }

    #sign canvas {
      width: 100%;
      height: 100%;
    }

    .copyCanvas {
      display: none;
    }

    .address {
      margin: 1rem;
      padding-bottom: 1rem;
      margin-bottom: 0rem;
      display: flex;
      align-items: center;
      justify-content: space-between;
    }

    .qianming img {
      width: 1rem;
      float: right;
      margin-top: 4px;
    }

    .qianming button {
      width: 1rem;
      float: right;
      display: flex;
      justify-content: flex-end;
    }

    .qianming {
      align-items: flex-start;
    }

    .signature {
      background-color: #fff;
      /* width: calc(100% - 2rem);
  height: calc(100% - 2rem);
  margin: 1rem; */
      height: 100%;
      width: calc(100vw - 2rem);
      display: flex;
      flex-direction: column;
      justify-content: space-between;
    }

    .signature>div:first-child {
      height: calc(100% - 70px - (0.6*16*2px));
      border: 1px dashed #c1c1c1;
      margin: 0.6rem;
    }

    .signature button {
      color: #404040;
      font-size: 1.2rem;
      width: initial;
      transform: rotate(90deg);
      text-align: center;
      width: 100%;
      height: 100%;
      border: none;
      outline: none;
      background-color: transparent;
      padding: 0;
    }

    .mask {
      position: absolute;
      width: 100%;
      height: 100%;
      z-index: 1;
      display: flex;
      text-align: right;
    }

    canvas {
      position: relative;
      z-index: 2;
    }

    .mask div {
      flex: 1;
      position: relative;
    }

    .mask div span {
      transform: rotate(90deg);
      display: inline-block;
      color: #c1c1c1;
      position: relative;
      right: 0;
      top: 40px;
      font-weight: 500;
    }

    .qianmings {
      border-right: 1px dashed #c1c1c1;
    }

    .btns button {
      padding: 0.7rem;
      background-color: #5c92ff;
      border-radius: 1.5rem;
      font-size: 1.1rem;
      box-shadow: 0px 2px 5px rgb(0 0 0 / 20%);
      color: #fff;
      width: 100%;
      box-sizing: border-box;
      margin-top: 15px;
    }

    .btns {
      margin: 1rem;
    }

    .signBox {
      width: calc(100vw - 2rem);
      height: calc(100vh - 2rem);
      overflow: hidden;
    }

    #copyCanvas {
      display: none;
    }
  </style>
</head>

<body>
  <div id="app" v-cloak>
    <!-- 旋转前 -->
    <img src="" id="mysignature">
    <!-- 旋转后 -->
    <img :src="signature" id="mysignatureCopy">
    <van-popup v-model="showUserSign" class="buyShow">
      <user-sign :show-user-sign="showUserSign" @changepopup="changePopup" @signature="getSignature"></user-sign>
    </van-popup>
  </div>
</body>
<script>
  /**
   * 用户签名组件
   */
  /* 注册全局组件 */
  Vue.component('user-sign', {
    template: `
    <div class="signBox">
      <canvas ref="copyCanvas" id="copyCanvas"></canvas>
      <div class="signature">
        <div id="sign" ref="fRoot">
          <div class="mask">
            <div class="qianmings">
              <span>本人签名</span>
            </div>
            <div class="qmtime">
              <span>签名时间</span>
            </div>
          </div>
        </div>
        <div class="signBtn">
          <button @click="closeUserSign">关闭</button>
          <button @click="clearCanvas">清除</button>
          <button @click="saveCanvas">保存</button>
        </div>
      </div>
    </div>
  `,
    props: ['showUserSign'],
    data () {
      return {
        linewidth: 4,
        color: '#404040',
        background: 'transparent',
        drawStatus: false,
        cxt: '',
        cxtCopy: '',
        copy: '',
        canvasStyle: {
          width: '',
          height: ''
        }
      };
    },
    mounted () {
      this.initCanvas()
    },
    methods: {
      closeUserSign () {
        this.$emit('changepopup', false)
      },
      initCanvas () {
        let canvas = document.createElement("canvas")
        this.canvas = canvas
        this.$refs.fRoot.appendChild(canvas)
        let cxt = canvas.getContext("2d")
        this.cxt = cxt
        let width = this.$refs.fRoot.clientWidth
        let height = this.$refs.fRoot.clientHeight
        cxt.fillStyle = this.background;
        canvas.width = width;
        canvas.height = height;
        this.canvasStyle.width = width;
        this.canvasStyle.height = height;
        // cxt.fillRect(0, 0, width, height);
        cxt.strokeStyle = this.color;
        cxt.lineWidth = this.linewidth;
        cxt.lineCap = "round";
        this.cxtCopy = this.$refs.copyCanvas.getContext("2d");
        this.copy = this.$refs.copyCanvas
        const offset = 24;
        //开始绘制
        canvas.addEventListener(
          "touchstart",
          function (e) {
            this.drawStatus = true
            cxt.beginPath();
            cxt.moveTo(
              e.changedTouches[0].pageX - offset,
              e.changedTouches[0].pageY - offset
            );
          }.bind(this),
          false
        );
        //绘制中
        canvas.addEventListener(
          "touchmove",
          function (e) {
            cxt.lineTo(
              e.changedTouches[0].pageX - offset,
              e.changedTouches[0].pageY - offset
            );
            cxt.stroke();
          }.bind(this),
          false
        );
        //结束绘制
        canvas.addEventListener(
          "touchend",
          function () {
            cxt.closePath();
          }.bind(this),
          false
        );
      },
      clearCanvas () {
        // 清除画布
        this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
        this.drawStatus = false
      },
      saveCanvas () {
        // 保存图片,直接转base64
        let imgBase64Copy = ''
        let signature = ''
        const imgBase64 = this.canvas.toDataURL();
        const img = document.querySelector("#mysignature");
        img.src = imgBase64;
        img.onload = () => {
          // 图片宽高
          let iw = img.width
          let ih = img.height
          // canvas宽高
          let cw = 145
          let ch = 86
          const opt = this.getXY(cw, ch, ih, iw)
          this.cxtCopy.clearRect(0, 0, opt.rw, opt.rh)
          this.cxtCopy.translate(0, opt.rh + opt.points[1])
          this.cxtCopy.rotate(-Math.PI / 2)
          this.cxtCopy.drawImage(img, opt.points[1], opt.points[0], opt.rh, opt.rw)
          // 将有效部分图片截取
          let frame = this.cxtCopy.getImageData(0, 0, opt.rw, opt.rh)
          // 将canvas保持与图片大小相同
          this.copy.height = opt.rh
          this.copy.width = opt.rw
          // 清除画布
          this.cxtCopy.clearRect(0, 0, opt.rw, opt.rh)
          // 重新绘制
          this.cxtCopy.putImageData(frame, 0, 0)
          imgBase64Copy = this.copy.toDataURL();
          if (this.drawStatus) {
            signature = imgBase64Copy;
          } else {
            signature = ''
          }
          this.drawStatus = false
          this.clearCanvas()
          this.$emit('signature', signature)
        }
      },
      /**
     * @description: 
     * @param {*} cw canvas宽度
     * @param {*} ch canvas高度
     * @param {*} iw img宽度
     * @param {*} ih img高度
     * @return {*}
     */
      getXY (cw, ch, iw, ih) {
        // 比较宽高比例,大的一边撑满
        let li = iw / ih
        let lc = cw / ch
        // console.log('图片宽高比', li, 'canvas宽高比', lc);
        // 需要绘制的宽高起点
        let points = [0, 0]
        let rw, rh
        let wall = false // 是否宽度占满
        if (li > lc) {
          // 宽度100%,等比缩放
          rw = cw
          rh = rw / li
          points[0] = 0
          points[1] = (ch - rh) / 2
          wall = true
        } else {
          rh = ch
          rw = rh * li
          points[0] = (cw - rw) / 2
          points[1] = 0
          wall = false
        }
        rw = Math.floor(rw)
        rh = Math.floor(rh)
        // console.log('canvas', cw, ch, 'img', iw, ih, '绘制', rw, rh);
        return {
          points,
          rw,
          rh
        }
      }
    }
  });

</script>
<!-- <script src="js/signature.js" defer="defer"></script> -->
<script>
  new Vue({
    el: '#app',
    data () {
      return {
        showUserSign: true,
        signature: ''
      }
    },
    methods: {
      getSignature (val) {
        this.signature = val
        this.showUserSign = false
      },
      goSign () {
        this.showUserSign = true
      },
      changePopup (val) {
        this.showUserSign = val
      }
    }
  })
</script>

</html>

canvas实现图片旋转并保存 引用https://blog.csdn.net/qq_43585229/article/details/120045282

转载请注明出处或者链接地址:https://www.qianduange.cn//article/1608.html
标签
评论
发布的文章

CSS样式变换效果及动画

2024-02-23 11:02:51

实现 抽屉效果 css3

2024-02-23 11:02:47

jQuery (JavaScript)进阶使用

2024-02-23 11:02:59

CSS样式

2024-02-23 11:02:49

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!