Skip to content

Commit

Permalink
Closes #8: Add spouses
Browse files Browse the repository at this point in the history
  • Loading branch information
magicsunday committed Feb 27, 2023
2 parents 1e8e84c + 9b60708 commit 0a7a3b6
Show file tree
Hide file tree
Showing 27 changed files with 895 additions and 356 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
},
"description": "",
"scripts": {
"prepare": "rollup -c"
"prepare": "rollup --config rollup.config.js",
"watch": "rollup --watch --config rollup.config.js"
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^15.0",
"d3-fetch": "^3.0",
"d3-hierarchy": "^3.0",
"d3-path": "^3.0",
"d3-scale": "^4.0",
"d3-selection": "^3.0",
"d3-shape": "^3.0",
Expand Down
7 changes: 7 additions & 0 deletions resources/css/svg.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@
fill: var(--sex-u-bg, rgb(255, 255, 255));
}

#webtrees-descendants-chart-container svg .spouse rect {
stroke-dasharray: 5;
stroke-width: 1px;
}

#webtrees-descendants-chart-container svg rect.image {
stroke: rgb(175, 175, 175);
}
Expand All @@ -44,6 +49,8 @@
fill: none;
stroke: rgb(175, 175, 175);
stroke-width: 1.5px;
stroke-linecap: butt;
/*shape-rendering: crispEdges;*/
}

#webtrees-descendants-chart-container svg g.name text {
Expand Down
2 changes: 1 addition & 1 deletion resources/js/descendants-chart.min.js

Large diffs are not rendered by default.

