//Create the canvas, then collect the height and width
var a, b, c, canvas, rect;
//zoomon click
var zoomOnClick = true;
//if running
var running = false;
//to prevent error during loading, make sure that
//the canvas is loaded first before calling any methods
canvas = document.getElementById("paper");
c = canvas.getContext("2d");
a = canvas.width;
b = canvas.height;
//when canvas is clicked, call drawOnClick function
canvas.onclick = function(e){
setTimeout(function(){
drawOnClick(e);
}, 10)
}
//changes the mandelbrot set based on mouse clicks
function drawOnClick(e){
rect = canvas.getBoundingClientRect()
if(zoomOnClick){
var mx = panX + (e.clientX - rect.left) / zooms;
var my = panY + (e.clientY - rect.top) / zooms;
zooms *= zf;
panX = mx - ((e.clientX - rect.left) / zooms);
panY = my - ((e.clientY - rect.top) / zooms);
}else{
var mx = panX + (e.clientX - rect.left) / zooms;
var my = panY + (e.clientY - rect.top) / zooms;
zooms /= zf;
panX = mx - ((e.clientX - rect.left) / zooms);
panY = my - ((e.clientY - rect.top) / zooms);
}
pan = (panX + 2 / zooms) - (panX - 1 / zooms);
document.getElementById("xa").value = panX;
document.getElementById("ya").value = panY;
document.getElementById("za").value = zooms;
pallete.setNumberRange(0,maxI);
if(0 < zooms && zooms < 50){
pallete.setNumberRange(0, 50);
maxI = 50;
}else if(50 < zooms && zooms < 100){
pallete.setNumberRange(0,100);
maxI = 100;
}else if(100 < zooms && zooms < 1000){
pallete.setNumberRange(0,255);
maxI = 255;
}else if(1000 < zooms && zooms < 10000){
pallete.setNumberRange(0,500);
maxI = 500;
}else if(10000 < zooms && zooms < 100000){
pallete.setNumberRange(0, 750);
maxI = 750;
}else if(100000 < zooms && zooms < 1000000){
pallete.setNumberRange(0, 1000);
maxI = 1000;
}else if(1000000 < zooms && zooms < 10000000){
pallete.setNumberRange(0, 2500);
maxI = 2500;
}
show();
requestAnimationFrame(abortRun);
requestAnimationFrame(startRun);
}
//when + was clicked above the canvas
function plus(){
zoomOnClick = true;
}
//same here
function minus(){
zoomOnClick = false;
}
//aborts startRun
function abortRun(){
if(running){running = false}
}
//starts calling mandelbrot
function startRun(){
//(function(){
setTimeout(function(){running = true}, 10);
setTimeout(function(){mandelbrot(zooms, panX, panY, 8)}, 10);
setTimeout(function(){mandelbrot(zooms, panX, panY, 5)}, 20);
setTimeout(function(){mandelbrot(zooms, panX, panY, 1)}, 30);
//})()
}
//in the instance, create all thngs
try{
//pan is the length of scroll
//zooms is the current number of zoom
//panX is the upper left Corner
//panY is the bottom left Corner
//zf is the increase factor in the zoom
//maxI is the total number of iteration
//per complex number
//create pallete to color mandelbrot by
//using rainbowvis.js
var pan, zooms, panX, panY, zf, maxI = 50, ticks, coloringType;
//pallete for escapeTime
var pallete = new Rainbow();
pallete.setSpectrum("#000764","#206bcb","#edffff","#ffaa00","#000200");
pallete.setNumberRange(0,maxI);
//pallete for smoothColoring
var _pallete = ["#000764","#206bcb","#edffff","#ffaa00","#000200"];
//function that draws the mandelbrot set
// based on current zoom, panX, panY and scale
/***********************MANDELBROT*********************************/
/******************************************************************/
function mandelbrot(zm, panX, panY, scale){
//cncel run in some case
if(!running){
return;
}
if(scale === 1){
running = false;
}
scale = scale || 1;
//reset ticks
ticks = 0;
//px - Canvas x
//py - canvas y
//x - real x
//y - imaginary y
var px, py, x, y;
//loop from y's, then loop all x's
for(px = 0; px < a; px+=scale){
for(py = 0; py < b; py+=scale){
//zoom factors
x0 = panX + px/zm;
y0 = panY + py/zm;
var x = 0;
var y = 0;
var i = 0;
var xtemp;
while (x*x + y*y <= 4 && i < maxI) {
ticks++
xtemp = x*x - y*y + x0
y = 2*x*y + y0
x = xtemp
i = i + 1
}
//coloring
if("smoothColoring" === coloringType){
if(i < maxI){
log_zn = Math.log(x*x + y*y)/2
nu = Math.log( log_zn / Math.log(2) ) / Math.log(2);
i = i + 1 - nu;
c.fillStyle = color(i / maxI * (_pallete.length - 1));
c.fillRect(px, py, scale, scale);
}else{
c.fillStyle = "black";
c.fillRect(px, py, scale, scale);
}
}else{
c.fillStyle = color(i);
c.fillRect(px, py, scale, scale);
}
}
}
console.log("Total ticks: " + ticks + ", based on scale " + scale);
}
/******************************************************************/
/******************************************************************/
function color(num,x,y){
switch(coloringType){
case "escapeTime":
var selection = pallete.colourAt(num);
return "#" + selection;
break;
case "smoothColoring":
return interpolation(num);
break;
default:
var selection = pallete.colourAt(num);
return "#" + selection;
}
}
function hexToRGBObject(hex){
hex = (hex+"").replace("#","");
return {
r: parseInt(hex.charAt(0) + hex.charAt(1),16),
g: parseInt(hex.charAt(2) + hex.charAt(3),16),
b: parseInt(hex.charAt(4) + hex.charAt(5),16)
}
}
function linear_interpolate(color1, color2, ratio){
var r = Math.floor((color2.r - color1.r)*ratio+color1.r);
var g = Math.floor((color2.g - color1.g)*ratio+color1.g);
var b = Math.floor((color2.b - color1.b)*ratio+color1.b);
return "rgb(" + r + "," + g + "," + b + ")";
}
function interpolation(iteration){
var color1 = hexToRGBObject(_pallete[Math.floor(iteration)]);
var color2 = hexToRGBObject(_pallete[Math.floor(iteration)+1]);
return linear_interpolate(color1, color2, iteration % 1);
}
//reset
function work(){
document.getElementById("xa").value = -2.5;
document.getElementById("ya").value = -2;
document.getElementById("za").value = a/4;
pan = 0.01;
zooms = a / 4;
panX = -2.5;
panY = -2.0;
zf = 1.5;
maxI = 50;
pallete.setSpectrum("#000764","#206bcb","#edffff","#ffaa00","#000200");
pallete.setNumberRange(0,maxI);
_pallete = ["#000764","#206bcb","#edffff","#ffaa00","#000200"];
coloringType = "smoothColoring";
document.getElementById("clrt").value = coloringType;
show();
abortRun();
startRun();
}
//left to right scroll adjustment
function xScroll(n){
var temp = n ? parseFloat(document.getElementById("xa").value) + pan : parseFloat(document.getElementById("xa").value) - pan;
document.getElementById("xa").value = temp;
panX = temp;
show();
abortRun();
startRun();
}
//top to bottom scroll adjustment
function yScroll(n){
var temp = n ? parseFloat(document.getElementById("ya").value) + pan : parseFloat(document.getElementById("ya").value) - pan;
document.getElementById("ya").value = temp;
panY = temp;
show();
abortRun();
startRun();
}
//draw again
function drawAgain(){
panX = parseFloat(document.getElementById("xa").value);
panY = parseFloat(document.getElementById("ya").value);
zooms = parseFloat(document.getElementById("za").value);
show();
abortRun();
startRun();
}
//the change zoom function
function zoom(){
//NOT YET
/*var rect = canvas.getBoundingClientRect();
var mx = panX + (panX - rect.left) / zooms;
var my = panY + (panY - rect.top) / zooms;
zooms = document.getElementById("za");
panX = mx - ((panX - rect.left) / zooms);
panY = my - ((panY - rect.top) / zooms);
*/
zooms = document.getElementById("za").value;
mx = ((panX + (a-1)/zooms) - panX) / 2;
panX -= mx;
my = ((panY + (b-1)/zooms) - panY) / 2;
panY -= mx;
show();
abortRun();
startRun();
}
//zoom in function
function zoomIn(){
zooms = zooms + zf;
pan = (panX + 2 / zooms) - (panX - 1 / zooms);
document.getElementById("za").value = zooms;
if(0 < zooms && zooms < 100){
pallete.setNumberRange(0,100);
maxI = 100;
}else if(100 < zooms && zooms < 1000){
pallete.setNumberRange(0,255);
maxI = 255;
}else if(1000 < zooms && zooms < 10000){
pallete.setNumberRange(0,500);
maxI = 500;
}
show();
abortRun();
startRun();
}
//zoom out function
function zoomOut(){
zooms = zooms - zf;
pan = (panX + 2 / zooms) - (panX - 1 / zooms)
document.getElementById("za").value = zooms;
if(zooms < 100){
pallete.setNumberRange(0,50);
maxI = 50;
}else if(zooms > 100 && zooms < 1000){
pallete.setNumberRange(0,100);
maxI = 100;
}else if(zooms > 1000 && zooms < 10000){
pallete.setNumberRange(0,255);
maxI = 255;
}
show();
abortRun();
startRun();
}
//adjust zoomfactor
function zoomFactor(){
var temp = document.getElementById("zf").value;
zf = parseInt(temp);
show();
}
//adjust maxI
function changeMaxI(){
var temp = document.getElementById("mi").value;
maxI = parseInt(temp);
pallete.setNumberRange(0,maxI);
show();
abortRun();
startRun();
}
//changes coloringType
function changeColoringType(){
var temp;
switch(coloringType){
case "smoothColoring":
temp = "escapeTime";
break;
case "escapeTime":
temp = "smoothColoring";
break;
}
coloringType = temp;
document.getElementById("clrt").value = temp;
show();
abortRun();
startRun();
}
//adjust pallete
function changePallete(){
var temp = (document.getElementById("plt").value).split(" ");
if(temp.length < 3){
alert(" Please enter more colors ");
return
}
pallete.setSpectrumByArray(temp);
show();
abortRun();
startRun();
}
//updateCoords
function changeCoords(){
var temp = (document.getElementById("crd").value).split(" ");
if(temp.length < 4){
alert(" Please enter complete details");
return
}
panX = parseFloat(temp[0]);
panY = parseFloat(temp[1]);
zooms = parseFloat(temp[2]);
maxI = parseFloat(temp[3]);
pallete.setNumberRange(0, maxI);
document.getElementById("xa").value = panX;
document.getElementById("ya").value = panY;
document.getElementById("za").value = zooms;
show();
abortRun();
startRun();
}
//resize canvas
function resize(){
a = canvas.width = parseInt(prompt("Please enter canvas width in pixels",200)) || 200;
b = canvas.height = parseInt(prompt("Please enter canvas height in pixels",200)) || 200;
work();
}
//show details
function show(){
var temp = "Scroll: " + pan + "
Current zoom: " + zooms + "
topLeftX: " + panX + "
topRightY: " + panY + "
zoom factor: " + zf + "
max iterations of loop: " + maxI + "
uses " + coloringType + " algorithm for coloring";
document.getElementById("dtls").innerHTML = temp;
}
/*favorable zoom
-0.7253464660778749
0.2520240908085526
18892488895.231102
-0.373346235978374
-0.6582261932152258
7000
-0.3618206208864465
-0.6453957620586814
155300315925100
*/
//about function
function about(){
alert("A mandelbrot set generator in javascript created by pvzzombs")
console.log("A mandelbrot set generator in javascript created by pvzzombs");
}
}catch(e){
throw "Error: " + e ;
}