export function addLegend(svg, labelsSet, color) { const labels = Array.from(labelsSet) const legend = svg .selectAll(".legend-group") .data([null]) .enter() .append("g") .attr("class", "legend-group") .attr("transform", `translate(${width - 200}, 0)`) .selectAll(".legend-item") .data(labels) .enter() .append("g") .attr("class", "legend-item") .attr("transform", (d, i) => `translate(0, ${i * 20})`) .each(function(d, i) { const group = d3.select(this); group.append("rect") .attr("width", 10) .attr("height", 10) .attr("fill", color(d)) .on("mouseover", () => { svg.selectAll(".line").classed("highlighted", line => line === d); }) .on("mouseout", () => { svg.selectAll(".line").classed("highlighted", false); }); group.append("text") .attr("x", 20) .attr("y", 10) .attr("text-anchor", "start") .style("text-transform", "capitalize") .text(d); }); const legendBBox = svg.select(".legend-group").node().getBBox() svg.select(".legend-group") .insert("rect", ":first-child") .attr("width", 140) .attr("height", labels.length*20+20) .attr("transform", `translate(-10, -10)`) .attr("fill", "white") .attr("fill-opacity", 0.7) .attr("stroke", "#c6c6c6") .attr("stroke-width", 2) .attr("rx", 5) .attr("ry", 5) } export function addSvg(containerSelector, addX=0, addY=0) { return d3.select(containerSelector) .append("svg") .attr("width", "100%") .attr("height", "100%") .append("g") .attr("transform", `translate(${margin.left + 30+addX},${margin.top - 10+addY})`) } export function getDimensions(data) { return Object .entries(data[0]) .filter(([key, value])=>typeof value === "number" && key !== "Year") .map(([key, value]) => key); } //load schengen csv and country csv let visaCsv let countryCsv export async function loadData() { if (visaCsv&&countryCsv) { return [visaCsv, countryCsv]; } else { visaCsv = await d3.csv("schengen_data.csv"); countryCsv = await d3.csv("world-data-2023.csv"); return [visaCsv, countryCsv]; } } const views = { tree: document.getElementById('tree-container'), timeSeries: document.getElementById('time-series-container'), parallel: document.getElementById('parallel-coordinates-container'), bubble: document.getElementById('bubble-container') }; const buttons = { tree: document.getElementById('tree-view'), timeSeries: document.getElementById('time-series-view'), parallel: document.getElementById('parallel-view'), bubble: document.getElementById('bubble-view') }; export function navigate(viewName) { Object.values(views).forEach(view => view.classList.remove('visible')); Object.values(buttons).forEach(button => button.classList.remove('active')); views[viewName].classList.add('visible'); buttons[viewName].classList.add('active'); } export function initNavigation() { buttons.tree.addEventListener('click', () => navigate('tree')); buttons.timeSeries.addEventListener('click', () => navigate('timeSeries')); buttons.parallel.addEventListener('click', () => navigate('parallel')); buttons.bubble.addEventListener('click', () => navigate('bubble')); } export const margin = { top: 20, right: 30, bottom: 50, left: 50 }; export const width = window.innerWidth - margin.left - margin.right; export const height = window.innerHeight - margin.top - margin.bottom; export const colors = ["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99","#b15928","#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"]