手机签名 --- 横屏竖屏不一样的画板

手机竖屏


image.png

手机横屏


image.png
<template>
  <div style="width:100%;height:100%;padding:0.1rem;">
    <div v-if="direction=='horizontal'" class="mydraw2">
      <div class="cont buttonDiv2 commoBtn2">
        <yd-button @click.native="clear">
          <span>清除</span>
        </yd-button>
        <yd-button @click.native="save" :loading="saveLoading">
          <span>保存</span>
        </yd-button>
      </div>
      <div class="cont canvasDiv2">
        <canvas
          id="canvas"
          ref="mycanvas"
          @touchstart="onTouchStart"
          @touchmove="onTouchMove"
          @touchend="onTouchEnd"
        >Canvas画板</canvas>
      </div>
      <div class="cont signLabelDiv2">
        <p>签&nbsp;&nbsp;字</p>
      </div>
    </div>
    <div v-else style='text-align: center'>
      <div>
        <p style='font-size: 0.3rem;height: 30px;margin-top: 10px;'>签&nbsp;&nbsp;字</p>
        <div class="cont canvasDiv" style="width: 100%">
          <canvas
            id="canvas"
            ref="mycanvas"
            @touchstart="onTouchStart"
            @touchmove="onTouchMove"
            @touchend="onTouchEnd"
          >Canvas画板</canvas>
        </div>
        <div style="margin-top: 10px">
          <yd-button @click.native="clear">
            <span>清除</span>
          </yd-button>
          <yd-button @click.native="save" :loading="saveLoading" style='margin-left: 10px'>
            <span>保存</span>
          </yd-button>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
import html2canvas from '../../node_modules/html2canvas'
import { getSignature } from '@/api/auth'
import Util from '@/libs/util.js'

