Como criar uma ferramenta “Blob Generator” em JavaScript (Tutorial de Canvas)

Então, o que estamos fazendo?! Esse:

Estaremos nos familiarizando com os catadores de cores, os elementos da tela, as curvas. Você escolhe.

Construindo a interface

Vamos começar com uma interface mínima que consiste em:

  • Uma área de visualização contendo um elemento de tela para exibir o blob.
  • Um elemento de seletor de cores para alterar a cor do blob (nós daremos um valor padrão de um bom ga-analytics #sendElementsClickevent “> Envato Green #9cee69).
  • 2 elementos deslizantes da faixa para alterar a variação e a complexidade do blob.
  • UM download botão para salvar o blob gerado

A estrutura HTML ficará assim:

1
 class="container">
2
  
3
    

Blob Generator

4
  
5

6
   class="preview">
7
     id="canvas" width="300" height="300">
8
  
9
   class="customize-container">
10
     for="colorPicker">Color:
11
    
12
      type="color"
13
      id="colorPicker"
14
      class="color-picker"
15
      value="#9cee69"
16
    />
17

18
     class="slider-container">
19
       for="complexitySlider" class="slider-label">Complexity:
20
      
21
        type="range"
22
        id="complexitySlider"
23
        class="slider"
24
        min="3"
25
        max="12"
26
        value="6"
27
      />
28
    
29

30
     class="slider-container">
31
       for="Variation" class="slider-label">Variation:
32
      
33
        type="range"
34
        id="variation-slider"
35
        class="slider"
36
        min="0"
37
        max="100"
38
        value="50"
39
      />
40
    
41

42
     type="button" id="downloadBtn">Download Blob
43
  

Estilando com CSS

Hora de Snazz Things Up. Aqui estão os estilos base para melhorar o design da interface do usuário.

1
body {
2
    display: flex;
3
    flex-direction: column;
4
    align-items: center;
5
    min-height: 100vh;
6
    background-color: #f5f5f5;
7
    font-family: "DM Mono", monospace;
8
  }
9
  .container {
10
    width: 90%;
11
    max-width: 600px;
12
    height: fit-content;
13
    display: flex;
14
    flex-direction: column;
15
    align-items: center;
16
    border-radius: 20px;
17
    background: white;
18
  }
19
  header {
20
    width: 100%;
21
    text-align: center;
22
  }

Área de visualização:

1
  .preview {
2
    position: relative;
3
    width: 350px;
4
    height: 300px;
5
    display: flex;
6
    align-items: center;
7
    justify-content: center;
8
    margin: 1rem 0;
9
    overflow: hidden;
10
    border: 2px dashed #e0e0e0;
11
    border-radius: 8px;
12
  }

Personalize o contêiner

Temos um contêiner personalizado que abriga o seletor de cores e os elementos de alcance. Para garantir que esses elementos estejam alinhados ordenadamente, defina uma largura máxima para o contêiner personalizado.

1
.customize-container {
2
 width: 100%;
3
 max-width: 300px;
4
}

Seletor de cores e elementos de alcance

Adicione esses estilos para garantir a consistência nos elementos do seletor de cores e do alcance.

1
input[type="color"] {
2
    width: 100%;
3
    height: 40px;
4
    border: none;
5
    padding: 4px;
6
    border-radius: 8px;
7
    cursor: pointer;
8
  }
9
  .slider-label,
10
  .customize-container,
11
  p {
12
    display: block;
13
    margin-bottom: 8px;
14
    font-size: 0.75rem;
15
    color: #403e3e;
16
  }
17

18
  .slider {
19
    width: 100%;
20
    height: 4px;
21
    background: #e0e0e0;
22
    border-radius: 2px;
23
    appearance: none;
24
    outline: none;
25
  }
26
  .slider-container {
27
    margin-bottom: 5px;
28
    width: 300px;
29
    min-width: 300px;
30
  }

Para garantir também a consistência no aparecimento de controles deslizantes em vários navegadores, vamos aplicar estilos personalizados para navegadores baseados em cromo e Firefox. Nos navegadores de cromo, usamos o -webkit-slider-thumb pseudo-elemento, enquanto estiver no Firefox, usamos o -moz-range-thumb Pseudo-elemento.

1
.slider {
2
    width: 100%;
3
    height: 4px;
4
    background: #e0e0e0;
5
    border-radius: 2px;
6
    appearance: none;
7
    outline: none;
8
  }
9
  .slider-container {
10
    margin-bottom: 5px;
11
    width: 300px;
12
    min-width: 300px;
13
  }
14
  .slider::-webkit-slider-thumb {
15
    appearance: none;
16
    width: 16px;
17
    height: 16px;
18
    background: #147ccb;
19
    border-radius: 50%;
20
    cursor: pointer;
21
    transition: transform 0.2s;
22
  }
23

24
  .slider::-moz-range-thumb {
25
    width: 16px;
26
    height: 16px;
27
    background: #147ccb;
28
    border-radius: 50%;
29
    cursor: pointer;
30
    border: none;
31
    transition: transform 0.2s;
32
  }

Por fim, o botão de download terá os seguintes estilos.

1
#downloadBtn {
2
    margin-top: 10px;
3
    color: white;
4
    background-color: #147ccb;
5
    border: none;
6
    padding: 10px 20px;
7
    border-radius: 5px;
8
    cursor: pointer;
9
}

