paracoords = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);
svg
.append("style")
.text("path.hidden { stroke: #000; stroke-opacity: 0.01;}");
let activeBrushes = new Map();
const polylines = svg
.append("g")
.attr("fill", "none")
.attr("stroke-width", 1.5)
.attr("stroke-opacity", 0.4)
.selectAll("path")
.data(data)
.join("path")
.attr("stroke", "black")
.attr("d", d => d3.line()
.defined(([, value]) => value != null)
.x(([key]) => x(key))
.y(([key, value]) => y.get(key)(value))
(d3.cross(attributes, [d], (key, d) => [key, d[key]])))
.attr("stroke", d => z(d[colorAttribute]));
const axes = svg
.append("g")
.selectAll("g")
.data(attributes)
.join("g")
.attr("transform", d => `translate(${x(d)},0)`);
// TODO: add the visual representation of the axes
axes.append("g")
// match axes to function y to get the scales
.each(function(d) {d3.select(this).call(d3.axisRight(y.get(d)));})
// add label for each axis with shortAttributeNames
.call(g => g.append("text")
.attr("x", margin.left - 15)
.attr("y", 7.5)
.attr("text-anchor", "end")
.attr("fill", "currentColor")
.text(d => shortAttributeNames.get(d)))
// add style for text for a better appearance (SOURCE: d3 example from above)
.call(g => g
.selectAll("text")
.clone(true)
.lower()
.attr("fill", "none")
.attr("stroke-with", 5)
.attr("stroke-linejoin", "round")
.attr("stroke", "gray"));
function updateBrushing(i) {
// TODO implement brushing & linking
if(d3.event.selection === null) {
polylines.classed("hidden", false);
}
polylines.classed("hidden", d => {
for(var i = 0; i< attributes.length; ++i) { // check if attribute is in
// activeBrushes
var range_y = activeBrushes.get(attributes[i]);
// get y_coordinate of polylines in current attribute
var lines_y = y.get(attributes[i])(d[attributes[i]]);
if(range_y != null && (lines_y < range_y[0] || lines_y > range_y[1])) {
return true;
}
}
return false;
});
}
function brushed(attribute) {
activeBrushes.set(attribute, d3.event.selection);
updateBrushing();
}
function brushEnd(attribute) {
if (d3.event.selection !== null) return;
activeBrushes.delete(attribute);
updateBrushing();
}
const brushes = axes.append("g").call(
d3
.brushY()
.extent([[-10, margin.top], [10, height - margin.bottom]])
.on("brush", brushed)
.on("end", brushEnd)
);
return svg.node();
}