03. KineticJS

01. Using Kinetic create a family tree.
Example:
Example

I’m using KineticJS and RequireJS
index.html

<!-- 01. Using Kinetic create a family tree. -->

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
    <style>
        #canvas-container {
            width: 1000px;
            height: 500px;
            border: 1px solid black;
        }
    </style>
</head>
<body>
    <div id="canvas-container"></div>
    <script src="scripts/libs/kinetic-v5.1.0.min.js"></script>
    <script type="text/javascript" src="scripts/libs/require.js" data-main="scripts/app"></script>
</body>
</html>

app.js

(function() {
    require(['MainModules/Drawer'], function (Drawer) {
        Drawer.drawFamilyTree();
    });
}());

InputData/FamilyMembers.js

define(function () {
    var familyMembers = [{
        mother: 'Maria Petrova',
        father: 'Georgi Petrov',
        children: ['Teodora Petrova', 'Peter Petrov']
    }, {
        mother: 'Petra Stamatova',
        father: 'Todor Stamatov',
        children: ['Maria Petrova']
    }];

    return familyMembers;
});

Helper/GlobalVariables.js

define(function() {
    return {
        families: []
    };
});

Helper/GetFamilyMembers.js

define(['Helper/GlobalVariables' ,'InputData/FamilyMembers', 'MainModules/Family'],function(GlobalVariables, FamilyMembers, Family) {
    function getFamilyMembers() {
        for (var i = 0; i < FamilyMembers.length; i++) {
            GlobalVariables.families.push(new Family(FamilyMembers[i].father, FamilyMembers[i].mother, FamilyMembers[i].children));
        }
    }

    function buildDictionary() {
        var child, childFamily;

        for (var i = 0; i < GlobalVariables.families.length; i++) {
            for (var j = 0; j < GlobalVariables.families[i].getChildren().length; j++) {
                child = GlobalVariables.families[i].getChildren()[j];
                childFamily = findFamily(child);

                if(childFamily === null) {
                    GlobalVariables.families[i].getChildren()[j] = new Family(child);
                }
                else {
                    GlobalVariables.families[i].getChildren()[j] = childFamily;

                    if(child === GlobalVariables.families[i].getChildren()[j].getMother()) {
                        GlobalVariables.families[i].setIsChildFemale(true);
                    }
                }

                GlobalVariables.families[i].getChildren()[j].setHasParents(true);
            }
        }
    }

    function findRoot() {
        getFamilyMembers();
        buildDictionary();

        for (var i = 0; i < GlobalVariables.families.length; i++) {
            if(!GlobalVariables.families[i].getHasParents()) {
                return GlobalVariables.families[i];
            }
        }
    }

    function findFamily(child) {
        for (var i = 0; i < GlobalVariables.families.length; i++) {
            if(GlobalVariables.families[i].getMother() === child || GlobalVariables.families[i].getFather() === child) {
                return GlobalVariables.families[i];
            }
        }

        return null;
    }

    return {
        findRoot: findRoot,
        findFamily: findFamily
    };
});

MainModules/Family.js

define(function () {
    var Family = (function () {

        function Family(father, mother, children) {
            this.father = father;
            this.mother = mother;
            this.children = children;
            this.hasParenst = false;
            this.isChildFemale = false;
            this.positionX = 200;
            this.positionY = 10;
        }

        Family.prototype.getFather = function() {
            return this.father;
        };

        Family.prototype.getMother = function() {
            return this.mother;
        };

        Family.prototype.getChildren = function() {
            return this.children;
        };

        Family.prototype.getHasParents = function() {
            return this.hasParenst;
        };

        Family.prototype.setHasParents = function(hasParents) {
            this.hasParenst = hasParents;
        };

        Family.prototype.getIsChildFemale = function() {
            return this.isChildFemale;
        };

        Family.prototype.setIsChildFemale = function(isFemale) {
            this.isChildFemale = isFemale;
        };

        Family.prototype.getPositionX = function() {
            return this.positionX;
        };

        Family.prototype.setPositionX = function (x) {
            this.positionX = x;
        };

        Family.prototype.getPositionY = function() {
            return this.positionY;
        };

        Family.prototype.setPositionY = function (y) {
            this.positionY = y;
        };

        Family.prototype.findChild = function(child) {
            for (var i = 0; i < this.children.length; i++) {
                if(this.children[i] === child) {
                    return true;
                }
            }

            return false;
        };

        return Family;
    }());

    return Family;
});

MainModules/Drawer.js

