graf: sila tahnouci nody dolu, pokud maji hodne zavislosti

This commit is contained in:
Vašek Šraier 2020-09-28 23:25:19 +02:00
parent b926dd3526
commit 102c0677ed
4 changed files with 59 additions and 4 deletions

View file

@ -7,7 +7,7 @@
export let tasks: TasksFile;
let repulsionForce: number = -600;
let repulsionForce: number = -1000;
let clicked: string[] = [];
let graph: Graph;
let currentTask: TaskDescriptor | null = null;

View file

@ -5,10 +5,11 @@
import * as d3 from "d3";
import type { TasksFile, TaskDescriptor } from "./task-loader";
import { createNodesAndEdges } from "./graph-types";
import { taskForce } from "./task-force";
export let tasks: TasksFile;
let hoveredTask: null | string = null;
export let repulsionForce: number = -600;
export let repulsionForce: number = -1000;
// Svelte automatically fills these with a reference
let container: HTMLElement;
@ -61,7 +62,8 @@
)
.force("charge", d3.forceManyBody().strength(repulsionForce)) // This adds repulsion between nodes. Play with the -400 for the repulsion strength
.force("x", d3.forceX()) // attracts elements to the zero X coord
.force("y", d3.forceY()) // attracts elements to the zero Y coord
.force("y", d3.forceY().strength(0.5)) // attracts elements to the zero Y coord
.force("dependencies", taskForce())
.on("tick", ticked)
.on("end", ticked);

View file

@ -10,5 +10,8 @@
$: y2 = edge === undefined || edge.target === undefined || edge.target.y === undefined ? 0 : edge.target.y;
</script>
<line {x1} {x2} {y1} {y2} style="stroke: #aaa" />
<line x1={x1+10} y1={y1} {x2} {y2} style="stroke: #aaa" />
<line x1={x1} y1={y1+10} {x2} {y2} style="stroke: #aaa" />
<line x1={x1-10} y1={y1} {x2} {y2} style="stroke: #aaa" />
<line x1={x1} y1={y1-10} {x2} {y2} style="stroke: #aaa" />

View file

@ -0,0 +1,50 @@
import type { TaskId } from "./graph-types";
/* copied from graph-types.ts */
function toMapById(nodes: TaskId[]): Map<string, TaskId> {
let nodeMap = new Map<string, TaskId>();
for (let task of nodes) {
if (task.id in nodeMap)
throw 'duplicate IDs';
nodeMap.set(task.id, task);
}
return nodeMap;
}
export function taskForce(): d3.Force<TaskId, undefined> {
let myNodes: TaskId[] | null = null;
let deps: Map<string, number> = new Map();
let idMap: Map<string, TaskId> = new Map();
function getNumberOfDeps(task: TaskId): number {
if (deps.has(task.id)) return deps.get(task.id)!;
if (task.task.requires.length == 0) return 0;
let res = 0;
for (let r of task.task.requires) {
res += getNumberOfDeps(idMap.get(r)!) + 1;
}
deps.set(task.id, res);
return res;
}
let force: d3.Force<TaskId, undefined> = function(alpha: number) {
if (myNodes == null) throw 'nodes not initialized';
for (let task of myNodes) {
if (task.vy == null) {
task.vy = 0
}
task.vy += getNumberOfDeps(task) * 25 * alpha;
}
}
force.initialize = function(nodes: TaskId[]) {
myNodes = nodes;
idMap = toMapById(myNodes);
}
return force;
}