When you first add a ui-template, it is pre-filled.
The docs also link off to the main dashboard docs where it goes into depth with more examples.
To do more complex things like you are asking, a level of vue knowledge is necessary though much of it is piecing together what you want with what you know
For example, you want things to change when message values arrive. So armed with the knowledge of how vue works, you might chose to watch the msg and update data variables. Alternatively, you might just bind directly to the msg object using the bind syntax - but you have to understand if you only send a msg with yellow, then the other bindings will get undefined values.
But, you give you a head start - here is something possibly close to what you need:

<template>
<svg xmlns="http://www.w3.org/2000/svg" id="powercard" viewBox="0 0 318 318" preserveAspectRatio="xMidYMid meet">
<!-- Kreise -->
<circle cx="45" cy="45" r="32" class="ring lightblue" />
<circle cx="275" cy="45" r="40" class="ring red" />
<circle cx="160" cy="45" r="40" class="ring yellow" />
<circle cx="45" cy="165" r="40" class="ring grey" />
<circle cx="275" cy="165" r="40" class="ring white" />
<circle cx="160" cy="275" r="40" class="ring blue" />
<circle cx="275" cy="275" r="40" class="ring brown" />
<circle cx="45" cy="275" r="40" class="ring green" />
<!-- Werte -->
<text x="45" y="50" class="value">{{msg.P1}}</text>
<text x="160" y="28" class="value">{{msg.P2}}W</text>
<text x="275" y="28" class="value">{{msg.P3}}W</text>
<text x="45" y="148" class="value">{{msg.P4}}W</text>
<text x="275" y="148" class="value">{{msg.P6}}W</text>
<text x="160" y="258" class="value">{{msg.P8}}W</text>
<text x="275" y="258" class="value">{{msg.P9}}L</text>
<text x="200" y="220" fill="cornflowerblue" text-anchor="middle">{{msg.P_Bat}}W</text>
<!-- Labels + Symbole -->
<text x="160" y="74" class="label">PV</text>
<text x="160" y="55" class="label">🌞</text>
<text x="275" y="74" class="label">WP</text>
<text x="275" y="55" class="label">🔥</text>
<text x="275" y="192" class="label">Haus</text>
<text x="275" y="175" class="label">🏠</text>
<text x="160" y="298" class="label">{{msg.soc}}</text>
<text x="160" y="280" class="label">🔋</text>
<text x="45" y="192" class="label">Netz</text>
<text x="45" y="175" class="label">⚡</text>
<text x="275" y="298" class="label">Heizung</text>
<text x="275" y="280" class="label">🔥</text>
<!-- Erzeugung & Verbrauch unten links -->
<text x="45" y="270" class="value">
<tspan fill="#24FD00">🌞</tspan>{{msg.P_erzeugung}}kWh
</text>
<text x="45" y="290" class="value">
<tspan fill="#c00">🔌</tspan>{{msg.P_verbrauch}}kWh
</text>
<!-- Linien + Punkte mit dynamischer Geschwindigkeit -->
<g>
<path id="lineY3" d="M160,87 C160,166 160,166 160,235" class="line yellow" />
<circle r="3" class="dot yellow">
<animateMotion id="animY3" repeatCount="indefinite">
<mpath href="#lineY3" />
</animateMotion>
</circle>
</g>
<g>
<path id="lineB" d="M170,235 C170,176 170,176 235,176" class="line blue" />
<circle r="3" class="dot blue">
<animateMotion id="animB" repeatCount="indefinite">
<mpath href="#lineB" />
</animateMotion>
</circle>
</g>
<g>
<path id="lineR2" d="M200,45 L235,45" class="line red" />
<circle r="3" class="dot red">
<animateMotion id="animR2" repeatCount="indefinite">
<mpath href="#lineR2" />
</animateMotion>
</circle>
</g>
<g>
<path id="lineG2" d="M87,166 C160,166 160,166 233,166" class="line grey" />
<circle r="3" class="dot grey">
<animateMotion id="animG2" repeatCount="indefinite">
<mpath href="#lineG2" />
</animateMotion>
</circle>
</g>
<g>
<path id="lineBr" d="M275,235 C275,210 275,210 275,205" class="line brown" />
<circle r="3" class="dot brown">
<animateMotion id="animBr" repeatCount="indefinite">
<mpath href="#lineBr" />
</animateMotion>
</circle>
</g>
</svg>
</template>
<script>
export default {
watch: {
// watch msg for any changes
msg: function () {
const m = this.msg
console.log('msg changed', m)
this.updateDuration('animY3', m.v_yellow3)
this.updateDuration('animB', m.v_blue)
this.updateDuration('animR2', m.v_red2)
this.updateDuration('animG2', m.v_grey2)
this.updateDuration('animBr', m.brown)
}
},
methods: {
updateDuration(animationId, newValue, unit = 's') {
if (typeof newValue !== 'number' || newValue < 0) {
console.log(`Invalid animation duration for ${animationId}: ${newValue}`)
return;
}
console.log('Updating animation', animationId, 'to duration', newValue)
const anim = this.$el.querySelector(`#${animationId}`)
if (anim) {
anim.setAttribute('dur', (newValue ?? 5) + unit)
}
}
}
}
</script>
<style>
.ring {
fill: #fff;
fill-opacity: 0.1;
stroke-width: 3;
}
.ring.red {
stroke: #c00;
}
.ring.grey {
stroke: #ccc;
}
.ring.blue {
stroke: #005FFF;
}
.ring.lightblue {
stroke: #7FC6FE;
fill: #7FC6FE;
fill-opacity: 0.2;
}
.ring.yellow {
stroke: #FFF700;
}
.ring.brown {
stroke: #5C4033;
}
.ring.green {
stroke: #24FD00;
}
.ring.white {
stroke: #ffffff;
}
.label {
fill: #fff;
font-size: 0.9em;
text-anchor: middle;
}
.value {
fill: #fff;
font-size: 0.8em;
text-anchor: middle;
}
.line {
stroke-width: 2;
fill: none;
}
.line.yellow {
stroke: #ff0;
}
.line.blue {
stroke: #005FFF;
}
.line.red {
stroke: #c00;
}
.line.grey {
stroke: #ccc;
}
.line.brown {
stroke: #5C4033;
}
.dot {
stroke-width: 6;
stroke-linecap: round;
fill: none;
}
.dot.yellow {
stroke: #ff0;
}
.dot.blue {
stroke: #005FFF;
}
.dot.red {
stroke: #c00;
}
.dot.grey {
stroke: #ccc;
}
.dot.brown {
stroke: #5C4033;
}
</style>
