D3.JS treemap inconsistent zoom behavior - javascript

I'm trying to do a menu of sorts with a d3.js treemap. It mostly works, but I'm having a few glitches that I can't pinpoint.
Basically, sometimes my chart doesn't zoom correctly and instead of seeing the children take the whole SVG area, they show up "unzoomed".
I suspect it must have something to do with the animation's timing vs. some data manipulation for hiding/showing the different nodes, but can't actually figure it out. Other thing I thought might be borking up the behavior relates to the click events being registered by both "parent" and "children" nodes.
I have a similar example setup in JSBIN.
So, I was wondering how I could register/unregister click events in the parent/child nodes on zoom - if that's even the problem - and also if there was a simpler or less-error prone way to change the nodes' visibility.
Any help is welcome!

Well, this might be a bit unorthodox, but I found a way to overcome this.
Basically, instead of trying to mess around with event registering/unregistering, I simply ran the zoom only if the click wasn't from the node at the current zoom level.
So, in my zoom function, I wrapped the zoom handling in an if check:
function zoom(d) {
if(node!=d){
// the rest remains the same
}
}
Either way, I still think that this was happening due to the source elements where the click events were coming from being overlapped in the SVG area - simply put, the click event was being triggered by several overlapping elements, being the first (topmost) in the SVG tree order triggered inadvertently.
Here's a working version.
Hope this helps someone else!
EDIT: This solution isn't perfect, though. Now sometimes the click just doesn't do anything - But it's better than borking the UI. If anyone has other ideas, they're welcome.

Related

Adding a significant amount of text elements in D3 causes performance issues

I'm developing a D3 application that utilizes a lot of text. Since there is alot of text elements, panning around using D3 zoom causes some lag. Is there a way in which I can improve the performance of my application? I'm happy to hear any suggestions, you guys might have. I've been thinking about paginating my data and detecting pan events but my UI is very complex and the user has the freedom of placing things the way he wants so I am not sure how to go about implementing a pan/pagination solution.
Such an open question is bound to get very opinion-based answers, and without more context you're also bound to get some useless ones, but here you go: it depends on what you want and what you mean by "a significant amount".
Supposing that significant amount is > 1000 elements, consider using canvas instead of SVG. Sure, if you can click on individual text nodes, that's more of a hassle, but it should be really good at panning/zooming.
If that is not possible, look at your code. Are you repositioning all text nodes individually? If so, place them all inside one g node and give that node a transform and zoom. In other words, make that node responsible for all global movement, and place the text nodes only relative to each other.
If that is also not possible, consider removing text nodes if they're outside the bounds of the SVG. Repositioning invisible nodes takes a lot of computation power, be smart about it. This is probably the most complex solution, so try it last.

Advice on how to accomplish background scrolling in all directions

I'm trying to figure out what is the best way to begin creating an effect like (https://howifight.53.com) where the background is scrollable/draggable in all directions.
I know the technology behind this is pixi.js however, I can't seem to dig out how this effect is achieved. Any pointers in a good direction would be awesome.
First, you need to set up the page and styles.
You need a containing element to contain the HTML you're moving around (using overflow:hidden). Then you need an element within that to actually move around with JavaScript.
Then you need to implement some drag/drop functionality. Capture mousedown, then capture mousemove and update on each requestAnimationFrame, then stop dragging with mouseup is triggered.
That's a very basic overview, but I've mocked up an example for you to look at: jsFiddle. Feel free to ask any questions.

hidden/not displayed elements receiving mouse over events

I'm pretty new to event-handling inside svgs and there is a little weirdness happening here. I'm doing an infovis where I build an interface and want to display different column-graphs.
That's rather easy and working pretty nicely.
But I'm using hover-events to show the actual numbers when hovering a rect. it works with the one chart I'm generating first. But even though that chart is hidden (I tried both: visibility: hidden and display: none properties) the one that's drawn first still gets the event.
Do I need to remove that one completely in order to generate a new one? So should I better work with separate SVGs and have an external interface, hiding the different svgs?
Any advice/best-practice would be welcome!
Thanks already!
Suse
The other way of hiding things is to push them off the screen, as with hidden iframes. Just give them a negative x/y position. That should take care of mouse-over issues.

