Mon cahier d’exercices

La fractale de Benoît Mandelbrot

"Auteur : Hagnoul Daniel"

Texte : v1.0.2 2012-12-29
Texte : v1.0.0 2012-11-30

MandelbrotXXL est la version XXL (1500 * 1000 pixels, Code v1.0.2 2012-12-29), de la version originale (900 * 600 pixels, Présentation et codes )

Pour construire l'image, cette version utilise le même code que la version originale, mais le code est placé dans un "web-worker".

L'interface de MandelbrotXXL est un peu plus élaborée que celle de la version originale, on peut sauvegarder les coordonnées de 20 images dans le "localStorage" du navigateur. Le bouton "Reset", efface les coordonnées sauvegardées et restaure celles d'origines.

Sous Firefox, il est possible de sauvegarder l'image au format PNG d'un simple clic droit.

La version non compressée des codes

MandelbrotXXL utilise le plugin jQuery : dvjhStorage.

Pour plus d'informations sur l'espace de noms dvjh et le plugin dvjhStorage, voir le tutoriel : Plugin multitâche : méthode de construction personnelle et exemples.

Fichier MandelbrotXXL.js

"use strict";

/* 
 * Fonction "universelle" pour l'initialisation et l'appel des 
 * méthodes d'un plugin  multitâche. 
 * 
 * Ne pas copier-coller ni modifier sans nécessité. 
 */ 
var dvjhPluginCreate = function( objMethods, params ){ 
 
    var args = Array.prototype.slice.call( params ), 
        method = args.shift(); 
     
    // console.log( "dvjhPluginCreate, arguments : ", objMethods, method, args ); 
 
    if ( ! objMethods ){ 
        $.error( "dvjhPluginCreate : objMethods n'est pas défini !" ); 
    } 
     
    if ( typeof method === "string" && method.slice( 0, 1 ) === "_" ){ 
        $.error( "dvjhPluginCreate : les propriétés, les méthodes " + 
            "et les objets précédés d'un tiret bas (underscore) sont privés !" ); 
    } 
     
    var boolOK, boolInit, boolDestroy, objOpts, jObj, cMethod, cParams, 
        name = objMethods._copyright.objMethodsName; 
     
    /* 
     * Attention ! Ici, this c'est l'objet jQuery ! 
     * 
     * La valeur de this est particulière, elle 
     * correspond au sélecteur qui a créé le plugin. 
     * On ne doit donc jamais écrire $( this ) car 
     * cette écriture crée un $( $( selecteur ) ) inutile ! 
     *  
     * Objet et array : attention chaque instance ($( item ),  
     * un objet jQuery) doit travailler sur sa copie. 
     * 
     * Les options de l'instance sont stockées dans l'instance 
     * (par data( name )). À l'initialisation, il s'agit d'une 
     * copie des options par défaut. 
     */ 
    return this.each( function( i, item ){ 
        boolOK = true; 
        boolInit = false; 
        boolDestroy = false; 
        objOpts = $( item ).data( name ) || null; 
        jObj = $( item ); 
         
        if ( objOpts == null ){ 
            boolInit = true; 
            jObj.data( name, $.extend( true, {}, objMethods._options ) ); 
            objOpts = jObj.data( name ); 
        } 
         
        if ( method ){ 
            if ( $.isPlainObject( method ) ){ 
                cMethod = $.extend( true, {}, method ); 
            } else if ( $.isArray( method ) ){ 
                cMethod = method.concat(); 
            } else { 
                cMethod = method; 
            } 
        } 
         
        cParams = args.concat(); 
         
        objMethods.options = objOpts; // important ! 
        objMethods.jObj = $( item ); // important ! 
         
        // debug 
        /* 
        console.log( "dvjhPluginCreate, boolOK : ", boolOK ); 
        console.log( "dvjhPluginCreate, boolInit : ", boolInit ); 
        console.log( "dvjhPluginCreate, jObj : ", jObj ); 
        console.log( "dvjhPluginCreate, objOpts : ", objOpts ); 
        console.log( "dvjhPluginCreate, objMethods.options : ", 
                    objMethods.options ); 
        console.log( "dvjhPluginCreate, cMethod, typeof cMethod : ", 
                    cMethod, typeof cMethod ); 
        console.log( "dvjhPluginCreate, cParams, $.isArray( cParams ) : ", 
                    cParams, $.isArray( cParams ) ); 
        */ 
         
        if ( boolInit ){ 
            if ( cMethod === "init" ){ 
                objMethods[ cMethod ]( cParams ); 
            } else if ( $.isPlainObject( cMethod ) || ! cMethod ){ 
                objMethods.init( cMethod, cParams ); 
            } else { 
                /* 
                * cMethod peut contenir un paramètre de n'importe 
                * quel type sauf un objet. Car si le premier argument 
                * est un objet il doit contenir les options de  
                * l'utilisateur. 
                * 
                * On peut passer un autre objet si l'on passe un objet  
                * anonyme vide comme premier argument, exemple : 
                * jObj.dvjhPlugin( {}, new Date() ); 
                * 
                * On doit construire un nouvel array regroupant le 
                * contenu de cMethod et de l'array cParams. 
                */ 
                var tab; 
                 
                if ( typeof cMethod === "string" ||  
                                        typeof cMethod === "number" ){ 
                    tab = [ cMethod ]; 
                } else { 
                    tab = $.map( cMethod,  
                                function( value, key ){ return value; } ); 
                } 
                 
                objMethods.init( {}, $.merge( tab, cParams ) ); 
            } 
        } else { 
            if ( cMethod != "init" && cMethod in objMethods ){ 
             
                if ( cMethod === "destroy" ){ 
                    boolDestroy = true; 
                } 
                 
                objMethods[ cMethod ]( cParams ); 
            } else { 
                boolOK = false; 
            } 
        } 
         
        jObj.data( name, objMethods.options ); 
         
        objMethods.options = {}; // important ! 
        objMethods.jObj = null; // important ! 
         
        objOpts = cMethod = cParams = null; 
         
        if ( boolDestroy ){ 
            jObj.removeData( name ); 
        } 
         
        if ( ! boolOK ){ 
            $.error( "dvjhPluginCreate : la méthode " + 
                method + " n'existe pas ou cet élément du DOM " + 
                "a déjà été initialisé !" ); 
        } 
    }); 
}; 

