@@ -3,52 +3,68 @@ const pi = Math.PI,
33 epsilon = 1e-6 ,
44 tauEpsilon = tau - epsilon ;
55
6- function Path ( ) {
7- this . _x0 = this . _y0 = // start of current subpath
8- this . _x1 = this . _y1 = null ; // end of current subpath
9- this . _ = "" ;
6+ function append ( strings ) {
7+ this . _ += strings [ 0 ] ;
8+ for ( let i = 1 , n = strings . length ; i < n ; ++ i ) {
9+ this . _ += arguments [ i ] + strings [ i ] ;
10+ }
1011}
1112
12- function path ( ) {
13- return new Path ;
13+ function appendRound ( digits ) {
14+ let d = Math . floor ( digits ) ;
15+ if ( ! ( d >= 0 ) ) throw new Error ( `invalid digits: ${ digits } ` ) ;
16+ if ( d > 15 ) return append ;
17+ const k = 10 ** d ;
18+ return function ( strings ) {
19+ this . _ += strings [ 0 ] ;
20+ for ( let i = 1 , n = strings . length ; i < n ; ++ i ) {
21+ this . _ += Math . round ( arguments [ i ] * k ) / k + strings [ i ] ;
22+ }
23+ } ;
1424}
1525
16- Path . prototype = path . prototype = {
17- constructor : Path ,
18- moveTo : function ( x , y ) {
19- this . _ += "M" + ( this . _x0 = this . _x1 = + x ) + "," + ( this . _y0 = this . _y1 = + y ) ;
20- } ,
21- closePath : function ( ) {
26+ export class Path {
27+ constructor ( digits ) {
28+ this . _x0 = this . _y0 = // start of current subpath
29+ this . _x1 = this . _y1 = null ; // end of current subpath
30+ this . _ = "" ;
31+ this . _append = digits == null ? append : appendRound ( digits ) ;
32+ }
33+ moveTo ( x , y ) {
34+ this . _append `M${ this . _x0 = this . _x1 = + x } ,${ this . _y0 = this . _y1 = + y } ` ;
35+ }
36+ closePath ( ) {
2237 if ( this . _x1 !== null ) {
2338 this . _x1 = this . _x0 , this . _y1 = this . _y0 ;
24- this . _ += "Z" ;
39+ this . _append `Z` ;
2540 }
26- } ,
27- lineTo : function ( x , y ) {
28- this . _ += "L" + ( this . _x1 = + x ) + "," + ( this . _y1 = + y ) ;
29- } ,
30- quadraticCurveTo : function ( x1 , y1 , x , y ) {
31- this . _ += "Q" + ( + x1 ) + "," + ( + y1 ) + "," + ( this . _x1 = + x ) + "," + ( this . _y1 = + y ) ;
32- } ,
33- bezierCurveTo : function ( x1 , y1 , x2 , y2 , x , y ) {
34- this . _ += "C" + ( + x1 ) + "," + ( + y1 ) + "," + ( + x2 ) + "," + ( + y2 ) + "," + ( this . _x1 = + x ) + "," + ( this . _y1 = + y ) ;
35- } ,
36- arcTo : function ( x1 , y1 , x2 , y2 , r ) {
41+ }
42+ lineTo ( x , y ) {
43+ this . _append `L ${ this . _x1 = + x } , ${ this . _y1 = + y } ` ;
44+ }
45+ quadraticCurveTo ( x1 , y1 , x , y ) {
46+ this . _append `Q ${ + x1 } , ${ + y1 } , ${ this . _x1 = + x } , ${ this . _y1 = + y } ` ;
47+ }
48+ bezierCurveTo ( x1 , y1 , x2 , y2 , x , y ) {
49+ this . _append `C ${ + x1 } , ${ + y1 } , ${ + x2 } , ${ + y2 } , ${ this . _x1 = + x } , ${ this . _y1 = + y } ` ;
50+ }
51+ arcTo ( x1 , y1 , x2 , y2 , r ) {
3752 x1 = + x1 , y1 = + y1 , x2 = + x2 , y2 = + y2 , r = + r ;
38- var x0 = this . _x1 ,
53+
54+ // Is the radius negative? Error.
55+ if ( r < 0 ) throw new Error ( `negative radius: ${ r } ` ) ;
56+
57+ let x0 = this . _x1 ,
3958 y0 = this . _y1 ,
4059 x21 = x2 - x1 ,
4160 y21 = y2 - y1 ,
4261 x01 = x0 - x1 ,
4362 y01 = y0 - y1 ,
4463 l01_2 = x01 * x01 + y01 * y01 ;
4564
46- // Is the radius negative? Error.
47- if ( r < 0 ) throw new Error ( "negative radius: " + r ) ;
48-
4965 // Is this path empty? Move to (x1,y1).
5066 if ( this . _x1 === null ) {
51- this . _ += "M" + ( this . _x1 = x1 ) + "," + ( this . _y1 = y1 ) ;
67+ this . _append `M ${ this . _x1 = x1 } , ${ this . _y1 = y1 } ` ;
5268 }
5369
5470 // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.
@@ -58,12 +74,12 @@ Path.prototype = path.prototype = {
5874 // Equivalently, is (x1,y1) coincident with (x2,y2)?
5975 // Or, is the radius zero? Line to (x1,y1).
6076 else if ( ! ( Math . abs ( y01 * x21 - y21 * x01 ) > epsilon ) || ! r ) {
61- this . _ += "L" + ( this . _x1 = x1 ) + "," + ( this . _y1 = y1 ) ;
77+ this . _append `L ${ this . _x1 = x1 } , ${ this . _y1 = y1 } ` ;
6278 }
6379
6480 // Otherwise, draw an arc!
6581 else {
66- var x20 = x2 - x0 ,
82+ let x20 = x2 - x0 ,
6783 y20 = y2 - y0 ,
6884 l21_2 = x21 * x21 + y21 * y21 ,
6985 l20_2 = x20 * x20 + y20 * y20 ,
@@ -75,32 +91,33 @@ Path.prototype = path.prototype = {
7591
7692 // If the start tangent is not coincident with (x0,y0), line to.
7793 if ( Math . abs ( t01 - 1 ) > epsilon ) {
78- this . _ += "L" + ( x1 + t01 * x01 ) + "," + ( y1 + t01 * y01 ) ;
94+ this . _append `L ${ x1 + t01 * x01 } , ${ y1 + t01 * y01 } ` ;
7995 }
8096
81- this . _ += "A" + r + "," + r + " ,0,0," + ( + ( y01 * x20 > x01 * y20 ) ) + "," + ( this . _x1 = x1 + t21 * x21 ) + "," + ( this . _y1 = y1 + t21 * y21 ) ;
97+ this . _append `A ${ r } , ${ r } ,0,0,${ + ( y01 * x20 > x01 * y20 ) } , ${ this . _x1 = x1 + t21 * x21 } , ${ this . _y1 = y1 + t21 * y21 } ` ;
8298 }
83- } ,
84- arc : function ( x , y , r , a0 , a1 , ccw ) {
99+ }
100+ arc ( x , y , r , a0 , a1 , ccw ) {
85101 x = + x , y = + y , r = + r , ccw = ! ! ccw ;
86- var dx = r * Math . cos ( a0 ) ,
102+
103+ // Is the radius negative? Error.
104+ if ( r < 0 ) throw new Error ( `negative radius: ${ r } ` ) ;
105+
106+ let dx = r * Math . cos ( a0 ) ,
87107 dy = r * Math . sin ( a0 ) ,
88108 x0 = x + dx ,
89109 y0 = y + dy ,
90110 cw = 1 ^ ccw ,
91111 da = ccw ? a0 - a1 : a1 - a0 ;
92112
93- // Is the radius negative? Error.
94- if ( r < 0 ) throw new Error ( "negative radius: " + r ) ;
95-
96113 // Is this path empty? Move to (x0,y0).
97114 if ( this . _x1 === null ) {
98- this . _ += "M" + x0 + "," + y0 ;
115+ this . _append `M ${ x0 } , ${ y0 } ` ;
99116 }
100117
101118 // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).
102119 else if ( Math . abs ( this . _x1 - x0 ) > epsilon || Math . abs ( this . _y1 - y0 ) > epsilon ) {
103- this . _ += "L" + x0 + "," + y0 ;
120+ this . _append `L ${ x0 } , ${ y0 } ` ;
104121 }
105122
106123 // Is this arc empty? We’re done.
@@ -111,20 +128,29 @@ Path.prototype = path.prototype = {
111128
112129 // Is this a complete circle? Draw two arcs to complete the circle.
113130 if ( da > tauEpsilon ) {
114- this . _ += "A" + r + "," + r + " ,0,1," + cw + "," + ( x - dx ) + "," + ( y - dy ) + "A" + r + "," + r + " ,0,1," + cw + "," + ( this . _x1 = x0 ) + "," + ( this . _y1 = y0 ) ;
131+ this . _append `A ${ r } , ${ r } ,0,1,${ cw } , ${ x - dx } , ${ y - dy } A ${ r } , ${ r } ,0,1,${ cw } , ${ this . _x1 = x0 } , ${ this . _y1 = y0 } ` ;
115132 }
116133
117134 // Is this arc non-empty? Draw an arc!
118135 else if ( da > epsilon ) {
119- this . _ += "A" + r + "," + r + " ,0," + ( + ( da >= pi ) ) + "," + cw + "," + ( this . _x1 = x + r * Math . cos ( a1 ) ) + "," + ( this . _y1 = y + r * Math . sin ( a1 ) ) ;
136+ this . _append `A ${ r } , ${ r } ,0,${ + ( da >= pi ) } , ${ cw } , ${ this . _x1 = x + r * Math . cos ( a1 ) } , ${ this . _y1 = y + r * Math . sin ( a1 ) } ` ;
120137 }
121- } ,
122- rect : function ( x , y , w , h ) {
123- this . _ += "M" + ( this . _x0 = this . _x1 = + x ) + "," + ( this . _y0 = this . _y1 = + y ) + "h" + ( + w ) + "v" + ( + h ) + "h" + ( - w ) + "Z" ;
124- } ,
125- toString : function ( ) {
138+ }
139+ rect ( x , y , w , h ) {
140+ this . _append `M ${ this . _x0 = this . _x1 = + x } , ${ this . _y0 = this . _y1 = + y } h ${ w = + w } v ${ + h } h ${ - w } Z` ;
141+ }
142+ toString ( ) {
126143 return this . _ ;
127144 }
128- } ;
145+ }
129146
130- export default path ;
147+ export function path ( ) {
148+ return new Path ;
149+ }
150+
151+ // Allow instanceof d3.path
152+ path . prototype = Path . prototype ;
153+
154+ export function pathRound ( digits = 3 ) {
155+ return new Path ( + digits ) ;
156+ }
0 commit comments