Chapter Contents

Previous

Next
SAS/AF Software: Class Dictionary

Using the Organizational Chart Class


About the Data

In an organizational chart, each piece of information and its relation to every other piece of information is graphically represented. Every piece of information is a node that has a single parent node (except the root node, which is the top or first node in the tree), and zero or more subordinate nodes or children. A node and all the nodes below it are called a tree.

An organizational chart must be created from a data set or SCL list. Each observation in a data set or sublist in a list represents a node in the tree. The data for the chart tell the organizational chart object where to place each node in the tree. To do this, the data must define a node's position in the tree by providing either

Note:   Because the Organizational Chart class is a legacy class (that is, one based on Version 6), it does not support table specifications that exceed 32 characters. This limitation includes both name and associated options.  [cautionend]

Specifying a Level Number

Include the level number in a data set variable and map that variable to the node variable, LEVEL. For example, the data set in Data Set with Level Number contains the variables NODE and LEVEL. The shaded portion of the output includes notes that explain how the value of LEVEL determines the node's position in the tree:

Data Set with Level Number
            NODE             LEVEL        Node Position

            USA                1          at the tree root
            EAST               2          below USA
            Pat Watson         3          below EAST
            Miguel Aguero      4          below Pat Watson
            Fred Wong          3          next to Pat Watson and below EAST
            WEST               2          below USA and next to EAST
            Dana Josephs       3          below WEST
            Brenda Kratka      3          below WEST and next to Dana Josephs

Notice that a child node such as Pat Watson is listed directly after its parent (EAST). Miguel Aguero is a child node of Pat Watson and is listed directly after its parent and before any siblings of the parent, such as Fred Wong.

The mapping list for this data set is

Node Information Data Set Variable
TEXT = NODE
LEVEL = LEVEL
CURRENT_NODE = LEVEL

CURRENT_NODE is set in the Mapping List window field Data set variable that identifies current node. It is not a node variable but a list item that determines hierarchy.

Assigning a level number is the fastest way to build a chart because the chart does not need to search to find a node's parent.

Specifying the Parent Node

Include a data set variable that describes the node's parent and map that variable to PARENT_NODE. The data set in Data Set Specifying Parent Node includes the same node data as before (and creates the same chart), but instead of the LEVEL variable the data set contains a variable called FROM that contains the value of the node just above it in the tree (its parent). The exception is the root node, which has no parent so none is specified.

Data Set Specifying Parent Node
                        TEXT             FROM

                        USA
                        EAST             USA
                        Pat Watson       EAST
                        Miguel Aguero    Pat Watson
                        Fred Wong        EAST
                        WEST             USA
                        Dana Josephs     WEST
                        Brenda Kratka    WEST

The mapping list for this data set is

Node Information Data Set Variable
TEXT = NODE
CURRENT_NODE = NODE
PARENT_NODE = LEVEL

PARENT_NODE is set in the Mapping List window field called Data set variable that identifies parent node. Like CURRENT_NODE it is not a node variable but a list item that determines hierarchy.

The data set in Data Set Specifying Two Text Variables also determines the chart hierarchy by defining the parent node, in this case the manager's employee number. In the data set, each observation represents an employee and includes the employee's number as well as the number of the employee's manager.

Unlike the previous examples, the variables that are displayed as text (TITLE and NAME) are not the same as the variable specifying the current node (EMPNO). It is not necessary to display either PARENT_NODE or CURRENT_NODE.

Data Set Specifying Two Text Variables
            TITLE            NAME               EMPNO    MNGRNO

            President        Jean DuBois        0001         .
            Eastern VP       Laura Stoyavich    0002      0001
            Western VP       Roy Hodges         0005      0001
            Publisher        Pat Watson         0100      0002
            Sales Manager    Fred Wong          0200      0002
            MIS Manager      Dana Josephs       0300      0005
            Security         Brenda Kratka      0400      0005

The mapping list for this data set is

Node Information Data Set Variable
TEXT = NAME
TEXT = TITLE
CURRENT_NODE = EMPNO
PARENT_NODE = MNGRNO

Assigning the two text items displays the employee's name above the title in each node.

Specifying the parent node is less efficient because the chart searches the entire tree every time it processes an observation and positions a node.

Populating the Organizational Chart

When populating from a data set, use either the LEVEL node variable or the Parent node and Current node fields in the Mapping List window to indicate the chart hierarchy. (These fields correspond to the PARENT_NODE and CURRENT_NODE mapping list items).

