commsfwtools/commstools/svg/collaboration.pl
changeset 0 dfb7c4ff071f
equal deleted inserted replaced
-1:000000000000 0:dfb7c4ff071f
       
     1 # Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 # All rights reserved.
       
     3 # This component and the accompanying materials are made available
       
     4 # under the terms of "Eclipse Public License v1.0"
       
     5 # which accompanies this distribution, and is available
       
     6 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 #
       
     8 # Initial Contributors:
       
     9 # Nokia Corporation - initial contribution.
       
    10 #
       
    11 # Contributors:
       
    12 #
       
    13 # Description:
       
    14 #
       
    15 
       
    16 #!/usr/bin/perl
       
    17 
       
    18 
       
    19 use strict;
       
    20 
       
    21 my %objectCoordinates =  # pretty dumb. could smarten this up a lot.
       
    22 (
       
    23 	"CSocket",					[200,100],
       
    24 	"CSubConn",					[400,100],
       
    25 	"CConn",					[600,100],
       
    26 	"CCommsMgr",				[800,100],
       
    27 	"CSelectionRequest",		[1000,110], # NOT Tier Manager's sub-session hence offset
       
    28 
       
    29 	"CFlowFactCtr",				[100,150],
       
    30 	"CSubConnFactCtr",			[300,150],
       
    31 	"CConnFactCtr",				[500,150],
       
    32 	"CMetaConnFactCtr",			[700,150],
       
    33 	"CTierMgrFactCtr",			[900,150],
       
    34 
       
    35 
       
    36 	"CIPDefaultSCPrFact",		[300,200],
       
    37 	"CIPCPrFact",				[500,200],
       
    38 	"CNetMCPrFact",				[700,200],
       
    39 	"CNetTierMgrFact",			[900,200],
       
    40 
       
    41 	"CIPDefaultSCPr",			[400,250],
       
    42 	"CIPCPr",					[600,250],
       
    43 	"CNetMCPr",					[800,250],
       
    44 	"CNetTierMgr",				[1000,250],
       
    45 
       
    46 
       
    47 	"CIPProtoSCPrFact",			[300,300],
       
    48 	"CIPProtoCPrFact",			[500,300],
       
    49 	"CIPProtoMCPrFact",			[700,300],
       
    50 	"CIPProtoTierMgrFact",		[900,300],
       
    51 
       
    52 	"CIPProtoDefaultSCPr",		[400,350],
       
    53 	"CIPProtoCPr",				[600,350],
       
    54 	"CIPProtoMCPr",				[800,350],
       
    55 	"CIPProtoTierMgr",			[1000,350],
       
    56 
       
    57 
       
    58 	"CIPProtoDefaultSCPr-1",	[400,400],
       
    59 	"CIPProtoCPr-1",			[600,400],
       
    60 	
       
    61 	
       
    62 	"CPPPSCPrFact",				[300,500],
       
    63 	"CPPPCPrFact",				[500,500],
       
    64 	"CPPPMCPrFact",				[700,500],
       
    65 	"CPPPTierMgrFact",			[900,500],
       
    66 	
       
    67 	"CPPPSCPr",					[400,550],
       
    68 	"CPPPCPr",					[600,550],
       
    69 	"CPPPMCPr",					[800,550],
       
    70 	"CPPPTierMgr",				[1000,550],
       
    71 	
       
    72 );
       
    73 
       
    74 #
       
    75 # constants
       
    76 #
       
    77 my $incrementY = 20;
       
    78 my $topMargin = 20;
       
    79 my $arrowWidth = 10;
       
    80 my $textArrowSpacing = 1;
       
    81 my $messageSpacingAboveLine = 1;
       
    82 my $objectVerticalLineSpacing = 2;
       
    83 my $objectUnderlineToLifelineGap = 2;
       
    84 
       
    85 my $objectsPerRow = 4;
       
    86 my $objectSpacesToSkipBeforeAutoSpacing = 4 * $objectsPerRow - 1; # start on 5th line
       
    87 my $xSpacing = 200;
       
    88 my $ySpacing = 100;
       
    89 
       
    90 my $objectName = 0;
       
    91 my $objectX = 1;
       
    92 my $objectY = 2;
       
    93 my $objectMsgCount = 3;
       
    94 my $objectCreationPointKnown = 4;
       
    95 
       
    96 my $sequenceAction = 0;
       
    97 my $sequenceObjRef = 1;		# if action == "t" || "oc"
       
    98 my $sequenceMsgRef = 1;		# if action != "t"
       
    99 my $sequenceX = 2;
       
   100 my $sequenceY = 3;
       
   101 
       
   102 my $anims = 1;
       
   103 my $time = 0;
       
   104 my $timeDelta = 500;
       
   105 my $timeDur = $timeDelta * 0.9;
       
   106 
       
   107 my $colouredBoxes = 1;
       
   108 
       
   109 my $animKeys = '1234567890qwertyuiopasdfghjklzxcvbnm';
       
   110 #$animKeys = ''; # uncomment this line to enable animKeys
       
   111 my $animMessagesPerKey = 5;
       
   112 my $animKeyCounter = 0;
       
   113 my $animKeysFirstElement=1;
       
   114 
       
   115 my @sequences;
       
   116 my @messages;
       
   117 my @objects;
       
   118 
       
   119 if(@ARGV && $ARGV[0] eq '-auto')
       
   120 {
       
   121 shift;
       
   122 $animKeys='';
       
   123 }
       
   124 
       
   125 #
       
   126 # Data Structures:
       
   127 #
       
   128 # "objects" is array of arrays:
       
   129 #	[ <object name> <object X> <object Y> <object message count> <creation point known flag> ]
       
   130 #
       
   131 # "sequences" is an array of arrays:
       
   132 #	[ "t" \objects[<n>] "text" ]
       
   133 #	[ "[p|r]" \messages[n] \objects[<source>], \objects[<destination>] ]
       
   134 #	[ "oc" \objects[<n>] ]
       
   135 
       
   136 
       
   137 # Input file format:
       
   138 #
       
   139 #	<action> <arguments> ...
       
   140 #
       
   141 # specifically:
       
   142 #
       
   143 #	[P|R] <message name> <source object> <destination object>
       
   144 #	T <object> <text>
       
   145 #	OC <object>
       
   146 #
       
   147 # actions:
       
   148 #
       
   149 # P		Post
       
   150 # R		Receive
       
   151 # T		Text
       
   152 # OC	Object Create
       
   153 #
       
   154 # All fields are space separated text.  For example:
       
   155 #
       
   156 # P StartFlow SCPR Flow
       
   157 #
       
   158 
       
   159 while (<>) {
       
   160 	die unless s/^(\w+)\s+//;
       
   161 	my $action = $1;
       
   162 	if ($action eq "t")
       
   163 		{
       
   164 		# Text
       
   165 		# t <object> <text>
       
   166 		my $pos;
       
   167 		if (s/^([\w\d-]+)\s+//) { $pos = $1; }
       
   168 		my $objRef = addObject($pos);
       
   169 		chomp;
       
   170 		my $text = $_;
       
   171 		push @sequences, [$action, $objRef, $text];
       
   172 		}
       
   173 	elsif ($action eq "oc")
       
   174 		{
       
   175 		# Object Create
       
   176 		# oc <object>
       
   177 		my $objName;
       
   178 		if (s/^([\w\d-]+)\s+//) { $objName = $1; }
       
   179 		my $objRef = addObject($objName);
       
   180 		${$objRef}->[$objectCreationPointKnown] = 1;
       
   181 		chomp;
       
   182 		push @sequences, [$action, $objRef];
       
   183 		}
       
   184 	else
       
   185 		{
       
   186 		# Post/Receive
       
   187 		# [P|R] <message> <source object> <destination object>
       
   188 		split;
       
   189 		my $msgRef = addMessage(shift @_);
       
   190 		my $srcRef = addObject(shift @_);
       
   191 		my $destRef = addObject(shift @_);
       
   192 		${$srcRef}->[$objectMsgCount]++;
       
   193 		${$destRef}->[$objectMsgCount]++;
       
   194 		push @sequences, [$action, $msgRef, $srcRef, $destRef];
       
   195 		}
       
   196 	}
       
   197 
       
   198 
       
   199 my ($screenWidth,$screenHeight) = calculateObjectPositions();
       
   200 
       
   201 #my $screenWidth = $objects[$#objects]->[$objectX] + $rightMargin;
       
   202 #my $screenHeight = scalar(@sequences) * ($incrementY + 2) + $topMargin;
       
   203 #my $screenWidth = 500;
       
   204 #my $screenHeight = 500;
       
   205 
       
   206 outputDocHeader($screenWidth, $screenHeight);
       
   207 
       
   208 drawObjectsAtTop();
       
   209 
       
   210 	
       
   211 drawCollaborations();
       
   212 
       
   213 outputDocFooter();
       
   214 
       
   215 ####################
       
   216 # Message routines
       
   217 ####################
       
   218 
       
   219 
       
   220 sub drawObjectsAtTop()
       
   221 	{
       
   222 	my $i;
       
   223 	foreach $i (@objects)
       
   224 		{
       
   225 		if ($i->[$objectCreationPointKnown] == 1)
       
   226 			{
       
   227 			next;
       
   228 			}
       
   229 		outputText($i->[$objectX], $i->[$objectName], $i->[$objectY], "middle", "underline","freeze",'',0);
       
   230 		} 
       
   231 		print "\n";
       
   232 	}
       
   233 
       
   234 
       
   235 sub addMessage()
       
   236 	{
       
   237 	my $obj = $_[0];
       
   238 	my $i;
       
   239 	for ($i = 0 ; $i < scalar(@messages) ; ++$i) {
       
   240 		if ($messages[$i] eq $obj) {
       
   241 			return \$messages[$i];
       
   242 			}
       
   243 		}
       
   244 	$messages[$i] = $obj;
       
   245 	return \$messages[$i];
       
   246 	}
       
   247 
       
   248 sub printMessages()
       
   249 	{
       
   250 	print "Messages (", scalar(@messages), ") : ";
       
   251 	foreach my $msg (@messages) {
       
   252 		print $msg, " ";
       
   253 		}
       
   254 	print "\n";
       
   255 	}
       
   256 
       
   257 ###################
       
   258 # Object routines
       
   259 ###################
       
   260 
       
   261 sub addObject()
       
   262 	{
       
   263 	my $objName = $_[0];
       
   264 	my $i;
       
   265 	for ($i = 0 ; $i < scalar(@objects) ; ++$i) {
       
   266 		if ($objects[$i]->[$objectName] eq $objName) {
       
   267 			return \$objects[$i];
       
   268 			}
       
   269 		}
       
   270 		$objects[$i] = [ $objName, 0, 0, 0, 0 ];
       
   271 		return \$objects[$i];
       
   272 	}
       
   273 
       
   274 sub printObjects()
       
   275 	{
       
   276 	print "Objects (", scalar(@objects), "): ";
       
   277 	foreach my $obj (@objects) {
       
   278 		print $obj->[0], "(", $obj->[1], ") ";
       
   279 		}
       
   280 	print "\n";
       
   281 	}
       
   282 
       
   283 sub calculateObjectPositions()
       
   284 	{
       
   285 	my ($maxX, $maxY) = (0,0);
       
   286 	
       
   287 	my $xSpacing = 200;
       
   288 	my $ySpacing = 100;
       
   289 
       
   290 	my $objctr = $objectSpacesToSkipBeforeAutoSpacing;
       
   291 	my $i;
       
   292 	for ($i = 0 ; $i < scalar(@objects) ; ++$i)
       
   293 		{
       
   294  		my $coords = $objectCoordinates{$objects[$i][$objectName]};
       
   295  		if(defined $coords)
       
   296  			{
       
   297 			($objects[$i][$objectX],$objects[$i][$objectY]) =
       
   298 		    	($coords->[0], $coords->[1]);
       
   299 			}
       
   300 		else
       
   301 			{
       
   302 	 		$objctr++;
       
   303 #	for($objctr = 0 ; $objctr < 50 ; $objctr++)
       
   304 #	{
       
   305  			my $x = (1+($objctr % $objectsPerRow)) * $xSpacing;
       
   306  			my $y = (1+int($objctr / $objectsPerRow)) * $ySpacing;
       
   307  #			print STDERR ("X $x Y $y\n");
       
   308  #	}		
       
   309  #	exit;
       
   310 #my ($x,$y); 
       
   311 			($objects[$i][$objectX],$objects[$i][$objectY]) =
       
   312 		    	($x, $y);
       
   313 			}
       
   314 
       
   315 		if($objects[$i][$objectX] > $maxX) { $maxX = $objects[$i][$objectX];}
       
   316 		if($objects[$i][$objectY] > $maxY) { $maxY = $objects[$i][$objectY];}
       
   317 		
       
   318 		$objects[$i][$objectX] -= $xSpacing/2;
       
   319 		$objects[$i][$objectY] -= $ySpacing/2;
       
   320 		
       
   321 		print STDERR ("$i $objects[$i][$objectName] $objects[$i][$objectX] $objects[$i][$objectY]\n")
       
   322 		}
       
   323 #	die("$maxX $maxY");
       
   324 	return ($maxX,$maxY);
       
   325 	}
       
   326 
       
   327 sub trimSilentObjects()
       
   328 	{
       
   329 	# get rid of objects that didn't end up with any messages sent to/from them
       
   330 	my $i;
       
   331 	for ($i = 0 ; $i < scalar(@objects) ; ) {
       
   332 		if ($objects[$i][$objectMsgCount] == 0)
       
   333 			{
       
   334 			my $j;
       
   335 			for ($j = 0 ; $j < scalar(@sequences) ; )
       
   336 				{
       
   337 				my $action = $sequences[$j][$sequenceAction];
       
   338 				if ( (($action eq "t") || ($action eq "oc")) &&
       
   339 				     ($sequences[$j][$sequenceObjRef] == \$objects[$i]) )
       
   340 				    {
       
   341 					splice @sequences, $j, 1;
       
   342 #print "delete sequence $j\n";
       
   343 #++$j;
       
   344 					}
       
   345 				else
       
   346 					{
       
   347 					++$j;
       
   348 					}
       
   349 				}
       
   350 			splice @objects, $i, 1;
       
   351 #print "delete object $i $objects[$i][$objectName]\n";
       
   352 #++$i;
       
   353 			}
       
   354 		else
       
   355 			{
       
   356 			++$i;
       
   357 			}
       
   358 		}
       
   359 	}
       
   360 
       
   361 sub drawObject($$$)
       
   362 	{
       
   363 	my ($x,$y,$name) = @_;
       
   364 	outputText($x, $name, $y, "middle", "underline","freeze",qq{opacity="0.9"},0);
       
   365 #	outputVerticalLine($x, $y + $objectUnderlineToLifelineGap, $screenHeight - $topOffset);
       
   366 	}
       
   367 	
       
   368 
       
   369 
       
   370 sub drawCollaborations()
       
   371 	{
       
   372 	foreach my $ref (@sequences) {
       
   373 		my $action = $ref->[$sequenceAction];
       
   374 		if ($action eq "t")
       
   375 			{
       
   376 			my $objX = ${$ref->[$sequenceObjRef]}->[$objectX];
       
   377 			my $objY = ${$ref->[$sequenceObjRef]}->[$objectY] + $incrementY;
       
   378 			my $text = $ref->[2];
       
   379 print STDERR ("DRAWING $text $objX $objY\n");
       
   380 			outputText($objX, $text, $objY, "middle", "", "freeze",qq{opacity="0.9"},0);
       
   381 			$time += $timeDelta/2;
       
   382 			}
       
   383 		elsif ($action eq "oc") 
       
   384 			{
       
   385 #			if ($objectsDisplayedAtCreationPoint == 1)
       
   386 				{
       
   387 				my $objX = ${$ref->[$sequenceObjRef]}->[$objectX];
       
   388 				my $objY = ${$ref->[$sequenceObjRef]}->[$objectY];
       
   389 				my $objName = ${$ref->[$sequenceObjRef]}->[$objectName];
       
   390 				drawObject($objX, $objY, $objName);
       
   391 				}
       
   392 			}
       
   393 		else
       
   394 			{
       
   395 			my $msg = ${$ref->[$sequenceObjRef]};
       
   396 			my $srcX = ${$ref->[$sequenceX]}->[$objectX];
       
   397 			my $srcY = ${$ref->[$sequenceX]}->[$objectY];
       
   398 			my $destX = ${$ref->[$sequenceY]}->[$objectX];
       
   399 			my $destY = ${$ref->[$sequenceY]}->[$objectY];
       
   400 			my $align;
       
   401 			if ($action eq "p") {
       
   402 				$align = "tail";
       
   403 				}
       
   404 			elsif ($action eq "r") {
       
   405 				$align = "head";
       
   406 				}
       
   407 			outputLabelledLine($srcX, $srcY, $destX, $destY, $msg, $align);
       
   408 
       
   409 			$time += $timeDelta;
       
   410 			
       
   411 			if($animKeys)
       
   412 				{
       
   413 				$animKeyCounter++;
       
   414 				if($animKeyCounter % $animMessagesPerKey == 0)
       
   415 					{
       
   416 					$time = 0;
       
   417 					$animKeysFirstElement=1;
       
   418 					}
       
   419 				}
       
   420 				
       
   421 			}
       
   422 		print "\n";
       
   423 		}
       
   424 	}
       
   425 
       
   426 
       
   427 #######################
       
   428 # SVG output routines
       
   429 #######################
       
   430 
       
   431 sub outputDocHeader()
       
   432 	{
       
   433 	my ($width,$height) = @_;
       
   434 	print '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>',"\n";
       
   435 	print '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">',"\n";
       
   436 	print "<svg height=\"$height\" width=\"$width\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
       
   437 	outputDefs();
       
   438 	}
       
   439 
       
   440 sub outputDefs()
       
   441 	{
       
   442 	print "<defs>\n";
       
   443 	print qq{<marker id="arr" markerHeight="10" markerUnits="strokeWidth" markerWidth="10" orient="auto" refX="10" refY="5" viewBox="0 0 10 10">\n};
       
   444 	print qq{\t<path d="M 0 0 L 10 5 L 0 10 " />\n};
       
   445 	print "</marker>\n";
       
   446 	print "</defs>\n";
       
   447 	}
       
   448 
       
   449 sub outputDocFooter()
       
   450 	{
       
   451 	print "</svg>\n";
       
   452 	}
       
   453 
       
   454 sub shortenLine($$$$$)
       
   455 {
       
   456  	my($x1,$y1,$x2,$y2,$amount) = @_;
       
   457 
       
   458 	my $xdiff = $x1-$x2;
       
   459 	my $ydiff = $y1-$y2;
       
   460 	my $linelen = sqrt(($xdiff*$xdiff) + ($ydiff*$ydiff));
       
   461 	my $factor = 1 - ($amount / ($linelen+1));
       
   462 
       
   463  	if($x2>$x1)
       
   464  	{
       
   465  		$amount = (1-$factor) * ($x2-$x1);
       
   466  		$x1 += $amount;
       
   467  		$x2 -= $amount;
       
   468 	}
       
   469 	else
       
   470 	{
       
   471 		$amount = (1-$factor) * ($x1-$x2);
       
   472  		$x1 -= $amount;
       
   473  		$x2 += $amount;
       
   474 	}
       
   475  	
       
   476  	if($y2>$y1)
       
   477  	{
       
   478  		$amount = (1-$factor) * ($y2-$y1);
       
   479  		$y1 += $amount;
       
   480  		$y2 -= $amount;
       
   481 	}
       
   482 	else
       
   483 	{
       
   484 		$amount = (1-$factor) * ($y1-$y2);
       
   485  		$y1 -= $amount;
       
   486  		$y2 += $amount;
       
   487 	}
       
   488  	
       
   489  	return ($x1,$y1,$x2,$y2);
       
   490 }
       
   491 
       
   492 sub outputLabelledLine()
       
   493 	{
       
   494 	my ($x1,$y1,$x2,$y2,$text,$alignment) = @_;
       
   495 
       
   496 #	my $scale = 0.9;
       
   497 	($x1,$y1,$x2,$y2) = shortenLine($x1,$y1,$x2,$y2,15);
       
   498 	outputLine($x1,$y1,$x2,$y2);
       
   499 	
       
   500 	my ($textx,$texty);
       
   501 	my $anchor;
       
   502 #	if (!$alignment || $alignment eq "mid") {
       
   503 		$textx = (($x1 + $x2) / 2);
       
   504 		$texty = (($y1 + $y2) / 2);
       
   505 		$anchor = "middle";
       
   506 #		}
       
   507 #	else {
       
   508 #		if ($alignment eq "head") {
       
   509 #			if ($x1 < $x2) {
       
   510 #				$anchor = "end";
       
   511 #				$textx = $x2 - $arrowWidth - $textArrowSpacing;
       
   512 #				$texty = $y2 - $arrowWidth - $textArrowSpacing;
       
   513 #				}
       
   514 #			else {
       
   515 #				$anchor = "start";
       
   516 #				$textx = $x2 + $arrowWidth + $textArrowSpacing;
       
   517 #				$texty = $y2 + $arrowWidth + $textArrowSpacing;
       
   518 #				}
       
   519 #		} else {	# "tail"
       
   520 #			$textx = $x1;
       
   521 #			$texty = $y1;
       
   522 #			if ($x1 < $x2) {
       
   523 #				$anchor = "start";
       
   524 #			} else {
       
   525 #				$anchor = "end";
       
   526 #				}
       
   527 #			}
       
   528 #		}
       
   529 
       
   530 	my $rectangleColour = "black";
       
   531 
       
   532 	if($colouredBoxes)
       
   533 	{
       
   534 		if($alignment eq "head")
       
   535 		{
       
   536 			$rectangleColour='pink';
       
   537 		}
       
   538 		else
       
   539 		{
       
   540 			$rectangleColour='lightgreen';
       
   541 		}
       
   542 	}
       
   543 	
       
   544 	outputText($textx,$text,$texty, $anchor, "", "remove", "", $rectangleColour);
       
   545 	}
       
   546 
       
   547 sub getAnimStr
       
   548 {
       
   549 	my ($animFill) = @_;
       
   550 	
       
   551 	my $beginStr = '';
       
   552 	my $idStr = '';
       
   553 	if($animKeys)
       
   554 		{
       
   555 		my $char = substr ($animKeys, int($animKeyCounter/$animMessagesPerKey) , 1);
       
   556 		if($animKeysFirstElement) # if first in sequence
       
   557 			{
       
   558 			$animKeysFirstElement=0;
       
   559 			$beginStr.=qq{accessKey($char)};
       
   560 			$idStr = qq{ id="anim_$char" };
       
   561 			}
       
   562 		else
       
   563 			{
       
   564 			$beginStr = qq{anim_$char.begin};
       
   565 			if($time) {$beginStr .= qq{ + $time}.'ms'}
       
   566 			}
       
   567 		}
       
   568 	else
       
   569 		{
       
   570 		$beginStr = $time;
       
   571 		$beginStr .= 'ms';
       
   572 		}
       
   573 
       
   574 	my $anim = qq{<set $idStr attributeName="visibility" attributeType="CSS" to="visible" begin="$beginStr" dur="$timeDur}.qq{ms" fill="$animFill" />};
       
   575 	return $anim;
       
   576 }
       
   577 
       
   578 sub outputText()
       
   579 	{
       
   580 	my ($x,$text,$y,$anchor,$decoration,$animFill,$otherAttrs,$rectangleColour) = @_;
       
   581 
       
   582 #$rectangleUnder=1;	
       
   583 	my $attrs = qq{ x="$x" y="$y" $otherAttrs};
       
   584 	
       
   585 	if ($decoration)
       
   586 		{
       
   587 		$attrs .= qq{ text-decoration="$decoration" };
       
   588 		}
       
   589 
       
   590 	my $anim='';
       
   591 
       
   592 	if ($anims)
       
   593 		{
       
   594 		$attrs .= qq{ visibility="hidden" };
       
   595 		$anim = getAnimStr($animFill);
       
   596 		}
       
   597 	
       
   598 	if ($anchor)
       
   599 		{
       
   600 		$attrs .= qq { text-anchor="$anchor" };
       
   601 		}
       
   602 
       
   603 	if($rectangleColour)
       
   604 		{
       
   605 		my $w = 8*length($text);  # guessing
       
   606 		my $h = 18;  # guessing
       
   607 		my $rx = $x - $w/2;		
       
   608 		my $ry = $y - $h/2 - 4;
       
   609 		print qq{<rect x="$rx" y="$ry" width="$w" height="$h" visibility="hidden" style="fill:$rectangleColour" opacity="0.95">$anim</rect>\n};
       
   610 		}
       
   611 	print "<text $attrs>$text$anim</text>\n";
       
   612 	}
       
   613 
       
   614 sub outputLine()
       
   615 	{
       
   616 	my ($x1,$y1,$x2,$y2) = @_;
       
   617 	my $animTag='';
       
   618 	my $animAttr='';
       
   619 	if($anims)
       
   620 		{
       
   621 		$animAttr=qq{visibility="hidden"};
       
   622 		$animTag= getAnimStr('remove');
       
   623 		}
       
   624 	print qq{<line stroke="black" marker-end="url(#arr)" $animAttr x1="$x1" y1="$y1" x2="$x2" y2="$y2">$animTag</line>\n};
       
   625 	}
       
   626 
       
   627 sub outputVerticalLine()
       
   628 	{
       
   629 	my ($x,$y1,$y2) = @_;
       
   630 	print qq{<line stroke="black" x1="$x" y1="$y1" x2="$x" y2="$y2" />\n};
       
   631 	}
       
   632 
       
   633 
       
   634