开始用的2.0的脚手架,发现坑好多,忍不了换回1了。
断断续续大概写了半个月吧,大致的功能如下:
基本的增删、编辑笔记
按类别、标题、内容、时间戳进行过滤
按创建时间或标题排序
暂存未确认保存的笔记
支持 markdown 和涂鸦两种记录方式
用 localStorage 存取数据,不手动 clear 的话算是个本地的简易数据库吧
移动端适配(虽然体验不如桌面……不过我也不是设计师,已经尽力了)
然后我的问题来了…桌面端编辑涂鸦完全没问题,但手机上就是不行,canvas 的 context 的 stroke 方法似乎失效了。我已经在控制台里打印了 mouse 和 touch 事件的坐标,麻烦大神们看看是什么原因吧…实在搞不懂了T_T
涂鸦的方法如下
// 初始化涂鸦编辑器
const initCanvas = (canvasEle, colorsEle, controllersEle, imageData) => {
// 颜色值对象
const colorTable = [
{
name: 'black',
regularCode: '#222',
opagueCode: 'rgb(189, 189, 189)',
},
{
name: 'green',
regularCode: '#5cb85c',
opagueCode: 'rgb(206, 234, 206)',
},
{
name: 'yellow',
regularCode: '#f0ad4e',
opagueCode: 'rgb(251, 231, 202)',
},
{
name: 'red',
regularCode: '#d9534f',
opagueCode: 'rgb(244, 203, 202)',
},
{
name: 'white',
regularCode: '#fff',
opagueCode: '#fff',
},
];
// 初始化 context
let ctx = canvasEle.getContext('2d');
let selectedColor = null;
let hasOnGoingStroke = false;
let prevStatusStack = [];
let futureStatusStack = [];
let $canvas = $(canvasEle);
// 方法:将 imageData 写入一个 Image 对象,画在 canvas 上
const loadImageData = (data) => {
let img = new Image();
img.src = data;
img.onload = () => {
clearCanvas();
ctx.drawImage(img, 0, 0);
};
}
// 方法:存储当前的 canvas 内容为 imageData,推入状态栈
const saveImageData = () => {
let currentStatus = canvasEle.toDataURL();
prevStatusStack.unshift(currentStatus);
};
// 方法:清除画布
const clearCanvas = () => {
ctx.clearRect(0, 0, 260, 260);
};
// 若提供了 imageData 参数就画出来
if (imageData !== null) {
loadImageData(imageData);
}
// 然后无论此时是否已有内容,推入状态栈一次
saveImageData();
// 颜色选择器鼠标事件
$(colorsEle).children('li')
.on('click', function() {
let $this = $(this);
const tarColorName = $this.data('color');
selectedColor = colorTable.find((item) => {
return item.name === tarColorName;
});
$this
.siblings('.current')
.removeClass('current')
.end()
.addClass('current');
})
.siblings('[data-color=black]')
.click();
// canvas 鼠标事件
$canvas.on('mousedown touchstart', (evt) => {
let stX, stY;
switch (evt.type) {
case 'touchstart':
stX = evt.targetTouches[0].clientX;
stY = evt.targetTouches[0].clientY;
break;
default:
stX = evt.offsetX;
stY = evt.offsetY;
break;
}
console.log('st', stX, stY);
hasOnGoingStroke = true;
ctx.strokeStyle = selectedColor.opagueCode;
ctx.lineWidth = 5;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.imageSmoothingEnabled = true;
ctx.beginPath();
ctx.moveTo(stX, stY);
})
.on('mousemove touchmove', (evt) => {
if (hasOnGoingStroke === true) {
let mdX, mdY;
switch (evt.type) {
case 'touchmove':
mdX = evt.changedTouches[0].clientX;
mdY = evt.changedTouches[0].clientY;
break;
default:
mdX = evt.offsetX;
mdY = evt.offsetY;
break;
}
console.log('md', mdX, mdY);
ctx.lineTo(mdX, mdY);
ctx.stroke();
}
})
.on('mouseout mouseup touchend', (evt) => {
if (hasOnGoingStroke === true) {
let edX, edY;
switch (evt.type) {
case 'touchend':
edX = evt.changedTouches[0].clientX;
edY = evt.changedTouches[0].clientY;
break;
default:
edX = evt.offsetX;
edY = evt.offsetY;
break;
}
ctx.strokeStyle = selectedColor.regularCode;
ctx.lineTo(edX, edY);
ctx.stroke();
console.log('ed', edX, edY);
hasOnGoingStroke = false;
saveImageData();
}
});
// 控制器鼠标事件
$(controllersEle)
.children('.undo')
.on('click', (evt) => {
if (prevStatusStack.length !== 0) {
loadImageData(prevStatusStack[0]);
let currentStep = prevStatusStack.splice(0, 1);
futureStatusStack.unshift(currentStep);
}
})
.end()
.children('.redo')
.on('click', (evt) => {
if (futureStatusStack.length !== 0) {
loadImageData(futureStatusStack[0]);
let currentStep = futureStatusStack.splice(0, 1);
prevStatusStack.unshift(currentStep);
}
})
.end()
.children('.clear')
.on('click', () => {
clearCanvas();
});
};
已经自己解决,原因是
Touch对象的 clientX 和 clientY 是相对于视口的,要取得点击画布的实际位置,要将这两个值减去画布相对于视口的坐标: