New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Export to SVG extension #639
Comments
Yes, this has been considered. The reason it's not there currently is that we didn't want to maintain a separate SVG renderer that only gets used for export.
|
I'm trying to use SVGCanvas and the renderTo function. I'm running into an issue where cytoscape.js calls
and SVGKit implements:
where elem becomes centerX and tx becomes centerY. What would be the proper modification on the SVGKit side to properly pass the context? Also, SVGKit does not implement setTransform, but has its own currentTransformationMatrix and transformations attribute. I'm trying to understand SVGKit's transformation handling better. |
Maybe a different SVG library would be worth exploring? If I recall correctly, SVG expects transforms to be on groups ( |
Do you know another SVG library that could do the trick? It was my mistake that I instantiated an SVGKit instead of an SVGCanvas. The translate/scale transformations worked then fine. However, the library does not implement e.g. the fillText method to draw text . Adding a dummy fillText method to SVGCanvas let me create an SVG with the correct transformation, but other attributes (e.g. stroke width of cytoscape nodes) were not rendered correctly out of the box. |
I don't know of any libraries off the top of my head, so it would probably require more research. Another alternative in the short term is to use a high-res PNG. Maybe we could add/document some options for |
Indeed, options to specify dimensions with |
Hi all, SVGCanvas.prototype.transform = SVGCanvas.prototype.translate; ... and filtering the resulting SVG DOM to fix up small issues, for example:
These were easy to fix, fortunately, with a bit of ad-hoc post-processing. The code is here: Hope it helps others out there. Best, Albert |
@acardona You may want to package your code as a reusable SVG extension @unidesigner I've added a ticket for specifying zoom in |
Hi @maxkfranz , my workaround stopped working. Now, all paths rendered are like arrowhead paths--with the properties still correct as if they were the expected edges, arrowheads and node circles. Any ideas what could be going wrong? We use cytoscapejs 2.2.8. |
I think that with the new performance enhancements and new features, we use APIs that are not supported in those canvas-to-svg libs. Probably, the most stable and least invasive way to export to SVG would be to add a SVG option to the canvas renderer. This would involve adding a SVG option to the canvas renderer and adding SVG generating code to each of the low-level draw functions: (1) node Then the renderer would be renamed to something other than "canvas". Because the canvas renderer handles interaction on a low level, interaction with the SVG graphs would be free and probably much more performant than adding listeners on SVG elements. The main tricky part is reusing SVG elements for performance. I don't have time to look at this now, but I could fork the unstable branch if someone is interested in trying to get SVG output from the renderer. And I would be able to help out a bit if needed. |
We recently found out that the SVG export was broken, but couldn't really find a commit that caused this. Even commits that were known to work in the past suddenly failed. As it turns out (after stepping for quite a while through Cytoscape and SVGKit) does Cytoscape use Path2D to cache paths if it is available. SVGKit, however, is not able to use it and silently fails to draw paths if Cytoscape uses Path2D. This in turn makes our export function crash. The reason why this didn't show up earlier is that Chrome only recently marked Path2D to be not experimental anymore and made it available in the global namespace. Firefox, had it enabled for quite some time already, but we apparently never tested the SVG export in it. It now works there as well. This is related to the discussion in cytoscape/cytoscape.js#639.
Extending the canvas renderer would be nice indeed. If time permits I might have a look at it. The linked commit was in response to @acardona, because I fixed the workaround to work again. Like described in the commit message, it was Path2D which suddenly became a problem: The Chrome browser made it available by default. Cytoscape uses it for path caching as it seems, but SVGKit (which we use) can't deal with it. So I monkey-patched Cytoscape for the export to not use Path2D for the export and it works. |
I noticed that in the recent versions, an option for JPG export has been added in. Is there any hope that an SVG option will also get implemented soon considering this issue was created several months ago? |
Unfortunately, it would be a very large undertaking and I'm not sure whether it will fit into the next release -- given the extensive changes needed in the renderer. It also would double maintenance costs of the renderer for little pragmatic benefit over high-res PNGs. You could use @tomka's method and indeed his change to disable If you're interested in native support in the renderer sooner, I can review a PR that covers the changes I've mentioned earlier. |
Is it possible to have an example code that uses the SVGcanvas approach as developed by acardona and tomka? I am a rookie in javascript and had difficulty in implementing the svg export functionality. Thanks a lot in advance. |
Hi @miskar, the commit linked right before my last comment in this issue contains the changes needed to make it work (at least for us). You basically need to do the following:
|
I've tried the solution from @tomka , but ran into an error with setTransform (which isn't implemented in SVGKit as mentioned by @unidesigner). How did you get around this? |
I've tried |
I'm also getting some error's when trying to convert canvas to svg with canvas2svg.js
So i added this piece of code to make sure a path always starts with an "M". on line 515 of canvas2svg.js d=d.replace(/^L/, 'M'); i'm using Canvas 2 Svg v1.0.6 |
When I use canvs2svg I do not get errors. The first tests however give me a svg that is filled with PNG objects for each node (our nodes have SVG backgrounds). Is cytoscapeJS rendering background SVG as PNG? In that case there is no use for exporting to SVG, because it will always contain bitmaps. This is my code, which does not yet deliver a good SVG anyway.
|
Yeah we noticed the same. Cytoscape caches previously rendered elements as images. We had some success with overriding the caches during SVG export so that cache look-ups would always fail, which in turn causes the actual drawing routines to be called. However, this also didn't allow previous hack to work completely due to some problems with SVGCanvas. Since we only need to export relatively simple nodes and edges and their labels, we wrote our own SVG exporter in the end: On the calling side, all Cytoscape nodes and edges are walked and rendered one by one. Luckily Cytoscape caches some rendering information, so we barely need to do any math ourselves (for now): Depending on how complex your graph is and the features you use, a similar approach might work for you. |
This project will use a similar approach with new calculated rendered values in 3.1: The GSOC project (if accepted) will give a good initial version of a SVG export extension. It will probably support all rendering features in 3.1. For core versions beyond that, the extension will probably require community PRs for new rendering features added to the core. |
Is there any update on svg export? My apology if it is already supported through an extension. |
As far as I know there is no update. There are two roads that people seem to follow:
I tried the first route, because the second one is like building a new graph library for svg, including styling etc. I found out the cytoscape uses a lot of bitmap caching for speed, and as you can read above, people have tried to hack the renderer to forget the caches. What I did was just create a new cytoscape instance, fill this with the same elements - cy2.json(cy1.json()); - and render this to the pseudocanvas. This kind of worked, but not enough. The real problem in our project was, that we use SVG background images for nodes. These are rendered by CytoscapeJs using canvas.drawImage, with as argument an . At this point, any SVG paths are already turned into bitmaps, so the final SVG will contain a bitmapped image in the right dimensions for the current zoom. Not scalable at all... So I am ready to give up on this. The alternative might be finding a good way to export a PNG in a given resolution. The only thing I can think of right now (using route 1) is make the cytoscape renderer render svg images not through an image tag, but by converting the SVG into canvas. Maybe through Path2D (https://developer.mozilla.org/en-US/docs/Web/API/Path2D/Path2D) or some library? |
@jelmerjellema I try your way to use your code
it has no error happend, but it just output and svg with base64 encode image |
Trying to use any of the automatic canvas-to-svg conversion libs isn't going to work. It was only semi-working when cyjs just directly drew everything with the canvas fill/stroke apis. Now cyjs is more advanced. In future, cyjs will use webgl in places. At this point, using a canvas-to-svg is unrealistic and hacky. The only way to have this working is to build a svg exporter extension that builds up svg objects based on the stylesheet and the other computed style values (like bezier points). Please keep further discussion in this thread on the topic of an exporter extension for svg. |
@maxkfranz I just downloaded cytoscape and it seems like this is a feature on the current release. Might be suitable to close this issue. Thanks for providing this feature! |
@zfrenchee I don't see any mention of this in the release notes or other documentation of cytoscape.js. Are you maybe confusing cytoscape.js and cytoscape? The former is a JavaScript library while the latter is a standalone desktop app. See also http://manual.cytoscape.org/en/stable/Cytoscape.js_and_Cytoscape.html |
My mistake @VGSebastian! |
Hi, I just arrived to the conversation, but I would also in investigate using dagre graphlib / dot file format .(https://github.com/dagrejs) file format. Since the library already renders to dagre, would not be possible to extract the .dot file or graphlib representation ? . If so then it could be translated to a .doc file or to a .good quality svg. Dagre itself won't render but this project http://viz-js.com/, (emsripten port of graphbi) will render graphlib/.dot to svg Again, I'm new on these libraries and don't know the status of the project although the demo looks nice, but it could help people that just need to transform graphs offline. Regarding this, my advice would be not to invest trying to transform canvas/bitmaps to svg..My two cents. will try to investigate more, thanks |
Write an extension that builds up svg objects based on the computed style of each of the elements and returns a root svg element.
Using an automatic canvas-to-svg library will not work.
Original content follows:
Would be wonderful to be able to export to SVG, completing this fantastic library that is cytoscapejs. Is an export to SVG perhaps in the roadmap?
The text was updated successfully, but these errors were encountered: