Skip to content

Commit

Permalink
support scaling the display scale of arc segments (#70)
Browse files Browse the repository at this point in the history
* support scaling the display scale of arc segments

* Update snapshots

---------

Co-authored-by: Jakhongir Khusanov <[email protected]>
  • Loading branch information
rkyle35242 and jkhusanov authored Apr 9, 2024
1 parent 0f5959a commit c310637
Show file tree
Hide file tree
Showing 3 changed files with 302 additions and 11 deletions.
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

0 comments on commit c310637

Please sign in to comment.