Giter Site home page Giter Site logo

sgratzl / cytoscape.js-layers Goto Github PK

View Code? Open in Web Editor NEW
52.0 5.0 4.0 5.87 MB

Cytoscape.js plugin for simplified layers (svg, canvas, html)

License: MIT License

JavaScript 7.98% TypeScript 92.02%
cytoscape-plugin cytoscapejs cytoscapejs-extension

cytoscape.js-layers's Introduction

Cytoscape.js Layers Plugin

License: MIT NPM Package Github Actions Cytoscape Plugin

A Cytoscape.js plugin for easy rendering of different layers in SVG, HTML, or Canvas format.

Install

npm install cytoscape cytoscape-layers

Usage

see Samples on Github

or at this Open in CodePen

import cytoscape from 'cytoscape';
import Layers from 'cytoscape-layers';
cytoscape.use(Layers);

const cy = cytoscape({
  container: document.getElementById('app'),
  elements: [
    { data: { id: 'a' } },
    { data: { id: 'b' } },
    {
      data: {
        id: 'ab',
        source: 'a',
        target: 'b',
      },
    },
  ],
});
const layers = cy.layers();
layers.nodeLayer.insertAfter('html-static').node.innerHTML = 'Static Test Label';

layers.renderPerNode(layers.append('canvas'), (ctx, node, bb) => {
  ctx.strokeStyle = 'red';
  ctx.strokeRect(0, 0, bb.w, bb.h);
});
layers.renderPerNode(layers.append('html'), (elem, node) => {
  elem.textContent = node.id();
});
layers.renderPerEdge(layers.append('canvas'), (ctx, edge, path) => {
  ctx.strokeStyle = 'red';
  ctx.stroke(path);
});

Usage Examples

Annotation

render a bar and a histogram below each node

Code: annotation

image

Edge Animations

using a animated linear gradient to animate edges in a separate layer

Code: animatedEdges

animated edges

Circular Context Menu

similar to Cytoscape Cxtmenu extension.

Code: ctxmenu

image

HTML Label

similar to Cytoscape HTML Node Label extension

Code: node-html-label

image

Development Environment

npm i -g yarn
yarn set version latest
cat .yarnrc_patch.yml >> .yarnrc.yml
yarn
yarn pnpify --sdk vscode

Common commands

yarn compile
yarn test
yarn lint
yarn fix
yarn build
yarn docs
yarn release
yarn release:pre

cytoscape.js-layers's People

Contributors

dependabot[bot] avatar sgratzl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

cytoscape.js-layers's Issues

Rendering on Every Change

I'm trying to render a dom node for each cytoscape node but they seem to be additively rendering every change. This is what my render function looks like. Do you know what I may be doing wrong? Thanks for the awesome library!

layers.renderPerNode(layers.append("html"), (elem, node) => {
    const classes = (node.classes() as unknown as string[]).join(" ");
    drawNode(elem, node.data(), classes, ["label"]);
});
function drawNode(
  div: HTMLElement,
  data: NodeDefinition["data"],
  classes: string,
  visibleAttributes = ["label"]
) {
  // add the classes
  div.setAttribute("class", ("node " + classes).trim());

  // add the attributes that should be displayed
  for (let i = 0; i < visibleAttributes.length; i++) {
    const attr = visibleAttributes[i];
    const value = data[attr];
    if (value) {
      const span = document.createElement("span");
      span.setAttribute("class", attr);
      span.textContent = value;
      div.appendChild(span);
    }
  }
}
Screenshot 2023-05-19 at 10 20 59 AM

add basic headless support

allowing only canvas layer in combination with a offscreen canvas similar to cytoscape. Only useful in case #1 is supported

Is it Possible to Get at the Canvas Layer that cytoscape Writes to?

Hi there, I was wondering if it is possible to get the layer that cytoscape uses for their rendering? Otherwise is it possible to get a canvas "behind" their render? I'm trying to write to either a canvas or SVG behind the cytoscape render - not just behind nodes or edges

I tried this - but canvasLayer is undefined:

		// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
		const layers = cy.layers( );
		const canvasLayer = layers.canvasLayer;

Screenshots / Sketches

Context

  • Version: 2.3.1
  • Browser: chrome

Additional context

Layers doesn't seems to be removed when node is (probably my fault..)

GIF worth thousand words :

ezgif-2-4226096eaf

I'm using latest release of this awesome plugins and I'm figuring out that if I don't use queryEachTime: true, the layers doesn't seems to be deleting when I delete node. In the GIF we can see it by loading another graph but I've the same problem when trying to delete a single node by hand. I must be missing something, can you help me please ?

Sidenote: the reason I try to avoid using queryEachTime is that when graph have around 500 nodes, zooming, panning start to became a bit laggy. When a set it to false, it's ok.

Here's my messy useEffect :

  useEffect(() => {
    if (!graphRefCtx.current) return
    layersRef.current = (graphRefCtx.current as FixMeLater).layers()
    if (!layersRef.current) return

    // Only if graph have some nodes
    if (graphRefCtx.current.nodes().length)
      layersRef.current.renderPerNode(
        layersRef.current.append('html'),
        (elem: HTMLElement, node: NodeSingular) => {
          if (!node.data('note') && !node.data('image')) return

          let html = `
            <div class="graph-icon-wrapper"
              data-dimmed=${node.style('opacity') == 0.2}
              style="width: ${node.width()}px; height: ${node.height()}px;"
            >
          `

          // If node has a note
          if (node.data?.('note')?.length > 0) {
            html += `              
              <div class="graph-icon note" style="
              height: ${
                // Return at least 8px, or 1/3 of node height, or maxium 20px
                Math.max(7, Math.min(Math.floor(node.height() / 3.3), 15))
              }px;          
              border-color:${getIconColor('sticky-note')}">
                <img src="${getIconToString('sticky-note', '')}" />
                </div>
              `
          }

          // If node has an image
          if (node.data?.('image')?.length > 0) {
            html += `              
              <div class="graph-icon" style="
              height: ${
                // Return at least 8px, or 1/3 of node height, or maxium 20px
                Math.max(7, Math.min(Math.floor(node.height() / 3.3), 15))
              }px;
              
              border-color:${getIconColor(node.data('type'))}">
                <img src="${getIconToString(node.data('type'), '')}" />
                </div>
            `
          }

          // If node has a 'seeNote' class
          if (node.hasClass('seeNote')) {
            html += `
              <div class="visibleNote"
                style="left:${node.height() + 5}px;"
              >
                <p>${node.data('note')}</p>
              </div>
            `
          }

          elem.innerHTML = html + '</div>'
        },
        {
          position: 'center',
          transform: 'translate(-50%,-50%)',
          // uniqueElements: true,
          // queryEachTime: true,
        },
      )
  }, [currentGraph.id])

Offset of custom canvas position in exported graphics

Use the renderPerNode() method to draw the canvas first, and then use the png() method with the configuration option full=true to export the entire graphics. However, when exporting the entire graphics, the canvas may experience position offset.

updateOn renderer not working for renderPerEdge

When I try to pass the "{updateOn: "render"}" prop to renderPerEdge, nothing gets rendered at all. When I dont pass a value it gets rendered but does not update on rerender. the property does work as expected on the renderPerNode method.
This example does not render anything at all:

    layers.renderPerEdge(layers.append('canvas'), (ctx, edge, path, start, end) => {
      ctx.strokeStyle = 'red';
      ctx.stroke(path);


    }, {updateOn: "render"});

Expected behavior

Same behaviour as for the renderPerNode method

Context

  • Version:
    ^2.4.1
  • Browser:
    Chrome Version 116.0.5845.180

How to renderPerEdge from Source to Target Positions

If edges have arrows, the path when using renderPerEdge goes from edge.sourceEndpoint() to edge.targetEndpoint(). Is it possible to render the path from edge.source().position() to edge.target().position()? It seems straightforward if the path is "straight" but not sure how to apply it to "bezier" style. Is there a way to achieve this or maybe consider an option for fullPath?

add support for PNG export

It would be great if the library supports exporting the layers along with the graph

issues

  • Canvas .. oik
  • SVG ... what about css styles, font faces
  • HTML ... CSS + there is a workaround using SVG foreignObjects

"ctxmenu" link in readme is wrong.

hi, I found your repo while i'm looking for about cytoscape.js

I think ctxmenu link in the repo's readme file is wrong.
the link is ctxmenu.ts, but file name is cxtmenu.ts
html file name is too.

I think you should change the link in the readme file ctxmenu.ts to cxtmenu.ts

I don't know if I can create a pull request, so I'm leaving an issue.
it's trivial.

Screenshots / Sketches

readme link

if you click ctxmenu link

404

you can see 404

Context

  • Version:
  • Browser:

Additional context

How can I reduce the redrawing of the canvas?

I created 4 canvas layers using the insert method and then used the renderPerNode method to draw the canvas. I used queryEachTime=true because I needed to update the custom canvas every time it was redrawn. When there is a large amount of data, dragging or scaling the canvas will feel too laggy. How can I use methods like requestAnimationFrame to reduce the redrawing of the canvas?

How to restyle with renderPerEdge

Hello,

How can I change the style after calling renderPerEdge? Example, changing the color between red and blue using two buttons. It seems to rerender additionally for each click if I call below code on button click.

layers.renderPerEdge(customLayer, (ctx, edge, path) => {
  ctx.strokeStyle = btnColor;
  ctx.stroke(path);
});

The HTML canvas layer has bugs thats halts the rendering of the badges at correct places

We use cytoscape-layers plugin for rendering the informational badges with each node. We were using version 2.1.0 for a very long time, but since it had some unpredictable bugs and extra amount of re-rendering involved, we had to move to the latest version of this plugin. We had started using v2.3.0, but with the html layer it has got some serious bugs that are blocking the functional properties of our badges. In the code, there has been some calls to variables whose references aren't resolved giving uncaught errors, catching those errors block the behavioural properties of badges.

This is the error we get in production compiled build:
Screenshot 2022-11-28 at 3 05 42 PM
This error is arising from here:

this.cy.one('render', () => {
this.updateOnRenderOnceEnabled = false;
this.update();

fixing this particular error, the line 69 contains this.update(); which throws further error of update is not a function.
This has been the error with the v2.2.0 also.

The cytoscape badge in our UI looks like this: Screenshot 2022-11-28 at 3 19 32 PM
on changing the position of node, the position of badge doesnt change and stay at the same place.

To Reproduce

const createBadge = (nodeId, render, cy,) => {
  /** @type {LayersPlugin} */
  const layers = cy.layers();

  layers.renderPerNode(
    layers.append("html"),
    (elem, node) => {
      if (node.data("id") === nodeId) {
        render(node, elem);
      }
    },
  );
};
  1. layers.append("html") creates an html layer and render process has the styling config for it.
  2. On changing position of node, it throws an error as described above.

Expected behavior
On changing the position of the node, the badge should move at the correct place.

Screenshots

Context

  • Version: 2.3.0 and 2.2.0
  • Browser: Any

Additional context

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.