Using HTML instead of SVG within d3.js - javascript

I'm building a graph in d3.js and appending almost 30-60 circles along with 2 lines with each refresh. I find that this is slowing down in the browser, causing significant performance issues.
Would it be better to append html and use images within my css instead of drawing circles?
Also, how would I go about doing this?

I have a few examples of using D3.js with pure HTML here:
http://phrogz.net/js/d3-playground/#StockPrice_HTML
http://phrogz.net/js/d3-playground/#BoxMullerDistribution_HTML
http://phrogz.net/js/d3-playground/#MultiBars_HTML
As you can see from the code, you do this by just…doing it. Create the HTML elements you want by name and set either the attributes or CSS properties on them.
For example, to create an image of a circle you might do:
var imgs = d3.select("body").selectAll("img").data(myData);
imgs.enter().append("img").attr("src", "circle.png");
imgs.exit().remove();
As for whether or not this will be faster than SVG…probably a little faster, but not by much. I suspect that either your computer/browser is slow, or you may be doing something wrong in your code (e.g. accidentally destroying and re-creating certain elements). Without seeing an example of your problem, however, we can only guess.

Related

Why is my browser freezing while doing a counting for child elements inside a container div using jQuery?

I am using this jquery GanttView library to generate a Gantt Chart - https://github.com/thegrubbsian/jquery.ganttView
After the Gantt has been generated, I am executing following jQuery code to count child elements inside the ganttchart generated html:
$('.ganttview-grid').children().length
But it is freezing the browser to about 40 seconds and there aren't really much child elements inside the container (about 460 child elements exist inside this div recognized by $('.ganttview-grid').
Can someone tell me, how much data is too much for jQuery handling or reading, or is there a faster way to compute this without browser freeze?
I've tried with the sample page:
http://thegrubbsian.github.io/jquery.ganttView/example/index.html
and the script that you posted doesn't showed any problem (these are only 17 childs). Generally I've used jQuery to retrieve list of thousand or ten thousands elements without any problem. Are you really sure that it's this line to freeze your browser ? try placing a return in the line below to be sure that the problem is not some place after this call.
Generally working with the DOM is slow but not so slow that you can feel an operation like retrieving 500 elements. A simple way to speedup it is to store those elements when you draw it or to infer them from your starting data. They are number of elements that you passed to jQuery Gantt to draw and count those javascript elements is way faster than parsing the generated DOM. Try posting your code and we can help you about this.
Last test, I've never done a benchmark maybe this is faster:
$('.ganttview-block').length
Hope this helps

How to draw a graphic outside the browser/document?

A line graph is necessary for the purpose of my extension in an web game online.
I want to do something like this:
The intention is that this graph should be OUTSIDE of the DOM/browser, because if I put this inside the game document, they will know that this line has been put into the DOM with a simple call $("#rareLineGraph").length > 0 and they will detect it, and they should not know.
I tried it with frames, but are very uncomfortable (windows)
Some suggestions please ?. Thank you very much
You can in principle draw outside the browser with a separate program operated via Native Messaging, but that would be quite difficult and over-complicated. That is, however, the only approach that fully corresponds to your requirements.
As a suggestion, you can hide your graph from such a simple inspection by using a random ID, or even skipping using an ID and just keeping a reference to the created element in a variable. Also, inserting your node into random places in the document structure and using absolute positioning will obfuscate it further. It will be harder (but not impossible) to detect.
Other than that, I don't think there are many ideas that can help. Chrome renderer looks only at the DOM, and there's no API to create any kind of overlay. DOM can be hidden from the outer document with Shadow DOM techniques, but as far as I know the shadow root element will still be visible to the page.

How can I fix the Scaling and Rotating of an Inkscape SVG in FabricJS?