var dvjh = (function($){ 
     
    /* 
     * Plugin pour gérer le stockage des données au format JSON. 
     * On peut stocker dans le navigateur (sessionStorage ou localSorage) 
     * ou dans l'élément du DOM ( jObj.data( "dvjhStorage" ) ). 
     * 
     * Firefox : le sessionStorage n'est pas disponible en  
     * "local mode", mais il fonctionnera lorsque vous  
     * chargerez cette page Web à partir d'un serveur ! 
     *  
     * On sauvegarde des données. Si l'on passe un objet qui contient  
     * une fonction elle sera supprimée. "Non-integer/string keys are 
     * skipped in the object, as are keys that point to a function". 
     */ 
    var dvjhStorageMethods = { 
        "_copyright" : { // informations sur le plugin 
            "objMethodsName" : "dvjhStorageMethods", 
            "auteur" : "Daniel Hagnoul", 
            "version" : "1.0.0", 
            "date" : "2012-01-21T20:30:45.000+01:00", 
            "licence" : "libre de tous droits" 
        }, 
        "_options" : { // les options par défaut 
            "boolDebug" : false 
        }, 
        "jObj" : null, // l'instance (un objet jQuery ) 
        "options" : {}, // les options de l'instance 
        "init" : function(){ // initialisation du plugin 
            var args = Array.prototype.slice.call( arguments ), 
                param1 = args.shift(), 
                param2 = args.shift(); 
             
            if ( $.isPlainObject( param1 ) && ! $.isEmptyObject( param1 ) ){ 
                 
                if ( this.options.boolDebug ){ 
                    console.log( "init, options de l'utilisateur : ", 
                                 $.extend( true, {}, param1 ) ); 
                } 
                 
                $.extend( this.options, param1 ); 
            } 
             
            var dataOptions = this.jObj.data( "pluginOptions" ); 
              
            if ( $.isPlainObject( dataOptions ) && ! $.isEmptyObject( dataOptions ) ){ 
                 
                if ( this.options.boolDebug ){ 
                    console.log( "init, options de l'utilisateur : ", 
                                $.extend( true, {}, dataOptions ) ); 
                } 
                 
                $.extend( this.options, dataOptions ); 
            } 
             
            var mesArguments = []; 
             
            if ( $.isArray( param1 ) ){ 
                mesArguments = param1.concat(); 
            } else if ( $.isArray( param2 ) ){ 
                mesArguments = param2.concat(); 
            } 
             
            if ( this.options.boolDebug ){ 
                console.log( "init, this.jObj : ", this.jObj ); 
                console.log( "init, mesArguments : ", mesArguments.concat() ); 
            } 
             
            /* 
             * Si le navigateur n'est pas compatible, l'objet 
             * jQuery n'est pas créé ! 
             */ 
            if ( ! window.localStorage ){ 
                $.error( "Le localStorage n'est pas disponible ! Le navigateur est obsolète !" ); 
            } 
             
            this.jObj.data( "dvjhStorage", {} ); 
             
            if ( window.location.protocol === "file:" ){ 
                console.log( "Sur Firefox, le sessionStorage n'est pas disponible " + 
                    "en \"local mode\", mais il fonctionnera lorsque vous " + 
                    "chargerez cette page Web à partir d'un serveur !"); 
            } 
        }, 
        "destroy" : function( params ){ 
            // 1. Supprimer les gestionnaires d'événements. 
             
            // 2. Supprimer les composants UI. 
             
            // 3. Rendre null les objets (y compris array) 
        }, 
        "set" : function( params ){ 
            var location = params.shift(), 
                key = params.shift(), 
                value = params.shift();  
             
            if ( typeof location === "string" &&  
                 typeof key === "string" && 
                 value ){ 
                 
                var jsonValue = JSON.stringify( value ); 
                 
                if ( this.options.boolDebug ){ 
                    console.log( "set, location : ", location ); 
                    console.log( "set, key : ", key ); 
                 
                    if ( $.isArray( value ) ){ 
                        console.log( "set, value : ", value.concat() ); 
                    } else if ( $.isPlainObject( value ) ){ 
                        console.log( "set, value : ", $.extend( true, {}, value ) ); 
                    } else { 
                        console.log( "set, value : ", value ); 
                    } 
                } 
                 
                switch( location ){ 
                    case "session": 
                        this._sessionSet( key, jsonValue ); 
                        break; 
                    case "local": 
                        this._localSet( key, jsonValue ); 
                        break; 
                    case "data": 
                        this._dataSet( key, jsonValue ); 
                        break; 
                    default: 
                        $.error( "Cette location (" + location + ") n'existe pas !" ); 
                } 
            } else { 
                $.error( "dvjhStorageMethods, set : les paramètres location ( " + 
                         location +  
                         " ) ( session || local || data ) et key ( " + 
                         key + 
                         " ) doivent être de type text et le paramètre value ( " + 
                         value +  
                         " ) doit exiter !" ); 
            } 
        }, 
        "_sessionSet" : function( key, jsonValue ){ 
            try { 
                window.sessionStorage.setItem( key, jsonValue ); 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, sessionSet : " + e.message ); 
            } 
        }, 
        "_localSet" : function( key, jsonValue ){ 
            try { 
                window.localStorage.setItem( key, jsonValue ); 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, localSet : " + e.message ); 
            } 
        }, 
        "_dataSet" : function( key, jsonValue ){ 
            try { 
                var objAnonyme = this.jObj.data( "dvjhStorage" ); 
                 
                objAnonyme[ key ] = jsonValue; 
                 
                this.jObj.data( "dvjhStorage", objAnonyme ); 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, dataSet : " + e.message ); 
            } 
        }, 
        "get" : function( params ){ 
            var location = params.shift(), 
                key = params.shift(), 
                callback = params.shift() || function(){}; 
             
            if ( typeof location === "string" && typeof key === "string" ){ 
                 
                if ( this.options.boolDebug ){ 
                    console.log( "get, location : ", location ); 
                    console.log( "get, key : ", key ); 
                } 
                 
                switch( location ){ 
                    case "session": 
                        this._sessionGet( key, callback ); 
                        break; 
                    case "local": 
                        this._localGet( key, callback ); 
                        break; 
                    case "data": 
                        this._dataGet( key, callback ); 
                        break; 
                    default: 
                        $.error( "Cette location (" + location + ") n'existe pas !" ); 
                } 
            } else { 
                $.error( "dvjhStorageMethods, get : les paramètres location ( " + 
                        location + " ) ( session || local || data ) et key ( " + 
                        key + " ) doivent être de type text !" ); 
            } 
        }, 
        "_sessionGet" : function( key, callback ){ 
            var name = "get." + this._copyright.objMethodsName; 
             
            try { 
                // getItem retourne null si key n'existe pas ! 
                var value = JSON.parse( window.sessionStorage.getItem( key ) ); 
                 
                this.jObj.data( name, value ); 
                 
                callback( key, value ); 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, sessionGet : " + e.message ); 
            } 
        }, 
        "_localGet" : function( key, callback ){ 
            var name = "get." + this._copyright.objMethodsName; 
             
            try { 
                // getItem retourne null si key n'existe pas ! 
                var value = JSON.parse( window.localStorage.getItem( key ) ); 
                 
                this.jObj.data( name, value ); 
                 
                callback( key, value ); 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, localGet : " + e.message ); 
            } 
        }, 
        "_dataGet" : function( key, callback ){ 
            var name = "get." + this._copyright.objMethodsName; 
             
            try { 
                // getItem retourne null si key n'existe pas ! 
                 
                var objAnonyme = this.jObj.data( "dvjhStorage" ), 
                    value = null; 
                 
                if ( key in objAnonyme ){ 
                    value = JSON.parse( objAnonyme[ key ] ); 
                } 
                 
                this.jObj.data( name, value ); 
                 
                callback( key, value ); 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, dataGet : " + e.message ); 
            } 
        }, 
        "has" : function( params ){ 
            var key = params.shift(), 
                callback = params.shift() || function(){}, 
                name = "has." + this._copyright.objMethodsName; 
             
            if ( typeof key === "string" ){ 
                 
                if ( this.options.boolDebug ){ 
                    console.log( "has, key : ", key ); 
                } 
 
                try { 
                    var boolSession = false, 
                        boolLocal = false, 
                        boolData = false; 
                         
                    if ( key in window.sessionStorage ){ 
                        boolSession = true; 
                    } 
                     
                    if ( key in window.localStorage ){ 
                        boolLocal = true; 
                    } 
                     
                    if ( key in this.jObj.data( "dvjhStorage" ) ){ 
                        boolData = true; 
                    } 
                     
                    this.jObj.data( name, { 
                        "session" : boolSession, 
                        "local" : boolLocal, 
                        "data" : boolData 
                    }); 
                     
                    callback( key, { 
                        "session" : boolSession, 
                        "local" : boolLocal, 
                        "data" : boolData 
                    }); 
                } 
                catch( e ){ 
                    $.error( "dvjhStorage, has : " + e.message ); 
                } 
            } else { 
                $.error( "dvjhStorageMethods, has : le paramètre key ( " + 
                        key + " ) doit être de type text !" ); 
            } 
        }, 
        "remove" : function( params ){ 
            var location = params.shift(), 
                key = params.shift(); 
             
            if ( typeof location === "string" && typeof key === "string" ){ 
                 
                if ( this.options.boolDebug ){ 
                    console.log( "remove, location : ", location ); 
                    console.log( "remove, key : ", key ); 
                } 
                 
                switch( location ){ 
                    case "session": 
                        this._sessionRemove( key ); 
                        break; 
                    case "local": 
                        this._localRemove( key ); 
                        break; 
                    case "data": 
                        this._dataRemove( key ); 
                        break; 
                    default: 
                        $.error( "Cette location (" + location + ") n'existe pas !" ); 
                } 
            } else { 
                $.error( "dvjhStorageMethods, remove : les paramètres location ( " + 
                        location + " ) ( session || local || data ) et key ( " + 
                        key + " ) doivent être de type text !" ); 
            } 
        }, 
        "_sessionRemove" : function( key ){ 
            try { 
                // removeItem ne fait rien si key n'existe pas ! 
                window.sessionStorage.removeItem( key ); 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, sessionRemove : " + e.message ); 
            } 
        }, 
        "_localRemove" : function( key ){ 
            try { 
                // removeItem ne fait rien si key n'existe pas ! 
                window.localStorage.removeItem( key ); 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, localRemove : " + e.message ); 
            } 
        }, 
        "_dataRemove" : function( key ){ 
            try { 
                // remove ne fait rien si key n'existe pas ! 
                 
                var objAnonyme = this.jObj.data( "dvjhStorage" ); 
                 
                if ( key in objAnonyme ){ 
                    delete objAnonyme[ key ]; 
                } 
                 
                this.jObj.data( "dvjhStorage", objAnonyme ); 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, dataRemove : " + e.message ); 
            } 
        }, 
        "clear" : function( params ){ 
            var location = params.shift(); 
             
            if ( typeof location === "string" ){ 
                 
                if ( this.options.boolDebug ){ 
                    console.log( "clear, location : ", location ); 
                } 
                 
                switch( location ){ 
                    case "session": 
                        this._sessionClear(); 
                        break; 
                    case "local": 
                        this._localClear(); 
                        break; 
                    case "data": 
                        this._dataClear(); 
                        break; 
                    default: 
                        $.error( "Cette location (" + location + ") n'existe pas !" ); 
                } 
            } else { 
                $.error( "dvjhStorageMethods, setItem : le paramètre location ( " + 
                        location + " ) ( session || local || data ) et key ( " + 
                        " ) doit être de type text !" ); 
            } 
        }, 
        "clearAll" : function( params ){ 
            if ( this.options.boolDebug ){ 
                    console.log( "clearAll" ); 
            } 
             
            this._sessionClear(); 
            this._localClear(); 
            this._dataClear(); 
        }, 
        "_sessionClear" : function(){ 
            try { 
                window.sessionStorage.clear(); 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, sessionClear : " + e.message ); 
            } 
        }, 
        "_localClear" : function(){ 
            try { 
                window.localStorage.clear(); 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, localClear : " + e.message ); 
            } 
        }, 
        "_dataClear" : function(){ 
            try { 
                this.jObj.data( "dvjhStorage", {} ); 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, dataClear : " + e.message ); 
            } 
        }, 
        "relocate" : function( params ){ 
            var origine = params.shift(), 
                destination = params.shift(), 
                key = params.shift(); 
             
            if ( typeof origine === "string" && 
                 typeof destination === "string" && 
                 typeof key === "string" ){ 
                 
                if ( this.options.boolDebug ){ 
                    console.log( "relocate, origine : ", origine ); 
                    console.log( "relocate, destination : ", destination ); 
                    console.log( "relocate, key : ", key ); 
                } 
                 
                switch( origine ){ 
                    case "session": 
                        this._sessionRelocate( key, destination ); 
                        break; 
                    case "local": 
                        this._localRelocate( key, destination ); 
                        break; 
                    case "data": 
                        this._dataRelocate( key, destination ); 
                        break; 
                    default: 
                        $.error( "Cette origine (" + origine + ") n'existe pas !" ); 
                } 
            } else { 
                $.error( "dvjhStorageMethods, relocate : les paramètres origine ( " + 
                         origine +  
                         " ) ( session || local || data ), destination ( " + 
                         destination + 
                         " ) ( session || local || data ) et key " + 
                         " doivent être de type text !" ); 
            } 
        }, 
        "_sessionRelocate" : function( key, destination ){ 
            try { 
                // getItem retourne null si key n'existe pas ! 
                var jsonValue = window.sessionStorage.getItem( key ); 
                 
                if ( jsonValue ){ 
                    // removeItem ne fait rien si key n'existe pas ! 
                    window.sessionStorage.removeItem( key ); 
                     
                    switch( destination ){ 
                        case "local": 
                            this._localSet( key, jsonValue ); 
                            break; 
                        case "data": 
                            this._dataSet( key, jsonValue ); 
                            break; 
                        default: 
                            $.error( "Cette destination (" + destination + ") n'existe pas !" ); 
                    } 
                } 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, sessionRelocate : " + e.message ); 
            } 
        }, 
        "_localRelocate" : function( key, destination ){ 
            try { 
                // getItem retourne null si key n'existe pas ! 
                var jsonValue = window.localStorage.getItem( key ); 
                 
                if ( jsonValue ){ 
                    // removeItem ne fait rien si key n'existe pas ! 
                    window.localStorage.removeItem( key ); 
                     
                    switch( destination ){ 
                        case "session": 
                            this._sessionSet( key, jsonValue ); 
                            break; 
                        case "data": 
                            this._dataSet( key, jsonValue ); 
                            break; 
                        default: 
                            $.error( "Cette destination (" + destination + ") n'existe pas !" ); 
                    } 
                } 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, localRelocate : " + e.message ); 
            } 
        }, 
        "_dataRelocate" : function( key, destination ){ 
            try { 
                var objAnonyme = this.jObj.data( "dvjhStorage" ), 
                    jsonValue = null; 
                 
                if ( key in objAnonyme ){ 
                    jsonValue = objAnonyme[ key ]; 
                    delete objAnonyme[ key ]; 
                } 
                 
                this.jObj.data( "dvjhStorage", objAnonyme ) 
                 
                if ( jsonValue ){ 
                    switch( destination ){ 
                        case "local": 
                            this._localSet( key, jsonValue ); 
                            break; 
                        case "session": 
                            this._sessionSet( key, jsonValue ); 
                            break; 
                        default: 
                            $.error( "Cette destination (" + destination + ") n'existe pas !" ); 
                    } 
                } 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, dataRelocate : " + e.message ); 
            } 
        }, 
        "copy" : function( params ){ 
            var origine = params.shift(), 
                destination = params.shift(), 
                key = params.shift(); 
             
            if ( typeof origine === "string" && 
                 typeof destination === "string" && 
                 typeof key === "string" ){ 
                 
                if ( this.options.boolDebug ){ 
                    console.log( "copy, origine : ", origine ); 
                    console.log( "copy, destination : ", destination ); 
                    console.log( "copy, key : ", key ); 
                } 
                 
                switch( origine ){ 
                    case "session": 
                        this._sessionCopy( key, destination ); 
                        break; 
                    case "local": 
                        this._localCopy( key, destination ); 
                        break; 
                    case "data": 
                        this._dataCopy( key, destination ); 
                        break; 
                    default: 
                        $.error( "Cette origine (" + origine + ") n'existe pas !" ); 
                } 
            } else { 
                $.error( "dvjhStorageMethods, copy : les paramètres origine ( " + 
                        origine +  
                        " ) ( session || local || data ), destination ( " + 
                        destination + 
                        " ) ( session || local || data ) et key " + 
                        " doivent être de type text !" ); 
            } 
        }, 
        "_sessionCopy" : function( key, destination ){ 
            try { 
                // getItem retourne null si key n'existe pas ! 
                var jsonValue = window.sessionStorage.getItem( key ); 
                 
                if ( jsonValue ){ 
                    switch( destination ){ 
                        case "local": 
                            this._localSet( key, jsonValue ); 
                            break; 
                        case "data": 
                            this._dataSet( key, jsonValue ); 
                            break; 
                        default: 
                            $.error( "Cette destination (" + destination + ") n'existe pas !" ); 
                    } 
                } 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, sessionCopy : " + e.message ); 
            } 
        }, 
        "_localCopy" : function( key, destination ){ 
            try { 
                // getItem retourne null si key n'existe pas ! 
                var jsonValue = window.localStorage.getItem( key ); 
                 
                if ( jsonValue ){ 
                    switch( destination ){ 
                        case "session": 
                            this._sessionSet( key, jsonValue ); 
                            break; 
                        case "data": 
                            this._dataSet( key, jsonValue ); 
                            break; 
                        default: 
                            $.error( "Cette destination (" + destination + ") n'existe pas !" ); 
                    } 
                } 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, localCopy : " + e.message ); 
            } 
        }, 
        "_dataCopy" : function( key, destination ){ 
            try { 
                var objAnonyme = this.jObj.data( "dvjhStorage" ), 
                    jsonValue = null; 
                 
                if ( key in objAnonyme ){ 
                    jsonValue = objAnonyme[ key ]; 
                } 
                 
                if ( jsonValue ){ 
                    switch( destination ){ 
                        case "local": 
                            this._localSet( key, jsonValue ); 
                            break; 
                        case "session": 
                            this._sessionSet( key, jsonValue ); 
                            break; 
                        default: 
                            $.error( "Cette destination (" + destination + ") n'existe pas !" ); 
                    } 
                } 
            } 
            catch( e ){ 
                $.error( "dvjhStorage, dataCopy : " + e.message ); 
            } 
        }, 
        "setOption" : function( params ){ 
            var option = params.shift(), 
                value = params.shift(); 
                 
            if ( ! option || ! value ){ 
                $.error( "Les paramètres ne sont pas conformes : ( " +  
                         option + ", " + value + " )." ); 
            } 
             
            if ( option in this.options ){ 
                switch( option ){ 
                    case "boolDebug": 
                        this._setBoolDebug( value ); 
                        break; 
                    default: 
                        $.error( "Cette option existe mais elle n'est pas publique !" ); 
                }; 
                 
            } else { 
                $.error( "Cette option n'existe pas !" ); 
            } 
        }, 
        "_setBoolDebug" : function( value ){ 
            if ( typeof value === "boolean" ){ 
                this.options.boolDebug = value; 
            } 
        }, 
        "getOption" : function( params ){ 
            var option = params.shift(), 
                callback = params.shift() || function(){}, 
                name = "getOption." + this._copyright.objMethodsName; 
                 
            if ( ! option ){ 
                $.error( "getOption : le paramètre n'est pas conforme : ( " + option + " )." ); 
            } 
             
            /* 
             * Objet et array : attention de toujours transmettre une copie ! 
             */ 
             
            if ( option in this.options ){ 
                switch( option ){ 
                    case "boolDebug": 
                        var value = this.options.boolDebug; 
                        this.jObj.data( name, value ); 
                        callback( option, value ); 
                        break; 
                    default: 
                        $.error( "getOption : cette option existe mais elle n'est pas publique !" ); 
                }; 
            } else { 
                $.error( "getOption : cette option n'existe pas !" ); 
            } 
        } 
    }; 
     
    // Ajouts de méthodes (plugin) au prototype de l'objet jQuery ($.fn). 
    $.extend( $.fn, {                  
        "dvjhStorage" : function(){ // un plugin multitâche 
            return dvjhPluginCreate.call( this, dvjhStorageMethods, arguments ); 
        } 
    }); 
     
    return { 
        "initStorage" : function( selector ){ 
            /* 
             * La seule méthode disponible pour l'initialisation 
             * d'un dvjhStorage. 
             *  
             * Cette méthode garantit que l'on ne traite qu'un seul objet 
             * jQuery à la fois. Dans le cas contraire, on aurait autant 
             * d'opérations sur le navigateur (localStorage et 
             * sessionStorage) qu'il y a d'instances dans selector. 
             * 
             * Si le navigateur n'est pas compatible jObj est null ! 
             */ 
            var jObj = null; 
             
            try { 
                if ( typeof selector === "string" && $.isFunction( $( selector ).is ) ){ 
                     
                    jObj = $( selector ).eq(0).dvjhStorage(); 
                } 
            } 
            catch( e ){ 
                console.log( "dvjhStorage, initStorage : " + e.message ); 
            } 
             
            return jObj; 
        }, 
        "storageObjMethodsName" : dvjhStorageMethods._copyright.objMethodsName,
        "storageObjMethodsDefaultOptions" : function( objOptions ){ 
            /* 
             * Modifications des options par défaut. 
             * 
             * Ne modifiez pas ce code sans nécessité ! 
             */ 
            if ( $.isPlainObject( objOptions ) && ! $.isEmptyObject( objOptions ) ){ 
                $.extend( dvjhStorageMethods._options, objOptions ); 
            } 
        } 
    }; 
})( jQuery.sub() );

