function update ( ) {
var size = parseNum ( $ ( '#INPUT_SIZE' ) . val ( ) ) ;
var unit _select = $ ( '#unit_select input[type="radio"]:checked' ) . val ( ) ;
var hres1 = parseInt ( parseNum ( $ ( '#INPUT_HRES' ) . val ( ) ) ) ;
var vres1 = parseInt ( parseNum ( $ ( '#INPUT_VRES' ) . val ( ) ) ) ;
var ar _options = {
'p_max' : 4 ,
'p_min' : 2 ,
}
var ar1 = long _division ( hres1 , vres1 , ar _options ) ;
var diag = parseFloat ( size ) ;
var width = size * Math . sin ( Math . atan ( hres1 / vres1 ) ) ;
var height = size * Math . cos ( Math . atan ( hres1 / vres1 ) ) ;
var area = width * height ;
var px _density = hres1 / width ;
var total _px = hres1 * vres1 ;
var hres2 = parseNum ( $ ( '#INPUT_HRES2' ) . val ( ) ) ;
var vres2 = parseNum ( $ ( '#INPUT_VRES2' ) . val ( ) ) ;
var ar2 = hres2 / vres2 ;
var d _match = Math . sqrt ( ( height * height ) * ( 1 + ( ar2 * ar2 ) ) ) ;
var opt _res = parseInt ( vres1 * ar2 ) + ' × ' + vres1 ;
var hres _den = parseInt ( parseNum ( $ ( '#INPUT_HRES_DENSITY' ) . val ( ) ) ) ;
var vres _den = parseInt ( parseNum ( $ ( '#INPUT_VRES_DENSITY' ) . val ( ) ) ) ;
var ar _den = long _division ( hres _den , vres _den , ar _options ) ;
var width2 = width * ( hres _den / hres1 ) ;
var height2 = height * ( vres _den / vres1 ) ;
var size2 = Math . sqrt ( ( width2 * width2 ) + ( height2 * height2 ) ) ;
/ * C o n v e r s i o n C o d e s :
1 : Secondary units have normal conversion factor
2 : Secondary units have squared conversion factor
3 : Secondary units have reciprocal conversion factor
* /
display ( new UNIT ( unit _select ) ,
[
[ 'RESULT_DIAG' , 1 , diag . toFixed ( 3 ) , ( isPositive ( size ) ) ] ,
[ 'RESULT_WIDTH' , 1 , width . toFixed ( 3 ) , ( isPositive ( [ size , hres1 , vres1 ] ) ) ] ,
[ 'RESULT_HEIGHT' , 1 , height . toFixed ( 3 ) , ( isPositive ( [ size , hres1 , vres1 ] ) ) ] ,
[ 'RESULT_AREA' , 2 , area . toFixed ( 3 ) , ( isPositive ( [ size , hres1 , vres1 ] ) ) ] ,
[ 'RESULT_PX_DENSITY' , 3 , px _density . toFixed ( 3 ) , ( isPositive ( [ size , hres1 , vres1 ] ) ) ] ,
[ 'RESULT_D_MATCH' , 1 , d _match . toFixed ( 3 ) , ( isPositive ( [ size , hres1 , vres1 , hres2 , vres2 ] ) ) ] ,
[ 'RESULT_DENSITY_SIZE' , 1 , size2 . toFixed ( 3 ) , ( isPositive ( [ size , hres1 , vres1 , hres _den , vres _den ] ) ) ] ,
]
) ;
if ( isNum ( [ size , hres1 , vres1 , hres2 , vres2 ] ) && isPositive ( [ size , hres1 , vres1 , hres2 , vres2 ] ) ) {
$ ( '#RESULT_OPT_RES' ) . html ( opt _res ) ;
if ( hres2 == '21' && vres2 == '9' ) {
$ ( '#21_9_warning' ) . css ( 'display' , 'table-row' ) ;
}
else {
$ ( '#21_9_warning' ) . css ( 'display' , 'none' ) ;
}
}
else
{ $ ( '#RESULT_OPT_RES' ) . html ( '' ) ; }
//if (hres1 != '' && vres1 != '' && hres1 != 0 && vres1 != 0 && isNaN(hres1) == false && isNaN(vres1) == false) {
if ( isNum ( [ hres1 , vres1 ] ) && isPositive ( [ hres1 , vres1 ] ) ) {
// $('#RESULT_RATIO').html(commas(ar1.toFixed(3)) + ' (' + parseInt(hres1 / GCD(hres1, vres1)) + '<span style="vertical-align:baseline; position:relative; top:-0.05em;">:</span>' + parseInt(vres1 / GCD(hres1, vres1)) + ')');
$ ( '#RESULT_RATIO' ) . html ( ar1 + '∶1 (' + commas ( parseInt ( hres1 / GCD ( hres1 , vres1 ) ) ) + '∶' + commas ( parseInt ( vres1 / GCD ( hres1 , vres1 ) ) ) + ')' ) ;
$ ( '#RESULT_TOTAL_PX' ) . html ( commas ( total _px ) + ' (' + prefixGen ( total _px , 2 ) [ 'num' ] + ' ' + prefixGen ( total _px , 2 ) [ 'prefix' ] + 'px)' ) ;
}
else {
$ ( '#RESULT_RATIO' ) . html ( '' ) ;
$ ( '#RESULT_TOTAL_PX' ) . html ( '' ) ;
}
//!= '' && vres1 != '' && hres1 != 0 && vres1 != 0 && isNaN(hres1) == false && isNaN(vres1) == false
//DEBUG('isInt', isInt([hres1, vres1, hres_den, vres_den]), 'isPositive', isPositive([hres1, vres1, hres_den, vres_den]));
//DEBUG('hres1', hres1, isInt(hres1), 'vres1', vres1, isInt(vres1), 'hres_den', hres_den, isInt(hres_den), 'vres_den', vres_den, isInt(vres_den));
if ( isInt ( [ hres1 , vres1 , hres _den , vres _den ] ) && isPositive ( [ hres1 , vres1 , hres _den , vres _den ] ) ) {
// $('#RESULT_DENSITY_RATIO').html(commas(ar_den.toFixed(3)) + ' (' + parseInt(hres_den / GCD(hres_den, vres_den)) + '<span style="vertical-align:baseline; position:relative; top:-0.05em;">:</span>' + parseInt(vres_den / GCD(hres_den, vres_den)) + ')');
$ ( '#RESULT_DENSITY_RATIO' ) . html ( ar _den + '∶1 (' + commas ( parseInt ( hres _den / GCD ( hres _den , vres _den ) ) ) + '∶' + commas ( parseInt ( vres _den / GCD ( hres _den , vres _den ) ) ) + ')' ) ;
}
else {
$ ( '#RESULT_DENSITY_RATIO' ) . html ( '' ) ;
}
return ;
}
// Returns false if input is a non-integer number or NaN
function isInt ( num ) {
if ( Array . isArray ( num ) == true ) {
for ( a = 0 ; a < num . length ; a ++ ) {
if ( Number . isInteger ( parseNum ( num [ a ] ) ) == false ) {
//DEBUG('isInt Array False. a:', a, 'num[a]:', num[a], 'Number.isInteger(num[a]):', Number.isInteger(num[a]));
return false ;
}
return true ;
}
}
else
return Number . isInteger ( parseNum ( num ) ) ;
}
function isFloat ( num ) {
if ( Array . isArray ( num ) == true ) {
for ( a = 0 ; a < num . length ; a ++ ) {
if ( Number . isInteger ( parseNum ( num [ a ] ) ) == true || Number . isNaN ( num [ a ] ) == true ) {
return false ;
}
return true ;
}
}
else
return ! ( Number . isInteger ( parseNum ( num ) ) || Number . isNaN ( parseNum ( num ) ) ) ;
}
// Returns false if input is not a positive number (zero, negative number, or NaN)
function isPositive ( num ) {
if ( Array . isArray ( num ) == true ) {
for ( a = 0 ; a < num . length ; a ++ ) {
if ( Number . isNaN ( parseNum ( num [ a ] ) ) == true )
return false ;
else if ( num [ a ] <= 0 )
return false ;
}
return true ;
}
else {
if ( Number . isNaN ( parseNum ( num ) ) == true )
return false ;
else if ( num > 0 )
return true ;
else {
return false ;
}
}
}
function isNonNegative ( num ) {
if ( Array . isArray ( num ) == true ) {
for ( a = 0 ; a < num . length ; a ++ ) {
if ( Number . isNaN ( parseNum ( num [ a ] ) ) == true )
return false ;
else if ( num [ a ] < 0 )
return false ;
}
return true ;
}
else {
if ( Number . isNaN ( parseNum ( num ) ) == true )
return false ;
else if ( num >= 0 )
return true ;
else {
return false ;
}
}
}
// Returns false if input is NaN
function isNum ( num ) {
if ( Array . isArray ( num ) == true ) {
for ( a = 0 ; a < num . length ; a ++ ) {
if ( Number . isNaN ( parseNum ( num [ a ] ) ) == true ) {
return false ;
}
return true ;
}
}
else {
return ! Number . isNaN ( parseNum ( num ) ) ;
}
}
// Converts string to floating point if it has a decimal point, or integer if there is no decimal point. Also strips commas and spaces, and optionally applies absolute value.
// Cannot handle inputs with negative signs in the wrong position.
function parseNum ( str ) {
if ( typeof str === "string" ) {
str = str . replace ( /[^0-9\. ]/g , '' ) ; // Apply absolute value
// str = str.replace(/[^0-9\. -]/g, ''); // Allow negative numbers
// Return NaN if...
if ( str == '' // input is blank
|| str . indexOf ( '.' ) != str . lastIndexOf ( '.' ) // input contains multiple decimal places
|| str . indexOf ( '-' ) != str . lastIndexOf ( '-' ) // input contains multiple minus signs
|| ( str . indexOf ( '-' ) != - 1 && str . indexOf ( '-' ) != 0 ) ) { // input contains a minus sign in a position other than the first character
return NaN ;
}
else {
if ( str . indexOf ( '.' ) == - 1 )
return parseInt ( str ) ;
else {
return parseFloat ( str ) ;
}
}
}
else if ( Number . isNaN ( str ) )
return NaN ;
else if ( typeof str === "number" ) {
return str ;
}
}
function display ( units , list ) {
var el ;
for ( var x = 0 ; x < list . length ; x ++ ) {
if ( isNaN ( list [ x ] [ 2 ] ) == true || isFinite ( list [ x ] [ 2 ] ) == false || list [ x ] [ 3 ] == false ) {
$ ( '#' + list [ x ] [ 0 ] ) . html ( '' ) ;
}
else {
el = $ ( '#' + list [ x ] [ 0 ] ) ;
el . html ( commas ( list [ x ] [ 2 ] ) ) ;
if ( list [ x ] [ 1 ] == 1 ) {
el [ 0 ] . innerHTML += units . sym ( ) [ 0 ] + ' (' + commas ( ( list [ x ] [ 2 ] * units . conv ( ) ) . toFixed ( 3 ) ) + units . sym ( ) [ 1 ] + ')' ;
}
else if ( list [ x ] [ 1 ] == 2 ) {
el [ 0 ] . innerHTML += ' ' + units . abbr ( ) [ 0 ] + '<sup>2</sup> (' + commas ( ( list [ x ] [ 2 ] * units . conv ( ) * units . conv ( ) ) . toFixed ( 3 ) ) + ' ' + units . abbr ( ) [ 1 ] + '<sup>2</sup>)' ;
}
else if ( list [ x ] [ 1 ] == 3 ) {
el [ 0 ] . innerHTML += ' px/' + units . abbr ( ) [ 0 ] + ' (' + commas ( ( list [ x ] [ 2 ] * ( 1 / units . conv ( ) ) ) . toFixed ( 3 ) ) + ' px/' + units . abbr ( ) [ 1 ] + ')' ;
}
}
}
return ;
}
function UNIT ( mode ) {
this . _primary = mode ;
this . set = function ( mode ) {
this . _primary = mode ;
}
this . constructor = function ( mode ) {
this . _primary ( mode ) ;
}
this . full = function ( ) {
if ( this . _primary == 'in' ) { return [ 'inches' , 'centimeters' ] ; }
else if ( this . _primary == 'cm' ) { return [ 'centimeters' , 'inches' ] ; }
}
this . abbr = function ( ) {
if ( this . _primary == 'in' ) { return [ 'in' , 'cm' ] ; }
else if ( this . _primary == 'cm' ) { return [ 'cm' , 'in' ] ; }
}
this . sym = function ( ) {
if ( this . _primary == 'in' ) { return [ '"' , ' cm' ] ; }
else if ( this . _primary == 'cm' ) { return [ ' cm' , '"' ] ; }
}
this . conv = function ( ) {
if ( this . _primary == 'in' ) { return 2.54 ; }
else if ( this . _primary == 'cm' ) { return 1 / 2.54 ; }
}
}
function prefixGen ( num , precision ) {
var out _num ;
var out _prefix ;
var prefixDef = {
'-8' : 'y' ,
'-7' : 'z' ,
'-6' : 'a' ,
'-5' : 'f' ,
'-4' : 'p' ,
'-3' : 'n' ,
'-2' : 'µ' ,
'-1' : 'm' ,
'0' : '' ,
'1' : 'K' ,
'2' : 'M' ,
'3' : 'G' ,
'4' : 'T' ,
'5' : 'P' ,
'6' : 'E' ,
'7' : 'Z' ,
'8' : 'Y'
} ;
var magnitude = Math . floor ( Math . log ( num ) / Math . log ( 1000 ) ) ;
if ( magnitude >= - 8 && magnitude <= 8 ) {
out _num = commas ( Number ( num / Math . pow ( 1000 , magnitude ) ) . toFixed ( precision ) ) ;
out _prefix = prefixDef [ magnitude ] ;
}
else {
out _num = commas ( num ) ;
out _prefix = '' ;
}
return {
'num' : out _num ,
'prefix' : out _prefix
} ;
}
function pxPrefix ( num , precision ) {
var x = prefixGen ( num , precision ) ;
return ( x [ 'num' ] + ' ' + x [ 'prefix' ] + 'px' ) ;
}
function GCD ( a , b ) {
a = Math . abs ( a ) ;
b = Math . abs ( b ) ;
if ( b > a ) { var temp = a ; a = b ; b = temp ; }
while ( true ) {
if ( b == 0 ) return a ;
a %= b ;
if ( a == 0 ) return b ;
b %= a ;
}
}
function commas ( input , group , radix ) {
if ( ! group ) { group = ',' ; }
if ( ! radix ) { radix = '.' ; }
var parts = input . toString ( ) . split ( radix ) ;
parts [ 0 ] = parts [ 0 ] . replace ( /\B(?=(\d{3})+(?!\d))/g , group ) ;
return parts . join ( radix ) ;
}
function long _division ( A , B , options ) {
if ( isNaN ( A / B ) || ! isFinite ( A / B ) ) { DEBUG ( 'Answer is NaN or Infinity. Function aborted.' ) ; return '' ; }
var OL _open = '<span style="text-decoration:overline;">' ; // Overline markup opening tag
var OL _close = '</span>' ; // Overline markup closing tag. Used in conjunction with OL_open to surround the repeating numbers. May be set to control markup, separate it with parentheses, or simply left blank, etc.
var p _max = 8 ; // Maximum number of decimal places
var p _min = 3 ; // Minimum number of decimal places
var Approx = '≈' ; // Symbol to be used for "approximately equal to". Can be set blank to turn off this functionality, etc.
var Radix _Point = '.' ; // Character to use for the radix point ("decimal point")
var Group = ',' ; // Character to use for digit grouping. Can be set blank to disable digit grouping.
var Base = 10 ; // Number base system to use
var Minus _Sign = '−' ; // Character to preceed negative numbers. Default minus sign, can be set blank to output absolute value, or set to hyphen-minus for better compatibility or for other functions to be able to parse as a number correctly.
var Plus _Sign = '' ; // Character to preceed positive numbers. Default blank, but can be set to "+" if explicit signs on both positive and negative numbers is desired.
var RepeatSinglesFlag = true ; // Display single-digit repeating patterns as 1.(33) instead of 1.(3)
if ( typeof ( options ) === 'number' ) { // If 3rd argument is a number rather than a dictionary, use it as the p_max value
p _max = options ;
}
else if ( options ) {
if ( 'OL_open' in options ) { OL _open = options [ 'OL_open' ] ; }
if ( 'OL_close' in options ) { OL _close = options [ 'OL_close' ] ; }
if ( 'p_max' in options ) { p _max = options [ 'p_max' ] ; }
if ( 'p_min' in options ) { p _min = options [ 'p_min' ] ; }
if ( 'radix' in options ) { Radix _Point = options [ 'radix' ] ; }
if ( 'group' in options ) { Group = options [ 'group' ] ; }
if ( 'approx' in options ) { Approx = options [ 'approx' ] ; }
if ( 'minus' in options ) { Minus _Sign = options [ 'minus' ] ; }
if ( 'plus' in options ) { Plus _Sign = options [ 'plus' ] ; }
if ( 'base' in options ) { Base = options [ 'base' ] ; }
if ( 'repeat_singles' in options ) { RepeatSinglesFlag = options [ 'repeat_singles' ] ; }
}
var Decimal _Digits = '' ;
var Previous _Dividends = { } ;
var Prefix = '' ;
var Repetend = '' ;
var RepeatFlag = false ;
var ApproxFlag = true ;
var Sign = Plus _Sign ;
// Determine if answer will be negative, then use the absolute value of inputs for the rest of the calculations.
if ( ( A < 0 ) ? ! ( B < 0 ) : ( B < 0 ) ) { Sign = Minus _Sign ; } // If (A is negative) XOR (B is negative) then final result will be negative.
var Dividend = Math . abs ( parseFloat ( A ) ) ;
var Divisor = Math . abs ( parseFloat ( B ) ) ;
p _max = parseInt ( p _max ) ;
p _min = parseInt ( p _min ) ;
Base = parseInt ( Base ) ;
if ( p _max < 0 || p _min < 0 || p _max < p _min || isNaN ( p _max ) || isNaN ( p _min ) || ! isFinite ( p _max ) || ! isFinite ( p _min ) ) {
DEBUG ( 'Invalid p_max and p_min values. Both values must be non-negative numbers, and p_min cannot be greater than p_max. p_max:' , p _max , 'p_min' , p _min )
return '' ;
}
if ( ! isInt ( Base ) ) {
DEBUG ( 'Invalid Base value. Must be an integer number. Base:' , Base ) ;
return '' ;
}
if ( p _max == 0 ) { // If p_max is 0, then output is integer values only, and the long division section is not necessary.
var Result = Math . round ( Dividend / Divisor ) . toFixed ( 0 ) ;
if ( Result != ( Dividend / Divisor ) ) { ApproxFlag = true ; }
Result = Sign . concat ( Result . toString ( ) ) ;
if ( ApproxFlag == true ) { Result = Approx . concat ( Result ) ; }
return Result ;
}
var Quotient = Dividend / Divisor ;
var Remainder = Dividend % Divisor ;
var Result = Math . floor ( Quotient ) . toString ( ) + Radix _Point ; // Use floor division to determine the front part of the number immediately
Dividend = Remainder * Base ;
// Use long division for the decimal places, so that repeating decimals can be detected
var i = 0 ;
while ( i < p _max + 2 ) {
if ( ! ( Dividend in Previous _Dividends ) ) {
Previous _Dividends [ Dividend ] = i ;
Quotient = Dividend / Divisor ;
Remainder = Dividend % Divisor ;
Dividend = Remainder * Base ;
//if (i < p_max) {
Decimal _Digits += Math . floor ( Quotient ) . toString ( ) ;
//}
//DEBUG('i:', i, 'Quotient:', Quotient, 'Remainder:', Remainder, 'Dividend:', Dividend, 'Result:', Result, 'Decimal_Digits:', Decimal_Digits);
}
else {
RepeatFlag = true ;
ApproxFlag = false ;
Prefix = Decimal _Digits . substring ( 0 , Previous _Dividends [ Dividend ] ) ;
Repetend = Decimal _Digits . substring ( Previous _Dividends [ Dividend ] , Decimal _Digits . length ) ;
if ( Repetend == '0' ) { // A "repeating" dividend of 0 signals a non-repeating result
Repetend = '' ;
RepeatFlag = false ;
Decimal _Digits = Prefix ;
}
//Decimal_Digits = Prefix + Repetend;
break ;
}
i += 1 ;
}
if ( RepeatFlag == false ) {
if ( Decimal _Digits . length > p _max ) {
//Decimal_Digits = Decimal_Digits.substr(0, p_max);
Decimal _Digits = Math . round ( parseFloat ( Decimal _Digits . substr ( 0 , p _max ) + '.' + Decimal _Digits . substr ( p _max ) ) ) . toString ( ) ;
if ( p _max - Decimal _Digits . length >= 0 ) {
Decimal _Digits = '0' . repeat ( p _max - Decimal _Digits . length ) + Decimal _Digits ;
}
ApproxFlag = true ;
}
if ( ( Decimal _Digits . length < p _min ) && ( p _min - Decimal _Digits . length >= 0 ) ) {
Decimal _Digits += '0' . repeat ( p _min - Decimal _Digits . length ) ;
}
}
if ( RepeatFlag == true ) {
if ( Prefix . length + Repetend . length > p _max ) {
if ( Prefix . length > p _max ) {
Prefix = Math . round ( parseFloat ( Prefix . substr ( 0 , p _max ) + '.' + Prefix . substr ( p _max ) ) ) . toString ( ) ;
if ( p _max - Prefix . length >= 0 ) {
Prefix = '0' . repeat ( p _max - Prefix . length ) + Prefix ;
}
}
else {
Prefix = Prefix + Repetend . substr ( 0 , p _max - Prefix . length ) ;
}
Decimal _Digits = Prefix ;
RepeatFlag = false ;
ApproxFlag = true ;
}
if ( Prefix . length + Repetend . length < p _min ) {
if ( ( p _min - ( Prefix . length + Repetend . length ) ) >= Repetend . length ) {
Repetend += Repetend . repeat ( Math . floor ( ( p _min - ( Prefix . length + Repetend . length ) ) / Repetend . length ) ) ;
}
while ( Prefix . length + Repetend . length < p _min ) {
Prefix = Prefix . concat ( Repetend [ 0 ] ) ;
Repetend = Repetend . slice ( 1 ) . concat ( Repetend [ 0 ] ) ;
}
}
}
if ( RepeatFlag == true ) {
if ( Repetend . length == 1 && ( Prefix . length + Repetend . length < p _max ) && RepeatSinglesFlag == true ) { Repetend = Repetend . repeat ( 2 ) ; } // Single-digit repetitions will be displayed twice, i.e. 4/3 will result in 1.(33) rather than 1.(3)
Result += Prefix + OL _open + Repetend + OL _close ;
}
else {
Result += Decimal _Digits ;
}
if ( Result [ Result . length - 1 ] == Radix _Point ) { Result = Result . replace ( Radix _Point , '' ) ; }
Result = commas ( Result , Group , Radix _Point ) ;
Result = Sign . concat ( Result ) ;
if ( ApproxFlag == true ) {
Result = Approx . concat ( Result ) ;
}
return Result ;
//return Result * Sign;
}