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

v-network-graph & neo4j

Krusty84 opened this issue · comments

commented

Hello Dear @dash14 !
Thank you for amazing component!
But, maybe do you have some snippets about using neo4j and v-network-graph together?

Thank you!

Hi @Krusty84,
I have tried to write a simple example!

  • I checked with the Movies in Built-In Examples set up.
  • It does not include error handling.
  • Please replace the username and password with those of your environment.
<script setup lang="ts">
import { Nodes, Edges, defineConfigs, Edge } from "v-network-graph";
import { ForceLayout, ForceNodeDatum, ForceEdgeDatum } from "v-network-graph/lib/force-layout";
import { onMounted, ref, watch } from "vue";

// Constants and functions for retrieving data from neo4j ------------------------

const dbName = "neo4j";
const txUrl = `http://localhost:7474/db/${dbName}/tx/commit`;
const username = "neo4j";
const password = "neo4j";

async function cypher<T>(statement: string, parameters: object) {
  const method = "POST";
  const headers = {
    Authorization: "Basic " + btoa(`${username}:${password}`),
    Accept: "application/json; charset=UTF-8",
    "Content-Type": "application/json",
  };
  const body = JSON.stringify({ statements: [{ statement, parameters }] });
  const r = await fetch(txUrl, { method, headers, body });
  return (await r.json()) as T;
}

async function fetchFromNeo4j() {
  return await cypher<Neo4JQueryResult<MovieQueryResult>>(
    `MATCH p = (actor:Person)-[r:ACTED_IN]->(movie)
     WHERE actor.name = $name1 OR actor.name = $name2
     RETURN p`,
    { name1: "Tom Hanks", name2: "Meg Ryan" }
  );
}

// Type definitions --------------------------------------------------------------
interface Neo4jMeta {
  id: number;
  elementId: string;
  type: string;
  deleted: boolean;
}

type Neo4JQueryResultData<Row> = { row: Row[]; meta: Neo4jMeta[][] }[];

interface Neo4JQueryResult<Row> {
  errors: { code: number; message: string }[];
  results: { columns: string[]; data: Neo4JQueryResultData<Row> }[];
}

interface Person {
  name: string;
  born: number;
}

interface Movie {
  title: string;
  released: number;
}
interface PersonMovieRelationship {
  roles: string[];
}

type MovieQueryResult = [Person, PersonMovieRelationship, Movie];

// Setup v-network-graph ------------------------------------------------------

const nodes = ref<Nodes>({});
const edges = ref<Edges>({});

const configs = defineConfigs({
  view: {
    layoutHandler: new ForceLayout({
      positionFixedByDrag: false,
      positionFixedByClickWithAltKey: true,
      createSimulation: (d3, nodes, edges) => {
        const forceLink = d3
          .forceLink<ForceNodeDatum, ForceEdgeDatum>(edges)
          .id((d: Edge) => d.id);
        return d3
          .forceSimulation(nodes)
          .force("edge", forceLink.distance(200))
          .force("charge", d3.forceManyBody())
          .force("collide", d3.forceCollide(50).strength(0.1))
          .force("center", d3.forceCenter().strength(0.05))
          .alphaMin(0.001);
      },
    }),
  },
  node: {
    normal: {
      radius: (node) => (node.type === "actor" ? 32 : 24),
      color: (node) => (node.type === "actor" ? "#ffccaa" : "#aaccff"),
    },
    label: {
      visible: true,
      text: "name",
      direction: "center",
    },
  },
  edge: {
    label: {
      fontSize: 7,
    },
  },
});

const neo4jQueryResult = ref<Neo4JQueryResultData<MovieQueryResult>>([]);

onMounted(async () => {
  const result = await fetchFromNeo4j();
  if (result.errors.length > 0) {
    // FIXME: error handling
    return;
  }
  neo4jQueryResult.value = result.results[0].data;
});

watch(neo4jQueryResult, () => {
  // Translate neo4j model => v-network-graph model
  const data = neo4jQueryResult.value;

  const graphNodes: Nodes = {};
  const graphEdges: Edges = {};
  data.forEach((row) => {
    const [actor, relation, movie] = row.row[0];
    const [actorMeta, relationMeta, movieMeta] = row.meta[0];
    graphNodes[actorMeta.elementId] = {
      name: actor.name,
      born: actor.born,
      type: "actor",
    };
    graphNodes[movieMeta.elementId] = {
      name: movie.title,
      released: movie.released,
      type: "movie",
    };
    graphEdges[relationMeta.elementId] = {
      source: actorMeta.elementId,
      target: movieMeta.elementId,
      roles: relation.roles.join("\n"),
    };
  });

  nodes.value = graphNodes;
  edges.value = graphEdges;
});
</script>

<template>
  <v-network-graph :nodes="nodes" :edges="edges" :configs="configs">
    <template #edge-label="{ edge, ...slotProps }">
      <v-edge-label
        :text="edge.roles"
        align="center"
        vertical-align="above"
        v-bind="slotProps"
      />
    </template>
  </v-network-graph>
</template>

Screenshot:
v-network-graph and neo4j

I hope it can be helpful.

commented

You are amazing!
Arigato so much!