@@ -124,11 +124,130 @@ function linkModel(d, l, i) {
124124 } ;
125125}
126126
127+ function createCircularClosedPathString ( link ) {
128+ // Using coordinates computed by d3-sankey-circular
129+ var pathString = '' ;
130+ var offset = link . width / 2 ;
131+ var coords = link . circularPathData ;
132+ if ( link . circularLinkType === 'top' ) {
133+ // Top path
134+ pathString =
135+ // start at the left of the target node
136+ 'M ' +
137+ coords . targetX + ' ' + ( coords . targetY + offset ) + ' ' +
138+ 'L' +
139+ coords . rightInnerExtent + ' ' + ( coords . targetY + offset ) +
140+ 'A' +
141+ ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightSmallArcRadius + offset ) + ' 0 0 1 ' +
142+ ( coords . rightFullExtent - offset ) + ' ' + ( coords . targetY - coords . rightSmallArcRadius ) +
143+ 'L' +
144+ ( coords . rightFullExtent - offset ) + ' ' + coords . verticalRightInnerExtent +
145+ 'A' +
146+ ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightLargeArcRadius + offset ) + ' 0 0 1 ' +
147+ coords . rightInnerExtent + ' ' + ( coords . verticalFullExtent - offset ) +
148+ 'L' +
149+ coords . leftInnerExtent + ' ' + ( coords . verticalFullExtent - offset ) +
150+ 'A' +
151+ ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftLargeArcRadius + offset ) + ' 0 0 1 ' +
152+ ( coords . leftFullExtent + offset ) + ' ' + coords . verticalLeftInnerExtent +
153+ 'L' +
154+ ( coords . leftFullExtent + offset ) + ' ' + ( coords . sourceY - coords . leftSmallArcRadius ) +
155+ 'A' +
156+ ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftSmallArcRadius + offset ) + ' 0 0 1 ' +
157+ coords . leftInnerExtent + ' ' + ( coords . sourceY + offset ) +
158+ 'L' +
159+ coords . sourceX + ' ' + ( coords . sourceY + offset ) +
160+
161+ // Walking back
162+ 'L' +
163+ coords . sourceX + ' ' + ( coords . sourceY - offset ) +
164+ 'L' +
165+ coords . leftInnerExtent + ' ' + ( coords . sourceY - offset ) +
166+ 'A' +
167+ ( coords . leftLargeArcRadius - offset ) + ' ' + ( coords . leftSmallArcRadius - offset ) + ' 0 0 0 ' +
168+ ( coords . leftFullExtent - offset ) + ' ' + ( coords . sourceY - coords . leftSmallArcRadius ) +
169+ 'L' +
170+ ( coords . leftFullExtent - offset ) + ' ' + coords . verticalLeftInnerExtent +
171+ 'A' +
172+ ( coords . leftLargeArcRadius - offset ) + ' ' + ( coords . leftLargeArcRadius - offset ) + ' 0 0 0 ' +
173+ coords . leftInnerExtent + ' ' + ( coords . verticalFullExtent + offset ) +
174+ 'L' +
175+ coords . rightInnerExtent + ' ' + ( coords . verticalFullExtent + offset ) +
176+ 'A' +
177+ ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightLargeArcRadius - offset ) + ' 0 0 0 ' +
178+ ( coords . rightFullExtent + offset ) + ' ' + coords . verticalRightInnerExtent +
179+ 'L' +
180+ ( coords . rightFullExtent + offset ) + ' ' + ( coords . targetY - coords . rightSmallArcRadius ) +
181+ 'A' +
182+ ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightSmallArcRadius - offset ) + ' 0 0 0 ' +
183+ coords . rightInnerExtent + ' ' + ( coords . targetY - offset ) +
184+ 'L' +
185+ coords . targetX + ' ' + ( coords . targetY - offset ) +
186+ 'Z' ;
187+ } else {
188+ // Bottom path
189+ pathString =
190+ // start at the left of the target node
191+ 'M ' +
192+ coords . targetX + ' ' + ( coords . targetY - offset ) + ' ' +
193+ 'L' +
194+ coords . rightInnerExtent + ' ' + ( coords . targetY - offset ) +
195+ 'A' +
196+ ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightSmallArcRadius + offset ) + ' 0 0 0 ' +
197+ ( coords . rightFullExtent - offset ) + ' ' + ( coords . targetY + coords . rightSmallArcRadius ) +
198+ 'L' +
199+ ( coords . rightFullExtent - offset ) + ' ' + coords . verticalRightInnerExtent +
200+ 'A' +
201+ ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightLargeArcRadius + offset ) + ' 0 0 0 ' +
202+ coords . rightInnerExtent + ' ' + ( coords . verticalFullExtent + offset ) +
203+ 'L' +
204+ coords . leftInnerExtent + ' ' + ( coords . verticalFullExtent + offset ) +
205+ 'A' +
206+ ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftLargeArcRadius + offset ) + ' 0 0 0 ' +
207+ ( coords . leftFullExtent + offset ) + ' ' + coords . verticalLeftInnerExtent +
208+ 'L' +
209+ ( coords . leftFullExtent + offset ) + ' ' + ( coords . sourceY + coords . leftSmallArcRadius ) +
210+ 'A' +
211+ ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftSmallArcRadius + offset ) + ' 0 0 0 ' +
212+ coords . leftInnerExtent + ' ' + ( coords . sourceY - offset ) +
213+ 'L' +
214+ coords . sourceX + ' ' + ( coords . sourceY - offset ) +
215+
216+ // Walking back
217+ 'L' +
218+ coords . sourceX + ' ' + ( coords . sourceY + offset ) +
219+ 'L' +
220+ coords . leftInnerExtent + ' ' + ( coords . sourceY + offset ) +
221+ 'A' +
222+ ( coords . leftLargeArcRadius - offset ) + ' ' + ( coords . leftSmallArcRadius - offset ) + ' 0 0 1 ' +
223+ ( coords . leftFullExtent - offset ) + ' ' + ( coords . sourceY + coords . leftSmallArcRadius ) +
224+ 'L' +
225+ ( coords . leftFullExtent - offset ) + ' ' + coords . verticalLeftInnerExtent +
226+ 'A' +
227+ ( coords . leftLargeArcRadius - offset ) + ' ' + ( coords . leftLargeArcRadius - offset ) + ' 0 0 1 ' +
228+ coords . leftInnerExtent + ' ' + ( coords . verticalFullExtent - offset ) +
229+ 'L' +
230+ coords . rightInnerExtent + ' ' + ( coords . verticalFullExtent - offset ) +
231+ 'A' +
232+ ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightLargeArcRadius - offset ) + ' 0 0 1 ' +
233+ ( coords . rightFullExtent + offset ) + ' ' + coords . verticalRightInnerExtent +
234+ 'L' +
235+ ( coords . rightFullExtent + offset ) + ' ' + ( coords . targetY + coords . rightSmallArcRadius ) +
236+ 'A' +
237+ ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightSmallArcRadius - offset ) + ' 0 0 1 ' +
238+ coords . rightInnerExtent + ' ' + ( coords . targetY + offset ) +
239+ 'L' +
240+ coords . targetX + ' ' + ( coords . targetY + offset ) +
241+ 'Z' ;
242+ }
243+ return pathString ;
244+ }
245+
127246function linkPath ( ) {
128247 var curvature = 0.5 ;
129248 function path ( d ) {
130- if ( d . circular ) {
131- return d . link . path ; // TODO: turn this into a closed path to support link.line.(width|color)
249+ if ( d . link . circular ) {
250+ return createCircularClosedPathString ( d . link ) ;
132251 } else {
133252 var x0 = d . link . source . x1 ;
134253 var x1 = d . link . target . x0 ;
@@ -502,21 +621,18 @@ module.exports = function(svg, calcData, layout, callbacks) {
502621
503622 sankeyLink
504623 . style ( 'stroke' , function ( d ) {
505- if ( ! d . circular ) return salientEnough ( d ) ? Color . tinyRGB ( tinycolor ( d . linkLineColor ) ) : d . tinyColorHue ;
506- return d . tinyColorHue ;
624+ return salientEnough ( d ) ? Color . tinyRGB ( tinycolor ( d . linkLineColor ) ) : d . tinyColorHue ;
507625 } )
508626 . style ( 'stroke-opacity' , function ( d ) {
509- if ( ! d . circular ) return salientEnough ( d ) ? Color . opacity ( d . linkLineColor ) : d . tinyColorAlpha ;
510- return d . tinyColorAlpha ;
627+ return salientEnough ( d ) ? Color . opacity ( d . linkLineColor ) : d . tinyColorAlpha ;
511628 } )
512629 . style ( 'fill' , function ( d ) {
513- if ( ! d . circular ) return d . tinyColorHue ;
630+ return d . tinyColorHue ;
514631 } )
515632 . style ( 'fill-opacity' , function ( d ) {
516- if ( ! d . circular ) return d . tinyColorAlpha ;
633+ return d . tinyColorAlpha ;
517634 } )
518635 . style ( 'stroke-width' , function ( d ) {
519- if ( d . circular ) return d . link . width ;
520636 return salientEnough ( d ) ? d . linkLineWidth : 1 ;
521637 } ) ;
522638
0 commit comments