NEWS
vis-2 svg mit Datenpunkten ändern
-
Hallo Community,
ich möchte hier ein neues Thema aufmachen, da ich alles durchgesucht und auch vieles probiert habe, aber für meine Anwendung keine funktionierende bzw. zufriedenstellende Lösung gefunden habe.
Ich möchte für den Anfang eine einfache .svg Grafik in der vis-2 darstellen und diese in Echtzeit abhängig von einem Datenpunkt verändern.
Hier ist die svg:
<svg id="dynamic-svg" width="100" height="50" viewBox="0 0 350 175" xmlns="http://www.w3.org/2000/svg"> <defs> <linearGradient id="twoColors" x1="0%" y1="0%" x2="100%" y2="0%" gradientUnits="userSpaceOnUse"> <stop id="startColor" offset="50%" style="stop-color:#00ff00; stop-opacity:1" /> <stop id="middleColor" offset="50%" style="stop-color:#ffffff; stop-opacity:0.7" /> <stop id="endColor" offset="100%" style="stop-color:#ffffff; stop-opacity:0.7" /> </linearGradient> </defs> <rect x="0" y="0" width="325" height="175" rx="29" ry="29" fill="url(#twoColors)" /> <path d="M 330,57 h 6.5 a 13.5,13.5 0 0 1 13.5,13.5 v 34 a 13.5,13.5 0 0 1 -13.5,13.5 h -6.5 v -61 Z" fill="url(#twoColors)" /> </svg>
In diesem Fall eine Batterie und es soll der Ladezustand linearGradient id="twoColors" offset von id="startColor" und id="middleColor" abhängig von diesem Datenpunkt "0_userdata.0.Raumklima.SHC_Test_Batt" verändert werden.
Zur Zeit löse ich diesen Fall über JS-Adapter. Mit JS wird abhängig vom Wert aus dem Datenpunkt die svg generiert und in ein anderen Datenpunkt als String abgelegt. In einem HTML Basic Widget habe ich ein Binding auf den Datenpunkt mit svg.
Funktioniert soweit ganz zuverlässig, was mich aber stört in die Zeitverzögerung bis die Grafik im Browser angezeigt wird, wenn die Seite aufgerufen wird. Besonders nervig bei Navigieren von einer Seite auf die Andere.Letztendlich möchte euch um eure Erfahrung fragen, was der sinnvollste Weg ist für mein Vorhaben, insbesondere auch auf Sicht der Performance und Ausbaufähigkeit, wenn später mehr und auch umfangreiche Grafiken kommen mit mehreren Datenpunkten.
Welche Widget ist dafür am besten geeignet und wie nimmt man am besten den Einfluss auf svg, mit Binding, css oder doch JavaScript?Ich bin schon auf eure Ratschläge und Ideen sehr gespannt und würde mich über eine Lösung sehr freuen.
Mein System:
- RasPi 4 mit 8GB RAM
- IOBroker v7.2.6
- Node.js: v20.18.0
- NPM: v10.8.2
- vis-2 v2.9.64
- vis-1 ist auch installiert (falls die Info wichtig sein sollte)
Danke und Gruß
-
@bigdragan benutze noch keine VIS-2. Aber in VIS nutze ich hier
Das geht sofort, ohne Verzögerung. Ob es auch etwas Vergleichbares in VIS-2 gibt? Keine Ahnung.
Ro75.
-
@ro75 Hallo Ro75, danke für deine Rückmeldung.
in der vis-2 gibt es alle Basic Widgets wie in der vis, zumindest soweit ich das beurteilen kann.Ich habe das Widget "String img src" ausprobiert, leider ohne Erfolg. Danach hatte ich das Widget "String (unescaped)" probiert und wow, das ging tatsächlich. Beim Laden der Seite werden die Bilder direkt angezeigt. Super Hinweis, ich wäre nicht auf die Idee gekommen String Widgets zum Anzeigen von Bilder zu verwenden.
Also ich bin erstmal mit der Lösung voll zufrieden.
Ich frage mich aber trotzdem ob dieser Ansatz der beste ist, hier ist ein zusätlicher Code im JS-Adapter, plus ein zusätzlicher Datenpunkt für die svg notwendig und wenn es viele von der selben Grafik geben sollte, dann müssen es genau so viele zusätzliche Datenpunkte geben.
Elegant wäre es eine Grafik zentral abzulegen und in jedem Widget diese abzurufen und nur für das jeweilige Widget je nach Bedürfnis zu verändern.
Ob das wohl überhaupt möglich ist?Noch mal Danke dir?
-
@bigdragan muss das unbedingt diese Art von SVG sein?
Ro75.
-
@bigdragan sagte in vis-2 svg mit Datenpunkten ändern:
Ich frage mich aber trotzdem ob dieser Ansatz der beste ist, hier ist ein zusätlicher Code im JS-Adapter, plus ein zusätzlicher Datenpunkt für die svg notwendig und wenn es viele von der selben Grafik geben sollte, dann müssen es genau so viele zusätzliche Datenpunkte geben.
Elegant wäre es eine Grafik zentral abzulegen und in jedem Widget diese abzurufen und nur für das jeweilige Widget je nach Bedürfnis zu verändern.
Ob das wohl überhaupt möglich ist?Ich habe auch einige Batterie-Anzeigen drin, als PNG. Je nach Prozentstand (Ladung) wird in einem DP ein anderer String für diese Batterie erstellt.
Also.17 Grafiken und pro Anzeige ein DP. Letztlich überschaubar, da auch nur eine zentrale Funktion (wird von mehreren Stellen aufgerufen) nötig ist .
Ro75.
-
@ro75 Also mit der Batterieanzeige bin ich erst zufrieden und erst bei 8 Anzeigen noch übersichtlich. Aber je mehr man sich damit beschäftigt, desto mehr Lust bekommt man nach noch mehr. Ist etwas ansteckend das ganze
Ich denke nur an die zukünftigen Möglichkeiten, wie z.B. Visualisierung der Wärmepumpe und/oder Solaranlage. Dann wollte ich schon von Anfang an richtig machen.
Trotzdem Danke für den Hinweis. -
Alternative A
Du trägst das svg in ein html widget ein und ersetzt die punkt die mit der farbe aktualisier wird mit einem datenpunkt binding. problem ist, das bei änderung der komplette inhalt des html widgets neu geschrieben wird und das uU ebenfalls zu einer zeitverzögerung/flackern führt
in etwa so
<svg id="dynamic-svg" width="100" height="50" viewBox="0 0 350 175" xmlns="http://www.w3.org/2000/svg"> <defs> <linearGradient id="twoColors" x1="0%" y1="0%" x2="100%" y2="0%" gradientUnits="userSpaceOnUse"> <stop id="startColor" offset="50%" style="stop-color:{0_userdata.0.startcolor} stop-opacity:1" /> <stop id="middleColor" offset="50%" style="stop-color:#ffffff; stop-opacity:0.7" /> <stop id="endColor" offset="100%" style="stop-color:#ffffff; stop-opacity:0.7" /> </linearGradient> </defs> <rect x="0" y="0" width="325" height="175" rx="29" ry="29" fill="url(#twoColors)" /> <path d="M 330,57 h 6.5 a 13.5,13.5 0 0 1 13.5,13.5 v 34 a 13.5,13.5 0 0 1 -13.5,13.5 h -6.5 v -61 Z" fill="url(#twoColors)" /> </svg>
Alternative B
du fügst ebenfalls das svg in ein html widget, aber ohne datenpunkt bindings ein.
dann schreibst du ein javascript für den vis skript tab, der bei datenpunkt aktualisierung dann per javascript das objektmodell des svg adressiert und dann die farbei in das element einträgt.hier ist dazu ein beispiel
https://stackoverflow.com/questions/9872947/changing-svg-image-color-with-javascript
das ist meiner meinung nach die performanteste möglichkeit und dürfte nicht zum flackern führen. -
@oliverio das sind sehr interessante Ansätze. Ich werde das am WE mal testen und gib dann eine Rückmeldung.
Danke dir! -
@oliverio ich habe heute den ersten Anlauf gewagt.
Alternative 1: ich habe genau deinen Beispiel genommen und auch den Datenpunkt zum Testen angelegt und mit #ff0000 gefühlt. Leider bleibt die Batterie zur Hälfte schwarz eingefärbt. Keine Reaktion auf die Veränderungen der Farbe im Datenpunkt. Funktioniert dieses Bespiel bei dir?Alternative 2: ist schon etwas komplexer und übersteig momentan meine Fähigkeit.
Aber erstmal eine Frage zum Verständnis, bevor ich Zeit investiere um da durchzusteigen.
Wenn javascript die Farbe geändert hat, z.B. von rot auf grün, weil der Wert im Datenpunkt sich geändert hatte und dann die Seite neu geladen wird, dann ist die rote Ursprungsfarbe wieder aktiv, obwohl im Datenpunkt grün eingestellt ist, oder? Oder soll der Skript in einem Zeitintervall ausgeführt werden?Danke
-
also alternative 1 funktioniert bei mir
6771147b-2eb3-4ab3-9a11-b4e71702b9ab-20241101-1914-59.2944847.mp4<svg id="dynamic-svg" width="100" height="50" viewBox="0 0 350 175" xmlns="http://www.w3.org/2000/svg"> <defs> <linearGradient id="twoColors" x1="0%" y1="0%" x2="100%" y2="0%" gradientUnits="userSpaceOnUse"> <stop id="startColor" offset="50%" style="stop-color:{0_userdata.0.testFolder.color}; stop-opacity:1" /> <stop id="middleColor" offset="50%" style="stop-color:#ffffff; stop-opacity:0.7" /> <stop id="endColor" offset="100%" style="stop-color:#ffffff; stop-opacity:0.7" /> </linearGradient> </defs> <rect x="0" y="0" width="325" height="175" rx="29" ry="29" fill="url(#twoColors)" /> <path d="M 330,57 h 6.5 a 13.5,13.5 0 0 1 13.5,13.5 v 34 a 13.5,13.5 0 0 1 -13.5,13.5 h -6.5 v -61 Z" fill="url(#twoColors)" /> </svg>
alternative 2
ja da braucht man ein wenig, ich mach gleich mal ein beispiel, moment, ich aktualisiere dann diesen post
ok, 2.alternative funktioniert nicht in vis2, aus irgendeinem grund wird das binding, welches sich innerhalb eines script tags befindet nicht befüllt bzw aktualisiert wird.
also bleibt für vis 2 nur die alternative 1 -
@oliverio wegen alternative 2 sehr schaden, klang sehr vielversprechend.
Ich habe noch mal mit Binding versucht und es funktioniert doch, hatte wohl beim ersten Versuch irgendwo einen Fehler. Und ja, es ist ein leichtes Flackern beim Wechseln zwischen den Seiten zu erkennen, finde ich aber nicht so schlimm.
Ich habe die svg vervollständigt um die Varianten bewerten zu können.
Hier die vollständige svg:<style> @keyframes blink { 0%, 50% { visibility: visible; } 51%, 100% { visibility: hidden; } } #blinkingElement { animation: blink {0_userdata.0.Test_svg.blink}s infinite; } </style> <svg id="blinkingElement" width="100" height="50" viewBox="0 0 350 175" xmlns="http://www.w3.org/2000/svg"> <defs> <linearGradient id="twoColors" x1="0%" y1="0%" x2="100%" y2="0%" gradientUnits="userSpaceOnUse"> <stop offset="{0_userdata.0.Test_svg.batt}%" style="stop-color:{0_userdata.0.Test_svg.startcolor}; stop-opacity:1" /> <stop offset="{0_userdata.0.Test_svg.batt}%" style="stop-color:#ffffff; stop-opacity:0.7" /> <stop offset="100%" style="stop-color:#ffffff; stop-opacity:0.7" /> </linearGradient> </defs> <rect x="0" y="0" width="325" height="175" rx="29" ry="29" fill="url(#twoColors)" /> <path d="M 330,57 h 6.5 a 13.5,13.5 0 0 1 13.5,13.5 v 34 a 13.5,13.5 0 0 1 -13.5,13.5 h -6.5 v -61 Z" fill="url(#twoColors)" /> </svg>
Und hier JS der die Datenpunkte mit Farbe und Blinkintervall beschreibt:
// Funktion zur Auswahl der Farbe und Blinkdauer basierend auf dem Wert function getColorAndBlink(value) { let color = '#00ff00'; // Grün als Standardfarbe let blinkDuration = 0; // Keine Blinkdauer standardmäßig if (value <= 5) { color = '#ff0000'; // Rot blinkDuration = 1; // 1 Sekunde für Blinkdauer } else if (value <= 20) { color = '#ff8a00'; // Orange } return { color, blinkDuration }; } // Funktion zum Aktualisieren der Datenpunkte async function updateDataPoints(value) { const { color, blinkDuration } = getColorAndBlink(value); // Aktualisiere den Farb-Datenpunkt await setStateAsync('0_userdata.0.Test_svg.startcolor', color, true); // Aktualisiere den Blink-Datenpunkt await setStateAsync('0_userdata.0.Test_svg.blink', blinkDuration, true); } // Überwachen des Ladezustands-Datenpunkts auf Änderungen on({ id: '0_userdata.0.Test_svg.batt', change: "any" }, async (obj) => { const value = obj.state.val; // Wert des Ladezustands await updateDataPoints(value); // Aktualisiere Datenpunkte entsprechend });
ioBroker.vis - Google Chrome 2024-11-02 22-19-47.mp4
Ich muss sagen das diese Variante, zumindest für meine Anwendung, vergleichbar mit jetzigen Stand, eher nachteilig ist. Hier benötige ich trotzdem ein Code im JS-Adapter und zwei zusätzliche Datenpunkte. Und dieses kleine Flackern ist auch noch da.Aber trotzdem Danke für deine Unterstützung, ich möchte auch alle Möglichkeiten ausprobieren.