feat(tahuantinsuyu): cluster shrink, label compacto, hover destacado con z-order
Cuatro ajustes finos al esquema visual de planetas natales/topo:
1. **Discos achicados en cluster**: glyphs en cluster compartido
(≥2 miembros) llevan un factor adicional `0.86×` sobre el
shrink residual. Visualmente quedan apenas más pequeños — al
estar pegados, achicar un poco evita la sensación de
"amontonamiento" sin perder el unicode.
2. **Pill compartida más chica + libre de "espacios negros"**:
- Cálculo del ancho ahora usa `text.chars().count()` (era
`text.len()` en bytes — los chars unicode astronómicos
cuentan 3 bytes c/u y inflaban el ancho).
- Mínimo de ancho bajado de `font*2.0` a `font*1.4` y
padding lateral reducido. Pills con 1-3 chars ya no llevan
"espacios en negro" que sobrescriben elementos vecinos.
- Font del label compartido normal bajado a 9.0×s (era 10);
el hovereado sube a 10×s. Diferencial claro.
- Label individual también bajó a 8.5×s.
3. **Hover destacado**: nuevo "hovered_idx" identifica el glyph
bajo el cursor (de `HoverInfo::Body`). El glyph hovereado se
pinta al FINAL del árbol DOM — queda con z-order encima del
resto. Border al color pleno (vs 0.85), disco 1.18× y font
1.12× para destacarlo.
4. **Label del cluster hovereado destacado**: el cluster que
contiene al planeta bajo el cursor se renderiza con `fg_text`
(vs `fg_muted` para los demás) y font un punto más grande.
11 tests verdes (sin cambios — los affectados son del path de
render, no del cómputo).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1212,11 +1212,36 @@ fn render_wheel(
|
||||
}
|
||||
}
|
||||
|
||||
let shrink = (1.0 - residual * 0.30).clamp(0.60, 1.0);
|
||||
let disk_size = disk_size_base * shrink;
|
||||
let font_size_eff = (font_size * shrink).max(11.0);
|
||||
let shrink_residual = (1.0 - residual * 0.30).clamp(0.60, 1.0);
|
||||
|
||||
// El hovered glyph y su cluster reciben tratamiento
|
||||
// especial: lo postponemos para pintarlo al FINAL del
|
||||
// árbol (queda por encima del resto = z-order), y le
|
||||
// damos un border más fuerte. Su label cluster también
|
||||
// se destaca (color fg_text en lugar de fg_muted, font
|
||||
// un punto más grande).
|
||||
let hovered_sym: Option<&str> = match hover {
|
||||
Some(HoverInfo::Body { symbol, .. }) => Some(symbol.as_str()),
|
||||
_ => None,
|
||||
};
|
||||
let hovered_idx: Option<usize> = hovered_sym.and_then(|sym| {
|
||||
layer.glyphs.iter().position(|g| g.symbol == sym)
|
||||
});
|
||||
let hovered_cluster: Option<usize> = hovered_idx.map(|i| cluster_of[i]);
|
||||
|
||||
for (i, g) in layer.glyphs.iter().enumerate() {
|
||||
if Some(i) == hovered_idx {
|
||||
continue; // se pinta al final
|
||||
}
|
||||
// Achicar discos cuando el glyph está en cluster
|
||||
// (≥2 miembros) — al estar pegados se ven mejor
|
||||
// un poco más pequeños.
|
||||
let cluster_size = clusters[cluster_of[i]].len();
|
||||
let in_cluster_shrink = if cluster_size >= 2 { 0.86 } else { 1.0 };
|
||||
let effective_shrink = shrink_residual * in_cluster_shrink;
|
||||
let disk_size = disk_size_base * effective_shrink;
|
||||
let font_size_eff = (font_size * effective_shrink).max(11.0);
|
||||
|
||||
let display_deg = display_degs[i];
|
||||
let (x, y) = polar_to_screen(display_deg, asc, rot_offset, ring);
|
||||
let color = with_alpha(planet_color(palette, &g.symbol), alpha);
|
||||
@@ -1240,7 +1265,6 @@ fn render_wheel(
|
||||
|
||||
// Coord label individual: solo cuando el glyph
|
||||
// está SOLO en su cluster (≥2 ⇒ label compartido).
|
||||
let cluster_size = clusters[cluster_of[i]].len();
|
||||
if show_coords && (is_natal || is_topo) && cluster_size == 1 {
|
||||
let coord = format_coord_compact(g.deg);
|
||||
let label_r = ring - disk_size * 1.3;
|
||||
@@ -1252,20 +1276,21 @@ fn render_wheel(
|
||||
coord.into(),
|
||||
theme.fg_muted,
|
||||
halo_bg,
|
||||
9.5 * s,
|
||||
8.5 * s,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Label compartido para CADA cluster con ≥2 miembros.
|
||||
// Texto = símbolos concatenados + coord del centroide
|
||||
// real. Posicionado sobre el centroide DISPLAY (donde
|
||||
// se ven los discos tras el shift).
|
||||
// El del cluster hovereado se destaca: color fg_text
|
||||
// (vs fg_muted) y font un punto más grande.
|
||||
if show_coords && (is_natal || is_topo) {
|
||||
let disk_size_typical = disk_size_base * shrink_residual * 0.86;
|
||||
for (ci, c) in clusters.iter().enumerate() {
|
||||
if c.len() < 2 {
|
||||
continue;
|
||||
}
|
||||
let highlighted = Some(ci) == hovered_cluster;
|
||||
let center_display_deg = display_centroids[ci];
|
||||
let center_real_deg = cluster_centroids[ci];
|
||||
let symbols: String = c
|
||||
@@ -1275,17 +1300,68 @@ fn render_wheel(
|
||||
.join(" ");
|
||||
let coord = format_coord_compact(center_real_deg);
|
||||
let text = format!("{} {}", symbols, coord);
|
||||
let label_r = ring - disk_size * 1.5;
|
||||
let label_r = ring - disk_size_typical * 1.5;
|
||||
let (lx, ly) = polar_to_screen(
|
||||
center_display_deg,
|
||||
asc,
|
||||
rot_offset,
|
||||
label_r,
|
||||
);
|
||||
let (fg, font_sz) = if highlighted {
|
||||
(theme.fg_text, 10.0 * s)
|
||||
} else {
|
||||
(theme.fg_muted, 9.0 * s)
|
||||
};
|
||||
wheel = wheel.child(coord_label(
|
||||
cx_center + lx,
|
||||
cy_center + ly,
|
||||
text.into(),
|
||||
fg,
|
||||
halo_bg,
|
||||
font_sz,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// Render del glyph hovered al FINAL: queda encima del
|
||||
// resto en z-order. Disco un poco más grande y border
|
||||
// más prominente para destacar.
|
||||
if let Some(hi) = hovered_idx {
|
||||
let g = &layer.glyphs[hi];
|
||||
let display_deg = display_degs[hi];
|
||||
let (x, y) = polar_to_screen(display_deg, asc, rot_offset, ring);
|
||||
let color = with_alpha(planet_color(palette, &g.symbol), alpha);
|
||||
let mut glyph_text = planet_unicode(&g.symbol).to_string();
|
||||
if g.retrograde {
|
||||
glyph_text.push('ᴿ');
|
||||
}
|
||||
if let Some(marker) = &g.dignity_marker {
|
||||
glyph_text.push_str(marker);
|
||||
}
|
||||
let disk_size = disk_size_base * shrink_residual * 1.18;
|
||||
let font_size_eff = font_size * shrink_residual * 1.12;
|
||||
wheel = wheel.child(planet_glyph(
|
||||
cx_center + x,
|
||||
cy_center + y,
|
||||
disk_size,
|
||||
font_size_eff,
|
||||
glyph_text.into(),
|
||||
color,
|
||||
halo_bg,
|
||||
color, // border al color pleno (no .85) — destaca
|
||||
));
|
||||
// Si el hovered no está en cluster compartido,
|
||||
// pintamos su coord individual destacada acá.
|
||||
let cluster_size = clusters[cluster_of[hi]].len();
|
||||
if show_coords && (is_natal || is_topo) && cluster_size == 1 {
|
||||
let coord = format_coord_compact(g.deg);
|
||||
let label_r = ring - disk_size * 1.3;
|
||||
let (lx, ly) =
|
||||
polar_to_screen(display_deg, asc, rot_offset, label_r);
|
||||
wheel = wheel.child(coord_label(
|
||||
cx_center + lx,
|
||||
cy_center + ly,
|
||||
coord.into(),
|
||||
theme.fg_text,
|
||||
halo_bg,
|
||||
10.0 * s,
|
||||
@@ -2862,10 +2938,14 @@ fn coord_label(
|
||||
halo_bg: Hsla,
|
||||
font_size: f32,
|
||||
) -> gpui::Div {
|
||||
// Estimación gruesa del ancho (caracteres × ~5.5 px a font 9.5).
|
||||
// Suficiente para no recortar; el flex centra dentro.
|
||||
let w = (text.len() as f32 * (font_size * 0.58)).max(font_size * 2.0);
|
||||
let h = font_size + 6.0;
|
||||
// Estimación del ancho basada en `chars().count()` (NO `text.len()`
|
||||
// — los chars unicode astronómicos cuentan 3 bytes pero ocupan
|
||||
// ~1 columna de fuente). Padding lateral muy pequeño en lugar de
|
||||
// un mínimo grande: pills con 1-3 chars no llevan "espacios en
|
||||
// negro" que sobrescriben elementos vecinos.
|
||||
let char_count = text.chars().count() as f32;
|
||||
let w = (char_count * font_size * 0.62 + font_size * 0.5).max(font_size * 1.4);
|
||||
let h = font_size + 5.0;
|
||||
div()
|
||||
.absolute()
|
||||
.left(px(x - w / 2.0))
|
||||
|
||||
Reference in New Issue
Block a user