Money forecast: calm optimistic start, rising plateau, thin solid projected lines
Deploy production / deploy (push) Successful in 1m13s
Deploy production / deploy (push) Successful in 1m13s
- Optimistic: no crash or correction through 2031 (5 years from today), earning the 9.5% average; cycle resumes after (correction 2035, crash 2040). Salary plateau grows 2%/yr real so pay never stalls. - Realistic keeps its single -30% crash in 2029; pessimistic unchanged. - Projected lines are now thin, slightly lighter solid lines in every view; legend updated. - Explanation text lists the crash/correction years and recovery time.
This commit is contained in:
1 parent
d3b9bb9ba2
commit
78b69c7d8f
6 files changed
+135
-38
No files matched your search
@@ -105,14 +105,17 @@
|
||||
)
|
||||
.join(' ');
|
||||
}
|
||||
/** Solid part through `dashedFrom` and dashed part from the last solid point onward. */
|
||||
/** Actual part through `projectedFrom` and projected part from the last actual point onward. */
|
||||
function segments(item: ChartSeries) {
|
||||
if (!item.dashedFrom) return { solid: item.points, dashed: [] };
|
||||
const split = item.points.findLastIndex((point) => point.date <= item.dashedFrom!);
|
||||
if (!item.projectedFrom) return { actual: item.points, projected: [] };
|
||||
const split = item.points.findLastIndex((point) => point.date <= item.projectedFrom!);
|
||||
return split < 0
|
||||
? { solid: [], dashed: item.points }
|
||||
: { solid: item.points.slice(0, split + 1), dashed: item.points.slice(split) };
|
||||
? { actual: [], projected: item.points }
|
||||
: { actual: item.points.slice(0, split + 1), projected: item.points.slice(split) };
|
||||
}
|
||||
/** Actual lines are thick and opaque; projected ones a thin, slightly lighter solid line. */
|
||||
const lineWidth = (item: ChartSeries, projected: boolean) =>
|
||||
projected ? (item.emphasis ? 1.5 : 1.1) : item.emphasis ? 3 : 1.75;
|
||||
function pointAt(points: ChartPoint[], date: string) {
|
||||
if (!points.length || date < points[0].date || date > points.at(-1)!.date) return null;
|
||||
return points.findLast((point) => point.date <= date) ?? null;
|
||||
@@ -236,16 +239,17 @@
|
||||
{/if}
|
||||
{#each series as item (item.label)}
|
||||
{@const parts = segments(item)}
|
||||
{#each [parts.solid, parts.dashed] as points, index (index)}
|
||||
{#each [parts.actual, parts.projected] as points, index (index)}
|
||||
{#if points.length > 1}
|
||||
<path
|
||||
d={path(points)}
|
||||
fill="none"
|
||||
stroke={item.color}
|
||||
stroke-width={item.emphasis ? 3 : 1.75}
|
||||
stroke-dasharray={index ? '6 5' : undefined}
|
||||
stroke-linecap={index ? 'butt' : 'round'}
|
||||
stroke-width={lineWidth(item, index === 1)}
|
||||
stroke-opacity={index ? 0.8 : 1}
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
data-line={index ? 'projected' : 'actual'}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
@@ -306,16 +310,16 @@
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if series.length > 1 || series.some((item) => item.dashedFrom)}
|
||||
{#if series.length > 1 || series.some((item) => item.projectedFrom)}
|
||||
<figcaption class="legend">
|
||||
{#each series as item (item.label)}
|
||||
<span class:emphasis={item.emphasis}
|
||||
><span class="swatch" style={`background:${item.color}`}></span>{item.label}</span
|
||||
>
|
||||
{/each}
|
||||
{#if series.some((item) => item.dashedFrom)}
|
||||
<span class="line-key first"><span class="key solid"></span>Actual</span>
|
||||
<span class="line-key"><span class="key dashed"></span>Projected</span>
|
||||
{#if series.some((item) => item.projectedFrom)}
|
||||
<span class="line-key first"><span class="key actual"></span>Actual</span>
|
||||
<span class="line-key"><span class="key projected"></span>Projected</span>
|
||||
{/if}
|
||||
</figcaption>
|
||||
{/if}
|
||||
@@ -419,10 +423,12 @@
|
||||
.key {
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
border-top: 2px solid var(--site-muted);
|
||||
border-top: 3px solid var(--site-muted);
|
||||
border-radius: 2px;
|
||||
}
|
||||
.key.dashed {
|
||||
border-top-style: dashed;
|
||||
.key.projected {
|
||||
border-top-width: 1.5px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.swatch {
|
||||
display: inline-block;
|
||||
|
||||
Reference in new issue
Block a user