@@ -335,118 +335,165 @@ function createCircularClosedPathString(link, arrowLen) {
335335 var pathString = '' ;
336336 var offset = link . width / 2 ;
337337 var coords = link . circularPathData ;
338- if ( link . circularLinkType === 'top' ) {
339- // Top path
338+ var isSourceBeforeTarget = coords . sourceX + coords . verticalBuffer < coords . targetX ;
339+ var isPathOverlapped = ( coords . rightFullExtent - coords . rightLargeArcRadius - arrowLen ) <= ( coords . leftFullExtent - offset )
340+ var diff = Math . abs ( coords . rightFullExtent - coords . leftFullExtent - offset ) < offset ;
341+ if ( link . circularLinkType === 'top' ) {
340342 pathString =
341- // start at the left of the target node
342- 'M ' +
343- ( coords . targetX - arrowLen ) + ' ' + ( coords . targetY + offset ) + ' ' +
344- 'L' +
345- ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . targetY + offset ) +
346- 'A' +
347- ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightSmallArcRadius + offset ) + ' 0 0 1 ' +
348- ( coords . rightFullExtent - offset - arrowLen ) + ' ' + ( coords . targetY - coords . rightSmallArcRadius ) +
349- 'L' +
350- ( coords . rightFullExtent - offset - arrowLen ) + ' ' + coords . verticalRightInnerExtent +
351- 'A' +
352- ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightLargeArcRadius + offset ) + ' 0 0 1 ' +
353- ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . verticalFullExtent - offset ) +
354- 'L' +
355- coords . leftInnerExtent + ' ' + ( coords . verticalFullExtent - offset ) +
356- 'A' +
357- ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftLargeArcRadius + offset ) + ' 0 0 1 ' +
358- ( coords . leftFullExtent + offset ) + ' ' + coords . verticalLeftInnerExtent +
359- 'L' +
360- ( coords . leftFullExtent + offset ) + ' ' + ( coords . sourceY - coords . leftSmallArcRadius ) +
361- 'A' +
362- ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftSmallArcRadius + offset ) + ' 0 0 1 ' +
363- coords . leftInnerExtent + ' ' + ( coords . sourceY + offset ) +
364- 'L' +
365- coords . sourceX + ' ' + ( coords . sourceY + offset ) +
366-
367- // Walking back
368- 'L' +
369- coords . sourceX + ' ' + ( coords . sourceY - offset ) +
370- 'L' +
371- coords . leftInnerExtent + ' ' + ( coords . sourceY - offset ) +
372- 'A' +
373- ( coords . leftLargeArcRadius - offset ) + ' ' + ( coords . leftSmallArcRadius - offset ) + ' 0 0 0 ' +
374- ( coords . leftFullExtent - offset ) + ' ' + ( coords . sourceY - coords . leftSmallArcRadius ) +
375- 'L' +
376- ( coords . leftFullExtent - offset ) + ' ' + coords . verticalLeftInnerExtent +
377- 'A' +
378- ( coords . leftLargeArcRadius - offset ) + ' ' + ( coords . leftLargeArcRadius - offset ) + ' 0 0 0 ' +
379- coords . leftInnerExtent + ' ' + ( coords . verticalFullExtent + offset ) +
380- 'L' +
381- ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . verticalFullExtent + offset ) +
382- 'A' +
383- ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightLargeArcRadius - offset ) + ' 0 0 0 ' +
384- ( coords . rightFullExtent + offset - arrowLen ) + ' ' + coords . verticalRightInnerExtent +
385- 'L' +
386- ( coords . rightFullExtent + offset - arrowLen ) + ' ' + ( coords . targetY - coords . rightSmallArcRadius ) +
387- 'A' +
388- ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightSmallArcRadius - offset ) + ' 0 0 0 ' +
389- ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . targetY - offset ) +
390- 'L' +
391- ( coords . targetX - arrowLen ) + ' ' + ( coords . targetY - offset ) +
392- ( arrowLen > 0 ? 'L' + coords . targetX + ' ' + ( coords . targetY ) : '' ) +
393- 'Z' ;
343+ // start at the left of the target node
344+ 'M ' +
345+ ( coords . targetX - arrowLen ) + ' ' + ( coords . targetY + offset ) + ' ' +
346+ 'L ' +
347+ ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . targetY + offset ) +
348+ 'A ' +
349+ ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightSmallArcRadius + offset ) + ' 0 0 1 ' +
350+ ( coords . rightFullExtent - offset - arrowLen ) + ' ' + ( coords . targetY - coords . rightSmallArcRadius ) +
351+ 'L ' + ( coords . rightFullExtent - offset - arrowLen ) + ' ' + coords . verticalRightInnerExtent ;
352+
353+ if ( isSourceBeforeTarget && isPathOverlapped ) {
354+ pathString += ' A ' +
355+ ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightLargeArcRadius + offset ) + ' 0 0 1 ' +
356+ ( coords . rightFullExtent + offset - arrowLen - ( coords . rightLargeArcRadius - offset ) ) + ' ' +
357+ ( coords . verticalRightInnerExtent - ( coords . rightLargeArcRadius + offset ) ) +
358+ ' L ' +
359+ ( coords . rightFullExtent + offset - ( coords . rightLargeArcRadius - offset ) - arrowLen ) + ' ' +
360+ ( coords . verticalRightInnerExtent - ( coords . rightLargeArcRadius + offset ) ) +
361+ ' A ' +
362+ ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftLargeArcRadius + offset ) + ' 0 0 1 ' +
363+ ( coords . leftFullExtent + offset ) + ' ' + coords . verticalRightInnerExtent ;
364+ } else if ( isSourceBeforeTarget ) {
365+ pathString += ' A ' +
366+ ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightLargeArcRadius - offset ) + ' 0 0 0 ' +
367+ ( coords . rightFullExtent - offset - arrowLen - ( coords . rightLargeArcRadius - offset ) ) + ' ' +
368+ ( coords . verticalRightInnerExtent - ( coords . rightLargeArcRadius - offset ) ) +
369+ ' L ' +
370+ ( coords . leftFullExtent + offset + ( coords . rightLargeArcRadius - offset ) ) + ' ' +
371+ ( coords . verticalRightInnerExtent - ( coords . rightLargeArcRadius - offset ) ) +
372+ ' A ' +
373+ ( coords . leftLargeArcRadius - offset ) + ' ' + ( coords . leftLargeArcRadius - offset ) + ' 0 0 0 ' +
374+ ( coords . leftFullExtent + offset ) + ' ' + coords . verticalLeftInnerExtent ;
375+ } else {
376+ pathString += ' A ' +
377+ ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightLargeArcRadius + offset ) + ' 0 0 1 ' +
378+ ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . verticalFullExtent - offset ) +
379+ ' L ' +
380+ coords . leftInnerExtent + ' ' + ( coords . verticalFullExtent - offset ) +
381+ ' A ' +
382+ ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftLargeArcRadius + offset ) + ' 0 0 1 ' +
383+ ( coords . leftFullExtent + offset ) + ' ' + coords . verticalLeftInnerExtent ;
384+ }
385+
386+ pathString += ' L ' +
387+ ( coords . leftFullExtent + offset ) + ' ' + ( coords . sourceY - coords . leftSmallArcRadius ) +
388+ ' A ' +
389+ ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftSmallArcRadius + offset ) + ' 0 0 1 ' +
390+ coords . leftInnerExtent + ' ' + ( coords . sourceY + offset ) +
391+ ' L ' +
392+ coords . sourceX + ' ' + ( coords . sourceY + offset ) +
393+
394+ // Walking back
395+ ' L ' +
396+ coords . sourceX + ' ' + ( coords . sourceY - offset ) +
397+ ' L ' +
398+ coords . leftInnerExtent + ' ' + ( coords . sourceY - offset ) +
399+ ' A ' +
400+ ( coords . leftLargeArcRadius - offset ) + ' ' + ( coords . leftSmallArcRadius - offset ) + ' 0 0 0 ' +
401+ ( coords . leftFullExtent - offset ) + ' ' + ( coords . sourceY - coords . leftSmallArcRadius ) +
402+ ' L ' +
403+ ( coords . leftFullExtent - offset ) + ' ' + coords . verticalLeftInnerExtent ;
404+
405+ if ( isSourceBeforeTarget && isPathOverlapped ) {
406+ pathString += ' A ' +
407+ ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftSmallArcRadius + offset ) + ' 0 0 0 ' +
408+ ( coords . leftFullExtent - offset ) + ' ' + ( coords . verticalFullExtent + offset ) +
409+ 'L' + ( coords . rightFullExtent + offset - arrowLen ) + ' ' + ( coords . verticalFullExtent + offset ) +
410+ ' A ' +
411+ ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftSmallArcRadius + offset ) + ' 0 0 0 ' +
412+ ( coords . rightFullExtent + offset - arrowLen ) + ' ' + coords . verticalRightInnerExtent ;
413+ } else if ( isSourceBeforeTarget ) {
414+ pathString += ' A ' +
415+ ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftSmallArcRadius + offset ) + ' 0 0 1 ' +
416+ ( coords . leftFullExtent + offset ) + ' ' + ( coords . verticalFullExtent - offset ) +
417+ ' L ' +
418+ ( coords . rightFullExtent - offset - arrowLen ) + ' ' + ( coords . verticalFullExtent - offset ) +
419+ ' A ' +
420+ ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftSmallArcRadius + offset ) + ' 0 0 1 ' +
421+ ( coords . rightFullExtent + offset - arrowLen ) + ' ' + coords . verticalRightInnerExtent ;
422+ } else {
423+ pathString += ' A ' +
424+ ( coords . leftLargeArcRadius - offset ) + ' ' + ( coords . leftLargeArcRadius - offset ) + ' 0 0 0 ' +
425+ coords . leftInnerExtent + ' ' + ( coords . verticalFullExtent + offset ) +
426+ ' L ' +
427+ ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . verticalFullExtent + offset ) +
428+ ' A ' +
429+ ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightLargeArcRadius - offset ) + ' 0 0 0 ' +
430+ ( coords . rightFullExtent + offset - arrowLen ) + ' ' + coords . verticalRightInnerExtent ;
431+ }
432+
433+ pathString += ' L ' +
434+ ( coords . rightFullExtent + offset - arrowLen ) + ' ' + ( coords . targetY - coords . rightSmallArcRadius ) +
435+ ' A ' +
436+ ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightSmallArcRadius - offset ) + ' 0 0 0 ' +
437+ ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . targetY - offset ) +
438+ ' L ' +
439+ ( coords . targetX - arrowLen ) + ' ' + ( coords . targetY - offset ) +
440+ ( arrowLen > 0 ? ' L ' + coords . targetX + ' ' + coords . targetY : '' ) +
441+ 'Z' ;
394442 } else {
395- // Bottom path
396443 pathString =
397- // start at the left of the target node
398- 'M ' +
399- ( coords . targetX - arrowLen ) + ' ' + ( coords . targetY - offset ) + ' ' +
400- 'L ' +
401- ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . targetY - offset ) +
402- 'A' +
403- ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightSmallArcRadius + offset ) + ' 0 0 0 ' +
404- ( coords . rightFullExtent - offset - arrowLen ) + ' ' + ( coords . targetY + coords . rightSmallArcRadius ) +
405- 'L' +
406- ( coords . rightFullExtent - offset - arrowLen ) + ' ' + coords . verticalRightInnerExtent +
407- 'A ' +
408- ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightLargeArcRadius + offset ) + ' 0 0 0 ' +
409- ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . verticalFullExtent + offset ) +
410- 'L' +
411- coords . leftInnerExtent + ' ' + ( coords . verticalFullExtent + offset ) +
412- 'A ' +
413- ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftLargeArcRadius + offset ) + ' 0 0 0 ' +
414- ( coords . leftFullExtent + offset ) + ' ' + coords . verticalLeftInnerExtent +
415- 'L' +
416- ( coords . leftFullExtent + offset ) + ' ' + ( coords . sourceY + coords . leftSmallArcRadius ) +
417- 'A ' +
418- ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftSmallArcRadius + offset ) + ' 0 0 0 ' +
419- coords . leftInnerExtent + ' ' + ( coords . sourceY - offset ) +
420- 'L' +
421- coords . sourceX + ' ' + ( coords . sourceY - offset ) +
422-
423- // Walking back
424- 'L' +
425- coords . sourceX + ' ' + ( coords . sourceY + offset ) +
426- 'L' +
427- coords . leftInnerExtent + ' ' + ( coords . sourceY + offset ) +
428- 'A ' +
429- ( coords . leftLargeArcRadius - offset ) + ' ' + ( coords . leftSmallArcRadius - offset ) + ' 0 0 1 ' +
430- ( coords . leftFullExtent - offset ) + ' ' + ( coords . sourceY + coords . leftSmallArcRadius ) +
431- 'L' +
432- ( coords . leftFullExtent - offset ) + ' ' + coords . verticalLeftInnerExtent +
433- 'A' +
434- ( coords . leftLargeArcRadius - offset ) + ' ' + ( coords . leftLargeArcRadius - offset ) + ' 0 0 1 ' +
435- coords . leftInnerExtent + ' ' + ( coords . verticalFullExtent - offset ) +
436- 'L ' +
437- ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . verticalFullExtent - offset ) +
438- 'A' +
439- ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightLargeArcRadius - offset ) + ' 0 0 1 ' +
440- ( coords . rightFullExtent + offset - arrowLen ) + ' ' + coords . verticalRightInnerExtent +
441- 'L' +
442- ( coords . rightFullExtent + offset - arrowLen ) + ' ' + ( coords . targetY + coords . rightSmallArcRadius ) +
443- 'A' +
444- ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightSmallArcRadius - offset ) + ' 0 0 1 ' +
445- ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . targetY + offset ) +
446- 'L' +
447- ( coords . targetX - arrowLen ) + ' ' + ( coords . targetY + offset ) +
448- ( arrowLen > 0 ? 'L ' + coords . targetX + ' ' + ( coords . targetY ) : '' ) +
449- 'Z' ;
444+ 'M ' + ( coords . targetX - arrowLen ) + ' ' + ( coords . targetY - offset ) + ' ' +
445+ ' L ' + ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . targetY - offset ) +
446+ ' A ' + ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightSmallArcRadius + offset ) + ' 0 0 0 ' + ( coords . rightFullExtent - offset - arrowLen ) + ' ' + ( coords . targetY + coords . rightSmallArcRadius ) +
447+ ' L ' + ( coords . rightFullExtent - offset - arrowLen ) + ' ' + coords . verticalRightInnerExtent ;
448+
449+ if ( isSourceBeforeTarget && isPathOverlapped ) {
450+ pathString += ' A ' + ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightLargeArcRadius + offset ) + ' 0 0 0 ' +
451+ ( coords . rightInnerExtent - offset - arrowLen ) + ' ' + ( coords . verticalFullExtent + offset ) +
452+ ' L ' + ( coords . rightFullExtent + offset - arrowLen - ( coords . rightLargeArcRadius - offset ) ) + ' ' + ( coords . verticalFullExtent + offset ) +
453+ ' A ' + ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightLargeArcRadius + offset ) + ' 0 0 0 ' +
454+ ( coords . leftFullExtent + offset ) + ' ' + coords . verticalLeftInnerExtent ;
455+ } else if ( isSourceBeforeTarget ) {
456+ pathString += ' A ' + ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightSmallArcRadius - offset ) + ' 0 0 1 ' +
457+ ( coords . rightFullExtent - arrowLen - offset - ( coords . rightLargeArcRadius - offset ) ) + ' ' + ( coords . verticalFullExtent - offset ) +
458+ ' L ' + ( coords . leftFullExtent + offset + ( coords . rightLargeArcRadius - offset ) ) + ' ' + ( coords . verticalFullExtent - offset ) +
459+ ' A ' + ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightSmallArcRadius - offset ) + ' 0 0 1 ' +
460+ ( coords . leftFullExtent + offset ) + ' ' + coords . verticalLeftInnerExtent ;
461+ } else {
462+ pathString += ' A ' + ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightLargeArcRadius + offset ) + ' 0 0 0 ' + ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . verticalFullExtent + offset ) +
463+ ' L ' + coords . leftInnerExtent + ' ' + ( coords . verticalFullExtent + offset ) +
464+ ' A ' + ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftLargeArcRadius + offset ) + ' 0 0 0 ' + ( coords . leftFullExtent + offset ) + ' ' + coords . verticalLeftInnerExtent ;
465+ }
466+
467+ pathString += ' L ' + ( coords . leftFullExtent + offset ) + ' ' + ( coords . sourceY + coords . leftSmallArcRadius ) +
468+ ' A ' + ( coords . leftLargeArcRadius + offset ) + ' ' + ( coords . leftSmallArcRadius + offset ) + ' 0 0 0 ' + coords . leftInnerExtent + ' ' + ( coords . sourceY - offset ) +
469+ ' L ' + coords . sourceX + ' ' + ( coords . sourceY - offset ) +
470+
471+ // Walking back
472+ ' L ' + coords . sourceX + ' ' + ( coords . sourceY + offset ) +
473+ ' L ' + coords . leftInnerExtent + ' ' + ( coords . sourceY + offset ) +
474+ ' A ' + ( coords . leftLargeArcRadius - offset ) + ' ' + ( coords . leftSmallArcRadius - offset ) + ' 0 0 1 ' + ( coords . leftFullExtent - offset ) + ' ' + ( coords . sourceY + coords . leftSmallArcRadius ) +
475+ ' L ' + ( coords . leftFullExtent - offset ) + ' ' + coords . verticalLeftInnerExtent ;
476+
477+ if ( isSourceBeforeTarget && isPathOverlapped ) {
478+ pathString +=
479+ ' A ' + ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightSmallArcRadius - offset ) + ' 0 0 1 ' +
480+ ( coords . leftFullExtent - offset - ( coords . rightLargeArcRadius - offset ) ) + ' ' + ( coords . verticalFullExtent - offset ) +
481+ ' L ' + ( coords . rightFullExtent + offset - arrowLen + ( coords . rightLargeArcRadius - offset ) ) + ' ' + ( coords . verticalFullExtent - offset ) +
482+ ' A ' + ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightSmallArcRadius - offset ) + ' 0 0 1 ' +
483+ ( coords . rightFullExtent + offset - arrowLen ) + ' ' + coords . verticalRightInnerExtent ;
484+ } else if ( isSourceBeforeTarget ) {
485+ pathString += ' A ' + ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightLargeArcRadius + offset ) + ' 0 0 0 ' + ( coords . leftFullExtent + offset ) + ' ' + ( coords . verticalFullExtent + offset ) +
486+ ' L ' + ( coords . rightFullExtent - arrowLen - offset ) + ' ' + ( coords . verticalFullExtent + offset ) +
487+ ' A ' + ( coords . rightLargeArcRadius + offset ) + ' ' + ( coords . rightLargeArcRadius + offset ) + ' 0 0 0 ' + ( coords . rightFullExtent + offset - arrowLen ) + ' ' + coords . verticalRightInnerExtent ;
488+ } else {
489+ pathString += ' A ' + ( coords . leftLargeArcRadius - offset ) + ' ' + ( coords . leftLargeArcRadius - offset ) + ' 0 0 1 ' + coords . leftInnerExtent + ' ' + ( coords . verticalFullExtent - offset ) +
490+ ' L ' + ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . verticalFullExtent - offset ) +
491+ ' A ' + ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightLargeArcRadius - offset ) + ' 0 0 1 ' + ( coords . rightFullExtent + offset - arrowLen ) + ' ' + coords . verticalRightInnerExtent ;
492+ }
493+
494+ pathString += ' L ' + ( coords . rightFullExtent + offset - arrowLen ) + ' ' + ( coords . targetY + coords . rightSmallArcRadius ) +
495+ ' A ' + ( coords . rightLargeArcRadius - offset ) + ' ' + ( coords . rightSmallArcRadius - offset ) + ' 0 0 1 ' + ( coords . rightInnerExtent - arrowLen ) + ' ' + ( coords . targetY + offset ) +
496+ ' L ' + ( coords . targetX - arrowLen ) + ' ' + ( coords . targetY + offset ) + ( arrowLen > 0 ? ' L ' + coords . targetX + ' ' + coords . targetY : '' ) + 'Z' ;
450497 }
451498 return pathString ;
452499}
0 commit comments