Skip to content

Instantly share code, notes, and snippets.

@zipus
Created August 28, 2025 12:58
Show Gist options
  • Save zipus/e83470473bbd94a44d4b84d2d0f0764c to your computer and use it in GitHub Desktop.
Save zipus/e83470473bbd94a44d4b84d2d0f0764c to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>Treemaps sincronizados</title>
<script src="https://cdn.plot.ly/plotly-2.30.0.min.js"></script>
<style>
html, body { height: 100%; margin: 0; }
.treemap { width: 100%; height: 33vh; }
</style>
</head>
<body>
<div id="tm-units" class="treemap"></div>
<div id="tm-volume" class="treemap"></div>
<div id="tm-value" class="treemap"></div>
<script>
const products = [
{"name": "Pen", "units": 1200, "weight": 10, "unit_price": 2},
{"name": "Pencil", "units": 500, "weight": 5, "unit_price": 1},
{"name": "Notebook", "units": 800, "weight": 50, "unit_price": 3},
{"name": "Keyboard", "units": 150, "weight": 800, "unit_price": 120},
{"name": "Mouse", "units": 300, "weight": 400, "unit_price": 40},
{"name": "Monitor", "units": 90, "weight": 3500,"unit_price": 250},
{"name": "Chair", "units": 60, "weight": 7000,"unit_price": 80},
{"name": "Table", "units": 40, "weight": 20000,"unit_price": 300},
{"name": "Paper", "units": 5000, "weight": 1, "unit_price": 0.2},
{"name": "Printer", "units": 25, "weight": 15000,"unit_price": 600}
];
const metrics = {
units: p => p.units,
volume: p => p.units * p.weight,
value: p => p.units * p.unit_price
};
function treemapTrace(metricKey, title) {
const mfun = metrics[metricKey];
const sorted = [...products].sort((a,b)=>mfun(b)-mfun(a));
return {
type: 'treemap',
labels: sorted.map(p => p.name),
ids: sorted.map(p => p.name),
parents: sorted.map(_ => ''),
values: sorted.map(mfun),
textinfo: 'label+value',
hovertemplate: `<b>%{label}</b><br>${title}: %{value}<extra></extra>`,
tiling: {packing: 'squarify'},
sort: true,
marker: {colors: sorted.map(_ => baseColor)},
branchvalues: 'total'
};
}
const baseColor = '#8fd3ff';
const fadeColor = '#e3e3e3';
const highlightColor = '#1f77b4';
function layout(title) {
return {
title,
margin: {l: 10, r: 10, t: 30, b: 10}
};
}
const traceUnits = treemapTrace('units', 'Units');
const traceVolume = treemapTrace('volume', 'Volume');
const traceValue = treemapTrace('value', 'Valuation');
const divUnits = document.getElementById('tm-units');
const divVolume = document.getElementById('tm-volume');
const divValue = document.getElementById('tm-value');
Plotly.newPlot(divUnits, [traceUnits], layout('Products — Units'), {displayModeBar: false});
Plotly.newPlot(divVolume, [traceVolume], layout('Products — Volume'), {displayModeBar: false});
Plotly.newPlot(divValue, [traceValue], layout('Products — Valuation (units × unit price)'), {displayModeBar: false});
function indexById(figDiv) {
const pts = figDiv.data[0].ids;
const map = new Map();
pts.forEach((id, i) => map.set(id, i));
return map;
}
const idxUnits = indexById(divUnits);
const idxVolume = indexById(divVolume);
const idxValue = indexById(divValue);
const baseColorsUnits = [...divUnits.data[0].marker.colors];
const baseColorsVolume = [...divVolume.data[0].marker.colors];
const baseColorsValue = [...divValue.data[0].marker.colors];
function highlightEverywhere(productId) {
if (idxUnits.has(productId)) {
const colors = baseColorsUnits.map((c, i) => i === idxUnits.get(productId) ? highlightColor : fadeColor);
Plotly.restyle(divUnits, { 'marker.colors': [colors] }, [0]);
}
if (idxVolume.has(productId)) {
const colors = baseColorsVolume.map((c, i) => i === idxVolume.get(productId) ? highlightColor : fadeColor);
Plotly.restyle(divVolume, { 'marker.colors': [colors] }, [0]);
}
if (idxValue.has(productId)) {
const colors = baseColorsValue.map((c, i) => i === idxValue.get(productId) ? highlightColor : fadeColor);
Plotly.restyle(divValue, { 'marker.colors': [colors] }, [0]);
}
}
function clearHighlights() {
Plotly.restyle(divUnits, { 'marker.colors': [baseColorsUnits] }, [0]);
Plotly.restyle(divVolume, { 'marker.colors': [baseColorsVolume] }, [0]);
Plotly.restyle(divValue, { 'marker.colors': [baseColorsValue] }, [0]);
}
[divUnits, divVolume, divValue].forEach(div => {
div.on('plotly_hover', (ev) => {
const pt = ev.points[0];
const id = pt.id || pt.label; // id configurado arriba
if (id) highlightEverywhere(id);
});
div.on('plotly_unhover', clearHighlights);
});
window.addEventListener('resize', () => {
Plotly.Plots.resize(divUnits);
Plotly.Plots.resize(divVolume);
Plotly.Plots.resize(divValue);
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment