weathertopper / family-photo-project

0 stars 0 forks source link

Style the family tree as a family tree #8

Closed weathertopper closed 7 years ago

weathertopper commented 7 years ago

I have almost no idea how to do this. A simple tree would be one thing, but there are so many edge cases:

I found a css example of a tree once, I might need to find it again.

Maybe I can use d3 (not that I really understand d3).

This'll take some research. I'll add specs on how the tree will function later.

weathertopper commented 7 years ago

https://codepen.io/chuongdang/pen/lcnsC

weathertopper commented 7 years ago
# I want to build up the tree by LEVEL

# TREE TRUNKS

# TRUNK INDEX 0
# violet's parent 0
# violet 1
# robert 2 -- cora 2
# rosamund 2
# mary 3 -- matthew 3
# edith 3 -- bertie 3
# sybil 3 -- tom 3
# sibbie 4
# george 4
# marigold 4

# TRUNK INDEX 1
# martha 0
# harold 1
# cora 1 STOP

# TRUNK INDEX 2
# isobel 0
# matthew 1 STOP

# TRUNK 3
# tom 0 STOP

# COMBINE THE TRUNKS

# merge to the greater number (subtract the smaller number)

# keep track of merge points

#[tom (TRUNK 0 & 3), matthew (TRUNK 0 & 2), cora (TRUNK 0 & 1)]

# MERGING TOM
#     height in trunk 0 == 3
#     height in trunk 3 == 0
#     MERGE INTO TRUNK 0, ALTER INDICES IN TRUNK 3 BY <OFFSET>
#     offset = 3 - 0 = 3
#     GO BACK THROUGH TRUNK 3, STARTING AT SUPERPARENT, WITH NEW INDEX OFFSET (3)
#     tom index = 0 + 3
#     (DONE, THERE WAS NOTHING ELSE IN TRUNK 3)
#
# MERGING MATTHEW
#     height in trunk 0 == 3
#     height in trunk 2 == 1
#     MERGE INTO TRUNK 0, ALTER INDICES IN TRUNK 2 BY <OFFSET>
#     offset = 3 - 1 == 2
#     GO BACK THROUGH TRUNK 2, STARTING AT SUPERPARENT, WITH NEW INDEX OFFSET (2)
#     isobel index = 0 + 2 == 2
#     matthew index = 1 + 2 = 3
#     (DONE, THERE WAS NOTHING ELSE IN TRUNK 2)
#
#
# MERGING CORA
#     height in trunk 0 = 2
#     height in trunk 1 = 1
#     MERGE INTO TRUNK 0, ALTER INDICES IN TRUNK 1 BY <HEIGHT>
#     offset = 2 - 1 = 1
#     GO BACK THROUGH TRUNK 1, STARTING AT SUPERPARENT, WITH NEW INDEX OFFSET (1)
#     martha index = 0 + 1 = 1
#     harond index = 1 + 1 = 2
#     cora index = 1 + 1 = 2
#
#     NOTICE I ADDED A FAKE RELATIVE ABOVE VIOLET

# CHUCK ALL OBJECTS INTO TRUNK 0. THERE YOU GO
weathertopper commented 7 years ago
# could order trunk entries during build, but who cares. 

def deepSearch (relative, trunks)
    found_trunk = -1
    found_level = -1
    # trunks is array of trunks
    trunks.each_with_index do |trunk, trunk_index|
        break if (found_trunk > -1) && (found_level > -1)
        # trunk is array of levels
        trunk.each_with_index do |level, level_index|
            break if (found_trunk > -1) && (found_level > -1)
            if level.include? relative
                found_trunk = trunk_index
                found_level = level_index
            end
        end
    end
    return {"relative" => relative, "found_trunk" => found_trunk, "found_level" => found_level}
end

# I can compare returned hash to 'null hash'
# (which is {"relative" => relative,  "found_trunk" => -1, "found_level" => -1} ) using == ops
weathertopper commented 7 years ago

What the hell is that? ^^ I don't understand that at all

weathertopper commented 7 years ago

So I figured it out. I'm sorry to be pasting code here, but I don't have an actual code repo setup yet.

# tree is array of {relative, level} hashes
def buildTree(root, relatives, offspring_branches, spouse_branches)
    # 'root' is a predefined relative- assumed to be the first person ever added to the tree

    #tree init
    tree = [{"relative" => root, "level" => 0}]

    tree.each do |knob|

        relative = knob["relative"]
        level = knob["level"]

        #adding spouses
        if (relative.sex == 'male') # there has to be a better way to do this
            relative.spouse_branches.each do |spouse_branch|
                wife = Relative.find(spouse_branch.wife_id)
                unless treeIncludes(wife, tree )
                    tree.insert(tree.length, {"relative" => wife, "level" => level})
                end
            end
        else
            relative.spouse_branches.each do |spouse_branch|
                husband =  Relative.find(spouse_branch.husband_id)
                unless treeIncludes(husband, tree )
                    tree.insert(tree.length, {"relative" => husband, "level" => level})
                end
            end
        end

        #adding kids
        relative.offspring_branches.each do |kid_branch|
            kid = Relative.find(kid_branch.child_id)
            unless treeIncludes(kid, tree )
                tree.insert(tree.length, {'relative' => kid, "level" => level+1})
            end
        end

        #adding parents
        relative.reverse_offspring_branches.each do |parent_branch|
            parent = Relative.find(parent_branch.parent_id)
            unless treeIncludes(parent, tree )
                tree.insert(tree.length, {'relative' => parent, "level" => level-1})
            end
        end

    end

    tree.sort_by! { |knob| knob['level'] }

    return tree
