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.