Tighter analytics chart chrome
- Unified chart text at 11px system-ui; fixed size independent of theme font - Day view y axis reads "visits / 5 min" / "views / 5 min" - Left margin and y tick spacing tightened (MARGIN_L 56 -> 40) - Gap between visits and views charts removed - Legend repositioned for the larger font
This commit is contained in:
@@ -152,7 +152,7 @@ const abuseRows = computed(() => formatAbuseRows(rangeData.value?.abuse || [], c
|
||||
<div><strong :title="String(visits.length)">{{ formatCount(visits.length) }}</strong> visits</div>
|
||||
<div><strong :title="String(totalViews)">{{ formatCount(totalViews) }}</strong> page views</div>
|
||||
<div><strong>{{ readStats.avgMinPerVisit }}</strong> min/visit</div>
|
||||
<div><strong>{{ readStats.avgArticleMedianMin }}</strong> min article read</div>
|
||||
<div><strong>{{ readStats.avgArticleMedianMin }}</strong> min/read</div>
|
||||
</section>
|
||||
|
||||
<VisitorCharts :data="data" :range="range" />
|
||||
|
||||
@@ -37,6 +37,11 @@ function freqLabel(unit) {
|
||||
return unit === '5min' ? '5 min' : unit === 'hour' ? 'hourly' : 'daily'
|
||||
}
|
||||
|
||||
/** Vertical axis caption: "visits / 5 min" on the day view, else "hourly visits" style. */
|
||||
function axisLabel(unit, ylabel) {
|
||||
return unit === '5min' ? `${ylabel} / 5 min` : `${freqLabel(unit)} ${ylabel}`
|
||||
}
|
||||
|
||||
/** Legend label for the overlaid past weeks: "Week M" or "Week M–N". */
|
||||
function pastLabel(series) {
|
||||
const oldest = series.at(-1).label.slice(5) // strip "Week "
|
||||
@@ -63,7 +68,7 @@ const viewChart = computed(() => buildChart(viewSeries.value, now.value))
|
||||
]" :key="c.ylabel">
|
||||
<template v-if="c.chart">
|
||||
<svg class="chart" :viewBox="`${-MARGIN_L} 0 ${VIEW_W} ${VIEW_H}`"
|
||||
role="img" :aria-label="`${freqLabel(c.chart.unit)} ${c.ylabel}`">
|
||||
role="img" :aria-label="axisLabel(c.chart.unit, c.ylabel)">
|
||||
<line v-for="g in c.chart.majors.slice(1)" :key="'j' + g.value"
|
||||
:x1="0" :x2="CHART_W" :y1="g.y" :y2="g.y" class="major" />
|
||||
<template v-for="t in c.chart.xticks" :key="'t' + t.x">
|
||||
@@ -85,22 +90,22 @@ const viewChart = computed(() => buildChart(viewSeries.value, now.value))
|
||||
</template>
|
||||
<line :x1="0" :x2="CHART_W" :y1="CHART_H - 0.5" :y2="CHART_H - 0.5"
|
||||
class="axis" />
|
||||
<text v-for="g in c.chart.majors" :key="'y' + g.value" x="-8" :y="g.y"
|
||||
<text v-for="g in c.chart.majors" :key="'y' + g.value" x="-5" :y="g.y"
|
||||
text-anchor="end" dominant-baseline="middle" class="ylab">{{ g.label }}</text>
|
||||
<text :x="-(MARGIN_L - 10)" :y="CHART_H / 2" text-anchor="middle"
|
||||
:transform="`rotate(-90 ${-(MARGIN_L - 10)} ${CHART_H / 2})`"
|
||||
class="yaxis-label">{{ freqLabel(c.chart.unit) }} {{ c.ylabel }}</text>
|
||||
class="yaxis-label">{{ axisLabel(c.chart.unit, c.ylabel) }}</text>
|
||||
<text v-for="t in c.chart.xticks" :key="'x' + t.x" :x="t.x" :y="CHART_H + MARGIN_B - 8"
|
||||
text-anchor="middle" class="xlab">{{ t.label }}</text>
|
||||
<!-- Week overlay legend, top right inside the plot: current week in
|
||||
accent, one muted specimen for the whole past range. -->
|
||||
<g v-if="c.legend && c.chart.series.length > 1">
|
||||
<line :x1="CHART_W - 86" :x2="CHART_W - 66" y1="10" y2="10" class="line" />
|
||||
<text :x="CHART_W - 60" y="10" dominant-baseline="middle"
|
||||
<line :x1="CHART_W - 98" :x2="CHART_W - 78" y1="10" y2="10" class="line" />
|
||||
<text :x="CHART_W - 72" y="10" dominant-baseline="middle"
|
||||
class="leglab">{{ c.chart.series[0].label }}</text>
|
||||
<line :x1="CHART_W - 86" :x2="CHART_W - 66" y1="23" y2="23"
|
||||
<line :x1="CHART_W - 98" :x2="CHART_W - 78" y1="25" y2="25"
|
||||
class="line past" style="opacity: 0.6" />
|
||||
<text :x="CHART_W - 60" y="23" dominant-baseline="middle"
|
||||
<text :x="CHART_W - 72" y="25" dominant-baseline="middle"
|
||||
class="leglab">{{ pastLabel(c.chart.series) }}</text>
|
||||
</g>
|
||||
</svg>
|
||||
@@ -120,8 +125,10 @@ const viewChart = computed(() => buildChart(viewSeries.value, now.value))
|
||||
|
||||
.chart .ylab,
|
||||
.chart .xlab,
|
||||
.chart .yaxis-label {
|
||||
font-size: 12px;
|
||||
.chart .yaxis-label,
|
||||
.chart .leglab {
|
||||
font-family: system-ui, sans-serif; /* theme fonts can be overly styled */
|
||||
font-size: 11px;
|
||||
fill: var(--muted);
|
||||
}
|
||||
|
||||
@@ -129,11 +136,6 @@ const viewChart = computed(() => buildChart(viewSeries.value, now.value))
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.chart .leglab {
|
||||
font-size: 10px;
|
||||
fill: var(--muted);
|
||||
}
|
||||
|
||||
.chart .minor {
|
||||
stroke: var(--line);
|
||||
stroke-width: 1;
|
||||
@@ -183,7 +185,5 @@ const viewChart = computed(() => buildChart(viewSeries.value, now.value))
|
||||
stroke: var(--muted);
|
||||
}
|
||||
|
||||
section { margin-top: 1.8rem; }
|
||||
|
||||
.empty { color: var(--muted); }
|
||||
</style>
|
||||
|
||||
@@ -12,7 +12,7 @@ import { formatCount } from './format.js'
|
||||
export const CHART_W = 720
|
||||
export const CHART_H = 126
|
||||
export const PAD_TOP = 14 // room above the highest point
|
||||
export const MARGIN_L = 56 // y tick labels + vertical axis label
|
||||
export const MARGIN_L = 40 // y tick labels + vertical axis label
|
||||
export const MARGIN_B = 24 // x tick labels
|
||||
export const VIEW_W = MARGIN_L + CHART_W + 8
|
||||
export const VIEW_H = CHART_H + MARGIN_B
|
||||
@@ -156,7 +156,7 @@ export function spline(pts) {
|
||||
const c1y = clampY(p1.y + (p2.y - p0.y) / 6)
|
||||
const c2y = clampY(p2.y - (p3.y - p1.y) / 6)
|
||||
d += `C${p1.x + (p2.x - p0.x) / 6},${c1y} `
|
||||
+ `${p2.x - (p3.x - p1.x) / 6},${c2y} ${p2.x},${p2.y}`
|
||||
+ `${p2.x - (p3.x - p1.x) / 6},${c2y} ${p2.x},${p2.y}`
|
||||
}
|
||||
return d
|
||||
}
|
||||
@@ -339,7 +339,7 @@ export function xticksFor(t0, t1) {
|
||||
if (span <= 4 * 365 * DAY) {
|
||||
const d = new Date(t0)
|
||||
let t = Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 1)
|
||||
for (; t <= t1; ) {
|
||||
for (; t <= t1;) {
|
||||
ticks.push(t)
|
||||
const m = new Date(t)
|
||||
t = Date.UTC(m.getUTCFullYear(), m.getUTCMonth() + 1, 1)
|
||||
|
||||
Reference in New Issue
Block a user