diff --git a/frontend/src/AnalyticsView.vue b/frontend/src/AnalyticsView.vue index 4969235..61b264c 100644 --- a/frontend/src/AnalyticsView.vue +++ b/frontend/src/AnalyticsView.vue @@ -261,9 +261,10 @@ const abuseRows = computed(() => formatAbuseRows(data.value?.abuse || [], client } .analytics-panel { - margin: 0 auto; - width: min(60rem, 96vw); - padding: 1.5rem 2rem 4rem; + margin: 0; + width: 100%; + /* Same 1.25rem side spacing as main's article padding. */ + padding: 1.5rem 1.25rem 4rem; } .analytics-panel header { @@ -286,7 +287,7 @@ const abuseRows = computed(() => formatAbuseRows(data.value?.abuse || [], client .ranges button { padding: 0.2rem 0.7rem; font: inherit; - font-size: 0.85rem; + font-size: 0.9rem; color: var(--muted); background: none; border: 1px solid var(--line); @@ -344,7 +345,7 @@ const abuseRows = computed(() => formatAbuseRows(data.value?.abuse || [], client .visit-table { width: 100%; border-collapse: collapse; - font-size: 0.82rem; + font-size: 0.9rem; line-height: 1.3; } diff --git a/frontend/src/TransitionGraph.vue b/frontend/src/TransitionGraph.vue index b65c3f3..59325d8 100644 --- a/frontend/src/TransitionGraph.vue +++ b/frontend/src/TransitionGraph.vue @@ -6,7 +6,7 @@ * count), so the graph sums the buckets falling inside the selected * range, exactly like the charts and per-page views do. */ -import { computed, onBeforeUnmount, shallowRef, watch } from 'vue' +import { computed, onBeforeUnmount, onMounted, ref, shallowRef, watch } from 'vue' import { rangeWindow, WEEK } from './analytics/time.js' import { formatCount } from './analytics/format.js' import { @@ -121,11 +121,36 @@ const startBeads = (flows) => { watch(() => graph.value?.flows, startBeads, { immediate: true }) onBeforeUnmount(() => cancelAnimationFrame(rafId)) + +// Text in the graph must render at a constant screen size regardless of +// how far the enlarged graph's viewBox is scaled down to fit the panel: +// measure the unit→pixel ratio and expose it as --u on the svg, which the +// font-size rules divide by. Falls back to 1 (raw units) until measured. +const svgEl = ref(null) +const pxPerUnit = ref(1) +let resizeObs = null + +function updateScale() { + const el = svgEl.value + if (el && el.viewBox.baseVal.width) { + pxPerUnit.value = el.clientWidth / el.viewBox.baseVal.width + } +} + +onMounted(() => { + resizeObs = new ResizeObserver(updateScale) +}) +watch(svgEl, (el) => { + resizeObs?.disconnect() + if (el) resizeObs?.observe(el) +}) +watch(() => graph.value?.bounds, updateScale) +onBeforeUnmount(() => resizeObs?.disconnect())