extract Path.tsx, rename the constants

This commit is contained in:
Kevin Qi 2019-04-28 21:33:24 -07:00
parent d7a19730b0
commit f65a8e56db
3 changed files with 106 additions and 89 deletions

View File

@ -1,12 +1,12 @@
import React from 'react';
const MIN_PERCENTAGE = 0;
const MAX_PERCENTAGE = 100;
const MAX_X = 100;
const MAX_Y = 100;
const FULL_RADIUS = 50;
const CENTER_X = 50;
const CENTER_Y = 50;
import {
VIEWBOX_WIDTH,
VIEWBOX_HEIGHT,
VIEWBOX_HEIGHT_HALF,
VIEWBOX_CENTER_X,
VIEWBOX_CENTER_Y,
} from './constants';
import Path from './Path';
type CircularProgressbarDefaultProps = {
strokeWidth: number;
@ -122,7 +122,7 @@ class CircularProgressbar extends React.Component<
getPathRadius() {
// The radius of the path is defined to be in the middle, so in order for the path to
// fit perfectly inside the 100x100 viewBox, need to subtract half the strokeWidth
return FULL_RADIUS - this.props.strokeWidth / 2 - this.getBackgroundPadding();
return VIEWBOX_HEIGHT_HALF - this.props.strokeWidth / 2 - this.getBackgroundPadding();
}
render() {
@ -143,15 +143,15 @@ class CircularProgressbar extends React.Component<
<svg
className={`${classes.root} ${className}`}
style={styles.root}
viewBox={`0 0 ${MAX_X} ${MAX_Y}`}
viewBox={`0 0 ${VIEWBOX_WIDTH} ${VIEWBOX_HEIGHT}`}
>
{this.props.background ? (
<circle
className={classes.background}
style={styles.background}
cx={CENTER_X}
cy={CENTER_Y}
r={FULL_RADIUS}
cx={VIEWBOX_CENTER_X}
cy={VIEWBOX_CENTER_Y}
r={VIEWBOX_HEIGHT_HALF}
/>
) : null}
@ -174,7 +174,12 @@ class CircularProgressbar extends React.Component<
/>
{text ? (
<text className={classes.text} style={styles.text} x={CENTER_X} y={CENTER_Y}>
<text
className={classes.text}
style={styles.text}
x={VIEWBOX_CENTER_X}
y={VIEWBOX_CENTER_Y}
>
{text}
</text>
) : null}
@ -183,79 +188,4 @@ class CircularProgressbar extends React.Component<
}
}
function Path({
className,
counterClockwise,
pathRadius,
percentage,
strokeWidth,
style,
}: {
className?: string;
counterClockwise: boolean;
pathRadius: number;
percentage: number;
strokeWidth: number;
style?: object;
}) {
return (
<path
className={className}
style={Object.assign({}, style, getDashStyle({ pathRadius, percentage, counterClockwise }))}
d={getPathDescription({
pathRadius,
counterClockwise,
})}
strokeWidth={strokeWidth}
fillOpacity={0}
/>
);
}
// SVG path description specifies how the path should be drawn
function getPathDescription({
pathRadius,
counterClockwise,
}: {
pathRadius: number;
counterClockwise: boolean;
}) {
const radius = pathRadius;
const rotation = counterClockwise ? 1 : 0;
// Move to center of canvas
// Relative move to top canvas
// Relative arc to bottom of canvas
// Relative arc to top of canvas
return `
M ${CENTER_X},${CENTER_Y}
m 0,-${radius}
a ${radius},${radius} ${rotation} 1 1 0,${2 * radius}
a ${radius},${radius} ${rotation} 1 1 0,-${2 * radius}
`;
}
function getDashStyle({
pathRadius,
percentage,
counterClockwise,
}: {
pathRadius: number;
percentage: number;
counterClockwise: boolean;
}) {
const diameter = Math.PI * 2 * pathRadius;
// Keep percentage within range (MIN_PERCENTAGE, MAX_PERCENTAGE)
const truncatedPercentage = Math.min(Math.max(percentage, MIN_PERCENTAGE), MAX_PERCENTAGE);
const gapLength = (1 - truncatedPercentage / 100) * diameter;
return {
// Have dash be full diameter, and gap be full diameter
strokeDasharray: `${diameter}px ${diameter}px`,
// Shift dash backward by gapLength, so gap starts appearing at correct distance
strokeDashoffset: `${counterClockwise ? -gapLength : gapLength}px`,
};
}
export default CircularProgressbar;

82
src/Path.tsx Normal file
View File

@ -0,0 +1,82 @@
import React from 'react';
import { VIEWBOX_CENTER_X, VIEWBOX_CENTER_Y } from './constants';
const MIN_PERCENTAGE = 0;
const MAX_PERCENTAGE = 100;
function Path({
className,
counterClockwise,
pathRadius,
percentage,
strokeWidth,
style,
}: {
className?: string;
counterClockwise: boolean;
pathRadius: number;
percentage: number;
strokeWidth: number;
style?: object;
}) {
return (
<path
className={className}
style={Object.assign({}, style, getDashStyle({ pathRadius, percentage, counterClockwise }))}
d={getPathDescription({
pathRadius,
counterClockwise,
})}
strokeWidth={strokeWidth}
fillOpacity={0}
/>
);
}
// SVG path description specifies how the path should be drawn
function getPathDescription({
pathRadius,
counterClockwise,
}: {
pathRadius: number;
counterClockwise: boolean;
}) {
const radius = pathRadius;
const rotation = counterClockwise ? 1 : 0;
// Move to center of canvas
// Relative move to top canvas
// Relative arc to bottom of canvas
// Relative arc to top of canvas
return `
M ${VIEWBOX_CENTER_X},${VIEWBOX_CENTER_Y}
m 0,-${radius}
a ${radius},${radius} ${rotation} 1 1 0,${2 * radius}
a ${radius},${radius} ${rotation} 1 1 0,-${2 * radius}
`;
}
function getDashStyle({
pathRadius,
percentage,
counterClockwise,
}: {
pathRadius: number;
percentage: number;
counterClockwise: boolean;
}) {
const diameter = Math.PI * 2 * pathRadius;
// Keep percentage within range (MIN_PERCENTAGE, MAX_PERCENTAGE)
const truncatedPercentage = Math.min(Math.max(percentage, MIN_PERCENTAGE), MAX_PERCENTAGE);
const gapLength = (1 - truncatedPercentage / 100) * diameter;
return {
// Have dash be full diameter, and gap be full diameter
strokeDasharray: `${diameter}px ${diameter}px`,
// Shift dash backward by gapLength, so gap starts appearing at correct distance
strokeDashoffset: `${counterClockwise ? -gapLength : gapLength}px`,
};
}
export default Path;

5
src/constants.ts Normal file
View File

@ -0,0 +1,5 @@
export const VIEWBOX_WIDTH = 100;
export const VIEWBOX_HEIGHT = 100;
export const VIEWBOX_HEIGHT_HALF = 50;
export const VIEWBOX_CENTER_X = 50;
export const VIEWBOX_CENTER_Y = 50;