Changeset 22894


Ignore:
Timestamp:
07/03/18 01:05:04 (7 years ago)
Author:
dlcheng
Message:

CHG (JS): Updating js processing scripts.

Location:
issm/trunk-jpl/src
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • issm/trunk-jpl/src/c/bamg/BamgGeom.h

    r12821 r22894  
    77class BamgGeom{
    88
     9
     10// HI DANIEL I'M DANIEL.
     11//FLATTEN THAT ARRAY AND SET THAT SIZE. THANKS.
    912        public:
    1013                int     VerticesSize[2];
  • issm/trunk-jpl/src/m/array/arrayoperations.js

    r22878 r22894  
    258258        return notarray;
    259259} //}}}
     260function ArrayFlip(array) { //{{{
     261       
     262        var notarray=array.slice();
     263        for (var i=0;i<array.length;i++)notarray[i]=array[i]^1;
     264        return notarray;
     265} //}}}
    260266function ArrayCopy(array) { //{{{
    261267
     
    293299        for(var i=0;i<array.length;i++){
    294300            for(var j=0;j<array[0].length;j++){
    295                 if (Number.isNaN(array[i][j])) return 1;
     301                if (isNaN(array[i][j])) return 1;
    296302            }
    297303        }
     
    299305    else{
    300306        for(var i=0;i<array.length;i++){
    301             if (Number.isNaN(array[i])) return 1;
     307            if (isNaN(array[i])) return 1;
    302308        }
    303309    }
     
    333339function ArrayAnyEqual(array,value) { //{{{
    334340       
    335         if(!Number.isNaN(value)){
     341        if(!isNaN(value)){
    336342                for(var i=0;i<array.length;i++){
    337343                        if (array[i]==value)return 1;
     
    340346        else{
    341347                for(var i=0;i<array.length;i++){
    342                         if (Number.isNaN(array[i]))return 1;
     348                        if (isNaN(array[i]))return 1;
    343349                }
    344350        }
     
    553559
    554560} //}}}
     561function typedArraySliceSupport() { //{{{
     562        //TypedArray compatibility for Safari/IE
     563        if (typeof Int8Array !== 'undefined') {
     564                if (!Int8Array.prototype.fill) { Int8Array.prototype.fill = Array.prototype.fill; }
     565                if (!Int8Array.prototype.slice) { Int8Array.prototype.slice = Array.prototype.slice; }
     566        }
     567        if (typeof Uint8Array !== 'undefined') {
     568                if (!Uint8Array.prototype.fill) { Uint8Array.prototype.fill = Array.prototype.fill; }
     569                if (!Uint8Array.prototype.slice) { Uint8Array.prototype.slice = Array.prototype.slice; }
     570        }
     571        if (typeof Uint8ClampedArray !== 'undefined') {
     572                if (!Uint8ClampedArray.prototype.fill) { Uint8ClampedArray.prototype.fill = Array.prototype.fill; }
     573                if (!Uint8ClampedArray.prototype.slice) { Uint8ClampedArray.prototype.slice = Array.prototype.slice; }
     574        }
     575        if (typeof Int16Array !== 'undefined') {
     576                if (!Int16Array.prototype.fill) { Int16Array.prototype.fill = Array.prototype.fill; }
     577                if (!Int16Array.prototype.slice) { Int16Array.prototype.slice = Array.prototype.slice; }
     578        }
     579        if (typeof Uint16Array !== 'undefined') {
     580                if (!Uint16Array.prototype.fill) { Uint16Array.prototype.fill = Array.prototype.fill; }
     581                if (!Uint16Array.prototype.slice) { Uint16Array.prototype.slice = Array.prototype.slice; }
     582        }
     583        if (typeof Int32Array !== 'undefined') {
     584                if (!Int32Array.prototype.fill) { Int32Array.prototype.fill = Array.prototype.fill; }
     585                if (!Int32Array.prototype.slice) { Int32Array.prototype.slice = Array.prototype.slice; }
     586        }
     587        if (typeof Uint32Array !== 'undefined') {
     588                if (!Uint32Array.prototype.fill) { Uint32Array.prototype.fill = Array.prototype.fill; }
     589                if (!Uint32Array.prototype.slice) { Uint32Array.prototype.slice = Array.prototype.slice; }
     590        }
     591        if (typeof Float32Array !== 'undefined') {
     592                if (!Float32Array.prototype.fill) { Float32Array.prototype.fill = Array.prototype.fill; }
     593                if (!Float32Array.prototype.slice) { Float32Array.prototype.slice = Array.prototype.slice; }
     594        }
     595        if (typeof Float64Array !== 'undefined') {
     596                if (!Float64Array.prototype.fill) { Float64Array.prototype.fill = Array.prototype.fill; }
     597                if (!Float64Array.prototype.slice) { Float64Array.prototype.slice = Array.prototype.slice; }
     598        }
     599        if (typeof TypedArray !== 'undefined') {
     600                if (!TypedArray.prototype.fill) { TypedArray.prototype.fill = Array.prototype.fill; }
     601                if (!TypedArray.prototype.slice) { TypedArray.prototype.slice = Array.prototype.slice; }
     602        }
     603} //}}}
  • issm/trunk-jpl/src/m/classes/clusters/generic.js

    r21911 r22894  
    1 //GENERIC class definition
    2 //
    3 //   Usage:
    4 //      generic=new generic();
     1// Execute script in strict mode
     2'use strict';
     3/**
     4 * generic - Class that allows for sending requests to server and handling response or errors
     5 *
     6 *      Usage:
     7 *              generic = new generic();
     8 *
     9 *      Todo:
     10 *              Convert to ES6 class
     11 */
     12function generic() {
     13        // Retrieve options and apply to properties
     14        // {{{
     15        let args        = Array.prototype.slice.call(arguments);
     16        let options = new pairoptions(args.slice(0, args.length));
     17       
     18        this.url                        = options.getfieldvalue('url', '');
     19        this.np                         = options.getfieldvalue('np', 3);
     20        this.codeversion        = options.getfieldvalue('codeversion', 20486);
     21        this.codepath           = options.getfieldvalue('codepath', 'issmdir/bin');
     22        this.executionpath      = options.getfieldvalue('executionpath', 'issmdir/execution');
     23        //}}}
     24       
     25       
     26        // Methods
     27        //{{{
     28        this.disp = function() { //{{{
     29                console.log(sprintf('   generic class echo:'));
     30                console.log(sprintf('    url: %s', this.url));
     31                console.log(sprintf('    np: %i', this.np));
     32                console.log(sprintf('    codepath: %s', this.codepath));
     33                console.log(sprintf('    executionpath: %s', this.executionpath));
     34        }; //}}}
     35       
     36        this.classname = function() { //{{{
     37                return 'generic';
     38        }; //}}}
     39       
     40        this.checkconsistency = function(md, solution, analyses) { //{{{
     41                if (cluster.np < 1) {
     42                        md.checkmessage('Number of processors should be at least 1!');
     43                }
     44                if (isNaN(cluster.np)) {
     45                        md.checkmessage('Number of processors NaN!');
     46                }
     47        }; //}}}
     48       
     49        this.BuildQueueScript = function(cluster, dirname, modelname, solution, io_gather, isvalgrind, isgprof, isdakota) { //{{{
     50                //write queuing script
     51                //what is the executable being called?
     52                executable      = 'issm.exe';
     53               
     54                fid             = fopen(modelname + '.queue','w');
     55                fprintf(fid, '#!%s\n', cluster.shell);
     56                fprintf(fid, 'mpiexec -np %i %s/%s %s %s %s 2> %s.errlog >%s.outlog ', cluster.np, cluster.codepath, executable, EnumToString(solution), cluster.executionpath + '/' + dirname, modelname, modelname, modelname);                                       
     57                fclose(fid);
     58        }; //}}}
     59       
     60        this.UploadAndRun = function(md, fid, toolkitsstring, solutionstring, name, runtimename, successCallback, errorCallback, solveButtonId, callout, withProgressBar) { //{{{
     61                /* Local constants */
     62                let PROGRESS_BAR_ID                             = 'solve-progress-bar';
     63                let PROGRESS_BAR_TEXT_PERCENTAGE_ID = 'progress-bar-text-percentage';           
     64               
     65                /* Local variables */
     66                let hasCallout                                  = false;
     67                let isProgressBarLoaded                 = false;
     68                let progressBar                                 = {};
     69                let progressBarTextPercentage   = {};
     70                let request                                     = {};
     71                let solveButton                                 = $(solveButtonId);
     72                let solveButtonText                     = !vesl.helpers.isEmptyOrUndefined(solveButton) ? solveButton.text() : ''; // Save initial solve button text
     73               
     74                /* Local functions */
     75                // NOTE: After conversion of generic to ES6 class, these should be class methods
     76                function loadProgressBar() {
     77                        callout.setContent('\
     78                                <div class="progress-bar-wrapper">\
     79                                        <progress id="' + PROGRESS_BAR_ID + '" value="0" max="100"></progress>\
     80                                        <div class="progress-bar-text">\
     81                                                <span id="' + PROGRESS_BAR_TEXT_PERCENTAGE_ID + '">0</span>\
     82                                                <span>%</span>\
     83                                        </div>\
     84                                </div>\
     85                        ');
     86                       
     87                        progressBar                             = $('#' + PROGRESS_BAR_ID);
     88                        progressBarTextPercentage       = $('#' + PROGRESS_BAR_TEXT_PERCENTAGE_ID);
     89                        isProgressBarLoaded             = true;
     90                }
     91               
     92                function setProgressBar(progress) {
     93                        progressBar.val(progress);
     94                        progressBarTextPercentage.text(progress);
     95                }
     96               
     97                // Check certain arguments
     98                hasCallout = !vesl.helpers.isEmptyOrUndefined(callout);         
     99               
     100                // Check that we have a connection
     101                if (!navigator.onLine) {
     102                        console.log('Error: no connection!');
     103                        if (hasCallout) {
     104                                callout.set('No connection!', '');
     105                        } else {
     106                                solveButton.text('No connection!').prop('disabled', false);
     107                        }
     108                        errorCallback();
     109                        return;
     110                }
     111               
     112                // Create request
     113                request = new XMLHttpRequest();
     114                request.open('POST', this.url, true);
     115               
     116                // Set request properties
     117                request.position        = 0; // Keep track of current parsing position in repsonseText
     118                request.timeout         = 1000 * 60 * 60 * 3; // 3 hrs (in milliseconds); NOTE: This should match FastCgiServer timeout in Apache conf
     119               
     120                request.ontimeout = function(event) { //{{{
     121                        console.log('Error: timeout!');
     122                       
     123                        if (hasCallout) {
     124                                callout.set(vesl.ERROR_HEADER_GENERAL, '<p>Request timeout! ' + vesl.ERROR_CONTENT_TRY_AGAIN + '</p>');
     125                        } else {
     126                                solveButton.text('Timeout!').prop('disabled', false);
     127                        }
     128                       
     129                        errorCallback();
     130                }; //}}}
     131               
     132                request.onerror = function(event) { //{{{
     133                        console.log('Error: could not run!');
     134                       
     135                        if (hasCallout) {
     136                                callout.set(vesl.ERROR_HEADER_GENERAL, '<p>Something went wrong. ' + vesl.ERROR_CONTENT_TRY_AGAIN + '</p>');
     137                        } else {
     138                                solveButton.text('Could not run!').prop('disabled', false);
     139                        }
     140                       
     141                        errorCallback();
     142                }; //}}}
     143               
     144                request.upload.onprogress = function(event) { //{{{
     145                        let progress = (event.loaded / event.total * 100).toFixed(0);
     146                       
     147                        if (hasCallout) {
     148                                callout.setHeader('Sending request...');
     149                                if (withProgressBar) {
     150                                        if (!isProgressBarLoaded) {
     151                                                loadProgressBar();
     152                                        }
     153                                        setProgressBar(progress);
     154                                } else {
     155                                        callout.setContent('<p>' + progress + '%</p>');
     156                                }
     157                        } else {
     158                                solveButton.text('Sending: ' + progress + '%');
     159                        }
     160        }; //}}}
     161       
     162                request.onprogress = function(event) { //{{{
     163                        /* Local variables */
     164                        let progress    = 0;
    5165
    6 function generic (){
    7         //properties
    8         // {{{
    9         var args = Array.prototype.slice.call(arguments);
    10         var options = new pairoptions(args.slice(0,args.length));
     166                        // Receive updates by parsing message length as a 32-bit hex string of form 0x*09ABCDEF))
     167                        let startIndex  = request.position;
     168                        let endIndex    = request.position + 10;
     169                       
     170                        if (request.responseText.length >= endIndex) { // Ensure entire hex string is loaded
     171                                let chunkSize = parseInt(request.responseText.slice(startIndex, endIndex));
     172                               
     173                                startIndex      = endIndex;
     174                                endIndex        = startIndex + chunkSize;
     175                               
     176                                if (chunkSize >= 1024) { // Arbitrary maximium size of message (Must be below minimium size of model results)
     177                                        progress = ((request.responseText.length - request.position) / chunkSize * 100).toFixed(0);
     178                                        if (hasCallout) {
     179                                                callout.setHeader('Downloading result...');
     180                                                if (withProgressBar) {
     181                                                        setProgressBar(progress);
     182                                                } else {
     183                                                        callout.setContent('<p>' + progress + '%</p>');
     184                                                }
     185                                        } else {
     186                                                solveButton.text('Downloading: ' + progress + '%').prop('disabled', true);
     187                                        }
     188                                } else if (request.responseText.length >= endIndex) { // Ensure entire chunk is loaded
     189                                        progress = parseInt(request.responseText.slice(startIndex, endIndex));
     190                                        if (hasCallout) {
     191                                                callout.setHeader('Computing...');
     192                                                if (withProgressBar) {
     193                                                        setProgressBar(progress);
     194                                                } else {
     195                                                        callout.setContent('<p>' + progress + '%</p>');
     196                                                }
     197                                        } else {
     198                                                solveButton.text('Computing: ' + progress + '%').prop('disabled', true);
     199                                        }
     200                                        request.position = endIndex;
     201                                }
     202                        }
     203                }; //}}}
     204               
     205                request.onload = function(event) { //{{{
     206                        /* Local variables */
     207                        //{{{
     208                        let buffer                              = {};
     209//                      let bufferInflated              = {};
     210                        let responseText                = '';
     211                        //}}}
     212                       
     213                        // TODO: Get context to this.str2ab or otherwise declare it in order to avoid duplication
     214                        function str2ab(str) { //{{{
     215                                let buffer = new Uint8Array(str.length);
     216                                for (let i = 0, strLen = str.length; i < strLen; ++i) {
     217                                        buffer[i] = str.charCodeAt(i);
     218                                }
     219                                return buffer;
     220                        } //}}}
     221                       
     222                        try {
     223/*
     224                                console.log(request.responseText);
     225                                console.log('request.position : ' + request.position);
     226                                console.log('request.responseType : ' + request.responseType);
     227                                console.log('request.responseText.length : ' + request.responseText.length);
     228*/
     229                                responseText    = window.atob(request.responseText.slice(request.position + 10).replace(/\s/g, ''));
     230//                              console.log('responseText.length : ' + responseText.length);
     231                                buffer                  = str2ab(responseText);
     232//                              console.log('buffer.length : ' + buffer.length);
     233/*
     234                    bufferInflated      = UZIP.inflate(buffer);
     235                                console.log('bufferInflated.length : ' + bufferInflated.length);
     236*/
     237                   
     238/*
     239                                returnBuffer            = new Uint8Array(buffer);
     240                                returnBufferSize        = returnBuffer.byteLength;
     241*/
     242                       
     243                                //Write result buffer to file for debugging. Filename and MIME type are optional.
     244                                //writetofile(returnBuffer, 'resultBuffer', 'application/octet-stream');
     245//                              md.results = parseresultsfrombuffer(md, bufferInflated, bufferInflated.length);
     246                                md.results = parseresultsfrombuffer(md, buffer, buffer.length);
     247                               
     248                                // Let front end script handle changes to callout
     249                                if (hasCallout) {
     250                                        callout.set('Success!', '<p>Solve successful</p>');
     251                                } else {
     252                                        solveButton.text(solveButtonText).prop('disabled', false);
     253                                }
     254                                successCallback();
     255                        } catch (e) {
     256                                console.log(e);
     257                                if (vesl.string.startsWith(responseText, 'Error')) {
     258                                        if (hasCallout) {
     259                                                callout.set(vesl.ERROR_HEADER_GENERAL, '<p>Something went wrong. ' + vesl.ERROR_CONTENT_TRY_AGAIN + '</p>');
     260                                        } else {
     261                                                solveButton.text('ISSM error!').prop('disabled', false);
     262                                        }
     263                                } else {
     264                                        if (hasCallout) {
     265                                                callout.set(vesl.ERROR_HEADER_GENERAL, '<p>Something went wrong. ' + vesl.ERROR_CONTENT_TRY_AGAIN + '</p>');
     266                                        } else {
     267                                                solveButton.text('JS error!').prop('disabled', false);
     268                                        }
     269                                }
     270                                errorCallback();
     271                        }
     272                }; //}}}
     273               
     274                request.responseType = 'application/octet-stream';
     275               
     276                /* Construct request */
     277                let npbuffer = this.str2ab(md.cluster.np.toString());
     278                npbuffer = UZIP.deflate(npbuffer);
     279                let nplength = new Uint32Array(1);
     280                nplength[0] = npbuffer.byteLength;
     281               
     282                let codeversionbuffer = this.str2ab(md.cluster.codeversion.toString());
     283                codeversionbuffer = UZIP.deflate(codeversionbuffer);
     284                let codeversionlength = new Uint32Array(1);
     285                codeversionlength[0] = codeversionbuffer.byteLength;
     286               
     287                let runtimenamebuffer = this.str2ab(runtimename);
     288                runtimenamebuffer = UZIP.deflate(runtimenamebuffer);
     289                let runtimenamelength = new Uint32Array(1);
     290                runtimenamelength[0] = runtimenamebuffer.byteLength;
     291               
     292                let namebuffer = this.str2ab(name);
     293                namebuffer = UZIP.deflate(namebuffer);
     294                let namelength = new Uint32Array(1);
     295                namelength[0] = namebuffer.byteLength;
     296               
     297                let toolkitsbuffer = this.str2ab(toolkitsstring);
     298                toolkitsbuffer = UZIP.deflate(toolkitsbuffer);
     299                let toolkitslength = new Uint32Array(1);
     300                toolkitslength[0] = toolkitsbuffer.byteLength;
     301               
     302                let solutionbuffer = this.str2ab(solutionstring);
     303                solutionbuffer = UZIP.deflate(solutionbuffer);
     304                let solutionlength = new Uint32Array(1);
     305                solutionlength[0] = solutionbuffer.byteLength;
     306               
     307                let binbuffer = new Uint8Array(fid.rawbuffer()); //seems that 16 bits length could be incompatible.
     308                binbuffer = UZIP.deflate(binbuffer);
     309                let binlength = new Uint32Array(1);
     310                binlength[0] = binbuffer.byteLength;
     311               
     312                let data = new Blob(
     313                        [
     314                                nplength,
     315                                npbuffer,
     316                                codeversionlength,
     317                                codeversionbuffer,
     318                                runtimenamelength,
     319                                runtimenamebuffer,
     320                                namelength,
     321                                namebuffer,
     322                                toolkitslength,
     323                                toolkitsbuffer,
     324                                solutionlength,
     325                                solutionbuffer,
     326                                binlength,
     327                                binbuffer
     328                        ]
     329                );
    11330
    12         this.url=options.getfieldvalue('url','');
    13         this.np=options.getfieldvalue('np',3);
    14         this.codeversion=options.getfieldvalue('codeversion',20486);
    15         this.codepath=options.getfieldvalue('codepath','issmdir/bin');
    16         this.executionpath=options.getfieldvalue('executionpath','issmdir/execution');
    17         //}}}
    18         //methods
    19         this.disp= function(){// {{{
    20                 console.log(sprintf('   generic class echo:'));
    21                 console.log(sprintf('    url: "%s"',this.url));
    22                 console.log(sprintf('    np: %i',this.np));
    23                 console.log(sprintf('    codepath: "%s"',this.codepath));
    24                 console.log(sprintf('    executionpath: "%s"',this.executionpath));
    25         }// }}}
    26         this.classname= function(){// {{{
    27                 return "generic";
    28         }// }}}
    29         this.checkconsistency = function (md,solution,analyses) { //{{{
    30                 if (cluster.np<1){
    31                         md.checkmessage('number of processors should be at least 1');
    32                 }
    33                 if (isNaN(cluster.np)){
    34                         md.checkmessage('number of processors should not be NaN!');
    35                 }
    36         } //}}}
    37         this.BuildQueueScript = function (cluster,dirname,modelname,solution,io_gather,isvalgrind,isgprof,isdakota) { // {{{
    38 
    39                         //write queuing script
    40                         //what is the executable being called?
    41                         executable='issm.exe';
    42 
    43                         fid=fopen(modelname+'.queue','w');
    44                         fprintf(fid,'#!%s\n',cluster.shell);
    45                         fprintf(fid,'mpiexec -np %i %s/%s %s %s %s 2> %s.errlog >%s.outlog ',cluster.np,cluster.codepath,executable,EnumToString(solution),cluster.executionpath+'/'+dirname,modelname,modelname,modelname);                                   
    46                         fclose(fid);
    47         } //}}}
    48         this.UploadAndRun = function (md,callbackfunction,callbackerrorfunction,callbackid,fid,toolkitsstring,solutionstring,name,runtimename) { //{{{
    49                 if (!navigator.onLine) { //{{{
    50                         $(callbackid).html(sprintf("%-16s", "NO CONNECTION")).prop("disabled", false);
    51                         callbackerrorfunction();
    52                         return;
    53                 } //}}}
    54                 var request = new XMLHttpRequest();
    55                 request.open("POST", this.url, true);
    56                 $(callbackid).html(sprintf("%-16s", "CONNECTING...")).prop("disabled", true);
    57                 request.position = 0; //Keep track of current parsing position in repsonseText
    58                 request.timeout = 180000;
    59                 request.ontimeout = function (event) { //{{{
    60                         $(callbackid).html(sprintf("%-16s", "TIMEOUT")).prop("disabled", false);
    61                         callbackerrorfunction();
    62                 } //}}}
    63                 request.onerror = function (event) { //{{{
    64                         $(callbackid).html(sprintf("%-16s", "COULD NOT RUN")).prop("disabled", false);
    65                         callbackerrorfunction();
    66                 } //}}}
    67                 request.upload.onprogress = function(event) { //{{{
    68                         var progress = (event.loaded / event.total * 100).toFixed(0);
    69                         $(callbackid).html(sprintf("%-20s", "UPLOADING: " + progress + "%"));
    70         } //}}}
    71                 request.onprogress = function (event) { //{{{
    72                         //Receive updates by parsing message length as a 32-bit hex string of form 0x*09ABCDEF))
    73                         var startIndex = request.position;
    74                         var endIndex = request.position + 10;
    75                         if (request.responseText.length >= endIndex) { //Ensure entire hex string is loaded
    76                                 var chunkSize = parseInt(request.responseText.slice(startIndex, endIndex));
    77                                 startIndex = endIndex;
    78                                 endIndex = startIndex + chunkSize;
    79                                 if (chunkSize >= 1024) { //Arbitrary maximium size of message (Must be below minimium size of model results)
    80                                         $(callbackid).html(sprintf("%-20s", "DOWNLOADING: " + ((request.responseText.length - request.position) / chunkSize * 100).toFixed(0) + "%")).prop("disabled", true);
    81                                 }
    82                                 else if (request.responseText.length >= endIndex) { //Ensure entire chunk is loaded
    83                                         var responseChunk = request.responseText.slice(startIndex, endIndex);
    84                                         $(callbackid).html(responseChunk);
    85                                         request.position = endIndex;
    86                                 }
    87                         }
    88                 }; //}}}
    89                 request.onload = function (event) { //{{{
    90                         //get context to this.str2ab to avoid duplciation
    91                         function str2ab(str) {
    92                                 var buf = new Uint8Array(str.length);
    93                                 for (var i=0, strLen=str.length; i < strLen; i++) {
    94                                         buf[i] = str.charCodeAt(i);
    95                                 }
    96                                 return buf;
    97                         }
    98                         var responseText = window.atob(request.responseText.slice(request.position + 10).replace(/\s/g, ''));
    99             var buffer = pako.inflate(str2ab(responseText));
    100                         var returnBuffer = new Uint8Array(buffer);
    101                         var returnBuffer_size = returnBuffer.byteLength;
    102                         try {
    103                                 //Write result buffer to file for debugging. Filename and MIME type are optional.
    104                                 //writetofile(returnBuffer, "resultBuffer", "application/octet-stream");
    105                                 md.results = parseresultsfrombuffer(md,returnBuffer,returnBuffer_size);
    106                                 $(callbackid).html(sprintf("%-16s", "RUN")).prop("disabled", false);
    107                                 callbackfunction();
    108                         }
    109                         catch (e) {
    110                                 if (responseText.startsWith('Error')) {
    111                                         console.log(responseText);
    112                                         $(callbackid).html(sprintf("%-16s", "ISSM ERROR")).prop("disabled", false);
    113                                 }
    114                                 else {
    115                                         $(callbackid).html(sprintf("%-16s", "JS ERROR")).prop("disabled", false);
    116                                         console.log(e);
    117                                 }
    118                                 callbackerrorfunction();
    119                         }
    120                        
    121                 }; //}}}
    122                
    123                 var npbuffer = this.str2ab(md.cluster.np.toString());
    124                 npbuffer = pako.deflate(npbuffer);
    125                 var nplength = new Uint32Array(1);
    126                 nplength[0] = npbuffer.byteLength;
    127                
    128                 var codeversionbuffer = this.str2ab(md.cluster.codeversion.toString());
    129                 codeversionbuffer = pako.deflate(codeversionbuffer);
    130                 var codeversionlength = new Uint32Array(1);
    131                 codeversionlength[0] = codeversionbuffer.byteLength;
    132                
    133                 var runtimenamebuffer = this.str2ab(runtimename);
    134                 runtimenamebuffer = pako.deflate(runtimenamebuffer);
    135                 var runtimenamelength = new Uint32Array(1);
    136                 runtimenamelength[0] = runtimenamebuffer.byteLength;
    137                
    138                 var namebuffer = this.str2ab(name);
    139                 namebuffer = pako.deflate(namebuffer);
    140                 var namelength = new Uint32Array(1);
    141                 namelength[0] = namebuffer.byteLength;
    142                
    143                 var toolkitsbuffer = this.str2ab(toolkitsstring);
    144                 toolkitsbuffer = pako.deflate(toolkitsbuffer);
    145                 var toolkitslength = new Uint32Array(1);
    146                 toolkitslength[0] = toolkitsbuffer.byteLength;
    147                
    148                 var solutionbuffer = this.str2ab(solutionstring);
    149                 solutionbuffer = pako.deflate(solutionbuffer);
    150                 var solutionlength = new Uint32Array(1);
    151                 solutionlength[0] = solutionbuffer.byteLength;
    152                
    153                 var binbuffer = new Uint8Array(fid.rawbuffer()); //seems that 16 bits length could be incompatible.
    154                 binbuffer = pako.deflate(binbuffer);
    155                 var binlength = new Uint32Array(1);
    156                 binlength[0] = binbuffer.byteLength;
    157                
    158                 var data = new Blob([nplength,npbuffer,codeversionlength,codeversionbuffer,runtimenamelength,runtimenamebuffer,namelength,namebuffer,toolkitslength,toolkitsbuffer,solutionlength,solutionbuffer,binlength,binbuffer]);
    159                
    160                 request.responseType = 'application/octet-stream';
     331                // Send request
    161332                request.send(data);
    162333               
    163         } //}}}
     334                if (hasCallout) {
     335                        callout.set('Connecting...', '');
     336                } else {
     337                        solveButton.text('Connecting...').prop('disabled', true);
     338                }
     339        }; //}}}
     340       
    164341        this.ab2str = function(buf) { //{{{
    165342                return String.fromCharCode.apply(null, new Uint16Array(buf));
    166         } //}}}
     343        }; //}}}
     344       
    167345        this.str2ab = function(str) { //{{{
    168                 var buf = new Uint8Array(str.length);
    169                 for (var i=0, strLen=str.length; i < strLen; i++) {
     346                let buf = new Uint8Array(str.length);
     347               
     348                for (let i = 0, strLen = str.length; i < strLen; i++) {
    170349                        buf[i] = str.charCodeAt(i);
    171350                }
     351               
    172352                return buf;
    173         } //}}}
     353        }; //}}}
    174354}
  • issm/trunk-jpl/src/m/plot/applyoptions.js

    r22434 r22894  
    1313                        //{{{ Variable options initialization
    1414                        var caxis = options.getfieldvalue('caxis');
    15                         var colorbarinnerlabels = options.getfieldvalue('colorbarinnerlabels','off');
    1615                        var ccanvasid, ctitleid, clabelsid, ccanvas, ctitle, clabels, ccontext, cmap, colorbar, cwidth, cheight, cgradient, color, y, x;
    1716                        //}}}
     
    8382                        clabelsid = options.getfieldvalue('colorbarid', ccanvasid).replace('canvas','labels');
    8483                        clabels = $('#'+clabelsid);
    85                         if (colorbarinnerlabels=='on') {
    86                                 clabels.removeClass('sim-colorbar-labels-outer');
    87                                 clabels.addClass('sim-colorbar-labels-inner');
    88                         }
    89                         else {
    90                                 clabels.removeClass('sim-colorbar-labels-inner');
    91                                 clabels.addClass('sim-colorbar-labels-outer');
    92                         }
    9384                        var clabelstring = '';
    9485                        clabels.empty();
     
    137128        if (options.exist('maskregion')) {
    138129                var maskObject = options.getfieldvalue('maskregion',{'enabled':false});
    139                 if (maskObject.enabled && !VESL.Helpers.isEmptyOrUndefined(maskObject.colors)) {
     130                if (maskObject.enabled && !vesl.helpers.isEmptyOrUndefined(maskObject.colors)) {
    140131                        var x = 0;
    141132                        var sections = Object.keys(maskObject.colors).length + 1;
     
    157148        //}}}
    158149        //{{{ text display
    159         var overlaycanvasid = options.getfieldvalue('overlayid', options.getfieldvalue('canvasid')+'-overlay');
    160         var overlaycanvas = $('#'+overlaycanvasid)[0];
    161         if (!VESL.Helpers.isEmptyOrUndefined(overlaycanvas)) {
     150        var ctx;
     151        var overlaycanvasid;
     152        var overlaycanvas;
     153        //Only intialize overlay canvas once by checking if it's already been defined
     154        if (vesl.helpers.isEmptyOrUndefined(canvas.overlaycanvas)) {
    162155                //Get drawing context and save reference on main WebGL canvas
    163                 var ctx = overlaycanvas.getContext('2d');
     156                overlaycanvasid = options.getfieldvalue('overlayid', options.getfieldvalue('canvasid') + '-overlay')
     157                overlaycanvas = $('#' + overlaycanvasid)[0];
     158                ctx = overlaycanvas.getContext('2d');
    164159                canvas.overlaycanvas = overlaycanvas;
    165                
    166                 //Resize interal viewport coordinates to match screenspace coordinates
    167                 var rect = overlaycanvas.getBoundingClientRect();
    168                 overlaycanvas.width  = rect.width;
    169                 overlaycanvas.height = rect.height;
    170                
    171                 //Clear canvas each frame for any new drawings
    172                 canvas.overlayHandlers['draw'] = function(overlaycanvas) {
    173                         ctx.clearRect(0, 0, overlaycanvas.width, overlaycanvas.height);
    174                 }
    175160        }
    176         //{{{ lat long overlay
    177         if (options.exist('latlongoverlay')) {
    178                 var latitudes = {
    179                         //'-90': 1,
    180                         //'-65': .999,
    181                         '-60': 0.994046875,
    182                         '-45': 0.955729166666666,
    183                         '-30': 0.9226562500000024,
    184                         //'-15': 0.830729166666665,
    185                         '0': 0.74218749999999811,
    186                         //'15': 0.63932291666666663,
    187                         '30': 0.523390625000001,
    188                         '45': 0.4020001,
    189                         '60': 0.26953124999999978,
    190                         //'65': 0.225390625,
    191                         //'90': 0.0,
    192                 }
    193                 var longitudes = [-150, -120, -90, -60, -30, 0, 30, 60, 90, 120, 150, 180];
    194                 canvas.overlayHandlers['latlong'] = function(canvas) {
    195                         //Transform from world space to viewport space
    196                         var centerx = overlaycanvas.width / 2;
    197                         var centery = overlaycanvas.height / 2;
    198                         var radius = (overlaycanvas.height) / 2;
    199 
    200                         //Draw latitudes
    201                         ctx.setLineDash([5, 10]);
    202                         for(latitude in latitudes) {
    203                                 ctx.beginPath();
    204                                 ctx.arc(centerx, centery, radius * latitudes[latitude], 0, 2 * Math.PI);
    205                                 ctx.stroke();
    206                                 ctx.font = 'bold ' + String(options.getfieldvalue('colorbarfontsize', 18))+'px "Lato", Helvetica, Arial, sans-serif';
    207                                 ctx.fillStyle = options.getfieldvalue('colorbarfontcolor','black');
    208                                 ctx.strokeStyle = options.getfieldvalue('colorbarfontcolor','black');
    209                                 ctx.textAlign = 'center';
    210                                 ctx.textBaseline = 'middle';
    211                                 ctx.fillText(latitude, centerx, centery + radius * latitudes[latitude]);
    212                                 ctx.strokeText(latitude, centerx, centery + radius * latitudes[latitude]);
    213                         }
    214                         //Draw longitudes
    215                         ctx.setLineDash([1, 0]);
    216                         for (longitude in longitudes) {
    217                                 ctx.beginPath();
    218                                 ctx.moveTo(centerx, centery);
    219                                 ctx.lineTo(centerx + radius * Math.sin(longitudes[longitude] * DEG2RAD), centery + radius * Math.cos(longitudes[longitude] * DEG2RAD));
    220                                 ctx.stroke();
    221                         }
    222                 }
    223         } //}}}
    224         if (options.exist('textlabels')) {
     161        overlaycanvas = canvas.overlaycanvas;
     162        ctx = overlaycanvas.getContext('2d');
     163       
     164        if (options.exist('textlabels')) {//{{{
    225165                //Attatch new overlay handler to display text labels
    226166                var textLabels = options.getfieldvalue('textlabels',[]);
     
    239179                                // function declared in slr-gfm sim-front-end-controller.js
    240180                                // if labels are behind the globe sphere then skip iteartion and do not display them
    241                                 if (VESL.UI.isLabelVisible(textLabel)) {
     181                                if (vesl.ui.isLabelVisible(textLabel)) {
    242182                                        //Transform from world space to viewport space
    243183                                        var screenPoint = vec3.transformMat4(vec3.create(), textLabel.position, canvas.camera.vpMatrix);
     
    256196                        }
    257197                }
    258         } //}}}
     198        }//}}}
     199               
    259200        //{{{ additional rendering nodes
    260201        if (options.exist('render')) {
     
    275216
    276217                var renderObjects = options.getfieldvalue('render',{});
     218               
    277219                for (var renderObject in renderObjects) {
    278220                        //Modify renderObejct?
     
    289231                                color: defaultFor(object.color, 'black'),                                       //Diffuse color of object
    290232                                height: defaultFor(object.height, 25000),                                       //Height of object along y axis, currently for clouds only
    291                                 range: defaultFor(object.range, 120000),                                                //Range of sz plane to spawn object, currently for clouds only
    292                                 quantity: defaultFor(object.quantity, 15)                                       //Quantity of objects to display, currently for clouds only
     233                                range: defaultFor(object.range, 120000),                                        //Range of sz plane to spawn object, currently for clouds only
     234                                quantity: defaultFor(object.quantity, 15),                                      //Quantity of objects to display, currently for clouds only
     235                                source: defaultFor(object.source, 'NY'),                                        //Quantity of objects to display, currently for clouds only
     236                                targets: defaultFor(object.targets, ['NY'])                                     //Quantity of objects to display, currently for clouds only
    293237                        };
    294238                        if (!object.enabled) { continue; }
     
    382326                                node.patch('Vertices', [object.x, object.y, object.z], 'FaceColor', 'none');
    383327                        }
    384                         if ('city' === renderObject) {
     328                        if ('city' === renderObject && !vesl.helpers.isEmptyOrUndefined(overlaycanvas)) {
    385329                                //city
    386330                                var mesh = GL.Mesh.sphere({size: object.size});
     
    436380                                }
    437381                        }
     382                        if ('citylines' === renderObject) {
     383                                //city
     384                                node = new Node(
     385                                        'canvas', canvas,
     386                                        'options', options,
     387                                        'renderObject', object,
     388                                        'name', 'citylines',
     389                                        'shaderName', 'ColoredDiffuse',
     390                                        'drawMode', gl.LINES,
     391                                        'diffuseColor', object.color,
     392                                        'lineWidth', options.getfieldvalue('linewidth', 1),
     393                                        'scale', [object.scale, object.scale, object.scale],
     394                                        'rotation', [0, 0, 0]
     395                                );
     396                               
     397                                //For each target city, calculate the shortest line across the earth by performing a quaternion slerp.
     398                                //Treat source and target city as vectors to rotate to from the north pole.
     399                                //Then, slerp between the two rotations, and generate points across equidistance points on the earth to create the line.
     400                                var north = vec3.fromValues(0, 1, 0);
     401                                var source = object.source;
     402                                var sourceXYZ = vec3.fromValues(xcity[source], zcity[source], -ycity[source]);
     403                                var radius = vec3.length(sourceXYZ);
     404                                var lineSteps = 50;
     405                                var lineX = [];
     406                                var lineY = [];
     407                                var lineZ = [];
     408                                var lineXYZ = vec3.create();
     409
     410                                for (var i = 0; i < object.targets.length; i++) {
     411                                        var target = object.targets[i];
     412                                        var targetXYZ = vec3.fromValues(xcity[target], zcity[target], -ycity[target]);
     413                                        var axis = vec3.cross(vec3.create(), sourceXYZ, targetXYZ);
     414                                        vec3.normalize(axis, axis);             
     415                                       
     416                                        //Get the total angle between the two cities.
     417                                        var sourceXYZAxis = vec3.normalize(vec3.create(), sourceXYZ);
     418                                        var targetXYZAxis = vec3.normalize(vec3.create(), targetXYZ);
     419                                        var dotProduct = vec3.dot(sourceXYZAxis, targetXYZAxis);
     420                                        var totalAngle = Math.acos(dotProduct); //theta = arccos(u . v / (||u|| * ||v||); in this case, ||u|| and ||v|| are 1, since u and v are unit vectors.
     421                                       
     422                                        var lineQuat = quat.create();
     423                                        for (var j = 1; j <= lineSteps; j++) {
     424                                                //Calculate the partial rotation to obtain points on the line between the two cities.
     425                                                var angle = j / lineSteps * totalAngle;
     426                                                quat.setAxisAngle(lineQuat, axis, angle);
     427                                                quat.normalize(lineQuat, lineQuat);
     428                                                vec3.transformQuat(lineXYZ, sourceXYZ, lineQuat);
     429                                                //GL.LINES needs 2 points for each line - at the beginning, just use the sourceXYZ.
     430                                                //TODO: Eliminate this if statement.
     431                                                if (j === 1) {
     432                                                        lineX.push(sourceXYZ[0]);
     433                                                        lineY.push(sourceXYZ[1]);
     434                                                        lineZ.push(sourceXYZ[2]);
     435                                                } else {
     436                                                        lineX.push(lineX[lineX.length - 1]);
     437                                                        lineY.push(lineY[lineY.length - 1]);
     438                                                        lineZ.push(lineZ[lineZ.length - 1]);
     439                                                }
     440                                                lineX.push(lineXYZ[0]);
     441                                                lineY.push(lineXYZ[1]);
     442                                                lineZ.push(lineXYZ[2]);
     443                                        }
     444                                }
     445                                node.patch('Vertices', [lineX, lineY, lineZ]);
     446                        }
    438447                }
    439448        } //}}}
  • issm/trunk-jpl/src/m/plot/plot_mesh.js

    r22715 r22894  
    77        //   See also: PLOTMODEL, PLOT_MANAGER
    88
    9         //if ('mesh' in  canvas.nodes && options.getfieldvalue('cachenodes','on') === 'on') return;
     9        // If we already have the overlay and are using caching, short circuit
     10        if ('mesh' in canvas.nodes && options.getfieldvalue('cachenodes', 'off') === 'on') {
     11                return;
     12        }
    1013       
    11         //{{{ declare variables:
     14        /*
     15                Local variables
     16        */
     17        //{{{
    1218        //Process data and model
    1319        var meshresults = processmesh(md, [], options);
  • issm/trunk-jpl/src/m/plot/plot_overlay.js

    r22434 r22894  
    77        //   See also: PLOTMODEL, PLOT_MANAGER
    88
    9         if ('overlay' in  canvas.nodes && options.getfieldvalue('cachenodes','on') === 'on') return;
     9        // If we already have the overlay and are using caching, short circuit
     10        if ('overlay' in canvas.nodes && options.getfieldvalue('cachenodes', 'off') === 'on') {
     11                return;
     12        }
    1013       
    11         //{{{ declare variables:
     14        /*
     15                Local variables
     16        */
     17        //{{{
    1218        //Process data and model
    1319        var meshresults = processmesh(md, [], options);
  • issm/trunk-jpl/src/m/plot/plot_quiver.js

    r22434 r22894  
    1010        return;
    1111       
    12         if ('quiver' in  canvas.nodes && noCacheNodesOverride && options.getfieldvalue('cachenodes','on') === 'on') return;
     12        //if ('quiver' in canvas.nodes && noCacheNodesOverride && options.getfieldvalue('cachenodes','off') === 'on') return;
    1313       
    1414        //{{{ declare variables:
     
    2929
    3030        //Only displaying velocity fields for now
    31         var v = VESL.Helpers.isEmptyOrUndefined(md.results) ?  md.initialization.vel : md.results[canvas.animation.frame].Vel;
    32         var vx = VESL.Helpers.isEmptyOrUndefined(md.results) ? md.initialization.vx : md.results[canvas.animation.frame].Vx;
    33         var vy = VESL.Helpers.isEmptyOrUndefined(md.results) ? md.initialization.vy : md.results[canvas.animation.frame].Vy;
     31        var v = vesl.helpers.isEmptyOrUndefined(md.results) ?  md.initialization.vel : md.results[canvas.animation.frame].Vel;
     32        var vx = vesl.helpers.isEmptyOrUndefined(md.results) ? md.initialization.vx : md.results[canvas.animation.frame].Vx;
     33        var vy = vesl.helpers.isEmptyOrUndefined(md.results) ? md.initialization.vy : md.results[canvas.animation.frame].Vy;
    3434
    3535        //Handle heightscale
  • issm/trunk-jpl/src/m/plot/plot_transient_movie.js

    r22434 r22894  
    8181                        node.updateBuffer('Coords', processedData[frame]);
    8282                        canvas.unitData = processedData[frame];
    83                         if (canvas.dataMarkers.enabled) {
    84                                 updateMarker(canvas, false);
     83                        if (canvas.graph.enabled) {
     84                                vesl.graph.draw(canvas);
    8585                        }
    8686                        if (canvas.playbackSlider) {
     
    9090                                canvas.playbackTextProgress.html(steps[frame].toFixed(0) + " " + options.getfieldvalue("movietimeunit","yr"));
    9191                        }
    92                         if (!VESL.Helpers.isEmptyOrUndefined(canvas.nodes.quiver)) {
     92                        if (!vesl.helpers.isEmptyOrUndefined(canvas.nodes.quiver)) {
    9393                                plot_quiver(md,options,canvas,false);
    9494                        }
  • issm/trunk-jpl/src/m/plot/plot_unit.js

    r22434 r22894  
    1111                if (options.getfieldvalue('clf','on')=='on') {
    1212                        for (var node in canvas.nodes) {
    13                                 if (node.startsWith('unit')) {
     13                                if (vesl.string.startsWith(node, 'unit')) {
    1414                                        delete canvas.octrees[node];
    1515                                        delete canvas.nodes[node];
     
    3131        var is2d = meshresults[4];
    3232        var isplanet = meshresults[5];
    33         if (md.mesh.classname() !== 'mesh3dsurface') z = md.geometry.surface;
     33        if (md.mesh.classname() !== 'mesh3dsurface') {
     34                if (vesl.helpers.isNaN(md.geometry.surface) || (md.geometry.surface[0] !== undefined && vesl.helpers.isNaN(md.geometry.surface[0]))) {
     35                        md.geometry.surface = NewArrayFill(x.length, 0);
     36                }
     37                z = md.geometry.surface;
     38        }
    3439       
    3540        //Compute coordinates and data range:
     
    4853                scale = [1, 1, 1];
    4954        }
    50        
     55
    5156        //Compute gl variables:
    5257        var edgecolor = options.getfieldvalue('edgecolor', [1.0, 1.0, 1.0 ,1.0]);
  • issm/trunk-jpl/src/m/plot/plotdoc.js

    r22434 r22894  
    3737        console.log('       "colormap": same as standard matlab option (default "jet", ex: "hsv","cool","spring","gray","Ala","Rignot",...)');
    3838        console.log('       "controlsensitivity": sensitivty of view/zoom changes as a percentage of default (default 1, ex: 0.5, 2.75)');
    39         console.log('       "datamarkers": object cotaining data marker parameters. See webgl.js for defaults. (ex: {"enabled":true,"format":["<div id="sim-plot"></div>"],"labels":["thickness","velocity","value"],"animated":true})');
     39        console.log('       "dataMarker": object cotaining data marker parameters. See webgl.js for defaults. (ex: {"enabled":true,"format":["<div id="sim-plot"></div>"],"labels":["thickness","velocity","value"],"animated":true})');
    4040        console.log('           "enabled": toggle data marker displays (default true, ex: false)');
    41         console.log('           "image": image used for marking the clicked point (ex: "/canvas/data-markers/data_marker.svg")');
     41        console.log('           "image": image used for marking the clicked point (ex: "/canvas/data-markers/data-marker.svg")');
    4242        console.log('           "labels": when displaying a sim-plot graph, display these model fields. (ex: ["thickness","velocity","value"])');
    4343        console.log('           "font": font to be used for display (ex: "24px "Comic Sans MS", cursive")');
  • issm/trunk-jpl/src/m/plot/plotmodel.js

    r22434 r22894  
    11function plotmodel(md){ //{{{
    2 
    32        //Convert arguments to array:
    43        var args = Array.prototype.slice.call(arguments);
    54
    65        //First process options
    7         var  options = new plotoptions(args.slice(1,args.length));
    8 
     6        var options = new plotoptions(args.slice(1,args.length));
    97       
    108        //get number of subplots
     
    3028       
    3129        //check that nlines and ncols were given at the same time!
    32         if ((options.list[0].exist('ncols') & !options.list[0].exist('nlines')) | (options.list[0].exist('nlines') & !options.list[0].exist('ncols'))) throw Error('plotmodel error message: nlines and ncols  need to be specified together, or not at all');
     30        if ((options.list[0].exist('ncols') & !options.list[0].exist('nlines')) | (options.list[0].exist('nlines') & !options.list[0].exist('ncols'))) throw Error('plotmodel error message: nlines and ncols need to be specified together, or not at all');
    3331
    3432        //go through subplots
  • issm/trunk-jpl/src/m/plot/webgl.js

    r22434 r22894  
    44        //Initialize open Gl for each canvas and clear any previous animation handlers, once per plotmodel call:
    55        canvas = document.getElementById(options.getfieldvalue('canvasid'));
    6         //var canvas = document.getElementById(options.getfieldvalue('canvasid'));
     6       
    77        if (!canvas.initialized) {
    8                 if (!VESL.Helpers.isEmptyOrUndefined(canvas.draw) && canvas.draw.handler !== 0) { window.cancelAnimationFrame(canvas.draw.handler); }
    9                 if (!VESL.Helpers.isEmptyOrUndefined(canvas.animation) && canvas.animation.handler !== 0) { clearInterval(canvas.animation.handler); }
     8                if (!vesl.helpers.isEmptyOrUndefined(canvas.draw) && canvas.draw.handler !== 0) { window.cancelAnimationFrame(canvas.draw.handler); }
     9                if (!vesl.helpers.isEmptyOrUndefined(canvas.animation) && canvas.animation.handler !== 0) { clearInterval(canvas.animation.handler); }
    1010                initWebGL(canvas, options);
    11                 draw(canvas);
     11                drawCanvas(canvas);
     12               
    1213                canvas.initialized = true;
    1314               
    14                 //The onStart event triggers once per plotmodel call load after WebGL and canvas initialization are complete
    15                 canvas.selector.trigger('onStart', [canvas]);
    16         }
     15                triggerStartEvent(canvas);
     16        }
     17       
    1718        return canvas;
    1819}
     
    2021        //Initialize canvas.gl on page load, reusing gl context on additional runs
    2122        var gl = canvas.gl;
    22         if (VESL.Helpers.isEmptyOrUndefined(gl)) {
     23       
     24        if (vesl.helpers.isEmptyOrUndefined(gl)) {
    2325                gl = GL.create({canvas: canvas});
    2426                gl.enable(gl.DEPTH_TEST); // Enable depth testing
     
    3638                mc.add(new Hammer.Pan({threshold: 0, pointers: 0}));
    3739                mc.add(new Hammer.Pinch({threshold: 0})).recognizeWith(mc.get('pan'));
    38                 mc.on('tap', function (ev) {onTap(ev, canvas);});
    39                 mc.on('panstart panmove', function (ev) {onPan(ev, canvas, displayview);});
    40                 mc.on('pinchstart pinchmove', function (ev) {onPinch(ev, canvas, displayview);});
    41                 canvas.addEventListener('mousewheel', function (ev) {onZoom(ev, canvas, displayzoom)}, false);
    42                 canvas.addEventListener('DOMMouseScroll', function (ev) {onZoom(ev, canvas, displayzoom)}, false);
     40                mc.on('tap', function(ev) {onTap(ev, canvas);});
     41                mc.on('panstart panmove', function(ev) {onPan(ev, canvas, displayview);});
     42                mc.on('pinchstart pinchmove', function(ev) {onPinch(ev, canvas, displayview);});
     43                canvas.addEventListener('mousewheel', function(ev) {onZoom(ev, canvas, displayzoom)}, false);
     44                canvas.addEventListener('DOMMouseScroll', function(ev) {onZoom(ev, canvas, displayzoom)}, false);
    4345               
    4446                //Add persistent state variables
     
    6062        }
    6163       
    62         if (options.getfieldvalue('clf','on')=='on') {
    63                 //Add context state variables
    64                 canvas.render = options.getfieldvalue('render', {});
    65                 canvas.controlSensitivity = options.getfieldvalue('controlsensitivity', 1);
    66                 if (options.getfieldvalue('clf','on')=='on') canvas.overlayHandlers = {};
     64        if (options.getfieldvalue('clf', 'on') === 'on') {
     65                // Add context state variables
     66                canvas.render                           = options.getfieldvalue('render', {});
     67                canvas.controlSensitivity       = options.getfieldvalue('controlsensitivity', 1);
     68                canvas.overlayHandlers          = {};
     69               
    6770                var backgroundcolor = new RGBColor(options.getfieldvalue('backgroundcolor', 'lightcyan'));
    68                 if (backgroundcolor.ok) { canvas.backgroundcolor = [backgroundcolor.r/255.0, backgroundcolor.g/255.0, backgroundcolor.b/255.0, 1.0]; }
    69                 else { throw Error(sprintf('s%s%s\n','initWebGL error message: cound not find out background color for current canvas ', canvas)); }
     71               
     72                if (backgroundcolor.ok) {
     73                        canvas.backgroundcolor =        [
     74                                                                                        backgroundcolor.r / 255.0,
     75                                                                                        backgroundcolor.g / 255.0,
     76                                                                                        backgroundcolor.b / 255.0,
     77                                                                                        1.0
     78                                                                                ];
     79                } else {
     80                        throw Error(sprintf('s%s%s\n','initWebGL error message: cound not find out background color for current canvas ', canvas));
     81                }
    7082               
    7183                //Property intiialization, using values from options first, then from default values.
     
    125137                        ready: defaultFor(camera.ready,                                                         false)
    126138                };
    127                 var dataMarkers = options.getfieldvalue('datamarkers', {});
    128                 canvas.dataMarkers = {
    129                         enabled: defaultFor(dataMarkers.enabled,                                        true),
    130                         values: defaultFor(dataMarkers.values,                                          []),
    131                         image: defaultFor(dataMarkers.image,                                            canvas.assetsPath + '/data-markers/data_marker.svg'),
    132                         size: defaultFor(dataMarkers.size,                                                      [32, 32]),
    133                         format: defaultFor(dataMarkers.format,                                          ['X: %.2em<br>Y: %.2em<br>Z: %.2em<br>Value: %0.1f']),
    134                         animated: defaultFor(dataMarkers.animated,                                      false),
    135                         labels: defaultFor(dataMarkers.labels,                                          ['x', 'y', 'z', 'value']),
    136                         font: defaultFor(dataMarkers.font,                                                      ''),
    137                         marker: defaultFor(dataMarkers.marker,                                          document.getElementById('sim-data-marker-' + canvas.id)),
    138                         reposition: defaultFor(dataMarkers.reposition,                          true)
     139                if (vesl.helpers.isEmptyOrUndefined(canvas.dataMarker)) {
     140                        var dataMarker = options.getfieldvalue('dataMarker', {});
     141                       
     142                        canvas.dataMarker = {
     143                                enabled: defaultFor(dataMarker.enabled,                                 false),
     144                                element: defaultFor(dataMarker.element,                                 $('#sim-data-marker-' + canvas.id)),
     145                                isTooltip: defaultFor(dataMarker.isTooltip,                             false),
     146                                handlersReady: defaultFor(dataMarker.handlersReady,             false),
     147                                initialized: defaultFor(dataMarker.initialized,                 false),
     148                                visible: defaultFor(dataMarker.visible,                                 false),
     149                                image: defaultFor(dataMarker.image,                                     canvas.assetsPath + '/data-markers/data-marker.svg'),
     150                                size: defaultFor(dataMarker.size,                                               [32, 32]),
     151                                font: defaultFor(dataMarker.font,                                               ''),
     152                                reposition: defaultFor(dataMarker.reposition,                   true)
     153                        };
     154                }
     155                var graph = options.getfieldvalue('graph', {});
     156                canvas.graph = {
     157                        enabled: defaultFor(graph.enabled,                                                      false),
     158                        id: defaultFor(graph.id,                                                                        'sim-graph'),
     159                        animated: defaultFor(graph.animated,                                            false),
     160                        data: defaultFor(graph.data,                                                            []),
     161                        otherData: defaultFor(graph.otherData,                                          {})
    139162                };
    140163                var draw = options.getfieldvalue('draw', {});
     
    159182
    160183                // Override with parameters from URL, if any
    161                 VESL.UI.parsePermalinkCanvas(canvas);
     184                vesl.ui.parsePermalinkCanvas(canvas);
    162185        }
    163186} //}}}
     
    175198function initTexture(gl, imageSource) { //{{{
    176199        //Initialize textures, or load from memory if they already exist.
    177         if (VESL.Helpers.isEmptyOrUndefined(gl.textures[imageSource])) {
     200        if (vesl.helpers.isEmptyOrUndefined(gl.textures[imageSource])) {
    178201                gl.textures[imageSource] = GL.Texture.fromURL(imageSource, {minFilter: gl.LINEAR_MIPMAP_LINEAR, magFilter: gl.LINEAR}, null, gl);
    179202        }
     
    210233        for (var i = 0; i < properties.length; i++) {
    211234                object = object[properties[i]];
    212                 if (VESL.Helpers.isEmptyOrUndefined(object)) { break; }
     235                if (vesl.helpers.isEmptyOrUndefined(object)) { break; }
    213236    }
    214237        return defaultFor(object, value);
     238} //}}}
     239function triggerStartEvent(canvas) { //{{{
     240        // If data markers are enabled for this canvas, wait for their handlers to be registered before triggering onStart event
     241        if(!vesl.helpers.isEmptyOrUndefined(canvas.dataMarker) && canvas.dataMarker.enabled) {
     242                vesl.dataMarker.areHandlersReady(
     243                        canvas,
     244                        function() {
     245                                // The onStart event triggers once per plotmodel call load after WebGL and canvas initialization are complete
     246                                canvas.selector.trigger('onStart', [canvas]);
     247                        }
     248                );
     249        }
    215250} //}}}
    216251//}}}
     
    245280                                //TODO: convert canvas.view.rotation from az/el euler to quaternion
    246281                                if (canvas.view.twod) {
    247                                         canvas.view.position[0] += Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaX - Math.sin(DEG2RAD * 0) * deltaY;
    248                                         canvas.view.position[2] += Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaX + Math.cos(DEG2RAD * 0) * deltaY;
     282                                        canvas.view.position[0] += Math.cos(vesl.RATIO_DEG_TO_RAD * canvas.view.rotation[0]) * deltaX - Math.sin(vesl.RATIO_DEG_TO_RAD * 0) * deltaY;
     283                                        canvas.view.position[2] += Math.sin(vesl.RATIO_DEG_TO_RAD * canvas.view.rotation[0]) * deltaX + Math.cos(vesl.RATIO_DEG_TO_RAD * 0) * deltaY;
    249284                                }
    250285                                else {
    251                                         canvas.view.position[0] += Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaX - Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaY;
    252                                         canvas.view.position[2] += Math.sin(DEG2RAD * canvas.view.rotation[0]) * deltaX + Math.cos(DEG2RAD * canvas.view.rotation[0]) * deltaY;
     286                                        canvas.view.position[0] += Math.cos(vesl.RATIO_DEG_TO_RAD * canvas.view.rotation[0]) * deltaX - Math.sin(vesl.RATIO_DEG_TO_RAD * canvas.view.rotation[0]) * deltaY;
     287                                        canvas.view.position[2] += Math.sin(vesl.RATIO_DEG_TO_RAD * canvas.view.rotation[0]) * deltaX + Math.cos(vesl.RATIO_DEG_TO_RAD * canvas.view.rotation[0]) * deltaY;
    253288                                }
    254289                        }
     
    256291                //Else, rotate around camera center
    257292                else {
    258                         canvas.view.rotation[0] += (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth * 2 * canvas.controlSensitivity * RAD2DEG;
    259                         canvas.view.rotation[1] += (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight * -2 * canvas.controlSensitivity * RAD2DEG;
     293                        canvas.view.rotation[0] += (canvas.lastDeltaX - ev.deltaX) / canvas.clientWidth * 2 * canvas.controlSensitivity * vesl.RATIO_RAD_TO_DEG;
     294                        canvas.view.rotation[1] += (canvas.lastDeltaY - ev.deltaY) / canvas.clientHeight * -2 * canvas.controlSensitivity * vesl.RATIO_RAD_TO_DEG;
    260295                       
    261296                        if (canvas.view.rotation[0] > 360) { canvas.view.rotation[0] -= 360; };
     
    277312function onPinch(ev, canvas, displaylog) { //{{{
    278313        ev.preventDefault();
    279         if (ev.type === 'pinchstart') { canvas.view.lastZoom = canvas.view.zoom; }
    280         else {
     314       
     315        if (ev.type === 'pinchstart') {
     316                canvas.view.lastZoom = canvas.view.zoom;
     317        } else {
    281318                canvas.view.zoom = ev.scale * canvas.view.lastZoom;
    282                 if (displaylog) { console.log(canvas.view.zoom); }
     319               
     320                if (displaylog) {
     321                        console.log(canvas.view.zoom);
     322                }
    283323        }
    284324} //}}}
    285325function onZoom(ev, canvas, displaylog) { //{{{
    286326        ev.preventDefault();
    287         var delta = clamp(ev.scale || ev.wheelDelta || -ev.detail, -1, 1) * canvas.controlSensitivity * canvas.view.zoom / 2;
     327       
     328        var delta = clamp(ev.scale || ev.wheelDelta || -ev.detail, -1, 1) * canvas.controlSensitivity * canvas.view.zoom / 4;
     329       
    288330        modifyZoom(canvas.view.zoom + delta, canvas, displaylog, ev, 0);
    289331} //}}}
    290332function modifyZoom(value, canvas, displaylog, ev, duration) { //{{{
    291         if (VESL.Helpers.isEmptyOrUndefined(duration)) duration = 200;
    292         var targetZoom = clamp(value, canvas.view.zoomLimits[0], canvas.view.zoomLimits[1]);
     333        if (vesl.helpers.isEmptyOrUndefined(duration)) {
     334                duration = 200;
     335        }
     336       
     337        var targetZoom  = clamp(value, canvas.view.zoomLimits[0], canvas.view.zoomLimits[1]);
    293338        var currentZoom = canvas.view.zoom;
     339       
    294340        animateValue(
    295341                0,
     
    299345                function(value, info) {
    300346                        canvas.view.zoom = currentZoom * (1 - value) + targetZoom * value;
    301                         if (displaylog) { console.log(canvas.view.zoom); }
     347                       
     348                        if (displaylog) {
     349                                console.log(canvas.view.zoom);
     350                        }
    302351                       
    303352                        //Trigger any handlers attatched to this canvas event.
     
    310359} //}}}
    311360function screenToWorldPoint(canvas, x, y) { //{{{
    312         var viewportX = (x - canvas.width / 2) / (canvas.width / 2);
    313         var viewportY = (canvas.height / 2 - y) / (canvas.height / 2);
    314         var origin = vec3.transformMat4(vec3.create(), [viewportX, viewportY, 0], canvas.camera.vpInverseMatrix);
    315         return origin;
     361        var viewportX   = (x - canvas.width / 2) / (canvas.width / 2);
     362        var viewportY   = (canvas.height / 2 - y) / (canvas.height / 2);
     363       
     364        return vec3.transformMat4(vec3.create(), [viewportX, viewportY, 0], canvas.camera.vpInverseMatrix);
    316365} //}}}
    317366function screenToModelRay(canvas, x, y, node) { //{{{
    318         var inverseMVPMatrix = mat4.invert(mat4.create(), mat4.multiply(mat4.create(), canvas.camera.vpMatrix, node.modelMatrix));
    319         var viewportX = (x - canvas.width / 2) / (canvas.width / 2);
    320         var viewportY = (canvas.height / 2 - y) / (canvas.height / 2);
    321         var origin = vec3.transformMat4(vec3.create(), [viewportX, viewportY, 0], inverseMVPMatrix);
    322         var far = vec3.transformMat4(vec3.create(), [viewportX, viewportY, 1.0], inverseMVPMatrix);
    323         var direction = vec3.normalize(vec3.create(), vec3.subtract(vec3.create(), far, origin));
    324         return {'origin':origin, 'direction':direction};
     367        var inverseMVPMatrix    = mat4.invert(mat4.create(), mat4.multiply(mat4.create(), canvas.camera.vpMatrix, node.modelMatrix));
     368        var viewportX                   = (x - canvas.width / 2) / (canvas.width / 2);
     369        var viewportY                   = (canvas.height / 2 - y) / (canvas.height / 2);
     370        var origin                              = vec3.transformMat4(vec3.create(), [viewportX, viewportY, 0], inverseMVPMatrix);
     371        var far                                 = vec3.transformMat4(vec3.create(), [viewportX, viewportY, 1.0], inverseMVPMatrix);
     372        var direction                   = vec3.normalize(vec3.create(), vec3.subtract(vec3.create(), far, origin));
     373       
     374        return  {
     375                                'origin'        : origin,
     376                                'direction'     : direction
     377                        };
    325378} //}}}
    326379function raycast(canvas, origin, direction, node) { //{{{
     
    328381        //Returns hit objects with hit position, normals, barycentric coordinates, element number, and indices of ray-triangle intersection.
    329382        //TODO: Diagnose marker issues with orthographic views and slr-eustatic updates when switching between basins.
    330         if (!node.octree) { node.octree = new GL.Octree(node.mesh); }
     383        if (!node.octree) {
     384                node.octree = new GL.Octree(node.mesh);
     385        }
    331386       
    332387        var hit = node.octree.testRay(origin, direction, 1e3, 1e10);
    333         if (!hit) { return; }
     388       
     389        if (!hit) {
     390                return;
     391        }
    334392
    335393        hit.modelPos = vec3.copy(vec3.create(), hit.pos);
     394       
    336395        vec3.transformMat4(hit.pos, hit.pos, node.modelMatrix);
    337396       
     
    343402        //TODO: Diagnose marker issues with orthographic views and slr-eustatic updates when switching between basins.
    344403        var ray = screenToModelRay(canvas, x, y, node);
     404       
    345405        return raycast(canvas, ray.origin, ray.direction, node);
    346406} //}}}
    347407function animateValue(current, target, duration, easing, stepCallback, doneCallback) { //{{{
    348408        //Animates scalar value for length duration, calling callback each step. Specify smooth easing as a string ('swing', 'linear').
    349         $({'value':current}).animate({'value':target}, {
    350                 duration: duration,
    351                 easing: easing,
    352                 step: stepCallback,
    353                 done: doneCallback
     409        $({'value':current}).animate({'value' : target}, {
     410                duration        : duration,
     411                easing          : easing,
     412                step            : stepCallback,
     413                done            : doneCallback
    354414        });
    355415} //}}}
     
    358418function updateCameraMatrix(canvas) { //{{{
    359419    //Update view matrix and multiply with projection matrix to get the view-projection matrix.
    360         var vMatrix = mat4.create();
    361         var pMatrix = mat4.create();
    362         var translateMatrix = mat4.create();
    363         var rotationMatrix = mat4.create();
    364         var azimuthRotationMatrix = mat4.create();
    365         var elevationRotationMatrix = mat4.create();
    366         var aspectRatio = canvas.clientWidth / canvas.clientHeight;
    367         var camera = canvas.camera;
    368         var view = canvas.view;
     420        var vMatrix                                     = mat4.create();
     421        var pMatrix                                     = mat4.create();
     422        var translateMatrix                     = mat4.create();
     423        var rotationMatrix                              = mat4.create();
     424        var azimuthRotationMatrix               = mat4.create();
     425        var elevationRotationMatrix     = mat4.create();
     426        var aspectRatio                                 = canvas.clientWidth / canvas.clientHeight;
     427        var camera                                              = canvas.camera;
     428        var view                                                = canvas.view;
    369429
    370         if (view.twod) { mat4.ortho(pMatrix, -aspectRatio*6.371e6/view.zoom, aspectRatio*6.371e6/view.zoom, -6.371e6/view.zoom, 6.371e6/view.zoom, camera.near, camera.far); }
    371         else { mat4.perspective(pMatrix, camera.fov * DEG2RAD, aspectRatio, camera.near, camera.far); }
     430        if (view.twod) {
     431                mat4.ortho(
     432                        pMatrix, -aspectRatio * 6.371e6 / view.zoom,
     433                        aspectRatio * 6.371e6 / view.zoom,
     434                        -6.371e6 / view.zoom,
     435                        6.371e6 / view.zoom,
     436                        camera.near,
     437                        camera.far
     438                );
     439        } else {
     440                mat4.perspective(
     441                        pMatrix,
     442                        camera.fov * vesl.RATIO_DEG_TO_RAD,
     443                        aspectRatio,
     444                        camera.near,
     445                        camera.far
     446                );
     447        }
    372448       
    373449        //Apply worldspace translation
     
    376452        //Calculate rotation around camera focal point about worldspace origin
    377453        if (view.twod) {
    378                 mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, -DEG2RAD * 0, [0, 1, 0]);
    379                 mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, DEG2RAD * 90, [1, 0, 0]);
     454                mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, -vesl.RATIO_DEG_TO_RAD * 0, [0, 1, 0]);
     455                mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, vesl.RATIO_DEG_TO_RAD * 90, [1, 0, 0]);
    380456                mat4.multiply(rotationMatrix, elevationRotationMatrix, azimuthRotationMatrix);
    381         }
    382         else {
    383                 mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, -DEG2RAD * (view.rotation[0] + 90), [0, 1, 0]);
    384                 mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, DEG2RAD * view.rotation[1], [1, 0, 0]);
     457        } else {
     458                mat4.rotate(azimuthRotationMatrix, azimuthRotationMatrix, -vesl.RATIO_DEG_TO_RAD * (view.rotation[0] + 90), [0, 1, 0]);
     459                mat4.rotate(elevationRotationMatrix, elevationRotationMatrix, vesl.RATIO_DEG_TO_RAD * view.rotation[1], [1, 0, 0]);
    385460                mat4.multiply(rotationMatrix, elevationRotationMatrix, azimuthRotationMatrix);
    386                 //var quaternionWorldX = Node.prototype.eulerToQuaternion(0, 0, DEG2RAD * (view.rotation[0]));
    387                 //var quaternionWorldY = Node.prototype.eulerToQuaternion(0, DEG2RAD * (view.rotation[1]), 0);
    388                 //var quaternionWorldZ = Node.prototype.eulerToQuaternion(DEG2RAD * (view.rotation[2]), 0, 0);
     461                //var quaternionWorldX = Node.prototype.eulerToQuaternion(0, 0, vesl.RATIO_DEG_TO_RAD * (view.rotation[0]));
     462                //var quaternionWorldY = Node.prototype.eulerToQuaternion(0, vesl.RATIO_DEG_TO_RAD * (view.rotation[1]), 0);
     463                //var quaternionWorldZ = Node.prototype.eulerToQuaternion(vesl.RATIO_DEG_TO_RAD * (view.rotation[2]), 0, 0);
    389464                //var quaternionTemp = quat.multiply(quat.create(), quaternionWorldY, quaternionWorldX);
    390465                //quat.multiply(camera.rotation, quaternionWorldZ, quaternionTemp);
     
    397472        //Apply screenspace translation to emulate rotation around point
    398473        mat4.identity(translateMatrix);
    399         mat4.translate(translateMatrix, translateMatrix, [0.0, 0.0, -6.371e6/view.zoom]);
     474        mat4.translate(translateMatrix, translateMatrix, [0.0, 0.0, -6.371e6 / view.zoom]);
    400475        mat4.multiply(vMatrix, translateMatrix, vMatrix);
    401476       
     
    415490}//}}}
    416491function drawSceneGraphNode(canvas, node) { //{{{
    417         if (!node.enabled) { return; }
     492        if (!node.enabled) {
     493                return;
     494        }
    418495
    419496        var gl = canvas.gl;
     497       
    420498        gl.makeCurrent();
    421499       
    422500        var mvpMatrix = mat4.create();
     501       
    423502        mat4.multiply(mvpMatrix, canvas.camera.vpMatrix, node.modelMatrix);
    424503       
    425         var normalMatrix = mat3.create();
    426         var tempMatrix = mat4.create();
     504        var normalMatrix        = mat3.create();
     505        var tempMatrix          = mat4.create();
     506       
    427507        mat4.invert(tempMatrix, node.modelMatrix);
    428508        mat4.transpose(tempMatrix, tempMatrix);
    429509        mat3.fromMat4(normalMatrix, tempMatrix);
    430510       
    431         if (node.texture) { node.texture.bind(0); }
    432         if (node.disableDepthTest) { gl.disable(gl.DEPTH_TEST); }
    433         if (node.enableCullFace) { gl.enable(gl.CULL_FACE); }
     511        if (node.texture) {
     512                node.texture.bind(0);
     513        }
     514       
     515        if (node.disableDepthTest) {
     516                gl.disable(gl.DEPTH_TEST);
     517        }
     518       
     519        if (node.enableCullFace) {
     520                gl.enable(gl.CULL_FACE);
     521        }
    434522
    435523        gl.cullFace(node.cullFace);
     
    438526       
    439527        //Setup for light that originates from camera
    440         var atm = canvas.atmosphere;
     528        var atm                 = canvas.atmosphere;
    441529        var lightOrigin = vec3.create();
    442530       
     
    495583function canvasResize(canvas) {
    496584        var rect = canvas.getBoundingClientRect();
     585       
    497586        canvas.width  = rect.width;
    498587        canvas.height = rect.height;
     588       
    499589        canvas.gl.viewport(0, 0, canvas.width, canvas.height);
    500590       
    501         if (!VESL.Helpers.isEmptyOrUndefined(canvas.overlaycanvas)) {
    502                 rect = canvas.overlaycanvas.getBoundingClientRect();
    503                 canvas.overlaycanvas.width  = rect.width;
    504                 canvas.overlaycanvas.height = rect.height;
     591        var overlaycanvas = canvas.overlaycanvas;
     592       
     593        if (!vesl.helpers.isEmptyOrUndefined(overlaycanvas)) {
     594                rect = overlaycanvas.getBoundingClientRect();
     595                overlaycanvas.width  = rect.width;
     596                overlaycanvas.height = rect.height;
     597                overlaycanvas.getContext('2d').clearRect(0, 0, overlaycanvas.width, overlaycanvas.height);
    505598        }
    506599}
    507 function draw(canvas) { //{{{
     600function drawCanvas(canvas) { //{{{
    508601        //Ensure all nodes are ready to render
    509602        //TODO: Come up with better way to check if shaders are ready, or move outside of main draw function
    510603        var nodes = canvas.nodes;
     604       
    511605        if (!canvas.draw.ready) {
    512606                if (Object.keys(nodes).length !== 0) {
    513607                        canvas.draw.ready = true;
     608                       
    514609                        for (var node in nodes) {
    515610                                if (nodes[node].shader.ready === false) {
    516611                                        canvas.draw.ready = false;
     612                                       
    517613                                        break;
    518614                                }
    519615                        }
    520                        
    521616                }
    522617        }
     
    528623               
    529624                var gl = canvas.gl;
     625               
    530626                gl.makeCurrent(); //litegl function to handle switching between multiple canvases
    531627                gl.clearColor(canvas.backgroundcolor[0], canvas.backgroundcolor[1], canvas.backgroundcolor[2], canvas.backgroundcolor[3]);
     
    537633                canvas.selector.trigger('onPreRender', [canvas]);
    538634               
    539                 for (var handler in canvas.overlayHandlers) { canvas.overlayHandlers[handler](canvas); }
     635                for (var handler in canvas.overlayHandlers) {
     636                        canvas.overlayHandlers[handler](canvas);
     637                }
    540638               
    541639                var drawPassNumber = 3;
     640               
     641                // NOTE: For large value of drawPassNumber/nodes.length, could copy nodes to a new array and pop elements as each drawOrder is found
    542642                for (var i = drawPassNumber - 1; i >= 0; --i) {
    543643                        for (var node in nodes) {
    544                                 if (nodes[node].drawOrder === i) { drawSceneGraphNode(canvas, nodes[node]); }
     644                                if (nodes[node].drawOrder === i) {
     645                                        drawSceneGraphNode(canvas, nodes[node]);
     646                                }
    545647                        }
    546648                }
     
    548650       
    549651        //Regardless of ready state, schedule next frame to check for ready state and render
    550         canvas.draw.handler = window.requestAnimationFrame(function(time) { draw(canvas); });
     652        canvas.draw.handler = window.requestAnimationFrame(function(time) { drawCanvas(canvas); });
    551653} //}}}
    552654//}}}
  • issm/trunk-jpl/src/m/plot/webgl_node.js

    r22434 r22894  
    106106        var yaw = Math.atan2(t3, t4);
    107107       
    108         return [pitch * RAD2DEG, roll * RAD2DEG, yaw * RAD2DEG];
     108        return [pitch * vesl.RATIO_RAD_TO_DEG, roll * vesl.RATIO_RAD_TO_DEG, yaw * vesl.RATIO_RAD_TO_DEG];
    109109} //}}}
    110110Node.prototype.updateModelMatrix = function() { //{{{
     
    122122        var rotationMatrix = mat4.create();
    123123        var zRotationMatrix = mat4.create();   
    124         mat4.rotate(zRotationMatrix, zRotationMatrix, DEG2RAD * this.rotation[2], [0.0, 0.0, 1.0]);
     124        mat4.rotate(zRotationMatrix, zRotationMatrix, vesl.RATIO_DEG_TO_RAD * this.rotation[2], [0.0, 0.0, 1.0]);
    125125        mat4.multiply(rotationMatrix, zRotationMatrix, rotationMatrix);
    126126        var yRotationMatrix = mat4.create();   
    127         mat4.rotate(yRotationMatrix, yRotationMatrix, DEG2RAD * this.rotation[1], [0.0, 1.0, 0.0]);
     127        mat4.rotate(yRotationMatrix, yRotationMatrix, vesl.RATIO_DEG_TO_RAD * this.rotation[1], [0.0, 1.0, 0.0]);
    128128        mat4.multiply(rotationMatrix, yRotationMatrix, rotationMatrix);
    129129        var xRotationMatrix = mat4.create();   
    130         mat4.rotate(xRotationMatrix, xRotationMatrix, DEG2RAD * this.rotation[0], [1.0, 0.0, 0.0]);
     130        mat4.rotate(xRotationMatrix, xRotationMatrix, vesl.RATIO_DEG_TO_RAD * this.rotation[0], [1.0, 0.0, 0.0]);
    131131        mat4.multiply(rotationMatrix, xRotationMatrix, rotationMatrix);
    132132        mat4.multiply(modelMatrix, rotationMatrix, modelMatrix);
    133133
    134         //var rotationQuaternionX = this.eulerToQuaternion(0, -DEG2RAD * this.rotation[0], 0);
    135         //var rotationQuaternionY = this.eulerToQuaternion(DEG2RAD * this.rotation[1], 0, 0);
     134        //var rotationQuaternionX = this.eulerToQuaternion(0, -vesl.RATIO_DEG_TO_RAD * this.rotation[0], 0);
     135        //var rotationQuaternionY = this.eulerToQuaternion(vesl.RATIO_DEG_TO_RAD * this.rotation[1], 0, 0);
    136136        //mat4.fromQuat(this.rotationMatrix, quat.multiply(quat.create(), rotationQuaternionY, rotationQuaternionX));
    137137
     
    163163} //}}}
    164164Node.prototype.transform = function() { //{{{
    165         //Transforms the translation, rotation, or scle fo the node and updates the model matrix.
     165        //Transforms the translation, rotation, or scale of the node and updates the model matrix.
    166166        var args = Array.prototype.slice.call(arguments);
    167167        var options = new pairoptions(args.slice(0,args.length));
     
    171171        var scale = options.getfieldvalue('scale', undefined);
    172172       
    173         if (!VESL.Helpers.isEmptyOrUndefined(translation)) this.translation = translation;
    174         if (!VESL.Helpers.isEmptyOrUndefined(rotation)) this.rotation = rotation;
    175         if (!VESL.Helpers.isEmptyOrUndefined(scale)) this.scale = scale;
     173        if (!vesl.helpers.isEmptyOrUndefined(translation)) this.translation = translation;
     174        if (!vesl.helpers.isEmptyOrUndefined(rotation)) this.rotation = rotation;
     175        if (!vesl.helpers.isEmptyOrUndefined(scale)) this.scale = scale;
    176176        this.updateModelMatrix();
    177177} //}}}
     
    212212        var face;
    213213       
    214         if (VESL.Helpers.isEmptyOrUndefined(faceVertexCData)) {
     214        if (vesl.helpers.isEmptyOrUndefined(faceVertexCData)) {
    215215                vertexArray = new Float32Array(vertices[0].length * 3);
    216216                for(var i = 0, v = 0; i < vertices[0].length; i++) {   
     
    289289        var face;
    290290       
    291         if (VESL.Helpers.isEmptyOrUndefined(faceVertexCData)) { return; }
     291        if (vesl.helpers.isEmptyOrUndefined(faceVertexCData)) { return; }
    292292       
    293293        //Use logarithmic scaling if it is valid
     
    368368        }
    369369       
    370         if (this.computeIndices === true && !VESL.Helpers.isEmptyOrUndefined(faces)) {
    371                 if (!VESL.Helpers.isEmptyOrUndefined(faces[0])) { //Check for 2D format and process if needed
     370        if (this.computeIndices === true && !vesl.helpers.isEmptyOrUndefined(faces)) {
     371                if (!vesl.helpers.isEmptyOrUndefined(faces[0])) { //Check for 2D format and process if needed
    372372                        if (faceColor !== 'none') { //Check for triangle rendering
    373373                                indexArray = new Uint16Array(faces.length * 3);
     
    405405       
    406406        var coords = options.getfieldvalue('Coords', undefined);
    407         if (!VESL.Helpers.isEmptyOrUndefined(coords)) {
     407        if (!vesl.helpers.isEmptyOrUndefined(coords)) {
    408408                this.patchCoords(coords, this.faces, this.vertices);
    409409                var buffer = this.mesh.getBuffer("coords");
     
    415415        //Computes and caches octrees for a node.
    416416        var octree = this.canvas.octrees[this.name];
    417         if (VESL.Helpers.isEmptyOrUndefined(octree)) {
     417        if (vesl.helpers.isEmptyOrUndefined(octree)) {
    418418                octree = new GL.Octree(this.mesh);
    419419        }
     
    441441                        var coordinateObject = vertices[i];
    442442                        var j = 0;
    443                         if (VESL.Helpers.isEmptyOrUndefined(indices)) {
     443                        if (vesl.helpers.isEmptyOrUndefined(indices)) {
    444444                                for (var key in coordinateObject) {
    445445                                        console.log(key);
     
    486486        //Scales and returns vertices x, y, and z by factor scale. Uses md.geometry.scale for heightscaling in 3d meshes.
    487487        var region = maskObject.region;
    488         var mask = maskObject.enabled ? maskObject.heightmask[region] : [];
     488        var mask;
    489489        var maskScale = maskObject.enabled ? maskObject.scale : 1;
    490490       
    491         //The maskScaleField is the height scaling array. Use one if provided by maskObject.field, otherwise use md.geometry.surface
    492         var maskScaleField = !VESL.Helpers.isEmptyOrUndefined(maskObject.scaleField) ? maskObject.scaleField : md.geometry.surface;
    493         //If md.geometry.surface was empty and was used as maskScaleField, assign an empty array to both.
    494         if (!maskScaleField) {
    495                 md.geometry.surface = NewArrayFill(md.mesh.x.length,0);
     491        //The maskScaleField is the height scaling array.
     492        var maskScaleField = maskObject.scaleField;
     493        if (Array.isArray(md.geometry.surface) && md.geometry.surface[0] === undefined) {
     494                md.geometry.surface = NewArrayFill(x.length, 1);
     495        }
     496        if (vesl.helpers.isNaN(maskScaleField) || maskScaleField === undefined || (Array.isArray(maskScaleField) && maskScaleField[0]  === undefined)) {
    496497                maskScaleField = md.geometry.surface;
    497498        }
    498        
     499               
    499500        //Scale in 3D if using globe model, or in 2D otherwise.
    500501        if (md.mesh.classname() === 'mesh3dsurface') {
    501502                var element;
    502503                if (x.length === md.mesh.numberofelements) { //element plot
     504                        mask = maskObject.enabled ? maskObject.heightmask[region] : NewArrayFill(elements.length, 1);
    503505                        for (var i = 0; i < x.length; i++) {
    504506                                if (maskObject.enabled) { //Scale the element if mask is not enabled, or if it is, only if it is also in the mask
     
    517519                }
    518520                else if (x.length === md.mesh.numberofvertices) { //node plot
     521                        mask = maskObject.enabled ? maskObject.heightmask[region] : NewArrayFill(x.length, 1);
    519522                        for (var i = 0; i < x.length; i++) {
    520523                                if (!maskObject.enabled || mask[i] === 1) { //Scale the node if mask is not enabled, or if it is, only if it is also in the mask
     
    530533        } else {
    531534                z = z.slice();
     535                mask = maskObject.enabled ? maskObject.heightmask[region] : NewArrayFill(z.length, 1);
    532536                var zMin = ArrayMin(maskScaleField);
    533537                for(var i = 0; i < z.length; i++) {
Note: See TracChangeset for help on using the changeset viewer.