@@ -475,27 +475,59 @@ export class CircularHeatmapComponent implements OnInit, OnDestroy {
475475 'translate(' + ( margin . left + offset ) + ',' + ( margin . top + offset ) + ')'
476476 ) ;
477477
478+ function wordWrap ( text : string , maxLen = 18 ) : string [ ] {
479+ if ( text . length <= maxLen ) return [ text ] ;
480+ var mid = Math . floor ( text . length / 2 ) ;
481+ for ( var d = 0 ; d <= mid ; d ++ ) {
482+ if ( text [ mid + d ] === ' ' )
483+ return [ text . substring ( 0 , mid + d ) , text . substring ( mid + d + 1 ) ] ;
484+ if ( mid - d >= 0 && text [ mid - d ] === ' ' )
485+ return [ text . substring ( 0 , mid - d ) , text . substring ( mid - d + 1 ) ] ;
486+ }
487+ return [ text ] ;
488+ }
489+
490+ var wrappedLabels = segmentLabels . map ( ( l : string ) => wordWrap ( l ) ) ;
491+ var hasMultiLine = wrappedLabels . some ( ( parts : string [ ] ) => parts . length > 1 ) ;
492+ var outerLabelRadius = hasMultiLine ? labelBaseRadius + labelLineHeight : labelBaseRadius ;
493+
494+ function arcPath ( radius : number ) : string {
495+ return 'm0 -' + radius + ' a' + radius + ' ' + radius + ' 0 1 1 -1 0' ;
496+ }
497+
498+ var labelPathIds = [ 'segment-label-path-' + id + '-outer' ] ;
478499 labels
479500 . append ( 'def' )
480501 . append ( 'path' )
481- . attr ( 'id' , 'segment-label-path-' + id )
482- . attr ( 'd' , 'm0 -' + r + ' a' + r + ' ' + r + ' 0 1 1 -1 0' ) ;
502+ . attr ( 'id' , labelPathIds [ 0 ] )
503+ . attr ( 'd' , arcPath ( outerLabelRadius ) ) ;
504+
505+ if ( hasMultiLine ) {
506+ labelPathIds . push ( 'segment-label-path-' + id + '-inner' ) ;
507+ labels
508+ . append ( 'def' )
509+ . append ( 'path' )
510+ . attr ( 'id' , labelPathIds [ 1 ] )
511+ . attr ( 'd' , arcPath ( labelBaseRadius ) ) ;
512+ }
483513
484- labels
485- . selectAll ( 'text' )
486- . data ( segmentLabels )
487- . enter ( )
488- . append ( 'text' )
489- . append ( 'textPath' )
490- . attr ( 'text-anchor' , 'middle' )
491- . attr ( 'xlink:href' , '#segment-label-path-' + id )
492- . style ( 'font-size' , segmentLabelFontSize + 'px' )
493- . attr ( 'startOffset' , function ( d , i ) {
494- return ( ( i + 0.5 ) * 100 ) / numSegments + '%' ; // shift ½ segment to center
495- } )
496- . text ( function ( d : any ) {
497- return d ;
514+ wrappedLabels . forEach ( function ( parts : string [ ] , i : number ) {
515+ var startOffset = ( ( i + 0.5 ) * 100 ) / numSegments + '%' ;
516+ parts . forEach ( function ( line : string , lineIndex : number ) {
517+ var pathId =
518+ lineIndex === 0 && parts . length > 1
519+ ? labelPathIds [ 0 ]
520+ : labelPathIds [ hasMultiLine ? 1 : 0 ] ;
521+ labels
522+ . append ( 'text' )
523+ . append ( 'textPath' )
524+ . attr ( 'text-anchor' , 'middle' )
525+ . attr ( 'xlink:href' , '#' + pathId )
526+ . style ( 'font-size' , segmentLabelFontSize + 'px' )
527+ . attr ( 'startOffset' , startOffset )
528+ . text ( line ) ;
498529 } ) ;
530+ } ) ;
499531 var cursors = svg
500532 . append ( 'g' )
501533 . classed ( 'cursors' , true )
0 commit comments