$( function(){
	var btnDatas = {
			0 : {
				rstep : 1.9200000000000033e-5,
				istep : 1.9199999999999996e-5,
				r1 : -4.7705599999999992e-1,
				r2 : -4.4825599999999988e-1,
				i1 : 5.3980799999999995e-1,
				i2 : 5.5900799999999995e-1,
				nmax : 300,
				jc : 1
			},
			1 : {
				rstep : 4.8000000000000012e-4,
				istep : 4.7999999999999985e-4,
				r1 : -1.1873599999999995e+0,
				r2 : -4.6735999999999933e-1,
				i1 : -2.9279999999999196e-2,
				i2 : 4.5072000000000068e-1,
				nmax : 100,
				jc : 1
			},
			2 : {
				rstep : 9.6000000000000084e-5,
				istep : 9.5999999999999948e-5,
				r1 : -9.0271999999999952e-1,
				r2 : -7.5871999999999939e-1,
				i1 : 1.6224000000000074e-1,
				i2 : 2.5824000000000069e-1,
				nmax : 300,
				jc : 1
			},
			3 : {
				rstep : 1.9200000000000033e-5,
				istep : 1.9199999999999996e-5,
				r1 : -8.4502399999999944e-1,
				r2 : -8.1622399999999939e-1,
				i1 : 1.9766400000000073e-1,
				i2 : 2.1686400000000072e-1,
				nmax : 300,
				jc : 1 
			},
			4 : {
				rstep : 3.0720000000000064e-4,
				istep : 3.0719999999999993e-4,
				r1 : 4.9676800000001853e-2,
				r2 : 5.1047680000000284e-1,
				i1 : -1.5586559999999927e-1,
				i2 : 1.5133440000000065e-1,
				nmax : 100,
				jc : 1
			},
			5 : {
				rstep : 6.1440000000000130e-5,
				istep : 6.1439999999999995e-5,
				r1 : 2.5550080000000230e-1,
				r2 : 3.4766080000000249e-1,
				i1 : -5.4182399999999298e-2,
				i2 : 7.2576000000006968e-3,
				nmax : 300,
				jc : 1
			},
			6 : {
				rstep : 1.2288000000000003e-5,
				istep : 1.2288000000000000e-5,
				r1 : 2.7712768000000237e-1,
				r2 : 2.9555968000000238e-1,
				i1 : -1.7871359999999302e-2,
				i2 : -5.5833599999993017e-3,
				nmax : 300,
				jc : 1
			},
			7 : {
				rstep : 2.4576000000000229e-6,
				istep : 2.4575999999999991e-6,
				r1 : 2.8129331200000235e-1,
				r2 : 2.8497971200000238e-1,
				i1 : -1.2476927999999301e-2,
				i2 : -1.0019327999999302e-2,
				nmax : 500,
				jc : 1
			},
			8 : {
				rstep : 1.9660800000000173e-4,
				istep : 1.9660800000000000e-4,
				r1 : -1.2215364608000112e+0,
				r2 : -9.2662446080000860e-1,
				i1 : -3.7137254399999886e-1,
				i2 : -1.7476454399999886e-1,
				nmax : 200,
				jc : 1
			},
			9 : {
				rstep : 3.9321600000000366e-5,
				istep : 3.9321600000000040e-5,
				r1 : -1.1108461568000103e+0,
				r2 : -1.0518637568000098e+0,
				i1 : -2.6834995199999889e-1,
				i2 : -2.2902835199999885e-1,
				nmax : 200,
				jc : 1
			},
			10 : {
				rstep : 7.8643200000000728e-6,
				istep : 7.8643200000000084e-6,
				r1 : -1.0926795776000102e+0,
				r2 : -1.0808830976000101e+0,
				i1 : -2.4098211839999886e-1,
				i2 : -2.3311779839999885e-1,
				nmax : 200,
				jc : 1
			},
			11 : {
				rstep : 7.8643200000000728e-6,
				istep : 7.8643200000000084e-6,
				r1 : -1.0926009344000103e+0,
				r2 : -1.0808044544000102e+0,
				i1 : -2.4040802303999886e-1,
				i2 : -2.3254370303999886e-1,
				nmax : 400,
				jc : 1
			},
			12 : {
				rstep : 7.8643200000000728e-6,
				istep : 7.8643200000000084e-6,
				r1 : -1.0929391001600102e+0,
				r2 : -1.0811426201600101e+0,
				i1 : -2.4026646527999887e-1,
				i2 : -2.3240214527999886e-1,
				nmax : 600,
				jc : 1
			},
			13 : {
				rstep : 7.8643200000000728e-6,
				istep : 7.8643199999999796e-6,
				r1 : -1.0929155072000103e+0,
				r2 : -1.0811190272000102e+0,
				i1 : -2.4019568639999886e-1,
				i2 : -2.3233136639999888e-1,
				nmax : 2000,
				jc : 1
			},
			14 : {
				rstep : 7.6799999999999089e-7,
				istep : 7.6800000000010196e-7,
				r1 : -4.6601983999999991e-1,
				r2 : -4.6486783999999992e-1,
				i1 : 5.5032575999999989e-1,
				i2 : 5.5109375999999999e-1,
				nmax : 300,
				jc : 1
			},
			15 : {
				rstep : 4.7999999999999985e-4,
				istep : 4.7999999999999974e-4,
				r1 : -1.5488000000000000e+0,
				r2 : -8.2880000000000020e-1,
				i1 : -5.3760000000000008e-1,
				i2 : -5.7600000000000318e-2,
				nmax : 100,
				jc : 1
			},
			16 : {
				rstep : 9.5999999999999935e-5,
				istep : 9.5999999999999975e-5,
				r1 : -1.3332800000000000e+0,
				r2 : -1.1892800000000001e+0,
				i1 : -4.0368000000000015e-1,
				i2 : -3.0768000000000018e-1,
				nmax : 100,
				jc : 1
			},
			17 : {
				rstep : 1.9199999999999958e-5,
				istep : 1.9199999999999996e-5,
				r1 : -1.2749120000000000e+0,
				r2 : -1.2461120000000001e+0,
				i1 : -3.6470400000000014e-1,
				i2 : -3.4550400000000014e-1,
				nmax : 100,
				jc : 1
			},
			18 : {
				rstep : 3.8399999999999912e-6,
				istep : 3.8400000000000098e-6,
				r1 : -1.2645440000000001e+0,
				r2 : -1.2587840000000001e+0,
				i1 : -3.5765760000000013e-1,
				i2 : -3.5381760000000012e-1,
				nmax : 300,
				jc : 1
			},
			19 : {
				rstep : 1.5359999999997599e-7,
				istep : 1.5360000000003150e-7,
				r1 : -1.2617768960000002e+0,
				r2 : -1.2615464960000002e+0,
				i1 : -3.5584819200000012e-1,
				i2 : -3.5569459200000009e-1,
				nmax : 300,
				jc : 1
			}
		},
		width = 1500,
	    height = 1000,
	    r1 = -2.30,
	    r2 = 1.30,
	    i1 = -1.20,
	    i2 = 1.20,
	    rstep = 0,
	    istep = 0,
	    ctx,
	    nmax,
	    img,
		jc,
	    element = $( "#conteneurID" )[ 0 ],
	    jObjCanvas = $( "#canvasID" ),
	    jObjIter = $( "#maxIter" ),
	    jObjZoom = $( "#zoom" ),
        jObjSens = $( "input[type='radio'][name='sens']" ),
	    jObjBtnCoords = $( "button.btnCoords" ),
	    jObjReset = $( "#btnClearAll" ),
	    jObjSave = $( "#btnSauvegarder" ),
	    jObjAspect = $( "#aspect" ),
	    enterFullScreen = function( element ){
		    if( element.requestFullScreen ){
		        element.requestFullScreen();
		    } else if ( element.webkitRequestFullScreen ){
		        element.webkitRequestFullScreen( Element.ALLOW_KEYBOARD_INPUT );
		    } else if ( element.mozRequestFullScreen ){
		    	element.mozRequestFullScreen();
		    }
		},
	    affiche = function( ms) {      
	        $( "#coords" ).html( "rstep = " + rstep.toExponential(16) +
	        				  " | istep = " + istep.toExponential(16) +
	        				  " | r1 = " + r1.toExponential(16) +
	                          " | r2 = " + r2.toExponential(16) +
	                          " | i1 = " + i1.toExponential(16) +
	                          " | i2 = " + i2.toExponential(16) +
	                          " | nmax = " + nmax +
	                          " | ms = " + ms );
	         
	         jObjCanvas.removeClass( "calcul" );
	    },
	    nbIter = function(){
	    	var n = parseInt( jObjIter.val(), 10 ) || 50;
	        
	        if ( n > 8000 ){
		    	jObjIter.val( n = 8000 );
		    } else if (n < 20){
		    	jObjIter.val( n = 20 );
		    }
	 
	        return n;
	    },
	    zoom = function(){
	     	var z = parseInt( jObjZoom.val(), 10) || 5;
	 
	        if (z > 20) {
	            jObjZoom.val( z = 20 );
	        } else if (z < 1){
	            jObjZoom.val( z = 1 );
	        }
	 
	        return z;
	    },
	    sens = function(){
            return $( "input[name='sens']:checked" ).val() || "+";
	    },
	    worker = new Worker( "canvasWorker-min.js" ),
	    message = function(){
            $( "span.msgDisponible" ).hide();
            $( "span.msgPatience" ).show();
			
			jObjCanvas
				.off( "click" )
				.addClass( "calcul" );
			
            jObjAspect.prop( "disabled", true );
			jObjBtnCoords.prop( "disabled", true );
			jObjReset.prop( "disabled", true );
			jObjSave.prop( "disabled", true );
		 	
		    worker.postMessage({
		    	"width" : width,
				"height" : height,
				"r1" : r1,
				"r2" : r2,
				"i1" : i1,
				"i2" : i2,
				"rstep" : rstep,
				"istep" : istep,
				"fond" : jc,
				"nmax" : nmax,
				"img" : img      	
		   });
		},
	    clickEventHandler = function( e ){
		   	enterFullScreen( element );
		   	
		    var x = e.pageX - this.offsetLeft,
		    	y = e.pageY - this.offsetTop,
		        z = zoom(),
		        ss = sens(),
		        r = r1,
		        i = i1,
		        w = 0,
		        h = 0;
		    
		    if ( ss == "+" ){
		    	w = width/(2*z);
		        h = height/(2*z);
		    } else {
		    	w = width * z / 2;
		    	h = height * z / 2;
		    }
		    
		    r1 = r + (x - w) * rstep;
		    i1 = i + (y - h) * istep;
		    r2 = r + (x + w) * rstep;
		    i2 = i + (y + h) * istep;
		    
		    nmax = nbIter();
		    jc = jObjAspect.val();
		    
		    message();
		};
		    
	worker.onmessage = function( event ){
		var ms = event.data.ms;
		
		rstep = event.data.rstep;
		istep = event.data.istep;
		r1 = event.data.r1;
		r2 = event.data.r2;
		i1 = event.data.i1;
		i2 = event.data.i2;
		img = event.data.img;
		
		ctx.putImageData(img, 0, 0);
		
        $( "span.msgPatience" ).hide();
        $( "span.msgDisponible" ).show();
        
		affiche( ms );
		
		jObjCanvas.on( "click", clickEventHandler );
		
        jObjAspect.prop( "disabled", false );
		jObjBtnCoords.prop( "disabled", false );
		jObjReset.prop( "disabled", false );
		jObjSave.prop( "disabled", false );
	};

    jObjAspect.on( "change", function( e ){
        nmax = nbIter();
        jc = jObjAspect.val();
        message();
    });
	
	$( "#btnHelp" ).on( "click", function(){
		window.open( "MandelbrotXXL-Help.html", "_blank" );
	});
	
    if ( jObjCanvas[ 0 ].getContext ){
        ctx = jObjCanvas[ 0 ].getContext( "2d" );
        
        ctx.fillStyle = "#000000";
        ctx.fillRect( 0, 0, width-1, height-1 );
        
        img = ctx.getImageData( 0, 0, width, height );
        
        nmax = nbIter();
        jc = jObjAspect.val();
        
        message();
    }

	try { 
        var jObjStorage = dvjh.initStorage( "canvas" ),
        	strNamespace = "canvas",
	        mesDatas = {},
	        dataKey = "mesDatas." + strNamespace,
        	getResult = function( key, value ){
        		if ( value != null ){
	        		mesDatas = value;
		        } else {
		        	mesDatas = btnDatas;
		        }
	        		
	        	// stocke dataKey et sa valeur dans data 
	        	jObjStorage.dvjhStorage( "set", "data", dataKey, mesDatas );
	        };
	
        if ( jObjStorage ){
		      		            	
        	/*
             * Au démarrage de l'application, trouve dataKey et 
             * sa valeur dans local et traite le résultat dans
             * getResult().
             */ 
            jObjStorage.dvjhStorage( "get", "local", dataKey, getResult );
        	
        	/*
        	 * Bouton enregistre les coordonnées
        	 */
		    jObjSave.on( "click", function(){
		    	var pos = parseInt( prompt( "Sauvegarder dans le bouton numéro (1 à 20 inclus) ?", 1 ), 10 ) || 1;
		    	
		    	if ( pos < 1 ){
		    		pos = 1;
		    	} else if ( pos > 20 ){
		    		pos = 20;
		    	}

		    	mesDatas[ --pos ] = {
		    		"rstep" : rstep,
		    		"istep" : istep,
		    		"r1" : r1,
		    		"r2" : r2,
		    		"i1" : i1,
		    		"i2" : i2,
		    		"nmax" : nmax,
					"jc" : jc
		    	};
		            
	            // stocke dataKey et sa valeur dans data 
	            jObjStorage.dvjhStorage( "set", "data", dataKey, mesDatas );
	            
	            // copie dataKey et sa valeur dans le localStorage du navigateur 
	            jObjStorage.dvjhStorage( "copy", "data", "local", dataKey );
		    });
		    
		    jObjBtnCoords.on( "click", function(){
		    	enterFullScreen( element );
		    	
		    	var pos = $( this ).data( "dvjhPos" );
		    	
		    	rstep = mesDatas[ pos ].rstep;
		    	istep = mesDatas[ pos ].istep;
		    	r1 = mesDatas[ pos ].r1;
		    	r2 = mesDatas[ pos ].r2;
		    	i1 = mesDatas[ pos ].i1;
		    	i2 = mesDatas[ pos ].i2;
		    	nmax = mesDatas[ pos ].nmax;
				jc = mesDatas[ pos ].jc;
		    	
		    	jObjIter.val( nmax );
		    	jObjZoom.val( 1 );
		    	$( "input[name='sens']" ).eq( 0 ).prop( "checked", true );
                jObjAspect.val( jc );
		    	
		    	message();
		    });
		    
		    // Bouton reset
		    jObjReset.on( "click", function(){
		    	jObjStorage.dvjhStorage( "clearAll" );
		    	
		    	getResult( dataKey, null );
		    });
        } 
    } 
    catch( e ){ 
        alert( "dvjhStorage, " + e.message ); 
    } 
});

Fichier canvasWorker.js

"use strict";

onmessage = function( event ){
	var width = event.data.width,
	    height = event.data.height,
	    r1 = event.data.r1,
	    r2 = event.data.r2,
	    i1 = event.data.i1,
	    i2 = event.data.i2,
	    rstep = event.data.rstep,
	    istep = event.data.istep,
	    nmax = event.data.nmax,
	    fond = event.data.fond,
	    img = event.data.img,
	    pix = img.data,
	    complexe = function(cr, ci){
	        var zr = 0,
	            zi = 0,
	            zr_next,
	            zi_next;
	 
	        for (var n = 1; n <= nmax; n++){
	            zr_next = zr*zr - zi*zi + cr;
	            zi_next = 2*zr*zi + ci;
	 
	            if ((zr_next*zr_next + zi_next*zi_next) > 4){
	                return n;
	            }
	 
	            zr = zr_next;
	            zi = zi_next;
	        }
	 
	        return 0;
	    },
	    draw = function(rmin, imin, rmax, imax){
	        rstep = (rmax - rmin) / width;
	        istep = (imax - imin) / height;
	 
	        var t1 = new Date().getTime(),
	            t2,
	            z = -1,
	            thr = Math.floor(nmax / 5),
	            eThr,
	            i,
	            r,
	            e,
	            red,
	            green,
	            blue;
	        
	        for(var y = 0; y < height; y++) {
	            i = imin + y * istep;
	            for(var x = 0; x < width; x++) {
	                r = rmin + x * rstep;
	                e = complexe(r, i);
	                eThr = e/thr;
	                if(e > 0) {
	                	if ( fond == 1 ){
		                    if(e <= thr) {
		                        red = Math.floor(eThr * 255);
		                        green = 0;
		                        blue = 0;
		                    } else {
		                        e -= thr;
		                        eThr = e/thr;
		                        green = Math.floor(eThr * 127.5);
		                        red = 0; 
		                        blue = Math.floor(eThr * 255);
		                    }
		            	} else if ( fond == 2 ){
		                    if(e <= thr) {
		                        green = Math.floor(eThr * 255);
		                        red = 0;
		                        blue = 0;
		                    } else {
		                        e -= thr;
		                        eThr = e/thr;
		                        red = Math.floor(eThr * 127.5);
		                        green = 0; 
		                        blue = Math.floor(eThr * 255);
		                    }
		            	} else if ( fond == 3 ) {
		                    if(e <= thr) {
		                        blue = Math.floor(eThr * 255);
		                        green = 0;
		                        red = 0;
		                    } else {
		                        e -= thr;
		                        eThr = e/thr;
		                        red = Math.floor(eThr * 127.5);
		                        blue = 0; 
		                        green = Math.floor(eThr * 255);
		                    }		            		
		            	} else if ( fond == 4 ){
		                    if(e <= thr) {
		                        red = Math.floor(eThr * 255);
		                        blue = 0;
		                        green = 0;
		                    } else {
		                        e -= thr;
		                        eThr = e/thr;
		                        red = 0;
		                        blue = 255 - Math.floor(eThr * 127.5); 
		                        green = Math.floor(eThr * 255);
		                    }		            		
		            	} else {
		                    if(e <= thr) {
		                        red = Math.floor(eThr * 255);
		                        blue = 0;
		                        green = 0;
		                    } else {
		                        e -= thr;
		                        eThr = e/thr;
		                        red = 255 - Math.floor(eThr * 25);
		                        blue = Math.floor(eThr * 127.5); 
		                        green = Math.floor(eThr * 255);
		                    }
		            	}
	                } else {
	                    red = 0;
	                    green = 0;
	                    blue = 0;
	                }
	                pix[z += 1] = red;
	                pix[z += 1] = green;
	                pix[z += 1] = blue;
	                z += 1;
	            }
	        }
	        
	        t2 = new Date().getTime();
	        return t2 - t1;
	    };
	    
	    var ms = draw( r1, i1, r2, i2 );
	    
	    postMessage({
	    	"ms" : ms,
	    	"rstep" : rstep,
	    	"istep" : istep,
	    	"r1" : r1,
	    	"r2" : r2,
	    	"i1" : i1,
	    	"i2" : i2,
	    	"img" : img
	    });
};

À bientôt !

Veuillez poser vos questions
techniques sur les forums DVP,
s'il vous plait.

Avertissement solennel

Autodidacte en informatique, l’auteur a tous les défauts de sa qualité. Si vous vous inspirez, copiez ou pire utilisez le contenu de cette page, vous êtes téméraire, inconscient du danger !

Reconnaissant avoir été dûment informé, vous déchargez l’auteur et à fortiori l’hébergeur du site de toute responsabilité dans les graves dégâts que vous causerez sûrement !

Vous n'aurez jamais fini d'apprendre la programmation, aussi apprenez à apprendre en vous amusant.

Creative Commons License Attribution-Share Alike 2.0 Belgium Except where otherwise noted, content on this site is licensed under a Creative Commons License : Attribution-Share Alike 2.0 Belgium

Mention obligatoire : "Auteur : Hagnoul Daniel (https://www.developpez.net/forums/u285162/danielhagnoul/)"