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