Predefined Templates
Modes
Family Tree JS can be displayed in "dark" or "light" modes by settong the mode option:
light modedark mode
Templates
Family Tree JS arrives with 2 predefined templates. You can change the template by setting the template option. Here is an example:
var family = new FamilyTree(document.getElementById("tree"), { template: "hugo", ... });
You can get the source code of any of the templates and change it.
tommyFamilyTree.templates.tommy = Object.assign({}, FamilyTree.templates.base); FamilyTree.templates.tommy.defs = `<style> .{randId} .bft-edit-form-header, .{randId} .bft-img-button{ background-color: #aeaeae; } .{randId}.male .bft-edit-form-header, .{randId}.male .bft-img-button{ background-color: #039BE5; } .{randId}.male div.bft-img-button:hover{ background-color: #F57C00; } .{randId}.female .bft-edit-form-header, .{randId}.female .bft-img-button{ background-color: #F57C00; } .{randId}.female div.bft-img-button:hover{ background-color: #039BE5; } </style>`; FamilyTree.templates.tommy.field_0 = '<text ' + FamilyTree.attr.width + ' ="230" style="font-size: 18px;font-weight:bold;" fill="#ffffff" x="10" y="90" text-anchor="start">{val}</text>'; FamilyTree.templates.tommy.field_1 = '<text ' + FamilyTree.attr.width + ' ="150" style="font-size: 14px;" fill="#ffffff" x="10" y="65" text-anchor="start">{val}</text>'; FamilyTree.templates.tommy.node = '<rect x="0" y="0" height="{h}" width="{w}" stroke-width="1" fill="#aeaeae" stroke="#aeaeae" rx="7" ry="7"></rect>'; FamilyTree.templates.tommy_male = Object.assign({}, FamilyTree.templates.tommy); FamilyTree.templates.tommy_male.node = '<rect x="0" y="0" height="{h}" width="{w}" stroke-width="1" fill="#039BE5" stroke="#aeaeae" rx="7" ry="7"></rect>'; FamilyTree.templates.tommy_female = Object.assign({}, FamilyTree.templates.tommy); FamilyTree.templates.tommy_female.node = '<rect x="0" y="0" height="{h}" width="{w}" stroke-width="1" fill="#F57C00" stroke="#aeaeae" rx="7" ry="7"></rect>';
hugo
FamilyTree.templates.hugo = Object.assign({}, FamilyTree.templates.base); FamilyTree.templates.hugo.defs = `<clipPath id="hugo_img_0"><rect id="hugo_img_0_stroke" stroke-width="2" stroke="#fff" x="90" y="-5" rx="25" ry="25" width="70" height="70"></rect></clipPath> <linearGradient id="hugo_grad_female" x1="0%" y1="0%" x2="100%" y2="0%"> <stop offset="0%" style="stop-color:#FF8024;stop-opacity:1" /> <stop offset="100%" style="stop-color:#FF46A3;stop-opacity:1" /> </linearGradient> <linearGradient id="hugo_grad_male" x1="0%" y1="0%" x2="100%" y2="0%"> <stop offset="0%" style="stop-color:#00D3A5;stop-opacity:1" /> <stop offset="100%" style="stop-color:#00A7D4;stop-opacity:1" /> </linearGradient> <linearGradient id="hugo_grad" x1="0%" y1="0%" x2="100%" y2="0%"> <stop offset="0%" style="stop-color:#D0D0D0;stop-opacity:1" /> <stop offset="100%" style="stop-color:#909090;stop-opacity:1" /> </linearGradient> <g id="hugo_up"> <circle cx="12" cy="12" r="15" fill="transparent"></circle> ${FamilyTree.icon.ft(24,24,'#fff', 0, 0)} </g> <g id="hugo_node_menu" style="cursor:pointer;"> <rect x="0" y="0" fill="transparent" width="22" height="22"></rect> <circle cx="11" cy="4" r="2" fill="#ffffff"></circle><circle cx="11" cy="11" r="2" fill="#ffffff"></circle> <circle cx="11" cy="18" r="2" fill="#ffffff"></circle> </g> <style> .{randId} .bft-edit-form-header{ background: linear-gradient(90deg, #D0D0D0 0%, #909090 100%); } .{randId}.male .bft-edit-form-header{ background: linear-gradient(90deg, #00D3A5 0%, #00A7D4 100%); } .{randId}.female .bft-edit-form-header{ background: linear-gradient(90deg, #FF8024 0%, #FF46A3 100%); } .{randId} .bft-img-button{ background-color: #909090; } .{randId} .bft-img-button:hover{ background-color: #D0D0D0; } .{randId}.male .bft-img-button{ background-color: #00A7D4; } .{randId}.male .bft-img-button:hover{ background-color: #00D3A5; } .{randId}.female .bft-img-button{ background-color: #FF46A3; } .{randId}.female .bft-img-button:hover{ background-color: #FF8024; } </style>`; FamilyTree.templates.hugo.img_0 = '<use xlink:href="#hugo_img_0_stroke" /> <image preserveAspectRatio="xMidYMid slice" clip-path="url(#hugo_img_0)" xlink:href="{val}" x="90" y="-5" width="70" height="70"></image>'; FamilyTree.templates.hugo.field_0 = '<text ' + FamilyTree.attr.width + ' ="230" style="font-size: 18px;font-weight:bold;" fill="#ffffff" x="125" y="85" text-anchor="middle">{val}</text>'; FamilyTree.templates.hugo.field_1 = '<text ' + FamilyTree.attr.width + ' ="230" style="font-size: 14px;" fill="#ffffff" x="125" y="105" text-anchor="middle">{val}</text>'; FamilyTree.templates.hugo.node = '<rect x="0" y="0" height="{h}" width="{w}" stroke-width="1" fill=url(#hugo_grad) stroke="#aeaeae" rx="7" ry="7"></rect>'; FamilyTree.templates.hugo_male = Object.assign({}, FamilyTree.templates.hugo); FamilyTree.templates.hugo_male.node = '<rect x="0" y="0" height="{h}" width="{w}" stroke-width="1" fill=url(#hugo_grad_male) stroke="#aeaeae" rx="7" ry="7"></rect>'; FamilyTree.templates.hugo_female = Object.assign({}, FamilyTree.templates.hugo); FamilyTree.templates.hugo_female.node = '<rect x="0" y="0" height="{h}" width="{w}" stroke-width="1" fill=url(#hugo_grad_female) stroke="#aeaeae" rx="7" ry="7"></rect>'; FamilyTree.templates.hugo.up = '<use x="200" y="10" xlink:href="#hugo_up" />'; FamilyTree.templates.hugo.nodeMenuButton = `<use x="225" y="10" ${FamilyTree.attr.control_node_menu_id}="{id}" xlink:href="#hugo_node_menu" />`;
john
FamilyTree.templates.john = Object.assign({}, FamilyTree.templates.base); FamilyTree.templates.john.defs = `<style> .{randId} .bft-edit-form-header, .{randId} .bft-img-button{ background-color: #aeaeae; } .{randId}.male .bft-edit-form-header, .{randId}.male .bft-img-button{ background-color: #039BE5; } .{randId}.male div.bft-img-button:hover{ background-color: #F57C00; } .{randId}.female .bft-edit-form-header, .{randId}.female .bft-img-button{ background-color: #F57C00; } .{randId}.female div.bft-img-button:hover{ background-color: #039BE5; } </style> <clipPath id="john_img_0"><rect x="6" y="6" rx="54" ry="54" width="108" height="108"></rect></clipPath> ${FamilyTree.gradientCircleForDefs('circle', '#aeaeae', 60, 5)} ${FamilyTree.gradientCircleForDefs('male_circle', '#039BE5', 60, 5)} ${FamilyTree.gradientCircleForDefs('female_circle', '#F57C00', 60, 5)}`; FamilyTree.templates.john.field_0 = '<text ' + FamilyTree.attr.width + ' ="230" style="font-size: 16px;font-weight:bold;" fill="#aeaeae" x="60" y="135" text-anchor="middle">{val}</text>'; FamilyTree.templates.john.field_1 = '<text ' + FamilyTree.attr.width + ' ="150" style="font-size: 13px;" fill="#aeaeae" x="60" y="150" text-anchor="middle">{val}</text>'; FamilyTree.templates.john.node = '<use x="0" y="0" xlink:href="#circle" />'; FamilyTree.templates.john.img_0 = '<image preserveAspectRatio="xMidYMid slice" clip-path="url(#john_img_0)" xlink:href="{val}" x="6" y="6" width="108" height="108"></image>'; FamilyTree.templates.john.ripple = { radius: 60, color: "#e6e6e6", rect: null }; FamilyTree.templates.john.size = [120, 120] FamilyTree.templates.john_male = Object.assign({}, FamilyTree.templates.john); FamilyTree.templates.john_male.node += '<use x="0" y="0" xlink:href="#male_circle" />'; FamilyTree.templates.john_male.ripple = { radius: 60, color: "#039BE5", rect: null }; FamilyTree.templates.john_female = Object.assign({}, FamilyTree.templates.john); FamilyTree.templates.john_female.node += '<use x="0" y="0" xlink:href="#female_circle" />'; FamilyTree.templates.john_female.ripple = { radius: 60, color: "#F57C00", rect: null };
All templates are inherited form the base template. Here are defined all the other properties.
FamilyTree.templates.base = { defs: `<g transform="matrix(1,0,0,1,0,0)" id="dot"><circle class="ba-fill" cx="0" cy="0" r="5" stroke="#aeaeae" stroke-width="1"></circle></g> <g id="base_node_menu" style="cursor:pointer;"> <rect x="0" y="0" fill="transparent" width="22" height="22"></rect> <circle cx="4" cy="11" r="2" fill="#ffffff"></circle> <circle cx="11" cy="11" r="2" fill="#ffffff"></circle> <circle cx="18" cy="11" r="2" fill="#ffffff"></circle> </g> <g style="cursor: pointer;" id="base_tree_menu"> <rect x="0" y="0" width="25" height="25" fill="transparent"></rect> ${FamilyTree.icon.addUser(25, 25, '#fff', 0, 0)} </g> <g style="cursor: pointer;" id="base_tree_menu_close"> <circle cx="12.5" cy="12.5" r="12" fill="#F57C00"></circle> ${FamilyTree.icon.close(25, 25, '#fff', 0, 0)} </g> <g id="base_up"> <circle cx="15" cy="15" r="15" fill="#fff" stroke="#aeaeae" stroke-width="1"></circle> ${FamilyTree.icon.ft(20,20,'#aeaeae', 5, 5)} </g> <clipPath id="base_img_0"> <rect id="base_img_0_stroke" stroke-width="3" stroke="#fff" x="170" y="-5" rx="25" ry="25" width="70" height="70"></rect> </clipPath>`, size: [250, 120], linkAdjuster: { fromX: 0, fromY: 0, toX: 0, toY: 0 }, ripple: { radius: 0, color: "#e6e6e6", rect: null }, expandCollapseSize: 0, svg: '<svg class="{randId} {template} {mode}" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:block;" width="{w}" height="{h}" viewBox="{viewBox}">{content}</svg>', link: '<path stroke-linejoin="round" stroke="#aeaeae" stroke-width="1px" fill="none" d="{rounded}" />', assistanseLink: '<path stroke-linejoin="round" stroke="#aeaeae" stroke-width="2px" fill="none" d="M{xa},{ya} {xb},{yb} {xc},{yc} {xd},{yd} L{xe},{ye}" />', pointer: '<g data-pointer="pointer" transform="matrix(0,0,0,0,100,100)"> <radialGradient id="pointerGradient"><stop stop-color="#ffffff" offset="0" /><stop stop-color="#C1C1C1" offset="1" /></radialGradient> <circle cx="16" cy="16" r="16" stroke-width="1" stroke="#acacac" fill="url(#pointerGradient)"></circle> </g>', node: '<rect x="0" y="0" height="{h}" width="{w}" stroke-width="1" stroke="#aeaeae" rx="7" ry="7"></rect>', menuButton: '<div style="position:absolute;right:{p}px;top:{p}px; width:40px;height:50px;cursor:pointer;" ' + FamilyTree.attr.control_export_menu + ' =""> <hr style="background-color: #7A7A7A; height: 3px; border: none;"> <hr style="background-color: #7A7A7A; height: 3px; border: none;"> <hr style="background-color: #7A7A7A; height: 3px; border: none;"> </div>', padding: [50, 20, 35, 20], nodeMenuButton: `<use ${FamilyTree.attr.control_node_menu_id}="{id}" x="220" y="95" xlink:href="#base_node_menu" />`, nodeTreeMenuButton: `<use ${'data-ctrl-n-t-menu-id'}="{id}" x="10" y="10" xlink:href="#base_tree_menu" />`, nodeTreeMenuCloseButton: `<use ${'data-ctrl-n-t-menu-c'}="" x="10" y="10" xlink:href="#base_tree_menu_close" />`, up: '<use x="110" y="-10" xlink:href="#base_up" />', img_0: '<use xlink:href="#base_img_0_stroke" /> <image preserveAspectRatio="xMidYMid slice" clip-path="url(#base_img_0)" xlink:href="{val}" x="170" y="-5" width="70" height="70"></image>', link_field_0: '<text text-anchor="middle" fill="#aeaeae" ' + FamilyTree.attr.width + ' ="290" x="0" y="0" style="font-size:10px;">{val}</text>'
We have also predefined templates for adding nodes using the NodeTreeMenu:
mother
FamilyTree.templates.mother = Object.assign({}, FamilyTree.templates.base); FamilyTree.templates.mother.up = ''; FamilyTree.templates.mother.node = '<rect x="0" y="0" height="{h}" width="{w}" style="fill:transparent;" stroke-width="1" stroke="#F57C00" rx="5" ry="5"></rect>' + '<text style="font-size: 18px;" fill="#F57C00" x="240" y="30" text-anchor="end">Add mother</text>' + FamilyTree.icon.mother(70, 70, '#F57C00', 10, 40);
father
FamilyTree.templates.father = Object.assign({}, FamilyTree.templates.mother); FamilyTree.templates.father.node = '<rect x="0" y="0" height="{h}" width="{w}" style="fill:transparent;height:{h}; width:{w};stroke-width:1;stroke:#039BE5;rx:5;ry:5;"></rect>' + '<text style="font-size: 18px;" fill="#039BE5" x="240" y="30" text-anchor="end">Add father</text>' + FamilyTree.icon.father(70, 70, '#039BE5', 10, 40);
partner
FamilyTree.templates.partner = Object.assign({}, FamilyTree.templates.mother); FamilyTree.templates.partner.node = '<rect x="0" y="0" height="{h}" width="{w}" style="fill:transparent;height:{h}; width:{w};stroke-width:1;stroke:#aeaeae;rx:5;ry:5;"></rect>' + '<text style="font-size: 18px;" fill="#aeaeae" x="240" y="30" text-anchor="end">Add partner</text>';
son
FamilyTree.templates.son = Object.assign({}, FamilyTree.templates.mother); FamilyTree.templates.son.node = '<rect x="0" y="0" height="{h}" width="{w}" style="fill:transparent;height:{h}; width:{w};stroke-width:1;stroke:#039BE5;rx:5;ry:5;"></rect>' + '<text style="font-size: 18px;" fill="#039BE5" x="240" y="30" text-anchor="end">Add son</text>' + FamilyTree.icon.son(70, 70, '#039BE5', 10, 40);
daughter
FamilyTree.templates.daughter = Object.assign({}, FamilyTree.templates.mother); FamilyTree.templates.daughter.node = '<rect x="0" y="0" height="{h}" width="{w}" style="fill:transparent;height:{h}; width:{w};stroke-width:1;stroke:#F57C00;rx:5;ry:5;"></rect>' + '<text style="font-size: 18px;" fill="#F57C00" x="240" y="30" text-anchor="end">Add daughter</text>' + FamilyTree.icon.daughter(70, 70, '#F57C00', 10, 40);
husband
FamilyTree.templates.husband = Object.assign({}, FamilyTree.templates.mother); FamilyTree.templates.husband.node = '<rect x="0" y="0" height="{h}" width="{w}" style="fill:transparent;height:{h}; width:{w};stroke-width:1;stroke:#039BE5;rx:5;ry:5;"></rect>' + '<text style="font-size: 18px;" fill="#039BE5" x="240" y="30" text-anchor="end">Add husband</text>' + FamilyTree.icon.husband(70, 70, '#039BE5', 10, 40);
wife
FamilyTree.templates.wife = Object.assign({}, FamilyTree.templates.mother); FamilyTree.templates.wife.node = '<rect x="0" y="0" height="{h}" width="{w}" style="fill:transparent;height:{h}; width:{w};stroke-width:1;stroke:#F57C00;rx:5;ry:5;"></rect>' + '<text style="font-size: 18px;" fill="#F57C00" x="240" y="30" text-anchor="end">Add wife</text>' + FamilyTree.icon.wife(70, 70, '#F57C00', 10, 40);
pet
FamilyTree.templates.pet = Object.assign({}, FamilyTree.templates.mother); FamilyTree.templates.pet.node = '<rect x="0" y="0" style="fill:transparent;height:{h}; width:{w};stroke-width:1;stroke:#F57C00;rx:5;ry:5;"></rect>' + '<text style="font-size: 18px;" fill="#F57C00" x="240" y="30" text-anchor="end">Add pet</text>' + FamilyTree.icon.teddy(70, 70, '#F57C00', 10, 40);