How to generate svg client-side with d3 without attaching it to the DOM (using with React.js) - svg

I'm using React.js to build an app, which includes quite a few svg charts. I'm using d3 functions that help in chart creation, such as scales, but then using React to generate the svg elements. Here's a great writeup on the approach: http://10consulting.com/2014/02/19/d3-plus-reactjs-for-charting/
Part of why I'm going down this road was for performance - the first version of the app was too slow. It has a lot of elements and a lot of user-interactivity, all client-side. I'm trying to basically recreate the dc.js library in React.
It's a really fun approach and intuitive (more so than d3 alone IMO). Building axes is tedious though, and d3 does it so nicely. I would love d3 to just be able to output a string of svg elements that represent the axis (and maybe other elements) , and I feed it to React to include in the DOM.
I did see this SO question (How to make d3.js generate an svg without drawing it?) and the answer was to append it in the DOM and remove it, or create a DOM fragment. Those approaches go against the React approach and likely negate the performance benefits of React. I also saw jsdom and phantomjs solutions, which will not work in my case.
Can d3 generate svg without appending it to the DOM?

#Lars is correct if you are using traditional means. However, this is definitely possible with 'jsdom'. This library can simulate the DOM and also allows for string input. Which means you could inject the root element into the fake DOM and get a new window element to manipulate. You could then use D3 without changing it's source and using is like normal.
This would allow for the generation of an SVG.

No. D3 by design operates directly on the DOM through its selections. To have it generate string representations instead without modifying the DOM, you would need to modify its source code (and it would be quite a significant modification).

Related

How to draw custom shapes with draw2d?

I am using draw2d javascript library for drawing predefined shapes and custom shapes in it's canvas.
As I don't have any example made yet, I am trying to copy from it's documentation but doesn't seem to find a good way to research it as it contains a whole lot of it.
Here is the circle example.
http://www.draw2d.org/draw2d_touch/jsdoc_6/#!/api/draw2d.shape.basic.Circle
and here are some more documentation with examples.
http://www.draw2d.org/draw2d_touch/jsdoc_6/
I have premade shapes with html and css and I am trying to drag and drop and render them on canvas like these in this image. Also when dropped, they should have input and output ports too.
Is it possible to convert this html/css to draw2d shapes?
So here this is made possible via extending draw2d's SVGFigure and thus we have ability to provide custom svg to render it as a custom shape.
Below links were useful in this context.
http://www.draw2d.org/draw2d_touch/jsdoc/#!/guide/extending_svg_figure-section-live-example
https://github.com/freegroup/draw2d/tree/master/examples/shape_custom_svg
http://www.draw2d.org/draw2d_touch/jsdoc_6/#!/api/draw2d.SetFigure
https://github.com/freegroup/draw2d/tree/master/examples/shape_labeld
https://github.com/freegroup/draw2d/tree/master/examples/shape_custom_markdown

How to speed up Inline SVG changes

In my hybrid Android app I use inline SVG to display images that are large (of the order of 2Mb) and complex (several hundred SVG elements per image). When I need to change the image I do the following
var puzzle = document.createElementNS(SVGNS,'svg'),
kutu = document.getElementById('kutu');
puzzle.id = 'puzzle';
puzzle.setAttribute('preserveAspectRatio','none');
puzzle.setAttribute('width','100vw');
puzzle.setAttribute('height','85.5vh');
puzzle.setAttribute('xmlns',SVGNS);
puzzle.setAttribute('xmlns:xlink',XLINK);
puzzle.setAttribute('fill-rule','evenodd');
puzzle.setAttribute('clip-rule','evenodd');
puzzle.setAttribute('stroke-linejoin','round');
puzzle.setAttribute('stroke-miterlimit','1.414');
puzzle.setAttribute('viewBox','0 0 1600 770');
puzzle.innerHTML = SVG;
//SVG here is the SVG image content shorn off the outer <svg>..</svg>
if (0 < kutu.children.length) kutu.children[0].remove();
//remove old image, iff any
kutu.appendChild(puzzle);
//append the new image
While this is working the process of displaying the new image is slow. I suspect it is because of the innerHTML assignment above. Recreating through a sequence of createElementNS, puzzle.àppendChild would require me to first parse the incoming raw SVG content etc. Is that the way to go or would there be a faster way to display the content.
Once again for clarity - SVG here is the content of the new SVG image to be displayed shorn of its outer <svg>...</svg> wrrapper.
Just a side note it would probably be better to use setAttributeNS in place of setAttribute for consistency purpose since createElementNS is used, though it might not make a difference in speeding up the SVG image change.
In the case of a native app, a tool like the Android Profiler if using Android Studio 3.0 and higher can be used to analyze performance bottleneck. However since your app is a hybrid app, some sort of performance profiler that's applicable to the hybrid app (Whether it's Ionic or Cordova, etc.) can help to pinpoint where your performance bottleneck is.
Since your app is a hybrid, without knowing the resource capacity of your android app session, the guess is it seems to be a possible cause that it calls something like .setAttribute to set session-level attributes on the fly during the change of the image and the session resource might not be enough, and also the DOM has to perform .innerHTML and appendChild, which are dynamic operations. DOM manipulation is known to be slow.
Conversion of attributes of all the SVGs and store the result in some sort of storage or cache, and when needed, call it from the persistent storage or cache might be helpful.
Or consider using AngularJS to do the SVG change beforehand and preload the SVG images, refer to easily preload images in your Angular app. Here is another similar code to yours except it's using AngularJS to add SVG for starters.
Another simpler way, without changing your code, if you could minify the incoming SVGs beforehand, is to use SVG Optimizer or SVGO, a node.js open source project to compress your SVGs. Quoted from the SVGO link it says:
"SVG files, especially those exported from various editors, usually contain a lot of redundant and useless information. This can include editor metadata, comments, hidden elements, default or non-optimal values and other stuff that can be safely removed or converted without affecting the SVG rendering result." Although the performance gain might not be obvious going this route.

Draw a graphic structure with JSF

I would like to create a JSF web application to display a graphic structure (composed of hierarchical elements organised in a database) where, if possible, the user could eventually zoom in/out, add new elements...
But I haven't been able to identify a single JSF component (or compatible component) to help me do that.
This is what I would like : http://www.yworks.com/products/yfileshtml/demos/Complete/demo.yfiles.graph.orgchart/index.html
But it's not free and not in JSF.
I thought of the PrimeFaces mindmap component, but it is not compatible with IE8 and this is a requirement for my projet...
My second thought was to use RichFaces' Paint2D to manually draw info in rectangles and links between rectangles with calculated coordinates, but this seems a bit complex...
http://livedemo.exadel.com/richfaces-demo/richfaces/paint2D.jsf?c=paint2d
A final thought was to use CSS to display rectangles, but I can't display links and interact with the structure...
Any better idea ?
Thank you for your help !
OmniFaces has a component for creating a hierarchical tree.
Maybe you could use that to display a custom markup, and work out a way to manipulate it with Javascript, in order to get the behavior you want.
If that is not feasible, I'd suggest you to study a little bit of HTML5 Canvas, see what you can do with that. You can get inspired here checking out this is open source (GPL) HTML5 mind map app, the code is at GitHub.

js libraries with fully cross-browser svg manipulation

I have an svg map which I'm looking to add javascript interactions to. In the past I've used RaphaelJS, which worked well. But I'm what alternatives there might be for svg manipulation with js?
One of the problems I don't like is that Raphael JS uses its own proprietary js objects instead of svg. Are there maybe some js libraries that are able to take svg directly and still support vml output where required?

Create a map with clickable provinces/states using SVG, HTML/CSS, ImageMap

