A port of the Mandelbrot set: https://en.wikipedia.org/wiki/Mandelbrot_set
I coded a slow version of this in Game Maker a long time ago. I never colored it and it was very slow.
/** * https://en.wikipedia.org/wiki/Mandelbrot_set * Ported from Coding Train Lesson #21 * https://www.youtube.com/watch?v=6z7GQewK-Ks&list=PLRqwX-V7Uu6ZiZxtDDRCi6uhfTH4FilpH&index=25 * */ const WH = 700 window.onload = function() { 'use strict'; const m = new Mandelbrot() document.getElementById('min').addEventListener('change',function() { document.getElementById('minv').innerHTML = this.value m.mnzoom = ~~this.value m.loop() }) document.getElementById('max').addEventListener('change',function() { document.getElementById('maxv').innerHTML = this.value m.mxzoom = ~~this.value m.loop() }) setTimeout(()=>{m.loop()},100) } class Mandelbrot { constructor() { this.max = 100 this.infinity = 16 this.tau = Math.PI*2 this.mnzoom = ~~document.getElementById('min').value this.mxzoom = ~~document.getElementById('max').value this.pixels = [] // create the canvas let c = document.createElement('canvas') c.setAttribute('hidpi','no') c.setAttribute("width",WH) c.setAttribute("height",WH) document.getElementById('target').appendChild(c) c.width = c.offsetWidth c.height = c.offsetHeight this.ctx = c.getContext("2d") } /** * @method loop * */ loop() { const t2 = performance.now() for(let x=1;x<WH;x++) { for(let y=1;y<WH;y++) { let a = this.map(x, 0, WH, this.mnzoom, this.mxzoom) let b = this.map(y, 0, WH, this.mnzoom, this.mxzoom) let r = this.inSet(a, b) if(r === true) { this.rectangle(x,y,x,y,'#000000') }else{ r = this.componentToHex(r) this.rectangle(x,y,x,y,this.rgbToHex((r * 2) % 255,(r * 3) % 255,(r * 4) % 255)) } } } const t3 = performance.now() console.log(`Call took ${t3 - t2} milliseconds.`) } /** * @method inSet * @param {Array} a * @param {Array} b * @return {Mixed} * */ inSet(a,b) { let n = 0, z = 0, aorigin = a, borigin = b while(n < this.max) { let aa = a * a - b * b let bb = 2 * a * b a = aa + aorigin b = bb + borigin if(Math.abs(a + b) > this.infinity) { return (Math.abs(n * this.infinity) % 255) } n++ } return true } /** * @method map * @param {Number} value the incoming value to be converted * @param {Number} start1 lower bound of the value's current range * @param {Number} stop1 upper bound of the value's current range * @param {Number} start2 lower bound of the value's target range * @param {Number} stop2 upper bound of the value's target range * @param {Boolean} [withinBounds] constrain the value to the newly mapped range * @return {Number} remapped number * */ map (n, start1, stop1, start2, stop2, withinBounds) { var newval = (n - start1) / (stop1 - start1) * (stop2 - start2) + start2; if (!withinBounds) { return newval; } if (start2 < stop2) { return this.constrain(newval, start2, stop2); } else { return this.constrain(newval, stop2, start2); } } /** * @method constrain * @param {Number} n number to constrain * @param {Number} low minimum limit * @param {Number} high maximum limit * @return {Number} constrained number * */ constrain (n, low, high) { return Math.max(Math.min(n, high), low); } /** * @method makePixel * @param {Number} * @param {Number} * @param {String} * @return {Object} * */ makePixel(x,y,c) { return { x:x, y:y, c:c } } /** * @method rectangle * @param {Number} * @param {Number} * @param {Number} * @param {Number} * @param {String} * */ rectangle(x1,y1,x2,y2,c) { x1 = ~~x1 y1 = ~~y1 x2 = ~~x2 y2 = ~~y2 this.ctx.fillStyle=c this.ctx.fillRect(x1,y1,x2,y2) } /** * @method clear * */ clear() { this.ctx.save() this.ctx.setTransform(1, 0, 0, 1, 0, 0) this.ctx.clearRect(0, 0, WH, WH) this.ctx.restore() } /** * @method componentToHex * returns a color hex value from an integer * @param {Number} * @return {String} * */ componentToHex(c) { c = ~~c var hex = c.toString(16) return hex.length == 1 ? "0" + hex : hex } /** * returns a color hex value from an 3 integers * @param {Number} * @param {Number} * @param {Number} * @return {String} * */ rgbToHex(r, g, b) { return "#" + this.componentToHex(r) + this.componentToHex(g) + this.componentToHex(b) } }
Categories