graf: sila tahnouci nody dolu, pokud maji hodne zavislosti
This commit is contained in:
		
							parent
							
								
									b926dd3526
								
							
						
					
					
						commit
						102c0677ed
					
				
					 4 changed files with 59 additions and 4 deletions
				
			
		|  | @ -7,7 +7,7 @@ | ||||||
| 
 | 
 | ||||||
|   export let tasks: TasksFile; |   export let tasks: TasksFile; | ||||||
| 
 | 
 | ||||||
|   let repulsionForce: number = -600; |   let repulsionForce: number = -1000; | ||||||
|   let clicked: string[] = []; |   let clicked: string[] = []; | ||||||
|   let graph: Graph; |   let graph: Graph; | ||||||
|   let currentTask: TaskDescriptor | null = null; |   let currentTask: TaskDescriptor | null = null; | ||||||
|  |  | ||||||
|  | @ -5,10 +5,11 @@ | ||||||
|   import * as d3 from "d3"; |   import * as d3 from "d3"; | ||||||
|   import type { TasksFile, TaskDescriptor } from "./task-loader"; |   import type { TasksFile, TaskDescriptor } from "./task-loader"; | ||||||
|   import { createNodesAndEdges } from "./graph-types"; |   import { createNodesAndEdges } from "./graph-types"; | ||||||
|  |   import { taskForce } from "./task-force"; | ||||||
| 
 | 
 | ||||||
|   export let tasks: TasksFile; |   export let tasks: TasksFile; | ||||||
|   let hoveredTask: null | string = null; |   let hoveredTask: null | string = null; | ||||||
|   export let repulsionForce: number = -600; |   export let repulsionForce: number = -1000; | ||||||
| 
 | 
 | ||||||
|   // Svelte automatically fills these with a reference |   // Svelte automatically fills these with a reference | ||||||
|   let container: HTMLElement; |   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("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("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("tick", ticked) | ||||||
|       .on("end", ticked); |       .on("end", ticked); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -10,5 +10,8 @@ | ||||||
|     $: y2 = edge === undefined || edge.target === undefined || edge.target.y === undefined ? 0 : edge.target.y; |     $: y2 = edge === undefined || edge.target === undefined || edge.target.y === undefined ? 0 : edge.target.y; | ||||||
| </script> | </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" /> | ||||||
|    |    | ||||||
							
								
								
									
										50
									
								
								frontend/src/task-force.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								frontend/src/task-force.ts
									
									
									
									
									
										Normal 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; | ||||||
|  | } | ||||||
		Reference in a new issue