Commit 27cdff23 authored by Chad Barb's avatar Chad Barb

Added "thumbnail view" to Experiment List page.
Added thumbnail rendering to renderer.

Note that thumbnail view is not available when viewing the idle list.

Also, loading thumbnails for "all" as admin takes a while!
parent ba2dc611
......@@ -15,10 +15,10 @@ use Getopt::Std;
sub usage()
{
print STDOUT
"Usage: dbvistoplogy [-o <outputfile>] [-z <zoomfactor>] [-d <detaillevel>] <pid> <eid>\n";
"Usage: dbvistoplogy [-o <outputfile>] [-t <thumbsize> ] [-z <zoomfactor>] [-d <detaillevel>] <pid> <eid>\n";
exit(-1);
}
my $optlist = "o:z:d:";
my $optlist = "o:z:d:t:";
#
# Configure variables
......@@ -37,6 +37,7 @@ my $render = "$TB/libexec/vis/render";
my $output;
my $zoom;
my $detail;
my $thumb;
#
# Turn off line buffering on output
......@@ -63,6 +64,17 @@ if (@ARGV != 2) {
my $pid = $ARGV[0];
my $eid = $ARGV[1];
if (defined($options{"t"})) {
$thumb = $options{"t"};
if ($thumb =~ /^([0-9]+)$/) {
$thumb = $1;
}
else {
die("Bad data in thumbnail size: $thumb");
}
}
if (defined($options{"o"})) {
$output = $options{"o"};
......@@ -138,6 +150,10 @@ if (defined($detail)) {
$args .= "-d $detail ";
}
if (defined($thumb)) {
$args .= "-t $thumb ";
}
$args .= "$pid $eid ";
if (defined($output)) {
......
......@@ -30,10 +30,10 @@ my $ICONDIR = "$TB/www";
sub dprint($);
sub usage {
die "Usage:\nrender [-v] [-z zoomfactor] [-d detaillevel] <pid> <eid>\n";
die "Usage:\nrender [-v] [-t <thumbsize>] [-z <zoomfactor>] [-d <detaillevel>] <pid> <eid>\n";
}
my $optlist = "z:d:v";
my $optlist = "z:d:vt:";
if (! getopts($optlist, \%options)) { usage; }
if (@ARGV != 2) { usage; }
......@@ -61,6 +61,16 @@ if (defined($options{"d"})) {
}
}
my $thumbnail = 0;
if (defined($options{"t"})) {
my $tf = $options{"t"};
if ($tf =~ /^([0-9]+)/) {
$thumbnail = $1;
} else {
die("Bad argument to -t; must be non-negative integer.");
}
}
my %nodes = ();
my %links = ();
......@@ -116,21 +126,26 @@ while (my ($name, $vis_type, $vis_x, $vis_y, $ips, $virt_type) = $result->fetchr
if (!(defined $min_x)) {
# no nodes.
die "No visible nodes in '$pid/$eid', or experiment does not exist.\n";
}
dprint "min x,y = $min_x, $min_y\n" .
if ($thumbnail != 0) {
$max_x = 64;
$max_y = 64;
}
$noNodes = 1;
# die "No visible nodes in '$pid/$eid', or experiment does not exist.\n";
} else {
dprint "min x,y = $min_x, $min_y\n" .
"max x,y = $max_x, $max_y\n";
# adjust each node's position so topleftmost node is at (60,60) * $zoom.
foreach $i (keys %nodes) {
# adjust each node's position so topleftmost node is at (60,60) * $zoom.
foreach $i (keys %nodes) {
$nodes{$i}{"x"} = ($nodes{$i}{"x"} - $min_x + 60) * $zoom;
$nodes{$i}{"y"} = ($nodes{$i}{"y"} - $min_y + 60) * $zoom;
}
}
# adjust max x,y appropriately.
$max_x = ($max_x - $min_x + 120) * $zoom;
$max_y = ($max_y - $min_y + 120) * $zoom;
# adjust max x,y appropriately.
$max_x = ($max_x - $min_x + 120) * $zoom;
$max_y = ($max_y - $min_y + 120) * $zoom;
}
# get vlan list.
......@@ -204,7 +219,12 @@ if ($zoom >= 1.75) { $embiggen = 2; }
# start constructing the image
dprint "Image size = $max_x x $max_y\n";
$im = new GD::Image($max_x, $max_y);
if ($thumbnail == 0) {
$im = new GD::Image($max_x, $max_y);
} else {
$im = new GD::Image($thumbnail, $thumbnail);
}
$nodeicon = GD::Image->newFromPng("$ICONDIR/nodeicon.png") || warn "nodeicon.png not found";
$lanicon = GD::Image->newFromPng("$ICONDIR/lanicon.png") || warn "lanicon.png not found";
......@@ -218,7 +238,10 @@ $colors{"red"} = $im->colorAllocate(192,0,0);
$colors{"blue"} = $im->colorAllocate(0,0,192);
$colors{"paleyellow"} = $im->colorAllocate(192,192,127);
$colors{"paleblue"} = $im->colorAllocate(127,127,192);
$colors{"green"} = $im->colorAllocate(0,96,0);
$colors{"palered"} = $im->colorAllocate(210,200,180);
#$colors{"green"} = $im->colorAllocate(0,96,0);
$colors{"green"} = $im->colorAllocate(0,192,0);
$colors{"palegreen"} = $im->colorAllocate(96,192,96);
$colors{"lightgreen"} = $im->colorAllocate(0, 160, 0);
$colors{"orange"} = $im->colorAllocate(255, 128, 0);
$colors{"yellow"} = $im->colorAllocate(255, 255, 0);
......@@ -232,15 +255,68 @@ $colors{"gray25"} = $im->colorAllocate(63,63,63);
# set clear background
$bgcolor = $im->colorAllocate(254, 254, 254);
# $im->transparent($bgcolor);
$im->transparent($bgcolor);
$im->fill( 1, 1, $bgcolor );
#$im->interlaced('true');
#$im->rectangle( 0,0,99,99, $gray50 );
# render shadows
if ($thumbnail != 0) {
# Thumbnails are drawn similarly to full views,
# but there are enough differences to warrant separate code.
foreach $i (keys %links) {
# get endpoint names from link name
($a, $b) = ($i =~ /(\S+)\s(\S+)/);
# get endpoint node location
($x1, $y1) = ($nodes{ $a }{"x"}, $nodes{ $a }{"y"});
($x2, $y2) = ($nodes{ $b }{"x"}, $nodes{ $b }{"y"});
# scale down to thumbnail size; 'ceil' prevents subpixel errors,
# though it is probably not needed for lines.
$x1 = ceil(($x1 * $thumbnail) / $max_x);
$y1 = ceil(($y1 * $thumbnail) / $max_y);
$x2 = ceil(($x2 * $thumbnail) / $max_x);
$y2 = ceil(($y2 * $thumbnail) / $max_y);
$im->line( $x1, $y1, $x2, $y2, $colors{"paleblue"} );
}
foreach $i (keys %nodes) {
# get node position and type.
my ($x, $y) = ($nodes{$i}{"x"}, $nodes{$i}{"y"});
my $type = $nodes{$i}{"type"};
# scale down to thumbnail size; 'ceil' prevents subpixel errors.
# 'ceil' is important, since if $x has a fractional part as well as $size,
# when they're added together, they may produce an additional pixel of
# width or height on some of the nodes; such an error is surprisingly noticable.
$x = ceil(($x * $thumbnail) / $max_x);
$y = ceil(($y * $thumbnail) / $max_y);
foreach $i (keys %nodes) {
$size = ceil(min( 16 * $thumbnail / $max_x, 16 * $thumbnail / $max_y ));
if ($type eq "special") {
$im->filledRectangle( $x - $size, $y - $size, $x + $size, $y + $size, $colors{"darkred"} );
$im->rectangle( $x - $size, $y - $size, $x + $size, $y + $size, $colors{"black"} );
} elsif ($type eq "lan") {
for ($i = 1; $i < $size; $i++) {
$im->arc( $x, $y, $i * 2, $i * 2, 0, 360, $colors{"blue"} );
}
$im->arc( $x, $y, $size * 2, $size * 2, 0, 360, $colors{"black"} );
} elsif ($type eq "node") {
$im->filledRectangle( $x - $size, $y - $size, $x + $size, $y + $size, $colors{"palegreen"} );
$im->rectangle( $x - $size, $y - $size, $x + $size, $y + $size, $colors{"black"} );
}
}
} else {
# not a thumbnail, so we do the full rendering path.
# render shadows
foreach $i (keys %nodes) {
# get node location
($x, $y) = ($nodes{$i}{"x"}, $nodes{$i}{"y"});
if ($nodes{$i}{"type"} eq "lan") {
......@@ -258,11 +334,10 @@ foreach $i (keys %nodes) {
$im->filledRectangle( $x - 12, $y - 12,
$x + 20, $y + 20, $colors{"gray80"});
}
}
}
# render links
foreach $i (keys %links) {
foreach $i (keys %links) {
# get endpoint names from link name
($a, $b) = ($i =~ /(\S+)\s(\S+)/);
......@@ -313,11 +388,11 @@ foreach $i (keys %links) {
$im->setStyle( $colors{"black"}, gdTransparent );
$im->line( $x1, $y1, $x2, $y2, gdStyled );
}
}
}
# render nodes.
foreach $i (keys %nodes) {
foreach $i (keys %nodes) {
# get node position and type.
my ($x, $y) = ($nodes{$i}{"x"}, $nodes{$i}{"y"});
my $type = $nodes{$i}{"type"};
......@@ -341,22 +416,24 @@ foreach $i (keys %nodes) {
$im->arc( $x, $y, $i * 2, $i * 2, 0, 360, $colors{"white"} );
}
# render icon
$im->copy($lanicon, $x-16, $y-16, 0, 0, 32, 32);
} else {
# anything that isn't a LAN (in other words, a node.)
$im->rectangle( $x - 16, $y - 16, $x + 16, $y + 16, $colors{"gray25"} );
$im->rectangle( $x - 15, $y - 15, $x + 15, $y + 15, $colors{"gray25"} );
$im->filledRectangle( $x - 14, $y - 14,
$x + 14, $y + 14, $colors{"white"} );
$im->filledRectangle( $x - 14, $y - 14, $x + 14, $y + 14, $colors{"white"} );
# render icon
$im->copy($nodeicon, $x-16, $y-16, 0, 0, 32, 32);
}
}
} # foreach $i (keys %nodes)
# render link text.
# (this is done in a second pass so no text is obscured by boxes)
foreach $i (keys %links) {
foreach $i (keys %links) {
# only render label if there _is_ a label.
if (!exists $links{$i}{"label"}) { next; }
......@@ -391,12 +468,12 @@ foreach $i (keys %links) {
$j, $colors{"darkblue"});
$y += ($embiggen == 2) ? gdSmallFont->height : gdTinyFont->height;
}
}
} # foreach $i (keys %links)
# render node text.
# (this is done in a second pass so no text is obscured by boxes)
foreach $i (keys %nodes) {
foreach $i (keys %nodes) {
# only render label if there _is_ a label.
if (!exists $nodes{$i}{"label"}) { next; }
......@@ -479,6 +556,31 @@ foreach $i (keys %nodes) {
$j, $colors{"black"});
$y += ($embiggen) ? gdSmallFont->height : gdTinyFont->height;
}
} # foreach $j (@lines)
} # foreach $i (keys %nodes)
} # if ($thumbnail == 0)
# if there were no nodes, provide visual clue as to what's up.
if ($noNodes) {
if ($thumbnail) {
$center_x = ceil( $thumbnail / 2 );
$center_y = $center_x;
$radius = $center_x;
($brx,$bry) = ($thumbnail, $thumbnail);
} else {
$center_x = ceil( $max_x / 2 );
$center_y = ceil( $max_y / 2 );
$radius = min( $center_x, $center_y );
($brx,$bry) = ($max_x, $max_y);
}
for ($i = 0; $i < 4; $i++) {
$im->arc( $center_x, $center_y, $radius - $i, $radius - $i, 0, 360, $colors{"palered"} );
}
for ($i = -3; $i < 4; $i++) {
$im->line( 0, 0 + $i,$brx,$bry + $i, $bgcolor );
}
}
......@@ -575,6 +677,13 @@ sub min {
return $b;
}
sub ceil {
my ($a) = @_;
my $b = sprintf("%i",$a);
if ($a == $b) { return $b; }
return $b + 1;
}
sub dprint($) {
my $n = shift;
if ($debug > 0) { print STDERR $n; }
......
......@@ -27,16 +27,19 @@ if (! isset($showtype))
$showtype="active";
if (! isset($sortby))
$sortby = "normal";
if (! isset($thumb))
$thumb = 0;
echo "<b>Show:
<a href='showexp_list.php3?showtype=active&sortby=$sortby'>active</a>,
<a href='showexp_list.php3?showtype=batch&sortby=$sortby'>batch</a>,";
<a href='showexp_list.php3?showtype=active&sortby=$sortby&thumb=$thumb'>active</a>,
<a href='showexp_list.php3?showtype=batch&sortby=$sortby&thumb=$thumb'>batch</a>,";
if ($isadmin)
echo "\n<a href='showexp_list.php3?showtype=idle&sortby=$sortby'".
echo "\n<a href='showexp_list.php3?showtype=idle&sortby=$sortby&thumb=$thumb'".
">idle</a>,";
echo "\n <a href='showexp_list.php3?showtype=all&sortby=$sortby'>all</a>.
</b><br><br>\n";
echo "\n <a href='showexp_list.php3?showtype=all&sortby=$sortby&thumb=$thumb'>all</a>.
</b><br />\n";
#
# Handle showtype
......@@ -69,6 +72,22 @@ else {
$active = 1;
}
if (!$idle) {
if (!$thumb) {
echo "<b><a href='showexp_list.php3?showtype=$showtype&sortby=pid&thumb=1'>".
"Switch to Thumbnail view".
"</a></b><br />";
} else {
echo "<b><a href='showexp_list.php3?showtype=$showtype&sortby=pid&thumb=0'>".
"Switch to List view".
"</a></b><br />";
}
}
echo "<br />\n";
#
# Handle sortby.
#
......@@ -207,6 +226,57 @@ if (mysql_num_rows($experiments_result)) {
#
# Now shove out the column headers.
#
if ($thumb && !$idle) {
echo "<table border=2 cols=0
cellpadding=0 cellspacing=2 align=center><tr>";
$thumbCount = 0;
while ($row = mysql_fetch_array($experiments_result)) {
$pid = $row["pid"];
$eid = $row["eid"];
$huid = $row["expt_head_uid"];
$name = stripslashes($row["expt_name"]);
$date = $row["d"];
if ($idle && ($str=="&nbsp;" || !$pcs)) { continue; }
echo "<td width=33%><img src='top2image.php3?pid=$pid&eid=$eid&thumb=128' align=center><br />\n" .
"<b><a href='showproject.php3?pid=$pid'>$pid</a>/".
"<a href='showexp.php3?pid=$pid&eid=$eid'>$eid</a></b></h4><br />\n".
"<font size=-1>$name</font><br />\n";
# echo "<font size=-2>Using 69 PCs</font>\n";
if ($isadmin) {
$swappable= $row["swappable"];
$swapreq=$row["swap_requests"];
$lastswapreq=$row["lastreq"];
$lastlogin = "";
if ($lastexpnodelogins = TBExpUidLastLogins($pid, $eid)) {
$daysidle=$lastexpnodelogins["daysidle"];
#if ($idle && $daysidle < 1)
# continue;
$lastlogin .= $lastexpnodelogins["date"] . " " .
"(" . $lastexpnodelogins["uid"] . ")";
} elseif ($state=="active") {
$daysidle=$row["lastswap"];
$lastlogin .= "$date Swapped In";
}
# if ($lastlogin=="") { $lastlogin="<td>&nbsp;</td>\n"; }
if ($lastlogin != "") {
echo "<font size=-2>Last Login: $lastlogin</font><br />\n";
}
}
echo "</td>\n";
$thumbcount++;
if (($thumbcount % 3) == 0) { echo "</tr><tr>\n"; }
}
echo "</tr></table>";
} else {
echo "<table border=2 cols=0
cellpadding=0 cellspacing=2 align=center>
<tr>
......@@ -361,6 +431,8 @@ if (mysql_num_rows($experiments_result)) {
}
echo "</table>\n";
}
echo "<ol>
<li><font color=red>Red</font> indicates nodes other than PCs.
A $idlemark mark by the node count indicates that the
......
......@@ -36,10 +36,13 @@ $exp_pid = $pid;
# note: one can use is_numeric in php4 instead of ereg.
if (!isset($zoom) || !ereg("^[0-9]{1,50}.?[0-9]{0,50}$", $zoom)) { $zoom = 1; }
if (!isset($detail) || !ereg("^[0-9]{1,50}$", $detail)) { $detail = 0; }
if (!isset($thumb) || !ereg("^[0-9]{1,50}$", $detail)) { $thumb = 0; }
if ($zoom > 8.0) { $zoom = 8.0; }
if ($zoom <= 0.0) { $zoom = 1.0; }
if ($thumb > 1024) { $thumb = 1024; }
#
# Check to make sure this is a valid PID/EID tuple.
#
......@@ -65,15 +68,18 @@ if (ISADMIN($uid)) {
$gid = $exp_pid;
}
# note that we've already ensured that $detail is numeric above.
if ($detail != 0) { $detailstring = "-d $detail"; } else { $detailstring = ""; }
$arguments = "";
# note that we've already ensured that $detail and $thumb are numeric above.
if ($detail != 0) { $arguments .= " -d $detail"; }
if ($thumb != 0) { $arguments .= " -t $thumb"; }
#
# Spit out the image with a content header.
#
if ($fp = popen("$TBSUEXEC_PATH $uid $gid webvistopology " .
"$detailstring -z $zoom $pid $eid", "r")) {
"$arguments -z $zoom $pid $eid", "r")) {
header("Content-type: image/png");
fpassthru($fp);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment