90 lines
2.7 KiB
TypeScript
90 lines
2.7 KiB
TypeScript
|
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
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
// An event to trigger drawing an Edge
|
||
|
export type Motion = {
|
||
|
duration: number,
|
||
|
movement: Movement,
|
||
|
}
|
||
|
|
||
|
export type Event = {
|
||
|
date: Date,
|
||
|
title: String,
|
||
|
description: String
|
||
|
}
|
||
|
|
||
|
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 = 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
|
||
|
// 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}`;
|
||
|
}
|