uniapp 小程序横向写字板生成图片并上传(处理模糊图片,更改线条粗细和颜色,手写时阻止页面拉伸)

这里是通过父子传值,用弹窗的形式写的

父组件 

<script>
// 引用手写板组件
import htzSign from "@/subPackage/homeBed/pages/project/service/service/htz-sign.vue";
	export default {
		name: "serviceIn",
		components: {
      htzSign,
		},
		data() {
			return {
        // 是否滚动 防止在手写板输入内容的时候,手写板滚动
        popupShow:false,       
        staffImg:'',				 
			}
		},
		methods: {
      // 写字板弹窗
      goSignstaff(type){     
        this.$refs.popupstaff.open(type)
        this.popupShow = true;
      },
      //提交签字
      async sumbit(res) {
        try {
            // 自己的上传接口
       ... .then(r=> {            
              this.staffImg=r.Model
              this.$refs.popupstaff.close()            
            this.popupShow = false;
          })
        } catch (e) {
          uni.hideLoading()
        }
      },
      // 签字失败
      fail(err) {
        console.log('fail', err)
      },
      // 勿删  手写板禁止晃动的事件 可以给空事件
      stopRoll() {}
		}
	}
</script>

<template>
	<view class="mainView" :class="{popupShow:popupShow}" >
        <uni-card title="签字" v-if="AutoSyncQn()" >
          <image class="imgSize" v-if="staffImg!==''" :src="staffImg" @click="goSignstaff( 'bottom')"></image>
          <image class="imgSize" v-else :src="userInfo.StaffSignImg " @click="goSignstaff( 'bottom')"></image>
          <uni-popup  :animation="false" :is-mask-click="false" ref="popupstaff" background-color="#fff"   class="pop">
            <view class="popup-content"  @touchmove.stop.prevent="stopRoll">
              <!--              签字板组件-->
              <htz-sign @sumbit="sumbit" @fail="fail" cid="ceshi1" ></htz-sign>
            </view>
          </uni-popup>
        </uni-card>
	</view>
</template>

<style scoped lang="scss">
.popupShow {
  overflow: hidden;
  position: fixed;
}
.imgSize{
  width: 100%;
  height: 150px;
}
//模糊处理
image {
  will-change: transform;//解决加载时瞬间拉伸问题
  width: auto;//解决加载时瞬间拉伸问题
  height: auto;//解决加载时瞬间拉伸问题
  image-rendering:-moz-crisp-edges;
  image-rendering:-o-crisp-edges;
  image-rendering:-webkit-optimize-contrast;
  image-rendering: crisp-edges;
  -ms-interpolation-mode:nearest-neighbor;
}
	.mainView {
		padding: 8px 4px;
		height: 100%;
		background-color: #F2F6FC;
	}
  .popup-content {
    height: 100vh;
    width: 100%;
    background-color: #fff;
  }
.pop{
  width: 100%;
  height:100%;
}

</style>

手写板组件

