Showing/Hiding child nodes and links in Highcharts Networkgraph - javascript

I've built a network graph with Highcharts and I'm struggling to find a way to easily "expand" or "show" a node's children. The problem I've got is that the way the data is declared is very linear. It doesn't really have much of a hierarchy.
Here's a pen of what I have so far https://codepen.io/anon/pen/xvGMwa. The issue I have is that the "links" aren't associated with the nodes. So I can't easily find a group of nodes and their links and hide/show them.
What I'd like is for it to start off with just the first 4 nodes and then be able to click an action on the node to show/hide its children. I'd ideally do this with CSS.
The nearest I've found is this example but it's not really what I want:
point: {
events: {
click: function() {
this.remove();
}
}
}
Weirdly, the example from Highcharts here https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/series-networkgraph/data-options/ has ids on the links. But my example doesn't. I don't know why that is? I think if I had ids on my links then it'd be easier to find them and hide/show them.

By clicking on the node you can find its links in point.linksTo and point.linksFrom arrays.
To show and hide them just use Highcharts.SVGElement.hide() and Highcharts.SVGElement.show() methods. Check demo and code posted below.
Code:
series: [{
...
point: {
events: {
click: function() {
var point = this;
if (!point.linksHidden) {
point.linksHidden = true;
point.linksTo.forEach(function(link) {
link.graphic.hide();
link.fromNode.graphic.hide();
link.fromNode.dataLabel.hide();
})
} else {
point.linksHidden = false;
point.linksTo.forEach(function(link) {
link.graphic.show();
link.fromNode.graphic.show();
link.fromNode.dataLabel.show();
})
}
}
}
}
...
}]
Demo:
https://jsfiddle.net/BlackLabel/9drzxj2L/
API reference:
https://api.highcharts.com/class-reference/Highcharts.SVGElement#hide
https://api.highcharts.com/class-reference/Highcharts.SVGElement#show

Related

Bootstrap tooltip gets stuck if element changes when visible

I am using Bootstrap 5.1.3 (in Rails). Our application consists of dynamically loaded data, that is not always the fastest to load (some complicated SQL queries / huge amounts of data to make calculations with).
We use tooltips on different elements to show extra information / indicate (click)actions. Tooltips are added like this.
On the element that should get the tooltip:
data-bs-toggle="tooltip" data-bs-placement="top" title={question.questionDescription}
In that Bootstrap file:
componentDidUpdate(previousProps, previousState)
{
// Enable all tooltips.
TooltipHelper.enableTooltips([].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]')));
}
And then TooltipHelper:
static enableTooltips(targets)
{
var enabledTooltips = targets.map(function (target) {
return new bootstrap.Tooltip(target, { trigger: 'hover' });
});
}
The tooltips work, but don't always go away. My guess is that when a tooltip is shown (because hovering over something) and then that element (or a parent of that element) gets changed, for example the content of it, the tooltip stays there. No matter if I click somewhere of hover over other elements.
I've tried adding a delay within the enableTooltips()-function. This seems to work, but the needed delay is too big. Also, it still breaks when elements are dynamically added and content is loaded, when the page isn't reloaded.
My hacky solution:
static enableTooltips(targets)
{
setTimeout(function() {
var enabledTooltips = targets.map(function (target) {
return new bootstrap.Tooltip(target, { trigger: 'hover' });
});
}, 5000);
}
Anyone know of a solution? Thanks

How to run a jQuery function only for child elements?

