H5手写签名

news/2024/7/10 3:15:13 标签: html, vue, javascript, jquery, css
htmledit_views">

一,借鉴网络实现

htmljquery实现

html"><!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>学写一个字</title>
    <meta   name="viewport"
            content="height=device-height,
            width = device-width,
            initial-scale = 1.0,
            minimum-scale = 1.0,
            maxmum - scale = 1.0,
            user - scalable =no"/>

            
    <style>
       
        ul{
            overflow:hidden;
            cursor:pointer;
            width:400px;
            text-align:center;
            margin:20px auto;
        }
        ul li{
            float:left;
            width:40px;
            height:40px;
            border-radius:50%;
            margin-right:10px;
            border:4px solid transparent;
            list-style:none;
        }
        ul li:hover{
            border:4px solid violet;
        }
        .red{
            background-color:red;
        }
        .black{
            background-color:black;
        }
        .green{
            background-color:green;
        }
        .yellow{
            background-color:yellow;
        }
        .blue{
            background-color:blue;
        }
        button{
            width:90px;
            height:40px;
            line-height:40px;
            border:none;
            background:#ddd;
            margin-left:50px;
        }
        img{
            width:100px;
            margin-top:20px;
            text-align:left;
        }
    </style>
</head>

<body style="text-align:center;">
    <canvas id="canvas" style="border:1px solid #ddd;"></canvas>
  
    <!---取色盘---->
    <ul>
        <li class="red" name="red"></li>
        <li class="black" name="black"></li>
        <li class="green" name="green"></li>
        <li class="yellow" name="yellow"></li>
        <li class="blue" name="blue"></li>
    </ul>
    <div style="text-align: center;"><button class="save" >保存</button><button class="clear">清除</button></div>
    <div class="img"></div>
   
</body>
<script src="jquery-3.2.1.min.js"></script>
<script>
    window.onload = function(){
        var canvas = document.getElementById('canvas');
        var context = canvas.getContext('2d');
        var isMouseDown = false; //鼠标是否按下
        var lastLoc = {x:0,y:0};//鼠标上一次所在位置
        var lastTimestamp = 0;//时间戳
        var lastLineWidth=-1;//上一次线条宽度


        canvas.width = Math.min( 600 , window.innerWidth - 20 );
        canvas.height = canvas.width;
        var color ="black";
        //画出田字格
        drawGrid();

        //选择颜色
        $('ul').on('click','li',function(){
            color = $(this).attr('name');
        });

        //清除田字格的内容
        $('body').on('click','button.clear',function(){
            context.clearRect( 0 , 0 , canvas.width, canvas.height );
            drawGrid();
        });

        //将canvas保存成图片
        $('body').on('click','button.save',function(){
              var dataurl = canvas.toDataURL('image/png');
              
              var a = document.createElement('a');
              a.href = dataurl;
              a.download = "我的书法";
              a.click();
              
             $('.img').append('<img src="'+dataurl+'"/>');
        });

        //函数封装--开始
        function beginStroke(point){
            isMouseDown = true
            //console.log("mouse down!")
            lastLoc = windowToCanvas(point.x, point.y)
            lastTimestamp = new Date().getTime();
        }
        function endStroke(){
            isMouseDown = false
        }
        function moveStroke(point){
            var curLoc = windowToCanvas(point.x , point.y);//获得当前坐标
                var curTimestamp = new Date().getTime();//当前时间
                var s = calcDistance(curLoc,lastLoc);//获得运笔距离
                var t = curTimestamp-lastTimestamp;//运笔时间
                var lineWidth = calcLineWidth(t,s);
                context.lineWidth=lineWidth;

                context.beginPath();
                context.moveTo(lastLoc.x,lastLoc.y);
                context.lineTo(curLoc.x,curLoc.y);

                context.strokeStyle=color;
                context.lineCap = "round"
                context.lineJoin = "round"
                context.stroke();
            
                lastLoc = curLoc;
                lastTimestamp = curTimestamp;
                lastLineWidth = lineWidth;
        }

        //手机端事件
        canvas.addEventListener('touchstart',function(e){
            e.preventDefault()
            touch = e.touches[0] //获得坐标位置
            beginStroke( {x: touch.pageX , y: touch.pageY} )
        });
        canvas.addEventListener('touchmove',function(e){
            e.preventDefault()
            if( isMouseDown ){
                touch = e.touches[0]
                moveStroke({x: touch.pageX , y: touch.pageY})
            }
        });
        canvas.addEventListener('touchend',function(e){
            e.preventDefault()
            endStroke()
        });

        canvas.onmousedown=function(e){
            e.preventDefault();
            beginStroke( {x: e.clientX , y: e.clientY} )
        }
        canvas.onmouseup = function(e){
            e.preventDefault();
            endStroke();
        }
        canvas.onmouseout = function(e){
            e.preventDefault();
            endStroke();
        }
        canvas.onmousemove = function(e){
            e.preventDefault();
            if(isMouseDown){
                //draw
               var curLoc = windowToCanvas(e.clientX,e.clientY);//获得当前坐标
               moveStroke({x: e.clientX , y: e.clientY})
            }
        }

        
        //获得canvas坐标
        function windowToCanvas(x,y){
            var bbox = canvas.getBoundingClientRect();
            return {x:Math.round(x-bbox.left),y:Math.round(y-bbox.top)};
        }
        //求两点之间距离
        function calcDistance(loc1,loc2){
            return Math.sqrt((loc1.x - loc2.x)*(loc1.x - loc2.x)+(loc1.y - loc2.y)*(loc1.y - loc2.y));
        }
        //求速度
        function calcLineWidth(t,s){
            var v = s/t;
            var resultLineWidth;
            if(v<=0.1){
                resultLineWidth=30;
            }else if(v>=10){
                resultLineWidth=1;
            }else{
                resultLineWidth=30-(v-0.1)/(10-0.1)*(30-1);
            }
            if(lastLineWidth==-1){
                return resultLineWidth;
            }
            return lastLineWidth*2/3+resultLineWidth*1/3;
        }
        //田字格
        function drawGrid(){
            context.save();
            context.strokeStyle = "rgb(230,11,9)";
            context.beginPath();
            context.moveTo(3,3);
            context.lineTo(canvas.width - 3,3);
            context.lineTo(canvas.width - 3,canvas.height -3);
            context.lineTo(3,canvas.height -3);
            context.closePath();

            context.lineWidth = 6;
            context.stroke();

            context.beginPath();
            context.moveTo(0,0);
            context.lineTo(canvas.width,canvas.height);

            context.moveTo(canvas.width,0);
            context.lineTo(0,canvas.height);

            context.moveTo(canvas.width/2,0);
            context.lineTo(canvas.width/2,canvas.height);

            context.moveTo(0,canvas.width/2);
            context.lineTo(canvas.width,canvas.height/2);
            context.lineWidth=1;
            context.stroke();
            context.restore();

        }
        
    }
        




    
