- Files
- Index
- Style
- Script
- README
- CDN Add
PLEASE WAIT...
<div id="canvas-container">
<canvas id="diagramaCanvas"></canvas>
</div>
#canvas-container {
overflow: auto;
width: 100%;
height: 100%;
}
#diagramaCanvas {
width: 1000px;
height: 1000px;
}
const canvas = document.getElementById("diagramaCanvas")
const ctx = canvas.getContext("2d")
const canvasContainer = document.getElementById("canvas-container")
const dpr = window.devicePixelRatio || 1
canvas.width = canvas.clientWidth * dpr
canvas.height = canvas.clientHeight * dpr
ctx.scale(dpr, dpr)
canvasContainer.style.width = canvas.width + "px"
canvasContainer.style.height = canvas.height + "px"
ctx.imageSmoothingEnabled = false
ctx.textBaseline = "middle"
ctx.font = "16px Arial"
const tree = {
title: "Parent",
children: [
{
title: "Child A",
children: [
{
title: "Child A A - XX",
},
{
title: "Child A A - Prueba Larga",
},
{
title: "Child A B",
},
],
},
{
title: "Child B",
children: [
{
title: "Child B A",
},
],
},
],
}
const nodoLado = 60
const separacionHorizontal = 100
const separacionVertical = 20
function calcularTotalNodosNivel(nodo) {
if (!nodo || !nodo.children) {
return 1
} else {
return nodo.children.reduce(
(total, hijo) => total + calcularTotalNodosNivel(hijo),
0
)
}
}
function dibujarArbol(nodo, posX, posY, nodoResaltado) {
ctx.font = "16px Arial"
const medidaTexto = ctx.measureText(nodo.title)
const anchoTexto = medidaTexto.width
const margenHorizontal = 10
const anchoRect = anchoTexto + margenHorizontal
if (nodo.children) {
let yOffset =
posY - (separacionVertical * (calcularTotalNodosNivel(nodo) - 1)) / 2
nodo.children.forEach((hijo) => {
const totalNodosHijo = calcularTotalNodosNivel(hijo)
const hijoX = posX + separacionHorizontal + anchoRect
const hijoY = yOffset
dibujarLinea(posX + anchoRect, posY + 20 / 2, hijoX, hijoY + 20 / 2)
dibujarArbol(hijo, hijoX, hijoY, nodoResaltado)
yOffset += (nodoLado + separacionVertical) * totalNodosHijo
})
}
const resaltado = nodo === nodoResaltado
dibujarNodo(nodo, posX, posY, resaltado)
}
// function dibujarLineaCurva(startX, startY, endX, endY) {
// const controlX = startX + (endX - startX) / 2;
// const controlY = startY - separacionVertical * 2;
// ctx.beginPath();
// ctx.moveTo(startX, startY);
// ctx.quadraticCurveTo(controlX, controlY, endX, endY);
// ctx.strokeStyle = '#000000';
// ctx.stroke();
// }
function dibujarLinea(x1, y1, x2, y2) {
ctx.beginPath()
ctx.moveTo(x1, y1)
ctx.lineTo(x2, y2)
ctx.strokeStyle = "#004D40"
ctx.lineWidth = 2
ctx.stroke()
ctx.closePath()
}
function dibujarNodo(nodo, x, y, resaltado) {
const texto = nodo.title
const medidaTexto = ctx.measureText(texto)
const anchoTexto = medidaTexto.width
const margenHorizontal = 10
const margenVertical = 10
const anchoRect = anchoTexto + margenHorizontal
const altoRect = 20 + margenVertical
ctx.fillStyle = resaltado ? "#00BFA5" : "#009688"
ctx.fillRect(x, y, anchoRect, altoRect)
ctx.strokeStyle = "#004D40"
ctx.lineWidth = 2
ctx.strokeRect(x, y, anchoRect, altoRect)
ctx.fillStyle = "white"
ctx.font = "16px Arial"
ctx.textAlign = "center"
ctx.textBaseline = "middle"
ctx.fillText(texto, x + anchoRect / 2, y + altoRect / 2)
}
function obtenerNodoClickeado(nodo, posX, posY, punteroX, punteroY) {
ctx.font = "16px Arial"
const medidaTexto = ctx.measureText(nodo.title)
const anchoTexto = medidaTexto.width
const margenHorizontal = 10
const margenVertical = 10
const anchoRect = anchoTexto + margenHorizontal
const altoRect = 20 + margenVertical
if (punteroDentroNodo(punteroX, punteroY, posX, posY, anchoRect, altoRect)) {
return nodo
}
if (nodo.children) {
let yOffset =
posY - (separacionVertical * (calcularTotalNodosNivel(nodo) - 1)) / 2
for (const hijo of nodo.children) {
const totalNodosHijo = calcularTotalNodosNivel(hijo)
const hijoX = posX + separacionHorizontal + anchoRect
const hijoY = yOffset
const nodoClickeado = obtenerNodoClickeado(
hijo,
hijoX,
hijoY,
punteroX,
punteroY
)
if (nodoClickeado) {
return nodoClickeado
}
yOffset += (nodoLado + separacionVertical) * totalNodosHijo
}
}
return null
}
function punteroDentroNodo(x, y, nodoX, nodoY, anchoRect, altoRect) {
return (
x >= nodoX && x <= nodoX + anchoRect && y >= nodoY && y <= nodoY + altoRect
)
}
function limpiarCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height)
}
let nodoResaltado = null
canvas.addEventListener("mousemove", (event) => {
const rect = canvas.getBoundingClientRect()
const x = event.clientX - rect.left
const y = event.clientY - rect.top
const nuevoNodoResaltado = obtenerNodoClickeado(tree, inicioX, inicioY, x, y)
if (nuevoNodoResaltado !== nodoResaltado) {
nodoResaltado = nuevoNodoResaltado
limpiarCanvas()
dibujarArbol(tree, inicioX, inicioY, nodoResaltado)
}
})
canvas.addEventListener("click", (event) => {
const rect = canvas.getBoundingClientRect()
const x = event.clientX - rect.left
const y = event.clientY - rect.top
const nodoClickeado = obtenerNodoClickeado(tree, inicioX, inicioY, x, y)
if (nodoClickeado) {
console.log("Nodo clickeado:", nodoClickeado.title)
// Aquí puedes agregar cualquier acción que desees realizar cuando se haga clic en un nodo
}
})
const inicioX = nodoLado
const inicioY = ((canvas.height / dpr) - nodoLado) / 2
dibujarArbol(tree, inicioX, inicioY)