<template>
  <view class="htz-signature-body">
    <canvas  class="canvas" :canvas-id="cid" :id="cid" @touchstart="touchstart" @touchmove="touchmove"
            @touchend="touchend"></canvas>
    <!--用于旋转图片的canvas容器-->
    <canvas  style="position: fixed;z-index: 0;top:-500%;" canvas-id="handWriting2"></canvas>
    <view class="htz-signature-fixed-bottom">
      <view class="htz-signature-fixed-bottom-item htz-signature-tools">
        <view class="htz-signature-tools-item" @click="lineWidth">
          <image src="https://cdn.cos.adl66.com/Applets/ShiLaoHuaGaiZao/bicuxi.png"></image>
          <view>线条</view>
        </view>
        <view class="htz-signature-tools-item" @click="color">
          <image src="https://cdn.cos.adl66.com/Applets/ShiLaoHuaGaiZao/color-plate-fill.png"></image>
          <view>颜色</view>
        </view>
        <view class="htz-signature-tools-item" @click="revoke">
          <image src="https://cdn.cos.adl66.com/Applets/ShiLaoHuaGaiZao/chehuinormal.png"></image>
          <view>撤回</view>
        </view>
        <view class="htz-signature-tools-item" @click="clear">
          <image src="https://cdn.cos.adl66.com/Applets/ShiLaoHuaGaiZao/qingkong_1.png"></image>
          <view>清空</view>
        </view>
      </view>
      <view class="htz-signature-fixed-bottom-item sumbit" @click="sumbit">提交</view>
    </view>

    <!-- #ifdef APP-PLUS -->
    <view class="htz-signature-color-main" v-if="colorShow">
      <view @click="selColor(index)"
            :class="index==colorIndex?'htz-signature-color-item on ':'htz-signature-color-item '"
            :style="'background-color:'+item.value" v-for="(item,index) in colorData" :key="index">
        <image class="htz-signature-color-item-icon" src="https://cdn.cos.adl66.com/Applets/ShiLaoHuaGaiZao/on.png"></image>
      </view>
    </view>
    <view class="htz-signature-color-main" v-if="lineWidthShow">
      <view @click="selLineWidth(index)"
            :class="index==lineWidthIndex?'htz-signature-lineWidth-item on':'htz-signature-lineWidth-item'"
            v-for="(item,index) in lineWidthData" :key="index">
        <view
            :style="'width:60%;height:'+item+'px;background-color:#000000;position: absolute;top: 50%;left: 20%;margin-top:-'+item/2+'px'">
        </view>
      </view>
    </view>
    <!-- #endif -->
    <!-- #ifndef APP-PLUS -->
    <cover-view class="htz-signature-color-main" v-if="colorShow">
      <cover-view @click="selColor(index)"
                  :class="index==colorIndex?'htz-signature-color-item on ':'htz-signature-color-item '"
                  :style="'background-color:'+item.value" v-for="(item,index) in colorData" :key="index">
        <cover-image class="htz-signature-color-item-icon" src="https://cdn.cos.adl66.com/Applets/ShiLaoHuaGaiZao/on.png">
        </cover-image>
      </cover-view>
    </cover-view>
    <cover-view class="htz-signature-color-main" v-if="lineWidthShow">
      <cover-view @click="selLineWidth(index)"
                  :class="index==lineWidthIndex?'htz-signature-lineWidth-item on':'htz-signature-lineWidth-item'"
                  v-for="(item,index) in lineWidthData" :key="index">
        <cover-view
            :style="'width:60%;height:'+item+'px;background-color:#000000;position: absolute;top: 50%;left: 20%;margin-top:-'+item/2+'px'">
        </cover-view>
      </cover-view>
    </cover-view>
    <!-- #endif -->
  </view>
</template>

