fileOverview import React , { PureComponent , SVGProps } from 'react' ; import classNames from 'classnames' ; import { filterProps , GeometrySector } from '../util/types' ; import { polarToCartesian , RADIAN } from '../util/PolarUtils' ; import { getPercentValue , mathSign } from '../util/DataUtils' ; const getDeltaAngle = ( startAngle , endAngle ) => { const sign = mathSign ( endAngle - startAngle ) ; const deltaAngle = Math . min ( Math . abs ( endAngle - startAngle ) , 359.999 ) ; return sign * deltaAngle ; } ; interface TangentCircleDef { cx ? : number ; cy ? : number ; radius ? : number ; angle ? : number ; sign ? : number ; isExternal ? : boolean ; cornerRadius ? : number ; cornerIsExternal ? : boolean ; } const getTangentCircle = ( { cx , cy , radius , angle , sign , isExternal , cornerRadius , cornerIsExternal , } ) => { const centerRadius = cornerRadius * ( isExternal ? 1 : - 1 ) + radius ; const theta = Math . asin ( cornerRadius / centerRadius ) / RADIAN ; const centerAngle = cornerIsExternal ? angle : angle + sign * theta ; const center = polarToCartesian ( cx , cy , centerRadius , centerAngle ) ; const circleTangency = polarToCartesian ( cx , cy , radius , centerAngle ) ; const lineTangencyAngle = cornerIsExternal ? angle - sign * theta : angle ; const lineTangency = polarToCartesian ( cx , cy , centerRadius * Math . cos ( theta * RADIAN ) , lineTangencyAngle ) ; return { center , circleTangency , lineTangency , theta } ; } ; const getSectorPath = ( { cx , cy , innerRadius , outerRadius , startAngle , endAngle } ) => { const angle = getDeltaAngle ( startAngle , endAngle ) ; const tempEndAngle = startAngle + angle ; const outerStartPoint = polarToCartesian ( cx , cy , outerRadius , startAngle ) ; const outerEndPoint = polarToCartesian ( cx , cy , outerRadius , tempEndAngle ) ; let path = `M ${ outerStartPoint . x },${ outerStartPoint . y }
    A ${ outerRadius },${ outerRadius },0,
    ${ + ( Math . abs ( angle ) > 180 ) },${ + ( startAngle > tempEndAngle ) },
    ${ outerEndPoint . x },${ outerEndPoint . y }
  ` ; if ( innerRadius > 0 ) { const innerStartPoint = polarToCartesian ( cx , cy , innerRadius , startAngle ) ; const innerEndPoint = polarToCartesian ( cx , cy , innerRadius , tempEndAngle ) ; path += `L ${ innerEndPoint . x },${ innerEndPoint . y }
            A ${ innerRadius },${ innerRadius },0,
            ${ + ( Math . abs ( angle ) > 180 ) },${ + ( startAngle <= tempEndAngle ) },
            ${ innerStartPoint . x },${ innerStartPoint . y } Z` ; } else { path += `L ${ cx },${ cy } Z` ; } return path ; } ; const getSectorWithCorner = ( { cx , cy , innerRadius , outerRadius , cornerRadius , forceCornerRadius , cornerIsExternal , startAngle , endAngle , } ) => { const sign = mathSign ( endAngle - startAngle ) ; const { circleTangency : soct , lineTangency : solt , theta : sot } = getTangentCircle ( { cx , cy , radius : outerRadius , angle : startAngle , sign , cornerRadius , cornerIsExternal , } ) ; const { circleTangency : eoct , lineTangency : eolt , theta : eot } = getTangentCircle ( { cx , cy , radius : outerRadius , angle : endAngle , sign : - sign , cornerRadius , cornerIsExternal , } ) ; const outerArcAngle = cornerIsExternal ? Math . abs ( startAngle - endAngle ) : Math . abs ( startAngle - endAngle ) - sot - eot ; if ( outerArcAngle < 0 ) { if ( forceCornerRadius ) { return `M ${ solt . x },${ solt . y }
        a${ cornerRadius },${ cornerRadius },0,0,1,${ cornerRadius * 2 },0
        a${ cornerRadius },${ cornerRadius },0,0,1,${ - cornerRadius * 2 },0
      ` ; } return getSectorPath ( { cx , cy , innerRadius , outerRadius , startAngle , endAngle , } ) ; } let path = `M ${ solt . x },${ solt . y }
    A${ cornerRadius },${ cornerRadius },0,0,${ + ( sign < 0 ) },${ soct . x },${ soct . y }
    A${ outerRadius },${ outerRadius },0,${ + ( outerArcAngle > 180 ) },${ + ( sign < 0 ) },${ eoct . x },${ eoct . y }
    A${ cornerRadius },${ cornerRadius },0,0,${ + ( sign < 0 ) },${ eolt . x },${ eolt . y }
  ` ; if ( innerRadius > 0 ) { const { circleTangency : sict , lineTangency : silt , theta : sit } = getTangentCircle ( { cx , cy , radius : innerRadius , angle : startAngle , sign , isExternal : true , cornerRadius , cornerIsExternal , } ) ; const { circleTangency : eict , lineTangency : eilt , theta : eit } = getTangentCircle ( { cx , cy , radius : innerRadius , angle : endAngle , sign : - sign , isExternal : true , cornerRadius , cornerIsExternal , } ) ; const innerArcAngle = cornerIsExternal ? Math . abs ( startAngle - endAngle ) : Math . abs ( startAngle - endAngle ) - sit - eit ; if ( innerArcAngle < 0 && cornerRadius === 0 ) { return `${ path }L${ cx },${ cy }Z` ; } path += `L${ eilt . x },${ eilt . y }
      A${ cornerRadius },${ cornerRadius },0,0,${ + ( sign < 0 ) },${ eict . x },${ eict . y }
      A${ innerRadius },${ innerRadius },0,${ + ( innerArcAngle > 180 ) },${ + ( sign > 0 ) },${ sict . x },${ sict . y }
      A${ cornerRadius },${ cornerRadius },0,0,${ + ( sign < 0 ) },${ silt . x },${ silt . y }Z` ; } else { path += `L${ cx },${ cy }Z` ; } return path ; } ; interface SectorProps extends GeometrySector { className ? : string ; } export type Props = SVGProps < SVGPathElement > & SectorProps ; export class Sector extends PureComponent < Props > { static defaultProps = { cx : 0 , cy : 0 , innerRadius : 0 , outerRadius : 0 , startAngle : 0 , endAngle : 0 , cornerRadius : 0 , forceCornerRadius : false , cornerIsExternal : false , } ; render ( ) { const { cx , cy , innerRadius , outerRadius , cornerRadius , forceCornerRadius , cornerIsExternal , startAngle , endAngle , className , } = this . props ; if ( outerRadius < innerRadius || startAngle === endAngle ) { return null ; } const layerClass = classNames ( 'recharts-sector' , className ) ; const deltaRadius = outerRadius - innerRadius ; const cr = getPercentValue ( cornerRadius , deltaRadius , 0 , true ) ; let path ; if ( cr > 0 && Math . abs ( startAngle - endAngle ) < 360 ) { path = getSectorWithCorner ( { cx , cy , innerRadius , outerRadius , cornerRadius : Math . min ( cr , deltaRadius / 2 ) , forceCornerRadius , cornerIsExternal , startAngle , endAngle , } ) ; } else { path = getSectorPath ( { cx , cy , innerRadius , outerRadius , startAngle , endAngle } ) ; } return < path { ... filterProps ( this . props , true ) } className = { layerClass } d = { path } / > ; } }