dash14 / v-network-graph

An interactive network graph visualization component for Vue 3
https://dash14.github.io/v-network-graph/
MIT License
485 stars 44 forks source link

Custom Node Shape #80

Closed jjackevans closed 1 year ago

jjackevans commented 1 year ago

Hello again,

How would one achieve a custom node shape? I have the shape currently as an svg, but I can produce other formats if necessary.

Thanks.

dash14 commented 1 year ago

Hi @jjackevans, Sorry for the late reply. Custom node shape can be achieved using override-node slot. An example is shown below.

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

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

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

const layouts = ref({
  nodes: {
    node1: { x: 0, y: 0 },
    node2: { x: 50, y: 50 },
    node3: { x: 100, y: 0 },
    node4: { x: 150, y: 50 },
  },
});

const configs = defineConfigs({
  node: {
    selectable: true,
    normal: {
      // for ficus ring
      type: "circle",
      radius: 12,
    },
  },
});

const nodeWidth = 24;
const nodeHeight = 20;
</script>

<template>
  <v-network-graph
    :nodes="nodes"
    :edges="edges"
    :layouts="layouts"
    :configs="configs"
  >
    <!-- Replace the node component -->
    <template #override-node="{ scale, config, ...slotProps }">
      <!-- The center position of the node is (0,0).
           Use translate to move the shape and adjust the center if necessary. -->
      <path
        d="M12 0 L0 20 L24 20 Z"
        :fill="config.color"
        :transform="`scale(${scale}) translate(${-nodeWidth / 2}, ${-nodeHeight / 2 - 2})`"
        v-bind="slotProps"
      />
    </template>
  </v-network-graph>
</template>
screenshot

Currently, the focus ring that is displayed when a node is selected only supports the shape specified in the config (circle or rounded rectangle). If you want to customize the shape of the focus ring, it may be possible to set config.node.focusring.visible to false and then get the currently selected node from the selected-nodes prop and draw it in added own layer.

In addition, the example uses a svg element as the node shape, but you can also specify an external image (including svg) with the tag, as in the second example at the URL below. https://dash14.github.io/v-network-graph/examples/appearance.html#custom-node

I hope this helps.

jjackevans commented 1 year ago

Hi,

Thanks for this - working for the most part.

Having a strange issue. This works fine in development, but when the app is built and deployed, it fails. The reason being is that I need to access a property of the node to determine whether it should have a custom svg.

For example: node1: { x: 0, y: 0, type: 1 } should render differently based on type.

To access the type variable with your solution, I need to call a method on the parent component of v-network-graph to look-up node1 and retrieve the type property. WEIRDLY this runs fine in the npm serve development tool, but throws errors when deployed.

Let me know if you need any more information with regards to this.

Checked your docs to see how you'd implemented it with the v-html tag .

Perhaps I was being dumb earlier, everything works fine. I don't use the focus ring anyway, so this is not a concern to me.

Thanks again for your help! :)