graf: nepouzivaji se primo data z tasks.json pro renderovani
This commit is contained in:
		
							parent
							
								
									7668b12abb
								
							
						
					
					
						commit
						2494eab6e7
					
				
					 6 changed files with 85 additions and 68 deletions
				
			
		|  | @ -1,41 +1,27 @@ | |||
| <script type="ts"> | ||||
|   import Graph from "./Graph.svelte"; | ||||
|   import { nonNull } from "./helpers"; | ||||
|   import { grabAssignment } from "./ksp-task-grabber"; | ||||
|   import type { TaskDescriptor, TasksFile } from "./task-loader"; | ||||
|   import { saveTasks, createTaskMap, getCategories } from "./task-loader"; | ||||
|   import { saveTasks, getCategories } from "./task-loader"; | ||||
|   import TaskDisplay from "./TaskDisplay.svelte"; | ||||
| 
 | ||||
|   export let tasks: TasksFile; | ||||
| 
 | ||||
|   let selectedTask: string | null = null; | ||||
|   let clickedTask: string | null = null; | ||||
|   let repulsionForce: number = -600; | ||||
|   let clicked: string[] = []; | ||||
|   let graph: Graph; | ||||
|   let currentTask: TaskDescriptor | null = null; | ||||
| 
 | ||||
