feat(media): suppression Voronoi colore -- noeuds ecoles suffisent
This commit is contained in:
@@ -52,7 +52,6 @@ let d3EdgeLabelSel: any = null
|
|||||||
async function initGraph() {
|
async function initGraph() {
|
||||||
if (!svgRef.value || !props.data) return
|
if (!svgRef.value || !props.data) return
|
||||||
const d3 = await import('d3')
|
const d3 = await import('d3')
|
||||||
const { Delaunay } = await import('d3-delaunay')
|
|
||||||
|
|
||||||
const svgEl = svgRef.value
|
const svgEl = svgRef.value
|
||||||
const W = svgEl.clientWidth || 900
|
const W = svgEl.clientWidth || 900
|
||||||
@@ -66,73 +65,12 @@ async function initGraph() {
|
|||||||
|
|
||||||
const ecoleMap = new Map<string, EcoleData>(props.data.ecoles.map(e => [e.id, e]))
|
const ecoleMap = new Map<string, EcoleData>(props.data.ecoles.map(e => [e.id, e]))
|
||||||
|
|
||||||
// Positions fixes des ecoles (base pour Voronoi)
|
// Positions fixes des ecoles (base pour forces D3)
|
||||||
const ecolePositions = new Map<string, { tx: number; ty: number }>()
|
const ecolePositions = new Map<string, { tx: number; ty: number }>()
|
||||||
props.data.ecoles.forEach(e => {
|
props.data.ecoles.forEach(e => {
|
||||||
ecolePositions.set(e.id, { tx: W * e.x_hint, ty: H * e.y_hint })
|
ecolePositions.set(e.id, { tx: W * e.x_hint, ty: H * e.y_hint })
|
||||||
})
|
})
|
||||||
|
|
||||||
// ---- VORONOI BACKGROUND (couche 1) ----
|
|
||||||
const ecolesArr = props.data.ecoles
|
|
||||||
const points: [number, number][] = ecolesArr.map(e => [W * e.x_hint, H * e.y_hint])
|
|
||||||
|
|
||||||
const delaunay = Delaunay.from(points)
|
|
||||||
const voronoi = delaunay.voronoi([0, 0, W, H])
|
|
||||||
|
|
||||||
// Groupe Voronoi : separation Phase 8.D
|
|
||||||
// - gVoronoi : cells colorees, BLURRED via CSS .voronoi-bg
|
|
||||||
// - gVoronoiLabels : labels ecoles, NOT blurred (lisibilite 17px)
|
|
||||||
const gVoronoi = g.append('g').attr('class', 'voronoi-bg')
|
|
||||||
const gVoronoiLabels = g.append('g').attr('class', 'voronoi-labels')
|
|
||||||
|
|
||||||
ecolesArr.forEach((ecole, i) => {
|
|
||||||
const cellPath = voronoi.renderCell(i)
|
|
||||||
const poly = voronoi.cellPolygon(i)
|
|
||||||
|
|
||||||
gVoronoi.append('path')
|
|
||||||
.attr('d', cellPath)
|
|
||||||
.attr('fill', ecole.color)
|
|
||||||
.attr('fill-opacity', 0.48)
|
|
||||||
.attr('class', 'voronoi-cell')
|
|
||||||
.attr('data-ecole', ecole.id)
|
|
||||||
.on('mouseenter', (e: any) => {
|
|
||||||
if (!tooltipRef.value) return
|
|
||||||
tooltipRef.value.innerHTML = `<strong>${ecole.label}</strong><br><span style="opacity:0.75;font-size:0.72rem;">${ecole.description}</span>`
|
|
||||||
tooltipRef.value.style.opacity = '1'
|
|
||||||
})
|
|
||||||
.on('mousemove', (e: any) => {
|
|
||||||
if (!tooltipRef.value || !svgEl) return
|
|
||||||
const rect = (svgEl as HTMLElement).getBoundingClientRect()
|
|
||||||
tooltipRef.value.style.left = (e.clientX - rect.left + 14) + 'px'
|
|
||||||
tooltipRef.value.style.top = (e.clientY - rect.top - 10) + 'px'
|
|
||||||
})
|
|
||||||
.on('mouseleave', () => { if (tooltipRef.value) tooltipRef.value.style.opacity = '0' })
|
|
||||||
|
|
||||||
// Label ecole dans la cellule (centroid du polygone) - calque non-blurre
|
|
||||||
if (poly && poly.length > 0) {
|
|
||||||
const centroid = d3.polygonCentroid(poly as [number, number][])
|
|
||||||
if (centroid && !isNaN(centroid[0]) && !isNaN(centroid[1])) {
|
|
||||||
const words = ecole.label.split(' ')
|
|
||||||
const labelEl = gVoronoiLabels.append('text')
|
|
||||||
.attr('class', 'voronoi-cell-label')
|
|
||||||
.attr('x', centroid[0])
|
|
||||||
.attr('y', centroid[1])
|
|
||||||
.attr('text-anchor', 'middle')
|
|
||||||
.attr('dominant-baseline', 'middle')
|
|
||||||
.style('pointer-events', 'none')
|
|
||||||
.style('user-select', 'none')
|
|
||||||
|
|
||||||
if (words.length <= 2) {
|
|
||||||
labelEl.text(ecole.label)
|
|
||||||
} else {
|
|
||||||
const mid = Math.ceil(words.length / 2)
|
|
||||||
labelEl.append('tspan').attr('x', centroid[0]).attr('dy', '-0.55em').text(words.slice(0, mid).join(' '))
|
|
||||||
labelEl.append('tspan').attr('x', centroid[0]).attr('dy', '1.1em').text(words.slice(mid).join(' '))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// ---- LIENS D'INFLUENCE INTER-ECOLES (couche 3) ----
|
// ---- LIENS D'INFLUENCE INTER-ECOLES (couche 3) ----
|
||||||
const gInfluence = g.append('g').attr('class', 'links-influence')
|
const gInfluence = g.append('g').attr('class', 'links-influence')
|
||||||
|
|
||||||
@@ -382,12 +320,6 @@ defineExpose({ triggerResize })
|
|||||||
/* ---- Voronoi cellules : non-blurre Phase 8.F (revert Phase 8.D) ---- */
|
/* ---- Voronoi cellules : non-blurre Phase 8.F (revert Phase 8.D) ---- */
|
||||||
/* Blur retire ; les cellules colorees Bonpote-aligned suffisent visuellement. */
|
/* Blur retire ; les cellules colorees Bonpote-aligned suffisent visuellement. */
|
||||||
|
|
||||||
.voronoi-cell {
|
|
||||||
stroke: rgba(255, 255, 255, 0.3);
|
|
||||||
stroke-width: 1px;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ecole-node {
|
.ecole-node {
|
||||||
transition: opacity 0.15s, r 0.15s;
|
transition: opacity 0.15s, r 0.15s;
|
||||||
}
|
}
|
||||||
@@ -395,17 +327,4 @@ defineExpose({ triggerResize })
|
|||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- Labels ecoles : calque separe NON-blurre (Phase 8.D) ---- */
|
|
||||||
.voronoi-labels {
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.voronoi-cell-label {
|
|
||||||
fill: rgba(40,40,40,0.52);
|
|
||||||
font-size: 17px;
|
|
||||||
font-weight: 700;
|
|
||||||
letter-spacing: 0.3px;
|
|
||||||
pointer-events: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user