Drawing a graph (libgoocanvas / GTK / Cairo)

Post your FreeBASIC tips and tricks here. Please don’t post your code without including an explanation.
TJF
Posts: 3609
Joined: Dec 06, 2009 22:27
Location: N47°, E15°
Contact:

Drawing a graph (libgoocanvas / GTK / Cairo)

Postby TJF » Sep 23, 2011 14:50

Image

This little examples draws a graph in a window at the screen. The drawing area is scrollable. When you click at the graph ... compile and see yourself.

This example can be compiled and executed under windows and LINUX. The window and the scroll-area is created by GTK. Rendering is done by GooCanvas (GTK extension) using Cairo. You'll need the goocanvas2.0.0.bi header file. And you'll need an updated GTK header, ie from the package GladeToBac3.0.2.zip (oder newer).

All this installation efforts will be recompensed by powerful grafic features with high quality rendering and high speed output - at the screen and also in vector grafic formated files (ie *.ps for printer output).

Here's the code

Code: Select all

#INCLUDE ONCE "gtk/GTK-2.22.0_TJF.bi"
#INCLUDE ONCE "TJF/goocanvas-2.0.0.bi"

' Some variables and types
CONST Xmax = 1000, Ymax = 1000, Smin = 0.1
CONST GridX = 100.0, GridY = GridX, GridW = 400.0, GridH = 300.0


' Initialize GTK+.
gtk_init (@__FB_ARGC__, @__FB_ARGV__)

' Create the window and widgets.
VAR win = gtk_window_new (GTK_WINDOW_TOPLEVEL)
gtk_window_set_default_size (GTK_WINDOW (win), 640, 600)
gtk_widget_show (win)
g_signal_connect (win, "delete_event", G_CALLBACK(@gtk_main_quit), NULL)

VAR scrolled_win = gtk_scrolled_window_new (NULL, NULL)
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), _
                                     GTK_SHADOW_IN)
gtk_widget_show (scrolled_win)
gtk_container_add (GTK_CONTAINER (win), scrolled_win)

VAR canvas = goo_canvas_new ()
gtk_widget_set_size_request (canvas, 600, 450)
goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, Xmax, ymax)
gtk_widget_show (canvas)
gtk_container_add (GTK_CONTAINER (scrolled_win), canvas)


VAR root = goo_canvas_get_root_item (GOO_CANVAS (canvas))

VAR title = goo_canvas_text_new(root, _
       "<span size=""xx-large"">GooCanvas FreeBasic-Example</span>", _
                                GridX + 0.5 * GridW, GridY - 25, -1, _
                                GTK_ANCHOR_S, _
                                "use-markup", 1, _
                                 "font", "Times bold 14", _
                                NULL)

VAR group = goo_canvas_group_new(root, _
                                 "font", "Sans 14", _
                                 NULL)

' calculate some values
VAR line_group = 0.8 ' basic line width
VAR az = 100, pi = 4.0 * ATN(1), n = 2 * az - 1
VAR fx = GridW / (n - 1), sx = (az - 1) / pi, dx = 0.25 * GridW
VAR fy = GridH * 0.45, oy = GridY + 0.5 * GridH

VAR grid = goo_canvas_grid_new(group, _
                               GridX, GridY, GridW, GridH, _
                               dx, fy * 0.5, dx * 1.001, 0.05 * GridH, _
                               "border-width", line_group * 2, _
                               "horz-grid-line-width", line_group, _
                               "vert-grid-line-width", line_group, _
                               "horz-grid-line-color", "gray", _
                               "vert-grid-line-color", "gray", _
                               NULL)

VAR CanPoi = goo_canvas_points_new(az), copo = CanPoi->coords
FOR i AS INTEGER = 0 TO n STEP 2
  copo[i] = GridX + i * fx
  copo[i + 1] = oy - SIN(i/sx) * fy