When using a parent-child specification for the data used by the organizational chart, every child node must have a uniquely identified parent. If a child node does not have a unique parent, the resulting organizational chart may not render as intended. In such a situation, there may be more than one possible tree, which requires the organizational chart to select one.

When populating from an SCL list that specifies node variables, use the CHILDREN sublist to specify all the children of a node. This creates the chart hierarchy. For example, this is the contents of an SCL list that produces the same tree as the previous examples:

<listid>(TEXT = "USA"
         CHILDREN = ((TEXT = "EAST"
                      CHILDREN = ((TEXT = "Pat Watson"
                                   CHILDREN = ((TEXT = "Miguel Aguero")))
                                  (TEXT = "Fred Wong")))
                     (TEXT = "WEST"
                      CHILDREN = ((TEXT = "Dana Josephs")
                                  (TEXT = "Brenda Kratka"))))

For an example of populating an organizational chart from an SCL list, see the _repopulate method in this class.


About Nodes

Each node in an organizational chart is a widget that can display text or an image, or both. In addition, each node can perform actions or run sections of SCL code when selected.

Node Variables

Every node in an organizational chart has a predefined set of node variables that stores information about the node data it represents and about the node's appearance. Each node in the tree stores information in the variables described in the following table.

Node Variables
Node Variable Name Type Description
BACKGROUND_COLOR C the node's background color
BORDER_COLOR C the node's border color
CHILDREN N a list of the children of a node. Used only by the _repopulate method. The _getChildren method conditionally returns the value of this variable. See the description of these methods for details.
CLASS C the three- or four-level name of the widget class associated with the node type assigned to the current observation or list item. Used only by the _repopulate method. No Organizational Chart methods return the value of this variable.
CVALUE C an internal character value assigned to the node. Use the Mapping List window to assign a character data set variable to the CVALUE variable. You can store any text string here.
FOREGROUND_COLOR C the node's foreground color
ID N a numeric identification number assigned to the node by the user. Use the Mapping List window to assign a numeric data set variable value to the ID variable.
IMAGE C the name of an image:

  • For type 3 nodes, specify a one-level name of an IMAGE entry in the default image icon catalog, or a three- or four-level name of a specific IMAGE entry.

  • For type 2 nodes, specify either a host file name or a three- or four-level catalog entry name. (See also the Image class.)

  • A partial image name if the Name field in the Text and Image window specifies a prefix or mask.

LEVEL N a number indicating the level of the node in the tree
LINE_COLOR C the color of the line connecting the node to its parent
NODEID N a unique identification number assigned to the node by the organizational chart object. The user cannot set NODEID.
NVALUE N an internal numeric value assigned to the node. Use the Mapping List window to assign a numeric data set variable to the NVALUE variable. You can store any number here.
OBS N the number of the SAS data set observation from which the node was created. The OBS value may not match the true observation number if a WHERE clause was active when the organizational chart read in the data set, or if the node variable OBS is mapped to a different data set variable (not OBS) in the SAS data set.
OWNER N the numeric identifier of the organizational chart that is automatically passed to the node's _init, _postinit, and _select methods. You can also set this value by calling the _getOwner method after calling CALL SUPER (_SELF_, '_init'). This value cannot be retrieved by any other method.
TEXT C the text of the node; each line of text is a separate TEXT item
TYPE N the number of the node type (see Node Types). If not given, the node uses the default node type unless you specify CLASS.
WIDGETID N the temporary identification number assigned to the node by the frame. WIDGETID cannot be set by the user. Because each node is a widget, it has an object identifier as well as a node identifier. This value changes when you scroll the chart. Do not store this value.


Node Identifier

Organizational Chart methods identify nodes by the numeric node identifier (NODEID) instead of the object identifier (WIDGETID) because during scrolling, the nodes are removed from the frame when they are not visible, rendering the object identifier invalid. However, the organizational chart node identifier is always valid. Therefore, it is best to use only Organizational Chart methods to modify the appearance of a node so that you can scroll a widget off and back onto the display and the widget retains its appearance.

As an alternative, you may subclass a node widget and run other methods in the node's _init or _postinit method. Then if a node is scrolled out of viewing area and removed, when it is scrolled back into view, its _init and _postinit methods run and cause it to reappear.

Node Types

Nodes are separated into types. Each type has general region and object settings such as region borders, colors, fonts, line widths, and action upon selection. The following table describes the predefined node types.

Node Types
Node Type Index Description Widget Subclass
1 graphics text only (subclass of the Extended Text Entry class) SASHELP.FSP.ORGTEXT.CLASS
2 images only (subclass of the Image class) SASHELP.FSP.ORGIMAG.CLASS
3 images with text (subclass of the Image Icon class) SASHELP.FSP.ORGIMGI.CLASS

The general settings of these types can be changed, but the widget class, node type number, and description cannot be changed. You can create new node types with different colors, fonts, region borders, and so on. from the same widget class. Specify new node types in the Attributes window.

Because general node characteristics are specified in the Attributes window, several different node types can be of the same class, but you can change the default images, fonts, colors, and so forth by the numeric node type without creating more classes. To create a new node widget class, subclass one of the three predefined widget classes mentioned in the Node Types or create an entirely new widget class. For more information on subclassing, see Creating a New Node Type.

The three predefined organizational chart widget classes only override the _init and _binit methods of the base SASHELP.FSP.WIDGET classes they were derived from. In addition, they each define a _setFcolor method the Organizational Chart class calls to set the foreground color of a widget. For graphics text objects (node type 1) and image icons (node type 3), this method sets text color. For image objects (node type 2), _setFcolor has no effect.

The nodes in a chart can be different types, and nodes can be created from any of the following:


Creating a Sample Organizational Chart

Two sample data sets are provided with the class and can be selected from the Data set field of the Attributes window. To create and test an organizational chart from one of the sample data sets, follow these steps:

  1. Open a frame and create an organizational chart object.

  2. In the Attributes window, select WORK.ORGSAMP1 from the list displayed by the down arrow in the Data set field. Change both horizontal and vertical node spacing to 32 and turn off Display chart at run time only.

  3. Open the Node Appearance window and change Border to Simple.

  4. Open the Select Action window and turn on Hide/unhide children upon double click.

  5. Return to the frame and run TESTAF.

  6. Double click nodes to hide and unhide them. Change the background color of the nodes by selecting Attributes from the pop-up menu. Then open the Node Appearance window and choose a color for Background. Return to the Testaf window in which the nodes display the new color.

  7. Close the Testaf window and return to the frame. Note that the nodes retain their original background color.


Instance Variables

Selected instance variables that can be used with an organizational chart widget are described here. Instance variables are typically modified with methods or through the Attributes window. For more information on instance variables, see SAS/AF online help.

You can use the appropriate GETNITEMx() function to retrieve these values from the organizational chart widget identifier. If you set these instance variables with the appropriate SETNITEMx() function, you should make this method call:

call send (orgid, '_set_option_', 
          'iv_changed');

This statement notifies the organizational chart that one or more instance variables were set directly by the user.

For an example of using instance variables to control the run-time menu, see Controlling the Pop-up Menu with Instance Variables.

DATASET
names the data set that is read during the _repopulate method, if a data set identifier is not given. This value is automatically obtained from the Attributes window.

KILLMENU
controls the organizational chart's run-time menu. If the value is 0 or missing, the menu is available. Otherwise, the menu is unavailable. This variable has no effect on user pop-up options set with the PREPOP and POSTPOP instance variables.

_lselected
contains the node identifier of the selected node before the current node. This value is cleared if the node is released during a _repopulate method call.

MAPLIST
contains the list of node variables that have been mapped to data set variables. Every item in the list is a character item and should have a valid name. Valid names are listed in Node Variables. This list is automatically built from values entered in the Mapping List window but can be passed into the _repopulate method.

The character values for the mapping list items are the data set variable names that specify that particular attribute. For example, an item named TEXT with a value of OFFICE means the values in the data set variable OFFICE specify the text to display for each node.

If PARENT_NODE is not in the list, or is blank, you must map the CURRENT_NODE variable to the node level number as well as the LEVEL variable.

You do not have to specify all mapping list variables. The simplest mapping lists would specify TEXT and CURRENT_NODE if level numbers are used, or TEXT, CURRENT_NODE, and PARENT_NODE if level numbers are not used. For examples, see About the Data.

The PARENT_NODE and the CURRENT_NODE must map to the same variable type. That is, both must be numeric, or both must be character.

_popid
specifies the node identification number of the node the _popup method is running for. It is 0 unless you override _childPopup.

POPMENU_ITEM
returns the item number in the user-defined POPMENU.LIST of the selected item. Valid only in POSTPOP.

POPMENU_GRAYLIST
specifies a list of pop-up menu character values to be grayed out. These values can refer to

For example, specify "Print..." to gray that menu item. Set this list during the PREPOP label/method. An item that does not exist in the menu is ignored. See also the PREPOP instance variable.

POPMENU_LIST
specifies a list of items to add to the end of the run-time pop-up menu. Items marked INACTIVE via the SETLATTR() function are grayed in the pop-up menu.

POSTPOP
defines a labeled section of SCL code or a method to run if the user selects one of the user-defined options set up by the code specified by the PREPOP variable. Values can be a one-level SCL label or the five-level name of a method from another SCL program (for example, WORK.A.A.SCL:MYPOP).

PREPOP
defines a labeled section of SCL code or a method to run before the run-time pop-up menu displays. Values can be a one-level SCL label or the five-level name of a method from another SCL program.

You may add selections onto the end of the menu by defining an SCL list of options and assigning the instance variable POPMENU_LIST to that list.

_rootid
contains the node identification number of the root node, typically the title node. If there is no tree, this value is 0. The value of _rootid changes if the title is hidden or changes, or if the chart is repopulated. Therefore, each time you need this value, you should acquire it by calling the SCL function GETNITEMN(). Do not store this value.

_selected
contains the node identification number of the most recently selected node in the tree. This value is cleared if the node is released during a _repopulate method call.


Specifying Images for Nodes

When you use a node type that includes an image, you can choose whether the nodes display a standard image (the same image for every node of that type) or a custom image (the image depends on the content of the node).

If you want every node of a particular type to display the same image, assign the image in the Text and Image window. In this case you explicitly name the image using either the path name of an external file or the name of an IMAGE catalog entry.

If you want every node of a particular type to display a different image whose name is specified in a variable in the data set that populates the chart, you can do it in two ways:

  1. Store the name and location of the image associated with each node in a variable in the data set. In the Mapping List window, map the data set variable, for example PICTURES, to the node variable IMAGE. In this case, the data set variable must contain the exact location of the image, either the complete catalog entry or full file path name.

    If you want to assign a default image to display if the image in the data set is missing, specify that image in the Text and Image window and set Node Image Names to Override Name.

  2. If the data set does not include the complete location of the image, but has instead only the image name or some part of the name, you can use either a prefix or a mask to build an image reference from that information.

    For example, suppose you are populating a chart using both a data set of employee information and a catalog of employee photographs. The data set includes the employee identification number which is also used as the name of the catalog entry containing the employee's photograph.

    To use a prefix, in the Name field of the Text and Image window, specify the library and catalog containing the photographs and set Node Image Names to Append to Name. In the Mapping List window map the data set variable, for example EMPNUM, to the node variable IMAGE.

    Using a mask is similar except that instead of specifying a prefix, you specify the complete location using an asterisk (*) where the value of the data set variable should be substituted. For example, if the employee photographs are stored in a UNIX environment in a directory with filenames using the pattern pxxxx.photo.gif, where xxxx is the employee number, you could specify a pathname such as /mydir/p*.photo.gif, set Node Image Names to Override Name, and map EMPNUM to IMAGE. When the chart is populated, the employee number is inserted into the mask to build the correct pathname.


Creating a New Node Type

If you subclass one of the predefined node types to create a new widget class, you need to override the default _init and _binit methods and initialize the widget yourself from information passed to you from the organizational chart object. You may also override the default _select method to have whatever you want happen upon node selection.

In the _init method for your own defined class, the instance variable NODEDATA is passed to you from the _SELF_ list. NODEDATA is a list containing the information the organizational chart object has about the node it received at population time. This list is only valid during the _init and _binit methods. The format of the list is the same as the format of the returned list in the _getChildren method. The only difference is that the list items WIDGETID and CHILDREN are omitted.

It is up to you to set the proper instance variables for that widget class and perform a CALL SUPER method call if needed. If you subclass an Organizational Chart class and you do not wish the organizational chart to override your initialization settings during the CALL SUPER, you can set the numeric instance variable INITED to 1 on the NODEDATA list before calling CALL SUPER.

This is an example of the _init method for a user-defined widget class that will be used as a node. This code performs self initialization before CALL SUPER:

INIT: METHOD;
  ndinfo = getniteml(_self_,'_nodedata');
  text   = getnitemc(ndinfo,'text');
  value  = getnitemn(ndinfo,'nvalue');
  rc = setnitemc(_self_,text, 'mytext');
  rc = setnitemn(_self_,value,'myvalue');
  rc = setnitemn(ndinfo,1,'inited');
  call super(_self_,_method_);
ENDMETHOD;

The instance variable named _nodeid can be accessed in the SELECT label or SELECT METHOD for that widget and used for any appropriate Organizational Chart class methods you wish to call. This is true no matter what widget class you are using.


Controlling the Pop-up Menu with Instance Variables

This example shows how you can customize the run-time pop-up menu by adding items or graying items. It shows how to do this without having to subclass the organizational chart or node classes, and without having to create additional SCL programs to handle pop-up menu methods.

In addition, it shows how to use the _snapshot method (Widget class) to take a "picture" of the organizational chart and save it as an IMAGE catalog entry (see the POSTPOPL label in the example). The saved image can then be displayed with the Image or Image Icon class in any Frame. You can also change the size of the image when it is displayed with these classes.

Other features of the program include

This is how the program works. When the user opens the run-time pop-up menu, the organizational chart object first looks to see if the application specifies a PREPOP label or method. If so, the object runs that label to see if the application wants to gray or add anything to the menu. In this case, it adds two items: Edit and Take snapshot.

Then it tests to see if the user clicked on a node. If so, it grays out the application-defined item Edit by making it INACTIVE. It also grays out the default menu Attribute by putting it on a 'graylist'.

If the user makes a menu selection that is defined by the application, the POSTPOPL section runs. In this program POSTPOPL defines the action to take when the user selects either Edit or Take snapshot. If the selection is not an application defined item, the POSTPOPL section does not run.

   /* Get the widget ID for the chart and 
      tell        */
   /* the object to run PREPOP and POSTPOP 
      sections.  */
   /* Create the lists.         
                            */
INIT:
   call send(_frame_,"_getWidget",
             "ORGCHART",orgid);
   rc       = setnitemc(orgid,"PREPOPL,
                        "PREPOP");
   rc       = setnitemc(orgid,"POSTPOPL,
                        "POSTPOP");
   graylist = makelist(0);
   popmlist = makelist(0);
   return;

   /* After the program has run, free the
      lists. */
TERM:
   rc       = dellist(graylist,"Y");
   rc       = dellist(popmlist,"Y");
   rc       = setniteml(orgid,0,
                       "POPMENU_GRAYLIST");
   rc       = setniteml(orgid,0,
                       "POPMENU_LIST");
   return;

   /* When the menu is opened, add two 
      items to the menu. */
PREPOPL:
   rc       = clearlist(graylist,"Y");
   rc       = clearlist(popmlist,"Y");
   rc       = insertc(popmlist,"Take 
                      snapshot",-1);
   rc       = insertc(popmlist,"Edit...",-1);

      /* Test if the cursor was over a 
         node when */
      /* the user clicked to open the 
         menu.      */
   popid    = getnitemn(orgid,"_popid",1,1,0);

       /* If not on a node, gray the 
          application-defined 'Edit...' */
       /* menu item and the default
         'Attributes'
          menu item. */
   if (popid eq 0) then
      rc    = setlattr(popmlist,"INACTIVE",
                      -1);
   rc       = insertc(graylist,"Attributes...",
                     -1);
   rc       = setniteml(orgid,graylist,
                        "POPMENU_GRAYLIST");
   rc       = setniteml(orgid,popmlist,
                       "POPMENU_LIST");
   return;

   /*  If the user selected one of the
       items defined  */
   /*  in PREPOPL, this section runs.                 */
POSTPOPL:
   item     = getnitemn(orgid,"POPMENU_ITEM");
   select (item);
      when (1); /* SNAPSHOT */
         fname    = "WORK.A.SNAPSHOT.IMAGE";
         imgdatid = instance(loadclass("SASHELP.
                             FSP.IMGDAT.CLASS"));
         call send(orgid,"_snapshot",imgdatid,
                   rc,"MAIN");
         call send(imgdatid,"_writeCatalog",
                   fname);
         call send(imgdatid,"_term");
         _msg = "NOTE: Snapshot saved as
                 " || fname;
      when (2); /* EDIT     */
         call display("MYEDITOR.FRAME",
                       orgid,popid);
      end;  /* select */
   return;


Chapter Contents

Previous

Next

Top of Page

Copyright 1999 by SAS Institute Inc., Cary, NC, USA. All rights reserved.