end

def treeIncludes(relative, tree)
    tree.each do |knob|
        if knob['relative'] == relative
            return true
        end
    end
    return false
end

This is a breadth-first search for the record. Yay algorithms!

weathertopper commented 7 years ago

^^make the levels start at 0

weathertopper commented 7 years ago

So this starts at 0, but it's otherwise the same

# tree is array of {relative, level} hashes
def buildTree(root, relatives, offspring_branches, spouse_branches)
    # 'root' is a predefined relative- assumed to be the first person ever added to the tree

    #tree init
    tree = [{"relative" => root, "level" => 0}]

    tree.each do |knob|

        relative = knob["relative"]
        level = knob["level"]

        #adding spouses
        if (relative.sex == 'male') # there has to be a better way to do this
            relative.spouse_branches.each do |spouse_branch|
                wife = Relative.find(spouse_branch.wife_id)
                unless treeIncludes(wife, tree )
                    tree.insert(tree.length, {"relative" => wife, "level" => level})
                end
            end
        else
            relative.spouse_branches.each do |spouse_branch|
                husband =  Relative.find(spouse_branch.husband_id)
                unless treeIncludes(husband, tree )
                    tree.insert(tree.length, {"relative" => husband, "level" => level})
                end
            end
        end

        #adding kids
        relative.offspring_branches.each do |kid_branch|
            kid = Relative.find(kid_branch.child_id)
            unless treeIncludes(kid, tree )
                tree.insert(tree.length, {'relative' => kid, "level" => level+1})
            end
        end

        #adding parents
        relative.reverse_offspring_branches.each do |parent_branch|
            parent = Relative.find(parent_branch.parent_id)
            unless treeIncludes(parent, tree )
                tree.insert(tree.length, {'relative' => parent, "level" => level-1})
            end
        end

    end

    #sort smallest to largest (highest to lowest) level
    tree.sort_by! { |knob| knob['level'] }

    #normalize so 'highest' level is 0
    smallest_level = tree[0]['level']
    difference_to_0 = 0 - smallest_level
    tree.each do |knob|
        knob['level'] += difference_to_0
    end

    return tree
end

def treeIncludes(relative, tree)
    tree.each do |knob|
        if knob['relative'] == relative
            return true
        end
    end
    return false
end
weathertopper commented 7 years ago

So this is the code from the codepen above that turns unordered lists to rough trees

CSS:

* {margin: 0; padding: 0;}

.tree ul {
    padding-top: 20px; position: relative;

    -webkit-transition: all 0.5s;
    -moz-transition: all 0.5s;
    transition: all 0.5s;
}

.tree li {
    float: left; text-align: center;
    list-style-type: none;
    position: relative;
    padding: 20px 5px 0 5px;

    -webkit-transition: all 0.5s;
    -moz-transition: all 0.5s;
    transition: all 0.5s;
}

/*We will use ::before and ::after to draw the connectors*/

.tree li::before, .tree li::after{
    content: '';
    position: absolute; top: 0; right: 50%;
    border-top: 1px solid #ccc;
    width: 50%; height: 45px;
    z-index: -1;
}
.tree li::after{
    right: auto; left: 50%;
    border-left: 1px solid #ccc;
}

/*We need to remove left-right connectors from elements without 
any siblings*/
.tree li:only-child::after, .tree li:only-child::before {
    display: none;
}

/*Remove space from the top of single children*/
.tree li:only-child{ padding-top: 0;}

/*Remove left connector from first child and 
right connector from last child*/
.tree li:first-child::before, .tree li:last-child::after{
    border: 0 none;
}

/*Adding back the vertical connector to the last nodes*/
.tree li:last-child::before{
    border-right: 1px solid #ccc;
    border-radius: 0 5px 0 0;

    -webkit-transform: translateX(1px);
    -moz-transform: translateX(1px);
    transform: translateX(1px);

    -webkit-border-radius: 0 5px 0 0;
    -moz-border-radius: 0 5px 0 0;
    border-radius: 0 5px 0 0;
}

.tree li:first-child::after{
    border-radius: 5px 0 0 0;
    -webkit-border-radius: 5px 0 0 0;
    -moz-border-radius: 5px 0 0 0;
}

/*Time to add downward connectors from parents*/
.tree ul ul::before{
    content: '';
    position: absolute; top: -12px; left: 50%;
    border-left: 1px solid #ccc;
    width: 0; height: 32px;
    z-index: -1;
}