NEXT
VAR poly = goo_canvas_polyline_new(group, 0, 0, _
                                   "stroke-color", "red",_
                                   "line-width", line_group * 4,_
                                   "tooltip", "Test Polyline", _
                                   "points", CanPoi,_
                                   NULL)
goo_canvas_points_unref(CanPoi)

' and now some text, text, text, ...
VAR ox = GridX - 8 * line_group
VAR text = goo_canvas_text_new(group, "1", _
                               ox, oy - fy, -1, _
                               GTK_ANCHOR_E, _
                               NULL)
text = goo_canvas_text_new(group, "-1", _
                           ox, oy + fy, -1, _
                           GTK_ANCHOR_E, _
                           NULL)
fy /= 2
text = goo_canvas_text_new(group, "<small>0.5</small>", _
                           ox, oy - fy, -1, _
                           GTK_ANCHOR_E, _
                           "use-markup", 1, _
                           NULL)
text = goo_canvas_text_new(group, "<small>-0.5</small>", _
                           ox, oy + fy, -1, _
                           GTK_ANCHOR_E, _
                           "use-markup", 1, _
                           NULL)
text = goo_canvas_text_new(group, "0", _
                           ox, oy, -1, _
                           GTK_ANCHOR_E, _
                           NULL)
ox -= 35
text = goo_canvas_text_new(group, "f(<i>φ</i>) = sin(<i>φ</i>)", _
                           ox, oy, -1, _
                           GTK_ANCHOR_S, _
                           "use-markup", 1, _
                           NULL)
goo_canvas_item_rotate(text, -90.0, ox, oy)

ox = GridX
oy = GridY + GridH + 8 * line_group
text = goo_canvas_text_new(group, "0", _
                           ox, oy, -1, _
                           GTK_ANCHOR_N, _
                           NULL)
ox += dx
text = goo_canvas_text_new(group, "<small>0.5π</small>", _
                           ox, oy, -1, _
                           GTK_ANCHOR_N, _
                           "use-markup", 1, _
                           NULL)
ox += dx
text = goo_canvas_text_new(group, "π", _
                           ox, oy, -1, _
                           GTK_ANCHOR_N, _
                           NULL)
text = goo_canvas_text_new(group, "This <i>φ</i> looks like an <i>angel</i>", _
                           ox, oy + 25, -1, _
                           GTK_ANCHOR_N, _
                           "use-markup", 1, _
                           NULL)
ox += dx
text = goo_canvas_text_new(group, "<small>1.5π</small>", _
                           ox, oy, -1, _
                           GTK_ANCHOR_N, _
                           "use-markup", 1, _
                           NULL)
ox += dx
text = goo_canvas_text_new(group, "2π", _
                           ox, oy, -1, _
                           GTK_ANCHOR_N, _
                           NULL)
text = goo_canvas_text_new(group, "<span size=""x-small""><span foreground=""blue"">" _
                           !"Click me!</span>\n<span background=""yellow"">" _
                           " l · m · r </span></span>", _
                           ox - 0.5 * dx, GridY + .05 * GridH + 0.5 * fy, -1, _
                           GTK_ANCHOR_CENTER, _
                           "use-markup", 1, _
                           "alignment", PANGO_ALIGN_CENTER, _
                           NULL)

' unvisible rect to make the grid clickable (not only lines)
VAR rect = goo_canvas_rect_new(group, _
                               GridX, GridY, GridW, GridH, _
                               "fill-color-rgba", &hFF000000, _
                               "stroke-pattern", NULL, _
                               NULL)

TYPE CbPointer
  AS GooCanvasItem PTR Title, Group
END TYPE