Geração de blob com javascript

Vamos mergulhar na lógica de criar blobs. Mas primeiro, vamos obter todos os elementos que precisam de manipulação.

1
const canvas = document.getElementById("canvas");
2
const variationSlider = document.getElementById("variation-slider");
3
const complexitySlider = document.getElementById("complexitySlider");
4
const downloadBtn = document.getElementById("downloadBtn");
5
const colorPicker = document.getElementById("colorPicker");

Desenho com a API de tela

A API de tela é uma ferramenta poderosa para criar e manipular gráficos 2D no navegador. Ele nos permite desenhar formas diferentes, desde linhas básicas, círculos e retângulos a ainda mais complexos, como hexágonos e bolhas.

Para começar, precisamos acessar o contexto 2D da tela, que fornece as propriedades e métodos necessários para o desenho.

1
const ctx = canvas.getContext("2d");

O contexto atua como a superfície na qual os gráficos são desenhados.

Alguns dos métodos comuns para desenhar a API de tela incluem:

  • lineTo(x,y): Este método desenha uma linha da posição atual para as coordenadas X e Y especificadas.
  • rect(x,y, width, height): Este método desenha um retângulo na posição especificada com as dimensões especificadas.
  • quadraticCurveTo(cp1x, cp1y, x, y ): Este método cria uma curva suave usando CP1X e CP1Y como ponto de controle e x e y como o ponto final.
  • bezierCurveTo(cp1x, cp1x,cp1x,cp1x, x,y): Este método desenha uma curva nítida usando os pontos centrais e finais especificados (x, y).

O quadraticCurveTo O método é perfeito para criar formas orgânicas suaves. Ao conectar vários pontos aleatórios com curvas, podemos gerar bolhas de complexidade e forma variadas.

Por exemplo, aqui está o código necessário para gerar uma curva simples de um ponto para outro.

1
ctx.moveTo(100, 100);
2
ctx.quadraticCurveTo(200, 50, 300, 100);

Os pontos (100.100) representam o ponto de partida e a curva é atraída para (300.100) com (200, 50) como ponto de controle. O ponto de controle são os pontos para os quais a curva puxa.

Aqui está a curva gerada:

Para esclarecer as coisas, aqui está uma ilustração que mostra como o ponto de controle puxa a curva em direção a ele.

Gerar blobs com método quadraticcurveto

Crie uma função chamada createBlob.

1
const createBlob = () => {}

Dentro desta função, faremos o seguinte:

  • Limpe a tela
  • Gere uma matriz de pontos com base em valores de variação e complexidade.
  • Conecte os pontos usando curvas com o quadraticCurveTo método.

Defina um tamanho padrão para o blob e obtenha os valores de complexidade e variação atualmente selecionados.

1
const createBlob = () => {
2
    const color = colorPicker.value;
3
    const size = 100;
4
    const complexity = parseInt(complexitySlider.value);
5
    const variation = parseInt(variationSlider.value) / 100;
6

7
}

Antes de começarmos a desenhar, limpe a tela, carregue a cor atualmente selecionada e redefine o caminho atual para garantir que nenhum desenho esteja no caminho ativo do contexto.

1
ctx.clearRect(0, 0, canvas.width, canvas.height);
2
ctx.fillStyle = color;
3
ctx.beginPath();

Defina o centro da tela para garantir que o blob esteja posicionado simetricamente.

1
const centerX = canvas.width / 2;
2
const centerY = canvas.height / 2;

Definir um valor angleStep Isso representa a separação em radianos entre cada ponto na bolha. Este valor define a forma do blob. Um valor de complexidade mais alto resulta em mais pontos ao redor do centro, tornando a bobagem mais detalhada. Valores menores resultarão em uma bolha de aparência quase circular.

1
 const angleStep = (Math.PI * 2) / complexity;

Esse valor, como você pode ver, é calculado dividindo o círculo completo (2 *radianos PI) pelo valor da complexidade. Em seguida, crie uma matriz vazia chamada pontos para armazenar as coordenadas do blob.

Crie a para loop para iterar sobre o valor de complexityque determina o número de pontos na bolha. Em cada iteração gerar x e y coordenadas para cada ponto com base em um gerado aleatoriamente radius. Em seguida, empurre cada par de coordenadas para o points variedade. Em qualquer ponto, a matriz conterá valores diferentes para x e y que, quando desenhados e conectados, formará uma forma de blob.

1
const points = [];
2
for (let i = 0; i < complexity; i++) {
3
  const angle = i * angleStep;
4
  const radius = size * (1 + (Math.random() - 0.5) * variation);
5
  const x = centerX + radius * Math.cos(angle);
6
  const y = centerY + radius * Math.sin(angle);
7
  points.push([x, y]);
8
}

Para garantir uma transição suave no início e nos pontos de extremidade de qualquer caminho, precisamos mover o ponto de partida para o ponto médio dos primeiros e os últimos pontos;

1
ctx.moveTo(
2
  (points[0].x + points[points.length - 1].x) / 2,
3
  (points[0].y + points[points.length - 1].y) / 2
4
);

Finalmente desenhe o bolhas com quadraticCurveTo método.

1
for (let i = 0; i < points.length; i++) {
2
  const [x1, y1] = points[i];
3
  const [x2, y2] = points[(i + 1) % points.length];
4
  const midX = (x1 + x2) / 2;
5
  const midY = (y1 + y2) / 2;
6
  ctx.quadraticCurveTo(x1, y1, midX, midY);
7
}

Aqui estamos usando as coordenadas no points matriz para criar curvas que se conectam entre todos os pontos. Para garantir curvas suaves entre os pontos, definimos um ponto médio entre cada par de pontos consecutivos. Este ponto médio atua como o controle apontar garantir que a curva seja puxada suavemente em direção ao centro da linha que conecta o 2 pontos.

E como o ponto médio é colocado entre 2 pontos, isso ajuda a formar bolhas arredondadas. Finalmente, invocar o createBlob função

Invocando o createBlob A função desenhará uma bolha que combine a cor selecionada, variation e complexity valores. Quando esses valores mudam, a forma do blob também mudará.

1
colorPicker.addEventListener("input", createBlob);
2
variationSlider.addEventListener("input", createBlob);
3
complexitySlider.addEventListener("input", createBlob);

Aqui está o código final para o createBlob função.

1
const createBlob = () => {
2
  const color = colorPicker.value;
3
  const size = 100;
4
  const complexity = parseInt(complexitySlider.value);
5
  const variation = parseInt(variationSlider.value) / 100;
6

7
  ctx.clearRect(0, 0, canvas.width, canvas.height);
8
  ctx.fillStyle = color;
9
  ctx.beginPath();
10

11
  const centerX = canvas.width / 2;
12
  const centerY = canvas.height / 2;
13
  const angleStep = (Math.PI * 2) / complexity;
14

15
  const points = [];
16

17
  for (let i = 0; i < complexity; i++) {
18
    const angle = i * angleStep;
19
    const radius = size * (1 + (Math.random() - 0.5) * variation);
20
    const x = centerX + radius * Math.cos(angle);
21
    const y = centerY + radius * Math.sin(angle);
22
    points.push([x, y]);
23
  }
24

25
  ctx.moveTo(
26
    (points[0].x + points[points.length - 1].x) / 2,
27
    (points[0].y + points[points.length - 1].y) / 2
28
  );
29

30
  for (let i = 0; i < points.length; i++) {
31
    const [x1, y1] = points[i];
32
    const [x2, y2] = points[(i + 1) % points.length];
33
    const midX = (x1 + x2) / 2;
34
    const midY = (y1 + y2) / 2;
35
    ctx.quadraticCurveTo(x1, y1, midX, midY);
36
  }
37

38
  ctx.closePath();
39
  ctx.fill();
40
};

Baixe o Blob

Agora que podemos alterar a forma, a cor e a complexidade do blob, vamos adicionar a capacidade de baixar o blob para uso. Para conseguir isso, adicionaremos um ouvinte de evento de clique no botão de download. Quando o botão for clicado, o blob gerado será baixado.

Felizmente, a API de tela fornece uma maneira simples de baixar toda a tela usando o canvas.toDataURL. Este método converterá o conteúdo da tela em um URL de dados da imagem.

1
downloadBtn.addEventListener("click", () => {
2
const link = document.createElement("a");
3
const dataURL = canvas.toDataURL("image/png");
4
link.download = "blob/png";
5
link.href = dataURL;
6
link.click();

E terminamos!

Aqui está a demonstração final de trabalho.

Este gerador de blob fornecerá a flexibilidade de criar e personalizar Blobs para atender às suas necessidades criativas. Mas, além disso, este tem sido um exercício detalhado e aprofundado em JavaScript-espero que você tenha aprendido alguma coisa!

Deixe uma resposta