After trying printing from my browser and trying using screenshots, I
have decided to make a little script that will allow me to create a
LaTeX Gantt chart for creating a PDF. I have experience coding such
charts, I just need a little guidance extracting the info from TJ3.
I am thinking that the easiest way would be a CSV report that would
give me columns like this:
ID | Name | Duration | Start | Predecessors | isLeaf() | isMilestone()
Is a report like this possible?
-Rene
Not directly. You can only use the columns listed here:
http://www.taskjuggler.org/tj3/manual/columnid.html
But you can determine isLeaf from the ID (no other task ID starts with
the ID of a leaf task) and isMilestone from having identical start and
end dates or duration 0.
Chris
that is precisely what I do too. Let me begin by saying that this php
script has very limited use but if you want you or anyone else can use
it. No guarantees, no waranty, no nothing.
as a report I put:
taskreport "tasks"{
balance cost income
timeformat "%s"
formats csv
columns name,id,resources,start,end,complete,scenario,cost
scenarios plan,actual
}
then I run
tj3csv2gantt tasks.csv>gantt_tasks.lat
with the php script attached
then in my latex I put
\psscaleboxto(\textwidth,0){
\input{gantt_tasks.lat}
}
this uses pstricks
you can filter with flags in tasks and in the report.
parts are missing like dependency arrows which I keep planning to do.
it may produce errors and garbage but perhaps it proves useful to you.
sorry for being off topic for the list
Lieven
There's another site that seems to be down at the moment that used to
have some great examples:
-- Site: http://www.martin-kumm.de/tex_gantt_package.php
-- Cached copy:
http://webcache.googleusercontent.com/search?q=cache:http://www.martin-kumm.de/tex_gantt_package.php
Anyway, just thought I'd toss that out there. I do wish tj3 had a
better export function to something like a PDF. It's something I miss
from the UI in v2.
Thanks for contributing like this,
John
> --
> You received this message because you are subscribed to the "TaskJuggler Users" group.
> To post to this group, send email to taskjugg...@googlegroups.com
> To unsubscribe from this group, send email to
> taskjuggler-us...@googlegroups.com
> For more information about TaskJuggler visit http://www.taskjuggler.org
-Rene
> --
> You received this message because you are subscribed to the "TaskJuggler Users" group.
> To post to this group, send email to taskjugg...@googlegroups.com
> To unsubscribe from this group, send email to
> taskjuggler-us...@googlegroups.com
> For more information about TaskJuggler visit http://www.taskjuggler.org
> #!/usr/bin/php
>
> <?php
>
> function drawtasktext($scenario,&$atask,$listofkeys,$startofchart,$yoffset,$isfinal){
> //echo "in drawtasktext".$yoffset."\n";
> $subtasks=array_diff_key($atask,$listofkeys);
> $dagstart=$atask["Start"];
> $dagend=$atask["End"];
> $xpos=($atask["Start"]-$startofchart)/(60*60*24);
> $xpose=(($atask["End"]-$startofchart)/(60*60*24));
> if($isfinal){
> $kleur="cyan";
> }else{
> $kleur="red";
> };
> if($dagstart==$dagend){
> //echo "is milestone\n";
> //is milestone
> //$xpos=(strtotime("+ 12 hours",$atask["Start"])-$startofchart)/(60*60*24);
> $dateeve=mktime(17,0,0,date("n",$atask["Start"]),date("j",$atask["Start"]),date("Y",$atask["Start"]));
> $xpos=($dateeve-$startofchart)/(60*60*24);
> echo '\pscircle[linewidth=5pt,linecolor='.$kleur.']('.($xpos).",".$yoffset."){0.2}\n";
> if($isfinal){echo '\rput[tl]('.($xpos+0.8).",".($yoffset+0.1)."){Milestone: ".$atask["Name"]."}\n";}
> }else{
> //is tasks
> if(count($subtasks)!=0){
> //task container
> $dateeve=mktime(17,0,0,date("n",$atask["End"]),date("j",$atask["End"]),date("Y",$atask["End"]));
> $xpose=($dateeve-$startofchart)/(60*60*24);
> echo '\psline[linewidth=3pt,linecolor='.$kleur.']('.$xpos.",".($yoffset-0.3).")(".$xpose.",".($yoffset-0.3).")\n";
> if($isfinal){echo '\rput[tl]('.$xpos.",".($yoffset+0.1)."){".$atask["Name"]."}\n";}
> }else{
> //task
> echo '\psframe[linewidth=1pt,fillstyle=solid,fillcolor='.$kleur.']('.$xpos.",".($yoffset-0.3).")(".$xpose.",".($yoffset+0.3).")\n";
> if($isfinal){echo '\rput[tl]('.$xpos.",".($yoffset+0.1)."){Task: ".$atask["Name"]."}\n";}
> }
> }
> $yoffset--;
> //en dan de volgende taken
> foreach($subtasks as $key=>$subtask){
> $yoffset=drawtasktext($scenario,$subtask,$listofkeys,$startofchart,$yoffset,$isfinal);
> }
> return $yoffset;
> }
>
> setlocale(LC_NUMERIC,'en_GB');
> //$locale_info = localeconv();
> //print_r($locale_info);
> //echo locale_get_default();
> //locale_set_default("en-UK");
> $arg = $_SERVER['argv'];
> //print_r($arg);
> if(count($arg)>1){
> $handle = fopen($arg[1], "r");
> $firstrun = true;
> $thisdata=array();
> $listofkeys=array();
> $nooftasks=-1;
> while (($data = fgetcsv($handle, 10000, ";")) !== FALSE) {
> //echo "---------------------\n";
> foreach($data as $key => $val){
> if($firstrun){
> $thisdata[$val]=array();
> $listofkeys[]=$val;
> }else{
> //echo $val."\n";
> //if((!strcmp($listofkeys[$key],"Start") or !strcmp($listofkeys[$key],"End"))){
> // $datearr=preg_split("/-/",$val);
> // //print_r($datearr);
> // $val=mktime(0,0,0,$datearr[1],$datearr[0],$datearr[2]);
> //echo $val." -- ".date('Y-m-d',$val) ."\n";
> //}
> $thisdata[$listofkeys[$key]][]=$val;
> };
> };
> $nooftasks++;
> $firstrun = false;
> }
> //print_r($thisdata);
>
> $projectstart=min($thisdata["Start"]);
> //echo "projectstart:\t".date('Y-m-d:H:i:s',$projectstart) ."\n";
> $chartstart=strtotime("last Monday",$projectstart);
> //echo "chartstart:\t".date('Y-m-d:H:i:s',$chartstart) ."\n";
> $projectend=max($thisdata["End"]);
> //echo "projectend:\t".date('Y-m-d:H:i:s',$projectend) ."\n";
> $chartend=strtotime("next Sunday",$projectend);
> //echo "chartend:\t".date('Y-m-d:H:i:s',$chartend) ."\n";
> $chartinterval=($chartend-$chartstart)/(60*60*24);
> //echo "chartinterval:\t".$chartinterval."\n";
>
> //print_r($listofkeys);
> $IdKey=array_search("Id",$listofkeys);
> unset($listofkeys[$IdKey]);
> $listofkeysdiff=array_fill_keys($listofkeys,0);
> //print_r($listofkeysdiff);
>
> //print_r($listofkeys);
> //print_r($thisdata);
> //print_r($nooftasks);
> $scenarios=array();
> if(array_key_exists("Scenario",$thisdata)){
> $scenarios = array_unique($thisdata["Scenario"]);
> }
> //print_r($scenarios);
>
> $structdata=array();
> $previousId="";
> for($teller=0;$teller<$nooftasks;$teller++){
> if(array_key_exists("Scenario",$thisdata)){
> //echo "scenario included\n";
> if(!strcmp($thisdata["Id"][$teller],"")){
> $fullId=$thisdata["Scenario"][$teller].":".$previousId;
> }else{
> $fullId=$thisdata["Scenario"][$teller].":".$thisdata["Id"][$teller];
> $previousId=$thisdata["Id"][$teller];
> };
> //echo $fullId."\n";
> }
> //$here='$structdata["'.preg_replace('/[:\.]/','"]["',$thisdata[Id][$teller])."\"]";
> $here='$structdata["'.preg_replace('/[:\.]/','"]["',$fullId)."\"]";
> //echo $here."\n";
> //if(array_key_exists($val,$structdata)){
> // echo "exists:".$val."\n";
> //}else{
> //echo "new el:".$val."\n";
> $todo=$here.'=array();';
> eval($todo);
> foreach($listofkeys as $thekey){
> $todo=$here."[\"".$thekey."\"]=\$thisdata[\"".$thekey."\"][".$teller."];";
> //echo $todo."\n";
> eval($todo);
> }
> //$todo=$here."[\"volgnummer\"]=".$teller.";";
> //echo $todo."\n";
> //eval($todo);
> //}
> }
> //print_r($structdata);
>
> $uittext="";
> //$uittext=$uittext."\psset{unit=1mm}\n";
> $height=$nooftasks/count($scenarios);
> $uittext=$uittext."\begin{pspicture}(".$chartinterval.",".$height.")\n";
> echo "\begin{pspicture}(".$chartinterval.",".$height.")\n";
> //$uittext=$uittext."\psgrid\n";
> //draw grid
> $today=date('j F Y',time());
> //echo $today."\n";
> for($dag=0;$dag<$chartinterval;$dag++){
> $bottom=-1;
> $daginterval="+".$dag." day";
> //echo $daginterval."\n";
> $dedag=strtotime($daginterval,$chartstart);
> //$dedag=$chartstart+$dag*60*60*24;
> $dedagtext=date('j',$dedag);
> //echo $dedagtext."\n";
> $dagnaam=date('l',$dedag);
> $voldagnaam=date('j F Y',$dedag);
> $maandnaam=date('F Y',$dedag);
> $maanddag=date('j',$dedag);
> $weeknummer=date('W',$dedag);
> $dagwshift=$dag+.5;
> if($maanddag==1 or $dag==0){
> $top=$height+1;
> $uittext=$uittext.'\rput[tl]('.$dagwshift.",".$top."){".$maandnaam."}\n";
> echo '\rput[tl]('.$dagwshift.",".$top."){".$maandnaam."}\n";
> $uittext=$uittext."\psline[linewidth=1pt]($dag,$height)($dag,$top)\n";
> echo "\psline[linewidth=1pt]($dag,$height)($dag,$top)\n";
> }
> if(!strcmp('Monday',$dagnaam)){
> $top=$height+0.5;
> $uittext=$uittext."\psline[linewidth=1pt]($dag,$height)($dag,$top)\n";
> echo "\psline[linewidth=1pt]($dag,$height)($dag,$top)\n";
> echo '\rput[tl]('.$dagwshift.",".$top."){".$weeknummer."}\n";
> }
> if(!strcmp('Saturday',$dagnaam) or !strcmp('Sunday',$dagnaam)){
> $volgendedag=$dag+1;
> $uittext=$uittext.'\psframe[linewidth=0pt,fillstyle=solid,fillcolor=lime,linecolor=lime]('.$dag.",".$bottom.")(".$volgendedag.",".$height.")\n";
> echo '\psframe[linewidth=0pt,fillstyle=solid,fillcolor=lime,linecolor=lime]('.$dag.",".$bottom.")(".$volgendedag.",".$height.")\n";
> }
> if(!strcmp($today,$voldagnaam)){
> $volgendedag=$dag+1;
> $uittext=$uittext.'\psframe[linewidth=0pt,fillstyle=solid,fillcolor=green,linecolor=green]('.$dag.",".$bottom.")(".$volgendedag.",".$height.")\n";
> echo '\psframe[linewidth=0pt,fillstyle=solid,fillcolor=green,linecolor=green]('.$dag.",".$bottom.")(".$volgendedag.",".$height.")\n";
> }
>
> $uittext=$uittext.'\rput[tl]('.$dagwshift.",".$height."){".$dedagtext."}\n";
> echo '\rput[tl]('.$dagwshift.",".$height."){".$dedagtext."}\n";
> $uittext=$uittext."\psline[linewidth=1pt]($dag,".$bottom.")($dag,$height)\n";
> echo "\psline[linewidth=1pt]($dag,".$bottom.")($dag,$height)\n";
> }
>
> foreach(array_reverse($scenarios,true) as $sckey => $scval){
> $yoffset=$height-1-$sckey*0.2;
> //echo $yoffset."\n";
> $scenario=$structdata[$scval];
> $isfinal=($sckey==0);
> //echo $isfinal."\n";
> foreach($scenario as $key => $task){
> //echo $key."\n";
> $yoffset=drawtasktext($scval,$task,$listofkeysdiff,$chartstart,$yoffset,$isfinal);
> //$yoffset--;
> }
> }
>
> $uittext=$uittext."\end{pspicture}\n";
> echo "\end{pspicture}\n";
> fclose($handle);
> }
> ?>
I have completed the initial version of the converter, you can find it
at http://github.com/ravl1084/TJ2PDF
If you want to download the source code, it's available. If you just
want a runnable version, you can find a tarball in the Downloads
section.
Hope its helpful!
-Rene
Hello,
I have completed the initial version of the converter, you can find it
at http://github.com/ravl1084/TJ2PDF
If you want to download the source code, it's available. If you just
want a runnable version, you can find a tarball in the Downloads
section.
Hope its helpful!
-Rene
The reason for creating a separate file is that the goal of the script
was to generate the LaTeX snippet for the chart, to be included in
another document (which is what I needed, heh). I did not intend for
the test case LaTeX file that is sent as part of the script to be "The
Gannt Chart", just a minimal working example that would let someone
unfamiliar with LaTeX use the snippet.
The 'adjustbox' package is included in the test case as a way of
partitioning a chart that has many tasks, more than would fit on the
page. Without it, the chart will spill out just the same, but won't
show the sections that are out of bounds.
Another option is to use the 'standalone' document class, which will
produce a PDF file of the chart with no associated paper size or
orientation that can later be included in a document as an image. This
has the drawback that the full chart will be scaled to fit where it's
inserted, potentially making it illegible.
There are limitations to the script, as this is a first approach:
- The script assumes that every month has 30 days. So you could have a
milestone in February 30th.
- The chart's resolution (chronological, not graphical) is in days. If
you are tracking your project in hours, the script will not produce
an adequate chart. LaTeX's pgfgannt does not allow for fractions as
the duration. I chose days because it produces the most accurate
approximation, using weeks really distorts the chart because you
have to use full weeks.
I recommend using it for summary charts rather than displaying the
whole project. Remember that the TJ3 report can be filtered using
flags, tasks can be rolled up, etc.
I will be making changes to this along the way, one of the things in
my list is to include the Today line. This is not hard to implement, I
just haven't figured out how to include that information in the TJ3
report.
-Rene
Gotcha. I was primarily interested in the ganntt chart by itself, as I
usually generate a pdf and then include it vs. including a LaTeX
snippet in my document, at least if it's long.
> The 'adjustbox' package is included in the test case as a way of
> partitioning a chart that has many tasks, more than would fit on the
> page. Without it, the chart will spill out just the same, but won't
> show the sections that are out of bounds.
>
> Another option is to use the 'standalone' document class, which will
> produce a PDF file of the chart with no associated paper size or
> orientation that can later be included in a document as an image. This
> has the drawback that the full chart will be scaled to fit where it's
> inserted, potentially making it illegible.
>
I'll look into this. That might be what I want. My chart definitely
isn't *that* big. I'll see how that works.
> There are limitations to the script, as this is a first approach:
> - The script assumes that every month has 30 days. So you could have a
> milestone in February 30th.
> - The chart's resolution (chronological, not graphical) is in days. If
> you are tracking your project in hours, the script will not produce
> an adequate chart. LaTeX's pgfgannt does not allow for fractions as
> the duration. I chose days because it produces the most accurate
> approximation, using weeks really distorts the chart because you
> have to use full weeks.
>
I'm cool with this.
> I recommend using it for summary charts rather than displaying the
> whole project. Remember that the TJ3 report can be filtered using
> flags, tasks can be rolled up, etc.
>
I haven't looked into filtering, but this all makes perfect sense --
high level summary vs. trying to show every single thing using the
pgfgantt script.
> I will be making changes to this along the way, one of the things in
> my list is to include the Today line. This is not hard to implement, I
> just haven't figured out how to include that information in the TJ3
> report.
>
Thanks again for what you've already done. It's a great addition and
getting the chart out of html is a helpful tool indeed!
John