Skip to content

Commit

Permalink
tools/time: add subjective vs real chart
Browse files Browse the repository at this point in the history
  • Loading branch information
theonlypwner committed May 26, 2024
1 parent 863a9b0 commit 073e665
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 27 deletions.
12 changes: 12 additions & 0 deletions docs/tools/time.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: Time Perception
date: "2022-07-02 11:11:11 -0600"
mdate: 2024-05-26 12:19:00 -0600
entry: app_tools_time
---
<p>
Expand All @@ -9,6 +10,17 @@
When the differential equation is solved, subjective time is proportional to the square root of real time.
</p>

<p>
In the top chart, the blue line shows real time on the x-axis and subjective time on the y-axis.
The shape of this chart corresponds to the name of the time scale.
</p>

<p>
In the bottom chart, each rectangle represents one year.
The x-axis is rescaled to subjective time.
The white line shows subjective time on the x-axis and real time on the y-axis.
</p>

<p>Hover in one chart to see the corresponding time in all others.</p>

{% include app.html %}
107 changes: 80 additions & 27 deletions scripts/tools/time/AppToolsTime.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ let chartNodeL: HTMLDivElement
let chartNodeC: HTMLDivElement
let chartNodeQ: HTMLDivElement
function scaleChecked (scale: d3.ScaleContinuousNumeric<number, number, never>, val: number): number {
return val < scale.domain()[0] ? -1 : scale(val)
}
function init () {
const scaleR = d3.scaleLinear()
const scaleS = d3.scaleSqrt()
Expand All @@ -25,14 +29,20 @@ function init () {
const colorScale = d3.schemeCategory10
function updateHover (age: number) {
for (const { scale, hoverLine } of charts) {
const x = scale(age)
for (const { scale, hoverLineTop, hoverLine } of charts) {
const xR = scaleR(age)
const x = scaleChecked(scale, age)
hoverLineTop
.attr('x1', xR)
.attr('x2', xR)
hoverLine
.attr('x1', x)
.attr('x2', x)
}
}
const xAxisGenerator0 = d3.axisTop(scaleR)
const charts = ([
[chartNodeR, scaleR, 0],
[chartNodeS, scaleS, 0],
Expand All @@ -42,41 +52,60 @@ function init () {
] as [HTMLDivElement, d3.ScaleContinuousNumeric<number, number>, number][]).map(([chart, scale, lowerBound]) => {
const chartD3 = d3.select(chart)
const viz = chartD3.append('svg')
const groupBars = viz.append('g')
const xAxisGenerator = d3.axisBottom(scale)
const xAxisGenerator1 = d3.axisBottom(scale)
scale.domain([lowerBound, 2])
viz.on('mousemove', (event) => updateHover(scale.invert(d3.pointer(event)[0])))
const xAxis = viz.append('g')
.classed('axis', true)
.attr('transform', 'translate(0, 30)')
.call(xAxisGenerator)
viz.on('mousemove', (event) => {
const [mx, my] = d3.pointer(event)
updateHover((my < 40 ? scaleR : scale).invert(mx))
})
return {
chart,
scale,
lowerBound,
chartD3,
viz,
groupBars,
xAxisGenerator,
xAxis,
ageLine: viz.append('line')
groupBars: viz.append('g'),
lineChart0: viz.append('path'),
lineChart1: viz.append('path'),
xAxisGenerator0,
xAxisTop: viz.append('g')
.classed('axis', true)
.attr('transform', 'translate(0, 20)')
.call(xAxisGenerator0),
xAxisGenerator1,
xAxis: viz.append('g')
.classed('axis', true)
.attr('transform', 'translate(0, 60)')
.call(xAxisGenerator1),
ageLineTop: viz.append('line')
.attr('y1', 0)
.attr('y2', 100)
.attr('y2', 40)
.style('stroke', 'red'),
hoverLine: viz.append('line')
hoverLineTop: viz.append('line')
.attr('y1', 0)
.attr('y2', 100)
.style('stroke', 'black')
.attr('y2', 40)
.style('stroke', 'black'),
ageLine: viz.append('line')
.attr('y1', 40)
.attr('y2', 80)
.style('stroke', 'red'),
hoverLine: viz.append('line')
.attr('y1', 40)
.attr('y2', 80)
.style('stroke', 'black'),
}
})
updateCurHandler = function () {
for (const { scale, ageLine } of charts) {
const x = scale($curAge)
for (const { scale, ageLineTop, ageLine } of charts) {
const xR = scaleR($curAge)
const x = scaleChecked(scale, $curAge)
ageLineTop
.attr('x1', xR)
.attr('x2', xR)
ageLine
.attr('x1', x)
.attr('x2', x)
Expand All @@ -86,18 +115,42 @@ function init () {
updateMaxHandler = function () {
const years = [...Array($maxAge).keys()]
for (const { scale, lowerBound, groupBars, xAxisGenerator, xAxis } of charts) {
scale.domain([scale.domain()[0], $maxAge])
for (const { scale, lowerBound, groupBars, lineChart0, lineChart1, xAxisTop, xAxisGenerator1, xAxis } of charts) {
scale.domain([lowerBound, $maxAge])
const width = scale.range()[1]
const skip = scaleR(lowerBound)
const lineChartDatum0 = Array(Math.floor(width + 1 - skip)).fill(undefined).map((_, i) => [skip + i, 40 - 20 * scale(scaleR.invert(skip + i)) / width])
const lineChartDatum1 = Array(Math.floor(width + 1)).fill(undefined).map((_, i) => [i, 60 - 20 * scale.invert(i) / $maxAge])
lineChart0
.datum(lineChartDatum0)
.attr('fill', 'none')
.attr('stroke', 'steelblue')
.attr('stroke-width', 1.5)
.attr('d', d3.line())
lineChart1
.datum(lineChartDatum1)
.attr('fill', 'none')
.attr('stroke', 'white')
.attr('stroke-width', 1.5)
.attr('d', d3.line())
xAxisGenerator0
.scale(scaleR)
(xAxisTop)
xAxisGenerator
xAxisGenerator1
.scale(scale)
(xAxis)
groupBars.selectAll('rect')
.data(years.slice(lowerBound))
.join('rect')
.attr('x', (d) => scale(d))
.attr('y', 10)
.attr('y', 40)
.attr('width', (d) => scale(d + 1) - scale(d))
.attr('height', 20)
.attr('fill', (d) => colorScale[d % colorScale.length])
Expand Down Expand Up @@ -131,7 +184,7 @@ onMount(init)
<style>
.chart {
width: 100%;
height: 50px;
height: 80px;
background: #eee;
display: flex;
align-items: center;
Expand All @@ -144,7 +197,7 @@ onMount(init)
<div class="col-sm-6 mb-1">
<div class="input-group">
<span class="input-group-text">Current Age: </span>
<input type="number" class="form-control" bind:value={$curAge} min="1" on:change={() => updateCurHandler?.()}>
<input type="number" class="form-control" bind:value={$curAge} min="0" on:change={() => updateCurHandler?.()}>
</div>
</div>
<div class="col-sm-6 mb-3">
Expand All @@ -155,7 +208,7 @@ onMount(init)
</div>
</div>

<h1>Real Time</h1>
<h1>Real Time (Linear)</h1>
<p>This is a linear scale, representing real time.</p>
<div class="chart" bind:this={chartNodeR}></div>

Expand Down

0 comments on commit 073e665

Please sign in to comment.