我想在HTML5 canvas /或SVG上执行以下操作:
我的问题是我不知道如何检查绘制的线是否跟随路径。
有人可以解释一下如何做到这一点或者提供一些提示吗?
http://jsbin.com/reguyuxawo/edit?html,js,console,output
function drawBgPath() {
context.beginPath();
context.moveTo(100, 20);
context.lineTo(200, 160);
context.quadraticCurveTo(230, 200, 250, 120);
context.bezierCurveTo(290, -40, 300, 200, 400, 150);
context.lineTo(500, 90);
context.lineWidth = 5;
context.strokeStyle = 'rgba(0,0,0,.2)';
context.stroke();
}
答案 0 :(得分:1)
创建一个隐藏的画布,将原始路径存储为问题画布,例如#q
。
在#c
。
当用户即将绘制时,从问题中获取像素值,看它是否在线上。
通过上述信息确定绘制颜色。
var mousePressed = false;
var lastX, lastY;
var ctx;
var canvas = document.getElementById('c');
var context = canvas.getContext('2d');
var canvasq = document.getElementById('q');
var contextq = canvasq.getContext('2d');
canvas.width = 500;
canvas.height = 500;
canvasq.width = 500;
canvasq.height = 500;
$('#c').mousedown(function (e) {
mousePressed = true;
Draw(e.pageX - $(this).offset().left, e.pageY - $(this).offset().top, false);
});
$('#c').mousemove(function (e) {
if (mousePressed) {
Draw(e.pageX - $(this).offset().left, e.pageY - $(this).offset().top, true);
}
});
$('#c').mouseup(function (e) {
mousePressed = false;
});
$('#c').mouseleave(function (e) {
mousePressed = false;
});
function drawBgPath() {
contextq.beginPath();
contextq.moveTo(100, 20);
contextq.lineTo(200, 160);
contextq.quadraticCurveTo(230, 200, 250, 120);
contextq.bezierCurveTo(290, -40, 300, 200, 400, 150);
contextq.lineTo(500, 90);
contextq.lineWidth = 5;
contextq.strokeStyle = 'rgba(0,0,0,.2)';
contextq.stroke();
context.drawImage(canvasq, 0, 0);
}
function Draw(x, y, isDown) {
// If not integer, getImageData will get a 2x2 region.
x = Math.round(x);
y = Math.round(y);
if (isDown) {
var pixel = contextq.getImageData(x, y, 1, 1);
// If the canvas is not draw by line, the opacity value will be 0.
var color = (pixel.data[3] === 0) ? 'red' : 'purple';
context.beginPath();
context.strokeStyle = color;
context.lineWidth = 5;
context.lineJoin = "round";
context.moveTo(lastX, lastY);
context.lineTo(x, y);
context.closePath();
context.stroke();
}
lastX = x; lastY = y;
}
drawBgPath();
Draw();

#q {
display: none;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<canvas id="c"></canvas>
<canvas id="q"></canvas>
&#13;
另一种方式是:
创建另外2个画布,用于回答和提问。
当鼠标按下时,首先在回答中绘制路径。
然后将答案画布与问题画布进行比较。
在画布上绘制比较答案以显示。
我只是演示如何在这里实现。您可以剪裁绘制区域以提高性能。
以某种方式很难确定路径是否完整。但你仍然可以:
按问题剪辑答案图片,然后逐个比较他们的像素值。
如果有问题的像素有颜色total + 1
,如果两个像素的颜色和颜色相同,则为count + 1
。
检查count/total
是否超过特定阈值。
如果图片很大,可能会很慢,所以我只想在用户mouseup
或点击检查按钮时进行检查。
我还尝试使用.toDataURL
来按字符串比较它们的值,但是,它太严格了,不能让你有一个阈值。
var mousePressed = false;
var lastX, lastY;
var ctx;
// Question part
var qCanvas = document.createElement('canvas');
var qContext = qCanvas.getContext('2d');
var aCanvas = document.createElement('canvas');
var aContext = aCanvas.getContext('2d');
var canvas = document.getElementById('c');
var context = canvas.getContext('2d');
canvas.width = 500;
canvas.height = 500;
qCanvas.width = 500;
qCanvas.height = 500;
aCanvas.width = 500;
aCanvas.height = 500;
$('#c').mousedown(function (e) {
mousePressed = true;
Draw(e.pageX - $(this).offset().left, e.pageY - $(this).offset().top, false);
});
$('#c').mousemove(function (e) {
if (mousePressed) {
Draw(e.pageX - $(this).offset().left, e.pageY - $(this).offset().top, true);
}
});
$('#c').mouseup(function (e) {
mousePressed = false;
});
$('#c').mouseleave(function (e) {
mousePressed = false;
});
function drawBgPath() {
qContext.beginPath();
qContext.moveTo(100, 20);
qContext.lineTo(200, 160);
qContext.quadraticCurveTo(230, 200, 250, 120);
qContext.bezierCurveTo(290, -40, 300, 200, 400, 150);
qContext.lineTo(500, 90);
qContext.lineWidth = 5;
qContext.strokeStyle = 'rgb(0,0,0)';
qContext.stroke();
// Draw Question on canvas
context.save();
context.globalAlpha = 0.2;
context.drawImage(qCanvas, 0, 0);
context.restore();
// Now fill the question with purple.
qContext.fillStyle = 'purple';
qContext.globalCompositeOperation = 'source-atop';
qContext.fillRect(0, 0, qCanvas.width, qCanvas.height);
}
function Draw(x, y, isDown) {
if (isDown) {
// First draw on answer canvas
aContext.beginPath();
aContext.strokeStyle = 'red';
console.log(x, y);
aContext.lineWidth = 5;
aContext.lineJoin = "round";
aContext.moveTo(lastX, lastY);
aContext.lineTo(x, y);
aContext.closePath();
aContext.stroke();
// Compare answer with question.
aContext.save();
aContext.globalCompositeOperation = 'source-atop';
aContext.drawImage(qCanvas, 0, 0);
aContext.restore();
// Draw the result on what you want to show.
context.drawImage(aCanvas, 0, 0);
}
lastX = x; lastY = y;
}
var cv = document.createElement('canvas');
cv.width = 500;
cv.height = 500;
//document.body.appendChild(cv);
var ctx = cv.getContext('2d');
function checkAnswer() {
cv.width = 500;
cv.height = 500;
ctx.globalCompositeOperation = 'source-over';
ctx.drawImage(aCanvas, 0, 0);
ctx.globalCompositeOperation = 'destination-in';
ctx.drawImage(qCanvas, 0, 0);
var qData = qContext.getImageData(0, 0, 500, 500).data;
var aData = ctx.getImageData(0, 0, 500, 500).data;
var idx = 0, i, j;
var count = 0, total = 0;
for (i = 0; i < 500; ++i) {
for (j = 0; j < 500; ++j) {
if (qData[idx] !== 0) {
++total;
if (aData[idx] === qData[idx]) {
++count;
}
}
idx += 4;
}
}
console.log(count,total);
// Threshold.
if (count/total > 0.95) {
alert('Complete');
}
}
drawBgPath();
Draw();
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<canvas id="c"></canvas>
<button onclick="checkAnswer()">check</button>
&#13;