ub-movements/src/lib/types.ts

110 lines
3.3 KiB
TypeScript
Raw Normal View History

import type { Writable } from "svelte/store";
export type Location = Object;
// disambiguated (physical or online) library object
export type Item = {
title: String,
MMS: String,
Barcode: String, // String because of preceding 0
Publisher: String,
_original: Object
}
// A movement of the object (Request in Alma Analytics)
export type Movement = {
nr: number, // unique identifier in the set
source: Location,
target: Location,
item: Item,
_original: Object
// also contains additional request data (see requests.csv)
d: String, // the svg path
date: Date,
};
export type Occurences = Map<Item, Movement[]>
export interface Data {
locations: Map<String, Location>,
items: Map<string, Item>,
movements: Movement[],
occurences: Occurences
}
// An event to trigger drawing an Edge
export type Motion = {
duration: number,
movement: Movement,
}
export type Log = {
date: Date,
title: String,
description: String
}
// Type used by the scenes with all reactive Writables for drawable objects
export type VizData = {
drawn_motions: Writable<Motion[]>,
overlay_motions: Writable<Motion[]>,
events: Writable<Log[]>,
current_item: Writable<Item | null>
}
export function get_path_d(movement: Movement) {
const m = movement;
// console.log(m)
let sourceX, targetX, midX, dx, dy, angle;
// This mess makes the arrows exactly perfect.
// thanks to http://bl.ocks.org/curran/9b73eb564c1c8a3d8f3ab207de364bf4
if (m.source.x < m.target.x) {
sourceX = m.source.x;
targetX = m.target.x;
} else if (m.target.x < m.source.x) {
targetX = m.target.x;
sourceX = m.source.x;
} else if (m.target.isCircle) {
targetX = sourceX = m.target.x;
} else if (m.source.isCircle) {
targetX = sourceX = m.source.x;
} else {
midX = (m.source.x + m.target.x) / 2;
if (midX > m.target.x) {
midX = m.target.x;
} else if (midX > m.source.x) {
midX = m.source.x;
} else if (midX < m.target.x) {
midX = m.target.x;
} else if (midX < m.source.x) {
midX = m.source.x;
}
targetX = sourceX = midX;
}
dx = targetX - sourceX;
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);
// Compute the line endpoint such that the arrow
// it not in the center, but rather slightly out of it
// use a small ofset for the Movemente to compensate roughly for the curve
let m_sourceX = sourceX + Math.sin(angle + 0.5) * srcSize;
let m_targetX = targetX - Math.sin(angle - 0.5) * tgtSize;
let m_sourceY = m.source.y + Math.cos(angle + 0.5) * srcSize;
let m_targetY = m.target.y - Math.cos(angle - 0.5) * tgtSize;
// find radius of arc based on distance between points
// add a jitter to spread out the lines when links are stacked
const dr = Math.sqrt(dx * dx + dy * dy) * (0.7 + Math.random() * 0.5);
// "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y
return `M ${m_sourceX},${m_sourceY} A ${dr},${dr} 0 0,1 ${m_targetX},${m_targetY}`;
}