Acredito que todos deveriam ter encontrado essa necessidade ao aprender o canvas ou usá-lo no desenvolvimento de projetos: implementar um gadget de bloco de desenho que possa ser escrito.
Bem, acredito que para crianças que estão mais familiarizadas com o canvas, isso pode ser feito com apenas algumas dezenas de linhas de código. A demonstração a seguir é um exemplo simples:
<!DOCTYPE html><html><head> <title>Demonstração do Sketchpad</title> <style type=text/css> canvas { border: 1px azul sólido } </style></head><body> <canvas; id=canvas width=800 height=500></canvas> <script type=text/javascript> let isDown = false; document.querySelector('#canvas'); const ctx = canvas.getContext('2d'); // Definir cor da linha ctx.strokeStyle = 'red'; .lineCap = 'redondo'; canvas.addEventListener('mousedown', para baixo, falso); mover, falso); canvas.addEventListener('mouseup', up, false); canvas.addEventListener('mouseout', up, false); função down(evt) { isDown = true; move(evt) { if (!isDown) return; const endPoint = getPos(evt); up(evt) { if (!isDown) return; const endPoint = getPos(evt); drawLine(beginPoint, endPoint = null; function getPos(evt) { return { x: evt.clientX, y: evt.clientY } } function drawLine(beginPoint, endPoint) { ctx.beginPath(); ctx.moveTo(beginPoint.x, startPoint.y); ctx.lineTo(endPoint.x, endPoint.y); >
Sua lógica de implementação também é muito simples:
mousedown
, mouseup
e mousemove
, e também criamos uma variável isDown
;mousedown
), defina isDown
como true
, e quando o usuário coloca o mouse ( mouseup
), defina-o como false
. A vantagem disso é que pode determinar se o usuário está atualmente em um estado de desenho. ;mousemove
Se e somente se isDown
for true
(ou seja, no estado de escrita), o ponto atual será conectado e desenhado com o ponto anterior por meio do método lineTo
do. tela;Através das etapas acima, podemos realizar a função básica da prancheta. No entanto, as coisas não são tão simples. Os sapatos infantis cuidadosos podem encontrar um problema muito sério - as linhas desenhadas dessa forma são irregulares e não são suaves o suficiente, e você quanto mais rápido você. desenhar, mais forte será a sensação de linhas quebradas. O desempenho é mostrado abaixo:
Por que isso está acontecendo? Análise de problemasAs principais razões para este fenômeno são:
Conectamos os pontos usando o método lineTo
do canvas. O que conecta dois pontos adjacentes é uma linha reta, não uma curva, então o que é desenhado desta forma é uma polilinha;
Limitado pela frequência de coleta de eventos mousemove
do navegador, todos sabem que durante mousemove
, o navegador coleta as coordenadas do mouse atual a cada curto período de tempo. Portanto, quanto mais rápido o mouse se move, maior é a distância entre os dois pontos adjacentes coletados. longe, mais óbvia será a sensação de linhas dobradas;
Na verdade, existem maneiras de desenhar curvas suaves. Se lineTo
não for confiável, podemos usar outra API de desenho de canvas - quadraticCurveTo
, que é usada para desenhar curvas quadráticas de Bezier.
curva bézier quadrática
quadraticCurveTo(cp1x, cp1y, x, y)
Chamar quadraticCurveTo
requer quatro parâmetros cp1x
e cp1y
que descrevem os pontos de controle, enquanto x
e y
são os pontos finais da curva:
Informações mais detalhadas podem ser encontradas no MDN
Como queremos usar uma curva de Bézier, é óbvio que nossos dados não são suficientes. Para descrever completamente uma curva de Bézier quadrática, precisamos: ponto inicial, ponto de controle e ponto final.
Existe um algoritmo muito inteligente que pode nos ajudar a obter essas informações
Algoritmo para obtenção de pontos-chave quadráticos de BezierEste algoritmo não é difícil de entender. Deixe-me dar um exemplo diretamente:
Suponha que coletemos um total de 6 coordenadas do mouse em uma pintura, ou seja A, B, C, D, E, F
, pegue os três pontos anteriores A, B, C
, calcule o ponto médio B1
de B
e C
, e use A
é; o ponto inicial, B
é o ponto de controle B1
é o ponto final. Use quadraticCurveTo
para desenhar um segmento de curva quadrática de Bézier;
A seguir, calcule o ponto médio C1
entre os pontos C
e D
e continue a desenhar a curva com B1
como ponto inicial, C
como ponto de controle e C1
como ponto final;
O desenho continua por analogia Quando o último ponto F
é alcançado, a curva de Bézier termina com D1
, o ponto médio de D
e E
, como ponto inicial, E
como ponto de controle e F
como ponto final.
OK, o algoritmo é assim, então atualizaremos o código existente com base neste algoritmo:
let isDown = false;let points = [];let beginPoint = null;const canvas = document.querySelector('#canvas');const ctx = canvas.getContext('2d');//Definir a cor da linha ctx.strokeStyle = 'vermelho';ctx.lineWidth = 1;ctx.lineJoin = 'redondo';ctx.lineCap = 'round';canvas.addEventListener('mousedown', down, false);canvas.addEventListener('mousemove', move, false);canvas.addEventListener('mouseup', up, false);canvas.addEventListener('mouseout' , up, false); função down(evt) { isDown = const { x, y } = getPos(evt); pontos.push({x, y}); startPoint = {x, y};}função move(evt) { if (!isDown) return; x, y}); if (pontos.comprimento > 3) { const lastTwoPoints = points.slice(-2); x: (lastTwoPoints[0].x + lastTwoPoints[1].x) / 2, y: (lastTwoPoints[0].y + lastTwoPoints[1].y) / 2, } drawLine(beginPoint, controlPoint, endPoint); BeginPoint = endPoint; }}função up(evt) { if (!isDown) return; pontos.push({x, y}); if (pontos.comprimento > 3) { const lastTwoPoints = points.slice(-2); , controlPoint, endPoint); } BeginPoint = null; isDown = false; pontos = [];}function getPos(evt) { return { x: evt.clientX, y: evt.clientY }}function drawLine(beginPoint, controlPoint, endPoint) { ctx.beginPath(); y, ponto final.x, ponto final.y); ctx.closePath();}
Com base no original, criamos uma variável points
para salvar os pontos pelos quais o mouse passou no evento mousemove
anterior. De acordo com este algoritmo, são necessários pelo menos 3 pontos para desenhar uma curva quadrática de Bézier, então só temos o. pontos em points
O desenho só começa quando o número de pontos é maior que 3. O processamento subsequente é exatamente igual a este algoritmo, então não entrarei em detalhes aqui.
Após a atualização do código, nossa curva ficou muito mais suave, conforme mostrado na figura abaixo:
Este artigo termina aqui. Espero que todos se divirtam desenhando em tela ~ Até a próxima :)
Se você estiver interessado em calçados infantis, clique aqui para seguir meu blog. Qualquer postagem nova e interessante será compartilhada aqui o mais rápido possível ~.
O texto acima é todo o conteúdo deste artigo. Espero que seja útil para o estudo de todos. Também espero que todos apoiem a Rede VeVb Wulin.