Рисуем плазму на канве 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>
10.11.2020, 12:12 [1213 просмотров]