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

