Menus

NodeTreeMenu

You can add nodeTreeMenu using this option:

    
      nodeTreeMenu: true,

Example:

Family Tree JS has these menus

  1. menu - top right corner
  2. nodeMenu - a button in the node
  3. nodeContextMenu - context menu for none

Here is how to add a menu in the FamilyTree configuration:

 
        
    nodeMenu: {
        details: { text: "Details" },
        edit: { text: "Edit" },
        add: { text: "Add" },
        remove: { text: "Remove" }
    },
    

The demo bellow demonstrates how to define, menu, nodeMenu and nodeContextMenu in the FamilyTree configuration:

Predefined menus items

  • edit - calls editUI.show method
  • details - calls editUI.show method
  • svg - calls exportSVG method
  • pdf - calls exportPDF method
  • png - calls exportPNG method
  • csv - calls exportCSV method
For the predefined menu items you can specify the text and/or the icon
 
    
    nodeContextMenu: {
        edit: { text: "Edit", icon: FamilyTree.icon.edit(18, 18, '#039BE5')  },
    },
    

Add your own menu item to the node menu with Icon, Click event and Text

The icon can be image html element (img) or svg element:

 
    
let webcallMeIcon = <svg width="24" height="24" viewBox="0 0 300 400"><g transform="matrix...
// the svg code is in the example below
 
    
    nodeMenu: {
        call: {
            icon: webcallMeIcon,
            text: "Call now",
            onClick: callHandler
        }
    },
    

callHandler function has one parameter nodeId.

 
    
function callHandler(nodeId) {
    let nodeData = family.get(nodeId);
    let employeeName = nodeData["name"];
    window.open('https://webcall.me/' + employeeName, employeeName, 'width=340px, height=670px, top=50px, left=50px');
}
    

Here is an example:


Override node menu items for specific node using tags

You can override node menu items by tagging a node

If you have this in nodeMenu option:
 
    
        pdf: {
            text: "Export To Pdf",
        }
    
To ovverride the menu for some nodes, add a tag in tags option:
 
    
        overrideMenu:{
            nodeMenu:{
                edit: {text: "Edit" }
            }
        }
    
Then add the same tag in that nodes:
 
    
        { id: 2, pid: 1, tags: ["overrideMenu"] }
    

In the example below the node menu items for father and mother nodes will be different form node menus on children nodes:


Override node menu items for specific node using on show event

The methods should be added before family.load()
 
    
family.nodeMenuUI.on('show', function(sender, args){
    args.menu = { myMenuItem: { text: "My Text", icon: FamilyTree.icon.add(16,16,"#ccc"), onClick: function(id) {alert(id)} } }
});
    
family.menuUI.on('show', function(sender, args){
    args.menu = { myMenuItem: { text: "My Text", icon: FamilyTree.icon.add(16,16,"#ccc"), onClick: function(id) {alert(id)} } }
});
    
family.nodeContextMenuUI.on('show', function(sender, args){
    args.menu = { myMenuItem: { text: "My Text", icon: FamilyTree.icon.add(16,16,"#ccc"), onClick: function(id) {alert(id)} } }
});
    
Example:

Node Circle Menu

To add a Node Circle Menu:

  • First you need to define nodeCircleMenu for your template:
                
    FamilyTree.templates.tommy.nodeCircleMenuButton = 
        FamilyTree.templates.tommy_female.nodeCircleMenuButton = FamilyTree.templates.tommy_male.nodeCircleMenuButton = {
            radius: 25,
            x: 230,
            y: 60,
            color: '#fff',
            stroke: '#aeaeae'
        };
            
  • Then you need to add nodeCircleMenu in the family configuration:
            
        nodeCircleMenu: {
            PDFProfile: {
                icon: FamilyTree.icon.pdf(30, 30, '#aeaeae'),
                text: "PDF Profile",
                color: "white"
                },
    
                editNode: {
                    icon: FamilyTree.icon.edit(30, 30, '#aeaeae'),
                    text: "Edit node",
                    color: "white"
                },
                addClink: {
                    icon: FamilyTree.icon.link(30, 30, '#aeaeae'),
                    text: "Add C link",
                    color: '#fff',
                    draggable: true
                },
                pet: {
                    icon: FamilyTree.icon.teddy(30, 30, '#aeaeae'),
                    text: "Add pet",
                    color: "white"
                }
        }
            
  • You can use the show event to add menu item conditionaly:
                
    family.nodeCircleMenuUI.on('show', function (sender, args) {
        var node = family.getNode(args.nodeId);
        delete args.menu.father;
        delete args.menu.mother;
        delete args.menu.wife;
        delete args.menu.husband;
        if (FamilyTree.isNEU(node.mid)) {
            args.menu.mother = {
                icon: FamilyTree.icon.mother(30, 30, '#F57C00'),
                text: "Add mother",
                color: "white"
            };
        }
        if (FamilyTree.isNEU(node.fid)) {
            args.menu.father = {
                icon: FamilyTree.icon.father(30, 30, '#039BE5'),
                text: "Add father",
                color: "white"
            };
        }
        if (node.gender == 'male') {
            args.menu.wife = {
                icon: FamilyTree.icon.wife(30, 30, '#F57C00'),
                text: "Add wife",
                color: "white"
            };
        }
        else if (node.gender == 'female') {
            args.menu.husband = {
                icon: FamilyTree.icon.husband(30, 30, '#F57C00'),
                text: "Add husband",
                color: "white"
            };
        }
        else {
            args.menu.wife = {
                icon: FamilyTree.icon.wife(30, 30, '#F57C00'),
                text: "Add wife",
                color: "white"
            };
            args.menu.husband = {
                icon: FamilyTree.icon.husband(30, 30, '#039BE5'),
                text: "Add husband",
                color: "white"
            };
        }
    });
            
  • Use the click, drop, mouseenter or mouseout nodeCircleMenuUI events to create the node menu items functionality. Example:
            
    family.nodeCircleMenuUI.on('click', function (sender, args) {
        let node = family.getNode(args.nodeId);
        switch (args.menuItemName) {
            case "husband":
                family.addPartnerNode({ gender: 'male', pids: [args.nodeId] });
                break;
            case "wife":
                family.addPartnerNode({ gender: 'female', pids: [args.nodeId] });
                break;
            case "pet":
                family.addPartnerNode({ gender: 'pet', pids: [args.nodeId] });
                break;
            case "mother":
                let data = { gender: 'female' };
                if (!FamilyTree.isNEU(node.fid)) {
                    data.pids = [node.fid];
                }
                family.addParentNode(args.nodeId, 'mid', data);
                break;
            case "father":
                let data = { gender: 'male' };
                if (!FamilyTree.isNEU(node.mid)) {
                    data.pids = [node.mid];
                }
                family.addParentNode(args.nodeId, 'fid', data);
                break;
            case "PDFProfile":
                family.exportPDFProfile({
                    id: args.nodeId
                });
                break;
            case "editNode": family.editUI.show(args.nodeId);
                break;
            default:
        };
    });
            
            
    family.nodeCircleMenuUI.on('drop', function (sender, args) {
        family.addClink(args.from, args.to).draw(FamilyTree.action.update);
    });
     
        
    family.nodeCircleMenuUI.on('mouseenter', function (sender, args) {
        if (args.menuItem.text == "Remove node") {
            var node = document.querySelector('[data-n-id="' + args.from + '"]');
            node.style.opacity = 0.5;
        }
    });
     
            
    family.nodeCircleMenuUI.on('mouseout', function (sender, args) {
        var node = document.querySelector('[data-n-id="' + args.from + '"]');
        node.style.opacity = 1;
    });