|   function clickTask(e: CustomEvent<TaskDescriptor>) { | ||||
|     // sanity check | ||||
|     if (selectedTask == null) { | ||||
|       alert("tohle je divny event"); | ||||
|       return; | ||||
|     } | ||||
| 
 | ||||
|     // ukladani seznamu poslednich kliknuti | ||||
|     clicked.push(selectedTask); | ||||
|     clicked = [...clicked, e.detail.id]; | ||||
|     if (clicked.length > 3) | ||||
|       clicked = clicked.slice(clicked.length - 3, clicked.length); | ||||
|     clicked = clicked; | ||||
| 
 | ||||
|     // trackovani, kam se naposledy kliknulo | ||||
|     if (clickedTask == selectedTask) { | ||||
|       clickedTask = null; | ||||
|     } else { | ||||
|       clickedTask = selectedTask; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   $: taskMap = createTaskMap(tasks); | ||||
|   $: currentTask = clickedTask != null ? clickedTask : selectedTask; | ||||
|   function startHovering(e: CustomEvent<TaskDescriptor>) { | ||||
|     currentTask = e.detail; | ||||
|   } | ||||
| 
 | ||||
|   function addEdge() { | ||||
|     if (clicked.length > 1) { | ||||
|  | @ -44,21 +30,15 @@ | |||
| 
 | ||||
|       tasks.tasks.forEach((t) => { | ||||
|         if (t.id == first) { | ||||
|           t.requires.push(second); | ||||
|           t = t; | ||||
|           t.requires = [...t.requires, second]; | ||||
|         } | ||||
|       }); | ||||
|       tasks = tasks; | ||||
| 
 | ||||
|       // run simulation | ||||
|       graph.runSimulation() | ||||
|     } else { | ||||
|       alert("Nope, prvni musis nekam klikat..."); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   let graph: Graph | ||||
| 
 | ||||
|   async function saveCurrentState() { | ||||
|     await saveTasks(tasks); | ||||
|   } | ||||
|  | @ -122,8 +102,8 @@ | |||
|       <Graph | ||||
|         {tasks} | ||||
|         {repulsionForce} | ||||
|         bind:selectedTask | ||||
|         on:selectTask={clickTask} | ||||
|         on:preSelectTask={startHovering} | ||||
|         bind:this={graph} /> | ||||
|     </div> | ||||
|   </div> | ||||
|  | @ -133,7 +113,7 @@ | |||
|       <div> | ||||
|         <button on:click={addEdge}>Pridat hranu - posledni vyzaduje predposledni</button> | ||||
|       </div> | ||||
|       <div><button on:click={toggleDivnaPromena}>Spustit simulaci</button></div> | ||||
|       <div><button on:click={graph.runSimulation}>Spustit simulaci</button></div> | ||||
|       <div> | ||||
|         Repulsion force: <input type="number" bind:value={repulsionForce} name="repulsionForceInput" max="1000" min="-10000" /> | ||||
|       </div> | ||||
|  | @ -143,14 +123,14 @@ | |||
|     </div> | ||||
|     <div class="taskDetails"> | ||||
|       {#if currentTask != null} | ||||
|         <h3>{currentTask}</h3> | ||||
|         <span>{nonNull(taskMap.get(currentTask)).comment}</span> | ||||
|         <h3>{currentTask.id}</h3> | ||||
|         <span>{nonNull(currentTask).comment}</span> | ||||
|         <ul> | ||||
|           {#each getCategories(tasks, currentTask) as cat} | ||||
|           {#each getCategories(tasks, currentTask.id) as cat} | ||||
|             <li>{cat}</li> | ||||
|           {/each} | ||||
|         </ul> | ||||
|         <TaskDisplay taskId={currentTask} /> | ||||
|         <TaskDisplay taskId={currentTask.id} /> | ||||
|       {:else} | ||||
|         <h3>Nothing selected...</h3> | ||||
|       {/if} | ||||
|  |  | |||
|  | @ -3,8 +3,8 @@ | |||
|   import GraphEdge from "./GraphEdge.svelte"; | ||||
|   import { createEventDispatcher, onMount } from "svelte"; | ||||
|   import * as d3 from "d3"; | ||||
|   import { createLinksFromTaskMap } from "./task-loader"; | ||||
|   import type { TasksFile, TaskDescriptor } from "./task-loader"; | ||||
|   import { createNodesAndEdges } from "./graph-types"; | ||||
| 
 | ||||
|   export let tasks: TasksFile; | ||||
|   let hoveredTask: null | string = null; | ||||
|  | @ -16,8 +16,17 @@ | |||
|   let clientWidth: number; | ||||
|   let svgElement: SVGElement; | ||||
| 
 | ||||
|   $: nodes = tasks.tasks; | ||||
|   $: edges = createLinksFromTaskMap(tasks); | ||||
|   // this prevents svelte from updating nodes and edges | ||||
|   // when we update nodes and edges | ||||
|   let [nodes, edges] = createNodesAndEdges(tasks); | ||||
|   function hack() { | ||||
|     [nodes, edges] = createNodesAndEdges(tasks); | ||||
|     runSimulation(); | ||||
|   } | ||||
|   $: { | ||||
|     tasks; | ||||
|     hack(); | ||||
|   } | ||||
| 
 | ||||
|   const eventDispatcher = createEventDispatcher(); | ||||
| 
 | ||||
|  | @ -32,9 +41,8 @@ | |||
|       hoveredTask = task.id; | ||||
|       eventDispatcher("preSelectTask", task); | ||||
|     } else { | ||||
|       if (hoveredTask == task.id) | ||||
|         hoveredTask = null; | ||||
|         eventDispatcher("unPreSelectTask", task); | ||||
|       if (hoveredTask == task.id) hoveredTask = null; | ||||
|       eventDispatcher("unPreSelectTask", task); | ||||
|     } | ||||
|   }; | ||||
| 
 | ||||
|  | @ -83,6 +91,8 @@ | |||
|     } | ||||
|     let zoomer = d3.zoom().scaleExtent([0.1, 2]).on("zoom", zoomed); | ||||
|     d3.select(container).call(zoomer); | ||||
| 
 | ||||
|     runSimulation(); | ||||
|   }); | ||||
| </script> | ||||
| 
 | ||||
|  | @ -93,6 +103,8 @@ | |||
|   } | ||||
| </style> | ||||
| 
 | ||||
| {@debug tasks} | ||||
| 
 | ||||
| <div bind:this={container} bind:clientHeight bind:clientWidth> | ||||
|   <svg bind:this={svgElement}> | ||||
|     <g> | ||||
|  | @ -103,8 +115,8 @@ | |||
|         <GraphNode | ||||
|           {task} | ||||
|           on:taskClick | ||||
|           on:click={nodeClick(task)} | ||||
|           on:hoveringChange={nodeHover(task)} /> | ||||
|           on:click={nodeClick(task.task)} | ||||
|           on:hoveringChange={nodeHover(task.task)} /> | ||||
|       {/each} | ||||
|     </g> | ||||
|   </svg> | ||||
|  |  | |||
|  | @ -1,9 +1,8 @@ | |||
| <script lang="ts"> | ||||
|     import type { SimulationLinkDatum } from "d3"; | ||||
|     import type { TaskId } from "./graph-types"; | ||||
|    | ||||
|     import type { TaskDescriptor } from "./task-loader"; | ||||
|    | ||||
|     export let edge: SimulationLinkDatum<TaskDescriptor>; | ||||
|     export let edge: SimulationLinkDatum<TaskId>; | ||||
|    | ||||
|     $: x1 = edge === undefined || edge.source === undefined || edge.source.x === undefined ? 0 : edge.source.x; | ||||
|     $: y1 = edge === undefined || edge.source === undefined || edge.source.y === undefined ? 0 : edge.source.y; | ||||
|  |  | |||
|  | @ -1,8 +1,9 @@ | |||
| <script lang="ts"> | ||||
|   import { createEventDispatcher, onMount } from "svelte"; | ||||
|   import type { TaskDescriptor } from "./task-loader"; | ||||
|   import type { TaskId } from "./graph-types"; | ||||
| 
 | ||||
|   export let task: TaskDescriptor; | ||||
| 
 | ||||
|   export let task: TaskId; | ||||
|   let hovering: boolean = false; | ||||
|   let text_element: SVGTextElement; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										45
									
								
								frontend/src/graph-types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								frontend/src/graph-types.ts
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| import type { SimulationLinkDatum, SimulationNodeDatum } from "d3"; | ||||
| import type { TaskDescriptor, TasksFile } from "./task-loader"; | ||||
| import { createTaskMap } from "./task-loader"; | ||||
| 
 | ||||
| 
 | ||||
| export type TaskId = { | ||||
|     id: string; | ||||
|     task: TaskDescriptor; | ||||
| } & SimulationNodeDatum; | ||||
| 
 | ||||
| function createNodes(tasks: TasksFile, old?: TaskId[]): TaskId[] { | ||||
|     return tasks.tasks.map((t) => { | ||||
|         return { id: t.id, task: t }; | ||||
|     }); | ||||
| } | ||||
| 
 | ||||
| export function createNodesAndEdges(tasks: TasksFile, oldNodes?, oldEdges?): [TaskId[], SimulationLinkDatum<TaskId>[]] { | ||||
|     let nodes = createNodes(tasks, oldNodes); | ||||
| 
 | ||||
|     // create mapping from ID to node
 | ||||
|     let nodeMap = new Map<string, TaskId>(); | ||||
|     for (let task of nodes) { | ||||
|         if (task.id in nodeMap) throw 'duplicate IDs'; | ||||
|         nodeMap.set(task.id, task); | ||||
|     } | ||||
| 
 | ||||
|     let links: SimulationLinkDatum<TaskId>[] = []; | ||||
|     for (const task of tasks.tasks) { | ||||
|         const src = nodeMap.get(task.id)!; | ||||
|         for (const id of task.requires) { | ||||
|             const t = nodeMap.get(id); | ||||
| 
 | ||||
|             if (t === undefined) throw `missing task with id ${id}`; | ||||
| 
 | ||||
|             const l: SimulationLinkDatum<TaskId> = | ||||
|             { | ||||
|                 source: src, | ||||
|                 target: t | ||||
|             }; | ||||
|             links.push(l); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return [nodes, links];     | ||||
| } | ||||
|  | @ -4,8 +4,7 @@ export type TaskDescriptor = { | |||
|     id: string | ||||
|     requires: string[] | ||||
|     comment?: string | ||||
| } & SimulationNodeDatum | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| export type TasksFile = { | ||||
|     tasks: TaskDescriptor[] | ||||
|  | @ -44,25 +43,6 @@ export function createTaskMap(tasks: TasksFile): TaskMap { | |||
|     return m; | ||||
| } | ||||
| 
 | ||||
| export function createLinksFromTaskMap(tasks: TasksFile): SimulationLinkDatum<TaskDescriptor>[] { | ||||
|     let links: SimulationLinkDatum<TaskDescriptor>[] = []; | ||||
| 
 | ||||
|     const taskMap = createTaskMap(tasks); | ||||
| 
 | ||||
|     for (const task of tasks.tasks) { | ||||
|         for (const id of task.requires) { | ||||
|             const t = taskMap.get(id); | ||||
| 
 | ||||
|             if (t === undefined) throw `missing task with id ${id}`; | ||||
| 
 | ||||
|             const l: SimulationLinkDatum<TaskDescriptor> = { source: t, target: task }; | ||||
|             links.push(l); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return links; | ||||
| } | ||||
| 
 | ||||
| export function getCategories(tasks: TasksFile, taskId: string): string[] { | ||||
|     let res: string[] = []; | ||||
|     for (let [cat, ids] of Object.entries(tasks.clusters)) { | ||||
|  |  | |||
		Reference in a new issue