</script>
</html>

二,自己用vue做成插件

signature插件代码 signature.vue

html"><template>
  <div style="text-align: center">
    <div style="margin: 10px">请在下方签名</div>
    <canvas
      id="canvas"
      style="border: 1px solid #ddd; background-color: aliceblue; margin: 10px"
    ></canvas>

    <!---取色盘---->
    <div style="text-align: center">
      <button
        class="mui-btn mui-btn-primary"
        style="margin-right: 40px"
        @click="save()"
      >
        保存</button
      ><button class="mui-btn" @click="clear()">清除</button>
    </div>
    <img  id="result" :src="src"></img>
  </div>
</template>

<script> 
import { formatTime } from "@/common/dateUtil";
export default {
  data() {
    return {
      canvas: null,
      context: null,
      isMouseDown: false, //鼠标是否按下
      lastLoc: { x: 0, y: 0 }, //鼠标上一次所在位置
      lastTimestamp: 0, //时间戳
      lastLineWidth: -1, //上一次线条宽度};
      color: "black",
      src: null,
    };
  },
  props: {
      clickCallBack: {  //定义一个外来方法
        type: Function, //参数类型:函数
        required: true //是否必填:是
      }
    },
  methods: {
    //将canvas保存成图片
    save() {
      //this.drawDate();
      var base64Img = this.canvas.toDataURL("image/jpg");
      // this.src = base64Img;
      //this.$emit("callback", base64Img);
      this.$props.clickCallBack(base64Img); //调用Props传来的方法体,并送他一个参数~~
    },
    clear() {
      //清除田字格的内容
      this.context.clearRect(0, 0, self.canvas.width, self.canvas.height);
      //this.drawGrid();
    },

    doPageData() {
      var self = this;
      this.canvas = window.document.getElementById("canvas");
      this.context = this.canvas.getContext("2d");
      this.isMouseDown = false; //鼠标是否按下
      this.lastLoc = { x: 0, y: 0 }; //鼠标上一次所在位置
      this.lastTimestamp = 0; //时间戳
      this.lastLineWidth = -1; //上一次线条宽度

      this.canvas.width = window.innerWidth - 20;
      Math.min(600, window.innerWidth - 20);
      this.canvas.height = (this.canvas.width * 2) / 3; //this.canvas.width;
      this.color = "black";
      //画出田字格
      //this.drawGrid();

      //手机端事件
      this.canvas.addEventListener("touchstart", function (e) {
        e.preventDefault();
        var touch = e.touches[0]; //获得坐标位置
        self.beginStroke({ x: touch.pageX, y: touch.pageY });
      });
      this.canvas.addEventListener("touchmove", function (e) {
        e.preventDefault();
        if (self.isMouseDown) {
          var touch = e.touches[0];
          self.moveStroke({ x: touch.pageX, y: touch.pageY });
        }
      });
      this.canvas.addEventListener("touchend", function (e) {
        e.preventDefault();
        self.endStroke();
      });

      this.canvas.onmousedown = function (e) {
        e.preventDefault();
        self.beginStroke({ x: e.clientX, y: e.clientY });
      };
      this.canvas.onmouseup = function (e) {
        e.preventDefault();
        self.endStroke();
      };
      this.canvas.onmouseout = function (e) {
        e.preventDefault();
        self.endStroke();
      };
      this.canvas.onmousemove = function (e) {
        e.preventDefault();
        if (self.isMouseDown) {
          //draw
          var curLoc = self.windowToCanvas(e.clientX, e.clientY); //获得当前坐标
          self.moveStroke({ x: e.clientX, y: e.clientY });
        }
      };
    },

    //函数封装--开始
    beginStroke(point) {
      this.isMouseDown = true;
      //console.log("mouse down!")
      this.lastLoc = this.windowToCanvas(point.x, point.y);
      this.lastTimestamp = new Date().getTime();
    },
    endStroke() {
      this.isMouseDown = false;
    },
    moveStroke(point) {
      var curLoc = this.windowToCanvas(point.x, point.y); //获得当前坐标
      var curTimestamp = new Date().getTime(); //当前时间
      var s = this.calcDistance(curLoc, this.lastLoc); //获得运笔距离
      var t = curTimestamp - this.lastTimestamp; //运笔时间
      var lineWidth = 5; // this.calcLineWidth(t, s);
      this.context.lineWidth = lineWidth;

      this.context.beginPath();
      this.context.moveTo(this.lastLoc.x, this.lastLoc.y);
      this.context.lineTo(curLoc.x, curLoc.y);

      this.context.strokeStyle = this.color;
      this.context.lineCap = "round";
      this.context.lineJoin = "round";
      this.context.stroke();

      this.lastLoc = curLoc;
      this.lastTimestamp = curTimestamp;
      this.lastLineWidth = lineWidth;
    },

    //获得canvas坐标
    windowToCanvas(x, y) {
      var bbox = this.canvas.getBoundingClientRect();
      return { x: Math.round(x - bbox.left), y: Math.round(y - bbox.top) };
    },
    //求两点之间距离
    calcDistance(loc1, loc2) {
      return Math.sqrt(
        (loc1.x - loc2.x) * (loc1.x - loc2.x) +
          (loc1.y - loc2.y) * (loc1.y - loc2.y)
      );
    },
    //求速度
    calcLineWidth(t, s) {
      var v = s / t;
      var resultLineWidth;
      if (v <= 0.1) {
        resultLineWidth = 30;
      } else if (v >= 10) {
        resultLineWidth = 1;
      } else {
        resultLineWidth = 30 - ((v - 0.1) / (10 - 0.1)) * (30 - 1);
      }
      if (this.lastLineWidth == -1) {
        return resultLineWidth;
      }
      return (this.lastLineWidth * 2) / 3 + (resultLineWidth * 1) / 3;
    },
    //田字格
    drawGrid() {
      this.context.save();
      this.context.strokeStyle = "rgb(230,11,9)";
      this.context.beginPath();
      this.context.moveTo(3, 3);
      this.context.lineTo(this.canvas.width - 3, 3);
      this.context.lineTo(this.canvas.width - 3, this.canvas.height - 3);
      this.context.lineTo(3, this.canvas.height - 3);
      this.context.closePath();

      this.context.lineWidth = 6;
      this.context.stroke();

      this.context.beginPath();
      this.context.moveTo(0, 0);
      this.context.lineTo(this.canvas.width, this.canvas.height);

      this.context.moveTo(this.canvas.width, 0);
      this.context.lineTo(0, this.canvas.height);

      this.context.moveTo(this.canvas.width / 2, 0);
      this.context.lineTo(this.canvas.width / 2, this.canvas.height);

      this.context.moveTo(0, this.canvas.width / 2);
      this.context.lineTo(this.canvas.width, this.canvas.height / 2);
      this.context.lineWidth = 1;
      this.context.stroke();
      this.context.restore();
    },
    drawDate() {
      var now = new Date();
      var dateStr = formatTime(now);

      this.context.fillStyle = "black";
      this.context.font = "20px bold ";
      //alert(this.canvas.width+","+this.canvas.height)
      this.context.fillText(
        dateStr,
        this.canvas.width - 210,
        this.canvas.height - 10
      );

      this.context.stroke();
      this.context.restore();
      this.context.save();
    },
  },
  mounted() {
    this.doPageData();
  },
  created() {
     
  },
  activated() {
    this.doPageData();
  },
};
</script>


