d3 interaction on click event - javascript

I have a map with d3 circles showing the site locations, as well as a linechart showing the time trend for each of the site. I am trying to make a particular line highlight when a corresponding circle is clicked. Here is the code. I can't seem to connect the siteIDs with the following function:
function highlightLine(id) {
lineGroup.classed("g-highlight", function(d) {
return d.siteID == id.siteID;
});
};

Insert a console.log as shown below, and it should become clearer:
function highlightLine(id) {
lineGroup.classed("g-highlight", function(d) {
console.log(d);
return d.siteID == id.siteID;
});
};
Because you're binding to data that you've run through d3.nest, the id of d that you're interested in is actually d.key not d.siteID, which does not exist on that level. So the boolean inside classed should be
return d.key == id.siteID
That will cause the appropriate trendline's <g> to have a "g-highlight" class, however it still will not visibly color the line. I believe that's because your css rule .g-highlight { stroke:... } applies the stroke to the containing <g> instead of the <path> inside it. You can change that css rule to be .g-highlight path { ... } and that will color the path as you'd like.

To bind the click event in d3 you should select the object with that class and bind the click:
d3.selectAll(".g-highlight").on("click", function(d) {
return d.siteID == id.siteID;
});

Related

Detect onHover being complete on a Chart.js doughnut chart

