9von10 / ngx-cytoscapejs

Angular 13+ Cytoscape.js Wrapper
MIT License
16 stars 5 forks source link

How to Integrate cytoscape-cxtmenu Extension with ngx-cytoscapejs? #21

Closed GhandchiMorteza closed 2 months ago

GhandchiMorteza commented 3 months ago

First of all, thank you for the ngx-cytoscapejs library—it's been very helpful for my project!

I'm relatively new to Angular and I'm trying to integrate the cytoscape-cxtmenu extension with ngx-cytoscapejs, but I've run into some issues and I'm not sure how to proceed. Could you provide an example of how to correctly set up and use a Cytoscape.js extension like cytoscape-cxtmenu within an Angular component using ngx-cytoscapejs?

9von10 commented 3 months ago

Hello,

you can register extensions within the coreChanged event output of the component. I've provided a full example using cytoscape-cxtmenu below.

Best regards

# Install dependencies
npm install --save ngx-cytoscapejs cytoscape cytoscape-cxtmenu

# Install types
npm install --save-dev @types/cytoscape @types/cytoscape-cxtmenu
<!-- app.component.html -->
<cytoscapejs
  [cytoscapeOptions]="cytoscapeOptions"
  (coreChanged)="coreChanged($event)"
  id="cy"
></cytoscapejs>
// app.component.scss
#cy {
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  z-index: 999;
}
// app.component.ts
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
// Import dependencies
import { CytoscapejsComponent } from 'ngx-cytoscapejs';
import cytoscape, { Core, CytoscapeOptions } from 'cytoscape';
import cxtmenu from 'cytoscape-cxtmenu';

// Register extension
cytoscape.use(cxtmenu);

@Component({
  selector: 'app-root',
  standalone: true,
  // Import component
  imports: [RouterOutlet, CytoscapejsComponent],
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss',
})
export class AppComponent {
  // Cytoscape data
  cytoscapeOptions: CytoscapeOptions = {
    style: [
      {
        selector: 'node',
        css: {
          content: 'data(name)',
        },
      },

      {
        selector: 'edge',
        css: {
          'curve-style': 'bezier',
          'target-arrow-shape': 'triangle',
        },
      },
    ],
    elements: {
      nodes: [
        { data: { id: 'j', name: 'Jerry' } },
        { data: { id: 'e', name: 'Elaine' } },
        { data: { id: 'k', name: 'Kramer' } },
        { data: { id: 'g', name: 'George' } },
      ],
      edges: [
        { data: { source: 'j', target: 'e' } },
        { data: { source: 'j', target: 'k' } },
        { data: { source: 'j', target: 'g' } },
        { data: { source: 'e', target: 'j' } },
        { data: { source: 'e', target: 'k' } },
        { data: { source: 'k', target: 'j' } },
        { data: { source: 'k', target: 'e' } },
        { data: { source: 'k', target: 'g' } },
        { data: { source: 'g', target: 'j' } },
      ],
    },
  };

  // Add desired functionality after the core has been build
  coreChanged(core: Core): void {
    // Extend type as cxtmenu is not a known property of Core
    const coreWithCxtMenu = core as Core & { cxtmenu: any };

    // Setup context menu
    coreWithCxtMenu.cxtmenu({
      selector: 'node, edge',
      commands: [
        {
          content: 'text1',
          select: function (ele: any) {
            console.log(ele.id());
          },
        },
        {
          content: 'text2',
          select: function (ele: any) {
            console.log(ele.data('name'));
          },
        },
        {
          content: 'text3',
          select: function (ele: any) {
            console.log(ele.data('name'));
          },
          enabled: false,
        },
      ],
    });

    coreWithCxtMenu.cxtmenu({
      selector: 'core',
      commands: [
        {
          content: 'bg1',
          select: function () {
            console.log('bg1');
          },
        },

        {
          content: 'bg2',
          select: function () {
            console.log('bg2');
          },
        },
      ],
    });
  }
}