' signal handler (callback)
FUNCTION on_button_press CDECL(BYVAL item AS GooCanvasItem PTR, _
                               BYVAL target AS GooCanvasItem PTR, _
                               BYVAL event AS GdkEventButton PTR, _
                               BYVAL dat AS CbPointer PTR) AS gboolean
  STATIC AS INTEGER mo = 0
  IF event->button = 2 THEN
    goo_canvas_item_stop_animation(dat->Title) : mo = 0
    goo_canvas_item_set_simple_transform (dat->Title, 0.0, 0.0, 1.0, 0.0)
    goo_canvas_item_stop_animation(dat->Group) : mo = 0
    goo_canvas_item_set_simple_transform (dat->Group, 0.0, 0.0, 1.0, 0.0)
    RETURN TRUE
  ELSEIF mo = 0 THEN
    goo_canvas_item_animate (dat->Title, _
                             GridX + 0.5 * GridW, GridY - 25, _
                             Smin, -7.0, _
                             FALSE, 8 * 40, 40, _
                             GOO_CANVAS_ANIMATE_BOUNCE)
    goo_canvas_item_animate (dat->Group, _
                             Xmax, Ymax, _
                             Smin, 90, _
                             FALSE, event->button * 50 * 40, 40, _
                             GOO_CANVAS_ANIMATE_BOUNCE)
    mo = 1
  ELSE
    goo_canvas_item_stop_animation(dat->Title)
    goo_canvas_item_set_simple_transform (dat->Title, 0.0, 0.0, 1.0, 0.0)
    goo_canvas_item_stop_animation(dat->Group) : mo = 0
  END IF

  RETURN TRUE
END FUNCTION
g_signal_connect (group, "button_press_event", _
                  G_CALLBACK (@on_button_press), @TYPE<CbPointer>(title, group))

' Pass control to the GTK+ main event loop.
gtk_main ()

END 0


Hint for windows users:

Don't forget to downlowd and install the GooCanvas binaries -- you'll need Runtime and Dev. If you don't have an updated GTK installation (GTK 2.22 is recomended):
http://ftp.gnome.org/pub/GNOME/binaries/win32/gtk+/2.22/gtk+-bundle_2.22.1-20101227_win32.zip

For updates watch

Zeichnen mit GooCanvas (ein Graph)
AGS
Posts: 1284
Joined: Sep 25, 2007 0:26
Location: the Netherlands

Postby AGS » Sep 25, 2011 8:52

I had a hard time getting this to compile. I downloaded everything needed but I guess I've got too many GTK+ versions on my PC. So I just dumped all the dlls into same dir as the demo and after changing a couple of things (something with a #include directive) everything worked.

Anyway, goocanvas looks great, demo looks good and a lot can be done with a stateful canvas . You can draw several things, put them in the same group and subsequently drag those things as a group. You can add a widget to the canvas and move that around as well. Lots of possibilities (lots of demos necessary to show of possibilities).

