Skip to content

Commit

Permalink
chore: merge conic logic, auto fallback (#254)
Browse files Browse the repository at this point in the history
* chore: fallback of liner

* chore: update direction

* chore: update demo

* chore: fallback of old bro
  • Loading branch information
zombieJ authored Aug 24, 2023
1 parent e23aaf1 commit 22ae75e
Show file tree
Hide file tree
Showing 9 changed files with 115 additions and 160 deletions.
12 changes: 0 additions & 12 deletions docs/examples/gap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,18 +109,6 @@ class Example extends React.Component<ProgressProps, any> {
gapDegree={70}
strokeWidth={6}
strokeColor={{
'0%': 'red',
'100%': 'blue',
}}
/>
</div>
<div style={circleContainerStyle}>
<Circle
percent={percent}
gapDegree={70}
strokeWidth={6}
strokeColor={{
conic: true,
'0%': 'red',
'99%': 'blue',
'100%': 'green',
Expand Down
19 changes: 1 addition & 18 deletions docs/examples/gradient-circle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,29 +35,12 @@ const Example = () => {
/>
</div>

<h3>Circle With Success Percent {65}%</h3>
<div style={circleContainerStyle}>
<Circle
percent={[65, 100]}
strokeWidth={6}
strokeLinecap="round"
strokeColor={[
'#87d068',
{
'100%': '#108ee9',
'0%': '#87d068',
},
]}
/>
</div>

<h3>Circle colors</h3>
<div style={circleContainerStyle}>
<Circle
percent={100}
percent={90}
strokeWidth={6}
strokeColor={{
conic: true,
'0%': 'green',
'99%': 'red',
'100%': 'blue',
Expand Down
26 changes: 0 additions & 26 deletions src/Circle/ColorGradient.tsx

This file was deleted.

64 changes: 38 additions & 26 deletions src/Circle/PtgCircle.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
import * as React from 'react';
import type { ProgressProps } from '..';
import type { StrokeColorType } from '../interface';
import type { StrokeColorObject } from '../interface';

interface BlockProps {
bg: string;
children?: React.ReactNode;
}

const Block = ({ bg, children }: BlockProps) => (
<div
style={{
width: '100%',
height: '100%',
background: bg,
}}
>
{children}
</div>
);

function getPtgColors(color: Record<string, string>, scale: number) {
return Object.keys(color).map((key) => {
const parsedKey = parseFloat(key);
const ptgKey = `${Math.floor(parsedKey * scale)}%`;

return `${color[key]} ${ptgKey}`;
});
}

export interface ColorGradientProps {
prefixCls: string;
Expand All @@ -11,8 +37,7 @@ export interface ColorGradientProps {
strokeLinecap: ProgressProps['strokeLinecap'];
strokeWidth: ProgressProps['strokeWidth'];
size: number;
color: StrokeColorType;
conic: boolean;
color: string | StrokeColorObject;
gapDegree: number;
}

Expand All @@ -27,19 +52,12 @@ const PtgCircle = React.forwardRef<SVGCircleElement, ColorGradientProps>((props,
strokeLinecap,
strokeWidth,
size,
conic,
gapDegree,
} = props;

const isGradient = color && typeof color === 'object';

const stroke = React.useMemo(() => {
if (conic) {
return '#FFF';
}

return isGradient ? `url(#${gradientId})` : undefined;
}, [gradientId, isGradient, conic]);
const stroke = isGradient ? `#FFF` : undefined;

// ========================== Circle ==========================
const halfSize = size / 2;
Expand All @@ -60,36 +78,30 @@ const PtgCircle = React.forwardRef<SVGCircleElement, ColorGradientProps>((props,
);

// ========================== Render ==========================
if (!conic) {
if (!isGradient) {
return circleNode;
}

const maskId = `${gradientId}-conic`;
const conicColorKeys = Object.keys(color).filter((key) => key !== 'conic');

const fromDeg = gapDegree ? `${180 + gapDegree / 2}deg` : '0deg';

const conicColors = conicColorKeys.map((key) => {
const parsedKey = parseFloat(key);
const ptgKey = `${gapDegree ? Math.floor((parsedKey * (360 - gapDegree)) / 360) : parsedKey}%`;

return `${color[key]} ${ptgKey}`;
});
const conicColors = getPtgColors(color, (360 - gapDegree) / 360);
const linearColors = getPtgColors(color, 1);

const conicColorBg = `conic-gradient(from ${fromDeg}, ${conicColors.join(', ')})`;
const linearColorBg = `linear-gradient(to ${gapDegree ? 'bottom' : 'top'}, ${linearColors.join(
', ',
)})`;

return (
<>
<mask id={maskId}>{circleNode}</mask>

<foreignObject x={0} y={0} width={size} height={size} mask={`url(#${maskId})`}>
<div
style={{
width: '100%',
height: '100%',
background: conicColorBg,
}}
/>
<Block bg={linearColorBg}>
<Block bg={conicColorBg} />
</Block>
</foreignObject>
</>
);
Expand Down
10 changes: 2 additions & 8 deletions src/Circle/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import classNames from 'classnames';
import { defaultProps, useTransitionDuration } from '../common';
import type { ProgressProps } from '../interface';
import useId from '../hooks/useId';
import ColorGradient from './ColorGradient';
import PtgCircle from './PtgCircle';
import { VIEW_BOX_SIZE, getCircleStyle, isConicColor } from './util';
import { VIEW_BOX_SIZE, getCircleStyle } from './util';

function toArray<T>(value: T | T[]): T[] {
const mergedValue = value ?? [];
Expand Down Expand Up @@ -50,7 +49,7 @@ const Circle: React.FC<ProgressProps> = (props) => {
string,
string
>;
const isConicGradient = isConicColor(gradient);
const isConicGradient = gradient && typeof gradient === 'object';
const mergedStrokeLinecap = isConicGradient ? 'butt' : strokeLinecap;

const circleStyle = getCircleStyle(
Expand Down Expand Up @@ -98,7 +97,6 @@ const Circle: React.FC<ProgressProps> = (props) => {
style={circleStyleForStack}
strokeLinecap={mergedStrokeLinecap}
strokeWidth={strokeWidth}
conic={isConicGradient}
gapDegree={gapDegree}
ref={(elem) => {
// https://reactjs.org/docs/refs-and-the-dom.html#callback-refs
Expand Down Expand Up @@ -169,10 +167,6 @@ const Circle: React.FC<ProgressProps> = (props) => {
role="presentation"
{...restProps}
>
{/* Line Gradient */}
{gradient && !isConicGradient && (
<ColorGradient gradientId={gradientId} gradient={gradient} />
)}
{!stepCount && (
<circle
className={`${prefixCls}-circle-trail`}
Expand Down
6 changes: 1 addition & 5 deletions src/Circle/util.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import type { StrokeColorObject, StrokeColorType } from '../interface';
import type { StrokeColorType } from '../interface';
import type { ProgressProps } from '..';

export const VIEW_BOX_SIZE = 100;

export function isConicColor(gradient: StrokeColorObject) {
return gradient && gradient.conic;
}

export const getCircleStyle = (
perimeter: number,
perimeterWithoutGap: number,
Expand Down
4 changes: 1 addition & 3 deletions src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ export interface ProgressProps {
steps?: number | { count: number; space: number };
}

export type StrokeColorObject = Partial<Record<`${number}%` | 'from' | 'to', string>> & {
conic?: boolean;
};
export type StrokeColorObject = Record<string, string>;

export type BaseStrokeColorType = string | StrokeColorObject;

Expand Down
12 changes: 10 additions & 2 deletions tests/__snapshots__/conic.spec.tsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@ exports[`Circle.conic gapDegree 1`] = `
>
<div
style="width: 100%; height: 100%;"
/>
>
<div
style="width: 100%; height: 100%;"
/>
</div>
</foreignobject>
</svg>
</DocumentFragment>
Expand Down Expand Up @@ -88,7 +92,11 @@ exports[`Circle.conic should work 1`] = `
>
<div
style="width: 100%; height: 100%;"
/>
>
<div
style="width: 100%; height: 100%;"
/>
</div>
</foreignobject>
</svg>
</DocumentFragment>
Expand Down
Loading

0 comments on commit 22ae75e

Please sign in to comment.