vue-cytoscape icon indicating copy to clipboard operation
vue-cytoscape copied to clipboard

How to use reactivity element and insert data from vuex

Open jrpersico opened this issue 5 years ago • 8 comments

Hello,

I'm trying to find out how to insert my data from my vuex store in Cyelement.

Here is an example :

<template>
  <div class="possession">
    <Navigation></Navigation>
    <b-container fluid>
      <b-row>
        <b-col xl="2" lg="3" md="4">
          <DNavigation></DNavigation>
        </b-col>
        <b-col xl="10" lg="9" md="8">
          <div>
            <b-tabs content-class="mt-3">
              <b-tab title="Global" active>
                <b-row>
                  <b-col xl="12" lg="12" md="12">
                    <div class="card card-left card-progress">
                      <h5>Passnetwork global</h5>
                      <div id="holder">
                        <cytoscape
                          :config="config"
                          v-on:mousedown="addNode"
                          v-on:cxttapstart="updateNode"
                        >
                          <cy-element
                            v-for="def in elements"
                            :key="`${def.data.id}`"
                            :definition="def"
                          />
                        </cytoscape>
                      </div>
                    </div>
                  </b-col>
                </b-row>
              </b-tab>
              <b-tab title="Selected match" v-if="match">
                <MatchInfo></MatchInfo>
                <b-row>
                  <b-col xl="12" lg="12" md="12">
                    <div class="card card-left card-progress">
                      <h5>Passnetwork of selected team</h5>
                    </div>
                  </b-col>
                </b-row>
              </b-tab>
            </b-tabs>
          </div>
        </b-col>
    </b-row>
    </b-container>
  </div>
</template>

<script>
import Navigation from '@/components/Navigation'
import DNavigation from '@/components/Dashboard-Navigation'
import MatchInfo from '@/components/MatchInfo'
// import Cytoscape from '@/components/Cytoscape'
import config from '@/utils/cytoscape-config'
// import CyElement from '@/components/CyElement'

const elements = [...config.elements]
delete config.elements



export default {
  name: 'possession',
  components: {
    'Navigation': Navigation,
    'DNavigation': DNavigation,
    'MatchInfo': MatchInfo
    // Cytoscape,
    // CyElement
  },
  methods: {
    preConfig(cytoscape) {
          console.log("calling pre-config");
        },
        afterCreated(cy) {
          console.log("after created");
          this.setCyElements(cy);
        },
        setCyElements(cy) {
          console.log("setCyElements");
          let cytoElems = [];
          cy.startBatch();
          cy.elements().remove();
          for (let el of cytoElems) {
            cy.add(el);
          }
          cy.endBatch();
          cy.fit();
        }
  },
  data() {
      return {
        config,
        elements: [
          {
            data: { id: "1" , name: "Arias", weight: 25, totpass: 8, faveColor: "#14387F", faveShape: "ellipse", playername: "Arias"},
            position: { x: 10, y: 10 }
          }
        ]
      }
    },
    computed: {
      match() {
        return this.$store.getters.match
      }
    }
}
</script>

<style>
  #holder {
    width: 1200px;
    height: 800px;
  }
</style>

This code works when loading the view for the first time. If I navigate in an other view and return to the same view later, he does not charge me the elements anymore.

I probably missed a step.

Thanks for your help.

jrpersico avatar May 10 '19 12:05 jrpersico

Hi @jrpersico, first thing I notice is that you are adding elements to cytoscape both with cy-elements and manually in the preConfig hook, this would lead to unpredicted behaviour. I would suggest you to use only the cy-elements. Now to get the cy-elements updated you may need to change the key as to trigger the vue rendering of the component, or you can make sure yourself that the entire <cytoscape ... component gets re-rendered when you enter to your view, it may be the case that vue-router is caching your view somehow.

There is little help I can offer without seeing the code in context.

rcarcasses avatar May 10 '19 21:05 rcarcasses

Hi @rcarcasses, thank you for your return. I corrected the code to load the element only once in cyelement.

Here is the code:

<template>
  <div class="possession">
    <Navigation></Navigation>
    <b-container fluid>
      <b-row>
        <b-col xl="2" lg="3" md="4">
          <DNavigation></DNavigation>
        </b-col>
        <b-col xl="10" lg="9" md="8">
          <div>
            <b-tabs content-class="mt-3">
              <b-tab title="Global" active>
                <b-row>
                  <b-col xl="12" lg="12" md="12">
                    <div class="card card-left card-progress">
                      <h5>Passnetwork global</h5>
                      <div id="holder">
                        <cytoscape :config="config">
                          <cy-element v-for="element in elements" :key="element.id" :definition="element" />
                        </cytoscape>
                      </div>
                    </div>
                  </b-col>
                </b-row>
              </b-tab>
              <b-tab title="Selected match" v-if="match">
                <MatchInfo></MatchInfo>
                <b-row>
                  <b-col xl="12" lg="12" md="12">
                    <div class="card card-left card-progress">
                      <h5>Passnetwork of selected team</h5>
                    </div>
                  </b-col>
                </b-row>
              </b-tab>
            </b-tabs>
          </div>
        </b-col>
    </b-row>
    </b-container>
  </div>
</template>

<script>
import Navigation from '@/components/Navigation'
import DNavigation from '@/components/Dashboard-Navigation'
import MatchInfo from '@/components/MatchInfo'
// import Cytoscape from '@/components/Cytoscape'
import config from '@/utils/cytoscape-config'
// import CyElement from '@/components/CyElement'

const elements = [...config.elements]
delete config.elements



export default {
  name: 'possession',
  components: {
    'Navigation': Navigation,
    'DNavigation': DNavigation,
    'MatchInfo': MatchInfo
    // Cytoscape,
    // CyElement
  },
  methods: {

  },
  data() {
      return {
        config,
        elements: [
          {
            data: { id: "1" , name: "Arias", weight: 25, totpass: 8, faveColor: "#14387F", faveShape: "ellipse", playername: "Arias"},
            position: { x: 100, y: 100 }
          }
        ]
      }
    },
    computed: {
      match() {
        return this.$store.getters.match
      }
    }
}
</script>

<style>
  #holder {
    width: 1200px;
    height: 800px;
  }
</style>

However I still have the same problem, the Vue only starts the first time.

How can I restart the cytoscape element everytime I call the vue?

Thank you for your help.

jrpersico avatar May 13 '19 10:05 jrpersico

Hi @rcarcasses, do you have any idea ?

Thank you for your help.

jrpersico avatar May 22 '19 16:05 jrpersico

Hi @jrpersico, sorry but I can't see an issue with vue-cytoscape itself here. The only help I can provide you I guess is to comment you that I personally have use vue-cytoscape with vuex and things get re-rendered as expected. I would recommend you to read the elements from vuex state through a getter or similar, right now it seems to me that you have hardcoded it.

rcarcasses avatar May 22 '19 17:05 rcarcasses

I'm having a similar problem

I see in all your examples you use the component import Cytoscape from './components/Cytoscape' without a plugin. When I try using Vue.use(VueCytoscape) (Which I see you're using in your parent app), then use the plugin as outlined in the README, I can only render on first load when dealing with extensions. ~The error I get is Error: Can not register edgehandlesforcoresinceedgehandles already exists in the prototype and can not be overridden~

This issue actually happens in any hot reload/SPA page change

A simplified (broken) component is below

<template>
  <div id="holder">
    <!-- @mousedown="addNode" -->
    <cytoscape
      :config="config"
      :pre-config="preConfig"
      :after-created="afterCreated"
      @cxttapstart="updateNode"
    >
      <cy-element
        v-for="def in elements"
        :key="`${def.data.id}`"
        :definition="def"
      />
    </cytoscape>
  </div>
</template>

<script>
import Vue from 'vue'
import VueCytoscape from 'vue-cytoscape'
import 'vue-cytoscape/dist/vue-cytoscape.css'
import edgehandles from 'cytoscape-edgehandles'

import DataMap from './utils/DataMap'

// NOTICE, I USE 'use' HERE
Vue.use(VueCytoscape)

export default {
  name: 'App',
  props: {
    config: {
      required: true,
      type: Object,
    },
    defaultElements: {
      required: true,
      type: Array,
    },
    elementData: {
      default: () => [],
      type: Object,
    },
  },
  data() {
    const dataMap = new DataMap(this.elementData.steps)
    const elements = dataMap.getData()
    return {
      i: 0,
      elements,
    }
  },
  methods: {
    preConfig(cytoscape) {
      cytoscape.use(edgehandles)
      cytoscape.use(nodeLabel)
    },
    async afterCreated(cy) {
      cy.edgehandles().enable()
    },
  },
}
</script>

I've also tried employing this method outlined here: https://github.com/cytoscape/cytoscape.js/issues/1585, but it doesn't seem that it is properly registered in the preConfig hook in time...

@jrpersico, did you gain any traction on this

joshhoegen avatar Jun 06 '19 10:06 joshhoegen

Hello @joshhoegen, I still can not solve my problem unfortunately ... Keep me informed if you can move forward

jrpersico avatar Jul 08 '19 08:07 jrpersico

@jrpersico, I just ended up using the bare cytoscapeJs lib. It wasn't that hard to implement and found it much easier to do some basic things

joshhoegen avatar Jul 08 '19 09:07 joshhoegen

I started using this library because I wanted reactive data binding to my cytoscape instance, since cytoscape isn't itself reactive. You either have to remove and re-add the elements that changed, or call setter functions like ele.data(newData).

I dug into the code, and this library treats cytoscape as if it is reactive, sending observers into the instance so the data updates. This doesn't work because, in most cases, cytoscape isn't listening for a change in the data. At this point, you basically have to re-mount all of your CyElements when the data changes for cytoscape to re-draw them.

I'll submit a PR shortly for an update that adds genuine reactivity to the library, so that changes in the parent component's "elements" array propagate in the cytoscape instance.

wfischer42 avatar Nov 13 '19 17:11 wfischer42