5

I am trying to use cytoscape.js within vue.js framework. I made a simple template and also have a variable cy in the data section. The in mounted() hook function I call cytoscape. Everything works fine as long as I store the result of cytoscape inside a local varaible, you can see below in mounted() function let cy = cytoscape({...}); As soon as I try to store cy varaible inside the data instance variable, i.e., this.cy = cy the whole browser crashes. Any ideas?

 <template>
  <div id="cyto" ref="cyto"></div>
</template>
<script>
import cytoscape from "cytoscape";

export default {
  name: "HelloWorld",
  data: function() {
    return {
      cy: null
    };
  },
  props: {
    msg: String
  },
  mounted() {
    let cy = cytoscape({
      container: this.$refs.cyto,
      elements: [
        // list of graph elements to start with
        {
          // node a
          data: { id: "a" }
        },
        {
          // node b
          data: { id: "b" }
        },
        {
          // edge ab
          data: { id: "ab", source: "a", target: "b" }
        }
      ],

      style: [
        // the stylesheet for the graph
        {
          selector: "node",
          style: {
            "background-color": "#666",
            label: "data(id)"
          }
        },

        {
          selector: "edge",
          style: {
            width: 3,
            "line-color": "#ccc",
            "target-arrow-color": "#ccc",
            "target-arrow-shape": "triangle"
          }
        }
      ],

      layout: {
        name: "grid",
        rows: 1
      }
    });
    //this line below breaks the browser
    this.cy = cy;

  }
};
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
#cyto {
  height: 100%;
  display: block;
  border: 1px solid blue;
}
</style>
Amir
  • 189
  • 2
  • 12

4 Answers4

1

Which version of cytoscape.js are you using?

I had the same problem and solved it by using the version 3.2.22 explicitly. With this version your example seems to work

var app = new Vue({
        name: 'HelloWorld',
        el: '#app',
        data: function() {
          return {
            cy: null
          }
        },
        props: {
          msg: String
        },
        mounted() {
          let cy = cytoscape({
            container: this.$refs.cyto,
            elements: [
              // list of graph elements to start with
              {
                // node a
                data: { id: 'a' }
              },
              {
                // node b
                data: { id: 'b' }
              },
              {
                // edge ab
                data: { id: 'ab', source: 'a', target: 'b' }
              }
            ],

            style: [
              // the stylesheet for the graph
              {
                selector: 'node',
                style: {
                  'background-color': '#666',
                  label: 'data(id)'
                }
              },

              {
                selector: 'edge',
                style: {
                  width: 3,
                  'line-color': '#ccc',
                  'target-arrow-color': '#ccc',
                  'target-arrow-shape': 'triangle'
                }
              }
            ],

            layout: {
              name: 'grid',
              rows: 1
            }
          })
          //this line below breaks the browser
          this.cy = cy
        }
      })
<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>Page Title</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <script src="https://unpkg.com/cytoscape@3.2.22/dist/cytoscape.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  
  <style>
    #cyto {
      width: 300px;
      height: 300px;
      display: block;
      background-color: grey
    }
  </style>
</head>

<body><div id="app">
   <div id="cyto" ref="cyto"></div>
  </div>
</body>

</html>
Chris
  • 35
  • 6
  • I am running the latest version now. I had it working but as soon as I try to cache it in vuex store for examplee, hangs again. – Amir Feb 08 '19 at 10:58
  • Is it necessary to cache the cy object in vuex for you? If not you can just cache the JSON configuration, which you can get with cy.json(). Thats how I do it – Chris Feb 13 '19 at 08:37
  • No, I don't. But will this be reactive? – Amir Feb 14 '19 at 12:26
  • I use it as a save and load mechanism with buttons, so after the changes on the graph you have to save. If your graph is not that big you could save it after each change through events. – Chris Feb 16 '19 at 08:05
0

According to this source, you have to call renderView in order to initialize the view:

// index.js
import Cytoscape from './Cytoscape.vue';
export default Cytoscape;
/* cssFile.css */
#cyto {
  height: 100%;
  display: block;
  border: 1px solid blue;
}
<!-- AppVue.js -->
<template>
  <div class="cytoscape"></div>
</template>
<style>

</style>
<script>
  import cytoscape from 'cytoscape';
  export default {
    name: "HelloWorld",
    data: function() {
      return {
        cy: null
      };
    },
    props: {
      msg: String
    },
    methods: {
      renderView: function(newElements) {
        // the only reliable way to do this is to recreate the view
        let cy = cytoscape({
          container: this.$refs.cyto,
          elements: [
            // list of graph elements to start with
            {
              // node a
              data: {
                id: "a"
              }
            },
            {
              // node b
              data: {
                id: "b"
              }
            },
            {
              // edge ab
              data: {
                id: "ab",
                source: "a",
                target: "b"
              }
            }
          ],

          style: [
            // the stylesheet for the graph
            {
              selector: "node",
              style: {
                "background-color": "#666",
                label: "data(id)"
              }
            },

            {
              selector: "edge",
              style: {
                width: 3,
                "line-color": "#ccc",
                "target-arrow-color": "#ccc",
                "target-arrow-shape": "triangle"
              }
            }
          ],

          layout: {
            name: "grid",
            rows: 1
          }
        });
      }
    },
    mounted: function() {
      this.$emit('created', this);
    }
  }
</script>
Stephan T.
  • 5,843
  • 3
  • 20
  • 42
  • 1
    I thought `renderView` is not a hook function. Is it called by `created`. – Amir Dec 11 '18 at 09:27
  • 1
    I searched the whole github repo of vue, there is no `renderView`. Maybe I am mistaken. – Amir Dec 11 '18 at 09:33
  • As far as I understand, the created event is called on initial initialisation, within the handler of that event, renderView is called with the new elements?? (why then call it on cytoscape), so instead of defining special functions to handle the different situations, this only renders the site initially.... doesn't make a whole lot of sense i guess. You can also just take a look [here](https://github.com/rcarcasses/vue-cytoscape) and implement it with a combination of the two approaches :) – Stephan T. Dec 12 '18 at 05:35
  • Thanks @Stephan T. – Amir Dec 18 '18 at 19:29
0

You can store the cytoscape instance in a method:

export default {
  name: "HelloWorld",
  methods: {
    getCy: function () {
      return null;
    }
  }
  mounted() {
    const cy = cytoscape({
      container: this.$refs.cyto,
      elements: [{data: { id: "a" }}]
    });

    this.getCy = () => {return cy;}
  }
};
Bas Van Assche
  • 321
  • 2
  • 3
0

Very late to the party but none of the answers here fix the issue or explain why it happens to begin with. Try defining the variable with a $:

..
data: () => ({
  $cy: null
  ..
})

What does the dollar prefix ($) mean in Vue.js?

In general the variable must be public to prevent the browser hanging.

Zach Jensz
  • 3,650
  • 5
  • 15
  • 30
Rotem Revivo
  • 13
  • 1
  • 3