<style scoped>
</style>

signature插件引用

html"><template>
  <div>
    <button @click="showSign()">签名</button>
    <img v-if="imgSrc" :src="imgSrc" style="width:60px;height:40px;border: 1px solid darkgrey;" >
    <LearnVideoSignature v-if="isShowSign"  :click-call-back="callback"></LearnVideoSignature>
  </div>
</template>
<script>
import LearnVideoSignature from '@/components/learnVideo/signature' 
export default {
  data() {
    return { isShowSign:false ,imgSrc:null };
  },
  components:{
      LearnVideoSignature

  },
  methods:{
    showSign(){
        this. isShowSign=true;
    },
    callback(base64Img){ 
     this.imgSrc =base64Img;
        this.isShowSign=false;
    }
  },
  created() {
      
  },
  activated(){

  }
}
</script>

 时间处理dateUtil.js

javascript">const formatTime = date => {
    const year = date.getFullYear()
    const month = date.getMonth() + 1
    const day = date.getDate()
    const hour = date.getHours()
    const minute = date.getMinutes()
    const second = date.getSeconds()

    return [year, month, day].map(formatNumber).join('-') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
const formatDate = date => {
    const year = date.getFullYear()
    const month = date.getMonth() + 1
    const day = date.getDate()

    return [year, month, day].map(formatNumber).join('-')
}
const dealTime = dateStr => {
    dateStr = dateStr.replace('T', ' ').replace('Z', '');
    var date = new Date(dateStr.replace('-', '/'));
    var newDate = new Date(date.getTime() + 8 * 60 * 60 * 1000);
    return formatTime(newDate);
}

