htmledit_views">
一,借鉴网络实现
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
}