Here is an example of ReactiveHTML use to create custom progress indicator
class ArcProgressIndicator(pn.reactive.ReactiveHTML):
progress = param.Number(default=0, bounds=(0, 100))
transition_duration = param.Number(default=0.5, bounds=(0, None))
format_options = param.Dict(default={"locale":"en-US",
"minimumIntegerDigits":"1",
"maximumIntegerDigits":"3",
"minimumFractionDigits":"1",
"maximumFractionDigits":"1"})
text_style = param.Dict(default={
"font-size" : 5,
"text-anchor": "middle",
"letter-spacing": -0.5,
})
empty_color = param.Color(default="#e8f6fd")
fill_color = param.Color(default="#2a87d8")
_template = """
<div id="arcprog"></div>
"""
_scripts = {
"render": """
const container = document.getElementById(`arcprog-${data.id}`)
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg")
svg.setAttribute("viewBox", "0 0 20 9")
svg.setAttribute("style", "width:100%;height:100%;")
const empty_path = document.createElementNS("http://www.w3.org/2000/svg", "path")
empty_path.setAttribute("d", "M1 9 A 8 7 0 1 1 19 9")
empty_path.setAttribute("fill", "none")
empty_path.setAttribute("stroke-width", "1.5")
state.empty_path = empty_path
state.path_len = empty_path.getTotalLength()
const fill_path = empty_path.cloneNode()
fill_path.setAttribute("stroke-dasharray", `${state.path_len * data.progress/100} ${state.path_len}`)
fill_path.setAttribute("style", `transition: stroke-dasharray ${data.transition_duration}s`)
state.fill_path = fill_path
text = document.createElementNS("http://www.w3.org/2000/svg", "text")
text.setAttribute("y","8.8")
text.setAttribute("x","10")
self.text_style()
state.text = text
svg.appendChild(empty_path)
svg.appendChild(fill_path)
svg.appendChild(text)
container.appendChild(svg)
self.empty_color()
self.fill_color()
self.format_options()
self.progress()
""",
"progress": """
const textNode = document.createTextNode(`${state.formatter.format(data.progress)}%`)
if(state.text.firstChild)
state.text.firstChild.replaceWith(textNode)
else
text.appendChild(textNode)
state.fill_path.setAttribute("stroke-dasharray", `${state.path_len * data.progress/100} ${state.path_len}`)
""",
"transition_duration": """
state.fill_path.setAttribute("style", `transition: stroke-dasharray ${data.transition_duration}s`)
""",
"format_options":
"""
state.formatter = new Intl.NumberFormat(data.format_options.locale, data.format_options)
""",
"text_style": """
text.setAttribute("style", Object.entries(data.text_style).map(([k, v]) => `${k}:${v}`).join(';'))
""",
"empty_color": """
state.empty_path.setAttribute("stroke", data.empty_color)
""",
"fill_color": """
state.fill_path.setAttribute("stroke", data.fill_color)
state.text.setAttribute("fill", data.fill_color)
""",
}
indicator = ArcProgressIndicator(progress=10, background="#efebeb")
pn.Row(
indicator.controls()[0],
indicator
)