define(['Helper/GetFamilyMembers'], function(GetFamilyMembers) {
    function drawFamilyTree() {
        var stage = initializeStage(),
            layer = new Kinetic.Layer(),
            root = GetFamilyMembers.findRoot(),
            queue = [root],
            xShift = 140,
            radius = 5,
            fatherName,
            motherName,
            fatherShape,
            motherShape,
            parentsConnection,
            family;

        while(queue.length > 0) {
            family = queue.shift();

            if(family.getFather()) {
                fatherName = drawNameOfFamilyMember(family.getPositionX(), family.getPositionY(), family.getFather());
                fatherShape = drawShapeOfFamilyMember(family.getPositionX(), family.getPositionY(), radius);
            }

            if(family.getMother()) {
                motherName = drawNameOfFamilyMember(family.getPositionX() + xShift, family.getPositionY(), family.getMother());
                motherShape = drawShapeOfFamilyMember(family.getPositionX() + xShift, family.getPositionY(), radius * 3);
            }

            // If parents are no leafs (if they have children).
            if(family.getChildren()) {
                parentsConnection = drawConnectionBetweenParents(family.getPositionX() + 120, family.getPositionY() + 15,
                        family.getPositionX() + xShift, family.getPositionY() + 15);

                for (var i = 0; i < family.getChildren().length; i++) {

                   // If there is more than one child.
                    if(i > 0) {
                        family.getChildren()[i].setPositionX(family.getPositionX() + xShift * i)
                    }

                    family.getChildren()[i].setPositionY(family.getPositionY() + 100);
                    queue.push(family.getChildren()[i]);

                    if(family.isChildFemale === true) {
                        connectParentsWithChildren(parentsConnection, family.getChildren()[i].getPositionX() + xShift + 50,
                            family.getChildren()[i].getPositionY(), layer);
                    }
                    else {
                        connectParentsWithChildren(parentsConnection, family.getChildren()[i].getPositionX() + 50,
                            family.getChildren()[i].getPositionY(), layer);
                    }
                }
            }

            layer.add(fatherName, fatherShape, motherName, motherShape, parentsConnection);
            stage.add(layer);
        }

        return stage.add(layer);
    }

    function connectParentsWithChildren(parentsConnection, childPositionX, childPositionY, layer) {
        var parentConnectionX1 = parentsConnection.attrs.points[0],
            parentConnectionY1 = parentsConnection.attrs.points[1],
            parentConnectionX2 = parentsConnection.attrs.points[2],
            parentConnectionY2 = parentsConnection.attrs.points[3],
            childConnectionX = (parentConnectionX1 + parentConnectionX2) / 2,
            childConnectionY = (parentConnectionY1 + parentConnectionY2) / 2;

        layer.add(drawConnectionBetweenParentsAndChildren(childConnectionX, childConnectionY, childPositionX, childPositionY),
            drawArrow(childPositionX, childPositionY, childPositionX - 6, childPositionY - 6,
                    childPositionX + 6, childPositionY - 6));
    }

    function initializeStage() {
        return new Kinetic.Stage({
            container: 'canvas-container',
            width: 800,
            height: 500
        });
    }

    function drawShapeOfFamilyMember(x, y, radius) {
        return new Kinetic.Rect({
            x: x,
            y: y,
            width: 120,
            height: 30,
            stroke: 'yellowgreen',
            cornerRadius: radius
        });
    }

    function drawNameOfFamilyMember(x, level, name) {
        return new Kinetic.Text({
            x: x,
            y: level,
            text: name,
            padding: 10,
            fill: '#555',
            align: 'center'
        });
    }

    function drawConnectionBetweenParents(x1, y1, x2, y2) {
        return new Kinetic.Line({
            points: [x1, y1, x2, y2],
            stroke: 'yellowgreen',
            strokeWidth: 2
        });
    }

    function drawConnectionBetweenParentsAndChildren(x1, y1, x2, y2) {
        return new Kinetic.Line({
            points: [x1, y1, x1, y1 + 30, x2, y1 + 30, x2, y2],
            stroke: 'yellowgreen',
            strokeWidth: 2,
            lineJoin: 'round',
            tension: 0.3
        });
    }

    function drawArrow(x1, y1, x2, y2, x3, y3) {
        return new Kinetic.Line({
            points: [x1, y1, x2, y2, x3, y3],
            stroke: 'yellowgreen',
            fill: 'yellowgreen',
            strokeWidth: 2,
            closed: true
        });
    }

    return {
        drawFamilyTree: drawFamilyTree
    };
});

Result:
Result

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s