This Power BI report demonstrates creating custom, interactive visuals by combining DAX, HTML, SVG, and JavaScript. Visuals include state indicators (green = good, yellow = on track, red = warning with blinking), liquid fill gauges, five-star ratings, linear and circular gauges, sparklines with intersection highlights, barcode charts by month, and boxplots. Using DAX for data-driven calculations and HTML/JavaScript for rendering, each visual dynamically updates with the underlying dataset, allowing flexible styling and interactive effects. This project showcases how integrating scripting with Power BI enables highly customized, visually engaging dashboards beyond standard chart types.
🗝 Keywords: Power BI, SVG, HTML, JavaScript
This DAX measure generates a small SVG status badge based on the value of [stage category]. It chooses a color for the rectangle (Good = green, On Track = orange, Warning = red, Gray as default) and displays the stage text centered inside the rounded box. If the stage is “Warning,” it adds a blinking fill-opacity animation to draw attention. The measure outputs the colored, rounded status label as an inline SVG image for use in Power BI tables or matrices.
State =
VAR Stage = [stage category] //Measure
VAR Colour = SWITCH(
Stage,
"Warning", "#b30000",
"On Track", "Orange",
"Good", "Green",
"Gray" // fallback
)
VAR RectWidth = 100
VAR RectHeight = 30
VAR RectY = 0 // start at top of SVG
VAR TextY = 20 // vertical position of text inside rectangle
VAR FontSize = 16
VAR SvgWidth = RectWidth
VAR SvgHeight = RectHeight
/* Conditionally add blinking animation for Warning */
VAR AnimateWarning =
IF(
Stage = "Warning",
"<animate attributeName='fill-opacity' values='1;1;1;0;1;1;1' dur='2.5s' repeatCount='indefinite'/>",
""
)
VAR Box = "<rect x='0' y='" & RectY & "' rx='15' ry='15' width='" & RectWidth & "' height='" & RectHeight & "' fill='" & Colour & "' stroke='#D0D0D0' stroke-width='0'>" & AnimateWarning & "</rect>"
VAR Callout = "<text x='" & RectWidth/2 & "' y='" & TextY & "' text-anchor='middle' font-weight='bold' font-family='Segoe UI, sans-serif' font-size='" & FontSize & "' fill='white'>" & Stage & "</text>"
RETURN
"data:image/svg+xml;utf8," &
"<svg width='" & SvgWidth & "' height='" & SvgHeight & "' viewBox='0 0 " & SvgWidth & " " & SvgHeight & "' style='vertical-align:middle' xmlns='http://www.w3.org/2000/svg'>" &
Box & Callout &
"</svg>"
This DAX measure creates an animated liquid-fill gauge showing progress toward the yearly sales target.
It calculates the percentage of Current Year Sales vs. the Annual Goal, then animates a rising wave inside a circular clip path to visually represent the fill level.
Two layered waves provide motion and depth through path animation and gentle oscillation. An outer ring frames the gauge, and the center displays the numeric percentage.
The entire graphic is returned as an inline SVG for use in Power BI visuals.
Liquid Fill Gauge =
VAR _value = [Current Year Sales]
VAR _total = SUM('年度目標'[Amount])
VAR _percent = DIVIDE(_value,_total,0)
VAR _pctText = FORMAT(_percent,"0%")
VAR _svgWidth = 200
VAR _svgHeight = 200
VAR _r = 80
VAR _cx = 100
VAR _cy = 100
/* Start and target Y */
VAR _startY = 200
VAR _targetY = _svgHeight * (1-_percent)
/* Wave path template */
VAR _waveStartPath =
"M20 " & _startY &
" Q30 " & (_startY-2) & " 50 " & _startY & // crest 1
" T90 " & (_startY-1) &
" T145 " & (_startY+1) &
" T180 " & _startY &
" V200 H20 Z"
VAR _waveTargetPath =
"M20 " & _targetY &
" Q30 " & (_targetY-2) & " 50 " & (_targetY+2) & // crest 1
" T90 " & (_targetY-1) &
" T145 " & (_targetY-1) &
" T180 " & _targetY &
" V200 H20 Z"
VAR _svg =
"<svg viewBox='0 0 " & _svgWidth & " " & _svgHeight & "' width='" & _svgWidth & "' height='" & _svgHeight & "' xmlns='http://www.w3.org/2000/svg'>
<!-- Outer circle -->
<circle cx='" & _cx & "' cy='" & _cy & "' r='" & _r+5 & "' fill='#f3f6fb' stroke='#9bc1ef' stroke-width='10'/>
<defs>
<clipPath id='liquidClip'>
<circle cx='" & _cx & "' cy='" & _cy & "' r='" & _r & "'/>
</clipPath>
<!-- Optional gradient for more depth -->
<linearGradient id='waveGradient' x1='0' y1='0' x2='0' y2='1'>
<stop offset='0%' stop-color='#6bb6ff' stop-opacity='0.7'/>
<stop offset='100%' stop-color='#1E90FF' stop-opacity='1'/>
</linearGradient>
</defs>
<g clip-path='url(#liquidClip)'>
<!-- Main rising wave -->
<path d='" & _waveStartPath & "' fill='url(#waveGradient)'>
<animate attributeName='d'
from='" & _waveStartPath & "'
to='" & _waveTargetPath & "'
dur='2s' fill='freeze' />
<animateTransform attributeName='transform' type='translate' values='0 0; 0 5.5; 0 0' keyTimes='0;0.5;1' dur='4s' repeatCount='indefinite'/>
</path>
<!-- Overlapping secondary wave -->
<path d='" & _waveStartPath & "' fill='rgba(255,255,255,0.2)'>
<animate attributeName='d'
from='" & _waveStartPath & "'
to='" & _waveTargetPath & "'
dur='2s' fill='freeze' />
<animateTransform attributeName='transform' type='translate' values='0 0; 0 7; 0 0' keyTimes='0;0.5;1' dur='3s' repeatCount='indefinite'/>
</path>
</g>
<!-- Percentage Text -->
<text x='" & _cx+2.5 & "' y='" & _cy+2.5 & "' text-anchor='middle' font-size='28' font-weight='700' fill='#0b2545'>" & _pctText & "</text>
</svg>"
RETURN
"data:image/svg+xml;utf8," & _svg
This DAX measure builds an animated 5-star rating graphic. It draws five identical star shapes in a row, first in white (the background), then again in gold.
A dynamic clipPath controls how much of the gold layer is revealed, with the width animated from 0 to Achieved % × 500px, creating a smooth left-to-right “filling” effect (like Amazon-style star ratings).
If Achieved % is blank, it returns nothing; otherwise it outputs the complete SVG as a data URI for Power BI visuals.
Stars =
VAR svg_start = "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 500 100'>"
VAR svg_end = "</svg>"
VAR Star1 = "<path d='m50,2 12,34h36l-28,22 10,34-30-20-30,20 10-34-28-22h36z'/>"
VAR Star5 =
CONCATENATEX (
GENERATESERIES ( 0, 400, 100 ),
"<g transform='translate(" & [Value] & ",0)'>" & Star1 & "</g>"
)
// Clip 的寬度隨 Achieved % 動態變化 (0–500px)
VAR ClipWidth = 500 // Clip 最大寬度
VAR Defs =
"<defs>
<clipPath id='StarClip'>
<rect x='0' y='0' height='100' width='0'>
<animate attributeName='width' from='0' to='" & ([Achieved %]*500) & "' dur='2s' fill='freeze' />
</rect>
</clipPath>
</defs>"
VAR GreyStars = "<g fill='White' stroke-width='1' stroke='Black'>" & Star5 & "</g>"
VAR GoldStars = "<g fill='Gold' clip-path='url(#StarClip)'>" & Star5 & "</g>"
RETURN
IF (
ISBLANK([Achieved %]) || [Achieved %]="NA",
BLANK(),
svg_start & Defs & GreyStars & GoldStars & svg_end
)
This DAX measure creates a simple animated linear gauge showing progress toward a target. A gray track forms the background, and a blue bar animates its width from 0 to Achieved% × 100.
An orange vertical line marks the fixed target threshold (80%). Tooltips on both the fill bar and target line show the exact percentages. If Achieved% is blank or “NA,” the measure returns nothing; otherwise it outputs the full inline SVG for display in Power BI.
Linear Gauge =
VAR Achieved = [Achieved %]
VAR Target = 0.8
RETURN
IF(
ISBLANK(Achieved) || Achieved = "NA",
BLANK(),
"data:image/svg+xml;utf8," &
"<svg width='100' height='20' xmlns='http://www.w3.org/2000/svg' overflow='visible'>
<!-- 背景軌道 -->
<rect id='track' x='0' y='0' width='100' height='18' fill='#D0D0D0'/>
<!-- 動態填充條 -->
<rect id='fill' x='0' y='4' width='0' height='10' fill='#1F51FF'>
<animate attributeName='width'
from='0'
to='" & (Achieved*100) & "'
dur='1.5s'
fill='freeze' />
<title>Percent: " & FORMAT(Achieved, "0%") & "</title>
</rect>
<!-- 目標線 -->
<rect id='target' x='" & (Target*100) & "' y='0' width='2' height='18' fill='orange'>
<title>Target: " & FORMAT(Target, "0%") & "</title>
</rect>
</svg>"
)
This measure renders a semi-circular gauge with animation. It first draws a grey arc as the background. Then it adds a colored arc that animates by reducing its stroke-dashoffset, visually “filling” the gauge based on Achieved%.
The fill color changes automatically (red → yellow → green) depending on the percentage level. A simple pointer rotates from 0° to 180° to match the current value, and the percentage is shown as centered text.
If Achieved% is blank or “NA,” it returns nothing; otherwise it outputs the complete SVG for Power BI.
Gauge Animated =
VAR MAXValue = 1
VAR CounterValue = 'annualgoal'[Achieved %]
VAR PERCENTAGEFILL =
IF(
ISBLANK(CounterValue) || CounterValue = "NA",
BLANK(),
CounterValue / MAX(MAXValue, CounterValue))
VAR strokeColor = IF(PERCENTAGEFILL < 0.5, "#e62c29", IF(PERCENTAGEFILL < 0.65, "#F4E40E", "#28a428"))
RETURN
IF(
ISBLANK(CounterValue) || CounterValue = "NA",
BLANK(),
"data:image/svg+xml;charset=utf-8,
<svg xmlns='http://www.w3.org/2000/svg' width='100' height='80' viewBox='0 0 110 80'>
<!-- 背景軌道 -->
<path fill='none' stroke='lightgrey' stroke-width='20' d='M10,55 a45,45 0 1 1 90,0'/>
<!-- 動態填充條 -->
<path fill='none' stroke='" & strokeColor & "' stroke-width='20' stroke-dasharray='141.3717' stroke-dashoffset='141.3717' d='M10,55 a45,45 0 1 1 90,0'>
<animate attributeName='stroke-dashoffset' from='141.3717' to='" & (1-PERCENTAGEFILL)*141.3717 & "' dur='1s' fill='freeze'/>
</path>
<!-- Counter 指針 -->
<path fill='black' stroke='black' stroke-width='3' d='M0,55 L0,55' transform='rotate(" & PERCENTAGEFILL*180 & " 55 55)'/>
<!-- 文字 -->
<text x='35%' y='55' font-family='Segoe UI' font-size='16' font-weight='bold'>" & FORMAT(CounterValue,"0%") & "</text>
</svg>"
)