<script>
export default {
  name: 'htz-signature',
  props: {
    cid: {
      type: String,
      default: '',
    },
  },
  data() {
    return {
      id: '',
      Strokes: [],
      dom: null,
      width: 0,
      height: 0,
      colorShow: false,
      colorIndex: 0,
      colorData: [{
        name: 'black',
        value: '#000000'
      }, {
        name: 'red',
        value: '#f34336',
      }, {
        name: 'blue',
        value: '#0238d0',
      }, {
        name: 'green',
        value: '#8bc24b',
      }, {
        name: 'yellow',
        value: '#ffeb3c',
      }, {
        name: 'purple',
        value: '#a603d0',
      }, {
        name: 'grey',
        value: '#a5a5a5',
      }],
      lineWidthShow: false,
      lineWidthIndex: 0,
      lineWidthData: ['3', '6', '9', '12', '15', '18']
    }
  },
  mounted: function() {
    this.$nextTick(function() {
      // #ifdef H5
      document.body.addEventListener('touchmove', this.touchmoveEnd, {
        passive: false
      })
      // #endif

      uni.getSystemInfo({
        success: (res) => {
          this.width = res.windowWidth;
          this.height = res.windowHeight;
        }
      });

      this.dom = uni.createCanvasContext(this.cid, this);

    });
  },
  beforeDestroy: function() {
    // #ifdef H5
    document.body.removeEventListener('touchmove', this.touchmoveEnd, {
      passive: false
    })
    // #endif
  },
  methods: {
    touchmoveEnd(e) {
      e.preventDefault();
      e.stopPropagation();
    },
    sumbit() {
      var t=this;
      uni.canvasToTempFilePath({
        canvasId: this.cid,
        fileType:"jpg",
        quality: 1, //图片质量
        success:function(res) {
          //获取到原签名照片
          t.rotate(res.tempFilePath);
        },
        fail(e){
          console.log(e)
        }
      }, this)
    },
    //旋转图片,生成新canvas实例
    rotate(tempFilePaths){
      var _this = this;
      uni.getImageInfo({
        // 获取图片的信息
        src: tempFilePaths,
        success: (res1) => {
          // 将canvas1的内容复制到canvas2中
          let canvasContext = uni.createCanvasContext('handWriting2',this)
          let width =  _this.height
          let height =  _this.width
          canvasContext.translate(height / 2, width / 2)
          canvasContext.rotate((270 * Math.PI) / 180)
          canvasContext.drawImage(tempFilePaths, -width / 2, -height / 2, width, height)
          canvasContext.draw(false,(data)=>{
            // 将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中
            uni.canvasToTempFilePath({
              // 把当前画布指定区域的内容导出生成指定大小的图片。在 draw() 回调里调用该方法才能保证图片导出成功。
              canvasId: 'handWriting2',
              fileType: 'jpg',
              quality: 1, //图片质量
              success(res2) {
                // 调用uni.uploadFile上传图片即可
                _this.$emit('sumbit',res2);
              }
            },_this)
          });
        }
      })
    },

    clear() { //清空
      this.Strokes = [];
      this.dom.clearRect(0, 0, this.width, this.height)
      this.dom.draw();
    },
    lineWidth() {
      this.lineWidthShow = !this.lineWidthShow;
      this.colorShow = false;
    },
    selLineWidth(index) {
      this.lineWidthIndex = index;
      this.lineWidthShow = false;
    },
    color() {
      this.colorShow = !this.colorShow;
      this.lineWidthShow = false;
    },
    selColor(index) {
      this.colorIndex = index;
      this.colorShow = false;
    },
    revoke() { //撤销上一步
      var delItem = this.Strokes.pop();
      this.drawCanves();
    },
    drawCanves() {
      //this.dom.draw();
      this.Strokes.forEach((item, index) => {
        let StrokesItem = item;
        if (StrokesItem.points.length > 1) {
          this.dom.beginPath();
          this.dom.setLineCap('round');
          this.dom.setStrokeStyle(item.style.color);
          this.dom.setLineWidth(item.style.lineWidth);
          StrokesItem.points.forEach((sitem, sindex) => {
            if (sitem.type == "touchstart") {
              this.dom.moveTo(sitem.x, sitem.y)
            } else {
              this.dom.lineTo(sitem.x, sitem.y)
            }
          })
          this.dom.stroke();

        }
      })
      this.dom.draw();
    },
    createId() {
      var d = new Date();
      return 'can' + d.getTime();
    },
    touchstart(e) {
      this.Strokes.push({
        imageData: null,
        style: {
          color: this.colorData[this.colorIndex].value,
          lineWidth: this.lineWidthData[this.lineWidthIndex],
        },
        points: [{
          x: e.touches[0].x,
          y: e.touches[0].y,
          type: e.type,
        }]
      })
      this.drawLine(this.Strokes[this.Strokes.length - 1], e.type);
    },
    touchmove(e) {
      this.Strokes[this.Strokes.length - 1].points.push({
        x: e.touches[0].x,
        y: e.touches[0].y,
        type: e.type,
      })
      this.drawLine(this.Strokes[this.Strokes.length - 1], e.type);
    },
    touchend(e) {
      if (this.Strokes[this.Strokes.length - 1].points.length < 2) { //当此路径只有一个点的时候
        this.Strokes.pop();
      }
    },
    drawLine(StrokesItem, type) {
      if (StrokesItem.points.length > 1) {
        this.dom.beginPath();
        this.dom.setLineCap('round')
        this.dom.setStrokeStyle(StrokesItem.style.color);
        this.dom.setLineWidth(StrokesItem.style.lineWidth);
        this.dom.moveTo(StrokesItem.points[StrokesItem.points.length - 2].x, StrokesItem.points[StrokesItem
            .points.length -
        2].y);
        this.dom.lineTo(StrokesItem.points[StrokesItem.points.length - 1].x, StrokesItem.points[StrokesItem
            .points.length -
        1].y);
        this.dom.stroke();
        this.dom.draw(true);
      }
    }
  }
}
</script>