I hope I can come up with a nice goo demo (I will cheat by porting the demo at http://wiki.tcl.tk/4330 which is written in TCL/TK so that's going to be an interesting port :)).
TJF
Posts: 3609
Joined: Dec 06, 2009 22:27
Location: N47°, E15°
Contact:

Postby TJF » Sep 25, 2011 16:32

AGS wrote:I had a hard time getting this to compile. I downloaded everything needed but I guess I've got too many GTK+ versions on my PC. So I just dumped all the dlls into same dir as the demo and after changing a couple of things (something with a #include directive) everything worked.

Yes, I also had to do this work on windows. And I tested against different GTK versions.

BTW:
To test different GTK versions I use a folder C:\opt. In this folder several GTK versions are installed in subfolders. To use the GTK installations from each app my path is set to the GTK3\bin folder first and then to one of the GTK2\bin folders (for the runtime DLL loader). In the FB source code I use #LIBPATH "C:\opt\GTK-%version%\lib" to choose the version. Nothing gets mixed this way.

AGS wrote:Anyway, goocanvas looks great, demo looks good and a lot can be done with a stateful canvas . You can draw several things, put them in the same group and subsequently drag those things as a group. You can add a widget to the canvas and move that around as well. Lots of possibilities (lots of demos necessary to show of possibilities).

I also had lots of fun testing this lib. Remember all the pango-cairo text features using the system fonts in different pixel size with attributes (bold, underline, italic, subscript, superscript, ...) and the international UTF-8 character encoding. And it's not only that you can translate, scale, rotate and even use a perspective tranformation (by using cairo_matrix_t) for each group or the complete canvas. You also can easy output the drawing to files in vector grafic formats (PDF, PS, SVG) or pixel formats (PNG) by just sending the drawing to a new cairo_t PTR.

AGS wrote:I hope I can come up with a nice goo demo (I will cheat by porting the demo at http://wiki.tcl.tk/4330 which is written in TCL/TK so that's going to be an interesting port :)).

Sounds great! Good luck for this project.
vladimir777
Posts: 94
Joined: Aug 19, 2011 18:28

g_object_set (text_items(i), "description", "

Postby vladimir777 » Sep 25, 2011 22:42

And here is sample how to use g_object_set
with goocanvas. If you are makig maps then you will read data from a file
and insert it on canvas but without description for each object you will not know which OBJECT (house, road etc) customer selected

Code: Select all

#IF DEFINED(__FB_WIN32__)
#LIBPATH "C:\opt\GTK-2.22.1\lib" ' your paths here
#LIBPATH "C:\opt\goocanvas\lib"
#ENDIF


#INCLUDE "c:\opt\goocanvas\inc\goocanvas-2.0.0.bi"

#DEFINE NULL 0

/'
FUNCTION on_rect_button_press(BYVAL item AS GooCanvasItem PTR, _
                              BYVAL target AS GooCanvasItem PTR, _
                              BYVAL event AS GdkEventButton PTR, _
                              BYVAL data_ AS gpointer) AS gboolean
  ?"rect item received button press event"
  RETURN TRUE
END FUNCTION
'/




FUNCTION on_button_press(BYVAL item AS GooCanvasItem PTR, _
                        BYVAL target AS GooCanvasItem PTR, _
                        BYVAL event AS GdkEventButton PTR, _
                        BYVAL dat AS gpointer) AS gboolean
  IF event->button <> 1 ORELSE event->TYPE <> GDK_BUTTON_PRESS THEN RETURN FALSE

 
  'goo_canvas_item_translate (target, 1,1)
 
 
 
 
  dim as gchar ptr desc
  g_object_get (target, "description", @desc, NULL)
  print *desc
 
  RETURN TRUE
END FUNCTION

'gtk_set_locale ()
gtk_init (@__FB_ARGC__, @__FB_ARGV__)

' Create the window and widgets.
VAR win = gtk_window_new (GTK_WINDOW_TOPLEVEL)
gtk_window_set_default_size (GTK_WINDOW (win), 640, 600)
gtk_widget_show (win)
g_signal_connect (win, "delete_event", G_CALLBACK(@gtk_main_quit), NULL)

VAR scrolled_win = gtk_scrolled_window_new (NULL, NULL)
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win), _
                                     GTK_SHADOW_IN)
gtk_widget_show (scrolled_win)
gtk_container_add (GTK_CONTAINER (win), scrolled_win)

VAR canvas = goo_canvas_new ()
gtk_widget_set_size_request (canvas, 600, 450)
goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 1000, 1000)

gtk_widget_show (canvas)
gtk_container_add (GTK_CONTAINER (scrolled_win), canvas)

VAR root = goo_canvas_get_root_item (GOO_CANVAS (canvas))

Dim rect_items(1 To 20) As GooCanvasItem Ptr
Dim text_items(1 To 20) As GooCanvasItem Ptr

dim i as integer
dim x as double
dim y as double

for i = 1 to 20
   x=rnd*1000:y=rnd*1000



   rect_items(i) = goo_canvas_rect_new (root, x, y, 50, 50, _
                               "line-width", 3.0, _
                               "radius-x", 10.0, _
                               "radius-y", 10.0, _
                               "stroke-color", "green", _
                               "fill-color", "red", _
                               NULL)
   g_object_set (rect_items(i), "description", "R:" + str(i), NULL)

   text_items(i) = goo_canvas_text_new (root, str(i), x+25, y-25, -1, _
                               GTK_ANCHOR_CENTER, _
                               "font", "Sans 24", _
                               NULL)
   g_object_set (text_items(i), "description", "T:" + str(i), NULL)
