|
@@ -59,6 +59,8 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
|
|
|
|
|
|
var transform = getNodeTransform( node );
|
|
var transform = getNodeTransform( node );
|
|
|
|
|
|
|
|
+ var traverseChildNodes = true;
|
|
|
|
+
|
|
var path = null;
|
|
var path = null;
|
|
|
|
|
|
switch ( node.nodeName ) {
|
|
switch ( node.nodeName ) {
|
|
@@ -109,6 +111,24 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
|
|
path = parseLineNode( node );
|
|
path = parseLineNode( node );
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
+ case 'defs':
|
|
|
|
+ traverseChildNodes = false;
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 'use':
|
|
|
|
+ style = parseStyle( node, style );
|
|
|
|
+ var usedNodeId = node.href.baseVal.substring( 1 );
|
|
|
|
+ var usedNode = node.viewportElement.getElementById( usedNodeId );
|
|
|
|
+ if ( usedNode ) {
|
|
|
|
+
|
|
|
|
+ parseNode( usedNode, style );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ else console.warn( "SVGLoader: 'use node' references non-existent 'defs node' id: " + usedNodeId );
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+
|
|
default:
|
|
default:
|
|
// console.log( node );
|
|
// console.log( node );
|
|
|
|
|
|
@@ -130,11 +150,15 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- var nodes = node.childNodes;
|
|
|
|
|
|
+ if ( traverseChildNodes ) {
|
|
|
|
+
|
|
|
|
+ var nodes = node.childNodes;
|
|
|
|
|
|
- for ( var i = 0; i < nodes.length; i ++ ) {
|
|
|
|
|
|
+ for ( var i = 0; i < nodes.length; i ++ ) {
|
|
|
|
|
|
- parseNode( nodes[ i ], style );
|
|
|
|
|
|
+ parseNode( nodes[ i ], style );
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
@@ -641,13 +665,13 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
|
|
rx = Math.abs( rx );
|
|
rx = Math.abs( rx );
|
|
ry = Math.abs( ry );
|
|
ry = Math.abs( ry );
|
|
|
|
|
|
- // Compute (x1′, y1′)
|
|
|
|
|
|
+ // Compute (x1â², y1â²)
|
|
var dx2 = ( start.x - end.x ) / 2.0;
|
|
var dx2 = ( start.x - end.x ) / 2.0;
|
|
var dy2 = ( start.y - end.y ) / 2.0;
|
|
var dy2 = ( start.y - end.y ) / 2.0;
|
|
var x1p = Math.cos( x_axis_rotation ) * dx2 + Math.sin( x_axis_rotation ) * dy2;
|
|
var x1p = Math.cos( x_axis_rotation ) * dx2 + Math.sin( x_axis_rotation ) * dy2;
|
|
var y1p = - Math.sin( x_axis_rotation ) * dx2 + Math.cos( x_axis_rotation ) * dy2;
|
|
var y1p = - Math.sin( x_axis_rotation ) * dx2 + Math.cos( x_axis_rotation ) * dy2;
|
|
|
|
|
|
- // Compute (cx′, cy′)
|
|
|
|
|
|
+ // Compute (cxâ², cyâ²)
|
|
var rxs = rx * rx;
|
|
var rxs = rx * rx;
|
|
var rys = ry * ry;
|
|
var rys = ry * ry;
|
|
var x1ps = x1p * x1p;
|
|
var x1ps = x1p * x1p;
|
|
@@ -674,11 +698,11 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
|
|
var cxp = q * rx * y1p / ry;
|
|
var cxp = q * rx * y1p / ry;
|
|
var cyp = - q * ry * x1p / rx;
|
|
var cyp = - q * ry * x1p / rx;
|
|
|
|
|
|
- // Step 3: Compute (cx, cy) from (cx′, cy′)
|
|
|
|
|
|
+ // Step 3: Compute (cx, cy) from (cxâ², cyâ²)
|
|
var cx = Math.cos( x_axis_rotation ) * cxp - Math.sin( x_axis_rotation ) * cyp + ( start.x + end.x ) / 2;
|
|
var cx = Math.cos( x_axis_rotation ) * cxp - Math.sin( x_axis_rotation ) * cyp + ( start.x + end.x ) / 2;
|
|
var cy = Math.sin( x_axis_rotation ) * cxp + Math.cos( x_axis_rotation ) * cyp + ( start.y + end.y ) / 2;
|
|
var cy = Math.sin( x_axis_rotation ) * cxp + Math.cos( x_axis_rotation ) * cyp + ( start.y + end.y ) / 2;
|
|
|
|
|
|
- // Step 4: Compute θ1 and Δθ
|
|
|
|
|
|
+ // Step 4: Compute θ1 and Îθ
|
|
var theta = svgAngle( 1, 0, ( x1p - cxp ) / rx, ( y1p - cyp ) / ry );
|
|
var theta = svgAngle( 1, 0, ( x1p - cxp ) / rx, ( y1p - cyp ) / ry );
|
|
var delta = svgAngle( ( x1p - cxp ) / rx, ( y1p - cyp ) / ry, ( - x1p - cxp ) / rx, ( - y1p - cyp ) / ry ) % ( Math.PI * 2 );
|
|
var delta = svgAngle( ( x1p - cxp ) / rx, ( y1p - cyp ) / ry, ( - x1p - cxp ) / rx, ( - y1p - cyp ) / ry ) % ( Math.PI * 2 );
|
|
|
|
|
|
@@ -1069,7 +1093,7 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
|
|
|
|
|
|
function getNodeTransform( node ) {
|
|
function getNodeTransform( node ) {
|
|
|
|
|
|
- if ( ! node.hasAttribute( 'transform' ) ) {
|
|
|
|
|
|
+ if ( ! ( node.hasAttribute( 'transform' ) || ( node.nodeName == 'use' && ( node.hasAttribute( 'x' ) || node.hasAttribute( 'y' ) ) ) ) ) {
|
|
|
|
|
|
return null;
|
|
return null;
|
|
|
|
|
|
@@ -1092,144 +1116,158 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
|
|
|
|
|
|
function parseNodeTransform( node ) {
|
|
function parseNodeTransform( node ) {
|
|
|
|
|
|
- var transform = new THREE.Matrix3();
|
|
|
|
|
|
+ var transform = new Matrix3();
|
|
var currentTransform = tempTransform0;
|
|
var currentTransform = tempTransform0;
|
|
- var transformsTexts = node.getAttribute( 'transform' ).split( ')' );
|
|
|
|
|
|
|
|
- for ( var tIndex = transformsTexts.length - 1; tIndex >= 0; tIndex -- ) {
|
|
|
|
|
|
+ if ( node.nodeName == 'use' && ( node.hasAttribute( 'x' ) || node.hasAttribute( 'y' ) ) ) {
|
|
|
|
|
|
- var transformText = transformsTexts[ tIndex ].trim();
|
|
|
|
|
|
+ var tx = parseFloatWithUnits( node.getAttribute( 'x' ) );
|
|
|
|
+ var ty = parseFloatWithUnits( node.getAttribute( 'y' ) );
|
|
|
|
|
|
- if ( transformText === '' ) continue;
|
|
|
|
|
|
+ transform.translate( tx, ty );
|
|
|
|
|
|
- var openParPos = transformText.indexOf( '(' );
|
|
|
|
- var closeParPos = transformText.length;
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- if ( openParPos > 0 && openParPos < closeParPos ) {
|
|
|
|
|
|
+ if ( node.hasAttribute( 'transform' ) ) {
|
|
|
|
|
|
- var transformType = transformText.substr( 0, openParPos );
|
|
|
|
|
|
+ var transformsTexts = node.getAttribute( 'transform' ).split( ')' );
|
|
|
|
|
|
- var array = parseFloats( transformText.substr( openParPos + 1, closeParPos - openParPos - 1 ) );
|
|
|
|
|
|
+ for ( var tIndex = transformsTexts.length - 1; tIndex >= 0; tIndex -- ) {
|
|
|
|
|
|
- currentTransform.identity();
|
|
|
|
|
|
+ var transformText = transformsTexts[ tIndex ].trim();
|
|
|
|
+
|
|
|
|
+ if ( transformText === '' ) continue;
|
|
|
|
+
|
|
|
|
+ var openParPos = transformText.indexOf( '(' );
|
|
|
|
+ var closeParPos = transformText.length;
|
|
|
|
+
|
|
|
|
+ if ( openParPos > 0 && openParPos < closeParPos ) {
|
|
|
|
|
|
- switch ( transformType ) {
|
|
|
|
|
|
+ var transformType = transformText.substr( 0, openParPos );
|
|
|
|
|
|
- case "translate":
|
|
|
|
|
|
+ var array = parseFloats( transformText.substr( openParPos + 1, closeParPos - openParPos - 1 ) );
|
|
|
|
|
|
- if ( array.length >= 1 ) {
|
|
|
|
|
|
+ currentTransform.identity();
|
|
|
|
|
|
- var tx = array[ 0 ];
|
|
|
|
- var ty = tx;
|
|
|
|
|
|
+ switch ( transformType ) {
|
|
|
|
|
|
- if ( array.length >= 2 ) {
|
|
|
|
|
|
+ case "translate":
|
|
|
|
|
|
- ty = array[ 1 ];
|
|
|
|
|
|
+ if ( array.length >= 1 ) {
|
|
|
|
+
|
|
|
|
+ var tx = array[ 0 ];
|
|
|
|
+ var ty = tx;
|
|
|
|
+
|
|
|
|
+ if ( array.length >= 2 ) {
|
|
|
|
+
|
|
|
|
+ ty = array[ 1 ];
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ currentTransform.translate( tx, ty );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- currentTransform.translate( tx, ty );
|
|
|
|
|
|
+ break;
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ case "rotate":
|
|
|
|
|
|
- break;
|
|
|
|
|
|
+ if ( array.length >= 1 ) {
|
|
|
|
|
|
- case "rotate":
|
|
|
|
|
|
+ var angle = 0;
|
|
|
|
+ var cx = 0;
|
|
|
|
+ var cy = 0;
|
|
|
|
|
|
- if ( array.length >= 1 ) {
|
|
|
|
|
|
+ // Angle
|
|
|
|
+ angle = - array[ 0 ] * Math.PI / 180;
|
|
|
|
|
|
- var angle = 0;
|
|
|
|
- var cx = 0;
|
|
|
|
- var cy = 0;
|
|
|
|
|
|
+ if ( array.length >= 3 ) {
|
|
|
|
|
|
- // Angle
|
|
|
|
- angle = - array[ 0 ] * Math.PI / 180;
|
|
|
|
|
|
+ // Center x, y
|
|
|
|
+ cx = array[ 1 ];
|
|
|
|
+ cy = array[ 2 ];
|
|
|
|
|
|
- if ( array.length >= 3 ) {
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- // Center x, y
|
|
|
|
- cx = array[ 1 ];
|
|
|
|
- cy = array[ 2 ];
|
|
|
|
|
|
+ // Rotate around center (cx, cy)
|
|
|
|
+ tempTransform1.identity().translate( - cx, - cy );
|
|
|
|
+ tempTransform2.identity().rotate( angle );
|
|
|
|
+ tempTransform3.multiplyMatrices( tempTransform2, tempTransform1 );
|
|
|
|
+ tempTransform1.identity().translate( cx, cy );
|
|
|
|
+ currentTransform.multiplyMatrices( tempTransform1, tempTransform3 );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- // Rotate around center (cx, cy)
|
|
|
|
- tempTransform1.identity().translate( - cx, - cy );
|
|
|
|
- tempTransform2.identity().rotate( angle );
|
|
|
|
- tempTransform3.multiplyMatrices( tempTransform2, tempTransform1 );
|
|
|
|
- tempTransform1.identity().translate( cx, cy );
|
|
|
|
- currentTransform.multiplyMatrices( tempTransform1, tempTransform3 );
|
|
|
|
|
|
+ break;
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ case "scale":
|
|
|
|
|
|
- break;
|
|
|
|
|
|
+ if ( array.length >= 1 ) {
|
|
|
|
|
|
- case "scale":
|
|
|
|
|
|
+ var scaleX = array[ 0 ];
|
|
|
|
+ var scaleY = scaleX;
|
|
|
|
|
|
- if ( array.length >= 1 ) {
|
|
|
|
|
|
+ if ( array.length >= 2 ) {
|
|
|
|
|
|
- var scaleX = array[ 0 ];
|
|
|
|
- var scaleY = scaleX;
|
|
|
|
|
|
+ scaleY = array[ 1 ];
|
|
|
|
|
|
- if ( array.length >= 2 ) {
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- scaleY = array[ 1 ];
|
|
|
|
|
|
+ currentTransform.scale( scaleX, scaleY );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- currentTransform.scale( scaleX, scaleY );
|
|
|
|
|
|
+ break;
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ case "skewX":
|
|
|
|
|
|
- break;
|
|
|
|
|
|
+ if ( array.length === 1 ) {
|
|
|
|
|
|
- case "skewX":
|
|
|
|
|
|
+ currentTransform.set(
|
|
|
|
+ 1, Math.tan( array[ 0 ] * Math.PI / 180 ), 0,
|
|
|
|
+ 0, 1, 0,
|
|
|
|
+ 0, 0, 1
|
|
|
|
+ );
|
|
|
|
|
|
- if ( array.length === 1 ) {
|
|
|
|
-
|
|
|
|
- currentTransform.set(
|
|
|
|
- 1, Math.tan( array[ 0 ] * Math.PI / 180 ), 0,
|
|
|
|
- 0, 1, 0,
|
|
|
|
- 0, 0, 1
|
|
|
|
- );
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ break;
|
|
|
|
|
|
- break;
|
|
|
|
|
|
+ case "skewY":
|
|
|
|
|
|
- case "skewY":
|
|
|
|
|
|
+ if ( array.length === 1 ) {
|
|
|
|
|
|
- if ( array.length === 1 ) {
|
|
|
|
|
|
+ currentTransform.set(
|
|
|
|
+ 1, 0, 0,
|
|
|
|
+ Math.tan( array[ 0 ] * Math.PI / 180 ), 1, 0,
|
|
|
|
+ 0, 0, 1
|
|
|
|
+ );
|
|
|
|
|
|
- currentTransform.set(
|
|
|
|
- 1, 0, 0,
|
|
|
|
- Math.tan( array[ 0 ] * Math.PI / 180 ), 1, 0,
|
|
|
|
- 0, 0, 1
|
|
|
|
- );
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ break;
|
|
|
|
|
|
- break;
|
|
|
|
|
|
+ case "matrix":
|
|
|
|
|
|
- case "matrix":
|
|
|
|
|
|
+ if ( array.length === 6 ) {
|
|
|
|
|
|
- if ( array.length === 6 ) {
|
|
|
|
|
|
+ currentTransform.set(
|
|
|
|
+ array[ 0 ], array[ 2 ], array[ 4 ],
|
|
|
|
+ array[ 1 ], array[ 3 ], array[ 5 ],
|
|
|
|
+ 0, 0, 1
|
|
|
|
+ );
|
|
|
|
|
|
- currentTransform.set(
|
|
|
|
- array[ 0 ], array[ 2 ], array[ 4 ],
|
|
|
|
- array[ 1 ], array[ 3 ], array[ 5 ],
|
|
|
|
- 0, 0, 1
|
|
|
|
- );
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ break;
|
|
|
|
|
|
- break;
|
|
|
|
|
|
+ }
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ transform.premultiply( currentTransform );
|
|
|
|
|
|
- transform.premultiply( currentTransform );
|
|
|
|
|
|
+ }
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|