function chapterFlow() {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("font-size", 10)
.attr("dominant-baseline", "central")
.attr("style", "background-color: #ffffff")
;
let flow = svg.append("g")
.attr("class", "flow")
.selectAll("g.edition")
.data(editions)
.join("g")
.attr("class", "edition")
.attr("transform", d => "translate(" + x(d.edition) + ",0)")
;
let chapters = svg.append("g")
.attr("class", "chapters")
.selectAll("g.edition")
.data(editions)
.join("g")
.attr("class", "edition")
.attr("transform", d => "translate(" + x(d.edition) + ",0)")
;
chapters.append("text")
.text(d => "Edition " + d.edition + " (" + editionYears[d.edition-1] + ", " + d.pages + " pages)")
.attr("y", d => y(d.pages) - 20)
.attr("font-weight", "bold")
.attr("font-size", "16")
;
let chapter = chapters.selectAll("g.chapter")
.data(d => d.chapters)
.join("g")
.attr("class", "chapter")
.attr("transform", d => "translate(0," + y(d.edition.pages - d.pageFrom) + ")")
;
// chapter rectangles
chapter.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", editionWidth)
.attr("height", d => y(d.pageFrom) - y(d.pageTo))
.attr("fill", "#ffffff")
.attr("stroke", "#000000")
.attr("stroke-width", "0.5")
.attr("rx", "5")
.attr("ry", "5")
;
// chapter title
// add a wrapper svg around text to establish clipping
chapter.append("svg")
.attr("width", editionWidth - 8)
.append("text")
.text(d => d.pageCount > 4 ? d.title : "")
.attr("y", d => (y(d.pageFrom) - y(d.pageTo)) / 2)
.attr("x", 8)
;
// circles for new chapters
chapter.each(function(d) {
if (d.edition.edition > 1 && d.predecessors.length == 0 ) {
d3.select(this)
.append("circle")
.attr("cx", -7)
.attr("cy", d => (y(d.pageFrom) - y(d.pageTo)) / 2)
.attr("r", 2.5)
.attr("fill","#ffffff")
.attr("stroke", "#bbbbbb")
.attr("stroke-width", 2)
}
});
// bars for chapters which are not continued in next edition
chapter.each(function(d) {
if (d.edition.edition < 3 && d.successors.length == 0 ) {
d3.select(this)
.append("rect")
.attr("x", editionWidth + 3)
.attr("y", 1)
.attr("width", 2.5)
.attr("height", d => Math.max(y(d.pageFrom) - y(d.pageTo) - 2, 2))
.attr("fill","#bbbbbb")
}
});
// "flow" of chapters between one edition an the next
let iGroups = flow.selectAll("path")
.data(d => {
let data = [];
for (let c of d.chapters) {
for (let p of c.predecessors) {
data.push({chapter: c, predecessor: p});
}
}
return data;
})
.join("path")
.attr("fill", "#dddddd")
.attr("stroke", d => d.chapter.pageCount > 0 ? "#ffffff" : "none")
.attr("stroke-width", 1)
.attr("d", flowPath) // see below for function that constructs the path geometry
.sort((a,b) => minPathWidth(b) - minPathWidth(a))
;
return svg.node();
}