Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cytoscape add custom image to node with clickable items on it

I am building a charting tool in ember using cytoscape js and I can render chart data however I do not know how to set each node to display with a image that has other images/buttons that function within it. Basically I want it to look like this:

enter image description here

In the image there are two buttons (I will most likely add icons as well) and also there are labels that exist within the node which I don't know how to do either.

Here is the code I currently have.

Template:

<div class="container" >
  <div id="cy"></div>
</div>

Component JS:

import Ember from 'ember';


export default Ember.Component.extend({
tagName: '',

map: Ember.computed('model.map_data', function()
{
 if(this.get('model.map_data')){
   return JSON.parse(this.get('model.map_data').data)
  } else {
   return {};
  }
 }),
cytoscape_data: Ember.computed('model.sub_apps.[]',function() {
var ret = {
        nodes: [],
        edges: []
};
var red = 50;//replace with threshold
var green = 25;//replace with threshold
var _this = this;
this.get("model").map_data.forEach(function(node) {
  var y= 0;
  var x = 0;
  var color = 'green';
  if(node.value >= red ){
    color = 'red';
  }else {
    if(node.value > green){
      color = 'orange';
    }
  }
  var position = _this.get("map")["app" + node.id];
  if(position){
    x = parseInt(position.split(',')[0]);
    y = parseInt(position.split(',')[1]);
  }
  ret["nodes"].push({
          data: {
                  id: node.id,
                  label: node.name,
                  node_type: 'app',
                  tooltip: node.description,
                  color: color
          },
          position: {
                  x: x,
                  y: y
          }
  });
  if(node.relations) {
    node.relations.forEach(function(parent) {

      ret["edges"].push({
        data: {
          source: node.id,
          target: parent.app_to_id
        }
      });
    });
  }
});

 return ret;
}),

didInsertElement: function() {
 this._super();
 var cy = cytoscape({
 container: Ember.$('#cy')[0],
 elements: this.get("cytoscape_data"),
 zoom: 1,
 pan: { x: 0, y: 0 },
 fit: true,
 randomize: false,
 layout: {
      name: 'preset'
    },
  style: [
    {
      selector: 'node',
      style: {
        'content': 'data(label)',
        'text-opacity': 0.8,
        'text-valign': 'center',
        'text-halign': 'right',
        'width': '200px',
        'height': '200px',
        'border-color': 'green',
        'border-width': 3,
        'border-opacity': 0.5,
        'background-image': 'url(../assets/images/base_node_image.svg)'
        // 'background-color': 'data(color)'
      }
    },
    {
      selector: 'edge',
      style: {
        'width': 6,
        'border-color': 'green',
        'target-arrow-shape': 'triangle',
        'target-arrow-color': 'red',
        'opacity': 1,
        'curve-style': 'bezier'
      }
    },

    {
      selector: ':selected',
      style: {
        'background-color': 'orange',
        'opacity': 1
      }
    },

    {
      selector: '.faded',
      style: {
        'opacity': 0.0,
        'text-opacity': 0
      }
    },
  ],

});
Ember.run.scheduleOnce('afterRender', this, function(){
  cy;
});
cy.on('click', 'node', function(evt){
  var node = evt.target;
  console.log( 'clicked ' + node.data('label') );
   });
  },
});

The chart this code renders looks like this:

enter image description here

I can display a background-image however it displays in a circle which I dont know how to get rid of. The color of the circle is determined by some logic above which was a test to see if it works and that is fine (going to use that for one of the icons on the node later). I can also display the label for the node but I don't know how to display that within the node itself.

Any help is appreciated, thanks!

like image 892
Surep Avatar asked Dec 07 '17 19:12

Surep


1 Answers

It is not so trivial to achieve what you want if not impossible. You say "set each node to display with a image that has other images/buttons that function within it."; this means you need to render html into a canvas; because what cytoscape puts as drawing area is an HTML canvas.

See @maxfranz's (author of cytoscape.js) for a relevant question; where he basically says "It's not possible to render HTML in a canvas, nor would you probably want to for performance".

This means putting html buttons, URLs might not be what you desire. See also MDN Web Docs for further explanation.

That said; I think you can still manage to achieve what you want; but with a different approach. You can make use of cytoscape's compound nodes. You can define the images and buttons as simple nodes and define compound nodes as surrounding containers. I have created a working example for you at the follwoing github repository.

The final result I got is as follows:

enter image description here

I hope this helps.

like image 175
feanor07 Avatar answered Nov 15 '22 08:11

feanor07