46 changes: 11 additions & 35 deletions resources/js/modules/chart.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export default class Chart
/**
* Returns the chart data.
*
* @returns {Object}
* @returns {Data}
*/
get data()
{
Expand All @@ -103,7 +103,7 @@ export default class Chart
/**
* Sets the chart data.
*
* @param {Object} value The chart data
* @param {Data} value The chart data
*/
set data(value)
{
Expand All @@ -130,32 +130,8 @@ export default class Chart
// Init the <svg> events
this._svg.initEvents(this._overlay);

let tree = new Tree(this._svg, this._configuration, this._hierarchy);

// let personGroup = this._svg.get().select("g.personGroup");
// let gradient = new Gradient(this._svg, this._configuration);
// let that = this;
//
// personGroup
// .selectAll("g.person")
// .data(this._hierarchy.nodes, (d) => d.data.id)
// .enter()
// .append("g")
// .attr("class", "person")
// .attr("id", (d) => "person-" + d.data.id);
//
// // Create a new selection in order to leave the previous enter() selection
// personGroup
// .selectAll("g.person")
// .each(function (d) {
// let person = d3.select(this);
//
// if (that._configuration.showColorGradients) {
// gradient.init(d);
// }
//
// new Person(that._svg, that._configuration, person, d);
// });
// Create tree
new Tree(this._svg, this._configuration, this._hierarchy);

this.bindClickEventListener();
this.updateViewBox();
Expand All @@ -170,14 +146,14 @@ export default class Chart

this._svg.visual
.selectAll("g.person")
.filter((d) => d.data.xref !== "")
.each(function (d) {
d3.select(this).on("click", function() { that.personClick(d.data); });
.filter(person => person.data.data.xref !== "")
.each(function (person) {
d3.select(this).on("click", function() { that.personClick(person.data); });
});
}

/**
* Method triggers either the "update" or "individual" method on the click on an person.
* Method triggers either the "update" or "individual" method on the click on a person.
*
* @param {Object} data The D3 data object
*
Expand All @@ -186,7 +162,7 @@ export default class Chart
personClick(data)
{
// Trigger either "update" or "redirectToIndividual" method on click depending on person in chart
(data.generation === 1) ? this.redirectToIndividual(data.url) : this.update(data.updateUrl);
(data.data.generation === 1) ? this.redirectToIndividual(data.data.url) : this.update(data.data.updateUrl);
}

/**
Expand Down Expand Up @@ -230,10 +206,10 @@ export default class Chart
// $.ajax({
// type: 'POST',
// url: indSelector.attr("data-ajax--url"),
// data: { q : data.xref }
// data: { q : data.data.xref }
// }).then(function (data) {
// // create the option and append to Select2
// var option = new Option(data.results[0].text, data.results[0].id, true, true);
// var option = new Option(data.data.results[0].text, data.data.results[0].id, true, true);
// indSelector.append(option).trigger('change');
// });
// });
Expand Down
124 changes: 111 additions & 13 deletions resources/js/modules/chart/elbow/horizontal.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,120 @@
* LICENSE file that was distributed with this source code.
*/

import * as d3 from "../../d3";

/**
* Draw the horizontal connecting lines between the profile boxes for Left/Right and Right/Left layout.
* Returns the path to draw the horizontal connecting lines between the profile
* boxes for Left/Right and Right/Left layout.
*
* @param {Object} datum D3 data object
* @param {Link} link The link object
* @param {Orientation} orientation The current orientation
*
* @returns {String}
*
* Curved edges => https://observablehq.com/@bumbeishvili/curved-edges-horizontal-d3-v3-v4-v5-v6
*/
export default function(datum, orientation)
export default function(link, orientation)
{
// Left => Right, Right => Left
const sourceX = datum.source.x + (orientation.direction() * (orientation.boxWidth / 2)),
sourceY = datum.source.y,
targetX = datum.target.x - (orientation.direction() * (orientation.boxWidth / 2)),
targetY = datum.target.y;

return "M " + sourceX + " " + sourceY +
" H " + (sourceX + ((targetX - sourceX) / 2)) +
" V " + targetY +
" H " + targetX;
const halfXOffset = orientation.xOffset / 2;
const halfYOffset = orientation.yOffset / 2;

let sourceX = link.source.x,
sourceY = link.source.y;

if ((typeof link.spouse !== "undefined") && (link.source.data.family === 0)) {
// For the first family, the link to the child nodes begins between
// the individual and the first spouse.
sourceY -= (link.source.y - link.spouse.y) / 2;
} else {
// For each additional family, the link to the child nodes begins at the additional spouse.
sourceX += (orientation.boxWidth / 2) * orientation.direction();
}

// No spouse assigned to source node
if (link.source.data.data === null) {
sourceX += (orientation.boxWidth / 2) * orientation.direction();
sourceY -= (orientation.boxHeight / 2) + (halfYOffset / 2);
}

if (link.target !== null) {
let targetX = link.target.x - (orientation.direction() * ((orientation.boxWidth / 2) + halfXOffset)),
targetY = link.target.y;

const path = d3.path();

// The line from source/spouse to target
path.moveTo(sourceX, sourceY);
path.lineTo(targetX, sourceY);
path.lineTo(targetX, targetY);
path.lineTo(targetX + (orientation.direction() * halfXOffset), targetY);

return path.toString();
}

return createLinksBetweenSpouses(link, orientation);
}

/**
* Returns the path needed to draw the lines between each spouse.
*
* @param {Link} link The link object
* @param {Orientation} orientation The current orientation
*
* @return {String}
*/
function createLinksBetweenSpouses(link, orientation)
{
const path = d3.path();

// The distance between the connecting lines when there are multiple spouses
const spouseLineOffset = 5;

// The distance from the line to the node. Causes the line to stop or begin just before the node,
// instead of going straight to the node, so that the connection to another spouse is clearer.
const lineStartOffset = 2;

let sourceX = link.source.x;

// Handle multiple spouses
if (link.source.data.family > 0) {
sourceX = link.spouse.x - (link.source.data.family * orientation.direction() * spouseLineOffset);
}

// Add link between first spouse and source
if (link.coords === null) {
path.moveTo(sourceX, link.spouse.y + (orientation.boxHeight / 2));
path.lineTo(sourceX, link.source.y - (orientation.boxHeight / 2));
}

// Append lines between source and all spouses
if (link.coords && (link.coords.length > 0)) {
for (let i = 0; i < link.coords.length; ++i) {
let startY = link.spouse.y + (orientation.boxHeight / 2);
let endY = link.coords[i].y - (orientation.boxHeight / 2);

if (i > 0) {
startY = link.coords[i - 1].y + (orientation.boxHeight / 2);
}

let startPosOffset = ((i > 0) ? lineStartOffset : 0);
let endPosOffset = (((i + 1) <= link.coords.length) ? lineStartOffset : 0);

path.moveTo(sourceX, startY + startPosOffset);
path.lineTo(sourceX, endY - endPosOffset);
}

// Add last part from previous spouse to actual spouse
path.moveTo(
sourceX,
link.coords[link.coords.length - 1].y + (orientation.boxHeight / 2) + lineStartOffset
);

path.lineTo(
sourceX,
link.source.y - (orientation.boxHeight / 2)
);
}

return path.toString();
}
122 changes: 109 additions & 13 deletions resources/js/modules/chart/elbow/vertical.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,118 @@
* LICENSE file that was distributed with this source code.
*/

import * as d3 from "../../d3";

/**
* Returns the path to draw the vertical connecting lines between the profile
* boxes for Top/Bottom and Bottom/Top layout.
*
* @param {Link} link The link object
* @param {Orientation} orientation The current orientation
*
* @returns {String}
*/
export default function(link, orientation)
{
const halfXOffset = orientation.xOffset / 2;
const halfYOffset = orientation.yOffset / 2;

let sourceX = link.source.x,
sourceY = link.source.y;

if ((typeof link.spouse !== "undefined") && (link.source.data.family === 0)) {
// For the first family, the link to the child nodes begins between
// the individual and the first spouse.
sourceX -= (link.source.x - link.spouse.x) / 2;
} else {
// For each additional family, the link to the child nodes begins at the additional spouse.
sourceY += (orientation.boxHeight / 2) * orientation.direction();
}

// No spouse assigned to source node
if (link.source.data.data === null) {
sourceX -= (orientation.boxWidth / 2) + (halfXOffset / 2);
sourceY += (orientation.boxHeight / 2) * orientation.direction();
}

if (link.target !== null) {
let targetX = link.target.x,
targetY = link.target.y - (orientation.direction() * ((orientation.boxHeight / 2) + halfYOffset));

const path = d3.path();

// The line from source/spouse to target
path.moveTo(sourceX, sourceY);
path.lineTo(sourceX, targetY);
path.lineTo(targetX, targetY);
path.lineTo(targetX, targetY + (orientation.direction() * halfYOffset));

return path.toString();
}

return createLinksBetweenSpouses(link, orientation);
}

/**
* Draw the vertical connecting lines between the profile boxes for Top/Bottom and Bottom/Top layout.
* Returns the path needed to draw the lines between each spouse.
*
* @param {Object} datum D3 data object
* @param {Link} link The link object
* @param {Orientation} orientation The current orientation
*
* @return {String}
*/
export default function(datum, orientation)
function createLinksBetweenSpouses(link, orientation)
{
// Top => Bottom, Bottom => Top
const sourceX = datum.source.x,
sourceY = datum.source.y + (orientation.direction() * (orientation.boxHeight / 2)),
targetX = datum.target.x,
targetY = datum.target.y - (orientation.direction() * (orientation.boxHeight / 2));

return "M " + sourceX + " " + sourceY +
" V " + (sourceY + ((targetY - sourceY) / 2)) +
" H " + targetX +
" V " + targetY;
const path = d3.path();

// The distance between the connecting lines when there are multiple spouses
const spouseLineOffset = 5;

// The distance from the line to the node. Causes the line to stop or begin just before the node,
// instead of going straight to the node, so that the connection to another spouse is clearer.
const lineStartOffset = 2;

let sourceY = link.source.y;

// Handle multiple spouses
if (link.source.data.family > 0) {
sourceY = link.spouse.y - (link.source.data.family * orientation.direction() * spouseLineOffset);
}

// Add link between first spouse and source
if (link.coords === null) {
path.moveTo(link.spouse.x + (orientation.boxWidth / 2), sourceY);
path.lineTo(link.source.x - (orientation.boxWidth / 2), sourceY);
}

// Append lines between source and all spouses
if (link.coords && (link.coords.length > 0)) {
for (let i = 0; i < link.coords.length; ++i) {
let startX = link.spouse.x + (orientation.boxWidth / 2);
let endX = link.coords[i].x - (orientation.boxWidth / 2);

if (i > 0) {
startX = link.coords[i - 1].x + (orientation.boxWidth / 2);
}

let startPosOffset = ((i > 0) ? lineStartOffset : 0);
let endPosOffset = (((i + 1) <= link.coords.length) ? lineStartOffset : 0);

path.moveTo(startX + startPosOffset, sourceY);
path.lineTo(endX - endPosOffset, sourceY);
}

// Add last part from previous spouse to actual spouse
path.moveTo(
link.coords[link.coords.length - 1].x + (orientation.boxWidth / 2) + lineStartOffset,
sourceY
);

path.lineTo(
link.source.x - (orientation.boxWidth / 2),
sourceY
);
}

return path.toString();
}
Loading

0 comments on commit 0a7a3b6

Please sign in to comment.