Search code examples
javascriptjsonvis.jsvis.js-network

Creating .json file and storing data in javascript -- using vis.js


In my project I need to save the data to .txt or .xml or .json file. I could not find any answer from vis.js website/issues blog. It might be simple, do not know. Really helpful if anyone help me out with example code. Thank you so much in advance.

function saveData(data,callback) {
  data.id = document.getElementById('node-id').value;
  data.label = document.getElementById('node-label').value;
  clearPopUp();
  callback(data);
}

Solution

  • If I understand you correctly, you are looking for a way to save data and options of a graph. In my graph editor adaptation for TiddlyWiki Classic I use the following method to extract data (the full implementation can be found in the repo, see config.macros.graph.saveDataAndOptions, here's a simplified one):

    config.macros.graph.saveDataAndOptions = function(network,newOptions) {
    
        newOptions = newOptions || {};
    
        // get nodes and edges
        var nodes = network.body.data.nodes._data; // contains id, label, x,y, custom per-node options and doesn't contain options from options.nodes; presumably contains option values set when network was created, not current ones (it is so for x,y)
        // no suitable getter unfortunately
        var edges = network.body.data.edges._data; // map; for edges to/from? certain node use network.getConnectedNodes(id)
        // network.body.data.edges._data is a hash of { id: , from: , to: }
    
        // get node positions, options
        var positions = network.getPositions(), // map
            options = // get options stored previously
        // merge newOptions into options
    
        for(var nodeId in nodes) {
            // nodes[nodeId].x is the initial value, positions[nodeId].x is the current one
            if(positions[nodeId]) { // undefined for hidden
                nodes[nodeId].x = positions[nodeId].x;
                nodes[nodeId].y = positions[nodeId].y;
            }
            storedNode = copyObjectProperties(nodes[nodeId]);
    
            storedNodes.push(storedNode);
        }
    
        //# do whatever you need with storedNodes, edges and options
        //  (pack them with JSON.stringify, store to a file etc)
    };
    

    However, while this works ok for storing data, this only helps to save options passed for storing explicitly which can be not very nice for some cases. I use this method in manipulation helpers and on dragEnd (network.on("dragEnd",this.saveToTiddlerAfterDragging), config.macros.graph.saveToTiddlerAfterDragging = function(stuff) { config.macros.graph.saveDataAndOptions(this,{ physics: false }); };). I haven't recieved any better suggestions, though.

    If you need to get data and options reactively and setting such helper to handle certain edit events can't solve your problem, then I suggest wrapping nodes, edges and options as vis.DataSet and save those when needed. This is related too.


    To answer the question about events/other ways to use such methods. Here's how I use them:

    1. I save data after drag&drop moving of nodes, this is done using an event handler. Namely, I introduced

      config.macros.graph.saveToTiddlerAfterDragging = function(stuff) {
          config.macros.graph.saveDataAndOptions(this,{ physics: false });
      };
      

      (when drag&drop is used, physics should be switched off, otherwise coordinates won't be preserved anyway) and then I use

      network.on("dragEnd",this.saveToTiddlerAfterDragging);
      

      so that changes are saved.

    2. As for saving after adding/editing a node/edge, I apply saving not by an event (although it's nice thinking, and you should try events of DataSet, since there's no special graph events for that). What I do is I add an elaborated hijack to the manipulation methods. Take a look at the source I've linked after the

      var mSettings = options.manipulation;
      

      line: for each manipulation method, like options.manipulation.addNode I hijack it so that its callback is hijacked to call config.macros.graph.saveDataAndOptions in the end. Here's a simplified version of what I'm doing:

      var nonSaving_addNode = options.manipulation.addNode;
      options.manipulation.addNode = function(data,callback) {
          // hijack callback to add saving
          arguments[1] = function() {
              callback.apply(this,arguments); // preserve initial action
              config.macros.graph.saveDataAndOptions(network); // add saving
          };
          nonSaving_addNode.apply(this,arguments);
      }
      

      The thing is, addNode is actually called when the add node button is clicked; though, I'm using a customized one to create a popup and apply changes once user is happy with the label they chose.