i added to meteor cytoscape : infinitedg:cytoscape
i have very basic meteor app:
hello.js http://pastebin.com/2frsHc9g
hello.html http://pastebin.com/10EYyJ74
but i am not able to make it work
here is error i can see in console of web browser:
on rendered zavolana hello.js:9 ss [object Object] debug.js:41
Exception from Tracker afterFlush function: debug.js:41 TypeError:
Cannot read property 'addEventListener' of undefined
at CanvasRenderer.registerBinding (infinitedg_cytoscape.js:17127)
at CanvasRenderer.load (infinitedg_cytoscape.js:17283)
at new CanvasRenderer (infinitedg_cytoscape.js:13419)
at $$.fn.core.initRenderer (infinitedg_cytoscape.js:7527)
at new $$.Core (infinitedg_cytoscape.js:6592)
at Function.$$.init (infinitedg_cytoscape.js:75)
at cytoscape (infinitedg_cytoscape.js:58)
at HTMLDivElement. (infinitedg_cytoscape.js:2808)
at Function.jQuery.extend.each (jquery.js:384)
at jQuery.fn.jQuery.each (jquery.js:136)
do you have please some "hello world" of combination of cytoscape and meteor ?
problem was with wrong library installed via meteor
after i installed correct cytoscape library, it is working
correct is cytoscape:cytoscape
here is minimal and working example:
JS
sit = "" //hlavni objekt
if (Meteor.isClient) {
Template.graf.rendered = function() {
// Meteor.defer(function() {
//setTimeout(function(){
console.log("on rendered called");
//var divcy = $('#cy');
// console.log("ss " + divcy);
sit = cytoscape({
container: document.getElementById('cy'),
ready: function() {
console.log("network ready");
updateNetworkData(sit); // load data when cy is ready
},
style: cytoscape.stylesheet()
.selector('node')
.style({
'content': function(e) {
return e.data("name")
},
'font-size': 12,
'text-valign': 'center',
'color': 'white',
'text-outline-width': 2,
'text-outline-color': function(e) {
return e.locked() ? "red" : "#888"
},
'min-zoomed-font-size': 8
// 'width': 'mapData(score, 0, 1, 20, 50)',
// 'height': 'mapData(score, 0, 1, 20, 50)'
})
.selector('edge')
.style({
'content': function(e) {
return e.data("name") ? e.data("name") : "";
},
'target-arrow-shape': 'triangle',
})
});
//})
}
}
if (Meteor.isServer) {
Meteor.startup(function() {
// code to run on server at startup
});
}
function updateNetworkData(net) {
// init Data
var nodes = [{ // node a
group: 'nodes',
data: {
id: 'a',
name:'a'
}
}, { // node b
group: 'nodes',
data: {
id: 'b',
name:'b'
}
}
]
var edges = [{ // edge ab
group: 'edges',
data: {
id: 'ab',
name:'ab',
source: 'a',
target: 'b'
}
}
]
net.elements().remove(); // make sure evything is clean
net.add(nodes);
net.add(edges);
net.reset() // render layout
}
CSS
#cy {
width : 70vw;
height: 50vw;
position: absolute;
}
HTML
<head>
<title>hello</title>
</head>
<body>
<h1>Welcome to Meteor!b</h1>
{{>graf}}
</body>
<template name="graf">
<div id="cy"></div>
</template>
Related
I´m trying to make a tree layout diagram to display an achievements list like the one in minecraft but I can´t find the way to use gojs components on my typescript proyect.
Here is the code:
import go from 'gojs';
import { useEffect, useState } from 'react';
import GoalModel from '../../models/goalModel';
import { ReactDiagram } from 'gojs-react';
const ipcRenderer = window.require("electron").ipcRenderer
function GoalsList(){
const [goalsList, setGoalsList] = useState<GoalModel[]>([])
useEffect(() => {
ipcRenderer.send("getGoals")
}, [])
ipcRenderer.on("goals", (e: any, goals: GoalModel[]) => {
console.log(goals)
setGoalsList(goals)
})
function makeDiagram(){
const $ = go.GraphObject.make;
// set your license key here before creating the diagram: go.Diagram.licenseKey = "...";
const diagram =
$(go.Diagram,
{
'undoManager.isEnabled': true, // must be set to allow for model change listening
// 'undoManager.maxHistoryLength': 0, // uncomment disable undo/redo functionality
'clickCreatingTool.archetypeNodeData': { text: 'new node', color: 'lightblue' },
model: new go.GraphLinksModel(
{
linkKeyProperty: 'key' // IMPORTANT! must be defined for merges and data sync when using GraphLinksModel
})
});
// define a simple Node template
diagram.nodeTemplate =
$(go.Node, 'Auto', // the Shape will go around the TextBlock
new go.Binding('location', 'loc', go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape, 'RoundedRectangle',
{ name: 'SHAPE', fill: 'white', strokeWidth: 0 },
// Shape.fill is bound to Node.data.color
new go.Binding('fill', 'color')),
$(go.TextBlock,
{ margin: 8, editable: true }, // some room around the text
new go.Binding('text').makeTwoWay()
)
);
diagram.layout =
$(go.TreeLayout,
{
layerSpacing: 20,
nodeSpacing:100
})
return diagram
};
return (
<div>
<h1>Objetivos</h1>
<div>
<ReactDiagram //The error shows up here
initDiagram={makeDiagram}
divClassName='diagram-component'
nodeDataArray={[
{ key: 0, text: 'Alpha', color: 'lightblue', loc: '0 0' },
{ key: 1, text: 'Beta', color: 'orange', loc: '150 0' },
{ key: 2, text: 'Gamma', color: 'lightgreen', loc: '0 150' },
{ key: 3, text: 'Delta', color: 'pink', loc: '150 150' }
]}
linkDataArray={[
{ key: -1, from: 0, to: 1 },
{ key: -2, from: 0, to: 2 },
{ key: -3, from: 1, to: 1 },
{ key: -4, from: 2, to: 3 },
{ key: -5, from: 3, to: 0 }
]}
/>
</div>
</div>
);}
export default GoalsList
Im getting the error when I use the ReactDiagram component from gojs in my typescript file.
Anyone has any idea on how to fix it?
Error here
I created a custom element using the jointjs tutorial like this:
CustomRect = joint.dia.Element.define('example.CustomRect', {
attrs: {
rect: {
refX: 0,
refY: 0,
refWidth: '116',
refHeight: '70',
strokeWidth: 1,
stroke: '#000000',
fill: '#FFFFFF'
},
label: {
textAnchor: 'left',
refX: 10,
fill: 'black',
fontSize: 18,
text: 'text'
},
upperRect: {
strokeWidth: 1,
stroke: '#000000',
fill: 'rgba(255,0,0,0.3)',
cursor: 'pointer'
}
}
}, {
markup: [{
tagName: 'rect',
selector: 'rect'
},
{
tagName: 'text',
selector: 'label'
},
{
tagName: 'rect',
selector: 'upperRect'
}]
})
...
let customRect = new this.CustomRect()
customRect.attr({
upperRect: {
refWidth: '116',
refHeight: '10',
refX: 0,
refY: -11,
event: 'element:upperRect:pointerdown'
}
})
Furthermore, I tried adding Ports with the Port API for joint.dia.Element like this:
customRect.addPorts([
{
args: {
y: 30
},
z: 0
}
]);
This does add Ports to my element, but they don't have the functionality they should have, so they're just some circles that do nothing.
The method shown in the Port Tutorial does not work, since I'm not using joint.shapes.devs.Model for my custom element, because then I can't customize it like the joint.dia.Element element (or at least I think I can't).
So, how can I add Ports to a custom element defined with joint.dia.Element that have the functionality they should have (as shown in the Port Tutorial)?
Unfortunately, the documentation does not explain this clear enough. If you want to make the ports interactive you need to set the magnet attribute on them.
const CustomRect = joint.dia.Element.define('example.CustomRect', {
/* ... */
attrs: {
root: {
// Don't allow the root of the element to be target of a connection
magnet: false
}
},
ports: {
items: [{
id: 'port1',
attrs: {
portBody: {
// The port can be a target of a connection
// The user can create a link from the port by dragging the port
magnet: true
}
}
}, {
id: 'port2',
attrs: {
portBody: {
// The port can only become a target of a connection
// The logic can be modified via paper.options.validateMagnet()
magnet: 'passive'
}
}
}]
}
}, {
/* ... */
portMarkup: [{
tagName: 'circle',
selector: 'portBody',
attributes: {
'r': 10,
'fill': '#FFFFFF',
'stroke': '#000000'
// If all the magnets are `true` / `passive` feel free to define
// the magnet here in the default port markup or per a port group
// 'magnet': true
}
}]
});
After reading the ECharts documentation and looking at examples, I haven't found anything that would allow coloring or highlight tree branch when I clicked a specific node and draw a path up to their children leaves.
Basically, I'm trying to do something like this ECharts tree example:
It is theoretically possible, but I did not have time to practice. In general my thought in the next steps:
Subscribe to listen click events for symbol, see events.
Get current (clicked) series and get rid for another series for exclude parents, it's can be done with instance.getModel().getSeries() or instance.getModel().eachSeries(...)
After it we have the only children nodes. Now you can change (with instance.setOption({...})) children leaves' lineStyle and paint it black.
If you do not succeed, I'll try later.
Update
I made what you wanted but code is dirty and not easy for learn, sorry I was hurry. Let me know if you have any question.
var container = document.getElementById('main');
var chart = echarts.init(container);
var data = {
name: "node 1",
children: [{
name: "node 1.1",
children: [{
name: "node 1.1.1",
children: [{
name: "node 1.1.1.1",
value: 721
}]
},
{
name: "node 1.1.2",
children: [{
name: "node 1.1.2.1",
value: 727,
children: [{
name: "node 1.1.2.1.1",
children: [{
name: "node 1.1.2.1.1.1",
value: 727
}]
}, {
name: "node 1.1.2.1.2",
children: [{
name: "node 1.1.2.1.2.1",
value: 727
}]
}]
}]
},
{
name: "node 1.1.3",
children: [{
name: "node 1.1.3.1",
value: 725
}]
}]
}]
};
var option = {
tooltip: {
trigger: 'item',
triggerOn: 'mousemove'
},
series: [{
type: 'tree',
id: 0,
name: 'tree1',
data: [data],
top: '10%',
left: '8%',
bottom: '22%',
right: '20%',
symbolSize: 7,
edgeShape: 'curve',
edgeForkPosition: '10%',
initialTreeDepth: 5,
lineStyle: {
width: 3,
curveness: 0.3
},
label: {
backgroundColor: '#fff',
position: 'left',
verticalAlign: 'middle',
align: 'right',
borderColor: 'red',
borderWidth: 1,
borderRadius: 10,
padding: 10
},
leaves: {
label: {
position: 'right',
verticalAlign: 'middle',
align: 'left'
}
},
expandAndCollapse: true,
animation: false,
}]
};
chart.setOption(option);
var hoverStyle = { lineStyle: { color: 'black' }};
// Traverse each node in tree
function traverse(node, callback){
if(node.children){
callback(node);
node.children.forEach(subNode => traverse(subNode, callback))
} else {
callback(node)
}
}
// Traverse from target node
function traverseFrom(opts){
var defaults = { tree: data, nodeName: null, callback: null, skipStartNode: false };
Object.assign(defaults, opts);
var targetNode = null;
// Find node for start paint
traverse(defaults.tree, node => {
if(node.name === defaults.nodeName){
targetNode = node;
}
});
// Find all children of found node
traverse(targetNode, node => {
if(defaults.skipStartNode && node.name === defaults.nodeName){
// Skip first because it is start branch
} else {
defaults.callback(node)
}
});
}
// Build new config with painted nodes
function buildSeriesConfig(nodes, style){
var seriesConfig = echarts.util.clone(data);
var nodes = [...nodes].flat();
traverse(seriesConfig, node => {
if(nodes.includes(node.name)){
Object.assign(node, style);
}
});
return seriesConfig
};
// General paint function
function paintBranch(chartInstance, nodeName){
var nodesForPaint = [];
var newSeries = null;
var mainOption = null;
traverseFrom({
nodeName: nodeName,
callback: node => nodesForPaint.push(node.name),
skipStartNode: true
});
if(nodesForPaint){
newSeries = buildSeriesConfig(nodesForPaint, hoverStyle)
} else {
throw 'Nodes for paint is not exists'
}
if(newSeries){
chartInstance.setOption({
series: [{ type: 'tree', id: '0', data: [newSeries] }]
}, false);
} else {
throw 'New series config is not builded'
}
};
function isNodeSelected(tree, nodeName){
var status = false;
traverseFrom({
tree: tree,
nodeName: nodeName,
callback: node => {
if(node.hasOwnProperty('lineStyle')) status = true;
},
skipStartNode: true
})
return status
}
function cleanTree(chartInstance){
var clonedData = echarts.util.clone(data);
chartInstance.setOption({
series: [{ type: 'tree', id: '0', data: [clonedData] }]
}, false);
};
chart.on('click', (e) => {
var chartTree = chart.getOption().series[0].data[0];
var nodeSelected = isNodeSelected(chartTree, e.name);
if(nodeSelected){
cleanTree(chart)
} else {
paintBranch(chart, e.name)
}
});
<script src="https://cdn.jsdelivr.net/npm/echarts#4.7.0/dist/echarts.js"></script>
<div id="main" style="width: 800px;height:600px; margin: 100px"></div>
There are 3 nodes in the example,I use modifier key + mousedown then drag,I can select 2 nodes and drag them,the problem is after I release the mouse,I can not see which nodes I have selected.They are not highlight or with shadow or reversed color or with some sign to mark they are selected.
<style>
#cy{
width:600px;
height:800px
}
</style>
<script src="cytoscape.js"></script>
<div id="cy"></div>
<script>
var cy = cytoscape({
container: document.getElementById('cy'), // container to render in
elements: [ // list of graph elements to start with
{ // node a
data: { id: 'a' }
},
{ // node b
data: { id: 'b' }
},
{ // node c
data: { id: 'c' }
},
{ // 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
},
boxSelectionEnabled:true,
panningEnabled: true
});
</script>
You can store the selected node(s) in a variable or array and then add a mouseUp event, in which you highlight the nodes in said variable or array.
http://js.cytoscape.org/#events/user-input-device-events
Here you find the bind for cytoscape (always unbind events before binding them again):
http://js.cytoscape.org/#cy.on
cy.unbind('mouseup');
cy.bind('mouseup',/* 'node', */ function () {});
I am trying to make a graph that, when the page loads, expands all the nodes in the graph out from the root node like a tree, like the opposite of this example. The graph is directed with no cycles and a pre-defined root node.
Right now, I hide all the nodes on the graph. I then run a DFS from the root node. At each child node, I move it to the location of the parent node, and then want to run .animate() with its original position as the destination so that there is a smooth animation. As seen in the code, the .animate() function doesn't pause the rest of the program. Any advice?
var cy = cytoscape({
container: document.getElementById('cy'),
boxSelectionEnabled: false,
autounselectify: true,
style: cytoscape.stylesheet()
.selector('node')
.css({
'content': 'data(id)'
})
.selector('edge')
.css({
'curve-style': 'bezier',
'target-arrow-shape': 'triangle',
'width': 4,
'line-color': '#ddd',
'target-arrow-color': '#ddd',
}),
elements: {
nodes: [
{ data: { id: 'a' } },
{ data: { id: 'b' } },
{ data: { id: 'c' } },
{ data: { id: 'd' } },
{ data: { id: 'e' } }
],
edges: [
{ data: { id: 'ae', weight: 1, source: 'a', target: 'e' } },
{ data: { id: 'ab', weight: 3, source: 'a', target: 'b' } },
{ data: { id: 'bc', weight: 5, source: 'b', target: 'c' } },
{ data: { id: 'cd', weight: 2, source: 'c', target: 'd' } },
]
},
layout: {
name: 'breadthfirst',
directed: true,
padding: 10,
roots: '#a',
}
}); // cy init
var root_id = 'a'
//get root
var root = cy.$('#'+root_id)[0]
//empty collection
var collection = cy.collection()
//hide all nodes except root
cy.ready(function(event){
collection = collection.add(cy.nodes('node[id!="'+root_id+'"]'))
collection = collection.add(cy.nodes().connectedEdges());
collection.style('visibility', 'hidden')
});
var visited_nodes = [root];
function dfs(node) {
//visit node
visited_nodes.push(node)
//for each neighbor w ov f
neighbors = cy.$('#'+node.id()).outgoers('edge')
neighbors.forEach(function (next) {
var next_node = cy.$('#'+next.data().target)
if (visited_nodes.indexOf(next_node) < 0){
//visit each unvisited node
//we will move the target node to the source node, then use .animate() to move the target node back to it's original location
source_id = next.data('source')
target_id = next.data('target')
var node_to_move = cy.$('#' + next.data('target'))[0]
//record the x and y coordinates to avoid messing around for objects. temporary.
var start_position_x = cy.$('#' + next.data('source')).position().x
var start_position_y = cy.$('#' + next.data('source')).position().y
var end_position_x = cy.$('#' + next.data('target')).position().x
var end_position_y = cy.$('#' + next.data('target')).position().y
//move the target node to its start position
node_to_move.position('x',start_position_x)
node_to_move.position('y',start_position_y)
node_to_move.style('visibility', 'visible')
//then animate the target node moving to it's original position
node_to_move.animate(
{
position: {end_position_x, end_position_y}
},
{
duration: 1000,
complete: function(){
node_to_move.style('visibility', 'visible')
// if (e !== undefined){
// e.style('visibility', 'visible')
// }
}
})
//DOESNT WORK WITH THESE COMMENTED OUT, DOES WITH THEM COMMENTED IN/
//I think this means it is a timing problem, with the dsf moving forward without the nodes getting moved
// node_to_move.position('x',end_position_x)
// node_to_move.position('y',end_position_y)
dfs(next_node)
}
})
}
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
}
#eat {
position: absolute;
left: 1em;
top: 1em;
font-size: 1em;
z-index: -1;
color: #c88;
}
<!DOCTYPE html>
<!-- This code is for demonstration purposes only. You should not hotlink to Github, Rawgit, or files from the Cytoscape.js documentation in your production apps. -->
<html>
<head>
<link href="style.css" rel="stylesheet" />
<meta charset=utf-8 />
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<title>Images</title>
<script src="cube/node_modules/cytoscape/dist/cytoscape.js"></script>
</head>
<body>
<div id="cy"></div>
<!-- Load appplication code at the end to ensure DOM is loaded -->
<script src="expand.js"></script>
</body>
</html>
You ran the animations at the same time. Chain animations using promises, e.g. node1.animation().play().promise().then( node2.animation().play.promise() ).then( ... )