Built with blockbuilder.org Credit for the genealogical research goes entirely to my brother. Credit for learning D3 goes to the incredible community. Next step is to clean up the code, and learn some more JavaScript.
Last active
January 4, 2018 04:32
-
-
Save stevenwmarks/ec701718dfe74fbee433d0d76f67f819 to your computer and use it in GitHub Desktop.
Family Tree on Map
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: mit | |
border: no | |
height: 600 | |
scrolling: yes |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
city | lat | lon | |
---|---|---|---|
London | 51.51 | -0.132 | |
Bath | 51.382 | -2.368 | |
Portsmouth | 50.86 | -1.09 | |
Oxford | 51.752 | -1.258 | |
WALES | 52.13 | -3.783 | |
SCOTLAND | 56.491 | -4.203 | |
Canterbury | 51.28 | 1.079 | |
Cambridge | 52.205 | 0.122 | |
Exeter | 50.718 | -3.534 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
gen | surname | name1 | birthYr | death | birthPlace | county | spouse | lat | lon | |
---|---|---|---|---|---|---|---|---|---|---|
mother | Arnold | Mavis Lillian | 1920 | 1978 | West Ham | Essex | Jack Charles Marks | 51.558 | 0.015 | |
grandfather | Arnold | Walter | 1894 | 1967 | Wakefield Mews | London | Lillian Mary Fulcher | 51.527 | -0.124 | |
great-grandfather | Arnold | William Henry | 1862 | 1897 | Islington | London | Eliza Sooby | 51.547 | 0.106 | |
g-g-grandfather | Arnold | Edward | 1837 | 1900 | Islington | London | Mary Thomas | 51.547 | 0.166 | |
g-g-g-grandfather | Arnold | John | 1803 | unknown | Chilham | Kent | Ann Allard | 51.244 | 0.966 | |
father | Marks | Jack Charles | 1915 | 1998 | Woodford | Essex | Mavis Lillian Arnold | 51.592 | 0.092 | |
grandfather | Marks | William Charles | 1878 | 1956 | Woodford | Essex | Jessie Rowlinson | 51.592 | 0.042 | |
great-grandfather | Marks | Henry Charles | 1847 | 1878 | Haggerston | Middlesex | Elizabeth Ann Saveall | 51.522 | -0.039 | |
g-g-grandfather | Marks | Benjamin | 1819 | 1891 | Frome | Somerset | Elizabeth Watts | 51.229 | -2.318 | |
g-g-g-grandfather | Marks | Edward | 1781 | 1825 | North Petherton | Somerset | Rachel [unknown surname] | 51.042 | -2.969 | |
g-g-g-g-grandfather | Marks | Edward | 1742 | unknown | North Petherton | Somerset | Joan Parish | 51.042 | -3.019 | |
g-g-g-g-g-grandfather | Marks | Thomas | 1702 | unknown | North Petherton | Somerset | Joane Higgins | 51.092 | -2.969 | |
g-g-g-g-g-g-grandfather | Marks | Edward | 1673 | unknown | North Petherton | Somerset | Jane Brain | 51.092 | -3.019 | |
g-g-g-g-g-g-g-grandfather | Markes | John | 1647 | unknown | North Petherton | Somerset | Lucretia Mitchell | 51.092 | -3.069 | |
grandmother | Fulcher | Lillian Mary | 1900 | 1980 | Southend | Essex | Walter Arnold | 51.546 | 0.708 | |
great-grandfather | Fulcher | Frank | 1874 | 1966 | Herne Hill | London | Ada Louisa Walker | 51.455 | 0.097 | |
g-g-grandfather | Fulcher | Henry | 1835 | 1893 | Newbourn | Suffolk | Charlotte Childs | 52.04 | 1.314 | |
g-g-g-grandfather | Fulcher | James | 1797 | 1855 | Newbourn | Suffolk | Mary Little | 52.04 | 1.264 | |
grandmother | Rowlinson | Jessie | 1881 | 1955 | Great Wratting | Suffolk | William Charles Marks | 52.059 | 0.461 | |
great-grandfather | Rowlinson | William | 1857 | 1926 | Great Wratting | Suffolk | Ellen Cornell | 52.059 | 0.411 | |
g-g-grandfather | Rowlingson | Richard | 1829 | 1900 | Great Wratting | Suffolk | Elizabeth Cornwell | 52.109 | 0.461 | |
g-g-g-grandfather | Rollingson | Richard | 1791 | 1858 | Great Wratting | Suffolk | Martha Browne | 52.109 | 0.411 | |
g-g-g-g-grandfather | Rollinson | Richard | 1761 | unknown | Great Wratting | Suffolk | Hannah Smith | 52.109 | 0.361 | |
great-grandmother | Saveall | Elizabeth Ann | 1846 | 1922 | Wanstead | Essex | Henry Charles Marks | 51.567 | 0.033 | |
g-g-grandfather | Saveall | William | 1821 | 1888 | Woodford Bridge | Essex | Sarah [unknown surname] | 51.606 | 0.056 | |
great-grandmother | Cornell | Ellen | 1857 | unknown | Great Wratting | Suffolk | William Rowlinson | 52.059 | 0.361 | |
g-g-grandfather | Cornell | Samuel | 1826 | 1904 | Barnardiston | Suffolk | Elizabeth Coe | 52.112 | 0.499 | |
g-g-g-grandfather | Cornell | Samuel | 1800 | 1870 | Barnardiston | Suffolk | Ann Hammond | 52.112 | 0.459 | |
g-g-g-g-grandfather | Cornell | Daniel | 1771 | 1843 | Haverhill | Suffolk | Mary Mansfield | 52.081 | 0.445 | |
g-g-g-g-g-grandfather | Cornell | Samuel | 1740 | 1788 | Little Wratting | Suffolk | Mary Filney | 52.098 | 0.46 | |
g-g-g-g-g-g-grandfather | Cornell | John | 1703 | 1761 | Withersfield | Suffolk | Ann Gowers | 52.1 | 0.403 | |
great-grandmother | Sooby | Eliza | 1867 | 1898 | St. Pancras | London | William Henry Arnold | 51.531 | 0.126 | |
g-g-grandfather | Sooby | John | 1821 | 1908 | St. Pancras | London | Caroline Elizabeth Newton | 51.531 | 0.076 | |
great-grandmother | Walker | Ada Louisa | 1873 | 1935 | Old Ford | Middlesex | Frank Fulcher | 51.534 | -0.026 | |
g-g-grandfather | Walker | Joseph Ebenezer | 1828 | 1919 | Bethnal Green | London | Mary Daycock | 51.527 | 0.067 | |
g-g-g-grandfather | Walker | John | 1802 | 1867 | Bethnal Green | London | Eliza Taylor | 51.527 | 0.017 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<!-- One-page version. Code still needs a lot of cleaning up. --> | |
<head> | |
<meta charset="utf-8"> | |
<title>Marks/Arnold Family Tree</title> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<style> | |
body { | |
font-family: Verdana, Tahoma, sans-serif; | |
font-size: 11pt; | |
} | |
#container { | |
width: 960px; | |
height: 600px; | |
margin: 0 auto; | |
position: relative; | |
border-left: 1px solid gray; | |
border-bottom: 1px solid gray; | |
} | |
#map { | |
width: 740px; | |
float: left; | |
} | |
#legend { | |
float: right; | |
width: 200px; | |
height: 360px; | |
font-size: 10pt; | |
text-align: center; | |
padding: 25px 10px; | |
background: lightgray; | |
border: 0px; | |
border-radius: 8px; | |
} | |
h1 { | |
font-size: 36pt; | |
color: gold; | |
text-shadow: 5px 5px black; | |
text-align: right; | |
position: absolute; | |
top: 445px; | |
left: 480px; | |
} | |
h5 { | |
font-size; 8pt; | |
font-style: italic; | |
position: absolute; | |
top: 435px; | |
left: 850px; | |
} | |
#cities { | |
font-size: 10pt; | |
font-weight: bold; | |
} | |
div.tooltip { | |
position: absolute; | |
top: 70px; | |
left: 160px; | |
text-align: center; | |
width: 275px; | |
height: 130px; | |
padding: 2px; | |
font: 16px sans-serif; | |
font-weight: bold; | |
background: lightgray; | |
opacity: .9; | |
border: 0px; | |
border-radius: 8px; | |
pointer-events: none; | |
} | |
#m { | |
background-color: red; | |
} | |
#a { | |
background-color: blue; | |
} | |
#r { | |
background-color: orange; | |
} | |
#f { | |
background-color: indigo; | |
color: gray; | |
} | |
#s { | |
background-color: yellow; | |
} | |
#sb { | |
background-color: violet; | |
} | |
#c { | |
background-color: orangeRed; | |
} | |
#w { | |
background-color: royalBlue; | |
} | |
.lineM { | |
fill: none; | |
stroke: red; | |
stroke-width: 2px; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="container"> | |
<h1 id="hede">england's green<br/> | |
and pleasant land</h1> | |
<h5 id ="subhede">for my family</h5> | |
<div id="map"> | |
<script type="text/javascript"> | |
//Width and height | |
var w = 740; | |
var h = 600; | |
// create tooltip div | |
var div = d3.select("#map").append("div") | |
.attr("class", "tooltip") | |
.html( "<br/>" + "Ancestor Facts"); | |
// Define map projection | |
var projection = d3.geoAlbers() | |
// Somerset to London | |
// .scale([10000]) | |
.rotate( [0.2,0] ) | |
.center([-0.8, 51.5]) | |
.translate( [w/2, h/2] ); | |
//Define path generator | |
var path = d3.geoPath() | |
.projection(projection); | |
//Create SVG element | |
var svg1 = d3.select("#map") | |
.append("svg") | |
.attr("width", w) | |
.attr("height", h); | |
// define what to do when panning or zooming | |
var zooming = function(d) { | |
// new offset array | |
var offset = [d3.event.transform.x, d3.event.transform.y]; | |
// calculate new scale | |
var newScale = d3.event.transform.k * 1300; // probably need to change this | |
// update projection with new offset and scale | |
projection.translate(offset) | |
.scale(newScale); | |
// update all paths and circles | |
svg1.selectAll("path") | |
.attr("d", path); | |
svg1.selectAll("circle") | |
.attr("cx", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("cy", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}); | |
svg1.selectAll("text") // city labels update | |
.attr("x", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("y", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}) | |
.attr("dx", function(d) { | |
if (d.city === "London") | |
return "-0.5em"; | |
else | |
return ".5em"; | |
}) | |
.attr("text-anchor", function(d) { | |
if (d.city === "London") | |
return "end"; | |
else | |
return "start"; | |
}) | |
.text(function(d) { | |
return d.city; | |
}); | |
var branchLine = d3.line() // branchLines update | |
.x(function(d) { return projection([d.lon, d.lat])[0]; }) | |
.y(function(d) { return projection([d.lon, d.lat])[1]; }); | |
svg1.selectAll("path.lineM") | |
.attr("d", branchLine) | |
.attr("x", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("y", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}); | |
}; | |
// define zoom behavior | |
var zoom = d3.zoom() | |
.on("zoom", zooming); | |
// create container in which all zoom-able elements will live | |
var mapHolder = svg1.append("g") | |
.attr("id", "mapHolder") | |
.call(zoom) //Bind the zoom behavior | |
.call(zoom.transform, d3.zoomIdentity //Then apply the initial transform | |
.translate(w/2, h/2) | |
.scale(8) | |
.translate(0, 0)); | |
// Create a new, invisible background rect to catch zoom events | |
mapHolder.append("rect") | |
.attr("x", 0) | |
.attr("y", 0) | |
.attr("width", w) | |
.attr("height", h) | |
.attr("opacity", 0); | |
//Load in GeoJSON data | |
d3.json("GBR_adm2-1.json", function(json) { | |
//Bind data and create one path per GeoJSON feature | |
mapHolder.selectAll("path") | |
.data(json.features) | |
.enter() | |
.append("path") | |
.attr("d", path) | |
.attr("fill", function(d) { | |
if (d.properties.NAME_1 === "Wales" || d.properties.NAME_1 === "Scotland") | |
return "gray"; | |
else if (d.properties.NAME_1 === "Northern Ireland") | |
return "white"; | |
else | |
return "green"; | |
}) | |
.attr("stroke", "white") | |
.attr("stroke-width", "1"); | |
// load in cities data | |
d3.csv("citiesGBR1.csv", function(data) { | |
mapHolder.selectAll("circle") | |
.data(data) | |
.enter() | |
.append("circle") | |
.attr("cx", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("cy", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}) | |
.attr("r", function(d) { | |
if (d.city === "WALES" || d.city === "SCOTLAND") // ugly, but I didn't want a separate country file with just three elements | |
return 0; | |
else | |
return 3; | |
}); | |
// add city names | |
mapHolder.selectAll("cities") | |
.data(data) | |
.enter() | |
.append("text") | |
.attr("id", "cities") | |
.attr("x", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("y", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}) | |
.attr("dx", function(d) { | |
if (d.city === "London") | |
return "-0.5em"; | |
else | |
return ".5em"; | |
}) | |
.attr("text-anchor", function(d) { | |
if (d.city === "London") | |
return "end"; | |
else | |
return "start"; | |
}) | |
.text(function(d) { | |
return d.city; | |
}); | |
}); // end cities.csv | |
// load in family data | |
d3.csv("famTree1.csv", function(data) { | |
// filter for family branches | |
var dataM = data.filter(function(d) {return (d.surname === "Marks" || d.surname === "Markes"); }); | |
var dataA = data.filter(function(d) {return (d.surname === "Arnold"); }); | |
var dataR = data.filter(function(d) {return (d.surname === "Rowlinson" || d.surname === "Rowlingson" || d.surname === "Rollingson" || d.surname === "Rollinson"); }); | |
var dataF = data.filter(function(d) {return (d.surname === "Fulcher"); }); | |
var dataS = data.filter(function(d) {return (d.surname === "Saveall"); }); | |
var dataSB = data.filter(function(d) {return (d.surname === "Sooby"); }); | |
var dataC = data.filter(function(d) {return (d.surname === "Cornell"); }); | |
var dataW = data.filter(function(d) {return (d.surname === "Walker"); }); | |
//define line | |
var branchLine = d3.line() | |
.x(function(d) { return projection([d.lon, d.lat])[0]; }) | |
.y(function(d) { return projection([d.lon, d.lat])[1]; }); | |
// create paths for family branches | |
mapHolder.selectAll("pathM") | |
.data([dataM]) | |
.enter() | |
.append("path") | |
.attr("class", "lineM") | |
.attr("d", branchLine) | |
.attr("x", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("y", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}); | |
mapHolder.selectAll("pathM") | |
.data([dataA]) | |
.enter() | |
.append("path") | |
.attr("class", "lineM") | |
.style("stroke", "blue") | |
.attr("d", branchLine) | |
.attr("x", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("y", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}); | |
mapHolder.selectAll("pathM") | |
.data([dataR]) | |
.enter() | |
.append("path") | |
.attr("class", "lineM") | |
.style("stroke", "orange") | |
.attr("d", branchLine) | |
.attr("x", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("y", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}); | |
mapHolder.selectAll("pathM") | |
.data([dataF]) | |
.enter() | |
.append("path") | |
.attr("class", "lineM") | |
.style("stroke", "indigo") | |
.attr("d", branchLine) | |
.attr("x", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("y", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}); | |
mapHolder.selectAll("pathM") | |
.data([dataS]) | |
.enter() | |
.append("path") | |
.attr("class", "lineM") | |
.style("stroke", "yellow") | |
.attr("d", branchLine) | |
.attr("x", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("y", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}); | |
mapHolder.selectAll("pathM") | |
.data([dataSB]) | |
.enter() | |
.append("path") | |
.attr("class", "lineM") | |
.style("stroke", "violet") | |
.attr("d", branchLine) | |
.attr("x", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("y", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}); | |
mapHolder.selectAll("pathM") | |
.data([dataC]) | |
.enter() | |
.append("path") | |
.attr("class", "lineM") | |
.style("stroke", "orangeRed") | |
.attr("d", branchLine) | |
.attr("x", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("y", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}); | |
mapHolder.selectAll("pathM") | |
.data([dataW]) | |
.enter() | |
.append("path") | |
.attr("class", "lineM") | |
.style("stroke", "royalBlue") | |
.attr("d", branchLine) | |
.attr("x", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("y", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}); | |
// create circles for locations | |
mapHolder.selectAll("dots") | |
.data(data) | |
.enter() | |
.append("circle") | |
.attr("r", 5) | |
.attr("stroke", "white") | |
.attr("stroke-width", 1) | |
.attr("cx", function(d) { | |
return projection([d.lon, d.lat])[0]; | |
}) | |
.attr("cy", function(d) { | |
return projection([d.lon, d.lat])[1]; | |
}) | |
.attr("fill", function(d) { | |
if (d.surname === "Marks" || d.surname === "Markes") | |
return "red"; | |
else if (d.surname === "Arnold") | |
return "blue"; | |
else if (d.surname === "Rowlinson" || d.surname === "Rowlingson" || d.surname === "Rollingson" || d.surname === "Rollinson") | |
return "orange"; | |
else if (d.surname === "Fulcher") | |
return "indigo"; | |
else if (d.surname === "Saveall") | |
return "yellow"; | |
else if (d.surname === "Cornell") | |
return "orangeRed"; | |
else if (d.surname === "Sooby") | |
return "violet"; | |
else (d.surname === "Walker") | |
return "royalBlue"; | |
}) | |
.on("mouseover", function(d) { | |
div.html("<br/>" + d.gen + "<br/>" + d.name1 + " " + d.surname | |
+ "<br/>" + d.birthPlace + ", " + d.county + "<br/>" + d.birthYr + | |
" - " + d.death + "<br/>" + "Spouse: " + d.spouse) | |
}) | |
.on("mouseout", function(d) { | |
div.html("<br/>" + "Ancestor Facts") | |
}); | |
}); //end famTree.csv | |
}); // end GeoJSON | |
</script> | |
</div> <!-- end of div map --> | |
<div id="legend"> | |
<h3>Legend</h3> | |
<span id='m'>Marks</span><br/> | |
<span id='r'>Rowlinson</span><br/> | |
<span id='s'>Saveall</span><br/> | |
<span id='c'>Cornell</span><br/><br/> | |
<span id='a'>Arnold</span><br/> | |
<span id='f'>Fulcher</span><br/> | |
<span id='sb'>Sooby</span><br/> | |
<span id='w'>Walker</span><br/><br/> | |
<p>To see more information about an ancestor, put your cursor over one of the colored circles.</p> | |
<p>Use your mouse wheel and left button, to zoom and drag the map.</p> | |
</div> | |
</div> <!-- end of div container --> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment