Category: | GUI programming |
Author/Contact Info | zentara of perlmonks |
Description: | The Goo::Canvas is ideal for solving many graphing problems. Like multiple y-axis (not shown here :-), zooming, and saving to pdf. This demo shows how to reverse the y axis (typically negative on canvases), so your plots can be in the normal cartesian direction. This makes plotting easier, your x,y values are plotted without the need to fudge their direction. This comes at a small price of needing to invert some text in the group. Margins are also taken care of nicely, by translating the plotting group from the edges, so it all stays 0,0 for plotting. 2 ways of rotating text are shown. One is an actual rotation of the Y_axis_label; and the other is the x tick values, which are automatically wrapped by 'char', to width 1, to give a vertical number..... the vertical spacing is a bit off, compared to fully rotated text, but it is easy to read ( no need to cock your head sideways to read :-) ) Zooming and pdf saving are also shown. This is just my proof-of-concept demo, to test ideas before making a full-fledged Goo::Canvas::Graph module. |
#!/usr/bin/perl -w use strict; use warnings; use Goo::Canvas; use Gtk2 '-init'; use Glib qw(TRUE FALSE); use Gtk2::Gdk::Keysyms; my $scale = 1; my $window = Gtk2::Window->new('toplevel'); $window->signal_connect('delete_event' => sub { Gtk2->main_quit; }); $window->set_size_request(800, 600); my $swin = Gtk2::ScrolledWindow->new; $swin->set_shadow_type('in'); $window->add($swin); my ($cwidth,$cheight)= (1200,1200); my $canvas = Goo::Canvas->new(); $canvas->set_size_request(800, 650); $canvas->set_bounds(0, 0, $cwidth, $cheight); my $black = Gtk2::Gdk::Color->new (0x0000,0x0000,0x0000); my $white = Gtk2::Gdk::Color->new (0xFFFF,0xFFFF,0xFFFF); $canvas->modify_base('normal',$white ); $swin->add($canvas); my $root = $canvas->get_root_item(); my ($margin_x,$margin_y) = (100,100); my $g = Goo::Canvas::Group->new($root); $g->scale(1,-1); #reverse direction of y axis, so graphing will be nor +mal cartesian $g->translate(0 + $margin_x, -1200 + $margin_y); #notice translations +are reversed $canvas->scroll_to(0,$cheight); # add a background rect filling $g, so button press will be detected # otherwise $g will be invisible to button-press-event my $rect = Goo::Canvas::Rect->new( $g, 0, 0, $cwidth,$cheight, 'line-width' => 1, 'stroke-color' => 'white', #invisible on white bg 'fill-color' => 'white', # must be filled for mouse event sensit +ivity ); # some key help my $markup = "<span font_family ='Arial ' foreground = '#000000' size = '12000' weight = 'ultralight'> Keys: 'Z' zoom in, 'z' zoom ou +t, 's' save a PDF </span>"; my $text = Goo::Canvas::Text->new( $g, $markup, -80 , 80 , -1, 'w', 'use markup' => 1, ); $text->scale(1,-1); $g->signal_connect('button-press-event', \&on_g_button_press); $canvas->signal_connect_after('key_press_event', \&on_key_press); $canvas->can_focus(TRUE); $canvas->grab_focus($root); &set_axis(); &plot(); $window->show_all(); Gtk2->main; sub set_axis{ # x axis my $xline = Goo::Canvas::Polyline->new( $g, TRUE, [0,0,900,0], 'stroke-color' => 'black', 'line-width' => 3, ); #label my $markup = "<span font_family ='Arial ' foreground = '#000000' size = '18000' weight = 'bold'> X axis Label </span>"; my $text = Goo::Canvas::Text->new( $g, $markup, 450 , 80 , -1, 'center', 'use markup' => 1, ); $text->scale(1,-1); for my $x (0..900){ if ($x % 100 == 0){ my $xtick = Goo::Canvas::Polyline->new( $g, TRUE, [$x,0,$x,-25], 'stroke-color' => 'black', 'line-width' => 3, ); $markup = "<span font_family ='Arial ' foreground = '#0000ff' size = '10000' weight = 'light'> $x </span>"; $text = Goo::Canvas::Text->new( $g, $markup, $x-1 , 10 , 1, 'north-east', 'use markup' => 1, 'wrap' => 'char'); $text->scale(1,-1); }elsif ($x % 10 == 0){ my $xtick = Goo::Canvas::Polyline->new( $g, TRUE, [$x,0,$x,-15], 'stroke-color' => 'red', 'line-width' => 1, ); my $markup = "<span font_family ='Arial ' foreground = '#ff0000' size = '8000' weight = 'ultralight'> $x </span>"; my $text = Goo::Canvas::Text->new( $g, $markup, $x-1 , 6 , 1, 'north-east', 'use markup' => 1, 'wrap' => 'char'); $text->scale(1,-1); } } # y axis my $yline = Goo::Canvas::Polyline->new( $g, TRUE, [0,0,0,900], 'stroke-color' => 'black', 'line-width' => 3, ); #label $markup = "<span font_family ='Arial ' foreground = '#000000' size = '18000' weight = 'bold'> Y axis Label </span>"; $text = Goo::Canvas::Text->new( $g, $markup, -70 ,-450 , -1, 'center', 'use markup' => 1, ); $text->scale(1,-1); $text->rotate(-90,-70,-450); for my $y (0..900){ if ($y % 100 == 0){ my $ytick = Goo::Canvas::Polyline->new( $g, TRUE, [0,$y,-25,$y], 'stroke-color' => 'black', 'line-width' => 3, ); $markup = "<span font_family ='Arial ' foreground = '#0000ff' size = '10000' weight = 'light'> $y </span>"; $text = Goo::Canvas::Text->new( $g, $markup, -25 , -$y -8 , -1, 'north-east', 'use markup' => 1, ); $text->scale(1,-1); }elsif ($y % 10 == 0){ my $ytick = Goo::Canvas::Polyline->new( $g, TRUE, [0,$y,-15,$y], 'stroke-color' => 'red', 'line-width' => 1, ); my $markup = "<span font_family ='Arial ' foreground = '#ff0000' size = '8000' weight = 'ultralight'> $y </span>"; my $text = Goo::Canvas::Text->new( $g, $markup, -16 , -$y - 6 , -1, 'north-east', 'use markup' => 1, ); $text->scale(1,-1); } } } sub plot{ my @points; for my $x (0..900){ push @points,$x, 300 + 100*sin( $x /5); } my $poly = Goo::Canvas::Polyline->new( $g, FALSE, \@points, 'stroke-color' => 'green', 'line-width' => 2, ); } sub on_g_button_press { #print "@_\n"; my ( $group, $widget, $event ) = @_; print $widget ,' ',$event->type, ' ','button',' ',$event->button +,"\n"; my ($x,$y) = ($event->x,$event->y); print "$x $y\n"; return 0; } sub on_key_press { # print "@_\n"; my ( $canvas, $event ) = @_; # print $event->type,"\n"; if ( $event->keyval == $Gtk2::Gdk::Keysyms{Z} ) { $scale += .1; $canvas->set_scale($scale); $canvas->scroll_to(0,$cheight); } if ( $event->keyval == $Gtk2::Gdk::Keysyms{z} ) { $scale -= .1; $canvas->set_scale($scale); $canvas->set_scale($scale); $canvas->scroll_to(0,$cheight); } if ( $event->keyval == $Gtk2::Gdk::Keysyms{s} ) { write_pdf($canvas); } # print "key was ", chr( $event->keyval ), "\n"; return 0; } sub write_pdf { #print "@_\n"; my $canvas = shift; print "Write PDF...\n"; my $scale = $canvas->get_scale; print "scale->$scale\n"; my $surface = Cairo::PdfSurface->create("$0-$scale.pdf", $scale*$cwidth, $scale*$cheight); my $cr = Cairo::Context->create($surface); # needed to save scaled version $cr->scale($scale, $scale); $canvas->render($cr, undef, 1); $cr->show_page; print "done\n"; return TRUE; } __END__ |
Back to
Code Catacombs