Advertisement
ForrestFox

MandelBrot JS

Mar 14th, 2021
636
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Класс для рисования на canvas
  2. class game {
  3.  
  4.     constructor() {
  5.  
  6.         // Вычисление размера экрана
  7.         let win  = window, doc = document, docelem = doc.documentElement,
  8.             body = doc.getElementsByTagName('body')[0],
  9.             wx = win.innerWidth  || docelem.clientWidth || body.clientWidth,
  10.             wy = win.innerHeight || docelem.clientHeight|| body.clientHeight;
  11.  
  12.         // Установить новый canvas size
  13.         this.el     = document.getElementById('viewport');
  14.         this.el.width  = wx;
  15.         this.el.height = wy;
  16.  
  17.         this.ctx    = this.el.getContext('2d');
  18.         this.width  = wx;
  19.         this.height = wy;
  20.         this.img    = this.ctx.getImageData(0, 0, wx, wy);
  21.  
  22.         // Первоначальные значения
  23.         this.x0 = -0.75;
  24.         this.y0 = 0;
  25.         this.ms = 4 / wx;
  26.  
  27.         this.start();
  28.  
  29.         // Регистрация событий
  30.         this.el.onclick = function(e) { this.click(e); }.bind(this);
  31.         win.onkeydown   = function(e) { this.click(e); }.bind(this);
  32.     }
  33.  
  34.     start() {
  35.  
  36.         this.palette();
  37.         this.redraw();
  38.     }
  39.  
  40.     // Генератор палитры
  41.     palette() {
  42.  
  43.         let pal = [
  44.             [0,     0,   0, 128],
  45.             [128,   0, 255, 255],
  46.             [255, 255, 255, 255],
  47.         ];
  48.  
  49.         this.palbank = {};
  50.  
  51.         for (let i = 0; i < pal.length - 1; i++) {
  52.  
  53.             // Соседние цвета и расстрояние между ними
  54.             let a = pal[i], b = pal[i + 1];
  55.             let d = b[0] - a[0];
  56.  
  57.             // Вычисление интерполяции
  58.             for (let j = a[0]; j < b[0]; j++) {
  59.  
  60.                 let t = (j - a[0]) / d;
  61.                 let [r_, g_, b_] = [
  62.                     Math.floor(a[1]*(1-t) + b[1]*t),
  63.                     Math.floor(a[2]*(1-t) + b[2]*t),
  64.                     Math.floor(a[3]*(1-t) + b[3]*t)
  65.                 ];
  66.  
  67.                 this.palbank[j] = r_*65536 + g_*256 + b_;
  68.             }
  69.         }
  70.     }
  71.  
  72.     // Перерисовать окно
  73.     redraw() {
  74.  
  75.         let [w, h] = [this.width, this.height];
  76.         let [w2, h2] = [w/2, h/2];
  77.  
  78.         let time = (new Date()).getTime();
  79.         let iter = 0, cnt = 0;
  80.  
  81.         // Сам фрактал
  82.         for (let y = 0; y < h; y++)
  83.         for (let x = 0; x < w; x++) {
  84.  
  85.             let [ax, bx] = [x - w2, y - h2];
  86.  
  87.             ax = ax*this.ms + this.x0;
  88.             bx = bx*this.ms + this.y0;
  89.  
  90.             let cl = this.mandel(ax, bx);
  91.             this.pset(x, y, this.palbank[cl]);
  92.  
  93.             cnt++; iter += (1 + cl);
  94.         }
  95.  
  96.         // Прицел
  97.         for (let x = -5; x <= 5; x++) {
  98.             this.pset(w2 + x, h2, 0xff0000);
  99.             this.pset(w2, h2 + x, 0xff0000);
  100.         }
  101.  
  102.         this.flush();
  103.  
  104.         let stop = (new Date()).getTime();
  105.         this.stats({iter: iter, cnt: cnt, time: stop - time});
  106.     }
  107.  
  108.     // Вычисление фрактала Мандельброта
  109.     mandel(x, y) {
  110.  
  111.         let max = 255;
  112.         let [cx, cy] = [x, y];
  113.         for (let i = 0; i <= max; i++) {
  114.  
  115.             if (x*x + y*y > 4)
  116.                 return i;
  117.  
  118.             let x_ = x*x - y*y + cx;
  119.             let y_ = 2*x*y     + cy;
  120.             [x, y] = [x_, y_];
  121.         }
  122.  
  123.         return max;
  124.     }
  125.  
  126.     // Рисование пикселя на экране
  127.     pset(x, y, k) {
  128.  
  129.         let p = 4*(x + y * this.width);
  130.         this.img.data[p    ] =  (k >> 16) & 0xff;
  131.         this.img.data[p + 1] =  (k >>  8) & 0xff;
  132.         this.img.data[p + 2] =  (k      ) & 0xff;
  133.         this.img.data[p + 3] = ((k >> 24) & 0xff) ^ 0xff;
  134.     }
  135.  
  136.     // Обновление экрана
  137.     flush() { this.ctx.putImageData(this.img, 0, 0); }
  138.  
  139.     // Вывод статистики
  140.     stats(info) {
  141.  
  142.         let text =
  143.             "size: " + this.ms + ", coord: {" +
  144.             this.x0 + ", " + this.y0 + "}, iter: " +
  145.             info.iter + ", pixels: " + info.cnt + ", time: " + info.time + " ms";
  146.  
  147.         this.ctx.font = "20px Monospace";
  148.         this.ctx.fillStyle = "#000000";
  149.         this.ctx.fillText(text, 10, this.height - 6);
  150.         this.ctx.fillStyle = "#ffffff";
  151.         this.ctx.fillText(text, 8, this.height - 8);
  152.     }
  153.  
  154.     // Нажатие на область
  155.     click(e) {
  156.  
  157.         if (e instanceof KeyboardEvent) {
  158.  
  159.             if (e.key == '+') this.ms /= 1.5;
  160.             else if (e.key == '-') this.ms *= 1.5;
  161.  
  162.         } else if (e instanceof MouseEvent) {
  163.  
  164.             let xn = (event.offsetX - this.width  / 2),
  165.                 yn = (event.offsetY - this.height / 2);
  166.             let bt = event.button;
  167.  
  168.             this.x0 += xn * this.ms;
  169.             this.y0 += yn * this.ms;
  170.  
  171.             if (bt == 0) this.ms /= 1.5; else this.ms *= 1.5;
  172.         }
  173.  
  174.         this.redraw();
  175.     }
  176. }
  177.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement