{"id":15377883,"url":"https://github.com/andrewjakubowicz/networkvizjs","last_synced_at":"2025-07-05T10:32:16.663Z","repository":{"id":42660734,"uuid":"88331195","full_name":"AndrewJakubowicz/networkVizJS","owner":"AndrewJakubowicz","description":"Easy abstraction for working with force directed graphs.","archived":false,"fork":false,"pushed_at":"2023-03-05T22:57:04.000Z","size":3836,"stargazers_count":47,"open_issues_count":9,"forks_count":7,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-28T23:03:12.457Z","etag":null,"topics":["force-directed-graphs","graph","visualisation"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AndrewJakubowicz.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2017-04-15T07:20:44.000Z","updated_at":"2024-09-18T07:12:47.000Z","dependencies_parsed_at":"2023-12-06T03:44:35.685Z","dependency_job_id":null,"html_url":"https://github.com/AndrewJakubowicz/networkVizJS","commit_stats":{"total_commits":270,"total_committers":12,"mean_commits":22.5,"dds":0.6333333333333333,"last_synced_commit":"0e11f1bae27fb3ca77cb1fb3df9a1ecfed471c61"},"previous_names":["spyr1014/networkvizjs"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndrewJakubowicz%2FnetworkVizJS","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndrewJakubowicz%2FnetworkVizJS/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndrewJakubowicz%2FnetworkVizJS/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndrewJakubowicz%2FnetworkVizJS/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AndrewJakubowicz","download_url":"https://codeload.github.com/AndrewJakubowicz/networkVizJS/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249116731,"owners_count":21215259,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["force-directed-graphs","graph","visualisation"],"created_at":"2024-10-01T14:14:02.545Z","updated_at":"2025-04-15T17:23:07.484Z","avatar_url":"https://github.com/AndrewJakubowicz.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Easy, interactive graphs with networkVizJS\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://media.giphy.com/media/xUA7b6EQrHg94qkynC/giphy.gif\" alt=\"Interacting with diagram\"\u003e\n\u003c/p\u003e\n\n## Examples\n\n- [Very simple graph editor](http://mind-map-prototype.surge.sh/)\n### vue-graphViz\nA fully functional graph editor built using networkVizJS\n- [Demo Link](https://andrewjakubowicz.github.io/vue-graphViz/)\n- [Github Project Link](https://github.com/AndrewJakubowicz/vue-graphViz)\n\n\n## Why this project exists\n\nForce directed graphs can be a mighty headache especially when trying to dynamically update nodes.\n\nThis project aims to abstract away much of the process of drawing a graph leaving you to focus on the\nthings that matter.\n\n### Features\n\n - Dragging.\n - Panning and zooming.\n - Avoid overlapping nodes.\n - Easy interface for adding / removing nodes.\n - Routing the edge lines around nodes.\n\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"https://media.giphy.com/media/xUPGciVhMEBSWGN94c/giphy.gif\" alt=\"Interacting with diagram\"\u003e\n\u003c/p\u003e\n\n - Very stable using [Webcola](http://marvl.infotech.monash.edu/webcola/) as the layout.\n - Easy handlers that allow you to finely tune the experience for the user.\n - Various layouts supported out of the box:\n    - Flow layout for force directed graph (horizontally and vertically)\n    - Jaccard layout (where denser node regions spread out)\n    - Regular layout allowing a fixed or dynamic edge length.\n - An intuitive API which lets you do what you want.\n\n\n\u003e\u003e Adding a node is as easy as `graph.addNode(\u003cyour node object\u003e)`!\n\n\n## Quickstart using Webpack or another bundler\n\n```shell\nnpm install --save networkvizjs\n```\n\nImport the module:\n\n```javascript\n// ES6\nimport networkVizJS from \"networkVizJS\";\n// commonjs\nvar networkVizJS = require('networkVizJS').default;\n```\n\nGiven we have an div with id `graph1`, we can initiate\na graph in that div using:\n\n```typescript\nconst graph = networkVizJS('graph1', options?);\n```\n\nNode must have at least these two properties:\nOptionally you can define `x` and `y`.\n\n### Adding and removing nodes\n```typescript\nconst node = {\n    id: \"uniqueString\", // id must be unique\n    hash: \"uniqueString\",   // see notes below\n    shortname: \"New Node\",\n    class: \"\",\n    fixed: true,\n    // optional properties\n    nodeShape: \"rect\",\n    color: '#aadcdc',\n    img: false,\n    fixedWidth: false,\n}\n```\n`addNode` takes a node object or a list of nodes.\nThey'll be immediately drawn to the svg canvas!\n\n```javascript\ngraph.addNode(node);\n```\n`removeNode` just takes a node hash.\nIt deletes the node and all edges that include that node.\n```javascript\ngraph.removeNode(\"uniqueString\");\n```\n\n### Adding and removing triplets (or edges between nodes)\n\nTo define an edge you use a triplet with the shape:\n\n```javascript\nvar someEdge = {\n    subject: { /* Node to start at */ }\n    predicate: { type: \"someType\", hash: 'uniqueString' } // Type allows different coloured edges. Hash must be unique\n    object: { /* Node to finish at */ }\n}\n```\n\n```javascript\ngraph.addTriplet(triplet);\ngraph.removeTriplet(triplet);\n```\n\nYou're pretty much good to go!\nBelow is the rest of the API.\n\n### Node Object:\nThe full node object is defined below\n\nNote: id and hash are the same, hash is depreceated but still needs to be defined for the time being\n\n```typescript\ninterface Node {\n// the following options are required as a minimum definition\n    id: Id;                 // unique id string.\n    hash: Id;               // deprecated - still required for compatability\n    shortname: string;      // text to display\n    class: string;          // CSS class to be applied to node element\n    fixed: boolean | number // node has fixed position or will auto layout \n                // internally is a bitstring in the form of a number but can be used as a simple boolean\n\n// the following will revert to the default specified in layoutOptions\n// valid values are determined by the function defined in layoutOptions\n    nodeShape: string;      // string description of node path\n    color: string;          // node color - use hex color code string\n\n// optional properties\n    img?: any;              // image data inside node\n    fixedWidth?: number | boolean;  // Set to number to manually set node width or false\n\n// properties set internally\n    constraint?: Constraint[];  // list of constraints applying to this node\n    parent?: Group;             // Group node is contained in\n    width?: number;             // specify a width and height of the node's bounding box if you turn on avoidOverlaps\n    height?: number;            // specify a width and height of the node's bounding box if you turn on avoidOverlaps\n    index?: number,             // index in nodes array, this is initialized by Layout.start()         \n    bounds: Rectangle;          // Rectangle of node bounds\n    innerBounds: Rectangle;     // Rectangle of node bounds\n\n// positioning is set internally but may be overwritten\n    px: number;\n    py: number;\n    x:number;\n    y:number;\n}\n```\n\n### Group Object\nAll properties available on the group object are shown below.\n\nLeaves should be entered as an array of node indices to avoid weird bugs\nwebcola will convert the index to the node object internally.\n \n```typescript\ninterface Group {\n    id: Id;                 // unique ID string\n    data: GroupData;        // Group data see below\n    parent?: Group;         // Parent group\n    groups?: Group[];       // Groups nested in group\n    leaves?: Node[];        // Nodes contained in group\n    bounds?: Rectangle;     // Rectangle of group bounds\n    padding: any;           // number or rectangle of group padding\n}\n\ninterface GroupData {\n    color?: string;         // group colour\n    class?: string;         // CSS class to be applied to HTML element\n    text?: string;          // group text label\n    level?: number;         // Group nesting level - set internally\n}\n```\n\n## Options object:\n\nThese options are all optional.\nJust pass in the ones you want.\nThis controls default settings of colours/sizes etc... as well as\nbehaviour to be performed on user interaction events eg. clickOnNode\n\n```typescript\ninterface LayoutOptions {\n    databaseName: string;               // Force the database name\n    layoutType: \"linkDistance\" | \"flowLayout\" | \"jaccardLinkLengths\";\n    jaccardModifier: number;            // Modifier for jaccardLinkLengths, number between 0 and 1\n    avoidOverlaps: boolean;             // True: No overlaps, False: Overlaps\n    handleDisconnected: boolean;        // False by default, clumps disconnected nodes\n    flowDirection: \"x\" | \"y\";\n    enableEdgeRouting: boolean;         // Edges route around nodes\n    nodeShape: string;                  // default node shape text description\n    nodePath: string | { (nodeObject?: Node): string };   // function returns node path from shape descriptor\n    width: number;                      // SVG width\n    height: number;                     // SVG height\n    pad: number;                        // Padding outside of nodes\n    margin: number;                     // Margin inside of nodes\n    groupPad: number;                   // padding around group\n\n    canDrag(): boolean;                 // True: You can drag nodes, False: You can't\n\n    nodeDragStart(d: Node, element: any): void;      // This callback is called when a drag event starts on a node.\n\n    nodeDragEnd(d: Node, element: any): void;        // Called when drag event ends\n\n    edgeLabelText: string | { (d?: EdgeData, i?: number): string };\n\n    // Mouse event handlers\n\n    clickAway(): void;\n\n    // Nodes\n    mouseDownNode(nodeObject?: Node, d3Selection?: Selection, event?: MouseEvent): void;\n\n    mouseOverNode(nodeObject?: Node, d3Selection?: Selection, event?: MouseEvent): void;\n\n    mouseOutNode(nodeObject?: Node, d3Selection?: Selection, event?: MouseEvent): void;\n\n    mouseUpNode(nodeObject?: Node, d3Selection?: Selection, event?: MouseEvent): void;\n\n    clickNode(nodeObject?: Node, d3Selection?: Selection, event?: MouseEvent): void;\n\n    dblclickNode(nodeObject?: Node, d3Selection?: Selection, event?: MouseEvent): void;\n\n    // Groups\n    mouseOverGroup(groupObject?: Group, d3Selection?: Selection, event?: MouseEvent): void;\n\n    mouseOutGroup(groupObject?: Group, d3Selection?: Selection, event?: MouseEvent): void;\n\n    clickGroup(groupObject?: Group, d3Selection?: Selection, event?: MouseEvent): void;\n\n    dblclickGroup(groupObject?: Group, d3Selection?: Selection, event?: MouseEvent): void;\n\n    // Edges\n    mouseOverEdge(edgeObject?: Edge, d3Selection?: Selection, event?: MouseEvent): void;\n\n    mouseOutEdge(edgeObject?: Edge, d3Selection?: Selection, event?: MouseEvent): void;\n\n    clickEdge(edgeObject?: Edge, d3Selection?: Selection, event?: MouseEvent): void;\n\n    dblclickEdge(edgeObject?: Edge, d3Selection?: Selection, event?: MouseEvent): void;\n\n\n    // These are \"live options\"\n    nodeToPin: boolean | { (d?: Node, i?: number): boolean };\n    nodeToColor: string | { (d?: Node, i?: number): string };        // Return a valid hexadecimal colour.\n    nodeToText: string | { (d?: Node, i?: number): string };        // Return text used to display in node.\n    nodeStrokeWidth: number | { (d?: Node, i?: number): number };\n    nodeStrokeColor: string | { (d?: Node, i?: number): string };\n    edgeColor: string | { (d?: EdgeData, i?: number): string };\n    edgeArrowhead: number | { (d?: EdgeData, i?: number): number };  // edgeArrowhead: 0 - None, 1 - Right, -1 - Left, 2 - Bidirectional\n    edgeStroke: number | { (d?: EdgeData, i?: number): number };\n    edgeStrokePad: number | { (d?: EdgeData, i?: number): number };  // size of clickable area behind edge\n    edgeDasharray: number | { (d?: EdgeData): number };\n    edgeLength: number | { (d?: Edge, i?: number): number };\n    edgeSmoothness: number;                                 // amount of smoothing applied to vertices in edges\n    groupFillColor: string | { (g?: Group): string };\n    snapToAlignment: boolean;                               // Enable snap to alignment whilst dragging\n    snapThreshold: number;                                  // Snap to alignment threshold\n    palette: string[];  // colour palette selection\n\n    zoomScale(scale: number): void;     // Triggered when zooming\n\n    isSelect(): boolean; // is tool in selection mode\n    nodeSizeChange(): void; // Triggers when node dimensions update\n\n    selection(): any;   // Returns current selection from select tool\n\n    imgResize(bool: boolean): void;  // Toggle when resizing image\n\n    edgeRemove(edgeObject?: any, d3Selection?: Selection, event?: MouseEvent): void; // TODO -ya defunct?\n\n}\n```\n\n## Methods on graph object\nThese are the API options available on each instance of a graph\n\n    hasNode(id: Id): boolean\nCheck if node is drawn.\nReturns boolean value on existence of node in graph.\n\n    getDB(): any\nPublic access to the levelgraph db.Returns the levelgraph db object.\n\nSee https://github.com/levelgraph/levelgraph for documentation\n\n    getNode(id?: Id): Node | Node[]\nReturns node object matching id. Leave id blank for all nodes. \n\n    getGroup(id?: Id): Group | Group[]\nReturns group object matching id. Leave id blank for all groups. \n\n\n    getByCoords(boundary: { x: number; X: number; y: number; Y: number }): { nodes: Node[]; edges: Edge[]; groups: Group[] }\nGet nodes, edges, and group objects within defined co-ordinate boundary.\nNodes and groups are defined to be inside if any overlap occurs between their bounds and target boundary.\nEdges are defined to be inside boundary if at least the middle 2/3rds of the line is within the bounds.\n\n\n    getPredicate(id?: Id): Edge | Edge[]\nGet edge predicate from predicateMap. Leave id blank for all edges.\n\n    getLayoutOptions(): LayoutOptions\nReturns layout options object.\n\n    getSVGElement(): d3Selection\u003cSVGElement, Node, HTMLElement, any\u003e\nGet d3 selection of the mainSVG element.\n If you want the HTML node use: `graph.getSVGElement().node();`\n\n    saveGraph(): Promise\u003cstring\u003e\nGet stringified representation of the graph.\nReturns a promise containing the serialised graph.\n\n    addTriplet(tripletObject: Edge, preventLayout?: boolean): Promise\u003cvoid\u003e\nAdd an edge to graph. Adds the node if it's not already present otherwise it just adds the edge.\n\nSet preventLayout flag to true to prevent layout restart from occurring automatically on completion\nReturns promise that resolves on completion.\n\n\n    removeTriplet(tripletObject: Edge, preventLayout?: boolean): Promise\u003cvoid\u003e\nRemove an edge from graph. Silently fails if edge doesn't exist.\n\nSet preventLayout flag to true to prevent layout restart from occurring automatically on completion\nReturns promise that resolves on completion.\n\n    updateTriplet(tripletObject: Edge): void\nDEPRECATED. Use editEdge method instead.\n \nUpdate edge data in the triplet database. Fails silently if doesn't exist.\n\n    removeNode(nodeHash: Id): void\nRemove a node and all edges connected to it.\n\n\n    addNode(nodeObjectOrArray: Node | Node[], preventLayout?: boolean): Promise\u003cvoid\u003e\nAdd a node or array of nodes to graph.\n\nSet preventLayout flag to true to prevent layout restart from occurring automatically on completion\nReturns promise that resolves on completion.\n\n    editNode(action: { property: string; id: Id | Id[]; value: any | any[] }): void\nPublic function to mutate node objects.\n\nCan mutate single nodes or multiple nodes at once. Can mutate multiple nodes to have 1 value, or multiple nodes to each have their own value\n\nfor multiple values, value array length==id Array length, first value will be mapped to first id in array etc...\n    \n    editEdge(action: { property: string; id: Id | Id[]; value: any | any[] }): void\nPublic function to mutate edge objects.\n\ncan mutate single edges or multiple edges at once. can mutate multiple edges to have 1 value, or multiple edges to each have their own value.\n\nfor multiple values, value array length==id array length, first value will be mapped to first id in array etc...\n\n    addToGroup(group: Group | Id, children: { nodes?: Id[]; groups?: Id[] }, preventLayout?: boolean): void\nAdd nodes or groups to group. \n\nSet preventLayout flag to true to prevent layout restart from occurring automatically on completion\nReturns promise that resolves on completion.\n\n    unGroup(children: { nodes?: Id[]; groups?: Id[] } | [{ nodes?: Id[]; groups?: Id[] }], preventLayout?: boolean): void\nRemove nodes or groups from group\n\nSet preventLayout flag to true to prevent layout restart from occurring automatically on completion\nReturns promise that resolves on completion.\n\n    constrain(consData: InputAlignConstraint | AlignConstraint, targets: { id: Id; offset: number }[])\n    constrain(consData: InputSeparationConstraint, targets: [Id, Id])\nCreate new constraint or add nodes to an existing alignment constraint.\nConstraints between a pair of nodes e.g. separation constraint cannot be modified, only deleted and created.\n\nsee: https://github.com/tgdwyer/WebCola/wiki/Constraints for constraint documentation.\n\nrequires restarting simulation after completion.\n\n    unconstrain(nodeId: Id | Id[], constraint?: Constraint): void;\nremove nodes from an existing alignment constraint; remove all nodes to remove constraint\n\nrequires restarting simulation after completion.\n\n    groupTextPreview(show: boolean, groupId: Id | Id[], text?: string): void\nShow or hide group text popup by creating temporary pop up at top of node for text\nCan be removed by passing show as false, or by restarting\n\n    // Restart styles or layout.\n    restart: {\n        // Redraw without changing layout\n        styles(): Promise\u003cvoid\u003e;\n        // Aligns text to centre of node\n        textAlign(): Promise\u003cvoid\u003e;\n        // Redraw the edges\n        redrawEdges(): Promise\u003cvoid\u003e;\n        // restart simulation and redraw layout\n        layout(callback: () =\u003e void, preventLayout?: boolean): Promise\u003cvoid\u003e;\n        // Handle disconnected graph components\n        handleDisconnects(): void;\n        // Aligns group text\n        repositionGroupText(): void;\n        // Refresh highlighted elements\n        highlight(): void;\n    };\n    canvasOptions: {\n        setWidth(width: number): void;\n        setHeight(height: number): void;\n    };\n    // Set event handlers for node.\n    nodeOptions: {\n        setDblClickNode;\n        setClickNode;\n        setMouseOver;\n        setMouseOut;\n        setMouseDown;\n    };\n    // Handler for clicking on the edge.\n    edgeOptions: {\n        setClickEdge;\n        setDblClickEdge;\n    };\n    groupOptions: {\n        setDblClickGroup;\n    };\n    // Change layouts on the fly.\n    // May be a webcola memory leak if you change the layout too many times.\n    colaOptions: {\n        flowLayout: {\n            down(callback: () =\u003e void): void;\n            right(callback: () =\u003e void): void;\n        };\n    };\n}\n\n## Todo\n\n- [ ] Batch node and edge updates without layout refreshing\n- [ ] Stabilise API (need help / guidance)\n- [ ] Add svg tests (need help / guidance)\n- [ ] Document full api\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrewjakubowicz%2Fnetworkvizjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrewjakubowicz%2Fnetworkvizjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrewjakubowicz%2Fnetworkvizjs/lists"}