graph: zooming and dragging, changed default repulsion force
This commit is contained in:
parent
2006216a99
commit
b1dcf45db6
4 changed files with 44 additions and 20 deletions
|
@ -8,10 +8,16 @@
|
||||||
|
|
||||||
let selectedTask: string | null = null;
|
let selectedTask: string | null = null;
|
||||||
let clickedTask: string | null = null;
|
let clickedTask: string | null = null;
|
||||||
|
let repulsionForce: number = -600;
|
||||||
let clicked: string[] = [];
|
let clicked: string[] = [];
|
||||||
|
|
||||||
function clickTask(e: CustomEvent<TaskDescriptor>) {
|
function clickTask(e: CustomEvent<TaskDescriptor>) {
|
||||||
|
// sanity check
|
||||||
|
if (selectedTask == null) {
|
||||||
|
alert("tohle je divny event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// ukladani seznamu poslednich kliknuti
|
// ukladani seznamu poslednich kliknuti
|
||||||
clicked.push(selectedTask);
|
clicked.push(selectedTask);
|
||||||
if (clicked.length > 3)
|
if (clicked.length > 3)
|
||||||
|
@ -41,6 +47,9 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
tasks = tasks;
|
tasks = tasks;
|
||||||
|
|
||||||
|
// run simulation
|
||||||
|
toggleDivnaPromena();
|
||||||
} else {
|
} else {
|
||||||
alert("Nope, prvni musis nekam klikat...");
|
alert("Nope, prvni musis nekam klikat...");
|
||||||
}
|
}
|
||||||
|
@ -48,7 +57,7 @@
|
||||||
|
|
||||||
let hovnoDivnaPromenaKteraJeFaktFuj = true;
|
let hovnoDivnaPromenaKteraJeFaktFuj = true;
|
||||||
function toggleDivnaPromena() {
|
function toggleDivnaPromena() {
|
||||||
hovnoDivnaPromenaKteraJeFaktFuj = ! hovnoDivnaPromenaKteraJeFaktFuj;
|
hovnoDivnaPromenaKteraJeFaktFuj = !hovnoDivnaPromenaKteraJeFaktFuj;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -62,7 +71,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
height: 100vh;
|
height: 99vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +115,12 @@
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="lastClicked">Last clicked: <b>{clicked.join(' | ')}</b></div>
|
<div class="lastClicked">Last clicked: <b>{clicked.join(' | ')}</b></div>
|
||||||
<div class="graph">
|
<div class="graph">
|
||||||
<Graph {tasks} bind:selectedTask on:selectTask={clickTask} runSimulationWeirdHack={hovnoDivnaPromenaKteraJeFaktFuj} />
|
<Graph
|
||||||
|
{tasks}
|
||||||
|
{repulsionForce}
|
||||||
|
bind:selectedTask
|
||||||
|
on:selectTask={clickTask}
|
||||||
|
runSimulationWeirdHack={hovnoDivnaPromenaKteraJeFaktFuj} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
|
@ -115,12 +129,14 @@
|
||||||
<div>
|
<div>
|
||||||
<button on:click={addEdge}>Pridat hranu - posledni vyzaduje predposledni</button>
|
<button on:click={addEdge}>Pridat hranu - posledni vyzaduje predposledni</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div><button on:click={toggleDivnaPromena}>Spustit simulaci</button></div>
|
||||||
<div>
|
<div>
|
||||||
<button on:click={toggleDivnaPromena}>Spustit simulaci</button>
|
Repulsion force: <input type="number" bind:value={repulsionForce} name="repulsionForceInput" max="1000" min="-10000" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="taskDetails">
|
<div class="taskDetails">
|
||||||
{#if currentTask != null}
|
{#if currentTask != null}
|
||||||
|
start
|
||||||
<h3>{currentTask}</h3>
|
<h3>{currentTask}</h3>
|
||||||
<span>{taskMap.get(currentTask).comment}</span>
|
<span>{taskMap.get(currentTask).comment}</span>
|
||||||
<ul>
|
<ul>
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
export let tasks: TasksFile;
|
export let tasks: TasksFile;
|
||||||
export let selectedTask: null | string = null;
|
export let selectedTask: null | string = null;
|
||||||
|
export let repulsionForce: number = -600;
|
||||||
|
|
||||||
$: nodes = tasks.tasks;
|
$: nodes = tasks.tasks;
|
||||||
$: edges = createLinksFromTaskMap(tasks);
|
$: edges = createLinksFromTaskMap(tasks);
|
||||||
|
@ -45,7 +46,7 @@
|
||||||
}) // This provide the id of a node
|
}) // This provide the id of a node
|
||||||
.links(edges) // and this the list of links
|
.links(edges) // and this the list of links
|
||||||
)
|
)
|
||||||
.force("charge", d3.forceManyBody().strength(-400)) // 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()) // attracts elements to the zero Y coord
|
||||||
.on("tick", ticked)
|
.on("tick", ticked)
|
||||||
|
@ -61,19 +62,29 @@
|
||||||
// run on create
|
// run on create
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
// set the dimensions and margins of the graph
|
// set the dimensions and margins of the graph
|
||||||
var margin = { top: 10, right: 30, bottom: 30, left: 40 },
|
const width = container.clientWidth;
|
||||||
width = container.clientWidth - margin.left - margin.right,
|
const height = container.clientHeight;
|
||||||
height = container.clientHeight - margin.top - margin.bottom;
|
|
||||||
|
|
||||||
// resize the svg object
|
// resize the svg object
|
||||||
var svg = d3
|
var svg = d3
|
||||||
.select(container)
|
.select(container)
|
||||||
.select("svg")
|
.select("svg")
|
||||||
.attr("width", width + margin.left + margin.right)
|
.attr("width", width)
|
||||||
.attr("height", height + margin.top + margin.bottom)
|
.attr("height", height)
|
||||||
.attr("viewBox", [-width / 2, -height / 2, width, height])
|
.attr("viewBox", [-width / 2, -height / 2, width, height])
|
||||||
.select("g")
|
.select("g");
|
||||||
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
|
|
||||||
|
function zoomed(e) {
|
||||||
|
let { transform } = e;
|
||||||
|
svg.attr("transform", transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
d3.select(container).call(
|
||||||
|
d3
|
||||||
|
.zoom()
|
||||||
|
.scaleExtent([0.1, 2])
|
||||||
|
.on("zoom", zoomed)
|
||||||
|
);
|
||||||
|
|
||||||
runSimulation();
|
runSimulation();
|
||||||
});
|
});
|
||||||
|
@ -85,7 +96,6 @@
|
||||||
runSimulation();
|
runSimulation();
|
||||||
}
|
}
|
||||||
// now it's safe to stop vomitting 🤮
|
// now it's safe to stop vomitting 🤮
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -104,6 +114,7 @@
|
||||||
{#each nodes as task}
|
{#each nodes as task}
|
||||||
<GraphNode
|
<GraphNode
|
||||||
{task}
|
{task}
|
||||||
|
on:taskClick
|
||||||
on:click={nodeClick(task)}
|
on:click={nodeClick(task)}
|
||||||
on:hoveringChange={nodeHover(task)} />
|
on:hoveringChange={nodeHover(task)} />
|
||||||
{/each}
|
{/each}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { SimulationLinkDatum } from "d3";
|
import type { SimulationLinkDatum } from "d3";
|
||||||
|
|
||||||
import { onMount } from "svelte";
|
|
||||||
|
|
||||||
import type { TaskDescriptor } from "./task-loader";
|
import type { TaskDescriptor } from "./task-loader";
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { createEventDispatcher, onMount } from "svelte";
|
import { createEventDispatcher, onMount } from "svelte";
|
||||||
|
|
||||||
import type { TaskDescriptor } from "./task-loader";
|
import type { TaskDescriptor } from "./task-loader";
|
||||||
|
|
||||||
export let task: TaskDescriptor;
|
export let task: TaskDescriptor;
|
||||||
let hovering: boolean = false;
|
let hovering: boolean = false;
|
||||||
let text_element: SVGTextElement;
|
let text_element: SVGTextElement;
|
||||||
|
|
||||||
const eventDispatcher = createEventDispatcher()
|
|
||||||
|
|
||||||
$: cx = task === undefined || task.x === undefined ? 0 : task.x;
|
$: cx = task === undefined || task.x === undefined ? 0 : task.x;
|
||||||
$: cy = task === undefined || task.y === undefined ? 0 : task.y;
|
$: cy = task === undefined || task.y === undefined ? 0 : task.y;
|
||||||
|
|
||||||
|
const eventDispatcher = createEventDispatcher()
|
||||||
function enter() {
|
function enter() {
|
||||||
hovering = true;
|
hovering = true;
|
||||||
eventDispatcher("hoveringChange", hovering)
|
eventDispatcher("hoveringChange", hovering)
|
||||||
|
@ -26,6 +24,7 @@
|
||||||
eventDispatcher("click", e)
|
eventDispatcher("click", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// automatically size the bubbles to fit the text
|
||||||
let ellipse_rx = 20;
|
let ellipse_rx = 20;
|
||||||
let ellipse_ry = 20;
|
let ellipse_ry = 20;
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
|
|
Reference in a new issue