Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support scaling the display scale of arc segments #70

Merged
merged 4 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 26 additions & 11 deletions src/SegmentedArc.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,23 +67,38 @@ export const SegmentedArc = ({
};

const _ensureDefaultSegmentScale = () => {
let segmentsWithoutScale = segments.filter(segment => !segment.scale);
let allocatedScale = segments.reduce((total, current) => total + (current.scale || 0), 0);
let defaultArcScale = (1 - allocatedScale) / segmentsWithoutScale.length;
const segmentsWithoutScale = segments.filter(segment => !segment.scale);
const allocatedScale = segments.reduce((total, current) => total + (current.scale || 0), 0);
const defaultArcScale = (1 - allocatedScale) / segmentsWithoutScale.length;
segmentsWithoutScale.forEach(segment => (segment.scale = defaultArcScale));
};

const _ensureDefaultArcScale = () => {
const segmentsWithoutArcDegreeScaleLength = segments.filter(
segment => typeof segment.arcDegreeScale !== 'number'
).length;
const totalProvidedArcDegreeScale = segments.reduce((acc, segment) => acc + (segment.arcDegreeScale ?? 0), 0);
segments.forEach(segment => {
if (typeof segment.arcDegreeScale !== 'number')
segment.arcDegreeScale = (1 - totalProvidedArcDegreeScale) / segmentsWithoutArcDegreeScaleLength;
});
};

let remainingValue = fillValue;

_ensureDefaultSegmentScale();
_ensureDefaultArcScale();

let arcs = [];
segments.forEach((segment, index) => {
const arcDegreeScale = segment.arcDegreeScale;
const previousSegmentEnd = !!index ? arcs[index - 1].end : arcsStart;
const start = previousSegmentEnd + (!!index ? spaceBetweenSegments : 0);
const end = (arcDegree - totalSpacing) * arcDegreeScale + start;

const arcs = segments.map((segment, index) => {
const scale = segment.scale;
const start = arcsStart + index * (arcSegmentDegree + spaceBetweenSegments);
const end = arcSegmentDegree + start;
const valueMax = 100 * scale;
const valueMax = 100 * segment.scale;
const effectiveScaledValue = Math.min(remainingValue, valueMax);
const scaledPercentage = effectiveScaledValue / (scale * 100);
const scaledPercentage = effectiveScaledValue / valueMax;
const filled = start + scaledPercentage * (end - start);
remainingValue -= effectiveScaledValue;

Expand All @@ -99,7 +114,7 @@ export const SegmentedArc = ({
data: segment.data
};

return newArc;
arcs.push(newArc);
});

const lastFilledSegment = arcs.find(a => a.filled !== a.end) || arcs[arcs.length - 1];
Expand All @@ -109,7 +124,7 @@ export const SegmentedArc = ({
if (animationRunning.current) return;
if (!isAnimated) return;
animationRunning.current = true;
new Animated.timing(arcAnimatedValue, {
Animated.timing(arcAnimatedValue, {
toValue: lastFilledSegment.filled,
duration: animationDuration,
delay: animationDelay,
Expand Down
58 changes: 58 additions & 0 deletions src/__tests__/SegmentedArc.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,62 @@ describe('SegmentedArc', () => {
wrapper = getWrapper(props);
expect(wrapper.getByTestId(testId).props).toMatchSnapshot();
});

it('renders segments with arc degree scales', () => {
const segments = [
{
scale: 0.25,
arcDegreeScale: 0.5,
filledColor: '#FF0000',
emptyColor: '#F2F3F5',
data: { label: 'First Segment' }
},
{
scale: 0.02,
arcDegreeScale: 0.3,
filledColor: '#FFA500',
emptyColor: '#F2F3F5',
data: { label: 'Second Segment' }
},
{
scale: 0.02,
arcDegreeScale: 0.2,
filledColor: '#FFA500',
emptyColor: '#F2F3F5',
data: { label: 'Third Segment' }
}
];
wrapper = getWrapper({ ...props, segments });
expect(wrapper.getByTestId(testId).props).toMatchSnapshot();
expect(Animated.timing).toHaveBeenCalledTimes(1);
expect(Easing.out).toHaveBeenCalledWith(Easing.ease);
});

it('renders with ensured arc degree scales when missing from segments', () => {
const segments = [
{
scale: 0.25,
arcDegreeScale: 0.5,
filledColor: '#FF0000',
emptyColor: '#F2F3F5',
data: { label: 'First Segment' }
},
{
scale: 0.02,
filledColor: '#FFA500',
emptyColor: '#F2F3F5',
data: { label: 'Second Segment' }
},
{
scale: 0.02,
filledColor: '#FFA500',
emptyColor: '#F2F3F5',
data: { label: 'Third Segment' }
}
];
wrapper = getWrapper({ ...props, segments });
expect(wrapper.getByTestId(testId).props).toMatchSnapshot();
expect(Animated.timing).toHaveBeenCalledTimes(1);
expect(Easing.out).toHaveBeenCalledWith(Easing.ease);
});
});
218 changes: 218 additions & 0 deletions src/__tests__/__snapshots__/SegmentedArc.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,224 @@ exports[`SegmentedArc renders default 1`] = `
}
`;

exports[`SegmentedArc renders segments with arc degree scales 1`] = `
{
"children": [
<Svg
height={126}
preserveAspectRatio="xMidYMid meet"
width={240}
>
<Context.Provider
value={
{
"animationDuration": 1000,
"arcAnimatedValue": 0,
"arcSegmentDegree": 58.666666666666664,
"arcsStart": 0,
"capInnerColor": "#28E037",
"capOuterColor": "#FFFFFF",
"center": 120,
"emptyArcWidth": 8,
"filledArcWidth": 8,
"isAnimated": true,
"lastFilledSegment": {
"centerX": 120,
"centerY": 120,
"data": {
"label": "Third Segment",
},
"emptyColor": "#F2F3F5",
"end": 180,
"filled": 180,
"filledColor": "#FFA500",
"isComplete": true,
"start": 144.8,
},
"margin": 12,
"radius": 100,
"ranges": [],
"rangesTextColor": "#000000",
"rangesTextStyle": {
"fontSize": 12,
},
"spaceBetweenSegments": 2,
"totalArcs": 3,
}
}
>
<Segment
arc={
{
"centerX": 120,
"centerY": 120,
"data": {
"label": "First Segment",
},
"emptyColor": "#F2F3F5",
"end": 88,
"filled": 88,
"filledColor": "#FF0000",
"isComplete": true,
"start": 0,
}
}
/>
<Segment
arc={
{
"centerX": 120,
"centerY": 120,
"data": {
"label": "Second Segment",
},
"emptyColor": "#F2F3F5",
"end": 142.8,
"filled": 142.8,
"filledColor": "#FFA500",
"isComplete": true,
"start": 90,
}
}
/>
<Segment
arc={
{
"centerX": 120,
"centerY": 120,
"data": {
"label": "Third Segment",
},
"emptyColor": "#F2F3F5",
"end": 180,
"filled": 180,
"filledColor": "#FFA500",
"isComplete": true,
"start": 144.8,
}
}
/>
<Cap />
</Context.Provider>
</Svg>,
undefined,
],
"style": {
"alignItems": "center",
},
"testID": "container",
}
`;

exports[`SegmentedArc renders with ensured arc degree scales when missing from segments 1`] = `
{
"children": [
<Svg
height={126}
preserveAspectRatio="xMidYMid meet"
width={240}
>
<Context.Provider
value={
{
"animationDuration": 1000,
"arcAnimatedValue": 0,
"arcSegmentDegree": 58.666666666666664,
"arcsStart": 0,
"capInnerColor": "#28E037",
"capOuterColor": "#FFFFFF",
"center": 120,
"emptyArcWidth": 8,
"filledArcWidth": 8,
"isAnimated": true,
"lastFilledSegment": {
"centerX": 120,
"centerY": 120,
"data": {
"label": "Third Segment",
},
"emptyColor": "#F2F3F5",
"end": 180,
"filled": 180,
"filledColor": "#FFA500",
"isComplete": true,
"start": 136,
},
"margin": 12,
"radius": 100,
"ranges": [],
"rangesTextColor": "#000000",
"rangesTextStyle": {
"fontSize": 12,
},
"spaceBetweenSegments": 2,
"totalArcs": 3,
}
}
>
<Segment
arc={
{
"centerX": 120,
"centerY": 120,
"data": {
"label": "First Segment",
},
"emptyColor": "#F2F3F5",
"end": 88,
"filled": 88,
"filledColor": "#FF0000",
"isComplete": true,
"start": 0,
}
}
/>
<Segment
arc={
{
"centerX": 120,
"centerY": 120,
"data": {
"label": "Second Segment",
},
"emptyColor": "#F2F3F5",
"end": 134,
"filled": 134,
"filledColor": "#FFA500",
"isComplete": true,
"start": 90,
}
}
/>
<Segment
arc={
{
"centerX": 120,
"centerY": 120,
"data": {
"label": "Third Segment",
},
"emptyColor": "#F2F3F5",
"end": 180,
"filled": 180,
"filledColor": "#FFA500",
"isComplete": true,
"start": 136,
}
}
/>
<Cap />
</Context.Provider>
</Svg>,
undefined,
],
"style": {
"alignItems": "center",
},
"testID": "container",
}
`;

exports[`SegmentedArc renders with middle content 1`] = `
{
"children": [
Expand Down
Loading