Restore cytoscape graph to original state - cytoscape.js

I have created a cytoscape.js graph. Users are allowed to click and zoom/drill down on any node to see all the neighboring nodes and edges. I need to add a reset button, that will restore the graph to it's original position, i.e. when the page was first loaded. I have tried using a couple of different functions such as cy.load, forcerender, cy.destroy and recreate graph. Only thing left is to clear the entire object from the dom and add another cytoscape graph object. I would like to know if there is a simple way I can do a redraw or reload the entire graph. I have all the details (original styles/node data) stored in an array.
Thanks

Save the positions and then restore them whenever you want with nodes.positions(): http://js.cytoscape.org/#nodes.positions
Or save the element JSONs and then later restore them: http://js.cytoscape.org/#ele.json

Related

Vue watcher restore old values?

im using this component to make a list of sortable items.
https://sortablejs.github.io/Vue.Draggable/#/simple
I have one array with the items in my view component data.
Then i use an v-for to pain the list, one row for each item in my array.
So everytime i move one item, the array of items gets sorted and change the order of the array items, thats the behaviour of this component.
But i have to make a post call to an api to save the new order fot the list.
So i defined a watcher over the array of items, and everytime it gets sorted by the draggable component, i make the request to the api if the array order has changed.
The problem comes when this request fails, i want to restore the old values in the view, so i dont have one order in the view an another different stored in database.
Inside my watcher i have prevValues and newValues, that i use to compare and check if there is any change in the items order, then make the request, and then, if the request fails, restore the datavalue with the prevValues array.
The problem is that could get to an infinite loop, because when i restore the old values, the watcher over the original array is triggered again, make the request, fails, restore values and so on.
Is there any way to restore old values passed to a watcher without triggering the watcher again?
Thank you
It would be more reliable to react to drag events to trigger your API calls, rather than watching the data. That way your code only does work in response to user action.
Alternatively, stash a copy of the original array and use something like deep-equal to compare it to the latest value to determine if changed before making a call.

How to select a single line from a leafletjs polyline when clicked?

I have a leaflet map (using Vue and vue2-leaflet) with many predefined nodes and connections between them (stored in a neo4j database). When the user clicks on a node (#mouseup, actually), all its connections are shown as a polyline. I want to be able to click on any of these connections on the map (the lines) and do stuff with it, like delete for example (there would be a popup or something with actions, but that's not important here).
The problem I'm having is that the click event doesn't record the connection ID (or anything that would identify which connection was in fact clicked). I could of course create one polyline for each connection, but I suspect the problem would persist, and it's not a really solution in my case, as I don't know how many connections each node has, and v-for doesn't seem to work with polylines (at least I wasn't able to make it work).
This is the nodes markers code:
<l-marker v-for="mapNode in MapStore.mapNodes"
#mouseup="nodeClick($event, mapNode.index)"
:lat-lng="[mapNode.latLng.lat, mapNode.latLng.lng]"
:key="mapNode.index"
</l-marker>
... and this is the polyline code:
<l-polyline
#mouseup="connectionClick($event)"
:lat-lngs="MapStore.selectedConnections.latlngs"
/>
The nodeClick function populates the MapStore.selectedConnections correctly as the polylines are shown as expected.
The problem is that I don't see anything being passed to the connectionClick function that would identify which connection was clicked, so that I could work with it.
Is that even possible?
Ok, so it turns out I was wrong and v-for works (there was something wrong with my code, I think, but I'm not sure what).
My solution is:
<l-polyline v-for="connection in MapStore.selectedConnections.latlngs"
#mouseup="connectionClick($event, connection)"
:lat-lngs="connection" />
This way it iterates through the connections, generates a separate polyline for each and passes to the connectionClick function the latlngs of the clicked connection.

Add eleObjs to collection

I'm using different collections of edges which are switched in CY based on user interactions so in every moment only one of these collections is in CY instance. I need to create new elements in one of this "remote" collections directly from JS object data and I can't figure how to do it other than create new edges with cy.add(eleObjs) and then remove these elements from CY.
Is there a way how to create CY elements from JS object (eleObj) other than with cy.add(eleObj)? I tried eles.add(eleObj) but it doesn't work.
I thought about creating a separate CY instance only for this purpose but I don't know if it's the best solution and one of the problems is that in this case I would also need to synchronize the nodes between CY instances in order to be able to create new edges.
You can think of having a removed node as being analogous to a file being in the trash in your filesystem. You wouldn't create removed nodes, just as you wouldn't create new files in the trash.
Add your elements to the graph, as you normally would. You can set a class with display: none on the elements you don't want displayed. You can also perform layouts on only the subset of the graph that's visible via eles.layout().
Explanation: Having detached elements that are not yet associated with a graph is inconsistent with the model. And creating elements without an associated graph wouldn't buy you any performance gains -- as the elements wouldn't hold anything more than the JSON you already had. And it wouldn't buy you any convenience -- as you couldn't do anything with the elements and cy.add( elesJson ) is just as convenient as cy.add( preexistingEles ).

Skrollr: Multiple instances

I have two columns that I would like to animate separately with a trigger. As I understand it: Skrollr only allows one instantiation on a page. Does anyone know if it's possible to have multiple instances that can be turned off and on?
I've started a working example here:
The grey column will activate the Skrollr instance when clicking on its "Activate!" button. (The "Destroy!" button will remove its instance.)
I would like to isolate the Skrollr animation to just the grey column, but as you can see in this example, the yellow/orange column is also being activated.
Three ways
Remove/add the data attributes between the destroy/init calls and only add them to the elements you want
Use two constants, defined as a function and toggle them between 0 and 1e6 (or something really large). Now the elements with the large one will effectively not be rendered (given you're using edgeStrategy reset)
Monkey patch the refresh method (without touching the skrollr code itself). Skrollr uses it internally when using init. Now you can patch it to use leftColumn.getElementsByTagName('*') or all elements in the right column when no parameter is passed. This way initializing will only affect elements inside one of the columns.

programmatically expand a tree inside a dojox.TreeGrid

I have a simple tree grid and i need to programmatically expand a row to show its children. In essence i need to fake the click event that triggers the opening of the tree.
see and example here http://archive.dojotoolkit.org/nightly/dojotoolkit/dojox/grid/tests/test_treegrid_model_lazy.html
I haven't personally used the TreeGrid, but from the API docs, it looks like you want to use the expandoFetch(rowIndex,open) function with the open parameter as true:
myTreeGrid.expandoFetch(0,true);