SVG-Timeline-Compact
view release on metacpan or search on metacpan
lib/SVG/Timeline/Compact.pm view on Meta::CPAN
foreach my $event (sort _byStart $self->ev_all){
my $found=0;
$event->resolution($self->_resolution);
$event->origin($self->_min);
for my $slot(0..$#slot){
my $evslot=$slot[$slot];
my $head=pop @{$evslot};if ($head){push @{$evslot}, $head;}
if ($head->x0+$head->width <$event->x0){
push @{$evslot},$event;
$found=1;
last;
}
}
if ($found==0){
my $newslot=[$event];
unshift @slot,$newslot;
}
}
return @slot;
}
sub to_ds {
my $self=shift;
my @slot=$self->layout;
my @ds;
my ($y0,$y1,$x0,$maxX)=(0,1.5,0,0);
my $fmt="yyyy-MM-dd hh:mm";
foreach my $slot (@slot){
foreach my $ev (@{$slot}){
push @ds,{idchangeset=>$ev->id,count=>$ev->name,name=>$ev->tooltip,created=>$ev->start->format_cldr($fmt),
x=>$ev->x0,y=>$y0,width=>$ev->width,height=>$y1, status=>$ev->color};
$maxX=$ev->x0+$ev->width if ($maxX<$ev->x0+$ev->width);
}
$y0+=1.5*$y1;
}
return {resolution=>$self->_resolution,start=>$self->_min->format_cldr($fmt),end=>$self->_max->format_cldr($fmt),maxX=>$maxX,maxY=>$y0,ds=>\@ds}
}
sub to_svg{
my $self=shift;
my @slot=$self->layout;
my $svg=SVG->new();
my $d = DateTime::Format::Duration->new( pattern => '%Y years, %m months, %e days, '. '%H hours, %M minutes, %S seconds');
my $bbox=$svg->group(id=>"bbox");
my $bars=$svg->group(id=>"bars");
my $def=$svg->defs(id=>"arrow","stroke-linecap"=>"round","stroke-width"=>"1");
$def->line(x1=>"-8",y1=>"-4",x2=>"1",y2=>"0");
$def->line(x1=>"1",y1=>"0",x2=>"-8",y2=>"4");
my ($y0,$y1,$x0,$maxX)=(0,$self->min_height,0,0);
foreach my $slot (@slot){
#p @slot;
foreach my $ev (@{$slot}){
#p $ev;
$x0=$ev->x0;
my $width=$ev->width;
my $color=$ev->color;
my $rect=$bars->rect(x=>$x0."px",y=>$y0."px",width=>$width."px",height=>$y1."px", fill=>$color,stroke=>"#000");
$bars->text(x=>$x0+$width/2,y=>($y0-2+$self->min_height),"text-anchor"=>"middle")->cdata($ev->name);
$rect->title->cdata($ev->tooltip.", Start: ". $ev->start.", End ". $ev->end);
$maxX=$x0+$width if ($maxX<$x0+$width);
}
$y0+=$y1*1.5;
}
#$y0+=$y1*1.5;
$maxX=$self->units if($maxX<$self->units);
my $border=$bbox->rect(x=>0,"fill-opacity"=>"0.1",y=>0,width=>$maxX."px",height=>$y0."px");
my $x=0 ;
my$dim=$bbox->group(id=>"dim");
$dim->line(x1=>0,y1=>($y0+$self->min_height),x2=>800,y2=>($y0+$self->min_height));
$dim->use("xlink:href"=>"#arrow",x=>0,y=>($y0+$self->min_height));
$dim->use("xlink:href"=>"#arrow",x=>800,y=>($y0+$self->min_height));
#$dim->text(x=>$maxX/2,y=>($y0+$self->min_height),"text-anchor"=>"middle")->cdata("<-------------- ". $self->_resolution. " --------------->");
#<use stroke="#000000" xlink:href="#ah" transform="translate(354.4 119.4)rotate(90)"/>
$bbox->text(x=>$maxX+10,y=>$self->min_height)->cdata("Min:\t".$self->_min->format_cldr("yyyy/MM/dd h:m"));
$bbox->text(x=>$maxX+10,y=>2*$self->min_height)->cdata("Max:\t".$self->_max->format_cldr("yyyy/MM/dd h:m"));
my $unit;
$unit= $self->_resolution->in_units('months')." Months" if ($self->_resolution->in_units('months')>0);
$unit= $self->_resolution->in_units('days')." Days" if ($self->_resolution->in_units('days')>0);
$unit= $self->_resolution->in_units('minutes')." Minutes" if ($self->_resolution->in_units('minutes')>0);
$bbox->text(x=>$maxX+10,y=>3*$self->min_height)->cdata("Scale:\t ".$unit);
while($x<=$maxX){
if($x%100 == 0){
$bbox->line(x1=>$x,x2=>$x,y1=>$y0,y2=>0 ,style=>"stroke:#000;stroke-width:1px" );
$dim->text(x=>$x,y=>($y0+$self->min_height),"text-anchor"=>"middle")->cdata("$x");
}else{
$bbox->line(x1=>$x,x2=>$x,y1=>$y0,y2=>0 ,style=>"stroke:#fff;stroke-width:1px" );
}
$x=$x+10;
}
return $svg->xmlify;
}
sub _set_resolution{
#We desire that atleast 50% of the graph is utilized. and we do not overflow.
#minutes up to 800 minutes
my $self=shift;
my $scale=get_scale($self->_min,$self->_max);
$self->_resolution($scale);
}
sub get_scale{
my ($min,$max)=@_;
my $duration=$max-$min;
my $days=$duration->in_units('months')*30 +$duration->in_units('days');
my $hours=$days*24+$duration->in_units('hours');
my $minutes=$hours*60+$duration->in_units('minutes');
my $scale;
#p $minutes;
if ($duration->in_units('months')>300){
$scale=DateTime::Duration->new(months=>POSIX::ceil($duration->in_units('months')/800));
}elsif ($days>300){
$scale=DateTime::Duration->new(days=>POSIX::ceil($days/800));
}elsif ($hours>300){
$scale=DateTime::Duration->new(hours=>POSIX::ceil($hours/800));
}else{
$scale=DateTime::Duration->new(minutes=>POSIX::ceil($minutes/800));
}
return $scale;
}
sub _byStart {
return DateTime->compare($a->start,$b->start);
}
__END__
=pod
=encoding UTF-8
=head1 NAME
SVG::Timeline::Compact - A Moose based SVG Timeline drawing class.
=head1 VERSION
version 0.003
=head1 SYNOPSIS
use SVG::Timeline::Compact;
use DateTime::Format::Natural;
my $svg=SVG::Timeline::Compact->new();
my $parser = DateTime::Format::Natural->new;
( run in 1.250 second using v1.01-cache-2.11-cpan-22024b96cdf )