БлогNot. Рисуем плазму на канве HTML с помощью Javascript

Рисуем плазму на канве HTML с помощью Javascript

Небольшой Engine для разливки плазмы.

В коде также показано как при необходимости сбросить имеющийся цикл анимации, чтобы начать новый (переменная requestId, внешняя по отношению к функциям анимации; в идеале, стоило бы сделать ещё одну обёртку над requestId, plasmaEngine и startPlasma). Для начала работы достаточно нажать кнопку "Плазма", также это можно сделать после изменения коэффициента масштабирования.

Коэффициент:

Ниже приводится исходный текст скрипта без обрамления HTML, предполагается, что он будет сохранён в кодировке Юникода UTF-8.

 <div style="text-align: center;">
  <p>
   Коэффициент: 
   <input id="divCoeff" type="number" value="16" min="2" max="99" step="1">
   <input type="button" value="Плазма!" onclick="startPlasma();">
  </p>
  <p><canvas id="canvas1"></canvas></p>
 </div>

 <script>
  let requestId = undefined;

  function plasmaEngine (id, w, h, divCoeff) {

   function createPlasma(w, h) {
    let buffer = new Array(h);
    for (let y = 0; y < h; y++) {
     buffer[y] = new Array (w);
     for (let x = 0; x < w; x++) {
      let value = Math.sin(x / divCoeff);
      value += Math.sin(y / divCoeff);
      value += Math.sin((x + y) / divCoeff);
      value += Math.sin(Math.sqrt(x * x + y * y) / divCoeff);
      value += Math.floor(divCoeff/4); // сдвиг
      value /= Math.floor(divCoeff/2); // уменьшить диапазон
      buffer[y][x] = value;
     }
    }
    return buffer;
   }

   function HSVtoRGB(h, s, v) { //HSV в RGB, функция со stackoverflow
    let r, g, b, i, f, p, q, t;
    i = Math.floor(h * 6);
    f = h * 6 - i;
    p = v * (1 - s);
    q = v * (1 - f * s);
    t = v * (1 - (1 - f) * s);
    switch (i % 6) {
     case 0: r = v; g = t; b = p; break;
     case 1: r = q; g = v; b = p; break;
     case 2: r = p; g = v; b = t; break;
     case 3: r = p; g = q; b = v; break;
     case 4: r = t; g = p; b = v; break;
     case 5: r = v; g = p; b = q; break;
    }
    return { r: Math.round(r * 255), g: Math.round(g * 255), b: Math.round(b * 255) };
   }

   function drawPlasma(w, h) {
    let img = ctx.getImageData(0, 0, w, h);
    for (let y = 0; y < h; y++) {
     for (let x = 0; x < w; x++) {
      let hue = hueShift + plasma[y][x] % 1;
      let rgb = HSVtoRGB (hue, 1, 1);
      let pos = (y * w + x) * 4;
      img.data[pos] = rgb.r;
      img.data[pos + 1] = rgb.g;
      img.data[pos + 2] = rgb.b;
     }
    }
    ctx.putImageData (img, 0, 0);
   }
 
   function animate(lastFrameTime) { //Основная функция анимации
    let time = new Date().getTime();
    let delay = 33; //задержка цикла анимации в мс
    if (lastFrameTime + delay < time) {
     hueShift = (hueShift + 0.02) % 100;
     drawPlasma (canvas.width, canvas.height);
     lastFrameTime = time;
    }
    if (requestId)  { //Сбросить старый цикл анимации, если есть!
     window.cancelAnimationFrame (requestId);
     requestId = undefined;
    }
    requestId = requestAnimationFrame (function () { animate(lastFrameTime); });
   }

   let canvas = document.getElementById(id);
   canvas.width = w;
   canvas.height = h;
   let ctx = canvas.getContext ('2d');
   let plasma = createPlasma (canvas.width, canvas.height);
   let hueShift = 0; //сдвиг оттенка
   ctx.fillRect (0, 0, canvas.width, canvas.height);
   animate (0);
  } 

  function startPlasma () {
   let d = parseInt(document.getElementById('divCoeff').value);
   if (isNaN(d) || !isFinite(d) || d<2 || d>99) {
    d = document.getElementById('divCoeff').value = 16;
   }
   plasmaEngine ('canvas1',400,400,d);
  }
 </script>
 <noscript>
  <p style="text-align: center;">Нужно включить в браузере Javascript для работы приложения</p>
 </noscript>

теги: javascript графика цвет

10.11.2020, 12:12; рейтинг: 68