mirror of
				https://github.com/jiawanlong/Cesium-Examples.git
				synced 2025-11-03 16:54:16 +00:00 
			
		
		
		
	
		
			
	
	
		
			1228 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			1228 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								* geostats() is a tiny and standalone javascript library for classification 
							 | 
						||
| 
								 | 
							
								* Project page - https://github.com/simogeo/geostats
							 | 
						||
| 
								 | 
							
								* Copyright (c) 2011 Simon Georget, http://www.empreinte-urbaine.eu
							 | 
						||
| 
								 | 
							
								* Licensed under the MIT license
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								(function (definition) {
							 | 
						||
| 
								 | 
							
								    // This file will function properly as a <script> tag, or a module
							 | 
						||
| 
								 | 
							
								    // using CommonJS and NodeJS or RequireJS module formats.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // CommonJS
							 | 
						||
| 
								 | 
							
								    if (typeof exports === "object") {
							 | 
						||
| 
								 | 
							
								        module.exports = definition();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // RequireJS
							 | 
						||
| 
								 | 
							
								    } else if (typeof define === "function" && define.amd) {
							 | 
						||
| 
								 | 
							
								        define(definition);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // <script>
							 | 
						||
| 
								 | 
							
								    } else {
							 | 
						||
| 
								 | 
							
								        geostats = definition();
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								})(function () {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var isInt = function(n) {
							 | 
						||
| 
								 | 
							
								   return typeof n === 'number' && parseFloat(n) == parseInt(n, 10) && !isNaN(n);
							 | 
						||
| 
								 | 
							
								} // 6 characters
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var _t = function(str) {
							 | 
						||
| 
								 | 
							
									return str;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//taking from http://stackoverflow.com/questions/18082/validate-decimal-numbers-in-javascript-isnumeric
							 | 
						||
| 
								 | 
							
								var isNumber = function(n) {
							 | 
						||
| 
								 | 
							
									  return !isNaN(parseFloat(n)) && isFinite(n);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//indexOf polyfill
							 | 
						||
| 
								 | 
							
								// from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
							 | 
						||
| 
								 | 
							
								if (!Array.prototype.indexOf) {
							 | 
						||
| 
								 | 
							
								    Array.prototype.indexOf = function (searchElement, fromIndex) {
							 | 
						||
| 
								 | 
							
								      if ( this === undefined || this === null ) {
							 | 
						||
| 
								 | 
							
								        throw new TypeError( '"this" is null or not defined' );
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      var length = this.length >>> 0; // Hack to convert object.length to a UInt32
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      fromIndex = +fromIndex || 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (Math.abs(fromIndex) === Infinity) {
							 | 
						||
| 
								 | 
							
								        fromIndex = 0;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if (fromIndex < 0) {
							 | 
						||
| 
								 | 
							
								        fromIndex += length;
							 | 
						||
| 
								 | 
							
								        if (fromIndex < 0) {
							 | 
						||
| 
								 | 
							
								          fromIndex = 0;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      for (;fromIndex < length; fromIndex++) {
							 | 
						||
| 
								 | 
							
								        if (this[fromIndex] === searchElement) {
							 | 
						||
| 
								 | 
							
								          return fromIndex;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      return -1;
							 | 
						||
| 
								 | 
							
								    };
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var geostats = function(a) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									this.objectID = '';
							 | 
						||
| 
								 | 
							
									this.separator = ' - ';
							 | 
						||
| 
								 | 
							
									this.legendSeparator = this.separator;
							 | 
						||
| 
								 | 
							
									this.method  = '';
							 | 
						||
| 
								 | 
							
									this.precision = 0;
							 | 
						||
| 
								 | 
							
									this.precisionflag = 'auto';
							 | 
						||
| 
								 | 
							
									this.roundlength 	= 2; // Number of decimals, round values
							 | 
						||
| 
								 | 
							
									this.is_uniqueValues = false;
							 | 
						||
| 
								 | 
							
									this.debug =  false;
							 | 
						||
| 
								 | 
							
									this.silent = false;
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									this.bounds  = Array();
							 | 
						||
| 
								 | 
							
									this.ranges  = Array();
							 | 
						||
| 
								 | 
							
									this.inner_ranges  = null;
							 | 
						||
| 
								 | 
							
									this.colors  = Array();
							 | 
						||
| 
								 | 
							
									this.counter = Array();
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// statistics information
							 | 
						||
| 
								 | 
							
									this.stat_sorted	= null;
							 | 
						||
| 
								 | 
							
									this.stat_mean 		= null;
							 | 
						||
| 
								 | 
							
									this.stat_median 	= null;
							 | 
						||
| 
								 | 
							
									this.stat_sum 		= null;
							 | 
						||
| 
								 | 
							
									this.stat_max 		= null;
							 | 
						||
| 
								 | 
							
									this.stat_min 		= null;
							 | 
						||
| 
								 | 
							
									this.stat_pop 		= null;
							 | 
						||
| 
								 | 
							
									this.stat_variance	= null;
							 | 
						||
| 
								 | 
							
									this.stat_stddev	= null;
							 | 
						||
| 
								 | 
							
									this.stat_cov		= null;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * logging method
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.log = function(msg, force) {
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
										if(this.debug == true || force != null)
							 | 
						||
| 
								 | 
							
											console.log(this.objectID + "(object id) :: " + msg);
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Set bounds
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.setBounds = function(a) {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										this.log('Setting bounds (' + a.length + ') : ' + a.join());
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
										this.bounds = Array() // init empty array to prevent bug when calling classification after another with less items (sample getQuantile(6) and getQuantile(4))
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										this.bounds = a;
							 | 
						||
| 
								 | 
							
										//this.bounds = this.decimalFormat(a);
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Set a new serie
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.setSerie = function(a) {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										this.log('Setting serie (' + a.length + ') : ' + a.join());
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
										this.serie = Array() // init empty array to prevent bug when calling classification after another with less items (sample getQuantile(6) and getQuantile(4))
							 | 
						||
| 
								 | 
							
										this.serie = a;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										//reset statistics after changing serie
							 | 
						||
| 
								 | 
							
									    this.resetStatistics();
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
										this.setPrecision();
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Set colors
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.setColors = function(colors) {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										this.log('Setting color ramp (' + colors.length + ') : '  + colors.join());
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										this.colors = colors;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Get feature count
							 | 
						||
| 
								 | 
							
									 * With bounds array(0, 0.75, 1.5, 2.25, 3); 
							 | 
						||
| 
								 | 
							
									 * should populate this.counter with 5 keys
							 | 
						||
| 
								 | 
							
									 * and increment counters for each key
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.doCount = function() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var tmp = this.sorted();
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										this.counter = new Array();
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										// we init counter with 0 value
							 | 
						||
| 
								 | 
							
										for(i = 0; i < this.bounds.length -1; i++) {
							 | 
						||
| 
								 | 
							
											this.counter[i]= 0;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										for(j=0; j < tmp.length; j++) {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// get current class for value to increment the counter
							 | 
						||
| 
								 | 
							
											var cclass = this.getClass(tmp[j]);
							 | 
						||
| 
								 | 
							
											this.counter[cclass]++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Set decimal precision according to user input
							 | 
						||
| 
								 | 
							
									 * or automatcally determined according
							 | 
						||
| 
								 | 
							
									 * to the given serie.
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.setPrecision = function(decimals) {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										// only when called from user
							 | 
						||
| 
								 | 
							
										if(typeof decimals !== "undefined") {
							 | 
						||
| 
								 | 
							
											this.precisionflag = 'manual';
							 | 
						||
| 
								 | 
							
											this.precision = decimals;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										// we calculate the maximal decimal length on given serie
							 | 
						||
| 
								 | 
							
										if(this.precisionflag == 'auto') {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											for (var i = 0; i < this.serie.length; i++) {
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												// check if the given value is a number and a float
							 | 
						||
| 
								 | 
							
												if (!isNaN((this.serie[i]+"")) && (this.serie[i]+"").toString().indexOf('.') != -1) {
							 | 
						||
| 
								 | 
							
													var precision = (this.serie[i] + "").split(".")[1].length;
							 | 
						||
| 
								 | 
							
												} else {
							 | 
						||
| 
								 | 
							
													var precision = 0;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												if(precision > this.precision) {
							 | 
						||
| 
								 | 
							
													this.precision = precision;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if(this.precision > 20) {
							 | 
						||
| 
								 | 
							
											// prevent "Uncaught RangeError: toFixed() digits argument must be between 0 and 20" bug. See https://github.com/simogeo/geostats/issues/34
							 | 
						||
| 
								 | 
							
											this.log('this.precision value (' + this.precision + ') is greater than max value. Automatic set-up to 20 to prevent "Uncaught RangeError: toFixed()" when calling decimalFormat() method.');
							 | 
						||
| 
								 | 
							
											this.precision = 20;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.log('Calling setPrecision(). Mode : ' + this.precisionflag + ' - Decimals : '+ this.precision);
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										this.serie = this.decimalFormat(this.serie);
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Format array numbers regarding to precision
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.decimalFormat = function(a) {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										var b = new Array();
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										for (var i = 0; i < a.length; i++) {
							 | 
						||
| 
								 | 
							
											// check if the given value is a number
							 | 
						||
| 
								 | 
							
											if (isNumber(a[i])) {
							 | 
						||
| 
								 | 
							
												b[i] = parseFloat(parseFloat(a[i]).toFixed(this.precision));
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												b[i] = a[i];
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return b;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Transform a bounds array to a range array the following array : array(0,
							 | 
						||
| 
								 | 
							
									 * 0.75, 1.5, 2.25, 3); becomes : array('0-0.75', '0.75-1.5', '1.5-2.25',
							 | 
						||
| 
								 | 
							
									 * '2.25-3');
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.setRanges = function() {
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
										this.ranges = Array(); // init empty array to prevent bug when calling classification after another with less items (sample getQuantile(6) and getQuantile(4))
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										for (i = 0; i < (this.bounds.length - 1); i++) {
							 | 
						||
| 
								 | 
							
											this.ranges[i] = this.bounds[i] + this.separator + this.bounds[i + 1];
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/** return min value */
							 | 
						||
| 
								 | 
							
									this.min = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										this.stat_min = this.serie[0];
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										for (i = 0; i < this.pop(); i++) {
							 | 
						||
| 
								 | 
							
											if (this.serie[i] < this.stat_min) {
							 | 
						||
| 
								 | 
							
												this.stat_min = this.serie[i];
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return this.stat_min;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/** return max value */
							 | 
						||
| 
								 | 
							
									this.max = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										this.stat_max = this.serie[0];
							 | 
						||
| 
								 | 
							
										for (i = 0; i < this.pop(); i++) {
							 | 
						||
| 
								 | 
							
											if (this.serie[i] > this.stat_max) {
							 | 
						||
| 
								 | 
							
												this.stat_max = this.serie[i];
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return this.stat_max;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/** return sum value */
							 | 
						||
| 
								 | 
							
									this.sum = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this.stat_sum  == null) {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											this.stat_sum = 0;
							 | 
						||
| 
								 | 
							
											for (i = 0; i < this.pop(); i++) {
							 | 
						||
| 
								 | 
							
												this.stat_sum += parseFloat(this.serie[i]);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return this.stat_sum;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/** return population number */
							 | 
						||
| 
								 | 
							
									this.pop = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this.stat_pop  == null) {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											this.stat_pop = this.serie.length;
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return this.stat_pop;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/** return mean value */
							 | 
						||
| 
								 | 
							
									this.mean = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (this.stat_mean  == null) {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											this.stat_mean = parseFloat(this.sum() / this.pop());
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return this.stat_mean;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/** return median value */
							 | 
						||
| 
								 | 
							
									this.median = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this.stat_median  == null) {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											this.stat_median = 0;
							 | 
						||
| 
								 | 
							
											var tmp = this.sorted();
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// serie pop is odd
							 | 
						||
| 
								 | 
							
											if (tmp.length % 2) {
							 | 
						||
| 
								 | 
							
												this.stat_median = parseFloat(tmp[(Math.ceil(tmp.length / 2) - 1)]);
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
											// serie pop is even
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												this.stat_median = ( parseFloat(tmp[((tmp.length / 2) - 1)]) + parseFloat(tmp[(tmp.length / 2)]) ) / 2;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return this.stat_median;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/** return variance value */
							 | 
						||
| 
								 | 
							
									this.variance = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										round = (typeof round === "undefined") ? true : false;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this.stat_variance  == null) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											var tmp = 0, serie_mean = this.mean();
							 | 
						||
| 
								 | 
							
											for (var i = 0; i < this.pop(); i++) {
							 | 
						||
| 
								 | 
							
												tmp += Math.pow( (this.serie[i] - serie_mean), 2 );
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											this.stat_variance =  tmp / this.pop();
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											if(round == true) {
							 | 
						||
| 
								 | 
							
												this.stat_variance = Math.round(this.stat_variance * Math.pow(10,this.roundlength) )/ Math.pow(10,this.roundlength);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return this.stat_variance;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/** return standard deviation value */
							 | 
						||
| 
								 | 
							
									this.stddev = function(round) {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										round = (typeof round === "undefined") ? true : false;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this.stat_stddev  == null) {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											this.stat_stddev = Math.sqrt(this.variance());
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											if(round == true) {
							 | 
						||
| 
								 | 
							
												this.stat_stddev = Math.round(this.stat_stddev * Math.pow(10,this.roundlength) )/ Math.pow(10,this.roundlength);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return this.stat_stddev;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/** coefficient of variation - measure of dispersion */
							 | 
						||
| 
								 | 
							
									this.cov = function(round) {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										round = (typeof round === "undefined") ? true : false;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this.stat_cov  == null) {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											this.stat_cov = this.stddev() / this.mean();
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											if(round == true) {
							 | 
						||
| 
								 | 
							
												this.stat_cov = Math.round(this.stat_cov * Math.pow(10,this.roundlength) )/ Math.pow(10,this.roundlength);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return this.stat_cov;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/** reset all attributes after setting a new serie */
							 | 
						||
| 
								 | 
							
									this.resetStatistics = function() {
							 | 
						||
| 
								 | 
							
									    this.stat_sorted    = null;
							 | 
						||
| 
								 | 
							
									    this.stat_mean  = null;
							 | 
						||
| 
								 | 
							
									    this.stat_median    = null;
							 | 
						||
| 
								 | 
							
									    this.stat_sum       = null;
							 | 
						||
| 
								 | 
							
									    this.stat_max       = null;
							 | 
						||
| 
								 | 
							
									    this.stat_min       = null;
							 | 
						||
| 
								 | 
							
									    this.stat_pop       = null;
							 | 
						||
| 
								 | 
							
									    this.stat_variance  = null;
							 | 
						||
| 
								 | 
							
									    this.stat_stddev    = null;
							 | 
						||
| 
								 | 
							
									    this.stat_cov       = null;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/** data test */
							 | 
						||
| 
								 | 
							
									this._nodata = function() {
							 | 
						||
| 
								 | 
							
										if (this.serie.length == 0) {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											if(this.silent) this.log("[silent mode] Error. You should first enter a serie!", true);
							 | 
						||
| 
								 | 
							
											else throw new TypeError("Error. You should first enter a serie!");
							 | 
						||
| 
								 | 
							
											return 1;
							 | 
						||
| 
								 | 
							
										} else
							 | 
						||
| 
								 | 
							
											return 0;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/** check if the serie contains negative value */
							 | 
						||
| 
								 | 
							
									this._hasNegativeValue = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										for (i = 0; i < this.serie.length; i++) {
							 | 
						||
| 
								 | 
							
									    	if(this.serie[i] < 0)
							 | 
						||
| 
								 | 
							
									    		return true;
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/** check if the serie contains zero value */
							 | 
						||
| 
								 | 
							
									this._hasZeroValue = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										for (i = 0; i < this.serie.length; i++) {
							 | 
						||
| 
								 | 
							
									    	if(parseFloat(this.serie[i]) === 0)
							 | 
						||
| 
								 | 
							
									    		return true;
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return false;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/** return sorted values (as array) */
							 | 
						||
| 
								 | 
							
									this.sorted = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this.stat_sorted  == null) {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											if(this.is_uniqueValues == false) {
							 | 
						||
| 
								 | 
							
												this.stat_sorted = this.serie.sort(function(a, b) {
							 | 
						||
| 
								 | 
							
													return a - b;
							 | 
						||
| 
								 | 
							
												});
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												this.stat_sorted = this.serie.sort(function(a,b){
							 | 
						||
| 
								 | 
							
													var nameA=a.toString().toLowerCase(), nameB=b.toString().toLowerCase();
							 | 
						||
| 
								 | 
							
												    if(nameA < nameB) return -1;
							 | 
						||
| 
								 | 
							
												    if(nameA > nameB) return 1;
							 | 
						||
| 
								 | 
							
												    return 0;
							 | 
						||
| 
								 | 
							
												})
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return this.stat_sorted;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/** return all info */
							 | 
						||
| 
								 | 
							
									this.info = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										var content = '';
							 | 
						||
| 
								 | 
							
										content += _t('Population') + ' : ' + this.pop() + ' - [' + _t('Min')
							 | 
						||
| 
								 | 
							
												+ ' : ' + this.min() + ' | ' + _t('Max') + ' : ' + this.max()
							 | 
						||
| 
								 | 
							
												+ ']' + "\n";
							 | 
						||
| 
								 | 
							
										content += _t('Mean') + ' : ' + this.mean() + ' - ' + _t('Median')	+ ' : ' + this.median() + "\n";
							 | 
						||
| 
								 | 
							
										content += _t('Variance') + ' : ' + this.variance() + ' - ' + _t('Standard deviation')	+ ' : ' + this.stddev()  
							 | 
						||
| 
								 | 
							
												+ ' - ' + _t('Coefficient of variation')	+ ' : ' + this.cov() + "\n";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return content;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Set Manual classification Return an array with bounds : ie array(0,
							 | 
						||
| 
								 | 
							
									 * 0.75, 1.5, 2.25, 3);
							 | 
						||
| 
								 | 
							
									 * Set ranges and prepare data for displaying legend
							 | 
						||
| 
								 | 
							
									 * 
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.setClassManually = function(array) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
									        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    if(array[0] !== this.min() || array[array.length-1] !== this.max()) {
							 | 
						||
| 
								 | 
							
									    	if(this.silent) this.log("[silent mode] " + t('Given bounds may not be correct! please check your input.\nMin value : ' + this.min() + ' / Max value : ' + this.max()), true);
							 | 
						||
| 
								 | 
							
											else throw new TypeError(_t('Given bounds may not be correct! please check your input.\nMin value : ' + this.min() + ' / Max value : ' + this.max()));
							 | 
						||
| 
								 | 
							
									    	return; 
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    this.setBounds(array);
							 | 
						||
| 
								 | 
							
									    this.setRanges();
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    // we specify the classification method
							 | 
						||
| 
								 | 
							
									    this.method = _t('manual classification') + ' (' + (array.length -1) + ' ' + _t('classes') + ')';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    return this.bounds;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Equal intervals classification Return an array with bounds : ie array(0,
							 | 
						||
| 
								 | 
							
									 * 0.75, 1.5, 2.25, 3);
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.getClassEqInterval = function(nbClass, forceMin, forceMax) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
									        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var tmpMin = (typeof forceMin === "undefined") ? this.min() : forceMin;
							 | 
						||
| 
								 | 
							
										var tmpMax = (typeof forceMax === "undefined") ? this.max() : forceMax;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
									    var a = Array();
							 | 
						||
| 
								 | 
							
									    var val = tmpMin;
							 | 
						||
| 
								 | 
							
									    var interval = (tmpMax - tmpMin) / nbClass;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    for (i = 0; i <= nbClass; i++) {
							 | 
						||
| 
								 | 
							
									        a[i] = val;
							 | 
						||
| 
								 | 
							
									        val += interval;
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    //-> Fix last bound to Max of values
							 | 
						||
| 
								 | 
							
									    a[nbClass] = tmpMax;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    this.setBounds(a);
							 | 
						||
| 
								 | 
							
									    this.setRanges();
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    // we specify the classification method
							 | 
						||
| 
								 | 
							
									    this.method = _t('eq. intervals') + ' (' + nbClass + ' ' + _t('classes') + ')';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    return this.bounds;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									this.getQuantiles = function(nbClass) {
							 | 
						||
| 
								 | 
							
										var tmp = this.sorted();
							 | 
						||
| 
								 | 
							
										var quantiles = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var step = this.pop() / nbClass;
							 | 
						||
| 
								 | 
							
										for (var i = 1; i < nbClass; i++) {
							 | 
						||
| 
								 | 
							
											var qidx = Math.round(i*step+0.49);
							 | 
						||
| 
								 | 
							
											quantiles.push(tmp[qidx-1]); // zero-based
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return quantiles;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Quantile classification Return an array with bounds : ie array(0, 0.75,
							 | 
						||
| 
								 | 
							
									 * 1.5, 2.25, 3);
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.getClassQuantile = function(nbClass) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var tmp = this.sorted();
							 | 
						||
| 
								 | 
							
										var bounds = this.getQuantiles(nbClass);
							 | 
						||
| 
								 | 
							
										bounds.unshift(tmp[0]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (bounds[tmp.length - 1] !== tmp[tmp.length - 1])
							 | 
						||
| 
								 | 
							
											bounds.push(tmp[tmp.length - 1]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.setBounds(bounds);
							 | 
						||
| 
								 | 
							
										this.setRanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// we specify the classification method
							 | 
						||
| 
								 | 
							
										this.method = _t('quantile') + ' (' + nbClass + ' ' + _t('classes') + ')';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										return this.bounds;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Standard Deviation classification
							 | 
						||
| 
								 | 
							
									 * Return an array with bounds : ie array(0,
							 | 
						||
| 
								 | 
							
									 * 0.75, 1.5, 2.25, 3);
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.getClassStdDeviation = function(nbClass, matchBounds) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
									        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    var tmpMax = this.max();
							 | 
						||
| 
								 | 
							
									    var tmpMin = this.min();
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    var a = Array();
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    // number of classes is odd
							 | 
						||
| 
								 | 
							
									    if(nbClass % 2 == 1) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    	// Euclidean division to get the inferior bound
							 | 
						||
| 
								 | 
							
									    	var infBound = Math.floor(nbClass / 2);
							 | 
						||
| 
								 | 
							
									    	
							 | 
						||
| 
								 | 
							
									    	var supBound = infBound + 1;
							 | 
						||
| 
								 | 
							
									    	
							 | 
						||
| 
								 | 
							
									    	// we set the central bounds
							 | 
						||
| 
								 | 
							
									    	a[infBound] = this.mean() - ( this.stddev() / 2);
							 | 
						||
| 
								 | 
							
									    	a[supBound] = this.mean() + ( this.stddev() / 2);
							 | 
						||
| 
								 | 
							
									    	
							 | 
						||
| 
								 | 
							
									    	// Values < to infBound, except first one
							 | 
						||
| 
								 | 
							
									    	for (i = infBound - 1; i > 0; i--) {
							 | 
						||
| 
								 | 
							
									    		var val = a[i+1] - this.stddev();
							 | 
						||
| 
								 | 
							
										        a[i] = val;
							 | 
						||
| 
								 | 
							
										    }
							 | 
						||
| 
								 | 
							
									    	
							 | 
						||
| 
								 | 
							
									    	// Values > to supBound, except last one
							 | 
						||
| 
								 | 
							
									    	for (i = supBound + 1; i < nbClass; i++) {
							 | 
						||
| 
								 | 
							
									    		var val = a[i-1] + this.stddev();
							 | 
						||
| 
								 | 
							
										        a[i] = val;
							 | 
						||
| 
								 | 
							
										    }
							 | 
						||
| 
								 | 
							
									    	
							 | 
						||
| 
								 | 
							
									    	// number of classes is even
							 | 
						||
| 
								 | 
							
									    } else {
							 | 
						||
| 
								 | 
							
									    	
							 | 
						||
| 
								 | 
							
									    	var meanBound = nbClass / 2;
							 | 
						||
| 
								 | 
							
									    	
							 | 
						||
| 
								 | 
							
									    	// we get the mean value
							 | 
						||
| 
								 | 
							
									    	a[meanBound] = this.mean();
							 | 
						||
| 
								 | 
							
									    	
							 | 
						||
| 
								 | 
							
									    	// Values < to the mean, except first one
							 | 
						||
| 
								 | 
							
									    	for (i = meanBound - 1; i > 0; i--) {
							 | 
						||
| 
								 | 
							
									    		var val = a[i+1] - this.stddev();
							 | 
						||
| 
								 | 
							
										        a[i] = val;
							 | 
						||
| 
								 | 
							
										    }
							 | 
						||
| 
								 | 
							
									    	
							 | 
						||
| 
								 | 
							
									    	// Values > to the mean, except last one
							 | 
						||
| 
								 | 
							
									    	for (i = meanBound + 1; i < nbClass; i++) {
							 | 
						||
| 
								 | 
							
									    		var val = a[i-1] + this.stddev();
							 | 
						||
| 
								 | 
							
										        a[i] = val;
							 | 
						||
| 
								 | 
							
										    }
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    // we finally set the first value
							 | 
						||
| 
								 | 
							
									    // do we excatly match min value or not ? 
							 | 
						||
| 
								 | 
							
									    a[0] = (typeof matchBounds === "undefined") ? a[1]-this.stddev() : this.min();
							 | 
						||
| 
								 | 
							
								    	
							 | 
						||
| 
								 | 
							
								    	// we finally set the last value
							 | 
						||
| 
								 | 
							
									    // do we excatly match max value or not ? 
							 | 
						||
| 
								 | 
							
								    	a[nbClass] = (typeof matchBounds === "undefined") ? a[nbClass-1]+this.stddev() : this.max();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    this.setBounds(a);
							 | 
						||
| 
								 | 
							
									    this.setRanges();
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    // we specify the classification method
							 | 
						||
| 
								 | 
							
									    this.method = _t('std deviation') + ' (' + nbClass + ' ' + _t('classes')+ ')'; 
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    return this.bounds;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Geometric Progression classification 
							 | 
						||
| 
								 | 
							
									 * http://en.wikipedia.org/wiki/Geometric_progression
							 | 
						||
| 
								 | 
							
									 * Return an array with bounds : ie array(0,
							 | 
						||
| 
								 | 
							
									 * 0.75, 1.5, 2.25, 3);
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.getClassGeometricProgression = function(nbClass) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
									        return;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    if(this._hasNegativeValue() || this._hasZeroValue()) {
							 | 
						||
| 
								 | 
							
									    	if(this.silent) this.log("[silent mode] " + _t('geometric progression can\'t be applied with a serie containing negative or zero values.'), true);
							 | 
						||
| 
								 | 
							
											else throw new TypeError(_t('geometric progression can\'t be applied with a serie containing negative or zero values.'));
							 | 
						||
| 
								 | 
							
									    	return;
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    var a = Array();
							 | 
						||
| 
								 | 
							
									    var tmpMin = this.min();
							 | 
						||
| 
								 | 
							
									    var tmpMax = this.max();
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    var logMax = Math.log(tmpMax) / Math.LN10; // max decimal logarithm (or base 10)
							 | 
						||
| 
								 | 
							
									    var logMin = Math.log(tmpMin) / Math.LN10;; // min decimal logarithm (or base 10)
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    var interval = (logMax - logMin) / nbClass;
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    // we compute log bounds
							 | 
						||
| 
								 | 
							
									    for (i = 0; i < nbClass; i++) {
							 | 
						||
| 
								 | 
							
									    	if(i == 0) {
							 | 
						||
| 
								 | 
							
									    		a[i] = logMin;
							 | 
						||
| 
								 | 
							
									    	} else {
							 | 
						||
| 
								 | 
							
									    		a[i] = a[i-1] + interval;
							 | 
						||
| 
								 | 
							
									    	}
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    // we compute antilog
							 | 
						||
| 
								 | 
							
									    a = a.map(function(x) { return Math.pow(10, x); });
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    // and we finally add max value
							 | 
						||
| 
								 | 
							
									    a.push(this.max());
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    this.setBounds(a);
							 | 
						||
| 
								 | 
							
									    this.setRanges();
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    // we specify the classification method
							 | 
						||
| 
								 | 
							
									    this.method = _t('geometric progression') + ' (' + nbClass + ' ' + _t('classes') + ')';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    return this.bounds;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Arithmetic Progression classification 
							 | 
						||
| 
								 | 
							
									 * http://en.wikipedia.org/wiki/Arithmetic_progression
							 | 
						||
| 
								 | 
							
									 * Return an array with bounds : ie array(0,
							 | 
						||
| 
								 | 
							
									 * 0.75, 1.5, 2.25, 3);
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.getClassArithmeticProgression = function(nbClass) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
									        return;
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    var denominator = 0;
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    // we compute the (french) "Raison"
							 | 
						||
| 
								 | 
							
									    for (i = 1; i <= nbClass; i++) {
							 | 
						||
| 
								 | 
							
									        denominator += i;
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    var a = Array();
							 | 
						||
| 
								 | 
							
									    var tmpMin = this.min();
							 | 
						||
| 
								 | 
							
									    var tmpMax = this.max();
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    var interval = (tmpMax - tmpMin) / denominator;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    for (i = 0; i <= nbClass; i++) {
							 | 
						||
| 
								 | 
							
									    	if(i == 0) {
							 | 
						||
| 
								 | 
							
									    		a[i] = tmpMin;
							 | 
						||
| 
								 | 
							
									    	} else {
							 | 
						||
| 
								 | 
							
									    		a[i] = a[i-1] + (i * interval);
							 | 
						||
| 
								 | 
							
									    	}
							 | 
						||
| 
								 | 
							
									    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    this.setBounds(a);
							 | 
						||
| 
								 | 
							
									    this.setRanges();
							 | 
						||
| 
								 | 
							
									    
							 | 
						||
| 
								 | 
							
									    // we specify the classification method
							 | 
						||
| 
								 | 
							
									    this.method = _t('arithmetic progression') + ' (' + nbClass + ' ' + _t('classes') + ')';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    return this.bounds;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Credits : Doug Curl (javascript) and Daniel J Lewis (python implementation)
							 | 
						||
| 
								 | 
							
									 * http://www.arcgis.com/home/item.html?id=0b633ff2f40d412995b8be377211c47b
							 | 
						||
| 
								 | 
							
									 * http://danieljlewis.org/2010/06/07/jenks-natural-breaks-algorithm-in-python/
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.getClassJenks = function(nbClass) {
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										dataList = this.sorted();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// now iterate through the datalist:
							 | 
						||
| 
								 | 
							
										// determine mat1 and mat2
							 | 
						||
| 
								 | 
							
										// really not sure how these 2 different arrays are set - the code for
							 | 
						||
| 
								 | 
							
										// each seems the same!
							 | 
						||
| 
								 | 
							
										// but the effect are 2 different arrays: mat1 and mat2
							 | 
						||
| 
								 | 
							
										var mat1 = []
							 | 
						||
| 
								 | 
							
										for ( var x = 0, xl = dataList.length + 1; x < xl; x++) {
							 | 
						||
| 
								 | 
							
											var temp = []
							 | 
						||
| 
								 | 
							
											for ( var j = 0, jl = nbClass + 1; j < jl; j++) {
							 | 
						||
| 
								 | 
							
												temp.push(0)
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											mat1.push(temp)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var mat2 = []
							 | 
						||
| 
								 | 
							
										for ( var i = 0, il = dataList.length + 1; i < il; i++) {
							 | 
						||
| 
								 | 
							
											var temp2 = []
							 | 
						||
| 
								 | 
							
											for ( var c = 0, cl = nbClass + 1; c < cl; c++) {
							 | 
						||
| 
								 | 
							
												temp2.push(0)
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											mat2.push(temp2)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// absolutely no idea what this does - best I can tell, it sets the 1st
							 | 
						||
| 
								 | 
							
										// group in the
							 | 
						||
| 
								 | 
							
										// mat1 and mat2 arrays to 1 and 0 respectively
							 | 
						||
| 
								 | 
							
										for ( var y = 1, yl = nbClass + 1; y < yl; y++) {
							 | 
						||
| 
								 | 
							
											mat1[0][y] = 1
							 | 
						||
| 
								 | 
							
											mat2[0][y] = 0
							 | 
						||
| 
								 | 
							
											for ( var t = 1, tl = dataList.length + 1; t < tl; t++) {
							 | 
						||
| 
								 | 
							
												mat2[t][y] = Infinity
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											var v = 0.0
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// and this part - I'm a little clueless on - but it works
							 | 
						||
| 
								 | 
							
										// pretty sure it iterates across the entire dataset and compares each
							 | 
						||
| 
								 | 
							
										// value to
							 | 
						||
| 
								 | 
							
										// one another to and adjust the indices until you meet the rules:
							 | 
						||
| 
								 | 
							
										// minimum deviation
							 | 
						||
| 
								 | 
							
										// within a class and maximum separation between classes
							 | 
						||
| 
								 | 
							
										for ( var l = 2, ll = dataList.length + 1; l < ll; l++) {
							 | 
						||
| 
								 | 
							
											var s1 = 0.0
							 | 
						||
| 
								 | 
							
											var s2 = 0.0
							 | 
						||
| 
								 | 
							
											var w = 0.0
							 | 
						||
| 
								 | 
							
											for ( var m = 1, ml = l + 1; m < ml; m++) {
							 | 
						||
| 
								 | 
							
												var i3 = l - m + 1
							 | 
						||
| 
								 | 
							
												var val = parseFloat(dataList[i3 - 1])
							 | 
						||
| 
								 | 
							
												s2 += val * val
							 | 
						||
| 
								 | 
							
												s1 += val
							 | 
						||
| 
								 | 
							
												w += 1
							 | 
						||
| 
								 | 
							
												v = s2 - (s1 * s1) / w
							 | 
						||
| 
								 | 
							
												var i4 = i3 - 1
							 | 
						||
| 
								 | 
							
												if (i4 != 0) {
							 | 
						||
| 
								 | 
							
													for ( var p = 2, pl = nbClass + 1; p < pl; p++) {
							 | 
						||
| 
								 | 
							
														if (mat2[l][p] >= (v + mat2[i4][p - 1])) {
							 | 
						||
| 
								 | 
							
															mat1[l][p] = i3
							 | 
						||
| 
								 | 
							
															mat2[l][p] = v + mat2[i4][p - 1]
							 | 
						||
| 
								 | 
							
														}
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											mat1[l][1] = 1
							 | 
						||
| 
								 | 
							
											mat2[l][1] = v
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var k = dataList.length
							 | 
						||
| 
								 | 
							
										var kclass = []
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// fill the kclass (classification) array with zeros:
							 | 
						||
| 
								 | 
							
										for (i = 0; i <= nbClass; i++) {
							 | 
						||
| 
								 | 
							
											kclass.push(0);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// this is the last number in the array:
							 | 
						||
| 
								 | 
							
										kclass[nbClass] = parseFloat(dataList[dataList.length - 1])
							 | 
						||
| 
								 | 
							
										// this is the first number - can set to zero, but want to set to lowest
							 | 
						||
| 
								 | 
							
										// to use for legend:
							 | 
						||
| 
								 | 
							
										kclass[0] = parseFloat(dataList[0])
							 | 
						||
| 
								 | 
							
										var countNum = nbClass
							 | 
						||
| 
								 | 
							
										while (countNum >= 2) {
							 | 
						||
| 
								 | 
							
											var id = parseInt((mat1[k][countNum]) - 2)
							 | 
						||
| 
								 | 
							
											kclass[countNum - 1] = dataList[id]
							 | 
						||
| 
								 | 
							
											k = parseInt((mat1[k][countNum] - 1))
							 | 
						||
| 
								 | 
							
											// spits out the rank and value of the break values:
							 | 
						||
| 
								 | 
							
											// console.log("id="+id,"rank = " + String(mat1[k][countNum]),"val =
							 | 
						||
| 
								 | 
							
											// " + String(dataList[id]))
							 | 
						||
| 
								 | 
							
											// count down:
							 | 
						||
| 
								 | 
							
											countNum -= 1
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										// check to see if the 0 and 1 in the array are the same - if so, set 0
							 | 
						||
| 
								 | 
							
										// to 0:
							 | 
						||
| 
								 | 
							
										if (kclass[0] == kclass[1]) {
							 | 
						||
| 
								 | 
							
											kclass[0] = 0
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										this.setBounds(kclass);
							 | 
						||
| 
								 | 
							
										this.setRanges();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										this.method = _t('Jenks') + ' (' + nbClass + ' ' + _t('classes') + ')';
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return this.bounds; //array of breaks
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Quantile classification Return an array with bounds : ie array(0, 0.75,
							 | 
						||
| 
								 | 
							
									 * 1.5, 2.25, 3);
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.getClassUniqueValues = function() {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										if (this._nodata())
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										this.is_uniqueValues = true;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										var tmp = this.sorted(); // display in alphabetical order
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										var a = Array();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (i = 0; i < this.pop(); i++) {
							 | 
						||
| 
								 | 
							
											if(a.indexOf(tmp[i]) === -1)
							 | 
						||
| 
								 | 
							
												a.push(tmp[i]);
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										this.bounds = a;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										// we specify the classification method
							 | 
						||
| 
								 | 
							
										this.method = _t('unique values');
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return a;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Return the class of a given value.
							 | 
						||
| 
								 | 
							
									 * For example value : 6
							 | 
						||
| 
								 | 
							
									 * and bounds array = (0, 4, 8, 12);
							 | 
						||
| 
								 | 
							
									 * Return 2
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.getClass = function(value) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for(i = 0; i < this.bounds.length; i++) {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											if(this.is_uniqueValues == true) {
							 | 
						||
| 
								 | 
							
												if(value == this.bounds[i])
							 | 
						||
| 
								 | 
							
													return i;
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												// parseFloat() is necessary
							 | 
						||
| 
								 | 
							
												if(parseFloat(value) <= this.bounds[i + 1]) {
							 | 
						||
| 
								 | 
							
													return i;
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return _t("Unable to get value's class.");
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Return the ranges array : array('0-0.75', '0.75-1.5', '1.5-2.25',
							 | 
						||
| 
								 | 
							
									 * '2.25-3');
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.getRanges = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return this.ranges;
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Returns the number/index of this.ranges that value falls into
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.getRangeNum = function(value) {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										var bounds, i;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										for (i = 0; i < this.ranges.length; i++) {
							 | 
						||
| 
								 | 
							
											bounds = this.ranges[i].split(/ - /);
							 | 
						||
| 
								 | 
							
											if (value <= parseFloat(bounds[1])) {
							 | 
						||
| 
								 | 
							
												return i;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/*
							 | 
						||
| 
								 | 
							
									 * Compute inner ranges based on serie. 
							 | 
						||
| 
								 | 
							
									 * Produce discontinous ranges used for legend - return an array similar to : 
							 | 
						||
| 
								 | 
							
									 * array('0.00-0.74', '0.98-1.52', '1.78-2.25', '2.99-3.14');
							 | 
						||
| 
								 | 
							
									 * If inner ranges already computed, return array values.
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.getInnerRanges = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										// if already computed, we return the result
							 | 
						||
| 
								 | 
							
										if(this.inner_ranges != null)
							 | 
						||
| 
								 | 
							
											return this.inner_ranges;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										var a = new Array();
							 | 
						||
| 
								 | 
							
										var tmp = this.sorted();
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										var cnt = 1; // bounds array counter
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										for (i = 0; i < tmp.length; i++) {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											if(i == 0) var range_firstvalue = tmp[i]; // we init first range value
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											if(parseFloat(tmp[i]) > parseFloat(this.bounds[cnt])) {
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												a[cnt - 1] = '' + range_firstvalue + this.separator + tmp[i-1];
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												var range_firstvalue =  tmp[i];
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												cnt++;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// we reach the last range, we finally complete manually
							 | 
						||
| 
								 | 
							
											// and return the array
							 | 
						||
| 
								 | 
							
											if(cnt == (this.bounds.length - 1)) {
							 | 
						||
| 
								 | 
							
												// we set the last value
							 | 
						||
| 
								 | 
							
												a[cnt - 1] = '' + range_firstvalue + this.separator + tmp[tmp.length-1];
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												this.inner_ranges = a;
							 | 
						||
| 
								 | 
							
												return this.inner_ranges;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									this.getSortedlist = function() {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										return this.sorted().join(', ');
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									/**
							 | 
						||
| 
								 | 
							
									 * Return an html legend
							 | 
						||
| 
								 | 
							
									 * colors : specify an array of color (hexadecimal values)
							 | 
						||
| 
								 | 
							
									 * legend :  specify a text input for the legend. By default, just displays 'legend'
							 | 
						||
| 
								 | 
							
									 * counter : if not null, display counter value
							 | 
						||
| 
								 | 
							
									 * callback : if not null, callback function applied on legend boundaries
							 | 
						||
| 
								 | 
							
									 * mode : 	null, 'default', 'distinct', 'discontinuous' : 
							 | 
						||
| 
								 | 
							
									 * 			- if mode is null, will display legend as 'default mode'
							 | 
						||
| 
								 | 
							
									 * 			- 'default' : displays ranges like in ranges array (continuous values), sample :  29.26 - 378.80 / 378.80 - 2762.25 /  2762.25 - 6884.84
							 | 
						||
| 
								 | 
							
									 * 			- 'distinct' : Add + 1 according to decimal precision to distinguish classes (discrete values), sample :  29.26 - 378.80 / 378.81 - 2762.25 /  2762.26 - 6884.84 
							 | 
						||
| 
								 | 
							
									 * 			- 'discontinuous' : indicates the range of data actually falling in each class , sample :  29.26 - 225.43 / 852.12 - 2762.20 /  3001.25 - 6884.84 / not implemented yet
							 | 
						||
| 
								 | 
							
									 * order : 	null, 'ASC', 'DESC'
							 | 
						||
| 
								 | 
							
									 */
							 | 
						||
| 
								 | 
							
									this.getHtmlLegend = function(colors, legend, counter, callback, mode, order) {
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										var cnt= '';
							 | 
						||
| 
								 | 
							
										var elements = new Array();
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										this.doCount(); // we do count, even if not displayed
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if(colors != null) {
							 | 
						||
| 
								 | 
							
											ccolors = colors;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else {
							 | 
						||
| 
								 | 
							
											ccolors = this.colors;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if(legend != null) {
							 | 
						||
| 
								 | 
							
											lg = legend;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else {
							 | 
						||
| 
								 | 
							
											lg =  'Legend';
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if(counter != null) {
							 | 
						||
| 
								 | 
							
											getcounter = true;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else {
							 | 
						||
| 
								 | 
							
											getcounter = false;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if(callback != null) {
							 | 
						||
| 
								 | 
							
											fn = callback;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else {
							 | 
						||
| 
								 | 
							
											fn = function(o) {return o;};
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if(mode == null) {
							 | 
						||
| 
								 | 
							
											mode = 'default';
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if(mode == 'discontinuous') {
							 | 
						||
| 
								 | 
							
											this.getInnerRanges();
							 | 
						||
| 
								 | 
							
											// check if some classes are not populated / equivalent of in_array function
							 | 
						||
| 
								 | 
							
											if(this.counter.indexOf(0) !== -1) {
							 | 
						||
| 
								 | 
							
										    	if(this.silent) this.log("[silent mode] " + _t("Geostats cannot apply 'discontinuous' mode to the getHtmlLegend() method because some classes are not populated.\nPlease switch to 'default' or 'distinct' modes. Exit!"), true);
							 | 
						||
| 
								 | 
							
												else throw new TypeError(_t("Geostats cannot apply 'discontinuous' mode to the getHtmlLegend() method because some classes are not populated.\nPlease switch to 'default' or 'distinct' modes. Exit!"));
							 | 
						||
| 
								 | 
							
												return;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if(order !== 'DESC') order = 'ASC';
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if(ccolors.length < this.ranges.length) {
							 | 
						||
| 
								 | 
							
											if(this.silent) this.log("[silent mode] " + _t('The number of colors should fit the number of ranges. Exit!'), true);
							 | 
						||
| 
								 | 
							
											else throw new TypeError(_t('The number of colors should fit the number of ranges. Exit!'));
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										if(this.is_uniqueValues == false) {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											for (i = 0; i < (this.ranges.length); i++) {
							 | 
						||
| 
								 | 
							
												if(getcounter===true) {
							 | 
						||
| 
								 | 
							
													cnt = ' <span class="geostats-legend-counter">(' + this.counter[i] + ')</span>';
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												//console.log("Ranges : " + this.ranges[i]);
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												// default mode 
							 | 
						||
| 
								 | 
							
												var tmp = this.ranges[i].split(this.separator);
							 | 
						||
| 
								 | 
							
													
							 | 
						||
| 
								 | 
							
												var start_value = parseFloat(tmp[0]).toFixed(this.precision);
							 | 
						||
| 
								 | 
							
												var end_value = parseFloat(tmp[1]).toFixed(this.precision);
							 | 
						||
| 
								 | 
							
													
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												// if mode == 'distinct' and we are not working on the first value
							 | 
						||
| 
								 | 
							
												if(mode == 'distinct' && i != 0) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
													if(isInt(start_value)) {
							 | 
						||
| 
								 | 
							
														start_value = parseInt(start_value) + 1;
							 | 
						||
| 
								 | 
							
														// format to float if necessary
							 | 
						||
| 
								 | 
							
														if(this.precisionflag == 'manual' && this.precision != 0) start_value = parseFloat(start_value).toFixed(this.precision);
							 | 
						||
| 
								 | 
							
													} else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
														start_value = parseFloat(start_value) + (1 / Math.pow(10,this.precision));
							 | 
						||
| 
								 | 
							
														// strangely the formula above return sometimes long decimal values, 
							 | 
						||
| 
								 | 
							
														// the following instruction fix it
							 | 
						||
| 
								 | 
							
														start_value = parseFloat(start_value).toFixed(this.precision);
							 | 
						||
| 
								 | 
							
													}
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												// if mode == 'discontinuous'
							 | 
						||
| 
								 | 
							
												if(mode == 'discontinuous') {
							 | 
						||
| 
								 | 
							
																		
							 | 
						||
| 
								 | 
							
													var tmp = this.inner_ranges[i].split(this.separator);
							 | 
						||
| 
								 | 
							
													// console.log("Ranges : " + this.inner_ranges[i]);
							 | 
						||
| 
								 | 
							
													
							 | 
						||
| 
								 | 
							
													var start_value = parseFloat(tmp[0]).toFixed(this.precision);
							 | 
						||
| 
								 | 
							
													var end_value = parseFloat(tmp[1]).toFixed(this.precision);
							 | 
						||
| 
								 | 
							
													
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												
							 | 
						||
| 
								 | 
							
												// we apply callback function
							 | 
						||
| 
								 | 
							
												var el = fn(start_value) + this.legendSeparator + fn(end_value);
							 | 
						||
| 
								 | 
							
													
							 | 
						||
| 
								 | 
							
												var block = '<div><div class="geostats-legend-block" style="background-color:' + ccolors[i] + '"></div> ' + el + cnt + '</div>';
							 | 
						||
| 
								 | 
							
												elements.push(block);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
											// only if classification is done on unique values
							 | 
						||
| 
								 | 
							
											for (i = 0; i < (this.bounds.length); i++) {
							 | 
						||
| 
								 | 
							
												if(getcounter===true) {
							 | 
						||
| 
								 | 
							
													cnt = ' <span class="geostats-legend-counter">(' + this.counter[i] + ')</span>';
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												var el = fn(this.bounds[i]);
							 | 
						||
| 
								 | 
							
												var block = '<div><div class="geostats-legend-block" style="background-color:' + ccolors[i] + '"></div> ' + el + cnt + '</div>';
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
												elements.push(block);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										// do we reverse the return legend ?
							 | 
						||
| 
								 | 
							
										if(order === 'DESC') elements.reverse(); 
							 | 
						||
| 
								 | 
							
										
							 | 
						||
| 
								 | 
							
										// finally we create HTML and return it
							 | 
						||
| 
								 | 
							
										var content  = '<div class="geostats-legend"><div class="geostats-legend-title">' + _t(lg) + '</div>';
							 | 
						||
| 
								 | 
							
										for (i = 0; i < (elements.length); i++) {
							 | 
						||
| 
								 | 
							
											content += elements[i];
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										content += '</div>';
							 | 
						||
| 
								 | 
							
								    
							 | 
						||
| 
								 | 
							
										return content;
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// object constructor
							 | 
						||
| 
								 | 
							
									// At the end of script. If not setPrecision() method is not known
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// we create an object identifier for debugging
							 | 
						||
| 
								 | 
							
									this.objectID = new Date().getUTCMilliseconds();
							 | 
						||
| 
								 | 
							
									this.log('Creating new geostats object');
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									if(typeof a !== 'undefined' && a.length > 0) {
							 | 
						||
| 
								 | 
							
										this.serie = a;
							 | 
						||
| 
								 | 
							
										this.setPrecision();
							 | 
						||
| 
								 | 
							
										this.log('Setting serie (' + a.length + ') : ' + a.join());
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										this.serie = Array();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									};
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									// creating aliases on classification function for backward compatibility
							 | 
						||
| 
								 | 
							
									this.getJenks = this.getClassJenks;
							 | 
						||
| 
								 | 
							
									this.getGeometricProgression = this.getClassGeometricProgression;
							 | 
						||
| 
								 | 
							
									this.getEqInterval = this.getClassEqInterval;
							 | 
						||
| 
								 | 
							
									this.getQuantile = this.getClassQuantile;
							 | 
						||
| 
								 | 
							
									this.getStdDeviation = this.getClassStdDeviation;
							 | 
						||
| 
								 | 
							
									this.getUniqueValues = this.getClassUniqueValues;
							 | 
						||
| 
								 | 
							
									this.getArithmeticProgression = this.getClassArithmeticProgression;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								window.geostats = geostats;
							 | 
						||
| 
								 | 
							
								return geostats;
							 | 
						||
| 
								 | 
							
								});
							 |