Timeline styling
This commit is contained in:
parent
f8a506bb77
commit
1590fa5615
3 changed files with 147 additions and 20 deletions
105
src/Viz.svelte
105
src/Viz.svelte
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import parsed_transits from "/data/parsed_transits.json";
|
||||
import { draw, slide, fade } from "svelte/transition";
|
||||
import { draw, slide, fade, scale } from "svelte/transition";
|
||||
import typewriter from "./lib/typewriter";
|
||||
import { fps } from "@sveu/browser";
|
||||
import LibrariesSvg from "./LibrariesSvg.svelte";
|
||||
|
||||
|
@ -261,30 +262,51 @@
|
|||
|
||||
<!-- {#if currentScene?.rendered_elements.indexOf("timeline") >= 0} -->
|
||||
<div id="timeline">
|
||||
{#if $current_item}
|
||||
<div id="current">
|
||||
<h2>{$current_item.title}</h2>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div id="events">
|
||||
{#each $events as e}
|
||||
<div class="entry" in:slide={{ duration: 200 }}>
|
||||
<!-- {m['Title (Complete)']} -->
|
||||
<span class="date"
|
||||
>{e.date.toLocaleDateString("en-UK", {
|
||||
weekday: "long",
|
||||
<span class="date" in:typewriter={{ delay: 1000, speed: 10 }}>
|
||||
<h3>
|
||||
{e.date.toLocaleDateString("en-UK", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
})}</span
|
||||
>
|
||||
<div class="text">
|
||||
<span class="title">{e.title}</span>
|
||||
<span class="description">{e.description}</span>
|
||||
})}
|
||||
</h3>
|
||||
<span class="weekday">
|
||||
{e.date.toLocaleDateString("en-UK", {
|
||||
weekday: "long",
|
||||
})}
|
||||
</span>
|
||||
<span class="time">
|
||||
{e.date.toLocaleTimeString("en-UK", {
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
})}
|
||||
</span>
|
||||
</span>
|
||||
<div class="divider">
|
||||
<div
|
||||
class="dot"
|
||||
in:scale={{ delay: 500, duration: 600 }}
|
||||
></div>
|
||||
<div class="connector"><!-- transition in css: --></div>
|
||||
</div>
|
||||
<div class="text" in:typewriter={{ delay: 1500, speed: 10 }}>
|
||||
<h3>{e.title}</h3>
|
||||
<p>{e.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{#if $current_item}
|
||||
<div id="current">
|
||||
<h2>{$current_item.title}</h2>
|
||||
<p>{[$current_item.Date, $current_item.Publisher, $current_item.Place].filter((e) => e).join(', ')}</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<!-- {/if} -->
|
||||
|
||||
|
@ -303,6 +325,58 @@
|
|||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
|
||||
#events{
|
||||
position: relative;
|
||||
// max-height: 200px;
|
||||
}
|
||||
|
||||
.entry {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
.date {
|
||||
width: 180px;
|
||||
}
|
||||
.divider {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
--divider-width: 15px;
|
||||
--connector-width: 2px;
|
||||
margin-right: 10px;
|
||||
|
||||
transform: translateY(calc(20px));
|
||||
|
||||
.dot {
|
||||
height: var(--divider-width);
|
||||
width: var(--divider-width);
|
||||
background-color: rgb(79 70 229);
|
||||
border-radius: calc(var(--divider-width) / 2);
|
||||
// border: solid 5px black;
|
||||
flex-grow: 0;
|
||||
}
|
||||
.connector {
|
||||
flex-grow: 1;
|
||||
border-left: solid var(--connector-width) rgb(203 213 225);
|
||||
transition: flex-grow 1s ease-in-out;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
margin-left: calc(
|
||||
(var(--divider-width) - var(--connector-width)) / 2
|
||||
);
|
||||
}
|
||||
}
|
||||
&:last-child .divider .connector {
|
||||
flex-grow: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.text {
|
||||
h3 {
|
||||
}
|
||||
p {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#fps {
|
||||
position: absolute;
|
||||
|
@ -355,7 +429,4 @@
|
|||
opacity: 0;
|
||||
} */
|
||||
|
||||
#events {
|
||||
max-height: 50px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -22,6 +22,7 @@ export type Item = {
|
|||
_original: Object
|
||||
}
|
||||
|
||||
|
||||
export function importItem(orig: Object, locations: Map<string, Location>): Item {
|
||||
// Barcode
|
||||
// Request Date
|
||||
|
|
55
src/lib/typewriter.js
Normal file
55
src/lib/typewriter.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Written by Weiming Wu
|
||||
// https://weimingwu.medium.com/a-better-typewriter-transition-in-svelte-528e9610ec2e
|
||||
|
||||
export default function typewriter(node, { delay = 0, speed = 50 }) {
|
||||
const textNodes = getAllTextNodes(node);
|
||||
if (!textNodes.length) {
|
||||
throw new Error(`This transition only works on elements with text nodes`);
|
||||
}
|
||||
|
||||
let totalLength = 0;
|
||||
const ranges = textNodes.map(textNode => {
|
||||
const range = [totalLength, totalLength + textNode.textContent.length];
|
||||
totalLength += textNode.textContent.length;
|
||||
const text = textNode.textContent;
|
||||
textNode.textContent = '';
|
||||
return { textNode, range, text };
|
||||
});
|
||||
|
||||
let currentRangeIndex = 0;
|
||||
function getCurrentRange(i) {
|
||||
while (ranges[currentRangeIndex].range[1] < i && currentRangeIndex < ranges.length) {
|
||||
const { textNode, text } = ranges[currentRangeIndex];
|
||||
textNode.textContent = text; // finish typing up the last node
|
||||
currentRangeIndex++;
|
||||
}
|
||||
return ranges[currentRangeIndex];
|
||||
}
|
||||
const duration = totalLength * speed;
|
||||
|
||||
return {
|
||||
delay,
|
||||
duration,
|
||||
tick: t => {
|
||||
const progress = ~~(totalLength * t);
|
||||
const { textNode, range, text } = getCurrentRange(progress);
|
||||
const [start, end] = range;
|
||||
const textLength = ((progress - start) / (end - start)) * text.length;
|
||||
textNode.textContent = text.slice(0, textLength);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function getAllTextNodes(node) {
|
||||
if (node.nodeType === 3) {
|
||||
return [node];
|
||||
} else if (node.hasChildNodes()) {
|
||||
let list = [];
|
||||
for (let child of node.childNodes) {
|
||||
getAllTextNodes(child).forEach(textNode => list.push(textNode));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
return [];
|
||||
}
|
Loading…
Reference in a new issue