Bootstrap Tooltip Following Animated Element

I have a D3.js chart similar to this. As the user drills down into the chart I utilize the bootstrap tooltip to display the nodes name. I am currently tracking the node by call the tooltip show method over and over which cause the tooltip to re-render at the new location.
setInterval(function(){
$(node).tooltip('show');
}, 100)
My concern is that calling this function like this will cause performance issues. Can anyone suggest a better way to accomplish this or give me some insights on to performance issues when using the setInterval function this way?
From your description it sounds like what you are trying to do would be better accomplished by listening for discrete changes in state rather than time. I haven't worked with D3.js, but even something as simple as listening for clicks on <circle> elements would be a ton more efficient.
JS
$('svg').on('click', 'circle', function () {
$(node).tooltip('show')
})
It looks like D3.js has it's own event framework, but I'm not sure if it supports delegation. Someone more familiar could probably provide a better suggestion to that end.
Finally, depending on how many nodes you show at once, calling tooltip show on all of them could itself generate a performance hit. Tracking which ones open and close each time by storing references could be more efficient. Again, there might be something already in D3.js to handle this, but it's not something I know.

Drag and drop elements into an iframe. Droppable area has wrong coordinates and collisions are wrong

I need to implement drag and drop functionalities in a web application between elements present in a web page, and elements inside an iframe (before you start complaining about iframes, I NEED it for technical reasons, it's not an option).
I have elements in the page that can be dragged into target droppable elements inside an iframe.
I've managed to do it with both jQuery UI and YUI, though both libraries present the same problem: the target element (droppable target) coordinates are misinterpreted, the drop area considered by both libraries is wrong and does not represent the actual droppable object, hence the collisions between the dragged object and the dropped element are messed up entirely. It's like the library sees the droppable element positioned in another place from where it effectively is.
I think this is due to the iframe not being positioned on top-left of page, but in the middle. I think this because I've read many people complaining about this issue and the problem went off if the iframe was top-left positioned. Someone suggest that the coordinates of the droppable element may be calculated based on screenX and screenY, instead of clientX and clientY, and this may be the cause of the issue, not taking into consideration the elements are inside an iframe, and so the coordinates differ between other elements outside the iframe.
So, since it seems there's no way to fix this directly using the library functionalities, and I really don't have time to try every library avaiable out there, I'm thinking about fixing the issue by modifying (patching) the internal functions of the library in question.
The questions are:
1) Did someone experience this behavior before, and managed to fix the issue? Or, is there a library which is able to do this flawlessly?
2) Is there some way to fix this issue using the methods and functionalities of the library itself? And if not,
3) Does somebody know which part of the library calculates the droppable area coordinates, so that I can fix it as a last extreme option?
Thanks in advance, even the smallest help will be appreciated!
EDIT
This fiddle demonstrate the problem. Try to move the green square inside the red square (which is inside an iframe). You will notice the collision between the two squares is wrong.
http://jsfiddle.net/DQdZ9/23/
This is not a "silver bullet" , but I'll go ahead and post this as an answer, but I'm not sure how much value it will have for you. I tracked down a key function in jQuery UI that might be what you're looking for. It's in $.ui.ddmanager (the drag and drop manager), and the function is prepareOffsets. This line:
m[i].offset = m[i].element.offset();
seems to be the one that is setting up the offset for use when the element is actually dropped. This might be a place to fiddle with to adjust the resulting offset based on whether the droppable element is a child of the iframe.
There is another function above it $.ui.intersect that performs the logic to see if the draggable and droppable are intersecting each other.
I'm in the latest release of jQuery UI, and the file is jquery-ui-1.8.14.custom.js on line 2012-2029. If you get the single droppable file itself, jquery.ui.droppable.js, it's on lines 203-220. And these are the dev files, not the min files.

Categories