drawStartLines = g => {
const starts = g.selectAll(".start")
.data(chartData)
.join("g")
.attr("opacity", 1)
.attr("fill", d => color(d.territory))
.attr("transform", (d, i) => `translate(${bar.width},${innerRadius(numOfBars - 1 - i) - minRadius + margin.top})`)
.call(g => g.append("circle").attr("cy", bar.width / 2).attr("r", bar.width / 2))
.call(g => g.append("rect").attr("width", start.left).attr("height", bar.width))
.call(title)
.on("mouseover", highlight)
.on("mouseout", restore);
const texts = starts.append("text")
.attr("class", "start")
.attr("font-weight", "bold")
.attr("alignment-baseline", "hanging")
.attr("dx", start.left + start.padding)
.attr("dy", 4)
.text(d => `${d.territory} ${d3.format("$.2s")(d.values[year])}`);
var widths = texts.nodes().map(d => d.getComputedTextLength());
const ext = d3.extent(widths);
const min = ext[0], max = ext[1];
starts.append("rect")
.attr("width", (d, i) => start.right + (max - widths[i]))
.attr("height", bar.width)
.attr("transform", (d, i) => `translate(${widths[i] + start.left + start.padding * 2},0)`)
const startLength = start.left + start.right + start.padding * 2 + max + bar.width + (triangle.num ? 3 : 0);
starts.append("g")
.selectAll("polygon")
.data(seq(triangle.num))
.join("polygon")
.attr("points", `0,2 ${triangle.width},${triangle.width} 0,${triangle.height - 2}`)
.attr("transform", (d, i) => `translate(${startLength - bar.width + i * (triangle.width + triangle.padding)},0)`);
const y = d => innerRadius(d) - bar.padding / 2 - minRadius + margin.top,
tspace = startLength + (triangle.width + triangle.padding) * triangle.num;
g.selectAll("line")
.data(seq(numOfBars + 1))
.join("line")
.attr("stroke", "#ccc")
.attr("x1", bar.width).attr("y1", y)
.attr("x2", tspace).attr("y2", y);
parts.start = starts;
return tspace;
}