I have a Chart.js doughnut chart (v2.7.1) and I am looking to set the class of an external element when the user hovers over the relevant chart element
I can use the onHover event within the options.hover of the chart
hover: {
onHover: function (evt, item) {
if (item.length) {
var index = item[0]._index;
var legendElement = $(#get element based on index#);
legendElement.addClass('active');
}
}
}
and this sets the class on the element (legendElement) perfectly but I need to be able to remove the class I set from the element when the user is no longer hovering over the element
Am I using the correct approach? Is there a way to detect that the onHover is complete or that the segment is no longer in focus?
Are you defining an "events" property apart from the "onHover" property? If you add "mouseout" to the list, the "onHover" function will be called in both cases. Check out the documentation for this https://www.chartjs.org/docs/latest/general/interactions/events.html
An example code that might work:
options: {
events: ["mousemove", "mouseout"],
onHover: function (evt, item) {
if (item.length) {
var index = item[0]._index;
var legendElement = $(#get element based on index#);
if(evt.type == "mousemove"){
legendElement.addClass('active');
}else{
legendElement.removeClass('active');
}
}
}
}

D3JS selection selectAll

I have this piece of code :
var series, seriesChildren;
selection.each(function (data) {
series = d3.select(this).selectAll('.my-series').data([data]);
series.enter().append('g').classed('my-series', true);
console.log(data);
seriesChildren = series.selectAll('.seriesChild')
.data(data, function (d) {
return d.x;
});
seriesChildren.enter()
.append('g')
.classed('seriesChild', true);
}
And I don't understand why it gives me the following :
<g class="my-series"></g>
without the children.
It should be :
<g class="my-series">
<g class="seriesChild"></g>
<g class="seriesChild"></g>
...
</g>
I did a console.log(data) and my data is good, it has thousands of elements within it.
It is working by doing seriesChildren = d3.selectAll('.my-series').selectAll('.seriesChild') but not working with seriesChildren = series.selectAll('.seriesChild')
I'm using D3JS v4.
These two statements are diffrent
1. seriesChildren = series.selectAll('.seriesChild')
2. seriesChildren = d3.selectAll('.my-series').selectAll('.seriesChild')
In 1st series is not a DOM element hence seriesChildren = d3.selectAll('.my-series').selectAll('.seriesChild') will not work as you are expecting
whereas in second case d3.selectAll('.my-series') this represent a DOM element and furter d3.selectAll('.myseries').selectAll('.seriesChild') will select another DOM element.

d3.js: Color by group based on user input

I'm a newbie using d3.js to create a multi-level filter plot based on user selections. All filters are working exceptenter link description here the categorical color selection. Colors are defaulting to fluid type (default should be material type) and using the radio button to switch doesn't work. Can anyone help?
https://plnkr.co/edit/yoFCbe?p=preview
function filter_color(){
colored = document.getElementById("color_Filter");
svg.append("circle")
.style("fill", function(d) {
if (colored == 0) {
return color(d["Material group"]);
} else {
return color(d["Fluid type"]);
}
})
}
You're not checking for the actual value of the radio box.
Get the checked/unchecked state and that if statement will run as it should:
colored = document.getElementById("color_Filter")[0].checked; // <= mind here
if (colored == 0) {
return color(d["Material group"]);
} else {
return color(d["Fluid type"]);
}
See https://plnkr.co/edit/gZOIbDgYj6OCs5aM1CV2?p=preview

D3.js ( in Coffeescript) show data on click

I am in the process of creating a bubble chart with D3.js. Now I want it to display a comment in the <h3 id="comment"></h3> tag when I click on each bubble.
Here is my data.csv file:
name,count,group,comment
apple,5,red,"This is the best apple ever."
grape,10,purple,"Grapes are huge."
banana,8,yellow,"Are these bananas even ripe?"
pineapple,1,yellow,"Great for making juice."
...
And in my viz.coffee, I have:
idValue = (d) -> d.name
textValue = (d) -> d.name
groupValue = (d) -> d.group
commentValue= (d) -> d.comment
Originally, I use the following code to display the name of the bubble when clicked:
updateActive = (id) ->
node.classed("bubble-selected", (d) -> id == idValue(d))
if id.length > 0
d3.select("#comment").html("<h3>#{id} is selected.</h3>")
else
d3.select("#comment").html("<h3>Nothing is selected</h3>")
How should I change it, so that when you click on the bubble, the comment displays instead?
I tried:
updateActive = (id) ->
node.classed("bubble-selected", (d) -> id == idValue(d))
if id.length > 0
d3.select("#comment").html(d.comment)
else
d3.select("#comment").html("<h3>Click on a bubble to read its comment.</h3>")
But it doesn't seem to work, because d is undefined, which I can see why, but I'm not sure what I should do. Please help.
Even though I'm not completely sure of your code I think this should work:
updateActive = (id) ->
node.classed("bubble-selected", (d) -> id == idValue(d))
if id
for x in data when idValue(x) is id
d3.select("#comment").html(commentValue(x))
else
d3.select("#comment").html("<h3>Click on a bubble to read its comment.</h3>")
Here data is what you supply to d3 through .data().

How are enter() and exit() detecting updated data in D3?

I am building a small UI where the user has to select a point on each of the two SVGs shown.
These points coordinates are then shown under the SVGs. I would like to achieve this using D3's data-binding with the enter() and exit() methods. However it seems that D3 doesn't always update the part where I display the points coordinates, even if I call the enter() method on the bound elements. When removing data, the exit() methods works however.
Here is the main code :
function showPoints() {
var coordinatesElements = d3.select('#coordinates').selectAll('.point').data(points);
coordinatesElements.enter().append('div').classed('point', true)
.text(function (d) {
var textParts = [];
if (d.firstSvg) { textParts.push('first : '+JSON.stringify(d.firstSvg)); }
if (d.secondSvg) { textParts.push('second : '+JSON.stringify(d.secondSvg)); }
return textParts.join(' - ');
})
.append("span")
.classed('removeCalibrationPoint', true)
.html(" X")
.on('click', function(d, i) {
points.splice(i, 1);
showPoints();
});
coordinatesElements.exit().remove();
}
I have created a JSBin fiddle that demonstrates the problem.
The first problem is that you have an empty div of class point in your HTML. This will be selected by the .selectAll('.point') and cause the first element in your data not to show up.
The second problem is that you're not handling the update selection -- in some cases, you're not adding new data, but modifying existing data. The following code updates the text for the data in the update selection.
coordinatesElements.text(function (d) {
var textParts = [];
if (d.firstSvg) { textParts.push('first : '+JSON.stringify(d.firstSvg)); }
if (d.secondSvg) { textParts.push('second : '+JSON.stringify(d.secondSvg)); }
return textParts.join(' - ');
});
Complete demo here. Notice I've simplified the code slightly by setting the text only on the update selection -- elements added from the enter selection merge into the update selection, so there's no need to do it twice.

Categories