|
@@ -985,35 +985,235 @@ SVGLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
|
|
|
|
|
|
}
|
|
|
|
|
|
- function parseFloats( string ) {
|
|
|
+ // from https://github.com/ppvg/svg-numbers (MIT License)
|
|
|
|
|
|
- var array = string.split( /[\s,]+|(?=\s?[+\-])/ );
|
|
|
+ function parseFloats( input ) {
|
|
|
|
|
|
- for ( var i = 0; i < array.length; i ++ ) {
|
|
|
+ if ( typeof input !== 'string' ) {
|
|
|
|
|
|
- var number = array[ i ];
|
|
|
+ throw new TypeError( 'Invalid input: ' + typeof input );
|
|
|
|
|
|
- // Handle values like 48.6037.7.8
|
|
|
- // TODO Find a regex for this
|
|
|
+ }
|
|
|
+
|
|
|
+ // Character groups
|
|
|
+ var RE = {
|
|
|
+ SEPARATOR: /[ \t\r\n\,.\-+]/,
|
|
|
+ WHITESPACE: /[ \t\r\n]/,
|
|
|
+ DIGIT: /[\d]/,
|
|
|
+ SIGN: /[-+]/,
|
|
|
+ POINT: /\./,
|
|
|
+ COMMA: /,/,
|
|
|
+ EXP: /e/i
|
|
|
+ };
|
|
|
+
|
|
|
+ // States
|
|
|
+ var SEP = 0;
|
|
|
+ var INT = 1;
|
|
|
+ var FLOAT = 2;
|
|
|
+ var EXP = 3;
|
|
|
+
|
|
|
+ var state = SEP;
|
|
|
+ var seenComma = true;
|
|
|
+ var result = [], number = '', exponent = '';
|
|
|
+
|
|
|
+ function throwSyntaxError( current, i, partial ) {
|
|
|
+
|
|
|
+ var error = new SyntaxError( 'Unexpected character "' + current + '" at index ' + i + '.' );
|
|
|
+ error.partial = partial;
|
|
|
+ throw error;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ function newNumber() {
|
|
|
+
|
|
|
+ if ( number !== '' ) {
|
|
|
+
|
|
|
+ if ( exponent === '' ) result.push( Number( number ) );
|
|
|
+ else result.push( Number( number ) * Math.pow( 10, Number( exponent ) ) );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ number = '';
|
|
|
+ exponent = '';
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ var current, i = 0, length = input.length;
|
|
|
+ for ( i = 0; i < length; i ++ ) {
|
|
|
+
|
|
|
+ current = input[ i ];
|
|
|
+
|
|
|
+ // parse until next number
|
|
|
+ if ( state === SEP ) {
|
|
|
+
|
|
|
+ // eat whitespace
|
|
|
+ if ( RE.WHITESPACE.test( current ) ) {
|
|
|
+
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // start new number
|
|
|
+ if ( RE.DIGIT.test( current ) || RE.SIGN.test( current ) ) {
|
|
|
+
|
|
|
+ state = INT;
|
|
|
+ number = current;
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( RE.POINT.test( current ) ) {
|
|
|
+
|
|
|
+ state = FLOAT;
|
|
|
+ number = current;
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // throw on double commas (e.g. "1, , 2")
|
|
|
+ if ( RE.COMMA.test( current ) ) {
|
|
|
+
|
|
|
+ if ( seenComma ) {
|
|
|
+
|
|
|
+ throwSyntaxError( current, i, result );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ seenComma = true;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // parse integer part
|
|
|
+ if ( state === INT ) {
|
|
|
+
|
|
|
+ if ( RE.DIGIT.test( current ) ) {
|
|
|
+
|
|
|
+ number += current;
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( RE.POINT.test( current ) ) {
|
|
|
+
|
|
|
+ number += current;
|
|
|
+ state = FLOAT;
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( RE.EXP.test( current ) ) {
|
|
|
|
|
|
- if ( number.indexOf( '.' ) !== number.lastIndexOf( '.' ) ) {
|
|
|
+ state = EXP;
|
|
|
+ continue;
|
|
|
|
|
|
- var split = number.split( '.' );
|
|
|
+ }
|
|
|
+
|
|
|
+ // throw on double signs ("-+1"), but not on sign as separator ("-1-2")
|
|
|
+ if ( RE.SIGN.test( current )
|
|
|
+ && number.length === 1
|
|
|
+ && RE.SIGN.test( number[ 0 ] ) ) {
|
|
|
+
|
|
|
+ throwSyntaxError( current, i, result );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // parse decimal part
|
|
|
+ if ( state === FLOAT ) {
|
|
|
+
|
|
|
+ if ( RE.DIGIT.test( current ) ) {
|
|
|
+
|
|
|
+ number += current;
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
- for ( var s = 2; s < split.length; s ++ ) {
|
|
|
+ if ( RE.EXP.test( current ) ) {
|
|
|
|
|
|
- array.splice( i + s - 1, 0, '0.' + split[ s ] );
|
|
|
+ state = EXP;
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ // throw on double decimal points (e.g. "1..2")
|
|
|
+ if ( RE.POINT.test( current ) && number[ number.length - 1 ] === '.' ) {
|
|
|
+
|
|
|
+ throwSyntaxError( current, i, result );
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
- array[ i ] = parseFloatWithUnits( number );
|
|
|
+ // parse exponent part
|
|
|
+ if ( state == EXP ) {
|
|
|
+
|
|
|
+ if ( RE.DIGIT.test( current ) ) {
|
|
|
+
|
|
|
+ exponent += current;
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( RE.SIGN.test( current ) ) {
|
|
|
+
|
|
|
+ if ( exponent === '' ) {
|
|
|
+
|
|
|
+ exponent += current;
|
|
|
+ continue;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ if ( exponent.length === 1 && RE.SIGN.test( exponent ) ) {
|
|
|
+
|
|
|
+ throwSyntaxError( current, i, result );
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // end of number
|
|
|
+ if ( RE.WHITESPACE.test( current ) ) {
|
|
|
+
|
|
|
+ newNumber();
|
|
|
+ state = SEP;
|
|
|
+ seenComma = false;
|
|
|
+
|
|
|
+ } else if ( RE.COMMA.test( current ) ) {
|
|
|
+
|
|
|
+ newNumber();
|
|
|
+ state = SEP;
|
|
|
+ seenComma = true;
|
|
|
+
|
|
|
+ } else if ( RE.SIGN.test( current ) ) {
|
|
|
+
|
|
|
+ newNumber();
|
|
|
+ state = INT;
|
|
|
+ number = current;
|
|
|
+
|
|
|
+ } else if ( RE.POINT.test( current ) ) {
|
|
|
+
|
|
|
+ newNumber();
|
|
|
+ state = FLOAT;
|
|
|
+ number = current;
|
|
|
+
|
|
|
+ } else {
|
|
|
+
|
|
|
+ throwSyntaxError( current, i, result );
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
|
- return array;
|
|
|
+ // add the last number found (if any)
|
|
|
+ newNumber();
|
|
|
|
|
|
+ return result;
|
|
|
|
|
|
}
|
|
|
|