Pie Chart - Donut with Text
A donut chart with the total value and a caption rendered in the center hole, a clock-sweep animation, and click-to-reveal tooltips via the legend. Powered by a Power Apps collection. Inspired by the shadcn/ui Pie Chart - Donut with Text.
Pie Chart - Donut with Text
January - June 2024
Trending up by 5.2% this month
Showing total visitors for the last 6 months
How to Use
- Create the collection: ClearCollect(colPieDntTxtData, {label: "Chrome", value: 275}, {label: "Safari", value: 200}, {label: "Firefox", value: 187}, {label: "Edge", value: 173}, {label: "Other", value: 90})
- On your screen's OnVisible, add: Set(varPieDntTxtAnimate, true); Set(varTooltipPieDntTxtIdx, 0)
- Paste the copied YAML into Power Apps Studio (Ctrl+V).
- The donut sweeps in from 12 o'clock. The total sum is always visible in the center. Click a legend item to highlight the slice and show a tooltip.
- To replay the animation: Set(varPieDntTxtAnimate, false); Set(varPieDntTxtAnimate, true)
- Replace colPieDntTxtData with any data source that has {label, value} columns. The center total updates automatically.
Problem Solved
Renders an animated SVG donut chart with a live total count in the center hole, powered by a Power Apps collection. The total is a real Label control bound to Sum(colPieDntTxtData, value), not static text.
Integration
Bind colPieDntTxtData to any data source with {label, value} columns. The center total and chart both redraw automatically when the collection changes.
YAML Code
- conPieDntTxtChart:
Control: GroupContainer@1.5.0
Variant: ManualLayout
Properties:
BorderColor: =RGBA(226, 232, 240, 1)
BorderStyle: =BorderStyle.Solid
BorderThickness: =1
DropShadow: =DropShadow.Regular
Fill: =RGBA(255, 255, 255, 1)
Height: =390
RadiusBottomLeft: =12
RadiusBottomRight: =12
RadiusTopLeft: =12
RadiusTopRight: =12
Width: =440
Children:
- tmrPieDntTxtAnimate:
Control: Timer@2.1.0
Properties:
Duration: =1200
Height: =1
OnTimerEnd: =Set(varPieDntTxtAnimate, false)
Repeat: =false
Start: =varPieDntTxtAnimate
Visible: =false
Width: =1
X: =0
Y: =0
- lblPieDntTxtTitle:
Control: Label@2.5.1
Properties:
Align: =Align.Center
Color: =RGBA(15, 23, 42, 1)
Font: =Font.'Open Sans'
FontWeight: =FontWeight.Bold
Height: =24
Size: =14
Text: ="Pie Chart - Donut with Text"
Width: =400
X: =20
Y: =14
- lblPieDntTxtDesc:
Control: Label@2.5.1
Properties:
Align: =Align.Center
Color: =RGBA(100, 116, 139, 1)
Font: =Font.'Open Sans'
Height: =20
Size: =12
Text: ="January - June 2024"
Width: =400
X: =20
Y: =44
- rectPieDntTxtHeader:
Control: Rectangle@2.3.0
Properties:
Fill: =RGBA(226, 232, 240, 1)
Height: =1
Width: =440
X: =0
Y: =68
- imgPieDntTxtChart:
Control: Image@2.2.3
Properties:
Height: =216
Width: =416
X: =12
Y: =72
Image: |-
=With(
{
_n: CountRows(colPieDntTxtData),
_total: Sum(colPieDntTxtData, value),
_p: Min(1, tmrPieDntTxtAnimate.Value / 1200)
},
With(
{ _ease: 1 - Power(Max(0, 1 - _p), 3) },
"data:image/svg+xml;utf8, " & EncodeUrl(
"<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 416 216'>" &
Concat(Sequence(_n),
With(
{
_cf: Sum(FirstN(colPieDntTxtData, Value - 1), value) / _total,
_tf: Index(colPieDntTxtData, Value).value / _total
},
With(
{
_sf: _cf,
_ef: Min(_cf + _tf, _ease)
},
If(_sf < _ease And _ef - _sf > 0.001,
With(
{
_sa: _sf * 2 * Pi() - Pi() / 2,
_ea: _ef * 2 * Pi() - Pi() / 2,
_df: _ef - _sf
},
With(
{
_x1: Text(Round(208 + 96 * Cos(_sa), 1)),
_y1: Text(Round(108 + 96 * Sin(_sa), 1)),
_x2: Text(Round(208 + 96 * Cos(_ea), 1)),
_y2: Text(Round(108 + 96 * Sin(_ea), 1)),
_la: If(_df > 0.5, "1", "0"),
_col: Switch(Value, 1, "#3b82f6", 2, "#10b981", 3, "#f59e0b", 4, "#8b5cf6", "#6b7280"),
_str: If(varTooltipPieDntTxtIdx = Value, " stroke='white' stroke-width='3'", "")
},
"<path d='M 208,108 L " & _x1 & "," & _y1 &
" A 96,96 0 " & _la & ",1 " & _x2 & "," & _y2 &
" Z' fill='" & _col & "'" & _str & "/>"
)
),
""
)
)
)
) &
"<circle cx='208' cy='108' r='50' fill='white'/>" &
If(_p > 0,
"<text x='208' y='108' text-anchor='middle' font-family='Arial,sans-serif' font-size='18' font-weight='700' fill='#0f172a'>" & Text(_total) & "</text>" &
"<text x='208' y='124' text-anchor='middle' font-family='Arial,sans-serif' font-size='11' fill='#64748b'>Visitors</text>",
""
) &
"</svg>"
)
)
)
- galPieDntTxtLegend:
Control: Gallery@2.15.0
Variant: Horizontal
Properties:
Fill: =RGBA(0, 0, 0, 0)
Height: =36
Items: =Sequence(CountRows(colPieDntTxtData))
ShowScrollbar: =false
TemplatePadding: =0
TemplateSize: =440 / Max(1, CountRows(colPieDntTxtData))
Width: =440
X: =0
Y: =296
Children:
- imgPieDntTxtLegDot:
Control: Image@2.2.3
Properties:
Fill: =Switch(ThisItem.Value, 1, RGBA(59, 130, 246, 1), 2, RGBA(16, 185, 129, 1), 3, RGBA(245, 158, 11, 1), 4, RGBA(139, 92, 246, 1), RGBA(107, 114, 128, 1))
Height: =10
Image: =Blank()
RadiusBottomLeft: =5
RadiusBottomRight: =5
RadiusTopLeft: =5
RadiusTopRight: =5
Width: =10
X: =14
Y: =13
- lblPieDntTxtLegLabel:
Control: Label@2.5.1
Properties:
Color: =RGBA(15, 23, 42, 1)
Font: =Font.'Open Sans'
Height: =14
Size: =10
Text: =Index(colPieDntTxtData, ThisItem.Value).label
Width: =62
X: =28
Y: =11
- btnPieDntTxtLegHit:
Control: Button@0.0.45
Properties:
Appearance: ='ButtonCanvas.Appearance'.Transparent
Height: =Parent.TemplateHeight
OnSelect: =If(varTooltipPieDntTxtIdx = ThisItem.Value, Set(varTooltipPieDntTxtIdx, 0), Set(varTooltipPieDntTxtIdx, ThisItem.Value))
Text: =""
Width: =Parent.TemplateWidth
X: =0
Y: =0
- conPieDntTxtTooltip:
Control: GroupContainer@1.5.0
Variant: ManualLayout
Properties:
BorderColor: =RGBA(226, 232, 240, 1)
BorderStyle: =BorderStyle.Solid
BorderThickness: =1
DropShadow: =DropShadow.Regular
Fill: =RGBA(255, 255, 255, 1)
Height: =72
RadiusBottomLeft: =8
RadiusBottomRight: =8
RadiusTopLeft: =8
RadiusTopRight: =8
Visible: =varTooltipPieDntTxtIdx > 0
Width: =130
X: =Max(10, Min(300, (varTooltipPieDntTxtIdx - 1) * (440 / Max(1, CountRows(colPieDntTxtData))) + 22 - 65))
Y: =218
Children:
- lblTooltipPieDntTxtLabel:
Control: Label@2.5.1
Properties:
Color: =RGBA(100, 116, 139, 1)
Font: =Font.'Open Sans'
FontWeight: =FontWeight.Semibold
Height: =18
Size: =10
Text: =If(varTooltipPieDntTxtIdx > 0, Index(colPieDntTxtData, varTooltipPieDntTxtIdx).label, "")
Width: =116
X: =8
Y: =6
- imgTooltipPieDntTxtDot:
Control: Image@2.2.3
Properties:
Fill: =Switch(varTooltipPieDntTxtIdx, 1, RGBA(59, 130, 246, 1), 2, RGBA(16, 185, 129, 1), 3, RGBA(245, 158, 11, 1), 4, RGBA(139, 92, 246, 1), RGBA(107, 114, 128, 1))
Height: =8
Image: =Blank()
RadiusBottomLeft: =4
RadiusBottomRight: =4
RadiusTopLeft: =4
RadiusTopRight: =4
Width: =8
X: =8
Y: =30
- lblTooltipPieDntTxtValue:
Control: Label@2.5.1
Properties:
Color: =RGBA(15, 23, 42, 1)
Font: =Font.'Open Sans'
FontWeight: =FontWeight.Semibold
Height: =18
Size: =11
Text: =If(varTooltipPieDntTxtIdx > 0, Text(Index(colPieDntTxtData, varTooltipPieDntTxtIdx).value), "")
Width: =108
X: =20
Y: =28
- lblTooltipPieDntTxtPct:
Control: Label@2.5.1
Properties:
Color: =RGBA(100, 116, 139, 1)
Font: =Font.'Open Sans'
Height: =18
Size: =10
Text: =If(varTooltipPieDntTxtIdx > 0, Text(Round(Index(colPieDntTxtData, varTooltipPieDntTxtIdx).value / Max(1, Sum(colPieDntTxtData, value)) * 100, 1)) & "% of total", "")
Width: =116
X: =8
Y: =50
- rectPieDntTxtFooter:
Control: Rectangle@2.3.0
Properties:
Fill: =RGBA(226, 232, 240, 1)
Height: =1
Width: =440
X: =0
Y: =340
- lblPieDntTxtTrend:
Control: Label@2.5.1
Properties:
Align: =Align.Center
Color: =RGBA(15, 23, 42, 1)
Font: =Font.'Open Sans'
FontWeight: =FontWeight.Semibold
Height: =20
Size: =12
Text: ="Trending up by 5.2% this month"
Width: =400
X: =20
Y: =350
- lblPieDntTxtDateRange:
Control: Label@2.5.1
Properties:
Align: =Align.Center
Color: =RGBA(100, 116, 139, 1)
Font: =Font.'Open Sans'
Height: =20
Size: =11
Text: ="Showing total visitors for the last 6 months"
Width: =400
X: =20
Y: =374Implementation
Copies the customized component code directly to your clipboard. Use Ctrl+V in Power Apps Studio.
Something not pasting right? Troubleshooting guide