JS Canvas - 无法绘制流畅的线条
JS Canvas - Can't draw smooth lines
我一直试图在我的 canvas 上画出流畅的线条,但我没有成功。我试过将 lineCap 设置为圆形,使用 quadratic 而不是 lineTo,但没有任何效果。
在鼠标移动的同时,将鼠标的位置记录到一个数组中,然后遍历数组绘制线条。
**JavaScript**
// GLOBAL VARIABLES - CONTAINER/CANVAS
var wContainer = document.getElementById('Whiteboard_Container');
var layerGrid = document.getElementById('LayerGrid');
var lgctx = layerGrid.getContext('2d');
var layer1 = document.getElementById('Layer1');
var l1ctx = layer1.getContext('2d');
// GLOBAL VARIABLES - MOUSE/TOUCH
var cursorPos = { top: 0, left: 0, x: 0, y: 0 };
var cursorType = 'mouse'; // USED TO CONTROL MOUSE/TOUCH
var dragging = false; // SETS/STOPS DRAGGING CANVAS
var dragLock = false; // USED TO PREVENT ACCIDENTAL DRAGGING (esp. touch)
// GLOBAL VARIABLES - DRAWING
var layer = 'LAYER1';
var vectors = [];
// MOUSE EVENT LISTENERS
layer1.addEventListener('mousedown', mouseDown);
layer1.addEventListener('mouseup', mouseUp);
// TOUCH EVENT LISTENERS
layer1.addEventListener('touchstart', touchDown);
layer1.addEventListener('touchend', touchUp);
// INITIALISER
function init()
{
resize();
// SET PEN STYLE
lgctx.strokeStyle = 'rgba(230, 230, 230, 1)';
lgctx.lineWidth = 1;
lgctx.lineCap = 'round';
lgctx.lineJoin = 'round';
// SET PEN STYLE
l1ctx.strokeStyle = 'rgba(0, 0, 0, 1)';
l1ctx.lineWidth = 10;
l1ctx.lineCap = 'round';
l1ctx.lineJoin = 'round';
}
init();
// AUTO SIZE THE CANVAS
function resize()
{
// SET THE CANVAS SIZE
layerGrid.width = window.innerWidth * 4;
layerGrid.height = window.innerHeight * 4;
layer1.height = window.innerHeight * 4;
layer1.width = window.innerWidth * 4;
layer1.height = window.innerHeight * 4;
}
// MOUSE DOWN
function mouseDown(e)
{
// Set cursor type
cursorType = 'mouse';
// EMPTY CURRENT VECTOR LIST
vectors = [];
vectors.length = 0;
if(e.button == 0) // LEFT MOUSE CLICK
{
layer1.addEventListener('mousemove', setVectors);
}
else if(e.button == 2 && dragLock == false) // RIGHT MOUSE CLICK
{
dragging = true;
layer1.addEventListener('mousemove', canvasDrag);
// SET START SCROLL POSITION
cursorPos.top = wContainer.scrollTop;
cursorPos.left = wContainer.scrollLeft;
// SET CURSOR POSITION
cursorPos.x = e.clientX;
cursorPos.y = e.clientY;
}
}
// MOUSE UP
function mouseUp(e)
{
// PREVENT DRAGGING & REMOVE GRID
dragging = false;
layer1.removeEventListener('mousemove', canvasDrag);
layer1.removeEventListener('mousemove', setVectors);
removeGrid();
}
// TOUCH DOWN
function touchDown(e)
{
e.preventDefault();
// Set cursor type
cursorType = 'touch';
// EMPTY CURRENT VECTOR LIST
vectors = [];
vectors.length = 0;
if(e.touches.length == 1) // SINGLE TOUCH
{
layer1.addEventListener('touchmove', setVectors);
}
else if(e.touches.length > 1 && dragLock == false) // MULTI-TOUCH
{
dragging = true;
layer1.addEventListener('touchmove', canvasDrag);
// SET START SCROLL POSITION
cursorPos.top = wContainer.scrollTop;
cursorPos.left = wContainer.scrollLeft;
// SET CURSOR POSITION
cursorPos.x = e.touches[0].clientX;
cursorPos.y = e.touches[0].clientY;
}
}
// TOUCH UP
function touchUp(e)
{
// PREVENT DRAGGING & REMOVE GRID
dragging = false;
layer1.removeEventListener('mousemove', canvasDrag);
layer1.removeEventListener('touchmove', setVectors);
removeGrid();
}
// HANDLE MOVEMENT
function canvasDrag(e)
{
if(dragging == true && cursorType == 'mouse') // MOUSE DRAG
{
// DRAW GRID AS GUIDANCE
drawGrid();
const dx = e.clientX - cursorPos.x;
const dy = e.clientY - cursorPos.y;
wContainer.scrollTop = cursorPos.top - dy;
wContainer.scrollLeft = cursorPos.left - dx;
}
else if(dragging == true && cursorType == 'touch' && e.touches.length > 1) // TOUCH DRAG
{
// DRAW GRID AS GUIDANCE
drawGrid();
const dx = e.touches[0].clientX - cursorPos.x;
const dy = e.touches[0].clientY - cursorPos.y;
wContainer.scrollTop = cursorPos.top - dy;
wContainer.scrollLeft = cursorPos.left - dx;
}
}
// SET VECTORS
function setVectors(e)
{
if(cursorType == 'mouse') // MOUSE DRAW
{
// Set the drawing vectors
vectors.push({x:e.clientX + wContainer.scrollLeft, y:e.clientY + wContainer.scrollTop});
}
else if(cursorType == 'touch' && e.touches.length == 1) // ONLY ALLOW IF SINGLE TOUCH
{
// Set the drawing vectors
vectors.push({x:e.touches[0].clientX + wContainer.scrollLeft, y:e.touches[0].clientY + wContainer.scrollTop});
}
// Draw the path, based on the vectors array
drawVectors();
}
// DRAW VECTORS
function drawVectors()
{
l1ctx.beginPath();
//l1ctx.clearRect(0, 0, layer1.width, layer1.height);
for(var i = 0; i < vectors.length - 2; i++)
{
var xc = (vectors[i].x + vectors[i + 1].x) / 2;
var yc = (vectors[i].y + vectors[i + 1].y) / 2;
l1ctx.quadraticCurveTo(vectors[i].x, vectors[i].y, xc, yc);
//l1ctx.lineTo(vectors[i].x, vectors[i].y);
}
l1ctx.stroke();
}
// DRAW GRID
function drawGrid()
{
lgctx.beginPath();
for(var i = 0; i < layer1.width; i = i + 100)
{
lgctx.moveTo(i, 0);
lgctx.lineTo(i, layer1.height);
}
lgctx.moveTo(0, 0);
for(var i = 0; i < layer1.height; i = i + 100)
{
lgctx.moveTo(0, i);
lgctx.lineTo(layer1.width, i);
}
lgctx.stroke();
lgctx.closePath();
}
// REMOVE GRID
function removeGrid()
{
lgctx.clearRect(0, 0, layerGrid.width, layerGrid.height);
}
第一行是它的绘制方式,第二行是我试图让它出现的方式:
Line comparison
这是相当大的代码块,因此很难给出准确的解决方案,但归根结底,您需要 anti-aliasing。尝试找到其中包含该术语的一些函数或属性。如果没有,则必须手动实施。
你永远不会清除你的 l1ctx
上下文。
所以你总是在以前的线上画新线并取消抗锯齿。
只需在drawVectors
的开头添加一个clearRect
调用即可。
我一直试图在我的 canvas 上画出流畅的线条,但我没有成功。我试过将 lineCap 设置为圆形,使用 quadratic 而不是 lineTo,但没有任何效果。
在鼠标移动的同时,将鼠标的位置记录到一个数组中,然后遍历数组绘制线条。
**JavaScript**
// GLOBAL VARIABLES - CONTAINER/CANVAS
var wContainer = document.getElementById('Whiteboard_Container');
var layerGrid = document.getElementById('LayerGrid');
var lgctx = layerGrid.getContext('2d');
var layer1 = document.getElementById('Layer1');
var l1ctx = layer1.getContext('2d');
// GLOBAL VARIABLES - MOUSE/TOUCH
var cursorPos = { top: 0, left: 0, x: 0, y: 0 };
var cursorType = 'mouse'; // USED TO CONTROL MOUSE/TOUCH
var dragging = false; // SETS/STOPS DRAGGING CANVAS
var dragLock = false; // USED TO PREVENT ACCIDENTAL DRAGGING (esp. touch)
// GLOBAL VARIABLES - DRAWING
var layer = 'LAYER1';
var vectors = [];
// MOUSE EVENT LISTENERS
layer1.addEventListener('mousedown', mouseDown);
layer1.addEventListener('mouseup', mouseUp);
// TOUCH EVENT LISTENERS
layer1.addEventListener('touchstart', touchDown);
layer1.addEventListener('touchend', touchUp);
// INITIALISER
function init()
{
resize();
// SET PEN STYLE
lgctx.strokeStyle = 'rgba(230, 230, 230, 1)';
lgctx.lineWidth = 1;
lgctx.lineCap = 'round';
lgctx.lineJoin = 'round';
// SET PEN STYLE
l1ctx.strokeStyle = 'rgba(0, 0, 0, 1)';
l1ctx.lineWidth = 10;
l1ctx.lineCap = 'round';
l1ctx.lineJoin = 'round';
}
init();
// AUTO SIZE THE CANVAS
function resize()
{
// SET THE CANVAS SIZE
layerGrid.width = window.innerWidth * 4;
layerGrid.height = window.innerHeight * 4;
layer1.height = window.innerHeight * 4;
layer1.width = window.innerWidth * 4;
layer1.height = window.innerHeight * 4;
}
// MOUSE DOWN
function mouseDown(e)
{
// Set cursor type
cursorType = 'mouse';
// EMPTY CURRENT VECTOR LIST
vectors = [];
vectors.length = 0;
if(e.button == 0) // LEFT MOUSE CLICK
{
layer1.addEventListener('mousemove', setVectors);
}
else if(e.button == 2 && dragLock == false) // RIGHT MOUSE CLICK
{
dragging = true;
layer1.addEventListener('mousemove', canvasDrag);
// SET START SCROLL POSITION
cursorPos.top = wContainer.scrollTop;
cursorPos.left = wContainer.scrollLeft;
// SET CURSOR POSITION
cursorPos.x = e.clientX;
cursorPos.y = e.clientY;
}
}
// MOUSE UP
function mouseUp(e)
{
// PREVENT DRAGGING & REMOVE GRID
dragging = false;
layer1.removeEventListener('mousemove', canvasDrag);
layer1.removeEventListener('mousemove', setVectors);
removeGrid();
}
// TOUCH DOWN
function touchDown(e)
{
e.preventDefault();
// Set cursor type
cursorType = 'touch';
// EMPTY CURRENT VECTOR LIST
vectors = [];
vectors.length = 0;
if(e.touches.length == 1) // SINGLE TOUCH
{
layer1.addEventListener('touchmove', setVectors);
}
else if(e.touches.length > 1 && dragLock == false) // MULTI-TOUCH
{
dragging = true;
layer1.addEventListener('touchmove', canvasDrag);
// SET START SCROLL POSITION
cursorPos.top = wContainer.scrollTop;
cursorPos.left = wContainer.scrollLeft;
// SET CURSOR POSITION
cursorPos.x = e.touches[0].clientX;
cursorPos.y = e.touches[0].clientY;
}
}
// TOUCH UP
function touchUp(e)
{
// PREVENT DRAGGING & REMOVE GRID
dragging = false;
layer1.removeEventListener('mousemove', canvasDrag);
layer1.removeEventListener('touchmove', setVectors);
removeGrid();
}
// HANDLE MOVEMENT
function canvasDrag(e)
{
if(dragging == true && cursorType == 'mouse') // MOUSE DRAG
{
// DRAW GRID AS GUIDANCE
drawGrid();
const dx = e.clientX - cursorPos.x;
const dy = e.clientY - cursorPos.y;
wContainer.scrollTop = cursorPos.top - dy;
wContainer.scrollLeft = cursorPos.left - dx;
}
else if(dragging == true && cursorType == 'touch' && e.touches.length > 1) // TOUCH DRAG
{
// DRAW GRID AS GUIDANCE
drawGrid();
const dx = e.touches[0].clientX - cursorPos.x;
const dy = e.touches[0].clientY - cursorPos.y;
wContainer.scrollTop = cursorPos.top - dy;
wContainer.scrollLeft = cursorPos.left - dx;
}
}
// SET VECTORS
function setVectors(e)
{
if(cursorType == 'mouse') // MOUSE DRAW
{
// Set the drawing vectors
vectors.push({x:e.clientX + wContainer.scrollLeft, y:e.clientY + wContainer.scrollTop});
}
else if(cursorType == 'touch' && e.touches.length == 1) // ONLY ALLOW IF SINGLE TOUCH
{
// Set the drawing vectors
vectors.push({x:e.touches[0].clientX + wContainer.scrollLeft, y:e.touches[0].clientY + wContainer.scrollTop});
}
// Draw the path, based on the vectors array
drawVectors();
}
// DRAW VECTORS
function drawVectors()
{
l1ctx.beginPath();
//l1ctx.clearRect(0, 0, layer1.width, layer1.height);
for(var i = 0; i < vectors.length - 2; i++)
{
var xc = (vectors[i].x + vectors[i + 1].x) / 2;
var yc = (vectors[i].y + vectors[i + 1].y) / 2;
l1ctx.quadraticCurveTo(vectors[i].x, vectors[i].y, xc, yc);
//l1ctx.lineTo(vectors[i].x, vectors[i].y);
}
l1ctx.stroke();
}
// DRAW GRID
function drawGrid()
{
lgctx.beginPath();
for(var i = 0; i < layer1.width; i = i + 100)
{
lgctx.moveTo(i, 0);
lgctx.lineTo(i, layer1.height);
}
lgctx.moveTo(0, 0);
for(var i = 0; i < layer1.height; i = i + 100)
{
lgctx.moveTo(0, i);
lgctx.lineTo(layer1.width, i);
}
lgctx.stroke();
lgctx.closePath();
}
// REMOVE GRID
function removeGrid()
{
lgctx.clearRect(0, 0, layerGrid.width, layerGrid.height);
}
第一行是它的绘制方式,第二行是我试图让它出现的方式: Line comparison
这是相当大的代码块,因此很难给出准确的解决方案,但归根结底,您需要 anti-aliasing。尝试找到其中包含该术语的一些函数或属性。如果没有,则必须手动实施。
你永远不会清除你的 l1ctx
上下文。
所以你总是在以前的线上画新线并取消抗锯齿。
只需在drawVectors
的开头添加一个clearRect
调用即可。