next i                           



g_signal_connect(root, "button_press_event", G_CALLBACK(@on_button_press), NULL)

gtk_main ()

END 0
TJF
Posts: 3609
Joined: Dec 06, 2009 22:27
Location: N47°, E15°
Contact:

Postby TJF » Sep 26, 2011 5:47

@vladimir777

Thanks for your example. I would improve this
  • A signal handler connected to the button_press_event will allways receive an event with event->type = GDK_BUTTON_PRESS (AFAIK you need not check it).
  • With the given code (on_button_press connected to root) the event handler may get a zero pointer for target (when the user clicks on an empty area). In this case the g_object_get function returns zero and prints an error message. To avoid this error message you may better use in button_press_event

    Code: Select all

      IF target THEN
        DIM AS gchar PTR desc
        g_object_get (target, "description", @desc, NULL)
        PRINT *desc
      ELSE
        ? "Button press without target."
      END IF
vladimir777
Posts: 94
Joined: Aug 19, 2011 18:28

Postby vladimir777 » Sep 27, 2011 16:59

I already did a simple routine for client to be able to view DXF files
DXF file were simple: just point lines and polylines all in one layer


Then I search internet and find this It is raw C code for reading DWG files

It will be very cool with GOOCANVAS!!!
(and not just goocanvas)

http://git.savannah.gnu.org/cgit/libredwg.git/tree/

This is a library to allow reading data from a DWG file. That's a very important acquisiton, which may improve a lot the ability of the free software comunity to develop more interesting applications, in the field of computer technical drawing (CAD).

The DWG structure is very complicated, it seems to be crafted so that none can easily understand it. That's a strong reason to not use it, and that's also why we do not provide the writing feature in the library. One should use LibDWG mainly to read such files, filtering them to some other format, free and usable.
TJF
Posts: 3609
Joined: Dec 06, 2009 22:27
Location: N47°, E15°
Contact:

Postby TJF » Sep 27, 2011 18:06

@vladimir777

Sounds great! I'm looking forward to your next code example.
vladimir777
Posts: 94
Joined: Aug 19, 2011 18:28

Postby vladimir777 » Sep 27, 2011 19:33

Nothing to show. I just use simple dxf routine to read POINTS and LINES.
and goocanvas to show on the screen

It is not more advanced (except it reads file) than I posted already.
When I have something new to show I will make example, but I CAN NOT
post this little project because data are proprietary (big oil company)
I wouldnt even risk to place s screenshot.

Whenever I have something it is useful to other I will post it and share,
but I am not using FB that much now
jmgbsas
Posts: 7
Joined: Dec 26, 2020 16:03

Re: Drawing a graph (libgoocanvas / GTK / Cairo)

Postby jmgbsas » Feb 22, 2021 22:04

And, Where is the cairo commands?
cairo_show_text...
cairo_move_to etc ????
I have an application with cairo and need to embed in gTK I am using the commands of cairo...
TJF
Posts: 3609
Joined: Dec 06, 2009 22:27
Location: N47°, E15°
Contact:

Re: Drawing a graph (libgoocanvas / GTK / Cairo)

Postby TJF » Feb 23, 2021 6:21

jmgbsas wrote:And, Where is the cairo commands?
cairo_show_text...
cairo_move_to etc ????
I have an application with cairo and need to embed in gTK I am using the commands of cairo...

And, where is your netiquette?

You're in a more than 110 month old thread on drawing a graph, based on libgoocanvas (based on Cairo) and meanwhile deprecated GTK-2.22.

To answer your question:
The Cairo commands are in the source code of libgoocanvas.

Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 5 guests