Draw the set charts at all, and give their figures room to be drawn in

Neither chart drew anything. createBoardMap already awaits the map's load event
and resolves after it, so attaching a second load handler waited for something
that had already happened: the layer setup never ran, each map held only its
basemap layers, and the panel showed an empty whiteboard.

It failed silently, which is why the visible-failure branch did not catch it.
Nothing threw — the map was fine, the source was simply never added. A guard that
reports errors cannot report an absence of work.

The setup now runs directly after the await, and still binds once('load') if a
future engine resolves earlier. That keeps the fix correct rather than merely
right today.

The figures also grow from a zero basis instead of from their content. The map
inside is absolutely positioned and has no intrinsic width, so a basis of auto
asks for a content size of nothing and the legend takes the column — the figure
was measured at 39 pixels across while the decoder had the rest. This was hidden
behind the first bug: an empty chart and a chart with no room look the same.
This commit is contained in:
Doxa Maps 2026-09-28 20:04:07 +00:00
parent 66e0697645
commit 2f26f61ea4
4 changed files with 25 additions and 6 deletions

View file

@ -74,7 +74,7 @@ useShadowStyles(
// can never push the figure out of its pane the way the legend did on the centered set.
'.gbs{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;' +
'justify-content:center;padding:46px 10px 10px;box-sizing:border-box;overflow:hidden;background:#f3f3f1}' +
'.gbs-fig{position:relative;flex:1 1 auto;align-self:stretch;min-height:0;min-width:0}' +
'.gbs-fig{position:relative;flex:1 1 0%;align-self:stretch;min-height:240px;min-width:0}' +
'.gbs-ring{fill:none;stroke:#3b463d;stroke-width:1.5}' +
'.gbs-in{fill:#92b195}.gbs-out{fill:#6d766e;opacity:.65}' +
'.gbs-cross-halo{stroke:var(--gbs-bg,#f3f3f1);stroke-width:7;stroke-linecap:square}' +

View file

@ -59,7 +59,13 @@ onMounted(async () => {
{ whiteboard: true, boundaries: false, center: [0, 0], zoom: 1 })
const map = markRaw(made.map || made)
mapRef.value = map
map.on('load', () => {
// ★ createBoardMap ALREADY AWAITS LOAD. boardEngine resolves only after
// `await new Promise(res => map.once('load', res))`, so by the time this runs the event has
// fired and will not fire again — a second `map.on('load', …)` never runs and the layers are
// never added. The chart then draws a basemap-less whiteboard with no source on it: empty,
// silent, and with nothing thrown for a failure branch to catch.
// Guarded rather than assumed: if a future engine resolves earlier, once('load') still fires.
const setup = () => {
handle.value = markRaw(addTieredPointLayers(map, {
data: data.value,
sourceId: 'gbsm',
@ -79,7 +85,8 @@ onMounted(async () => {
},
font: labelFont,
}))
})
}
if (map.loaded()) setup(); else map.once('load', setup)
} catch (e) {
failed.value = String(e?.message || e)
}

View file

@ -127,7 +127,12 @@ useShadowStyles(
// when the same rule is written twice.
// min-height in the narrow column: a flex child with auto content can resolve to zero height,
// which is what a 0x0 chart is. rega measured exactly that at 390px.
'.gcs-fig{position:relative;flex:1 1 auto;align-self:stretch;min-width:0;min-height:240px;' +
// flex-basis 0, not auto. The map inside is position:absolute, so the figure has NO intrinsic
// width to be sized from — with basis auto it asks for its content, the content is nothing, and
// the legend beside it takes the column. rega measured the figure at 39px across while the
// decoder card had the rest. Growing from zero makes the figure take the remaining space
// whatever it happens to contain.
'.gcs-fig{position:relative;flex:1 1 0%;align-self:stretch;min-width:0;min-height:240px;' +
'display:flex;flex-direction:column;align-items:center;justify-content:center;overflow:hidden}' +
'.gcs-aside{flex:0 1 340px;min-width:0;min-height:0;overflow:auto;display:flex;align-items:flex-start}' +
'.gcs-legend-toggle{width:100%;padding:6px 10px;border:1px solid #d1d4cd;border-radius:8px;' +

View file

@ -79,7 +79,13 @@ onMounted(async () => {
{ whiteboard: true, boundaries: false, center: [0, 0], zoom: 1 })
const map = markRaw(made.map || made)
mapRef.value = map
map.on('load', () => {
// ★ createBoardMap ALREADY AWAITS LOAD. boardEngine resolves only after
// `await new Promise(res => map.once('load', res))`, so by the time this runs the event has
// fired and will not fire again — a second `map.on('load', …)` never runs and the layers are
// never added. The chart then draws a basemap-less whiteboard with no source on it: empty,
// silent, and with nothing thrown for a failure branch to catch.
// Guarded rather than assumed: if a future engine resolves earlier, once('load') still fires.
const setup = () => {
handle.value = markRaw(addTieredPointLayers(map, {
data: data.value,
sourceId: 'gcsm',
@ -96,7 +102,8 @@ onMounted(async () => {
onClick: (id, f) => { const r = f?.properties?.ring; if (r != null) emit('select', r) },
}))
ready.value = true
})
}
if (map.loaded()) setup(); else map.once('load', setup)
} catch (e) {
// FAILS VISIBLY: an empty whiteboard is indistinguishable from a chart with no groups.
failed.value = String(e?.message || e)