目录结构:
index.wxml:
<view class="canvasBox">
<canvas canvas-id="myCanvas" class="myCanvas" catchtouchstart='canvasStart' catchtouchmove='canvasMoving'></canvas>
</view>
<view class="btn">
<button type="warn" bindtap='drawPen'>画笔</button>
<button type="primary" bindtap='clearCanvas'>清空画板</button>
<button type="warn" bindtap='clearLine'>橡皮擦</button>
<button style='background:#000;color:#fff;' bindtap="black">黑色</button>
<button style='background:yellow;color:#000;' bindtap="yellow">黄色</button>
<button style='background:red;color:#fff;' bindtap="red">红色</button>
<button style='background:blue;color:#fff;' bindtap="blue">蓝色</button>
<button style='background:green;color:#fff;' bindtap="green">绿色</button>
<button type="warn" bindtap="startRecording">开始录制</button>
<button type="primary" bindtap='rePlay'>复盘</button>
<button></button>
</view>
index.wxss:
.canvasBox{
position: relative;
top:0;
left:0;
width: 750rpx;
height:800rpx;
background:#eee;
}
.canvasBox .myCanvas{
width: 100%;
height:100%;
position: absolute;
top:0;
left:0;
}
.btn{
width: 750rpx;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.btn button{
width: 180rpx;
font-size: 24rpx;
}
index.js:
//index.js
//获取应用实例
import {hisData} from "../../utils/historyOperation.js";
const app = getApp()
var moveToX = 0, moveToY = 0, lineToX = 0, lineToY = 0;
var context = null;
var isStart = false;
var date;
var startDate;//开始时刻
var penType = "drawPen";
var colorStr = "#000";
var operationType = "mapping";
Page({
data: {
},
canvasStart:function(e){
var x = Math.floor(e.touches[0].clientX);
var y = Math.floor(e.touches[0].clientY);
date = new Date();
moveToX = x;
moveToY = y;
operationType = "mapping";
if(penType === "clearPen"){
operationType = "clearLine";
}
if (isStart) {
hisData.hisDataArr.push({
time: date.getTime() - startDate,
operation: operationType,
lineArr: {
startX: moveToX,
startY: moveToY,
currentX: x,
currentY: y,
z: 1,
colorStr:colorStr
}
})
}
},
//绘制线条
canvasMoving:function(e){
date = new Date();
var x = Math.floor(e.changedTouches[0].clientX);
var y = Math.floor(e.changedTouches[0].clientY);
lineToX = x;
lineToY = y;
if(penType === "clearPen"){
operationType = "clearLine";
context.clearRect(x-12, y-12, 24, 24);
context.draw(true);
}else{
operationType = "mapping";
context.setStrokeStyle(colorStr);
context.moveTo(moveToX, moveToY);
context.lineTo(lineToX, lineToY);
}
if (isStart) {
hisData.hisDataArr.push({
time: date.getTime() - startDate,
operation: operationType,
lineArr: {
startX: moveToX,
startY: moveToY,
currentX: lineToX,
currentY: lineToY,
z: 1,
colorStr: colorStr
}
})
}
moveToX = lineToX;
moveToY = lineToY;
context.stroke();
context.draw(true);
},
clearCanvas:function(){
context.clearRect(0,0,375,400);
context.draw(true);
date = new Date();//记录当前操作时刻
operationType = "clearCanvas";
if(isStart){
hisData.hisDataArr.push({
time: date.getTime() - startDate,
operation: operationType,
lineArr: {
startX: -1,
startY: -1,
currentX: -1,
currentY: -1,
z: 0,
colorStr: colorStr
}
})
}
},
drawPen:function(){
penType = "drawPen";
},
clearLine:function(){
penType = "clearPen";
},
black:function(){
colorStr = "#000";
},
yellow: function () {
colorStr = "yellow";
},
red: function () {
colorStr = "red";
},
blue: function () {
colorStr = "blue";
},
green: function () {
colorStr = "green";
},
startRecording:function(){
isStart = true;
date = new Date();
startDate = date.getTime();
},
rePlay:function(){
wx.navigateTo({
url: '../replay/replay',
})
},
onLoad: function () {
isStart = false;
context = wx.createCanvasContext('myCanvas');
context.beginPath();
context.setStrokeStyle('#000');
context.setLineWidth(5);
context.setLineCap('round');
context.setLineJoin('round');
}
})
historyOperation.js:该文件用来保存历史操作,以便复盘
const hisData = {
hisDataArr:[
{
time:0,//操作时间
/**
* 操作类型
* 绘图:mapping
* 拖动球员:moveplayer
* 清除画布:clearCanvas
* 橡皮擦:clearLine
*/
operation:"mapping",//操作类型
/**
* 绘制路径
* startX:开始x坐标
* startY:开y纵坐标
* currentX:目标位置的 x 坐标
* currentY:目标位置的 y 坐标
* z:1代表画线时鼠标处于move状态,0代表处于松开状态
* colorStr:线的填充颜色
*/
lineArr: { //绘制路径
startX:0,
startY:0,
currentX:0,
currentY:0,
z:0,
colorStr:"#000"
}
}
]
};
export {hisData};
复盘:
reply.wxml:
<!--pages/replay/replay.wxml-->
<view class="replayBox">
<canvas canvas-id='myCanvas' class="myCanvas"></canvas>
</view>
<button type="warn" bindtap="start">开始</button>
reply.wxss:
/* pages/replay/replay.wxss */
.replayBox{
position:relative;
width: 750rpx;
height:800rpx;
background: #eee;
}
.replayBox .myCanvas{
position: absolute;
top:0;
left:0;
width:100%;
height:100%;
}
reply.js:
// pages/replay/replay.js
import {hisData} from "../../utils/historyOperation.js";
var startDate;
var date;
var curTime;
var context = null;
var timer = null;
Page({
/**
* 页面的初始数据
*/
data: {
},
start:function(){
context.clearRect(0, 0, 375, 400);
clearInterval(timer);
date = new Date();
startDate = date.getTime();
var i = 0;
var that = this;
var len = hisData.hisDataArr.length;
timer = setInterval(function(){
date = new Date();
curTime = date.getTime() - startDate;
if (curTime >= hisData.hisDataArr[i].time){
switch (hisData.hisDataArr[i].operation) {
case "mapping":
context.setStrokeStyle(hisData.hisDataArr[i].lineArr.colorStr);
context.moveTo(hisData.hisDataArr[i].lineArr.startX, hisData.hisDataArr[i].lineArr.startY);
context.lineTo(hisData.hisDataArr[i].lineArr.currentX, hisData.hisDataArr[i].lineArr.currentY);
context.stroke();
context.draw(true);
break;
case "clearCanvas":
context.clearRect(0, 0, 375, 400);
context.draw(true);
break;
case "clearLine":
context.clearRect(hisData.hisDataArr[i].lineArr.currentX-12, hisData.hisDataArr[i].lineArr.currentY-12, 24, 24);
context.draw(true);
break;
}
i++;
}
if(i >= len){
clearInterval(timer);
}
},2);
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
context = wx.createCanvasContext('myCanvas');
context.beginPath();
context.setStrokeStyle('#000');
context.setLineWidth(3);
context.setLineCap('round');
context.setLineJoin('round');
}
})