我试图让用户通过在画布上绘制半透明线条的“绘画”工具在其上绘画来指定区域。其目的是为将在画布下方绘制的图像指定“掩码”。
这是我到目前为止所尝试的:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var canvasPos = canvas.getBoundingClientRect();
var dragging = false;
drawImage();
$(canvas).mousedown(mouseDown);
$(canvas).mouseup(mouseUp);
$(canvas).mousemove(mouseMove);
function drawImage() {
var img = new Image();
img.src = 'http://img2.timeinc.net/health/img/web/2013/03/slides/cat-allergies-400x400.jpg';
img.onload = function () {
ctx.drawImage(img, 0, 0);
};
}
function mouseDown(e) {
var pos = getCursorPosition(e);
dragging = true;
ctx.strokeStyle = 'rgba(0, 100, 0, 0.25)';
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.lineWidth = 15;
ctx.beginPath();
ctx.moveTo(pos.x, pos.y);
}
function mouseUp(e) {
dragging = false;
}
function mouseMove(e) {
var pos, i;
if (!dragging) {
return;
}
pos = getCursorPosition(e);
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
}
function getCursorPosition(e) {
return {
x: e.clientX - canvasPos.left,
y: e.clientY - canvasPos.top
};
}
此示例代码的问题在于,绘制的后续像素会使不透明度变得越来越不可见。我认为这是因为这条线的宽度为15像素(但我希望它宽一点)。
我该如何解决这个问题?
谢谢!
答案 0 :(得分:9)
问题是你一次又一次地画出整条道路:
function mouseMove(e) {
...
ctx.stroke(); // Draws whole path which begins where mouseDown happened.
}
您必须只绘制路径的新段(http://jsfiddle.net/jF9a6/)。然后......你遇到了15px线宽的问题。
那么如何解决这个问题?我们必须像你一样立刻绘制线条,但避免在现有线条上绘制。以下是代码:http://jsfiddle.net/yfDdC/
最大的变化是paths
数组。它包含是的,路径:-)路径是存储在mouseDown
和mouseMove
函数中的点数组。在mouseDown函数中创建了新路径:
paths.push([pos]); // Add new path, the first point is current pos.
在mouseMove中,将当前鼠标位置添加到paths
数组中的最后一个路径并刷新图像。
paths[paths.length-1].push(pos); // Append point tu current path.
refresh();
refresh()
函数清除整个画布,再次绘制猫并绘制每条路径。
function refresh() {
// Clear canvas and draw the cat.
ctx.clearRect(0, 0, ctx.width, ctx.height);
if (globImg)
ctx.drawImage(globImg, 0, 0);
for (var i=0; i<paths.length; ++i) {
var path = paths[i];
if (path.length<1)
continue; // Need at least two points to draw a line.
ctx.beginPath();
ctx.moveTo(path[0].x, path[0].y);
...
for (var j=1; j<path.length; ++j)
ctx.lineTo(path[j].x, path[j].y);
ctx.stroke();
}
}
答案 1 :(得分:2)
替代方法是将路径绘制为实体并使整个画布透明。当然,您必须将图像移出画布并将其堆叠在下面。您可以在此处找到代码:http://jsfiddle.net/fP297/
<div style="position: relative; border: 1px solid black; width: 400px; height: 400px;">
<img src='cat.jpg' style="position: absolute; z-order: 1;">
<canvas id="canvas" width="400" height="400" style="position: absolute; z-order: 2; opacity: 0.25;"></canvas>
</div>
通过绘制实线,您不必担心多次绘制区域,因此您不必担心删除图像并重新绘制所有内容。
答案 2 :(得分:0)
我同意 Strix。 在这里你会找到一个基于他的回答的例子。
<input type="text" class="password2" id="password" name="password" minlength="8" oninput="myFunction()"><br><br>
//
let mouseDownStartPosition: number | null = null;
let mouseDownLastPaintedPosition: number | null = null;
const drawRect = (canvas: HTMLCanvasElement, pixelX0 : number, pixelX1: number) => {
const context: CanvasRenderingContext2D = canvas.getContext('2d')!;
context.globalAlpha = 0.3;
context.fillStyle = "#bada55";
context.fillRect(pixelX0, 0, pixelX1 - pixelX0, context.canvas.height);
context.globalAlpha = 1.0;
}
const onCanvasMouseDown = (e: { clientX: number; }) => {
const canvas: HTMLCanvasElement = canvasRef.current!;
let rect = canvas.getBoundingClientRect();
mouseDownStartPosition = e.clientX - rect.left;
mouseDownLastPaintedPosition = mouseDownStartPosition;
}
const onCanvasMouseMove = (e: { clientX: number; }) => {
if (mouseDownLastPaintedPosition == null) return;
const canvas: HTMLCanvasElement = canvasRef.current!;
let rect = canvas.getBoundingClientRect();
const mouseCurrentPosition = e.clientX - rect.left;
drawRect(canvas, Math.min(mouseDownLastPaintedPosition, mouseCurrentPosition), Math.max(mouseDownLastPaintedPosition, mouseCurrentPosition));
mouseDownLastPaintedPosition = mouseCurrentPosition;
}
const onCanvasMouseUp = () => {
mouseDownStartPosition = null;
mouseDownLastPaintedPosition = null;
}