From b7481cac4be374f5ec3e07df3755beaeec73d734 Mon Sep 17 00:00:00 2001 From: rudolfkoenig <> Date: Wed, 18 May 2016 10:15:20 +0000 Subject: [PATCH] SVG.pm: log scale git-svn-id: https://svn.fhem.de/fhem/trunk@11478 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/98_SVG.pm | 125 ++++++++++++++++++++++++++++++------------- fhem/www/pgm2/svg.js | 31 +++++++---- 2 files changed, 111 insertions(+), 45 deletions(-) diff --git a/fhem/FHEM/98_SVG.pm b/fhem/FHEM/98_SVG.pm index a8601fe8e..d676b9574 100755 --- a/fhem/FHEM/98_SVG.pm +++ b/fhem/FHEM/98_SVG.pm @@ -187,6 +187,17 @@ SVG_isEmbed($) # $FW_userAgent !~ m/(iPhone|iPad|iPod).*OS (8|9)/)); } +sub +SVG_log10($) +{ + my ($n) = @_; + + return 0.0000000001 if( $n <= 0 ); + + return log($n)/log(10); +} + + ################## sub SVG_FwFn($$$$) @@ -292,7 +303,7 @@ SVG_cb($$$) { my ($v,$t,$c) = @_; $c = ($c ? " checked" : ""); - return "$t "; + return "$t "; } sub @@ -365,13 +376,17 @@ SVG_PEdit($$$$) $ret .= ""; $ret .= ""; $ret .= "Grid aligned"; - $ret .= SVG_cb("gridy", "left", $conf{hasygrid}); - $ret .= SVG_cb("gridy2","right",$conf{hasy2grid}); + $ret .= "".SVG_cb("gridy", "left", $conf{hasygrid}).""; + $ret .= "".SVG_cb("gridy2","right",$conf{hasy2grid}).""; $ret .= ""; $ret .= ""; $ret .= "Range as [min:max]"; - $ret .= "".SVG_txt("yrange", "left", $conf{yrange}, 16).""; - $ret .= "".SVG_txt("y2range", "right", $conf{y2range}, 16).""; + $ret .= "".SVG_txt("yrange", "left", $conf{yrange}, 16); + $ret .= "      ". + SVG_cb("yscale", "log", $conf{yscale}).""; + $ret .= "".SVG_txt("y2range", "right", $conf{y2range}, 16); + $ret .= "      ". + SVG_cb("y2scale", "log", $conf{y2scale}).""; $ret .= ""; if( $conf{xrange} ) { $ret .= ""; @@ -453,8 +468,8 @@ SVG_PEdit($$$$) $o .= $ph; $o .= ""; my $v = $conf{lAxis}[$idx]; - $o .= SVG_sel("axes_${idx}", "left,right", - ($v && $v eq "x1y1") ? "left" : "right"); + my $sel = ($v && $v eq "x1y1") ? "left" : "right"; + $o .= SVG_sel("axes_${idx}", "left,right,left log,right log", $sel ); $o .= SVG_sel("type_${idx}", "lines,points,steps,fsteps,histeps,bars,ibars,". "cubic,quadratic,quadraticSmooth", @@ -651,6 +666,8 @@ SVG_WriteGplot($) push @rows, "set xrange $FW_webArgs{xrange}" if($FW_webArgs{xrange}); push @rows, "set yrange $FW_webArgs{yrange}" if($FW_webArgs{yrange}); push @rows, "set y2range $FW_webArgs{y2range}" if($FW_webArgs{y2range}); + push @rows, "set yscale log" if($FW_webArgs{yscale}); + push @rows, "set y2scale log" if($FW_webArgs{y2scale}); push @rows, ""; my @plot; @@ -1671,33 +1688,38 @@ SVG_render($$$$$$$$$$) my $dh = $hmax{$a} - $hmin{$a}; my $hmul = $dh>0 ? $h/$dh : $h; + my $idx = 1; + $idx = $1 if( $a =~ m/x\d+y(\d+)/ ); + + my $scale = "y".($idx)."scale"; + $scale = "yscale" if( $idx == 1 ); + my $log = ""; + $log = $conf{$scale} if( $conf{$scale} ); + # offsets my ($align,$display,$cll); - if( $a =~ m/x1y(\d)/ ) { - my $idx = $1; - if( $idx <= $use_left_axis ) { - $off1 = $x - ($idx-1)*$axis_width-4-$th*0.3; - $off3 = $x - ($idx-1)*$axis_width-4; - $off4 = $off3+5; - $align = " text-anchor=\"end\""; - $display = ""; - $cll = ""; - } elsif( $idx <= $use_left_axis+$use_right_axis ) { - $off1 = $x+4+$w+($idx-1-$use_left_axis)*$axis_width+$th*0.3; - $off3 = $x+4+$w+($idx-1-$use_left_axis)*$axis_width-5; - $off4 = $off3+5; - $align = ""; - $display = ""; - $cll = ""; - } else { - $off1 = $x-$th*0.3+30; - $off3 = $x+30; - $off4 = $off3+5; - $align = " text-anchor=\"end\""; - $display = " display=\"none\" id=\"hline_$idx\""; - $cll = " class=\"SVGplot l$idx\""; - } - }; + if( $idx <= $use_left_axis ) { + $off1 = $x - ($idx-1)*$axis_width-4-$th*0.3; + $off3 = $x - ($idx-1)*$axis_width-4; + $off4 = $off3+5; + $align = " text-anchor=\"end\""; + $display = ""; + $cll = ""; + } elsif( $idx <= $use_left_axis+$use_right_axis ) { + $off1 = $x+4+$w+($idx-1-$use_left_axis)*$axis_width+$th*0.3; + $off3 = $x+4+$w+($idx-1-$use_left_axis)*$axis_width-5; + $off4 = $off3+5; + $align = ""; + $display = ""; + $cll = ""; + } else { + $off1 = $x-$th*0.3+30; + $off3 = $x+30; + $off4 = $off3+5; + $align = " text-anchor=\"end\""; + $display = " display=\"none\" id=\"hline_$idx\""; + $cll = " class=\"SVGplot l$idx\""; + } #-- grouping SVG_pO ""; @@ -1712,13 +1734,21 @@ SVG_render($$$$$$$$$$) #-- tics as in the config-file if($tic && $tic !~ m/mirror/) { $tic =~ s/^\((.*)\)$/$1/; # Strip () + for(my $decimal = 0; + $decimal < ($log eq 'log'?SVG_log10($hmax{$a}):1); + $decimal++ ) { + my $f = SVG_log10($hmax{$a}) / $hmax{$a}; foreach my $onetic (split(",", $tic)) { $onetic =~ s/^ *(.*) *$/$1/; my ($tlabel, $tvalue) = split(" ", $onetic); $tlabel =~ s/^"(.*)"$/$1/; $tvalue = 0 if( !$tvalue ); + $tvalue /= 10 ** $decimal; + $tlabel = $tvalue if( !$tlabel ); $off2 = int($y+($hmax{$a}-$tvalue)*$hmul); + $off2 = int($y+($hmax{$a}-SVG_log10($tvalue)/$f)*$hmul) + if( $log eq 'log' ); #-- tics SVG_pO ""; #--grids @@ -1732,12 +1762,20 @@ SVG_render($$$$$$$$$$) } $off2 += $th/4; #-- text - SVG_pO "$tlabel"; + SVG_pO + "$tlabel"; + } } #-- tics automatically } elsif( $hstep{$a}>0 ) { + for(my $decimal = 0; + $decimal < ($log eq 'log'?SVG_log10($hmax{$a}):1); + $decimal++ ) { + my $f = SVG_log10($hmax{$a}) / $hmax{$a}; for(my $i = $hmin{$a}; $i <= $hmax{$a}; $i += $hstep{$a}) { + my $i = $i / 10 ** $decimal; $off2 = int($y+($hmax{$a}-$i)*$hmul); + $off2 = int($y+($hmax{$a}-SVG_log10($i)/$f)*$hmul) if( $log eq 'log' ); #-- tics SVG_pO " "; #--grids @@ -1753,7 +1791,9 @@ SVG_render($$$$$$$$$$) $off2 += $th/4; #-- text my $txt = sprintf("%g", $i); - SVG_pO "$txt"; + SVG_pO + "$txt"; + } } } SVG_pO ""; @@ -1764,6 +1804,10 @@ SVG_render($$$$$$$$$$) # Second loop over the data: draw the measured points for(my $idx=$#hdx; $idx >= 0; $idx--) { my $a = $conf{lAxis}[$idx]; + my $scale = "y".($idx+1)."scale"; + $scale = "yscale" if( $idx == 0 ); + my $log = ""; + $log = $conf{$scale} if( $conf{$scale} ); SVG_pO "" if(!defined($a)); @@ -1778,6 +1822,13 @@ SVG_render($$$$$$$$$$) SVG_pO "" if(!defined($dxp)); next if(!defined($dxp)); + if( $log eq 'log' ) { + my $f = SVG_log10($hmax{$a}) / $hmax{$a}; + foreach my $i (1..int(@{$dxp})-1) { + $dyp->[$i] = SVG_log10($dyp->[$i]) / $f; + } + } + my $yh = $y+$h; #-- Title attributes my $tl = $conf{lTitle}[$idx] ? $conf{lTitle}[$idx] : ""; @@ -1785,8 +1836,11 @@ SVG_render($$$$$$$$$$) my $dec = length(sprintf("%d",$hmul*3))-1; $dec = 0 if($dec < 0); my $attributes = "id=\"line_$idx\" decimals=\"$dec\" ". - "x_off=\"$fromsec\" x_min=\"$x\" x_mul=\"$tmul\" ". + "x_min=\"$x\" ". + ($conf{xrange}?"x_off=\"$xmin\" ":"x_off=\"$fromsec\" "). + ($conf{xrange}?"x_mul=\"$xmul\" ":"t_mul=\"$tmul\" "). "y_h=\"$yh\" y_min=\"$min\" y_mul=\"$hmul\" title=\"$tl\" ". + ($log eq 'log'?"log_scale=\"".SVG_log10($hmax{$a})/$hmax{$a}."\" ":""). "onclick=\"parent.svg_click(evt)\" $conf{lWidth}[$idx]"; my $lStyle = $conf{lStyle}[$idx]; my $isFill = ($conf{lStyle}[$idx] =~ m/fill/); @@ -1965,7 +2019,6 @@ SVG_render($$$$$$$$$$) next if($x1 == $lx && $y1 == $ly); - # calc ymin/ymax for points with the same x coordinates if($x1 == $lx && $i < $maxIdx) { $ymin = $y1 if($y1 < $ymin); diff --git a/fhem/www/pgm2/svg.js b/fhem/www/pgm2/svg.js index 5cbe871d7..682fa2721 100644 --- a/fhem/www/pgm2/svg.js +++ b/fhem/www/pgm2/svg.js @@ -42,7 +42,8 @@ svg_load(key, nextFn) function svg_prepareHash(el) { - var obj = { y_mul:0,y_h:0,y_min:0, decimals:0, x_mul:0,x_off:0,x_min:0 }; + var obj = { y_mul:0,y_h:0,y_min:0, decimals:0, + t_mul:0,x_off:0,x_min:0, x_mul:0, log_scale:undefined }; for(var name in obj) obj[name] = parseFloat($(el).attr(name)); return obj; @@ -55,7 +56,7 @@ svg_click(evt) var o = svg_prepareHash(t); var y_org = (((o.y_h-evt.clientY)/o.y_mul)+o.y_min).toFixed(o.decimals); - var d = new Date((((evt.clientX-o.x_min)/o.x_mul)+o.x_off) * 1000); + var d = new Date((((evt.clientX-o.x_min)/o.t_mul)+o.x_off) * 1000); var ts = (d.getHours() < 10 ? '0' : '') + d.getHours() + ":"+ (d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); @@ -254,15 +255,27 @@ sv_menu(evt, embed) var xR = (xRaw-pp.x)/(pn.x-pp.x); // Compute interim values var yRaw = pp.y+xR*(pn.y-pp.y); - var y = (((par.y_h-yRaw)/par.y_mul)+par.y_min).toFixed(par.decimals); + var y = (((par.y_h-yRaw)/par.y_mul)+par.y_min); + + if( par.log_scale ) { + y *= par.log_scale; + y = Math.pow(10,y); + } + + y = y.toFixed(par.decimals); + + if( par.x_mul ) { + ts = (((xRaw-par.x_min)/par.x_mul)+par.x_off).toFixed(par.decimals); - var d = new Date((((xRaw-par.x_min)/par.x_mul)+par.x_off) * 1000), ts; - if(par.x_mul < 0.0001) { // Year - ts = (d.getMonth()+1)+"."+pad0(d.getDate()); - } else if(par.x_mul < 0.001) { // Month - ts = d.getDate()+". "+pad0(d.getHours())+":"+pad0(d.getMinutes()); } else { - ts = pad0(d.getHours())+":"+pad0(d.getMinutes()); + var d = new Date((((xRaw-par.x_min)/par.t_mul)+par.x_off) * 1000), ts; + if(par.t_mul < 0.0001) { // Year + ts = (d.getMonth()+1)+"."+pad0(d.getDate()); + } else if(par.t_mul < 0.001) { // Month + ts = d.getDate()+". "+pad0(d.getHours())+":"+pad0(d.getMinutes()); + } else { + ts = pad0(d.getHours())+":"+pad0(d.getMinutes()); + } } $(par.circle).attr("cx", xRaw).attr("cy", yRaw);