<style>
.canvas {
  position: relative;
z-index: 5;

  width: 100%;
  height: 100%;
}
.htz-signature-body {
  position: fixed;
  top: 0;
  bottom: 0rpx;
  left: 0;
  width: 100%;
}

.htz-signature-body canvas {
  width: 100%;
  height: 100%;
}

.htz-signature-fixed-bottom {
  transform:rotate(90deg) translate(0%,270%);
  position: fixed;
  left: 0%;
  top: 40%;
  width: 100%;
  height: 120rpx;
  line-height: 120rpx;
  text-align: center;
  color: #000;
  z-index: 11;
  display: -webkit-box;
  display: -webkit-flex;
  display: flex;
  background-color: #fff;
}

.htz-signature-fixed-bottom .htz-signature-fixed-bottom-item {
  -webkit-box-flex: 3;
  -webkit-flex-grow: 3;
  flex-grow: 3;
  border-top: 1px solid #d9d9d9;
  color: #1890ff;
}

.htz-signature-fixed-bottom view.sumbit {
  -webkit-box-flex: 1;
  -webkit-flex-grow: 1;
  flex-grow: 1;
  background-color: #1890ff;
  color: #fff;
}

.htz-signature-tools {
  display: -webkit-box;
  display: -webkit-flex;
  display: flex;
}

.htz-signature-tools-item {
  text-align: center;
  -webkit-box-flex: 1;
  -webkit-flex-grow: 1;
  flex-grow: 1;
  line-height: 35rpx;

}

.htz-signature-fixed-bottom-item view image {
  width: 50rpx;
  height: 50rpx;
  padding-top: 10rpx;
}

.htz-signature-tools-item view {
  font-size: 22rpx;
}

.htz-signature-color-main {
  position: fixed;
  bottom: 120rpx;
  left: 0;
  width: 710rpx;
  /* height: 75rpx; */
  z-index: 11;
  padding: 25rpx 20rpx;
  display: -webkit-box;
  display: -webkit-flex;
  display: flex;
  flex-wrap: wrap;
  background-color: #fff;
  border-top: 1px dashed #d9d9d9;
  transition: display 2s;
  -moz-transition: display 2s;
  /* Firefox 4 */
  -webkit-transition: display 2s;
  /* Safari 和 Chrome */
  -o-transition: display 2s;
}

.htz-signature-color-item {
  width: 80rpx;
  height: 80rpx;
  background-color: #000000;
  border-radius: 100px;
  margin: 5px;
  position: relative;
}

.htz-signature-lineWidth-item {
  width: 80rpx;
  height: 80rpx;
  background-color: #fff;
  border-radius: 100px;
  margin: 5px;
  position: relative;
}

.htz-signature-lineWidth-item.on {
  border: 1px solid #d4a39e;
}

.htz-signature-color-item .htz-signature-color-item-icon {
  display: none;
}

.htz-signature-color-item.on .htz-signature-color-item-icon {
  display: block;
  position: absolute;
  top: 50%;
  left: 50%;
  width: 50rpx;
  height: 50rpx;
  margin-top: -25rpx;
  margin-left: -25rpx;
}

.black {
  background-color: #000000 !important;
}
</style>

效果  手写板:

图片效果:

附加:手写板如果还晃动

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值