{"id":17464547,"url":"https://github.com/hqarroum/directed-graph","last_synced_at":"2025-10-24T11:11:31.558Z","repository":{"id":4093325,"uuid":"39854851","full_name":"HQarroum/directed-graph","owner":"HQarroum","description":":busstop: An implementation of a directed graph in Javascript.","archived":false,"fork":false,"pushed_at":"2023-04-16T16:30:34.000Z","size":299,"stargazers_count":25,"open_issues_count":6,"forks_count":5,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-12T22:57:36.026Z","etag":null,"topics":["directed-graph","routing"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/HQarroum.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2015-07-28T19:58:05.000Z","updated_at":"2025-04-03T14:56:24.000Z","dependencies_parsed_at":"2023-07-05T17:00:59.152Z","dependency_job_id":null,"html_url":"https://github.com/HQarroum/directed-graph","commit_stats":{"total_commits":85,"total_committers":2,"mean_commits":42.5,"dds":0.05882352941176472,"last_synced_commit":"8741129d0eb9c26b5fc01075a97b5ebc11e88a75"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HQarroum%2Fdirected-graph","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HQarroum%2Fdirected-graph/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HQarroum%2Fdirected-graph/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HQarroum%2Fdirected-graph/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HQarroum","download_url":"https://codeload.github.com/HQarroum/directed-graph/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249763393,"owners_count":21322076,"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":["directed-graph","routing"],"created_at":"2024-10-18T10:46:16.598Z","updated_at":"2025-10-24T11:11:31.432Z","avatar_url":"https://github.com/HQarroum.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp\u003e\n \u003cimg width=\"400\" src=\"https://computersciencewiki.org/images/c/c6/Directed_graph.png\" /\u003e\n\u003c/p\u003e\n\n## Graph\n\n[![Build Status](https://travis-ci.org/HQarroum/directed-graph.svg?branch=master)](https://travis-ci.org/HQarroum/directed-graph)\n[![CodeFactor](https://www.codefactor.io/repository/github/hqarroum/directed-graph/badge)](https://www.codefactor.io/repository/github/hqarroum/directed-graph)\n\nAn implementation of a simple directed graph.\n\nCurrent version: **1.0.6**\n\nLead Maintainer: [Halim Qarroum](mailto:hqm.post@gmail.com)\n\n## Install\n\n##### Using NPM\n\n```bash\nnpm install --save digraphe\n```\n\n## Usage\n\nBasic operations you can perform on the graph are insertion and removal of nodes and edges.\n\nTo do so, you will need to create a new instance of the graph, by simply calling its constructor :\n\n```javascript\nvar graph = new Graph();\n```\n\n### Node insertions\n\nInsertions of a *node* in an instance of a graph is performed using the unique identifier of this *node*, which is represented by a string. Behind the scenes, a *node* in the Graph will be represented through `Graph.Node` objects, which will carry its unique identifiers, but also all the *edges* the node is attached to.\n\n\n\n```javascript\nvar graph = new Graph();\n\n// This will add the `foo` node to the Graph.\ngraph.addNode('foo');\n// You can also add an optional payload to the node.\ngraph.addNode('bar', { key: 'value'});\n```\n\nNote that adding a node in the graph using an already inserted identifier will have no effect on the Graph data model.\n\nYou can at any moment check whether the graph carries a given node either using its unique identifier, either by using a `Graph.Node` instance :\n\n\n```javascript\nvar graph = new Graph();\n\ngraph.addNode('foo');\ngraph.hasNode('foo'); // Returns true.\n\n// Retrieving the instance of the `foo` node.\nvar node = graph.nodes['foo'];\ngraph.hasNode(node); // Returns true.\n```\n\n### Edge insertions\n\nInsertions of an *edge* in an instance of a graph is performed using the source node identifier as well as the target node identifier, which are represented by strings. Behind the scenes, an *edge* in the Graph will be represented through `Graph.Edge` objects, which will carry the source and target nodes, but also the *weight* of the *edge*.\n\n\n\n```javascript\nvar graph = new Graph();\n\n// This will create a new edge between the `foo`\n// node and the `bar` node.\ngraph.addEdge('foo', 'bar');\n// You can also specify a `weight` for an edge.\ngraph.addEdge('bar', 'baz', { weight: 2 });\n```\n\nNote that if the edge's nodes do not exist in the graph, they will be automatically added.\n\nYou can at any moment check whether the graph carries a given edge either using its unique identifier, either by using a `Graph.Edge` instance :\n\n\n```javascript\nvar graph = new Graph();\n\ngraph.addEdge('foo', 'bar');\n\n// Retrieving the node instances.\nvar foo = graph.nodes['foo'];\nvar bar = graph.nodes['bar'];\ngraph.hasEdge(foo, bar); // Returns true.\n```\n\n### Visitors\n\nVisitors are objects that allow you to browse the nodes of a graph. Two visitors are available in the current implementation.\n\nWe will use the following graph structure as an example for each of the following visitors :\n\n```javascript\n/**\n *                        Head Node\n *                          |  |\n *                          /  \\\n *                       1 /    \\ 1\n *                        /      \\\n *                       \\/      \\/\n *                      foo      bar\n *                      ||        ||\n *                       \\        /\n *                      2 \\      / 2\n *                         \\    /\n *                         \\/  \\/\n *                           baz\n */\n var graph = new Graph();\n\ngraph.addEdge('head', 'foo', { weight: 1 });\ngraph.addEdge('head', 'bar', { weight: 1 });\ngraph.addEdge('foo', 'baz', { weight: 2 });\ngraph.addEdge('bar', 'baz', { weight: 2 });\n```\n\n#### Depth-First Visitor\n\nThe Depth-First visitor uses the Depth-First Search algorithm to walk along the graph's nodes.\n\nIt implements the following prototype :\n\n`Graph.Visitor.DFS(graph, head, callback)`\n\n- `graph` is the instance of the graph the visitor will walk through\n- `head` is the head node from which the walk will start from\n- `callback` is an optional function which will be called back by the visitor on each discovered node\n\nExample :\n\n```javascript\nGraph.Visitor.DFS(graph, 'head', function (node) {\n    // Do something with the discovered node\n});\n```\n\nIf we print the sequence of nodes forwarded by the visitor using our example, it will result in `['foo', 'baz', 'bar']`.\n\n#### Breadth-First Visitor\n\nThe Breadth-First visitor uses the Breadth-First Search algorithm to walk along the graph's nodes.\n\nIt implements the following prototype :\n\n`Graph.Visitor.BFS(graph, head, callback)`\n\n- `graph` is the instance of the graph the visitor will walk through\n- `head` is the head node from which the walk will start from\n- `callback` is an optional function which will be called back by the visitor with as parameter an array of node discovered on a `depth`, and the current `depth` at which the nodes have been found.\n\nExample :\n\n```javascript\nGraph.Visitor.BFS(graph, 'head', function (array_of_nodes, depth) {\n    // Do something with the discovered node\n});\n```\n\nIf we print the sequence of nodes forwarded by the visitor using our example, it will result in `[['head'], ['foo', 'bar'], ['baz']];`.\n\n### Route management\n\nRoutes are the representation of a collection of nodes along a given *path*.\n\nIt is possible through the APIs offered by the `Graph` interface to create and retrieve routes dynamically.\n\nFor the sake of simplicity and to demonstrate all the route management APIs, we will stick to the previous graph representation example used for the `visitor` interface.\n\n#### The `Graph.routes` API\n\nThis method will take a query as an input and will return a collection routes as an output. Let's walk through the various options made available by this method.\n\n##### Resolving all the routes given a head node\n\nIt is possible for a client to compute all the routes in a graph having as head node a node `N` :\n\n```javascript\n// The following call will return all the `routes`\n// having the `head` node as a starting point.\nvar routes = graph.routes({ from: 'head' });\n```\nThe available route paths returned by the previous call can be represented as :\n\n- head -\u003e foo **(1)**\n- head -\u003e foo -\u003e baz **(3)**\n- head -\u003e bar **(1)**\n- head -\u003e bar -\u003e baz **(3)**\n\n**Note :** The numbers in parentheses are the weights associated with each routes.\n\n##### Resolving all the routes between two nodes\n\nTo compute all the routes, whatever their weights, between two given nodes you can use the following :\n\n```javascript\nvar routes = graph.routes({ from: 'head', to: 'baz' });\n```\nThe available route paths returned by the previous call can be represented as :\n\n- head -\u003e foo -\u003e baz **(3)**\n- head -\u003e bar -\u003e baz **(3)**\n\n##### Using advanced queries\n\nYou can specify additional query clauses to the `Graph.routes` API to filter your request using a `where` object :\n\n```javascript\nvar routes = graph.routes({\n  from: 'head',\n  to: 'baz',\n  where: {\n    length: 3\n  }\n});\n```\nThe available route paths returned by the previous call can be represented as :\n\n- head -\u003e foo -\u003e baz **(3)**\n- head -\u003e bar -\u003e baz **(3)**\n\n#### The `Graph.hasRoute` API\n\nThis method will use an optimized Breadth-First Search to determine whether the given `Graph.Route` is part of a graph instance.\n\nExample :\n\n```javascript\nvar routes = graph.routes({ from: 'head' });\n\n// For each found route, we check whether\n// it is part of the graph.\nroutes.forEach(function (route) {\n    // Obviously, this operation will always\n    // return `true`.\n    graph.hasRoute(route);\n});\n```\n\n#### The `Graph.findRoute` API\n\nThis method is a helper that will let you map an array of nodes identifiers to an actual route in the graph.\n\nExample :\n\n```javascript\nvar route = graph.findRoute(['head', 'foo', 'baz']);\n```\n\n### Events\n\nIt is possible to listen to particular events on a `Graph` instance since it implements the event emitter API. It is often useful to do so to add dynamic behaviour to the graph.\n\nA good example of such a behaviour would be the ability to check for orphan nodes on each nodes or edges removal and to remove them if any.\n\nYou can listen to four events on the graph :\n\n - `node.added` is emitted right after the insertion of a node\n - `node.removed` is emited when a node has been removed\n - `edge.added` is emitted after the insertion of a new edge\n - `edge.removed` is emitted after the removal of an edge\n\nExample :\n\n```javascript\nvar graph = new Graph();\n\n// This will represent our event receiver object.\nvar receiver = {\n  onNodeAdded: function (node) {\n    console.log(node.id, 'has been added !');\n  },\n  onNodeRemoved: function (id) {\n    console.log(id, 'has been removed !');\n  },\n  onEdgeAdded: function (edge) {\n    console.log(edge.source.id, '-\u003e', edge.target.id, 'created !');\n  },\n  onEdgeRemoved: function (source, target) {\n    console.log(source, '-\u003e', target, 'removed !');\n  }\n};\n\n// Subscribing to the graph events.\ngraph.on('node.added', receiver.onNodeAdded);\ngraph.on('node.removed', receiver.onNodeRemoved);\ngraph.on('edge.added', receiver.onEdgeAdded);\ngraph.on('edge.removed', receiver.onEdgeRemoved);\n// Adding a new edge, and two new nodes.\ngraph.addEdge('foo', 'bar');\n// Removing all nodes and edges.\ngraph.clear();\n```\n\n## Building\n\nThis project uses `Grunt` as its build management system and `Bower` as its dependency management system.\n\nGrunt uses the `Gruntfile.js` to know how to build the project, and will as a *default* task build the project\nand copy the binaries in the `dist/` folder.\n\nGrunt relies on `Node.js` and `NPM` to execute tasks, so you will need to ensure they are available on your build machine.\n\nTo install Grunt, its modules, and fetch the Bower dependencies of the project you will need to run the following command :\n\n```bash\n# This will install Grunt tasks and fetch the\n# required Bower module as a postinstall task.\nnpm install\n```\n\nTo run a build using the default task, simply run the following command :\n\n```bash\ngrunt\n```\n\n## Tests\n\nTests are available in the `tests/` directory.\n\nYou can either trigger them using `Jasmine JS` and its HTML presenter by opening `tests/index.html` in a browser, or trigger the\nfollowing commands :\n\n```bash\n# Using grunt\ngrunt\n\n# Using NPM\nnpm test\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhqarroum%2Fdirected-graph","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhqarroum%2Fdirected-graph","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhqarroum%2Fdirected-graph/lists"}