Compare commits
No commits in common. "5c35ce9a040c86e060a0b5e1d70bb19b51daba4b" and "c8187f3f5e36d0f98d12e386524233e128b92a60" have entirely different histories.
5c35ce9a04
...
c8187f3f5e
File diff suppressed because one or more lines are too long
20
index.html
20
index.html
|
@ -39,26 +39,6 @@
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* #libraries g circle{
|
||||
animation-timing-function: easeInOutCubic;
|
||||
} */
|
||||
#libraries g.send circle:nth-child(2){
|
||||
animation: send .5s 1 cubic-bezier(0.22, 1, 0.36, 1);
|
||||
/* fill: red; */
|
||||
}
|
||||
#libraries g.recv circle:nth-child(2){
|
||||
fill: rgba(199, 162, 217, 0.0)
|
||||
}
|
||||
#libraries g.recv circle:nth-child(2){
|
||||
/* fill: blue; */
|
||||
animation: recv 1s 1;
|
||||
}
|
||||
|
||||
|
||||
@keyframes send {15% {opacity: 1} 40%{r:25px; opacity:0;} 41% {r:10px; opacity:0.05} 100% {r: 20px; opacity:1}}
|
||||
@keyframes recv {50%{fill: rgba(199, 162, 217, 0.3);}}
|
||||
/* @keyframes recv {50%{transform:rotateY(180deg);}} */
|
||||
|
||||
body {
|
||||
background: black;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
||||
package = []
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.9"
|
||||
content-hash = "c595a0588c25d58f3e3834ad7169126836d262b925fe6ca9b5d540dcf301d254"
|
||||
content-hash = "5b80bcf39bc22fc51a0c05260792ccc8bde494467670046c58c64725c897eb75"
|
||||
|
||||
[metadata.files]
|
||||
|
|
|
@ -1,207 +0,0 @@
|
|||
<g
|
||||
id="APM"
|
||||
transform="translate(298.72484444444126, 433.0485336906215)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle484" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle486" />
|
||||
<text class="nodeTitle s-vynWWFEzB3Z5" y="13" x="35" id="text488"
|
||||
>Archaeological Collection</text
|
||||
>
|
||||
</g>
|
||||
<g
|
||||
id="OTM"
|
||||
transform="translate(1745.5955555555556, 3603.1193459656633)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle491" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle493" />
|
||||
<text
|
||||
class="nodeTitle s-vynWWFEzB3Z5"
|
||||
y="4.1199999"
|
||||
x="-35" text-anchor="end"
|
||||
id="text495">Allard Pierson Depot</text
|
||||
>
|
||||
</g>
|
||||
<g
|
||||
id="BC"
|
||||
transform="translate(298.72484444444126, 393.0485336906215)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle498" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle500" />
|
||||
<text class="nodeTitle s-vynWWFEzB3Z5" y="13" x="35" id="text502"
|
||||
>Handbibliotheek</text
|
||||
>
|
||||
<text
|
||||
class="nodeTitle s-vynWWFEzB3Z5"
|
||||
y="38"
|
||||
x="311.19113"
|
||||
id="text1097">Allard Pierson</text
|
||||
>
|
||||
</g>
|
||||
<g
|
||||
id="ARTIS"
|
||||
transform="translate(807.0959555555783, 551.9470916540013)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle505" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle507" />
|
||||
<text class="nodeTitle s-vynWWFEzB3Z5" y="13" x="35" id="text509"
|
||||
>Artis Bibliotheek</text
|
||||
>
|
||||
</g>
|
||||
<g
|
||||
id="BHBPU"
|
||||
transform="translate(408.1404000000112, 307.58142297433403)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle512" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle514" />
|
||||
<text class="nodeTitle s-vynWWFEzB3Z5" y="13" x="35" id="text516"
|
||||
>Bushuis - pickup location</text
|
||||
>
|
||||
</g>
|
||||
<g
|
||||
id="CEDLA"
|
||||
transform="translate(710.2181777777914, 820.5062916831351)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle519" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle521" />
|
||||
<text class="nodeTitle s-vynWWFEzB3Z5" y="13" x="35" id="text523">CEDLA</text
|
||||
>
|
||||
</g>
|
||||
<g
|
||||
id="UBGW"
|
||||
transform="translate(160.2826222222393, 520.1182633671162)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle526" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle528" />
|
||||
<text class="nodeTitle s-vynWWFEzB3Z5" y="13" x="35" id="text530"
|
||||
>GW-collecties UB</text
|
||||
>
|
||||
</g>
|
||||
<g
|
||||
id="IVIR"
|
||||
transform="translate(730.9048444444488, 682.295035560214)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle533" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle535" />
|
||||
<text class="nodeTitle s-vynWWFEzB3Z5" y="13" x="35" id="text537">IViR</text>
|
||||
</g>
|
||||
<g
|
||||
id="IWO"
|
||||
transform="translate(1775.5955555555554, 3553.1193459656633)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle540" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle542" />
|
||||
<text class="nodeTitle s-vynWWFEzB3Z5" y="13" x="35" id="text544"
|
||||
>IWO-depot</text
|
||||
>
|
||||
</g>
|
||||
<g
|
||||
id="JB"
|
||||
transform="translate(740.9048444444488, 750.295035560214)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle547" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle549" />
|
||||
<text class="nodeTitle s-vynWWFEzB3Z5" y="13" x="35" id="text551"
|
||||
>Juridische Bibliotheek</text
|
||||
>
|
||||
</g>
|
||||
<g
|
||||
id="REC"
|
||||
transform="translate(699.5315111111087, 623.2141384588231)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle554" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle556" />
|
||||
<text class="nodeTitle s-vynWWFEzB3Z5" y="13" x="35" id="text558"
|
||||
>Library Learning Centre Roeterseiland</text
|
||||
>
|
||||
</g>
|
||||
<g
|
||||
id="AMC"
|
||||
transform="translate(1767.38706666667, 3460.8911949512853)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle561" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle563" />
|
||||
<text class="nodeTitle s-vynWWFEzB3Z5" y="3.5" text-anchor="end" x="-35" id="text565"
|
||||
>Medische Bibliotheek</text
|
||||
>
|
||||
</g>
|
||||
<g
|
||||
id="PCHH"
|
||||
transform="translate(222.92706666665254, 150.79690464423038)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle568" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle570" />
|
||||
<text class="nodeTitle s-vynWWFEzB3Z5" y="13" x="35" id="text572"
|
||||
>P.C.Hoofthuis</text
|
||||
>
|
||||
</g>
|
||||
<g
|
||||
id="BETA"
|
||||
transform="translate(1687.8959555555593, 1008.3027457312287)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle575" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle577" />
|
||||
<text
|
||||
class="nodeTitle s-vynWWFEzB3Z5"
|
||||
y="4.1199999"
|
||||
x="-35" text-anchor="end"
|
||||
id="text579">Sciencepark Bibliotheek</text
|
||||
>
|
||||
</g>
|
||||
<g
|
||||
id="UBB"
|
||||
transform="translate(220.2826222222393, 630.1182633671162)"
|
||||
class="s-vynWWFEzB3Z5"
|
||||
>
|
||||
<circle r="5" class="s-vynWWFEzB3Z5" id="circle582" />
|
||||
<circle r="20" class="s-vynWWFEzB3Z5" id="circle584" />
|
||||
<text class="nodeTitle s-vynWWFEzB3Z5" y="13" x="35" id="text586"
|
||||
>UB Singel</text
|
||||
>
|
||||
</g>
|
||||
<path
|
||||
style=""
|
||||
d="M 492.42998,401.08039 H 593.04204 V 442.57506 L 579.95449,442.42775"
|
||||
id="path1093"
|
||||
/>
|
||||
<path
|
||||
style=""
|
||||
d="M 593.04204,421.82772 604.96062,421.82773"
|
||||
id="path1095"
|
||||
/>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
circle:first-child {
|
||||
fill: white;
|
||||
stroke: none;
|
||||
}
|
||||
circle {
|
||||
fill: none;
|
||||
stroke: white;
|
||||
stroke-width: 10;
|
||||
}
|
||||
text {
|
||||
fill: white;
|
||||
font-size: 15pt;
|
||||
}
|
||||
path{
|
||||
stroke: white;
|
||||
fill: none;
|
||||
stroke-width: 2px;
|
||||
}
|
||||
|
||||
</style>
|
104
src/Viz.svelte
104
src/Viz.svelte
|
@ -1,8 +1,7 @@
|
|||
<script lang="ts">
|
||||
import parsed_requests from "/data/parsed_requests.json";
|
||||
import { draw, slide, fade } from "svelte/transition";
|
||||
import { draw, slide } from "svelte/transition";
|
||||
import { fps } from "@sveu/browser";
|
||||
import LibrariesSvg from "./LibrariesSvg.svelte";
|
||||
|
||||
import { All, Scene, Timeline } from "./scenes/Scenes";
|
||||
import {
|
||||
|
@ -59,20 +58,20 @@
|
|||
|
||||
// filter nodes with only having both Latitude and Longitude.
|
||||
// then map these coordinates to the canvas space
|
||||
const locations = new Map(
|
||||
_nodes
|
||||
const locations = new Map(_nodes
|
||||
.filter((n) => n.lat && n.lon)
|
||||
.map((node) => {
|
||||
node["x"] = node_positions[node.code][0];
|
||||
node["y"] = node_positions[node.code][1];
|
||||
return node;
|
||||
})
|
||||
.map((d) => [d["name"], d]),
|
||||
.map((d) => [d["name"], d])
|
||||
);
|
||||
|
||||
|
||||
_requests
|
||||
// remove entries that stay at the same place
|
||||
.filter((n) => n["Owning Library Name"] != n["Pickup Location"])
|
||||
.filter((n) => n['Owning Library Name'] != n['Pickup Location'])
|
||||
.filter(
|
||||
(l) =>
|
||||
locations.has(l["Owning Library Name"]) &&
|
||||
|
@ -94,7 +93,6 @@
|
|||
target: locations.get(r["Pickup Location"]),
|
||||
nr: idx,
|
||||
item: items.get(identifier),
|
||||
date: new Date(r["Request Completion Date"]), // TODO: validate unfortunate M/D/Y format
|
||||
_original: r,
|
||||
d: "", // bit of a hacky workaround, refactor in object
|
||||
};
|
||||
|
@ -153,8 +151,8 @@
|
|||
|
||||
const occurences = new Map<Item, Movement[]>();
|
||||
movements.forEach((movement, idx) => {
|
||||
let movements = occurences.get(movement.item) ?? [];
|
||||
movements.push(movement);
|
||||
let movements = occurences.get(movement.item) ?? []
|
||||
movements.push(movement)
|
||||
occurences.set(movement.item, movements);
|
||||
});
|
||||
|
||||
|
@ -162,27 +160,25 @@
|
|||
locations: locations,
|
||||
items: items,
|
||||
movements: movements,
|
||||
occurences: occurences,
|
||||
};
|
||||
occurences: occurences
|
||||
}
|
||||
|
||||
let drawn_motions = writable(<Motion[]>[]); //.filter((m, i) => i < 100);
|
||||
$: opacity = Math.max(0.055, Math.min(.3, 70 / $drawn_motions.length));
|
||||
$: opacity = Math.max(0.055, Math.min(1, 200 / $drawn_motions.length));
|
||||
let overlay_motions = writable(<Motion[]>[]); //.filter((m, i) => i < 100);
|
||||
let events = writable(<Log[]>[]); //.filter((m, i) => i < 100);
|
||||
let current_item = writable(<Item | null>null); //.filter((m, i) => i < 100);
|
||||
|
||||
const viz_data: VizData = {
|
||||
drawn_motions: drawn_motions,
|
||||
overlay_motions: overlay_motions,
|
||||
events: events,
|
||||
current_item: current_item,
|
||||
};
|
||||
}
|
||||
|
||||
import { onMount, onDestroy } from "svelte";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
let scenes = [All, Timeline];
|
||||
let currentSceneI = parseInt(window.location.hash[1] ?? 0);
|
||||
let currentSceneI = 0;
|
||||
let currentScene: Scene;
|
||||
|
||||
function nextScene() {
|
||||
|
@ -191,7 +187,11 @@
|
|||
}
|
||||
|
||||
console.log("Next scene", currentSceneI);
|
||||
currentScene = new scenes[currentSceneI](data, viz_data, nextScene);
|
||||
currentScene = new scenes[currentSceneI](
|
||||
data,
|
||||
viz_data,
|
||||
nextScene,
|
||||
);
|
||||
currentSceneI = (currentSceneI + 1) % scenes.length;
|
||||
}
|
||||
|
||||
|
@ -226,10 +226,8 @@
|
|||
|
||||
<h1>library of <span id="motiontitle">motions</span></h1>
|
||||
<div id="about">
|
||||
<span
|
||||
>Work by <em>Ruben van de Ven</em> for the
|
||||
<em>University of Amsterdam Library</em>.</span
|
||||
>
|
||||
<span>Work by <em>Ruben van de Ven</em> for the
|
||||
<em>University of Amsterdam Library</em>.</span>
|
||||
<span>Fonts by <em>Open Source Publishing</em>.</span>
|
||||
</div>
|
||||
|
||||
|
@ -237,8 +235,7 @@
|
|||
<g id="movements">
|
||||
{#each $drawn_motions as m}
|
||||
<path
|
||||
in:draw={{ duration: m.duration }}
|
||||
out:fade={{ duration: 1000 }}
|
||||
in:draw|global={{ duration: m.duration }}
|
||||
d={m.movement.d}
|
||||
style="opacity: {opacity}"
|
||||
></path>
|
||||
|
@ -246,52 +243,34 @@
|
|||
</g>
|
||||
<g id="overlay_motions">
|
||||
{#each $overlay_motions as m}
|
||||
<path out:fade={{ duration: 1000 }}
|
||||
in:draw={{ duration: m.duration }}
|
||||
d={m.movement.d}
|
||||
<path in:draw|global={{ duration: m.duration }} d={m.movement.d}
|
||||
></path>
|
||||
{/each}
|
||||
</g>
|
||||
<g id="libraries">
|
||||
<LibrariesSvg />
|
||||
<!-- {#each locations.values() as node}
|
||||
{#each locations.values() as node}
|
||||
<g id={node.code} transform="translate({node.x}, {node.y})">
|
||||
<circle r="5"></circle>
|
||||
<circle r="20"></circle>
|
||||
<text class="nodeTitle" y="13" x="35">{node.name}</text>
|
||||
</g>
|
||||
{/each} -->
|
||||
{/each}
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
<!-- {#if currentScene?.rendered_elements.indexOf("timeline") >= 0} -->
|
||||
{#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}
|
||||
{#each $events as m}
|
||||
<div class="entry" in:slide={{ duration: 200 }}>
|
||||
<!-- {m['Title (Complete)']} -->
|
||||
<span class="date"
|
||||
>{e.date.toLocaleDateString("en-UK", {
|
||||
weekday: "long",
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
})}</span
|
||||
>{m.movement._original["Request Completion Date"]}</span
|
||||
>
|
||||
<div class="text">
|
||||
<span class="title">{e.title}</span>
|
||||
<span class="description">{e.description}</span>
|
||||
</div>
|
||||
<span class="location">{m.movement.target.name}</span>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
<!-- {/if} -->
|
||||
{/if}
|
||||
|
||||
{#if dev}
|
||||
<div id="fps">{$_fps}</div>
|
||||
|
@ -337,26 +316,31 @@
|
|||
display:block;
|
||||
}
|
||||
}
|
||||
|
||||
#libraries circle:first-child {
|
||||
fill: white;
|
||||
stroke: none;
|
||||
}
|
||||
#libraries circle {
|
||||
fill: none;
|
||||
stroke: white;
|
||||
stroke-width: 10;
|
||||
}
|
||||
path {
|
||||
stroke: #bc89ff;
|
||||
stroke-width: 3px;
|
||||
stroke-width: 2px;
|
||||
fill: none;
|
||||
animation: highlight-on-insert 1s 1;
|
||||
}
|
||||
@keyframes highlight-on-insert{10% {opacity: .7; stroke:#ff89ff}}
|
||||
#overlay_motions path {
|
||||
stroke: rgba(255, 255, 0, 0.641);
|
||||
stroke-width: 5;
|
||||
stroke: red;
|
||||
stroke-width: 4;
|
||||
opacity: 1;
|
||||
}
|
||||
text {
|
||||
fill: white;
|
||||
font-size: 30pt;
|
||||
}
|
||||
|
||||
/* path:not(.selected) {
|
||||
opacity: 0;
|
||||
} */
|
||||
|
||||
#events {
|
||||
max-height: 50px;
|
||||
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
font-weight: 200;
|
||||
color: black;
|
||||
/* background: linear-gradient(180deg, #3a294c 0%, #62487f 100%); */
|
||||
/* background: rgb(45, 45, 45); */
|
||||
background: rgb(45, 45, 45);
|
||||
/* background: linear-gradient(to bottom right, #6fa8d9f7, #cdeed3); */
|
||||
border-radius: 40px;
|
||||
}
|
||||
|
|
|
@ -19,8 +19,7 @@ export type Movement = {
|
|||
item: Item,
|
||||
_original: Object
|
||||
// also contains additional request data (see requests.csv)
|
||||
d: String, // the svg path
|
||||
date: Date,
|
||||
d: String
|
||||
};
|
||||
|
||||
export type Occurences = Map<Item, Movement[]>
|
||||
|
@ -50,8 +49,7 @@ export type Log = {
|
|||
export type VizData = {
|
||||
drawn_motions: Writable<Motion[]>,
|
||||
overlay_motions: Writable<Motion[]>,
|
||||
events: Writable<Log[]>,
|
||||
current_item: Writable<Item | null>
|
||||
events: Writable<Log[]>
|
||||
}
|
||||
|
||||
export function get_path_d(movement: Movement) {
|
||||
|
@ -89,8 +87,8 @@ export function get_path_d(movement: Movement) {
|
|||
dy = m.target.y - m.source.y;
|
||||
angle = Math.atan2(dx, dy);
|
||||
|
||||
var srcSize = 31; //_mapGraph.getSizeForNode(m.source);
|
||||
var tgtSize = 31; //_mapGraph.getSizeForNode(m.target);
|
||||
var srcSize = 5; //_mapGraph.getSizeForNode(m.source);
|
||||
var tgtSize = 5; //_mapGraph.getSizeForNode(m.target);
|
||||
|
||||
// Compute the line endpoint such that the arrow
|
||||
// it not in the center, but rather slightly out of it
|
||||
|
|
|
@ -1,83 +1,31 @@
|
|||
import type { Writable } from "svelte/store";
|
||||
import type { Data, Item, Log, Motion, Movement, VizData } from "../lib/types";
|
||||
import type { Data, Item, Motion, Movement, VizData } from "../lib/types";
|
||||
|
||||
export class Scene {
|
||||
rendered_elements: String[] = []
|
||||
data: Data;
|
||||
viz_data: VizData;
|
||||
nextScene: CallableFunction;
|
||||
|
||||
constructor(data: Data, viz_data: VizData, nextScene: CallableFunction) {
|
||||
this.data = data;
|
||||
this.viz_data = viz_data;
|
||||
this.nextScene = nextScene;
|
||||
}
|
||||
|
||||
drawMovements(movements: Movement[], duration: number, in_overlay = false){
|
||||
let motions: Motion[] = movements.map((m) => ({ duration: duration, movement: m }));
|
||||
// TODO abstract in function drawMovements()
|
||||
// TODO in there, setTimeout for arrival effect on node
|
||||
|
||||
const set = in_overlay ? this.viz_data.overlay_motions : this.viz_data.drawn_motions
|
||||
setTimeout(() => {
|
||||
set.update(items => ([...items, ...motions]))
|
||||
}, 100);
|
||||
|
||||
motions.forEach((motion) => {
|
||||
const movement = motion.movement
|
||||
const srcEl = document.getElementById(movement.source.code)
|
||||
const tgtEl = document.getElementById(movement.target.code)
|
||||
// console.log(srcEl, tgtEl, movement.source.code, movement.target.code)
|
||||
srcEl?.classList.remove('send', 'recv');
|
||||
setTimeout(() => {
|
||||
srcEl?.classList.add('send');
|
||||
}, 200) // very brief to just trigger css anim
|
||||
setTimeout(() => {
|
||||
tgtEl?.classList.remove('send', 'recv');
|
||||
}, duration - 280) // very brief to just trigger css anim
|
||||
setTimeout(() => {
|
||||
tgtEl?.classList.add('recv');
|
||||
}, duration - 250) // very brief to just trigger css anim
|
||||
})
|
||||
}
|
||||
|
||||
stop() {
|
||||
console.log("TODO: stop timeout")
|
||||
}
|
||||
}
|
||||
|
||||
export class All extends Scene {
|
||||
allMovements: Movement[]
|
||||
motions: Writable<Motion[]>
|
||||
interval: number
|
||||
step: number = 0
|
||||
nextScene: CallableFunction
|
||||
locationCounts = new Map<Location, { in: number, out: number }>()
|
||||
selected_movements: Movement[];
|
||||
|
||||
options = {
|
||||
interval_days: .1,
|
||||
tick_interval: 1000, // ms
|
||||
items_per_tick: 1,
|
||||
}
|
||||
|
||||
constructor(data: Data, viz_data: VizData, nextScene: CallableFunction) {
|
||||
super(data, viz_data, nextScene);
|
||||
super()
|
||||
|
||||
this.nextScene = nextScene
|
||||
|
||||
// start setInterval to trigger additions per 100 or so to drawn_movements (rendered on map)
|
||||
// when done, trigger parent.done()
|
||||
// this.allMovements = data.movements;
|
||||
|
||||
// sorted by date
|
||||
data.movements.sort((a,b) => a.date - b.date);
|
||||
const last_move_date = data.movements[data.movements.length-1].date
|
||||
|
||||
const interval_ms = this.options.interval_days * 24 * 3600 * 1000
|
||||
|
||||
const range = [new Date(last_move_date - interval_ms), last_move_date]
|
||||
console.log(range)
|
||||
this.selected_movements = data.movements.filter((movement) => movement.date > range[0] && movement.date <= range[1]);
|
||||
console.log(`Draw ${this.selected_movements.length} movements, will take ${this.selected_movements.length / this.options.items_per_tick * this.options.tick_interval / 1000} seconds`)
|
||||
|
||||
|
||||
this.allMovements = data.movements;
|
||||
|
||||
this.motions = viz_data.drawn_motions
|
||||
// TODO: group by hour and have it last nr-of-hours * interval
|
||||
// TODO: then, add a timeline
|
||||
// TODO: then, add an overlay with relevant events, e.g.
|
||||
|
@ -86,24 +34,26 @@ export class All extends Scene {
|
|||
// TODO: .. and any other filter
|
||||
// TODO: then finish with a summary per location
|
||||
// TODO: .. (or add these in small prints as counters under the location names)
|
||||
this.interval = setInterval(this.tick.bind(this), this.options.tick_interval);
|
||||
this.interval = setInterval(this.tick.bind(this), 500);
|
||||
|
||||
// clear the motions when kicking off:
|
||||
this.viz_data.drawn_motions.update(items => []);
|
||||
this.motions.update(items => []);
|
||||
}
|
||||
|
||||
tick() {
|
||||
const n = this.options.items_per_tick
|
||||
if (this.step >= this.selected_movements.length) {
|
||||
const n = 10
|
||||
if (this.step >= this.allMovements.length) {
|
||||
console.log('this', 'done')
|
||||
// todo: ease out all entries
|
||||
this.nextScene()
|
||||
return;
|
||||
}
|
||||
let movements: Movement[] = this.selected_movements.slice(this.step, this.step + n);
|
||||
let movements: Movement[] = this.allMovements.slice(this.step, this.step + n);
|
||||
|
||||
// duration 5000 + Math.random() * 10000
|
||||
this.drawMovements(movements, 3500)
|
||||
let motions: Motion[] = movements.map((m) => ({ duration: 5000, movement: m }));
|
||||
|
||||
this.motions.update(items => ([...items, ...motions]))
|
||||
this.step += n;
|
||||
}
|
||||
|
||||
|
@ -118,56 +68,40 @@ export class All extends Scene {
|
|||
export class Timeline extends Scene {
|
||||
movements: Movement[]
|
||||
item: Item
|
||||
motions: Writable<Motion[]>
|
||||
interval: number
|
||||
step: number = 0
|
||||
nextScene: CallableFunction
|
||||
locationCounts = new Map<Location, { in: number, out: number }>()
|
||||
|
||||
constructor(data: Data, viz_data: VizData, nextScene: CallableFunction) {
|
||||
super(data, viz_data, nextScene);
|
||||
super()
|
||||
|
||||
// clear canvas
|
||||
// this.viz_data.drawn_motions.update(items => [])
|
||||
this.nextScene = nextScene
|
||||
|
||||
// start setInterval to trigger additions per 100 or so to drawn_movements (rendered on map)
|
||||
// when done, trigger parent.done()
|
||||
const min_occurences = 3;
|
||||
const pick = this.pickMovements(min_occurences);
|
||||
if( pick === null) {
|
||||
console.error(`No items which occur at least ${min_occurences} times`)
|
||||
setTimeout(this.nextScene.bind(this), 1000);
|
||||
|
||||
return;
|
||||
}
|
||||
const [ item, movements ]= pick;
|
||||
console.log('s',data.occurences)
|
||||
const [ item, movements ]= this.pickMovements(data.occurences);
|
||||
this.item = item
|
||||
this.viz_data.current_item.set(item);
|
||||
this.movements = movements
|
||||
console.log('start timeline', item, movements)
|
||||
console.log(item, movements)
|
||||
|
||||
this.motions = viz_data.drawn_motions
|
||||
this.motions.update(items => [])
|
||||
|
||||
this.interval = setInterval(this.tick.bind(this), 3000);
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Pick a movement
|
||||
* @param min_occurences number The minimum number of occurences an item should have
|
||||
* @returns [Item, Movement[]]
|
||||
*/
|
||||
pickMovements(min_occurences: number) {
|
||||
pickMovements(occurences: Map<Item, Movement[]>) {
|
||||
|
||||
const item_movements = [...this.data.occurences]
|
||||
const item_movements = [...occurences]
|
||||
// TODO: variable lenght, prefer with most steps
|
||||
.filter(([item, movements]) => movements.length >= min_occurences)
|
||||
.filter(([item, movements]) => movements.length > 1)
|
||||
|
||||
if(!item_movements.length) {
|
||||
return null
|
||||
}
|
||||
|
||||
const pick = item_movements[Math.floor(Math.random() * item_movements.length)]
|
||||
pick[1].sort((a: Movement, b: Movement) => (a.date - b.date))
|
||||
return pick;
|
||||
return item_movements[Math.floor(Math.random() * item_movements.length)]
|
||||
}
|
||||
|
||||
tick() {
|
||||
|
@ -179,20 +113,13 @@ export class Timeline extends Scene {
|
|||
}
|
||||
|
||||
// duration 5000 + Math.random() * 10000
|
||||
const mov = this.movements[this.step]
|
||||
this.drawMovements([mov], 2000, true)
|
||||
// const motion: Motion = { duration: 2000, movement: mov };
|
||||
const log: Log = { date: mov.date, title: `Transfer to ${mov.target.name}`, description: "" };
|
||||
// console.log(motion, motion.movement.source, motion.movement.target)
|
||||
// this.viz_data.overlay_motions.update(items => ([...items, motion]))
|
||||
this.viz_data.events.update(items => ([...items, log]))
|
||||
const motion: Motion = { duration: 2000, movement: this.movements[this.step] };
|
||||
console.log(motion, motion.movement.source, motion.movement.target)
|
||||
this.motions.update(items => ([...items, motion]))
|
||||
this.step += 1;
|
||||
}
|
||||
|
||||
stop() {
|
||||
this.viz_data.current_item.set(null)
|
||||
this.viz_data.events.set([])
|
||||
this.viz_data.overlay_motions.set([])
|
||||
clearInterval(this.interval)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue