package Bio::EnsEMBL::GlyphSet::ruler;
use strict;
use base qw(Bio::EnsEMBL::GlyphSet);
sub _init {
my ($self) = @_;
my $strand = $self->strand;
if( $self->{'container'}->isa("Bio::EnsEMBL::Compara::AlignSlice::Slice")) {
return if ($self->{'container'}->{'compara'} ne 'primary');
}
my $strand_flag = $self->my_config('strand');
return if( $strand_flag eq 'r' && $strand != -1 || $strand_flag eq 'f' && $strand != 1 );
my $len = $self->{'container'}->length();
my $global_start = $self->{'container'}->start();
my $global_end = $self->{'container'}->end();
my $highlights = $self->highlights();
my $im_width = $self->image_width();
my $feature_colour = $self->my_colour('default') || 'black';
my( $fontname, $fontsize ) = $self->get_font_details( 'innertext' );
my @res = $self->get_text_width( 0, 'X', '', 'font'=>$fontname, 'ptsize' => $fontsize );
my $fontheight = $res[3];
my $fontwidth = $res[2];
my $con_strand = $self->{'container'}->strand();
my $pix_per_bp = $self->scalex;
#####################################################################
# The ruler has to be drawn in absolute x, because when the length is
# too small the rounding errors screw everything
#####################################################################
## let's work out what to draw...
## |-forward strand----------length bp------------------------->
## <-------------------------length bp----------reverse strand-|
my( $right, $left, $righttext, $lefttext )
= $self->{'container'}->isa("Bio::EnsEMBL::Compara::AlignSlice::Slice") ? ( 'bar', 'bar', '', '' )
: $self->my_config('notext') ? ( 'arrow', 'arrow', '', '' )
: $strand > 0 ? ( 'arrow', 'bar', $con_strand > 0 ? 'Forward strand' : 'Reverse strand', '' )
: ( 'bar', 'arrow', '', $con_strand < 0 ? 'Forward strand' : 'Reverse strand' )
;
# unless( $Config->{'compara'} && $con_strand == 1 ) {
# unless( $Config->{'compara'} && $con_strand == -1 ) {
my $length = int( $global_end - $global_start + 1 );
my $unit = [qw( bp Kb Mb Gb Tb )]->[my $power = int( ( length( abs($length) ) - 1 ) / 3 )];
my $centretext = $unit eq 'bp' ? "$length bp" : sprintf( "%.2f %s", $length / 1000**$power, $unit );
## First let's draw the blocksize in the middle....
my $O = 3; my $P = 20;
my @common = ( 'z' => 1000, 'colour' => $feature_colour, 'absolutex' => 1, 'absolutey' => 1, 'absolutewidth' => 1 );
my( $fontname, $fontsize ) = $self->get_font_details( 'innertext' );
my($X_1,$X_2,$W,$H) = $self->get_text_width(0,'X','','font'=>$fontname,'ptsize'=>$fontsize);
my @common_text = ( 'height' => $H, 'font' => $fontname, 'ptsize' => $fontsize, @common, 'y' => 0 );
## Now loop through the three blocks of text... Left text; centre text and right text....
my @lines = (0);
## Left hand side text...
if( $lefttext ) {
my($text,$part,$W,$H) = $self->get_text_width( 0, $lefttext, '', @common_text );
my $start = $P;
$self->push( $self->Text({ 'x' => $start, 'text' => $lefttext, 'halign' => 'left', @common_text }));
push @lines, $P-$O, $P+$O+$W;
}
## Centre text...
if( $centretext ) {
my($text,$part,$W,$H) = $self->get_text_width( 0, $centretext, '', @common_text );
my $start = ($im_width-$W)/2;
$self->push( $self->Text({ 'x' => $start, 'text' => $centretext, 'width' => $W, 'halign' => 'center', @common_text, 'textwidth' => $W }));
push @lines, $im_width/2 - $O-$W/2, $im_width/2 + $O+$W/2;
}
## Right text...
if( $righttext ) {
my($text,$part,$W,$H) = $self->get_text_width( 0, $righttext, '', @common_text );
my $start = $im_width - $P - $W;
$self->push( $self->Text({ 'x' => $start, 'text' => $righttext, 'halign' => 'right', 'width' => $W, @common_text, 'textwidth' => $W }));
push @lines, $im_width - $P-$O-$W, $im_width -$P+$O;
}
push @lines, $im_width;
## Loop through lines and draw them...
while( my($start,$end) = splice( @lines, 0, 2 ) ) {
$self->push( $self->Rect({ 'x' => $start, 'y' => 6, 'width' => $end-$start, 'height' => 0, @common }));
}
## Draw left hand decoration...
if( $left eq 'arrow' ) {
$self->push($self->Poly({ 'points' => [0,6, ($fontwidth*2),3, ($fontwidth*2),9], @common }));
} elsif( $left eq 'bar' ) {
$self->push($self->Rect({ 'x' => 0, 'y' => 3, 'height' => 6, 'width' => 0, @common }));
}
## and right hand decoration...
if( $right eq 'arrow' ) {
$self->push($self->Poly({ 'points' => [$im_width,6, ($im_width-$fontwidth*2),3, ($im_width-$fontwidth*2),9], @common }));
} elsif( $right eq 'bar' ) {
$self->push($self->Rect({ 'x' => $im_width, 'y' => 3, 'height' => 6, 'width' => 0, @common }));
}
}
1;
sub bp_to_nearest_unit {
my $bp = shift;
my @units = qw( bp Kb Mb Gb Tb );
my $power_ranger = int( ( length( abs($bp) ) - 1 ) / 3 );
my $unit = $units[$power_ranger];
my $unit_str;
my $value = int( $bp / ( 10 ** ( $power_ranger * 3 ) ) );
if ( $unit eq "bp" ) {
$unit_str = "$value bp";
} else {
$unit_str = sprintf( "%.2f%s", $bp / ( 10 ** ( $power_ranger * 3 ) ), " $unit" );
}
return $unit_str;
}