Table des matières

Ensemble de Mandelbrot

Ceci est une solution pour le TD Mandelbrot.

Page html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Fractale de Mandelbrot</title>
    
    <link rel="stylesheet" href="style.css">
  </head>
  <body>
    <canvas width="1200" height="800">
        En attente...
    </canvas>

    <script src="./script.js"></script>
  </body>
</html>

script js

const ITERATIONS = 500;
const ZOOMFACTOR = 2;
let canvas = document.querySelector('canvas');
let ctx = canvas.getContext('2d');
let w = canvas.width;
let h = canvas.height;

/* réglage de la vue :
   x, y: coordonées du centre
   dot: taille d'un pixel dans le repère
*/
var pan = {
    x:-.5,
    y:0,
    dot: 0.01
}

const colormap = [
    [0, 0, 0],
    [20, 0, 20],
    [50, 0, 50],
    [80, 0, 80],
    [30, 0, 80],
    [20, 80, 80],
    [0, 100, 80],
    [0, 100, 30],
    [60, 120, 10],
    [94, 100, 0],
    [100, 70, 0],
    [100, 14, 0]
];

function draw(){
    /*
      trace selon les les coordonnées dans pan
    */
    let img = ctx.getImageData(0, 0, w, h);
    let data = img.data;
    for (let i=0; i<data.length; i+=4){
        let indice = ~~(i /4);
        let col = indice % w;
        let lig = ~~(indice / w);
        let x = pan.x + (col - w/2)*pan.dot;
        let y = pan.y - (lig - h/2)/pan.dot;
        let score = getScore(x, y);
        let color = getColor(score);
        data[i] = color[0];
        data[i+1] = color[1];
        data[i+2] = color[2];
        data[i+3] = 255;
    }
    ctx.putImageData(img, 0, 0);
}

function mod2(z){
    /* 
      z: complexe, objet ayant les attributs re et im
      renvoie le  module de z au carré
    */
    return z.re*z.re + z.im*z.im
}

function getScore(cx, cy){
    /* teste l'appartenance ce cx, cy à l'ensemble.
       renvoie un float entre 0 et 1, 0 pour appartenance complète à l'ensemble. */
    let zx = 0;
    let zy = 0;
    for (let i=0; i<ITERATIONS; i++){
        let nzx = zx*zx - zy*zy + cx
        zy = 2*zx*zy + cy;
        zx = nzx;
        let m2 = zx*zx + zy*zy;
        if (m2>=4) {
            return 1 - Math.max(0, i - Math.log(m)/Math.log(4))/ITERATIONS;
        }
    }
    return 0;
}

function getColor(score)
{
    /* calcule la couleur selon le score et la colormap */
    if (score== 1) {
        return colormap[colormap.length - 1];
    }
    let x = (colormap.length-1)*value;

    let i = Math.floor(x);
    let di = x - i;
    let r1, g1, b1, r2, g2, b2;
    [r1, g1, b1] = colormap[i];
    [r2, g2, b2] = colormap[i+1];
    let r = Math.round(r1 + di*(r2 - r1));
    let g = Math.round(g1 + di*(g2 - g1));
    let b = Math.round(b1 + di*(b2 - b1));
    return [r, g, b];
}

function getCursorPosition(canvas, event) {
    /* lit les coordonnées du clic souris */
    const rect = canvas.getBoundingClientRect()
    const x = event.clientX - rect.left
    const y = event.clientY - rect.top
    return [x, y];
}

function click(e){
    /* gère un click */
    let lig, col;
    [col,lig] = getCursorPosition(canvas, e);
    let x = pan.x + (col-w/2)*pan.dot;
    let y = pan.y - (lig - h/2)*pan.dot;
    pan.dot /= ZOOMFACTOR;
    pan.x = x - (col - w/2)*dot;
    pan.y = y + (lig - h/2)*dot;
    draw();
}


canvas.addEventListener('mousedown', click)
draw();