|
@@ -44,9 +44,9 @@ THREE.SVGRenderer = function () {
|
|
_viewMatrix = new THREE.Matrix4(),
|
|
_viewMatrix = new THREE.Matrix4(),
|
|
_viewProjectionMatrix = new THREE.Matrix4(),
|
|
_viewProjectionMatrix = new THREE.Matrix4(),
|
|
|
|
|
|
- _svgPathPool = [], _svgLinePool = [], _svgRectPool = [],
|
|
|
|
- _svgNode, _pathCount = 0, _lineCount = 0, _rectCount = 0,
|
|
|
|
- _quality = 1;
|
|
|
|
|
|
+ _svgPathPool = [],
|
|
|
|
+ _svgNode, _pathCount = 0, _currPath, _currStyle,
|
|
|
|
+ _quality = 1, _precision = null;
|
|
|
|
|
|
this.domElement = _svg;
|
|
this.domElement = _svg;
|
|
|
|
|
|
@@ -104,11 +104,15 @@ THREE.SVGRenderer = function () {
|
|
|
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+ this.setPrecision = function ( precision ) {
|
|
|
|
+
|
|
|
|
+ _precision = precision;
|
|
|
|
+
|
|
|
|
+ };
|
|
|
|
+
|
|
function removeChildNodes() {
|
|
function removeChildNodes() {
|
|
|
|
|
|
_pathCount = 0;
|
|
_pathCount = 0;
|
|
- _lineCount = 0;
|
|
|
|
- _rectCount = 0;
|
|
|
|
|
|
|
|
while ( _svg.childNodes.length > 0 ) {
|
|
while ( _svg.childNodes.length > 0 ) {
|
|
|
|
|
|
@@ -118,10 +122,26 @@ THREE.SVGRenderer = function () {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ function getSvgColor ( color, opacity ) {
|
|
|
|
+
|
|
|
|
+ var arg = Math.floor( color.r * 255 ) + ',' + Math.floor( color.g * 255 ) + ',' + Math.floor( color.b * 255 );
|
|
|
|
+
|
|
|
|
+ if ( opacity === undefined || opacity === 1 ) return 'rgb(' + arg + ')';
|
|
|
|
+
|
|
|
|
+ return 'rgba(' + arg + ',' + opacity + ')';
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ function convert ( c ) {
|
|
|
|
+
|
|
|
|
+ return _precision !== null ? c.toFixed(_precision) : c;
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
this.clear = function () {
|
|
this.clear = function () {
|
|
|
|
|
|
removeChildNodes();
|
|
removeChildNodes();
|
|
- _svg.style.backgroundColor = 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')';
|
|
|
|
|
|
+ _svg.style.backgroundColor = getSvgColor( _clearColor, _clearAlpha );
|
|
|
|
|
|
};
|
|
};
|
|
|
|
|
|
@@ -139,7 +159,7 @@ THREE.SVGRenderer = function () {
|
|
if ( background && background.isColor ) {
|
|
if ( background && background.isColor ) {
|
|
|
|
|
|
removeChildNodes();
|
|
removeChildNodes();
|
|
- _svg.style.backgroundColor = 'rgb(' + Math.floor( background.r * 255 ) + ',' + Math.floor( background.g * 255 ) + ',' + Math.floor( background.b * 255 ) + ')';
|
|
|
|
|
|
+ _svg.style.backgroundColor = getSvgColor( background );
|
|
|
|
|
|
} else if ( this.autoClear === true ) {
|
|
} else if ( this.autoClear === true ) {
|
|
|
|
|
|
@@ -160,6 +180,7 @@ THREE.SVGRenderer = function () {
|
|
_normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );
|
|
_normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse );
|
|
|
|
|
|
calculateLights( _lights );
|
|
calculateLights( _lights );
|
|
|
|
+ _currPath = _currStyle = ""; // reset accumulated path
|
|
|
|
|
|
for ( var e = 0, el = _elements.length; e < el; e ++ ) {
|
|
for ( var e = 0, el = _elements.length; e < el; e ++ ) {
|
|
|
|
|
|
@@ -220,6 +241,8 @@ THREE.SVGRenderer = function () {
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ flushPath(); // just to flush last svg:path
|
|
|
|
+
|
|
scene.traverseVisible( function ( object ) {
|
|
scene.traverseVisible( function ( object ) {
|
|
|
|
|
|
if ( object instanceof THREE.SVGObject ) {
|
|
if ( object instanceof THREE.SVGObject ) {
|
|
@@ -331,37 +354,28 @@ THREE.SVGRenderer = function () {
|
|
scaleY *= material.size;
|
|
scaleY *= material.size;
|
|
}
|
|
}
|
|
|
|
|
|
- _svgNode = getRectNode( _rectCount ++ );
|
|
|
|
-
|
|
|
|
- _svgNode.setAttribute( 'x', v1.x - ( scaleX * 0.5 ) );
|
|
|
|
- _svgNode.setAttribute( 'y', v1.y - ( scaleY * 0.5 ) );
|
|
|
|
- _svgNode.setAttribute( 'width', scaleX );
|
|
|
|
- _svgNode.setAttribute( 'height', scaleY );
|
|
|
|
|
|
+ var path = 'M' + convert( v1.x - scaleX * 0.5 ) + ',' + convert( v1.y - scaleY * 0.5 ) + 'h' + convert( scaleX ) + 'v' + convert( scaleY ) + 'h' + convert(-scaleX) + 'z';
|
|
|
|
+ var style = "";
|
|
|
|
|
|
if ( material.isSpriteMaterial || material.isPointsMaterial ) {
|
|
if ( material.isSpriteMaterial || material.isPointsMaterial ) {
|
|
|
|
|
|
- _svgNode.setAttribute( 'style', 'fill: ' + material.color.getStyle() );
|
|
|
|
|
|
+ style = 'fill:' + getSvgColor( material.color, material.opacity );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- _svg.appendChild( _svgNode );
|
|
|
|
|
|
+ addPath( style, path );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
function renderLine( v1, v2, element, material ) {
|
|
function renderLine( v1, v2, element, material ) {
|
|
|
|
|
|
- _svgNode = getLineNode( _lineCount ++ );
|
|
|
|
-
|
|
|
|
- _svgNode.setAttribute( 'x1', v1.positionScreen.x );
|
|
|
|
- _svgNode.setAttribute( 'y1', v1.positionScreen.y );
|
|
|
|
- _svgNode.setAttribute( 'x2', v2.positionScreen.x );
|
|
|
|
- _svgNode.setAttribute( 'y2', v2.positionScreen.y );
|
|
|
|
|
|
+ var path = 'M' + convert( v1.positionScreen.x ) + ',' + convert( v1.positionScreen.y ) + 'L' + convert( v2.positionScreen.x ) + ',' + convert( v2.positionScreen.y );
|
|
|
|
|
|
if ( material instanceof THREE.LineBasicMaterial ) {
|
|
if ( material instanceof THREE.LineBasicMaterial ) {
|
|
|
|
|
|
- _svgNode.setAttribute( 'style', 'fill: none; stroke: ' + material.color.getStyle() + '; stroke-width: ' + material.linewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.linecap + '; stroke-linejoin: ' + material.linejoin );
|
|
|
|
|
|
+ var style = 'fill:none;stroke:' + getSvgColor( material.color, material.opacity ) + ';stroke-width:' + material.linewidth + ';stroke-linecap:' + material.linecap + ';stroke-linejoin:' + material.linejoin;
|
|
|
|
|
|
- _svg.appendChild( _svgNode );
|
|
|
|
|
|
+ addPath( style, path );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
@@ -372,8 +386,8 @@ THREE.SVGRenderer = function () {
|
|
_this.info.render.vertices += 3;
|
|
_this.info.render.vertices += 3;
|
|
_this.info.render.faces ++;
|
|
_this.info.render.faces ++;
|
|
|
|
|
|
- _svgNode = getPathNode( _pathCount ++ );
|
|
|
|
- _svgNode.setAttribute( 'd', 'M ' + v1.positionScreen.x + ' ' + v1.positionScreen.y + ' L ' + v2.positionScreen.x + ' ' + v2.positionScreen.y + ' L ' + v3.positionScreen.x + ',' + v3.positionScreen.y + 'z' );
|
|
|
|
|
|
+ var path = 'M' + convert( v1.positionScreen.x ) + ',' + convert( v1.positionScreen.y ) + 'L' + convert( v2.positionScreen.x ) + ',' + convert( v2.positionScreen.y ) + 'L' + convert( v3.positionScreen.x ) + ',' + convert( v3.positionScreen.y ) + 'z';
|
|
|
|
+ var style = '';
|
|
|
|
|
|
if ( material instanceof THREE.MeshBasicMaterial ) {
|
|
if ( material instanceof THREE.MeshBasicMaterial ) {
|
|
|
|
|
|
@@ -413,75 +427,66 @@ THREE.SVGRenderer = function () {
|
|
|
|
|
|
if ( material.wireframe ) {
|
|
if ( material.wireframe ) {
|
|
|
|
|
|
- _svgNode.setAttribute( 'style', 'fill: none; stroke: ' + _color.getStyle() + '; stroke-width: ' + material.wireframeLinewidth + '; stroke-opacity: ' + material.opacity + '; stroke-linecap: ' + material.wireframeLinecap + '; stroke-linejoin: ' + material.wireframeLinejoin );
|
|
|
|
|
|
+ style = 'fill:none;stroke:' + getSvgColor( _color, material.opacity ) + ';stroke-width:' + material.wireframeLinewidth + ';stroke-linecap:' + material.wireframeLinecap + ';stroke-linejoin:' + material.wireframeLinejoin;
|
|
|
|
|
|
} else {
|
|
} else {
|
|
|
|
|
|
- _svgNode.setAttribute( 'style', 'fill: ' + _color.getStyle() + '; fill-opacity: ' + material.opacity );
|
|
|
|
|
|
+ style = 'fill:' + getSvgColor( _color, material.opacity );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- _svg.appendChild( _svgNode );
|
|
|
|
|
|
+ addPath( style, path );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- function getLineNode( id ) {
|
|
|
|
-
|
|
|
|
- if ( _svgLinePool[ id ] == null ) {
|
|
|
|
|
|
+ function addPath ( style, path ) {
|
|
|
|
|
|
- _svgLinePool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'line' );
|
|
|
|
|
|
+ if ( _currStyle == style ) {
|
|
|
|
|
|
- if ( _quality == 0 ) {
|
|
|
|
|
|
+ _currPath += path
|
|
|
|
|
|
- _svgLinePool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
|
|
|
|
|
|
+ } else {
|
|
|
|
|
|
- }
|
|
|
|
|
|
+ flushPath();
|
|
|
|
|
|
- return _svgLinePool[ id ];
|
|
|
|
|
|
+ _currStyle = style;
|
|
|
|
+ _currPath = path;
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- return _svgLinePool[ id ];
|
|
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- function getPathNode( id ) {
|
|
|
|
-
|
|
|
|
- if ( _svgPathPool[ id ] == null ) {
|
|
|
|
-
|
|
|
|
- _svgPathPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
|
|
|
|
|
|
+ function flushPath() {
|
|
|
|
|
|
- if ( _quality == 0 ) {
|
|
|
|
-
|
|
|
|
- _svgPathPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
|
|
+ if ( _currPath ) {
|
|
|
|
|
|
- return _svgPathPool[ id ];
|
|
|
|
|
|
+ _svgNode = getPathNode( _pathCount ++ );
|
|
|
|
+ _svgNode.setAttribute( 'd', _currPath );
|
|
|
|
+ _svgNode.setAttribute( 'style', _currStyle );
|
|
|
|
+ _svg.appendChild( _svgNode );
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- return _svgPathPool[ id ];
|
|
|
|
-
|
|
|
|
|
|
+ _currPath = _currStyle = "";
|
|
}
|
|
}
|
|
|
|
|
|
- function getRectNode( id ) {
|
|
|
|
|
|
+ function getPathNode( id ) {
|
|
|
|
|
|
- if ( _svgRectPool[ id ] == null ) {
|
|
|
|
|
|
+ if ( _svgPathPool[ id ] == null ) {
|
|
|
|
|
|
- _svgRectPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'rect' );
|
|
|
|
|
|
+ _svgPathPool[ id ] = document.createElementNS( 'http://www.w3.org/2000/svg', 'path' );
|
|
|
|
|
|
if ( _quality == 0 ) {
|
|
if ( _quality == 0 ) {
|
|
|
|
|
|
- _svgRectPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
|
|
|
|
|
|
+ _svgPathPool[ id ].setAttribute( 'shape-rendering', 'crispEdges' ); //optimizeSpeed
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- return _svgRectPool[ id ];
|
|
|
|
|
|
+ return _svgPathPool[ id ];
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
- return _svgRectPool[ id ];
|
|
|
|
|
|
+ return _svgPathPool[ id ];
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|