From 5a11d0ea4ff93f46ac8070b8a4609a7c480a6408 Mon Sep 17 00:00:00 2001 From: Alec Winograd Date: Fri, 13 Sep 2019 16:39:14 -0500 Subject: [PATCH] Add ability to render a custom cap over the progress circle Adds two new props * padding - adds space around the circle to allow for a cap that bleeds over without clipping * renderCap - a function that returns the Svg component to draw --- index.d.ts | 16 ++++++++++++++++ src/CircularProgress.js | 37 +++++++++++++++++++++++++++---------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/index.d.ts b/index.d.ts index 5019dc5..9068798 100644 --- a/index.d.ts +++ b/index.d.ts @@ -129,6 +129,22 @@ declare module 'react-native-circular-progress' { * */ onAnimationComplete?: (event: { finished: boolean }) => void; + + /** + * Padding applied around the circle to allow for a cap that bleeds outside its boundary + * + * @type {number} + * @default 0 + */ + padding?: number; + + /** + * Function that's invoked during rendering to draw at the tip of the progress circle + * + */ + renderCap?: (payload: { + center: { x: number; y: number }; + }) => React.ReactNode; } export class AnimatedCircularProgress extends React.Component< diff --git a/src/CircularProgress.js b/src/CircularProgress.js index ab9d0ff..bc048d5 100644 --- a/src/CircularProgress.js +++ b/src/CircularProgress.js @@ -36,31 +36,44 @@ export default class CircularProgress extends React.PureComponent { fill, children, childrenContainerStyle, + padding, + renderCap, } = this.props; const maxWidthCircle = backgroundWidth ? Math.max(width, backgroundWidth) : width; + const sizeWithPadding = size / 2 + padding / 2; + const radius = size / 2 - maxWidthCircle / 2 - padding / 2; const backgroundPath = this.circlePath( - size / 2, - size / 2, - size / 2 - maxWidthCircle / 2, + sizeWithPadding, + sizeWithPadding, + radius, 0, arcSweepAngle ); + const currentFillAngle = (arcSweepAngle * this.clampFill(fill)) / 100; const circlePath = this.circlePath( - size / 2, - size / 2, - size / 2 - maxWidthCircle / 2, + sizeWithPadding, + sizeWithPadding, + radius, 0, - (arcSweepAngle * this.clampFill(fill)) / 100 + currentFillAngle ); + const coordinate = this.polarToCartesian( + sizeWithPadding, + sizeWithPadding, + radius, + currentFillAngle + ); + const cap = this.props.renderCap ? this.props.renderCap({ center: coordinate }) : null; + const offset = size - maxWidthCircle * 2; const localChildrenContainerStyle = { ...{ position: 'absolute', - left: maxWidthCircle, - top: maxWidthCircle, + left: maxWidthCircle + padding / 2, + top: maxWidthCircle + padding / 2, width: offset, height: offset, borderRadius: offset / 2, @@ -73,7 +86,7 @@ export default class CircularProgress extends React.PureComponent { return ( - + {backgroundColor && ( )} + {cap} {children && {children(fill)}} @@ -114,6 +128,8 @@ CircularProgress.propTypes = { arcSweepAngle: PropTypes.number, children: PropTypes.func, childrenContainerStyle: ViewPropTypes.style, + padding: PropTypes.number, + renderCap: PropTypes.func, }; CircularProgress.defaultProps = { @@ -121,4 +137,5 @@ CircularProgress.defaultProps = { rotation: 90, lineCap: 'butt', arcSweepAngle: 360, + paddinig: 0, };