############################################## package main; use strict; use warnings; use POSIX; #use Devel::Size qw(size total_size); sub SVG_render($$$$$$); sub time_to_sec($); sub fmtTime($$); my ($__lt, $__ltstr); ##################################### sub SVG_Initialize($) { my ($hash) = @_; } ##################################### sub SVG_render($$$$$$) { my $name = shift; # e.g. wl_8 my $from = shift; # e.g. 2008-01-01 my $to = shift; # e.g. 2009-01-01 my $confp = shift; # lines from the .gplot file, w/o FileLog and plot my $dp = shift; # pointer to data (one string) my $plot = shift; # Plot lines from the .gplot file return "" if(!defined($dp)); my $th = 16; # "Font" height my ($x, $y) = (3*$th, 1.2*$th); # Rect offset my %conf; # gnuplot file settings # Convert the configuration to a "readable" form -> array to hash map { chomp; my @a=split(" ",$_, 3); if($a[0] && $a[0] eq "set") { $conf{$a[1]} = $a[2]; } } @{$confp}; my $ps = "800,400"; $ps = $1 if($conf{terminal} =~ m/.*size[ ]*([^ ]*)/); $conf{title} =~ s/'//g; my ($ow,$oh) = split(",", $ps); # Original width my ($w, $h) = ($ow-2*$x, $oh-2*$y); # Rect size # Html Header pO ""; pO ""; pO ""; pO ""; pO ""; return; } if(!$tmul) { # recompute the x data if no range sepcified $fromsec = time_to_sec($dxp->[0]) if(!$fromsec); $tosec = time_to_sec($dxp->[int(@{$dxp})-1]) if(!$tosec); $tmul = $w/($tosec-$fromsec); for my $i (0..@hdx-1) { $dxp = $hdx[$i]; for my $i (0..@{$dxp}-1) { $dxp->[$i] = int((time_to_sec($dxp->[$i])-$fromsec)*$tmul); } } } # Compute & draw vertical tics, grid and labels my $ddur = ($tosec-$fromsec)/86400; my ($first_tag, $tag, $step, $tstep, $aligntext, $aligntics); if($ddur <= 0.5) { $first_tag=". 2 1"; $tag=": 3 4"; $step = 3600; $tstep = 900; } elsif($ddur <= 1) { $first_tag=". 2 1"; $tag=": 3 4"; $step = 4*3600; $tstep = 3600; } elsif ($ddur <= 7) { $first_tag=". 6"; $tag=". 2 1"; $step = 24*3600; $tstep = 6*3600; } elsif ($ddur <= 31) { $first_tag=". 6"; $tag=". 2 1"; $step = 7*24*3600; $tstep = 24*3600; $aligntext = 1; } else { $first_tag=". 6"; $tag=". 1"; $step = 28*24*3600; $tstep = 28*24*3600; $aligntext = 2; $aligntics = 2; } # First the tics $off2 = $y+4; my ($off3, $off4) = ($y+$h-4, $y+$h); my $initoffset = $tstep; $initoffset = int(($tstep/2)/86400)*86400 if($aligntics); for(my $i = $fromsec+$initoffset; $i < $tosec; $i += $tstep) { $i = time_align($i,$aligntics); $off1 = int($x+($i-$fromsec)*$tmul); pO ""; pO ""; } # then the text and the grid $off1 = $x; $off2 = $y+$h+$th; $t = fmtTime($first_tag, $fromsec); pO "$t"; $initoffset = $step; $initoffset = int(($step/2)/86400)*86400 if($aligntext); for(my $i = $fromsec+$initoffset; $i < $tosec; $i += $step) { $i = time_align($i,$aligntext); $off1 = int($x+($i-$fromsec)*$tmul); $t = fmtTime($tag, $i); pO "$t"; pO " "; } # Left and right axis tics / text / grid $hmin{x1y1}=$hmin{x1y2}, $hmax{x1y1}=$hmax{x1y2} if(!defined($hmin{x1y1})); $hmin{x1y2}=$hmin{x1y1}, $hmax{x1y2}=$hmax{x1y1} if(!defined($hmin{x1y2})); for my $axis ("x1y1", "x1y2") { # Round values, compute a nice step next if(!defined($hmax{$axis})); # yrange handling my $yr = ($axis eq "x1y1" ? "yrange" : "y2range"); if($conf{$yr} && $conf{$yr} =~ /\[(.*):(.*)\]/) { $hmin{$axis} = $1 if($1 ne ""); $hmax{$axis} = $2 if($2 ne ""); } my $dh = $hmax{$axis} - $hmin{$axis}; my ($step, $mi, $ma) = (1, 1, 1); my @limit = (1,2,5,10,20,50,100,200,500,1000,2000,5000,10000, 20000,50000,100000,200000,500000,1000000,2000000); for my $li (0..int(@limit)-1) { my $l = $limit[$li]; next if($dh > $l); $ma = doround($hmax{$axis}, $l/10, 1); $mi = doround($hmin{$axis}, $l/10, 0); if(($ma-$mi)/($l/10) >= 7) { # If more then 7 steps, then choose next $l = $limit[$li+1]; $ma = doround($hmax{$axis}, $l/10, 1); $mi = doround($hmin{$axis}, $l/10, 0); } $step = $l/10; last; } $hmax{$axis} = $ma; $hmin{$axis} = $mi; # Draw the horizontal values and grid my $hmul = $h/($ma-$mi); $off1 = ($axis eq "x1y1" ? $x-$th*0.3 : $x+$w+$th*0.3); $off3 = ($axis eq "x1y1" ? $x : $x+$w-5); $off4 = $off3+5; $yr = ($axis eq "x1y1" ? "ytics" : "y2tics"); my $tic = $conf{$yr}; if($tic && $tic !~ m/mirror/) { # Tics specified in the configfile $tic =~ s/^\((.*)\)$/$1/; # Strip () foreach my $onetic (split(",", $tic)) { $onetic =~ s/^ *(.*) *$/$1/; my ($tlabel, $tvalue) = split(" ", $onetic); $tlabel =~ s/^"(.*)"$/$1/; $off2 = int($y+($ma-$tvalue)*$hmul); pO ""; $off2 += $th/4; my $align = ($axis eq "x1y1" ? " text-anchor=\"end\"" : ""); pO " $tlabel"; } } else { # Auto-tic for(my $i = $mi; $i <= $ma; $i += $step) { $off2 = int($y+($ma-$i)*$hmul); pO " "; if($axis eq "x1y2") { my $o6 = $x+$w; pO " " if($i > $mi && $i < $ma); } $off2 += $th/4; my $align = ($axis eq "x1y1" ? " text-anchor=\"end\"" : ""); my $txt = sprintf("%g", $i); pO "$txt"; } } } # Second loop over the data: draw the measured points for my $idx (0..int(@hdx)-1) { my $a = $axes[$idx]; next if(!defined($a)); $min = $hmin{$a}; $hmax{$a} += 1 if($min == $hmax{$a}); # Else division by 0 in the next line my $hmul = $h/($hmax{$a}-$min); my $ret = ""; my ($dxp, $dyp) = ($hdx[$idx], $hdy[$idx]); next if(!defined($dxp)); my $yh = $y+$h; my $tl = $ltitle[$idx] ? $ltitle[$idx] : ""; my $dec = int(log($hmul*3)/log(10)); $dec = 0 if($dec < 0); my $js_helpers = "id=\"line_$idx\" decimals=\"$dec\" ". "x_off=\"$fromsec\" x_min=\"$x\" x_mul=\"$tmul\" ". "y_h=\"$yh\" y_min=\"$min\" y_mul=\"$hmul\" title=\"$tl\" ". "onclick=\"svg_click(evt)\""; my ($lx, $ly) = (-1,-1); if($type[$idx] eq "points" ) { foreach my $i (0..int(@{$dxp})-1) { my ($x1, $y1) = (int($x+$dxp->[$i]), int($y+$h-($dyp->[$i]-$min)*$hmul)); next if($x1 == $lx && $y1 == $ly); $ly = $x1; $ly = $y1; $ret = sprintf(" %d,%d %d,%d %d,%d %d,%d %d,%d", $x1-3,$y1, $x1,$y1-3, $x1+3,$y1, $x1,$y1+3, $x1-3,$y1); pO ""; } } elsif($type[$idx] eq "steps" || $type[$idx] eq "fsteps" ) { if(@{$dxp} == 1) { my $y1 = $y+$h-($dyp->[0]-$min)*$hmul; $ret .= sprintf(" %d,%d %d,%d %d,%d %d,%d", $x,$y+$h, $x,$y1, $x+$w,$y1, $x+$w,$y+$h); } else { foreach my $i (1..int(@{$dxp})-1) { my ($x1, $y1) = ($x+$dxp->[$i-1], $y+$h-($dyp->[$i-1]-$min)*$hmul); my ($x2, $y2) = ($x+$dxp->[$i], $y+$h-($dyp->[$i] -$min)*$hmul); next if(int($x2) == $lx && int($y1) == $ly); $lx = int($x2); $ly = int($y2); if($type[$idx] eq "steps") { $ret .= sprintf(" %d,%d %d,%d %d,%d", $x1,$y1, $x2,$y1, $x2,$y2); } else { $ret .= sprintf(" %d,%d %d,%d %d,%d", $x1,$y1, $x1,$y2, $x2,$y2); } } } pO ""; } elsif($type[$idx] eq "histeps" ) { if(@{$dxp} == 1) { my $y1 = $y+$h-($dyp->[0]-$min)*$hmul; $ret .= sprintf(" %d,%d %d,%d %d,%d %d,%d", $x,$y+$h, $x,$y1, $x+$w,$y1, $x+$w,$y+$h); } else { foreach my $i (1..int(@{$dxp})-1) { my ($x1, $y1) = ($x+$dxp->[$i-1], $y+$h-($dyp->[$i-1]-$min)*$hmul); my ($x2, $y2) = ($x+$dxp->[$i], $y+$h-($dyp->[$i] -$min)*$hmul); next if(int($x2) == $lx && int($y1) == $ly); $lx = int($x2); $ly = int($y2); $ret .= sprintf(" %d,%d %d,%d %d,%d %d,%d", $x1,$y1, ($x1+$x2)/2,$y1, ($x1+$x2)/2,$y2, $x2,$y2); } } pO ""; } else { # lines and everything else foreach my $i (0..int(@{$dxp})-1) { my ($x1, $y1) = (int($x+$dxp->[$i]), int($y+$h-($dyp->[$i]-$min)*$hmul)); next if($x1 == $lx && $y1 == $ly); $lx = $x1; $ly = $y1; $ret .= sprintf(" %d,%d", $x1, $y1); } pO ""; } } pO ""; } sub time_to_sec($) { my ($str) = @_; if(!$str) { return 0; } my ($y,$m,$d,$h,$mi,$s) = split("[-_:]", $str); $s = 0 if(!$s); $mi= 0 if(!$mi); $h = 0 if(!$h); $d = 1 if(!$d); $m = 1 if(!$m); if(!$__ltstr || $__ltstr ne "$y-$m-$d") { # 2.5x faster $__lt = mktime(0,0,0,$d,$m-1,$y-1900,0,0,-1); $__ltstr = "$y-$m-$d"; } return $s+$mi*60+$h*3600+$__lt; } sub fmtTime($$) { my ($sepfmt, $sec) = @_; my @tarr = split("[ :]+", localtime($sec)); my ($sep, $fmt) = split(" ", $sepfmt, 2); my $ret = ""; for my $f (split(" ", $fmt)) { $ret .= $sep if($ret); $ret .= $tarr[$f]; } return $ret; } sub time_align($$) { my ($v,$align) = @_; return $v if(!$align); if($align == 1) { # Look for the beginning of the week for(;;) { my @a = localtime($v); return $v if($a[6] == 0); $v += 86400; } } if($align == 2) { # Look for the beginning of the month for(;;) { my @a = localtime($v); return $v if($a[3] == 1); $v += 86400; } } } sub doround($$$) { my ($v, $step, $isup) = @_; if($v >= 0) { return (int($v/$step))*$step+($isup ? $step : 0); } else { return (int($v/$step))*$step+($isup ? 0 : -$step); } } 1;