.tree li a{
    border: 1px solid #ccc;
    padding: 5px 10px;
    text-decoration: none;
    color: #666;
    font-family: arial, verdana, tahoma;
    font-size: 11px;
    display: inline-block;
    background: white;

    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    border-radius: 5px;

    -webkit-transition: all 0.5s;
    -moz-transition: all 0.5s;
    transition: all 0.5s;
}
.tree li a+a {
    margin-left: 20px;
    position: relative;
}
.tree li a+a::before {
    content: '';
    position: absolute;
    border-top: 1px solid #ccc;
    top: 50%; left: -21px; 
    width: 20px;
}

/*Time for some hover effects*/
/*We will apply the hover effect the the lineage of the element also*/
.tree li a:hover, .tree li a:hover~ul li a {
    background: #c8e4f8; color: #000; border: 1px solid #94a0b4;
}
/*Connector styles on hover*/
.tree li a:hover~ul li::after, 
.tree li a:hover~ul li::before, 
.tree li a:hover~ul::before, 
.tree li a:hover~ul ul::before
{
    border-color: #94a0b4;
}

HTML:

<div class="tree">
    <ul>
        <li>
            <a href="#">Parent</a>
            <ul>
                <li>
                    <a href="#">Child</a>
                    <ul>
                        <li>
                            <a href="#">Grand Child</a>
                        </li>
                    </ul>
                </li>
                <li>
                    <a href="#">Sub Parent 1</a><a href="#">Sub Parent 2</a>
                    <ul>
                        <li><a href="#">Grand Child</a></li>
                        <li>
                            <a href="#">Grand Child</a>
                            <ul>
                                <li>
                                    <a href="#">Great Grand Child</a>
                                </li>
                                <li>
                                    <a href="#">Great Grand Child</a>
                                </li>
                                <li>
                                    <a href="#">Great Grand Child</a>
                                </li>
                            </ul>
                        </li>
                        <li><a href="#">Grand Child</a></li>
                    </ul>
                </li>
            </ul>
        </li>
    </ul>
</div>

The easiest way to view this is plugging this code into a codepen session

weathertopper commented 7 years ago

My problem is this-- levels are all well and good, but I could simplify drawing by assigning each person ONE parent. If someone has two parents, then his/her 'parent' is the relationship between his/her two parents. Good luck figuring that out.

weathertopper commented 7 years ago

https://developers.google.com/chart/interactive/docs/gallery/orgchart?csw=1#Example

weathertopper commented 7 years ago

parallax-scrolling.zip Parallax Scrolling - https://codepen.io/keithclark/pen/JycFw?editors=1100

weathertopper commented 7 years ago

Generations:

Progressive: 1843-1859 Missionary : 1860-1882 Lost : 1883-1900 G.I. : 1901-1924 Silent: 1925-1945 Baby Boomer: 1946-1964 Generation X: 1965- 1982 Millennial: 1982-1995 Generation Z: 1996- now

weathertopper commented 7 years ago

cool border animation:

<!DOCTYPE html>
<html>
<head>
<style>
div {
border-style: solid;
    width: 100px;
    height: 100px;
    border-color: transparent;
    -webkit-animation-name: example; /* Safari 4.0 - 8.0 */
    -webkit-animation-duration: 4s; /* Safari 4.0 - 8.0 */
    animation-name: example;
    animation-duration: 4s;
    animation-iteration-count: 1;
    animation-fill-mode: forwards; 
}

/* Safari 4.0 - 8.0 */
@-webkit-keyframes example {
    0%   {border-color: red;}
    25%  {border-color: yellow;}
    50%  {border-color: blue;}
    100% {border-color: green;}
}

/* Standard syntax */
@keyframes example {
    0%   {border-right-color: red;}
    25%  {border-right-color: red;
        border-bottom-color: red;}
    50%  {
    border-right-color: red;
        border-bottom-color: red;
    border-left-color: red;}
    100% {
    border-right-color: red;
        border-bottom-color: red;
    border-left-color: red;
    border-top-color: red;}
}
</style>
</head>
<body>

<p><b>Note:</b> This example does not work in Internet Explorer 9 and earlier versions.</p>

<div></div>

</body>
</html>
weathertopper commented 7 years ago

This has been a dumping ground for a bunch of weird info. Let me update my purpose:

I won't be drawing an actual tree. I will make a portrait wall of all relatives. When a 'tree' button is pressed on the portrait of a relative, all other relative portraits are updated to show how they relate to that selected relative. No drawing. I might (in the FAR AWAY future) try a filtered-tree that won't involve all relatives at once.

weathertopper commented 7 years ago

Stop being a bum and READ this on parallax scrolling: http://keithclark.co.uk/articles/pure-css-parallax-websites/ Until then, disable it because right now it's obnoxious.

weathertopper commented 7 years ago

ADD GRAND UNCLES/AUNTS