const formatNumber = n => {
        n = n.toString()
        return n[1] ? n : '0' + n
    }
    //是否为闰年
const isLeapYear = function(year) {
    if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) return true;
    return false;
};

module.exports = {
    formatTime: formatTime,
    dealTime: dealTime,
    isLeapYear: isLeapYear,
    formatDate: formatDate
}

 


http://www.niftyadmin.cn/n/1483662.html

相关文章

550 Mailbox unavailable or access denied

标题问题&#xff1a;550 Mailbox unavailable or access denied** 错误原因&#xff0c;你发送的邮箱用户近期被频繁发送邮件&#xff0c;说白了就是过滤了你的垃圾邮件。腾讯邮箱官网有回答 遇到这个问题&#xff0c;很无语&#xff0c;就换个邮箱试试&#xff0c;163

个人对项目小细节总结

1&#xff0c;Mybatis 中 mapper层 Param 只接收参数 &#xff0c;不接收对象传参。 2&#xff0c;Mybatis 中 .xml文件 返回列表 用 resultMap map参数接收。 3&#xff0c;SpringMVC 注解 RequestBody 用 Post 请求 &#xff0c; RequestParam 用 Get 请求. 4&#xff0…

java.sql.SQLSyntaxErrorException: ORA-00972: 标识符过长

select * from table_test t where t.ide18bdc3d29ab49cd946b9aa4288d73d3 请把字符串用单引号 括起来 select * from table_test t where t.ide18bdc3d29ab49cd946b9aa4288d73d3 如果是ibatis的框架请注意$与#的区别 比如xml 里面是${id}&#xff0c;改为#{id}…

RMAN duplicate from active 时遭遇 ORA-17627 ORA-12154

最近在从活动数据库进行异机克隆时碰到了ORA-17629&#xff0c;ORA-17627&#xff0c;ORA-12154的错误&#xff0c;起初以为是一个Bug呢。Oracle Bug着实太多了&#xff0c;已经成了习惯性思维了。汗&#xff01;错误提示是无法连接到连接到远程数据库&#xff0c;连接字符串无…

WinFrom日记————Label控件调整大小

WinFrom—Label控件调整大小 如果要更改Label的大小&#xff0c;只需要在控件属性种找到Autosize属性&#xff0c;将True改成False就可以

语法解析改进及代码生成

转载于:https://www.cnblogs.com/ZHONGZHENHUA/p/10212189.html

Linux 统计目录、文件数量

Linux 统计目录、文件数量 1.查看当前目录下的文件数量&#xff08;不包含子目录中的文件&#xff09; ls -l | grep "^-" | wc -l 2.查看当前目录下的文件数量&#xff08;包含子目录中的文件&#xff09;注意&#xff1a;R&#xff0c;代表子目录 ls -lR | grep …

Linux 挂载FreeNas ufs 格式磁盘

Linux支持ufs 格式 需要yum 模块# yum update# yum install kmod-ufs# modprobe ufs操作完成后&#xff0c;我的FreeNas 里的磁盘&#xff1a;gpt格式在linux里用parted 查看有两个分区&#xff0c;fdisk -l 查看为/dev/sdb则我mount如下mount -t ufs -o ufstypeufs2,ro dev…