Public
Edited
Jan 10
Insert cell
titulo = html`<h1>Mapa de relaciones</h1>`
Insert cell
csvURL = "https://docs.google.com/spreadsheets/d/e/2PACX-1vRZg544N1INu7IF4MKkxOQEDlx7DryxHIVHybDzO3fT1RJh41xwfuxiPjB-WjTut_rVo2dzE5JgSO3N/pub?output=csv";
Insert cell
function csvToJson(csv) {
const lines = csv.split("\n");
const headers = lines[0].split(",");

const result = lines.slice(1).map(line => {
const values = line.split(/,(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/);
const obj = {};
headers.forEach((header, index) => {
let value = values[index].trim();

value = value.replace(/"/g, '').trim();

obj[header.trim()] = value;
});
return obj;
});

return result;
}
Insert cell
googleSheetData = fetch(csvURL)
.then(response => response.text())
.then(csvText => csvToJson(csvText));
Insert cell
d3 = require("d3@6")
Insert cell
viewof svgMapa = FileAttachment("RELACIONES_FINALES2.svg").text()
Insert cell
viewof svgMapaRenderizado = {
const container = html`<div style="width: 100%; overflow: hidden; position: relative; margin: 0; padding: 0;"></div>`;
const svgElement = document.createElement("div");
svgElement.innerHTML = viewof svgMapa;
container.appendChild(svgElement);

const svg = svgElement.querySelector("svg");

if (!svg) {
console.error("El SVG no se ha cargado correctamente.");
return;
}

svg.onload = () => {
const svgHeight = svg.clientHeight;
container.style.height = `${svgHeight}px`;

const containerWidth = container.clientWidth;
const svgWidth = svg.clientWidth;

const translateX = (containerWidth - svgWidth) / 2;
const translateY = (container.clientHeight - svgHeight) / 2;

svg.setAttribute("transform", `translate(${translateX}, ${translateY})`);
};

const mapaGroup = svg.querySelector("#mapa");

// Configurar zoom
const zoom = d3.zoom()
.scaleExtent([0.5, 5])
.on("zoom", (event) => {
mapaGroup.setAttribute("transform", event.transform);
});

d3.select(svg)
.call(zoom)
.on("wheel.zoom", null)
.on("dblclick.zoom", null);

return container;
}
Insert cell
infoImagenes = googleSheetData;
Insert cell
viewof interactividad = {
const infoData = await googleSheetData;
const svgElement = viewof svgMapaRenderizado.querySelector("svg");

if (!svgElement) {
console.error("El SVG no se ha cargado correctamente.");
return;
}

const tooltip = document.createElement("div");
tooltip.id = "tooltip";
tooltip.style.position = "absolute";
tooltip.style.pointerEvents = "none";
tooltip.style.display = "none";
tooltip.style.background = "#fff";
tooltip.style.color = "#000";
tooltip.style.padding = "5px 10px";
tooltip.style.borderRadius = "5px";
tooltip.style.boxShadow = "0 2px 6px rgba(0, 0, 0, 0.2)";
tooltip.style.zIndex = "1000";
tooltip.style.maxWidth = "400px";
tooltip.style.minWidth = "150px";
tooltip.style.wordWrap = "break-word";
document.body.appendChild(tooltip);

let mapaGroup = svgElement.querySelector("#mapa");
if (!mapaGroup) {
mapaGroup = document.createElementNS("http://www.w3.org/2000/svg", "g");
mapaGroup.setAttribute("id", "mapa");

while (svgElement.firstChild) {
mapaGroup.appendChild(svgElement.firstChild);
}
svgElement.appendChild(mapaGroup);
}

const ajustarTooltip = (event) => {
const tooltipRect = tooltip.getBoundingClientRect();
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;

let left = event.clientX + 10;
let top = event.clientY + 10;

if (left + tooltipRect.width > viewportWidth) {
left = event.clientX - tooltipRect.width - 10;
}

if (top + tooltipRect.height > viewportHeight) {
top = event.clientY - tooltipRect.height - 10;
}

if (left < 0) left = 0;
if (top < 0) top = 0;

tooltip.style.left = `${left}px`;
tooltip.style.top = `${top}px`;
};

const mostrarTooltip = (event, data) => {
tooltip.style.display = "block";
tooltip.innerHTML = `<strong>${data.NOMBRE}</strong><br>${data.INFO}<br>${data.INFO2}`;
ajustarTooltip(event);
};

const ocultarTooltip = () => {
tooltip.style.display = "none";
};

const interactivos = svgElement.querySelectorAll("#Interactivo *");

interactivos.forEach(elemento => {
const id = elemento.id;
const data = infoData.find(row => row.id == id);

if (data) {
elemento.addEventListener("mouseover", (event) => {
mostrarTooltip(event, data);
elemento.style.cursor = "pointer";
});

elemento.addEventListener("mousemove", (event) => {
ajustarTooltip(event);
});

elemento.addEventListener("mouseout", () => {
ocultarTooltip();
});

elemento.addEventListener("click", (event) => {
mostrarTooltip(event, data);
});
}
});

return "Interactividad y zoom habilitados";
}
Insert cell
estilos = html`
<style>
body {
margin: 0;
padding: 0;
overflow-x: hidden;
}

#tooltip {
font-family: Helvetica, Arial, sans-serif;
background-color: white;
border: 3px solid #01f3b3;
color: black;
padding: 10px;
border-radius: 8px;
box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.1);
position: absolute;
display: none;
pointer-events: none;
z-index: 1000;
}

#tooltip strong {
font-size: 18px;
color: black;
}

#tooltip::before {
content: '';
position: absolute;
top: -3px;
left: -3px;
right: -3px;
bottom: -3px;
border: 3px solid #01f3b3;
border-radius: 8px;
}
</style>
<img src=${await FileAttachment("newtral_logo.png").url()} width="30" height="30" style="vertical-align: middle;">
<span style="font-family: Helvetica; border-bottom: 3px solid #01f3b3;">NewtralData</span>
`
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more