export default {
  data() {
    return {
      direction: 'vertical', // 画板方向 vertical horizontal
      colors: [
        { color: 'black', active: true },
        { color: 'red', active: false },
        { color: 'blue', active: false }
      ], // 可选颜色
      ctx: '', // canvas对象
      stage_info: '', // mycanvas的大小及其相对于视口的位置
      canvasWidth: '', // canvas宽度
      canvasHeight: '', // canvas高度
      lineColor: 'black', // 线条的颜色
      lineWidth: 5, // 线条宽度
      url: '', // 图片展示路径
      signData: {
        // 提交签名需要的内容
        lawCaseId: '',
        litigantId: '',
        lawyerId: '',
        image: ''
      },
      saveLoading: false // 保存按钮加载状态
    }
  },

  created() {
    // 阻止默认微信系统字体大小的影响
    if (
      typeof WeixinJSBridge == 'object' &&
      typeof WeixinJSBridge.invoke == 'function'
    ) {
      handleFontSize()
    } else {
      if (document.addEventListener) {
        document.addEventListener('WeixinJSBridgeReady', handleFontSize, false)
      } else if (document.attachEvent) {
        document.attachEvent('WeixinJSBridgeReady', handleFontSize)

        document.attachEvent('onWeixinJSBridgeReady', handleFontSize)
      }
    }

    function handleFontSize() {
      // 设置网页字体为默认大小
      WeixinJSBridge.invoke('setFontSizeCallback', {
        fontSize: 0
      })
      // 重写设置网页字体大小的事件
      WeixinJSBridge.on('menu:setfont', function() {
        WeixinJSBridge.invoke('setFontSizeCallback', {
          fontSize: 0
        })
      })
    }
  },

  mounted() {
    // 初始化获取链接参数
    this.signData.lawCaseId = Util.GetUrlParam('lawCaseId')
    this.signData.litigantId = Util.GetUrlParam('litigantId')
    this.signData.lawyerId = Util.GetUrlParam('lawyerId')
    console.log('this.signData', this.signData)
    // 检查横竖屏
    this.checkScreen()
    // 初始化画板
    this.writeName()
    // 监听屏幕旋转
    this.orientationchange()
    // 监听窗体大小改变
    this.onSizeChange()
  },

  methods: {
    // 点击签名,初始化画板
    writeName() {
      this.url = ''
      this.$nextTick(() => {
        this.initCanvas()
      })
    },
    /**
     * 初始化画板,获取canvas节点对象,设置画板的宽高
     * 不能在此方法中设置线条宽度样式,否则无效
     */
    initCanvas() {
      // 获取到当前canvas节点的信息,包含宽,高,top,left等
      var mycanvas = this.$refs.mycanvas // 获取canvas元素
      this.canvasWidth = mycanvas.clientWidth - 1 // 获取画板宽度
      this.canvasHeight = mycanvas.clientHeight - 1 // 获取画板高度
      // 设置canvas自适应的宽高到标签上(重要,canvas一定要遭标签上标识宽高,否则坐标获取不准确)
      console.log('clientWidth', this.canvasWidth)
      console.log('clientHeight', this.canvasHeight)
      mycanvas.width = this.canvasWidth
      mycanvas.height = this.canvasHeight

      // canvas基础设置,线条设置
      this.ctx = mycanvas.getContext('2d')
      // 获取mycanvas的大小及其相对于视口的位置
      this.stage_info = mycanvas.getBoundingClientRect()
      console.log('stage_info', this.stage_info)
      this.ctx.beginPath()
    },
    /**
     * 绘制笔触
     */
    handleDraw(targetX, targetY) {
      console.log(targetX, targetY)
      this.ctx.lineTo(targetX, targetY) // 将笔触移到当前点击点
      this.ctx.stroke()
    },
    /**
     * 触摸开始
     * 获取当前点击点的坐标
     * 设置线条颜色,宽度,样式等
     */
    onTouchStart(e) {
      let targetX = e.changedTouches[0].clientX - this.stage_info.left // 计算起始点X坐标
      let targetY = e.changedTouches[0].clientY - this.stage_info.top // 计算起始点Y坐标
      console.log(
        'clientX',
        e.changedTouches[0].clientX,
        'stage.top',
        this.stage_info.top
      )
      console.log(
        'clientY',
        e.changedTouches[0].clientY,
        'stage.left',
        this.stage_info.left
      )
      e.preventDefault()
      this.ctx.beginPath()
      this.ctx.strokeStyle = this.lineColor // 设置线条颜色
      this.ctx.lineWidth = this.lineWidth // 设置线条的宽度
      this.ctx.lineCap = 'round' // 设置线条的端点的样式,设为圆弧形
      this.ctx.lineJoin = 'round' // 设置线条的连接点的样式,设为弧形
      this.handleDraw(targetX, targetY)
    },
    /**
     * 触摸过程中
     * 获取并计算当前点击点的坐标,绘制线条
     */
    onTouchMove(e) {
      let targetX = e.changedTouches[0].clientX - this.stage_info.left // 计算起始点X坐标
      let targetY = e.changedTouches[0].clientY - this.stage_info.top // 计算起始点Y坐标
      e.preventDefault()
      this.handleDraw(targetX, targetY)
    },
    /**
     * 触摸结束
     */
    onTouchEnd(e) {
      e.preventDefault()
    },
    /**
     * 颜色模块点击事件,切换点击的颜色状态
     */
    clickColorItem(e) {
      this.colors.forEach(item => {
        item.active = false
      })
      e.active = true
      this.lineColor = e.color // 设置当前笔触颜色
    },
    /**
     * 重写按钮点击事件,清空画板内容
     */
    clear() {
      // 清空图片
      this.url = ''
      // 清空画板
      this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
      // 重新设置canvas画板节点对象,否则绘画会出问题,这里异步操作,否则绘画有误
      this.$nextTick(() => {
        this.initCanvas()
      })
    },
    // 监听屏幕旋转
    // 用此事件获取改变后的屏幕尺寸需要注意:
    //  1).iphone,可立即获取改变后的屏幕尺寸。
    //  2).android,获取的尺寸是改变前的。需要设置setTimeout在一段时间后再获取。iScroll4是200ms,建议设成300ms.
    orientationchange() {
      window.addEventListener(
        'orientationchange',
        () => {
          this.$nextTick(() => {
            this.checkScreen() // 检查横竖屏
          })
        },
        false
      )
    },
    checkScreen() {
      // 检查横竖屏
      switch (window.orientation) {
        case 90:
        case -90:
          console.log('横屏') // 这里是横屏
          this.direction = 'horizontal'
          break
        default:
          console.log('竖屏') // 这里是竖屏
          this.direction = 'vertical'
          break
      }
      this.$nextTick(() => {
        this.clear() // 重置画板
      })
    },
    // 监听窗体大小改变
    onSizeChange() {
      window.onresize = () => {
        console.log('窗体大小改变') // 这里是横屏
        this.clear() // 重置画板
      }
    },
    // 保存签名
    save() {
      this.url = this.$refs.mycanvas.toDataURL()
      this.submitText()
    },
    // 提交签名图片
    submitText() {
      if (this.url != '') {
        // 追加base64签名图片,转换角度(横屏不需要旋转图片角度)
        this.rotateBase64Img(
          this.url,
          this.direction == 'horizontal' ? 360 : 270,
          base64data => {
            this.signData.image = base64data
            // this.$dialog.loading.open('正在提交签名...');
            this.saveLoading = true
            // getSignature(this.signData).then(res => {
            //   // this.$dialog.loading.close();//关闭加载提示
            //   this.saveLoading = false
            //   if (res.data.state == 100) {
            //     this.$dialog.toast({
            //       mes: '提交成功',
            //       icon: 'success',
            //       timeout: 1500
            //     })
            //     this.$router.push({
            //       name: 'handDrawSuccess'
            //     })
            //   } else {
            //     this.$dialog.toast({
            //       mes: '提交失败,' + res.data.message,
            //       timeout: 1500
            //     })
            //   }
            // })
          }
        )
      } else {
        this.$dialog.toast({
          mes: '请先签名才能提交!',
          timeout: 1500
        })
      }
    },
    // 旋转base64图片
    rotateBase64Img(src, edg, callback) {
      // 旋转base64图片
      var canvas = document.createElement('canvas')
      var ctx = canvas.getContext('2d')
      var imgW // 图片宽度
      var imgH // 图片高度
      var size // canvas初始大小
      if (edg % 90 != 0) {
        console.error('旋转角度必须是90的倍数!')
        throw '旋转角度必须是90的倍数!'
      }
      edg < 0 && (edg = (edg % 360) + 360)
      const quadrant = (edg / 90) % 4 // 旋转象限
      const cutCoor = { sx: 0, sy: 0, ex: 0, ey: 0 } // 裁剪坐标
      var image = new Image()
      image.crossOrigin = 'anonymous'
      image.src = src
      image.onload = function() {
        imgW = image.width
        imgH = image.height
        size = imgW > imgH ? imgW : imgH
        canvas.width = size * 2
        canvas.height = size * 2
        switch (quadrant) {
          case 0:
            cutCoor.sx = size
            cutCoor.sy = size
            cutCoor.ex = size + imgW
            cutCoor.ey = size + imgH
            break
          case 1:
            cutCoor.sx = size - imgH
            cutCoor.sy = size
            cutCoor.ex = size
            cutCoor.ey = size + imgW
            break
          case 2:
            cutCoor.sx = size - imgW
            cutCoor.sy = size - imgH
            cutCoor.ex = size
            cutCoor.ey = size
            break
          case 3:
            cutCoor.sx = size
            cutCoor.sy = size - imgW
            cutCoor.ex = size + imgH
            cutCoor.ey = size + imgW
            break
        }
        ctx.translate(size, size)
        ctx.rotate((edg * Math.PI) / 180)
        ctx.drawImage(image, 0, 0)
        var imgData = ctx.getImageData(
          cutCoor.sx,
          cutCoor.sy,
          cutCoor.ex,
          cutCoor.ey
        )
        if (quadrant % 2 == 0) {
          canvas.width = imgW
          canvas.height = imgH
        } else {
          canvas.width = imgH
          canvas.height = imgW
        }
        ctx.putImageData(imgData, 0, 0)
        callback(canvas.toDataURL())
      }
    }
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->

<style scoped>
body {
  -webkit-text-size-adjust: 100% !important;
  text-size-adjust: 100% !important;
  -moz-text-size-adjust: 100% !important;
}

.cont {
  display: inline-block;
  vertical-align: middle;
}

.cont p {
  transform: rotate(90deg);
  -moz-transform: rotate(90deg);
  -webkit-transform: rotate(90deg);
}

.buttonDiv {
  width: 15vh;
}

.buttonDiv2 {
  height: 15vh;
  -moz-transform: rotate(180deg);
  -webkit-transform: rotate(180deg);
  transform: rotate(180deg);
}

.commoBtn button {
  transform: rotate(90deg);
  -moz-transform: rotate(90deg);
  -webkit-transform: rotate(90deg);
  margin: 20px 0px;
}

.commoBtn2 button {
  display: inline-block;
  margin: 10px;
}

.canvasDiv {
  width: 70vh;
  height: 100%;
  position: relative;
}

.canvasDiv2 {
  height: 70vh;
  width: 100%;
  position: relative;
  transform: rotate(180deg);
}

.signLabelDiv {
  width: 12vh;
  font-size: 0.3rem;
}

.signLabelDiv2 {
  height: 12vh;
  font-size: 0.3rem;
  transform: rotate(90deg);
  margin-left: -4.5%;
}

h1,
h2 {
  font-weight: normal;
}

ul {
  list-style-type: none;

  padding: 0;
}

li {
  display: inline-block;

  margin: 0 10px;
}

a {
  color: #42b983;
}

#canvas {
  background: #fff;
  cursor: default;
  border: 1px dashed rgb(204, 204, 204);
  /* 判断方向旋转辅助线 */
  /* border-bottom: 1px solid red; */
  height: 100%;
  width: 100%;
}

.mydraw {
  height: 100%;
  width: 100%;
}

.mydraw2 {
  height: 100%;
  width: 100%;
  transform: rotate(180deg);
  -moz-transform: rotate(180deg);
  -webkit-transform: rotate(180deg);
}
</style>
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,311评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,339评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,671评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,252评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,253评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,031评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,340评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,973评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,466评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,937评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,039评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,701评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,254评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,259评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,497评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,786评论 2 345