neue svg-Funktionen: icon_ring, icon_bar, cylinder_bars, icon_ring2

Begonnen von Damian, 30 Januar 2021, 20:03:18

Vorheriges Thema - Nächstes Thema

Damian

Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Sany

Hallo Damian,

mal wieder großes Lob und vielen Dank für die ständige Weiterentwicklung von DOIF, speziell jetzt uiTable. Die SVGs ring und cylinder/balken sehen immer besser aus, jetzt vor allem mit den Icons. Das spart "Erklärtext".
Ich habe schon vor eine Weile rumprobiert, wie ich die Werteanzeigen meiner Meinung nach besser darstellen kann: große Zahlen vor dem Punkt und etwas kleiner die Nachkommastellen. Im Anhang mal ein Bild, wie das aussieht.
Ich habe mir dann deine Funktionen abgeändert, z.B. style, wie in der Zeile "Zähler" zu sehen. Bisher war es so, dass der Wert, der an die Funktion übergeben wird, im richtigen Format sein muss (hier eben mit Nachkommastellen, eine Ganzzahl hätte einen Punkt.
Bei den beiden Ringen für Wasser und Strom ist es jetzt eine modifizierte ring-funktion, wo es egal ist, wie der Eingangswert aussieht, also so wie im Original.
Basiert auf "98_DOIF.pm             23744 2021-02-14 20:12:01Z Damian"

So sieht die aus:
sub my_ring
{
  my ($val,$min,$max,$minColor,$maxColor,$unit,$size,$func,$dec,$model,$lr,$ln,$icon) = @_;
  my $out;

  my ($ic,$iscale,$ix,$iy)=();

  if (defined ($icon)) {
    ($ic,$iscale,$ix,$iy,)=split(",",$icon);
    if (defined ($ix)) {
      $ix+=30;
    } else {
      $ix=30;
    };
    if (defined ($iy)) {
      $iy+=9;
    } else {
      $iy=9;
    };
    $iscale=1 if (!defined($iscale));
    $ic="" if (!defined($ic));
  }
   
  my ($format,$value);
  if (defined $lr) {
    if (!defined $ln) {
       $ln=$lr;
    }
  }
  $min=0 if (!defined $min);
  $max=100 if (!defined $max);

  $dec=1 if (!defined $dec);

  ($format,$value,$val)=format_value($val,$min,$dec);

  if (defined $func) {
    $minColor=&{$func}($min);
    $maxColor=&{$func}($max);
  } else {
    $minColor=120 if (!defined $minColor);
    $maxColor=0 if (!defined $maxColor);
  }
  $max=$value if($value>$max);
  $min=$value if ($value<$min);
  $size=100 if (!defined $size);
  my $prop=($value-$min)/($max-$min);
  my ($x1,$y1,$x2,$y2);
  ($x1,$y1,$x2,$y2)=($prop*100,0,0,(1-$prop)*100);
  my $val1=int($prop*100)+20;
  my $currColor;
  if (defined $func) {
    if (defined($model)) {
      $minColor=&{$func}($value);
    }
    $currColor=&{$func}($value);
  } else {
    if ($minColor < $maxColor) {
      $currColor=$prop*($maxColor-$minColor)+$minColor;
    } else {
      $currColor=(1-$prop)*($minColor-$maxColor)+$maxColor;
    }
    if (defined($model)) {
      $minColor=$currColor;
    }
  }
  if (defined $icon and $icon ne "") {


   

    $ic="$ic\@".color($currColor,$ln) if ($icon !~ /@/);
  }

  $out.= sprintf('<svg xmlns="http://www.w3.org/2000/svg" viewBox="10 0 63 58 " style="width:%dpx; height:%dpx;">',$size/100*63,$size/100*58);
  $out.= '<defs>';
  $out.= '<linearGradient id="gradbackring" x1="0" y1="1" x2="0" y2="0"><stop offset="0" style="stop-color:rgb(64,64,64);stop-opacity:0.8"/><stop offset="1" style="stop-color:rgb(32, 32, 32);stop-opacity:0.9"/></linearGradient>';
  $out.= sprintf('<linearGradient id="grad_ring1_%d_%d_%d" x1="%d%%" y1="%d%%" x2="%d%%" y2="%d%%"><stop offset="0" style="stop-color:%s; stop-opacity:1"/>\
  <stop offset="1" style="stop-color:%s;stop-opacity:0.5"/></linearGradient>',$currColor,$minColor,(defined $lr ? $lr:0),$x1,$y1,$x2,$y2,color($currColor,$lr),color($minColor,$lr));

  $out.= '<linearGradient id="grad_stroke3" x1="1" y1="0" x2="0" y2="0"><stop offset="0" style="stop-color:rgb(80,80,80); stop-opacity:0.6"/>\
  <stop offset="1" style="stop-color:rgb(48,48,48); stop-opacity:0.8"/><linearGradient>';
  $out.='</defs>';

  $out.='<circle cx="41" cy="30" r="26.5" fill="url(#gradbackring)" />';
  $out.='<g stroke="url(#grad_stroke3)" fill="none" stroke-width="4">';
  $out.=describeArc(41, 30, 28, 0, 280);
  $out.='</g>';
  $out.=sprintf('<g stroke="url(#grad_ring1_%d_%d_%d)" fill="none" stroke-width="3">',$currColor,$minColor,(defined $lr ? $lr:0));
  $out.=describeArc(41, 30, 27.5, 0, int($prop*280));
  $out.='</g>';
  if (defined $icon and $icon ne "" and  $icon ne " ") {
    $out.='<symbol id="Image_'.$ic.'" x="'.$ix.'" y="'.$iy.'" viewBox="0 0 '.int(640/$iscale).' '.int(640/$iscale).'">';
    $out.= ::FW_makeImage($ic);
    $out.='</symbol>';
    ##$out.='<g stroke="rgb(128,128,128)" >';
    $out.='<use href="#Image_'.$ic.'" height="22" width="22" />';#height="18" width="18"
    ##$out.='</g>';
  }
##################################################
  if ($val !~ /(-?\d+\.\d+)/) {
     #### diese Zeile entspricht dem Original (bis auf font-weight gelöscht)
     $out.= sprintf('<text text-anchor="middle" x="41" y="%s" style="fill:%s;font-size:%spx;">%s</text>',((defined ($icon) and $icon ne "") ? 43:34),color($currColor,$ln),(defined ($icon) ? 14:18),sprintf($format,$val)); ## font-weight:thin;

  } else {
 
my $valInt = 0;
my $valDec = 0;
($valInt,$valDec) = split(/\./,$val);
  $out.= sprintf('<text text-anchor="middle" x="41" y="%s" style="fill:%s;font-size:%spx;"><tspan>%s<tspan dx="-1" dy="0" style="fill:%s;font-size:70%%;font-weight:thin;">.%s</tspan></text>',(defined ($icon) ? 43:34),color($currColor,$ln),(defined ($icon) ? 14:18),$valInt,color($currColor,$ln),$valDec); ## font-weight:thin;
 
  }
##################################################    
 
  $out.= sprintf('<text text-anchor="middle" x="41" y="%s" style="fill:%s;font-size:10px;">%s</text>',((defined ($icon) and $icon ne "") ? 53:47),color($currColor,$ln),$unit) if (defined $unit);
  $out.= '</svg>';
  return ($out);
}


Ich habe markiert, was geändert ist.
Vielleicht gefällt es Dir ja und weil Du ja eh gerade alles überarbeitest vielleicht hast Du ja Lust, das zu übernehmen.

Viele Grüße

Sany
fhem auf Zotac ZBox nano als LXC auf Proxmox, weitere LXC mit ZigBee2MQTT, MariaDB und Grafana. Homematic, FS20, mySensors, MQTT2, Tasmota, Shelly, Z-Wave  ....

xenos1984

Zitat von: Damian am 17 Februar 2021, 14:08:50
Da gibt es ganz viel von:

https://forum.fhem.de/index.php/topic,12605.msg795076.html#msg795076

Oh, die kannte ich tatsächlich nicht - wieder etwas dazu gelernt.

Wie ich vermutet hatte, die Datei hat tatsächlich kein width und kein height. Vielleicht in dem Fall so ein Ansatz?


    my $svg_icon=::FW_makeImage($ic);
    if(!($svg_icon =~ s/height="[^"]*"/height="22"/)) {
        $svg_icon =~ s/svg/svg height="22"/ }
    if(!($svg_icon =~ s/width="[^"]*"/width="22"/)) {
        $svg_icon =~ s/svg/svg width="22"/ }
    $out.='<g transform="translate('.$ix.', '.$iy.') translate(11, 11) scale('.$iscale.') translate(-11, -11)">';
    $out.= $svg_icon;
    $out.='</g>';


Wenn kein width / height vorhanden sind, wird ins svn Tag eins eingebaut.

Damian

Zitat von: Sany am 17 Februar 2021, 14:13:30
Hallo Damian,

mal wieder großes Lob und vielen Dank für die ständige Weiterentwicklung von DOIF, speziell jetzt uiTable. Die SVGs ring und cylinder/balken sehen immer besser aus, jetzt vor allem mit den Icons. Das spart "Erklärtext".
Ich habe schon vor eine Weile rumprobiert, wie ich die Werteanzeigen meiner Meinung nach besser darstellen kann: große Zahlen vor dem Punkt und etwas kleiner die Nachkommastellen. Im Anhang mal ein Bild, wie das aussieht.
Ich habe mir dann deine Funktionen abgeändert, z.B. style, wie in der Zeile "Zähler" zu sehen. Bisher war es so, dass der Wert, der an die Funktion übergeben wird, im richtigen Format sein muss (hier eben mit Nachkommastellen, eine Ganzzahl hätte einen Punkt.
Bei den beiden Ringen für Wasser und Strom ist es jetzt eine modifizierte ring-funktion, wo es egal ist, wie der Eingangswert aussieht, also so wie im Original.
Basiert auf "98_DOIF.pm             23744 2021-02-14 20:12:01Z Damian"

So sieht die aus:
sub my_ring
{
  my ($val,$min,$max,$minColor,$maxColor,$unit,$size,$func,$dec,$model,$lr,$ln,$icon) = @_;
  my $out;

  my ($ic,$iscale,$ix,$iy)=();

  if (defined ($icon)) {
    ($ic,$iscale,$ix,$iy,)=split(",",$icon);
    if (defined ($ix)) {
      $ix+=30;
    } else {
      $ix=30;
    };
    if (defined ($iy)) {
      $iy+=9;
    } else {
      $iy=9;
    };
    $iscale=1 if (!defined($iscale));
    $ic="" if (!defined($ic));
  }
   
  my ($format,$value);
  if (defined $lr) {
    if (!defined $ln) {
       $ln=$lr;
    }
  }
  $min=0 if (!defined $min);
  $max=100 if (!defined $max);

  $dec=1 if (!defined $dec);

  ($format,$value,$val)=format_value($val,$min,$dec);

  if (defined $func) {
    $minColor=&{$func}($min);
    $maxColor=&{$func}($max);
  } else {
    $minColor=120 if (!defined $minColor);
    $maxColor=0 if (!defined $maxColor);
  }
  $max=$value if($value>$max);
  $min=$value if ($value<$min);
  $size=100 if (!defined $size);
  my $prop=($value-$min)/($max-$min);
  my ($x1,$y1,$x2,$y2);
  ($x1,$y1,$x2,$y2)=($prop*100,0,0,(1-$prop)*100);
  my $val1=int($prop*100)+20;
  my $currColor;
  if (defined $func) {
    if (defined($model)) {
      $minColor=&{$func}($value);
    }
    $currColor=&{$func}($value);
  } else {
    if ($minColor < $maxColor) {
      $currColor=$prop*($maxColor-$minColor)+$minColor;
    } else {
      $currColor=(1-$prop)*($minColor-$maxColor)+$maxColor;
    }
    if (defined($model)) {
      $minColor=$currColor;
    }
  }
  if (defined $icon and $icon ne "") {


   

    $ic="$ic\@".color($currColor,$ln) if ($icon !~ /@/);
  }

  $out.= sprintf('<svg xmlns="http://www.w3.org/2000/svg" viewBox="10 0 63 58 " style="width:%dpx; height:%dpx;">',$size/100*63,$size/100*58);
  $out.= '<defs>';
  $out.= '<linearGradient id="gradbackring" x1="0" y1="1" x2="0" y2="0"><stop offset="0" style="stop-color:rgb(64,64,64);stop-opacity:0.8"/><stop offset="1" style="stop-color:rgb(32, 32, 32);stop-opacity:0.9"/></linearGradient>';
  $out.= sprintf('<linearGradient id="grad_ring1_%d_%d_%d" x1="%d%%" y1="%d%%" x2="%d%%" y2="%d%%"><stop offset="0" style="stop-color:%s; stop-opacity:1"/>\
  <stop offset="1" style="stop-color:%s;stop-opacity:0.5"/></linearGradient>',$currColor,$minColor,(defined $lr ? $lr:0),$x1,$y1,$x2,$y2,color($currColor,$lr),color($minColor,$lr));

  $out.= '<linearGradient id="grad_stroke3" x1="1" y1="0" x2="0" y2="0"><stop offset="0" style="stop-color:rgb(80,80,80); stop-opacity:0.6"/>\
  <stop offset="1" style="stop-color:rgb(48,48,48); stop-opacity:0.8"/><linearGradient>';
  $out.='</defs>';

  $out.='<circle cx="41" cy="30" r="26.5" fill="url(#gradbackring)" />';
  $out.='<g stroke="url(#grad_stroke3)" fill="none" stroke-width="4">';
  $out.=describeArc(41, 30, 28, 0, 280);
  $out.='</g>';
  $out.=sprintf('<g stroke="url(#grad_ring1_%d_%d_%d)" fill="none" stroke-width="3">',$currColor,$minColor,(defined $lr ? $lr:0));
  $out.=describeArc(41, 30, 27.5, 0, int($prop*280));
  $out.='</g>';
  if (defined $icon and $icon ne "" and  $icon ne " ") {
    $out.='<symbol id="Image_'.$ic.'" x="'.$ix.'" y="'.$iy.'" viewBox="0 0 '.int(640/$iscale).' '.int(640/$iscale).'">';
    $out.= ::FW_makeImage($ic);
    $out.='</symbol>';
    ##$out.='<g stroke="rgb(128,128,128)" >';
    $out.='<use href="#Image_'.$ic.'" height="22" width="22" />';#height="18" width="18"
    ##$out.='</g>';
  }
##################################################
  if ($val !~ /(-?\d+\.\d+)/) {
     #### diese Zeile entspricht dem Original (bis auf font-weight gelöscht)
     $out.= sprintf('<text text-anchor="middle" x="41" y="%s" style="fill:%s;font-size:%spx;">%s</text>',((defined ($icon) and $icon ne "") ? 43:34),color($currColor,$ln),(defined ($icon) ? 14:18),sprintf($format,$val)); ## font-weight:thin;

  } else {
 
my $valInt = 0;
my $valDec = 0;
($valInt,$valDec) = split(/\./,$val);
  $out.= sprintf('<text text-anchor="middle" x="41" y="%s" style="fill:%s;font-size:%spx;"><tspan>%s<tspan dx="-1" dy="0" style="fill:%s;font-size:70%%;font-weight:thin;">.%s</tspan></text>',(defined ($icon) ? 43:34),color($currColor,$ln),(defined ($icon) ? 14:18),$valInt,color($currColor,$ln),$valDec); ## font-weight:thin;
 
  }
##################################################    
 
  $out.= sprintf('<text text-anchor="middle" x="41" y="%s" style="fill:%s;font-size:10px;">%s</text>',((defined ($icon) and $icon ne "") ? 53:47),color($currColor,$ln),$unit) if (defined $unit);
  $out.= '</svg>';
  return ($out);
}


Ich habe markiert, was geändert ist.
Vielleicht gefällt es Dir ja und weil Du ja eh gerade alles überarbeitest vielleicht hast Du ja Lust, das zu übernehmen.

Viele Grüße

Sany

ja, aber damit wäre die Funktion nicht abwärtskompatibel, da ja alle Kommazahlen dann anders dargestellt wären.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

Damian

Zitat von: xenos1984 am 17 Februar 2021, 14:21:03
Oh, die kannte ich tatsächlich nicht - wieder etwas dazu gelernt.

Wie ich vermutet hatte, die Datei hat tatsächlich kein width und kein height. Vielleicht in dem Fall so ein Ansatz?


    my $svg_icon=::FW_makeImage($ic);
    if(!($svg_icon =~ s/height="[^"]*"/height="22"/)) {
        $svg_icon =~ s/svg/svg height="22"/ }
    if(!($svg_icon =~ s/width="[^"]*"/width="22"/)) {
        $svg_icon =~ s/svg/svg width="22"/ }
    $out.='<g transform="translate('.$ix.', '.$iy.') translate(11, 11) scale('.$iscale.') translate(-11, -11)">';
    $out.= $svg_icon;
    $out.='</g>';


Wenn kein width / height vorhanden sind, wird ins svn Tag eins eingebaut.

fast, damit würde sogar mein Android 4.3 Wandtablet funktionieren, wenn es da nicht Icons gäbe, die man wieder besonders behandeln müsste z. B. das von mir gebastelte Icon "fuel", was zum FHEM-Standard gehört.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

xenos1984

Zitat von: Damian am 17 Februar 2021, 15:23:14
fast, damit würde sogar mein Android 4.3 Wandtablet funktionieren, wenn es da nicht Icons gäbe, die man wieder besonders behandeln müsste z. B. das von mir gebastelte Icon "fuel", was zum FHEM-Standard gehört.

Mühsam ernährt sich das Eichhörnchen... Ja, fuel hat kein width / height, aber später im Icon inkscape:window-width="... Gut, dann muss man wohl auf ein reines width / height ohne etwas davor testen...


    my $svg_icon=::FW_makeImage($ic);
    if(!($svg_icon =~ s/\sheight="[^"]*"/ height="22"/)) {
        $svg_icon =~ s/svg/svg height="22"/ }
    if(!($svg_icon =~ s/\swidth="[^"]*"/ width="22"/)) {
        $svg_icon =~ s/svg/svg width="22"/ }
    $out.='<g transform="translate('.$ix.', '.$iy.') translate(11, 11) scale('.$iscale.') translate(-11, -11)">';
    $out.= $svg_icon;
    $out.='</g>';


Damit wird nur noch ersetzt, wenn vor dem Attribut ein \s Zeichen kommt.

Damian

Zitat von: xenos1984 am 17 Februar 2021, 15:40:00
Mühsam ernährt sich das Eichhörnchen... Ja, fuel hat kein width / height, aber später im Icon inkscape:window-width="... Gut, dann muss man wohl auf ein reines width / height ohne etwas davor testen...


    my $svg_icon=::FW_makeImage($ic);
    if(!($svg_icon =~ s/\sheight="[^"]*"/ height="22"/)) {
        $svg_icon =~ s/svg/svg height="22"/ }
    if(!($svg_icon =~ s/\swidth="[^"]*"/ width="22"/)) {
        $svg_icon =~ s/svg/svg width="22"/ }
    $out.='<g transform="translate('.$ix.', '.$iy.') translate(11, 11) scale('.$iscale.') translate(-11, -11)">';
    $out.= $svg_icon;
    $out.='</g>';


Damit wird nur noch ersetzt, wenn vor dem Attribut ein \s Zeichen kommt.

OK. Jetzt noch alle anderen Icons durchtesten (vor allem die animierten Wetter-Icons) und dann kann ich einchecken. Ich sag ja, die Patcherei hinterlässt bei mir kein gutes Bauchgefühl, aber ist besser als die bisherige Lösung.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

xenos1984

Zitat von: Damian am 17 Februar 2021, 15:59:06
OK. Jetzt noch alle anderen Icons durchtesten (vor allem die animierten Wetter-Icons) und dann kann ich einchecken. Ich sag ja, die Patcherei hinterlässt bei mir kein gutes Bauchgefühl, aber ist besser als die bisherige Lösung.

Geht mir ähnlich. Annahmen an Eingaben (in dem Fall die Original-SVG) zu machen ist nie schön.

Noch eine andere Frage: Wäre es möglich, eine logarithmische Skalierung einzubauen, oder wäre die mit dem aktuellen Code schon möglich? Mein typischer Anwendungsfall wäre eine Anzeige der Netzwerkdatenrate. Wenn man da eine lineare Skala bis z.B. 100 MB/s hat, sieht man unter 1 MB/s praktisch keinen Unterschied mehr.

(Man könnte natürlich als numerischen Wert den Logarithmus an icon_ring übergeben, aber dann wird eben auch der als Zahl angezeigt und nicht mehr der eigentlich gewünschte Zahlenwert.)

Damian

Animierte SVG-Icons z. B. "cloudy" funktionieren auch.

Für logarithmische Anzeige könntest du den maximalen Wert, als Parameter der SVG-Funktion nicht fest vorgeben, sondern über eine Logarithmusfunktion abhängig vom Wert bestimmen. Auch die Farbfunktion kannst du selbst programmieren und als Parameter übergeben. Intern wird aber linear skaliert.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

xenos1984

Zitat von: Damian am 17 Februar 2021, 19:01:32
Für logarithmische Anzeige könntest du den maximalen Wert, als Parameter der SVG-Funktion nicht fest vorgeben, sondern über eine Logarithmusfunktion abhängig vom Wert bestimmen. Auch die Farbfunktion kannst du selbst programmieren und als Parameter übergeben. Intern wird aber linear skaliert.

Gute Idee, funktioniert perfekt! :)

Damian

Ich habe die Icon-Darstellung bei den icon_bar-Funktionen gleichgezogen und neue DOIF-Version eingecheckt.
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

xenos1984

Zitat von: Damian am 17 Februar 2021, 19:38:49
Ich habe die Icon-Darstellung bei den icon_bar-Funktionen gleichgezogen und neue DOIF-Version eingecheckt.

Danke - sieht gut aus! Jetzt machen Wetteranzeige und Computerstatus gleich mehr her 8)

Damian

Zitat von: xenos1984 am 18 Februar 2021, 08:05:15
Danke - sieht gut aus! Jetzt machen Wetteranzeige und Computerstatus gleich mehr her 8)

Es ist aber ziemlich kalt bei dir :)
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF

xenos1984

Zitat von: Damian am 18 Februar 2021, 08:21:27
Es ist aber ziemlich kalt bei dir :)

Oh ja - aber nicht ungewöhnlich für den Winter in Tartu / Estland ;) Bis -30°C habe ich schon erlebt. Meistens hält es nicht lange an, unter -20°C selten mehr als ein paar Tage, aber -15°C durchaus mal ein paar Wochen.

Damian

Zitat von: xenos1984 am 18 Februar 2021, 09:59:14
Oh ja - aber nicht ungewöhnlich für den Winter in Tartu / Estland ;) Bis -30°C habe ich schon erlebt. Meistens hält es nicht lange an, unter -20°C selten mehr als ein paar Tage, aber -15°C durchaus mal ein paar Wochen.

Dann dauert es bei dir noch bis ein Frühlingsgefühl aufkommt - bei uns sind am Wochenende +17°C mit Sonnenschein angesagt, dann werden sich meine Ringe eher gelb verfärben :)
Programmierte FHEM-Module: DOIF-FHEM, DOIF-Perl, DOIF-uiTable, THRESHOLD, FHEM-Befehl: IF