I am trying to create an interactive map where users can click on different provinces in the map to get info specific to that province.
Example:
archived: http://www.todospelaeducacao.org.br/
archived: http://code.google.com/p/svg2imap/
So far I've only found solutions that have limited functionality. I've only really searched for this using an SVG file, but I would be open to other file types if it is possible.
If anyone knows of a fully functioning way to do this (jQuery plug-in, PHP script, vector images) or a tutorial on how to do it manually please do share.
jQuery plugin for decorating image maps (highlights, select areas, tooltips):
http://www.outsharked.com/imagemapster/
Disclosure: I wrote it.
Sounds like you want a simple imagemap, I'd recommend to not make it more complex than it needs to be. Here's an article on how to improve imagemaps with svg. It's very easy to do clickable regions in svg itself, just add some <a> elements around the shapes you want to have clickable.
A couple of options if you need something more advanced:
http://jqvmap.com/
http://jvectormap.com/
http://polymaps.org/
I think it's better to divide my answer to 2 parts:
A-Create everything from scratch (using SVG, JavaScript, and HTML5):
Create a new HTML5 page
Create a new SVG file, each clickable area (province) should be a separate SVG Polygon in your SVG file,
(I'm using Adobe Illustrator for creating SVG files but you can find many alternative software products too, for example Inkscape)
Add mouseover and click events to your polygons one by one
<polygon points="200,10 250,190 160,210" style="fill:lime;stroke:purple;stroke-width:1"
onmouseover="mouseOverHandler(evt)"
onclick="clickHandler(evt)" />
Add a handler for each event in your JavaScript code and add your desired code to the handler
function mouseOverHandler(evt) {};
function clickHandler(evt) {};
Add the SVG file to your HTML page (I prefer inline SVG but you can use linked SVG file too)
Upload the files to your server
B-Use a software like FLDraw Interactive Image Creator (only if you have a map image and want to make it interactive):
Create an empty project and choose your map image as your base image when creating the new project
Add a Polygon element (from the Shape menu) for each province
For each polygon double click it to open the Properties window where you can choose an event type for mouse-over and click,
also change the shape opacity to 0 to make it invisible
Save your project and Publish it to HTML5, FLDraw will create a new folder that contains all of the required files for your project that you can upload to your server.
Option (A) is very good if you are programmer or you have someone to create the required code and SVG file for you,
Option (B) is good if you don't want to hire someone or spend your own time for creating everything from scratch
You have some other options too, for example using HTML5 Canvas instead of SVG, but it's not very easy to create a Zoomable map using HTML5 Canvas,
maybe there are some other ways too that I'm not aware of.
Just in case anyone will search for it - I used it on several sites, always the customization and RD possibilities were a perfect fit for what I needed. Simple and it is free to use:
Clickable CSS Maps
One note for more scripts on a site: I had some annoying problems with getting to work a map (that worked as a graphic menu) in Drupal 7. There where many other script used, and after handling them, I got stuck with the map - it still didn't work, although the jquery.cssmap.js, CSS (both local) and the script in the where in the right place. Firebug showed me an error and I suddenly eureka - a simple oversight, I left the script code as it was in the example and there was a conflict. Just change the front function "$" to "jQuery" (or other handler) and it works perfect. :]
Here's what I ment (of course you can put it before instead of the ):
<script type="text/javascript">
jQuery(function($){
$('#map-country').cssMap({'size' : 810});
});
</script>
Go to SVG to Script
with your SVG the default output is the map in SVG
Code which adds events is also added but is easily identified and can be altered as required.
I have been using makeaclickablemap for my province maps for some time now and it turned out to be a really good fit.
I had the same requirements and finally this Map converter worked for me. It is the best plugin for any map generation.
Here is another image map plugin I wrote to enhance image maps: https://github.com/gestixi/pictarea
It makes it easy to highlight all the area and let you specify different styles depending on the state of the zone: normal, hover, active, disable.
You can also specify how many zones can be selected at the same time.
The following code may help you:
$("#svgEuropa [id='stallwanger.it.dev_shape_DEU']").on("click",function(){
alert($(this).attr("id"));
});
Source
You have quite a few options for this:
1 - If you can find an SVG file for the map you want, you can use something like RaphaelJS or SnapSVG to add click listeners for your states/regions, this solution is the most customizable...
2 - You can use dedicated tools such as clickablemapbuilder (free) or makeaclickablemap (i think free also).
[disclaimer] Im the author of clickablemapbuilder.com :)
<script type="text/javascript">
jQuery(function($){
$('#map-country').cssMap({'size' : 810});
});
</script>
strong text

Resources