I'm trying to collapse all child comments including the parent comment when some clicks on the icon nested inside parent comment.
With below jQuery code I was able to get the comments box collapse but now the comments located inside another section are also getting collapsed.
jQuery code -
$('.comment-toggle pre').on('click', function(e) {
$(".single-comment-wrapper .comment-text, .single-comment-wrapper .comment-bottom, .single-comment-outer .child-comment ").slideToggle('fast', function() {
if ($(this).is(':visible')) {
$(".comment-toggle pre").text('[–]');
} else {
$(".comment-toggle pre").text('[+]');
}
});
});
$('.comment-toggle pre').on('click', function(e) {
$('.single-comment-wrapper .left-side').slideToggle('fast');
});
Since HTMLand CSS was too long. I've created a codepen. Below is the direct link to it.
https://codepen.io/anon/pen/Vzrvbm
Thanks in advance.
The structure of your divs makes this tricky, I've been playing around on the fiddle for ~10mins and have come up with this - its heading in the right direction but not perfect...
$('.comment-toggle pre').on('click', function(e) {
$(this).parents('.single-comment-wrapper').next().slideToggle('fast', function() {
All the plus and minuses change because currently your code is targeting classes, it needs to change to be relative to the +/- clicked so $(this). etc
Update you jQuery to search elements relative to your clicked element:
$('.comment-toggle pre').on('click', function(e) {
// find main comment element
var rootComment = $(this).closest('.single-comment-wrapper');
// hide child comments of current comment
var children = rootComment.parent().find('>.child-comment');
children.slideToggle('fast');
// hide left part
rootComment.find('.left-side').slideToggle('fast');
// hide current comment
rootComment.find('.comment-text').toggle('fast', function() {
if ($(this).is(':visible')) {
rootComment.find(".comment-toggle pre", this).text('[–]');
} else {
rootComment.find(".comment-toggle pre", this).text('[+]');
}
});
});
Also, if you can change markup to include children elements in the context of the main comment element it would be much more easier to work with. Tree-like view based on ul would simplify markup and reduce amount of HTML elements.
I think, you should use different classes for divs. Because when you click .content-togle class, javascript code executes actions for all .single-comment-wrapper .comment-text, .single-comment-wrapper .comment-bottom, .single-comment-outer .child-comment classes.

Elements out of scope?

I am having some trouble with elements being outside scope or something but I am not getting any errors so I am not really sure how to fix it. I've shrunk up my code below to include what is relevant.
(function(){
var zdf = {
theme : $('#zdf_theme')
};
zdf.setupPopup = function(){
zdf.loadThemes();
}
zdf.loadThemes = function() {
zdf.theme
.editableSelect({
effects: 'slide'
})
.on('select.editable-select', function(e, li) {
zdf.theme.attr("data-value", li.attr('value'));
});
});
}
}();
Hopefully I've provided enough code to identify the problem but basically everything is working up until the line
zdf.theme.attr("data-value", li.attr('value'));
It doesn't seem to select the object zdf.theme
If I replace it with the actual selector $('#zdf_theme') it works fine.
The editable select is this code base https://github.com/indrimuska/jquery-editable-select
Any input would be great!
Solution... editable select was replacing my input so I needed to redefine it after initializing the editable select.

Highchart drillup issue

I am trying to drill up using my own button but having difficulties.
JSfiddle with multi drilldown
$( "#backbtn" ).click(function(e) {
setChartC(name, categories, data, '', 1);
alert(chartC.xAxis[0]);
});
I have levels, how can I access the drilldown.level?
exporting: {
enabled: true,
buttons: {
customButton: {
text: 'Go Back',
onclick: function () {
var drilldown = chartC.drilldown;
alert(chartC.level);
}
}
}
Cant seem to access the level as i got drill down. is there any way I can access the level
You can use the native Highcharts back button. You can see an example here (link author here).
However, if you want to add a custom button, I don't believe that Highcharts have an easy way for that. If you find that I'm wrong, please correct me.
So, to add a custom back button, you need to track what is the current chart that you are showing. Knowing what is the current, you could look into a dictionary to find which level it is. To get the current chart, you can track the click events:
plotOptions: {
column: {
point: {
events: {
click: function () {
console.log("I'm at: " + this.drilldown.name)
}
}
}
}
}
Regarding the custom back button, look this JSFiddle.
Add this HTML:
<input type="button" id="backbtn" value="Back">
And this JS:
$("#backbtn").click(function(e) {
setChart(name, categories, data);
});
Since the variables name, categories and data were defined with the values of the top-level chart, clicking in this button will restore to the top-level.
If you create a tree object with all charts and their name/categories/data info, and if you know the current chart, you can set the Chart with its parent data to implement the custom back button.

Hover function in js spills over

I have set up my page so that when the user hovers over an image a text shows up and some bubbles. There are eleven images of fish and each one has its own text and bubble. I made sure that there is no overlap in the divs containing the fish, but when one hovers over a particular image the text of some of the other images show up too. This is too distracting since the user would want to see one text at a time. How can I solve this issue? Here is the link to the page: http://arabic001.com/colors
I'm curious myself as to what the common solution is to this problem.
When I run across this situation I use hoverIntent plugin for jquery.
if you went this route, you would change each .mouseOver(),.mouseOut() to the following:
from this
$('#fishBlue').mouseover(function() {
$('#bubblesBlue').toggle('slow');
$('#textBlue').toggle('slow');
});
$('#fishBlue').mouseout(function() {
$('#bubblesBlue').hide('slow');
$('#textBlue').toggle('slow');
});
to this
$('#fishBlue').hoverIntent(function() {
$('#bubblesBlue').toggle('slow');
$('#textBlue').toggle('slow');
});
}, function() {
$('#bubblesBlue').hide('slow');
$('#textBlue').toggle('slow')
});
note
that the hoverIntent plugin requires at least jquery 1.5.1
other tip
I would abstract things a bit more, why rewrite the same thing for each fish.
perhaps use classes
$('.fish').hoverIntent(function() {
$(this).next('.bubble').toggle('slow');
$(this).next('.text').toggle('slow');
});
}, function() {
$(this).next('.bubble').hide('slow');
$(this).next('.text').toggle('slow')
});

Categories