dash14 / v-network-graph

An interactive network graph visualization component for Vue 3

Home Page:https://dash14.github.io/v-network-graph/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

confirm node/edge deselect after container click

klipdassie opened this issue · comments

Hey @dash14,

Thank you for creating and maintaining this great component!

Is there a way to prevent deselection of a node/edge after a container click? and use a confirm dialog for example.
I experimented a bit with the 'node:select' and 'view:click' events but I could not find a solution. Hope you can help me out.

Thanks in advance.

Hi @klipdassie,

Thank you for using v-network-graph!

Is there a way to prevent deselection of a node/edge after a container click? and use a confirm dialog for example.

There is no direct functionality, but it may be controlled using the selected-nodes prop.

Two examples are shown below.

In the first example, when the node selection state changes and the number of nodes selected is less than one, the node before the change is forcibly reselected.

<script setup lang="ts">
import { defineConfigs } from "v-network-graph";
import { ref, watch } from "vue"
import data from "./data"

const configs = defineConfigs({
  node: {
    selectable: true
  },
})

const selectedNodes = ref<string[]>(["node1"])

watch(selectedNodes, (value, oldValue) => {
  if (value.length === 0 && oldValue.length > 0) {
    selectedNodes.value = oldValue
  }
})

</script>

<template>
  <v-network-graph
    v-model:selected-nodes="selectedNodes"
    :nodes="data.nodes"
    :edges="data.edges"
    :layouts="data.layouts"
    :configs="configs"
  />
</template>
// data.ts
import { Nodes, Edges, Layouts } from "v-network-graph"

const nodes: Nodes = {
  node1: { name: "Node 1" },
  node2: { name: "Node 2" },
  node3: { name: "Node 3" },
  node4: { name: "Node 4" },
}

const edges: Edges = {
  edge1: { source: "node1", target: "node2" },
  edge2: { source: "node2", target: "node3" },
  edge3: { source: "node2", target: "node4" },
}

const layouts: Layouts = {
  nodes: {
    node1: { x: 0, y: 80 },
    node2: { x: 200, y: 80 },
    node3: { x: 360, y: 0 },
    node4: { x: 360, y: 160 },
  },
}

export default {
  nodes,
  edges,
  layouts,
}

The second example is a bit more complicated. When a selected node is deselected, a confirmation is shown, and the selection is only deselected if "Yes" is clicked.
data.ts is the same as in the first example.

<script setup lang="ts">
import { defineConfigs } from "v-network-graph";
import { ref, watch } from "vue"
import data from "./data"

const configs = defineConfigs({
  node: {
    selectable: 1 // only one node
  },
})

const deselecting = ref(false)
const lockedNodes = ref<string[]>([])
const selectedNodes = ref<string[]>([])

watch(selectedNodes, (value, oldValue) => {
  // Note that when assigning a value to a variable monitored by watch, it is called recursively.

  if (value.length > 0 && oldValue.length === 0 && lockedNodes.value.length === 0) {
    // save selected nodes
    lockedNodes.value = value
    return
  }

  if (lockedNodes.value.length > 0 && !isEquals(value, lockedNodes.value)) {
    // prevent update selection
    selectedNodes.value = lockedNodes.value
    deselecting.value = true
    return
  }
})

function deselect() {
  lockedNodes.value = []
  selectedNodes.value = []
  deselecting.value = false
}

function isEquals<T>(array1: T[], array2: T[]) {
  return JSON.stringify(array1) === JSON.stringify(array2)
}
</script>

<template>
  <v-network-graph
    v-model:selected-nodes="selectedNodes"
    :nodes="data.nodes"
    :edges="data.edges"
    :layouts="data.layouts"
    :configs="configs"
  />
  <div v-if="deselecting">
    Are you sure you want to deselect "{{ selectedNodes[0] }}"?
    <button @click="deselect">Yes</button>
  </div>
</template>

Hope this will help.

Hey @dash14

Thank you for providing the examples, very useful!