graph: added tooltip
This commit is contained in:
parent
e383d513f8
commit
2a4d79e499
2 changed files with 72 additions and 8 deletions
|
@ -1,11 +1,12 @@
|
||||||
<script type="ts">
|
<script type="ts">
|
||||||
import GraphNode from "./GraphNode.svelte";
|
import GraphNode from "./GraphNode.svelte";
|
||||||
import GraphEdge from "./GraphEdge.svelte";
|
import GraphEdge from "./GraphEdge.svelte";
|
||||||
import { createEventDispatcher, onMount } from "svelte";
|
import { createEventDispatcher, onMount, tick } from "svelte";
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
import type { TasksFile, TaskDescriptor } from "./tasks";
|
import type { TasksFile, TaskDescriptor } from "./tasks";
|
||||||
import { createEdges } from "./tasks";
|
import { createEdges } from "./tasks";
|
||||||
import { taskStatuses } from "./task-status-cache";
|
import { taskStatuses } from "./task-status-cache";
|
||||||
|
import { grabAssignment } from "./ksp-task-grabber";
|
||||||
|
|
||||||
export let tasks: TasksFile;
|
export let tasks: TasksFile;
|
||||||
export let nodeDraggingEnabled: boolean = false;
|
export let nodeDraggingEnabled: boolean = false;
|
||||||
|
@ -14,7 +15,7 @@
|
||||||
export let selection: Set<TaskDescriptor> = new Set();
|
export let selection: Set<TaskDescriptor> = new Set();
|
||||||
export let showCenterMarker: boolean = false;
|
export let showCenterMarker: boolean = false;
|
||||||
|
|
||||||
let hoveredTask: null | string = null;
|
let hoveredTask: null | TaskDescriptor = null;
|
||||||
|
|
||||||
// Svelte automatically fills these with a reference
|
// Svelte automatically fills these with a reference
|
||||||
let container: HTMLElement;
|
let container: HTMLElement;
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
let innerSvgGroup: SVGElement;
|
let innerSvgGroup: SVGElement;
|
||||||
let selectionRectangle: [[number, number], [number, number]] | null = null;
|
let selectionRectangle: [[number, number], [number, number]] | null = null;
|
||||||
let dragInProgress: boolean = false;
|
let dragInProgress: boolean = false;
|
||||||
|
let tooltipTextElement: SVGTextElement;
|
||||||
|
|
||||||
$: nodes = tasks.tasks;
|
$: nodes = tasks.tasks;
|
||||||
$: edges = createEdges(nodes);
|
$: edges = createEdges(nodes);
|
||||||
|
@ -49,7 +51,7 @@
|
||||||
function nodeHover(task: TaskDescriptor) {
|
function nodeHover(task: TaskDescriptor) {
|
||||||
function eventHandler(hovering: CustomEvent<boolean>) {
|
function eventHandler(hovering: CustomEvent<boolean>) {
|
||||||
if (hovering.detail) {
|
if (hovering.detail) {
|
||||||
hoveredTask = task.id;
|
hoveredTask = task;
|
||||||
if (!selection.has(task) && !dragInProgress) {
|
if (!selection.has(task) && !dragInProgress) {
|
||||||
selection.clear();
|
selection.clear();
|
||||||
selection.add(task);
|
selection.add(task);
|
||||||
|
@ -57,7 +59,7 @@
|
||||||
}
|
}
|
||||||
eventDispatcher("preSelectTask", task);
|
eventDispatcher("preSelectTask", task);
|
||||||
} else {
|
} else {
|
||||||
if (hoveredTask == task.id) hoveredTask = null;
|
if (hoveredTask?.id == task.id) hoveredTask = null;
|
||||||
eventDispatcher("unPreSelectTask", task);
|
eventDispatcher("unPreSelectTask", task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,6 +188,39 @@
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
setupZoom();
|
setupZoom();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
let tooltipMaxPoints: number | null = null;
|
||||||
|
let tooltipCurrPoints: number | null = null;
|
||||||
|
$: tooltipTextPos = hoveredTask != null ? [(hoveredTask.position ?? [0,0])[0], (hoveredTask.position ?? [0,0])[1] + 40] : [0,0];
|
||||||
|
let tooltipBoxWidth = 0;
|
||||||
|
let tooltipBoxHeight = 0;
|
||||||
|
async function resizeTooltipBox() {
|
||||||
|
await tick();
|
||||||
|
if (tooltipTextElement == null) return;
|
||||||
|
const bbox = tooltipTextElement.getBBox()
|
||||||
|
tooltipBoxWidth = bbox.width + 10 + 10;
|
||||||
|
tooltipBoxHeight = bbox.height + 5 + 5;
|
||||||
|
}
|
||||||
|
$: {
|
||||||
|
if (hoveredTask != null) {
|
||||||
|
const status = $taskStatuses.get(hoveredTask.id);
|
||||||
|
if (status == null) {
|
||||||
|
const id = hoveredTask.id;
|
||||||
|
grabAssignment(hoveredTask.id).then(e => {
|
||||||
|
if (hoveredTask && hoveredTask.id == id)
|
||||||
|
tooltipMaxPoints = e.points;
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
tooltipMaxPoints = status.maxPoints;
|
||||||
|
tooltipCurrPoints = status.points;
|
||||||
|
}
|
||||||
|
resizeTooltipBox();
|
||||||
|
} else {
|
||||||
|
tooltipMaxPoints = null;
|
||||||
|
tooltipCurrPoints = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -212,11 +247,22 @@
|
||||||
z-index: 20;
|
z-index: 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
rect {
|
.selectionRectangle {
|
||||||
fill: transparent;
|
fill: transparent;
|
||||||
stroke-dasharray: 5, 5;
|
stroke-dasharray: 5, 5;
|
||||||
stroke: gainsboro;
|
stroke: gainsboro;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tooltip rect {
|
||||||
|
stroke: #ffb3a2;
|
||||||
|
stroke-width: 2px;
|
||||||
|
fill: #000000bb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tooltip text {
|
||||||
|
/* stroke: white;*/
|
||||||
|
fill: white;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
@ -237,6 +283,7 @@
|
||||||
transform="translate({clientWidth / 2}, {clientHeight / 2})">
|
transform="translate({clientWidth / 2}, {clientHeight / 2})">
|
||||||
{#if selectionRectangle != null}
|
{#if selectionRectangle != null}
|
||||||
<rect
|
<rect
|
||||||
|
class="selectionRectangle"
|
||||||
x={selectionRectangle[0][0]}
|
x={selectionRectangle[0][0]}
|
||||||
y={selectionRectangle[0][1]}
|
y={selectionRectangle[0][1]}
|
||||||
width={selectionRectangle[1][0] - selectionRectangle[0][0]}
|
width={selectionRectangle[1][0] - selectionRectangle[0][0]}
|
||||||
|
@ -274,6 +321,25 @@
|
||||||
status={$taskStatuses.get(task.id)}
|
status={$taskStatuses.get(task.id)}
|
||||||
on:dblclick={nodeDoubleClick(task)} />
|
on:dblclick={nodeDoubleClick(task)} />
|
||||||
{/each}
|
{/each}
|
||||||
|
{#if hoveredTask != null && hoveredTask.type == "open-data" }
|
||||||
|
<g class="tooltip">
|
||||||
|
<rect
|
||||||
|
x={tooltipTextPos[0]}
|
||||||
|
y={tooltipTextPos[1] - 15}
|
||||||
|
width={tooltipBoxWidth}
|
||||||
|
height={tooltipBoxHeight}
|
||||||
|
rx="3">
|
||||||
|
</rect>
|
||||||
|
<text
|
||||||
|
bind:this={tooltipTextElement}
|
||||||
|
x={tooltipTextPos[0] + tooltipBoxWidth / 2}
|
||||||
|
y={tooltipTextPos[1] + 4}
|
||||||
|
text-anchor="middle"
|
||||||
|
alignment-baseline="middle">
|
||||||
|
{hoveredTask.type == 'open-data' ? hoveredTask.taskReference : "text"} | {tooltipCurrPoints ?? '?'} bod{ "ů yyy"[tooltipCurrPoints ?? 0] ?? "ů" } z {tooltipMaxPoints ?? '?'}
|
||||||
|
</text>
|
||||||
|
</g>
|
||||||
|
{/if}
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as d3 from "d3";
|
|
||||||
|
|
||||||
import { createEventDispatcher, onMount } from "svelte";
|
import { createEventDispatcher, onMount } from "svelte";
|
||||||
import type { TaskStatus } from "./ksp-task-grabber";
|
import type { TaskStatus } from "./ksp-task-grabber";
|
||||||
import type { TaskDescriptor } from "./tasks";
|
import type { TaskDescriptor } from "./tasks";
|
||||||
|
|
||||||
export let task: TaskDescriptor;
|
export let task: TaskDescriptor;
|
||||||
export let selected: bool = false;
|
export let selected: boolean = false;
|
||||||
export let status: TaskStatus | undefined = undefined;
|
export let status: TaskStatus | undefined = undefined;
|
||||||
|
|
||||||
let hovering: boolean = false;
|
let hovering: boolean = false;
|
||||||
|
|
Reference in a new issue