joedski / dag-progress

Calculate user progress for each vertex in an acyclic digraph
1 stars 0 forks source link

Progress in a Directed Acyclic Graph

Build Status

Given a Directed Acyclic Graph (or Acyclic Digraph for short), calculate a Progress value for each vertex in the graph.

I'm using this to display meaningful progress values to a User when they are going through a branching interaction which may allow them to skip over parts or take different courses through that interaction. Representing the interaction as a directed acyclic graph allows this easily.

The progress calculation is very simple: Given a vertex, the length of the longest path possible from any source to that vertex divided by the length of the longest path possible from any source to any sink which conatains that vertex is the progress value for that vertex. This definition works surprisingly well given even quite disparate branch lengths in an interaction, and handles no-progress vertices quite well, too.

Note: As you might expect from a directed acyclic graph, this library does not support cycles in your story graph. To get a meaningful progress value in such cases, you should break any cycles before handing the graph to this code.

Dependencies

API

Preface: Types

dagProgress( adjacencyList: AdjacencyListMap, nodeOptions?: NodeOptionsMap ) => ProgressMap

Calculates the Progress value of each node in the DAG, as represented by its adjacency list.

Example

Note: Example is in ES6.

// During interaction initialization...

import dagProgress from 'dag-progress';
let storyDag = myThingThatMakesMyStoryIntoAnAdjacencyList( myStory );
let vertexProgresses = dagProgress( storyDag );

// Then, in some display component...

const render = ({ props }) => {
    let stepProgress = vertexProgresses[ props.page.id ];

    return (
        h( 'div', { 'class': 'interaction-progress' }, [
            `Progress: ${ Math.round( stepProgress.value * 100 ) }%`
        ])
    );
};

Degenerate Cases

Single Vertex Paths

A single Vertex will, if does not have weight: 0, have the Progress value 1. If it does have weight: 0 then it's a NaN which makes you a bad person who should feel bad.