I am having some trouble with scaling and rotation of SVG images with FabricJS.
I've been working on an icon builder for my website. A user can add layers, select a shape for that layer, then set a number of options such as coloring and stroke width. I populate the possible "shapes" and, for maximum flexibility in the shape's complexity, I am using SVG files that I have created with Inkscape. I use the loadSVGFromURL functionality in FabricJS to handle loading the file onto my canvas.
The problem is when I load some (seems to be most) of these SVGs to the canvas then try to use the handles to scale and rotate the image, the rendered result is not appearing as expected: Octagon SVG Image and Action Results.
On that image, don't worry about the "sliced" edges, that's just the editor's boundaries. After loading my octogon.svg to the canvas, it looks right. When I rotate, it gets messed up. I rotated to the right and downward and the image moved to the left and upward. Then, when I scale, it moves vertically the opposite direction.
I have tried programmatically changing these settings and it behaves the same way. I've read several posted questions here and on newsgroup discussions, but nothing got me a solid solution.
One very close solution was using an optimization tool to remove some transformation data that is apparently not liked much by fabric (that tool being found here http://petercollingridge.appspot.com/). It seemed to work, but not for every image, this one included. In fact, regardless of the optimization options I chose, the tool altered the octagon so much, it wasn't really usable as an octogon. That tool is also reference in this existing question: 10470508 (issue-with-svg-display-rendering-in-fabric-js)
I have saved the SVG out of Inkscape in various formats: Inkscape SVG, plain SVG, and Optimized SVG - none made any difference. I also tried Simplifying the Path prior to exporting in all of these formats - again, no difference (though for some shapes, this did seem to work).
I have read many bugs and the related discussions on GitHub with Kangax involved and tried things like the centeredRotation property and origin points on the objects.
I noticed that Inkscape's x,y of 0,0 is the bottom left corner which I thought was a little odd and thought maybe that had something to do with the scaling at least. To attempt fixing it from that point of view, I set flipY on the object, but that didn't work at all. It appeared very far above the editor panel. It almost feels like the transform point is somewhere way above the bounding box. But I cannot verify that. All the settings I check seem like they are set correctly.
I did try a hexagon made in Illustrator and it seemed to work, but I do not have Illustrator at my disposal and to say that is a "solution" is somewhat undesirable. Perhaps this is better logged as a bug, but with all the related chatter, I am somewhat hoping that it is resolved and I just have not found the right combination of settings or processes to follow. I really need to be able to use Inkscape for these. Kangax has pointed out that Inkscape SVGs are more troublesome for FabricJS, but he goes on to say they are getting better. So perhaps this can help with another step forward.
I have also reviewed the code itself on GitHub, but cannot seem to pin point what exactly I would need to change to fix this; though, I am not really sure where the point of failure is - fabric, my settings, or my SVG file.
UPDATE 2/21/2014 10:27PM EST
I began digging into the SVG file structure, comparing the ones giving me trouble with the ones that are working. It definitely does seem like the problem is due to a "transform" attribute being present on a path, container, or other object tag. The optimization processes I've tried should have removed them, but I still have not found a solid solution that just works in all cases. I'll keep you updated.
I don't know much about fabricjs and Inkscape, but using the svg DOM the following will apply for rotation and scale transformations applied individually to an element: Maybe you can apply this. If you want to rotate+scale an element your can append the transformation strings or use transformation matrix. Hope this helps
var bb=elem.getBBox()
var bbx=bb.x
var bby=bb.y
var bbw=bb.width
var bbh=bb.height
var cx=bbx+.5*bbw
var cy=bby+.5*bbh
//----rotate from center of elem---
elem.setAttribute("transform","rotate(angle "+cx+" "+cy+")")
//---scale: translate center to(0,0)+scale+translate back---
elem.setAttribute("transform","translate("+cx+" "+cy+")scale(myScale)translate("+(-cx)+" "+(-cy+")")
Would it be advantageous to load your svg files as xml using XMLHttpRequest? You could then treat them as xml, work on them, then insert them as SVG by cloning them.
pretty seamless, I think. You can extract elements from XMLdoc and insert them as svg by merely cloning them. Also you can include a DIV in your html and dump the entire xml response text into it as its innerHTML. Then everything is available for DOM workings.
var XMLdoc
function loadSVGasXML()
{
var SVGFile="my.svg"
var loadXML = new XMLHttpRequest;
function handler()
{
if(loadXML.readyState == 4 && loadXML.status == 200)
{
//---responseText---
var xmlString=loadXML.responseText
//---mySVGDiv.innerHTML=xmlString ---
//---DOMParser---
var parser = new DOMParser();
XMLdoc=parser.parseFromString(xmlString,"text/xml").documentElement ;
}
}
if (loadXML != null)
{
loadXML.open("GET", SVGFile, true);
loadXML.onreadystatechange = handler;
loadXML.send();
}
}
Like the other issues posted about this, the problem was still in the individual transformations on the paths. The online solutions I found never worked as well as I needed them to; at least not with SVGs from InkScape. Saving the SVG in a different type right out of InkScape also did not impact the end result. Some shapes, when "simplified", were fine; however, it was not consistent enough. So, I set out to develop a solution.
After reading SVG file structure documentation, I created this specifically to handle InkScape SVGs. Some SVG commands are not handled, but so far, I have not noticed an issue with the few missing commands (which were excluded simply due to time).
EvilEye Games - InkScape SVG Transform Remover
In the end though, I just decided to use some free SVGs from another website. So it was all for not for me. However, I was able to figure it out and fix the problem. So figured maybe this would come in handy for someone else. Its not perfect, but it does what it needs to.

SVG text element speed

I am building a web application which relies on svg heavily. For the reference, I am using raphael js library to deal with all of it.
In this particular case I have implemented something that mimics a scrollbar and moves bunch of svg features (~500 elements) across the screen. Part of those features are <text> (~100) elements. Other elements include <rect>, <image> and <path> elements.
So, I noticed that my application is not really very snappy on my laptop, and is down right annoying to deal with on an ipad, due to speed. However, whenever text elements are removed or ignored during scrolling, it immediately gets up to decent speed.
I tried doing some speed tests (very crude ones, using new Date().getTime()) and discovered that it takes ~10 ms to move all the elements except for <text> elements, however it takes ~120 ms when <text> elements are included.
I believe this happens because each letter is rendered as a vector shape and it takes loads of processing power to calculate what exactly is obstructed by such a complex structure.
Is it possible to just embed the text, so the text is rendered as raster graphic, and not as shapes? Or improve performance of rendering text in any other way?
I do not need background transparency, and I do not use any fancy fonts.
You can prerender the text using Canvas and embed images into the SVG. I don't know how this compares to text element rendering in general, but for our demos this works quite well (see the drop shadow in the "hierarchy" example - they are rendered into canvas first and then replicated and referenced from within the SVG).
Note that these demos also make heavy use of virtualization, i.e. if you zoom into the image and only some of the elements are actually inside the viewport, the others are removed from the SVG, which gives a huge speedup.
The demos do a lot more than just moving the elements around, so it should be easy to get the same or even better performance.
I don't know how to do this with raphael, though, but I believe you should be able to put the data url from the canvas image into the SVG with raphael, too.
Paper.print() according to the Raphael site
Creates path that represent given text written using given font at given position with given size
Essentially your text is converted to a path. Obviously this has performance issues.
Probably best to stick to using Paper.text()
UPDATE
So not content with just dishing out advice I have set up some tests on http://www.jsperf.com. They can be used to compare the differences in performance to animate and transform different types of Raphael objects.
If you run these on your iPad it should show if text elements are really much slower to move. One other thing to note is that, at least in the tests I ran, paper.print() and paper.text() were not that different in terms of performance.
Run the tests on jsperf

Appending repeated images in web page with javascript

I want to use javascript to append some images to a div in the web page. Each new instance of the image will be in a loop that includes something like
pic=new Image()
pic.src="./images/xyz.jpg"
document.getElementById(div1).appendChild(pic)
This works but because there are lots and lots of repeated images chosen randomly, I think that each repeat will be fetching an image from the server that I already have and I wonder how to avoid this overhead.
There are various techniques on the web for cloning object so you might think that something along the lines of
appendChild(pic1)
pic2=clone(pic1)
appendChild(pic2)
would do the trick but it seems that the cloning includes the .src so there would be no saving. In any case, only one image appears!
Any Ideas?
Actually, if the picture has been downloaded once, the browser will not download another copy. So you can add as many of the same image as you like.
When reloading the two pages, I don't notice any difference in the rendering time (with Google Chome).
My guess is that you're using a browser with a slow JavaScript engine and/or DOM implementation. Also appendChild() can be slow. Create the innerHTML as a large String and assign it in one go. Alternatively, use CSS to display the images (using background-image and a fixed size) and just create empty DIVs. That should be faster than creating hundreds of image objects.
If you need it even faster, try CSS sprites.

Categories

Resources