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

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.

Related

Chartist.js - Pass Label Value into Bar Click

I am using the Chartist.js graph api to create a graph and I need each bar to click to a location. This is easy enough, but I also need to pass the corresponding label value if possible.
var graph = new Chartist.Bar('.ct-chart', {
labels : ['L1','L2','L3'],
series : [1,2,3]
});
So, I have added an onclick method to each bar, but need it to get the corresponding label value to pass to the location page. Example:
graph.on('created', function() {
$('.ct-bar').click(function () {
var val = $(this).attr('ct:value');
if (val > 0) {
window.location = 'location/?label=BAR LABEL HERE (eg: L1)';
}
});
});
Would anyone know if this is possible?
Many thanks.

How to execute dc.js renderlet or pretransition functions in dc-tableview.js without rerendering whole table?

I am trying to conditionally format a dc-tableview.js table.
This works for the first page with following code:
tableView1.on('pretransition', function (tableView1) {
// tableView1.on('renderlet', function(tableView1){
var SecretKPIs = tableView1.selectAll('td.SecretKPI');
console.log('renderlet function 2');
SecretKPIs.each(function (d, i){
if (this.innerText >= MediumValueThreshhold && this.innerText < BadValueThreshhold){
this.classList.add('MediumValueFont');
} else if (this.innerText >= BadValueThreshhold){
this.classList.add('BadValueFont');
};
})
})
When I change to the next page or change the sorting of a column - the values change but the conditional formating does not apply anymore.
Any idea how I could apply the conditional formating again?
If I use the render function tableView1.render() - the table does not apply the filter of the page or the sorting.
Any help is highly appreciated.

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 interaction on click event

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;
});

label inside combobox and conditional multiselect

I am building a pretty combobox with checkboxes and conditional entries. Everything works out alright, except for two features that I cannot figure out how to implement.
1) I would like to move the label inside the combobox, make it shift the values to the right, and appear in a slightly gray color.
2) I would like the value to ignore certain entries (group headers) selected. Those entries are there for functionality only - to select/unselect groups of other entries.
The entire project is in the zip file. You don't need a server, it's a client base app. Just download the archive, unpack, and launch app.html in your browser.
http://filesave.me/file/30586/project-zip.html
And here's a snapshot of what I would like to achieve.
Regarding your second issue, the best way I see is to override combobox onListSelectionChange to filter the values you don't want:
onListSelectionChange: function(list, selectedRecords) {
//Add the following line
selectedRecords = Ext.Array.filter(selectedRecords, function(rec){
return rec.data.parent!=0;
});
//Original code unchanged from here
var me = this,
isMulti = me.multiSelect,
hasRecords = selectedRecords.length > 0;
// Only react to selection if it is not called from setValue, and if our list is
// expanded (ignores changes to the selection model triggered elsewhere)
if (!me.ignoreSelection && me.isExpanded) {
if (!isMulti) {
Ext.defer(me.collapse, 1, me);
}
/*
* Only set the value here if we're in multi selection mode or we have
* a selection. Otherwise setValue will be called with an empty value
* which will cause the change event to fire twice.
*/
if (isMulti || hasRecords) {
me.setValue(selectedRecords, false);
}
if (hasRecords) {
me.fireEvent('select', me, selectedRecords);
}
me.inputEl.focus();
}
},
And change your onBoundlistItemClick to only select and deselect items in the boundlist not to setValue of the combo:
onBoundlistItemClick: function(dataview, record, item, index, e, eOpts) {
var chk = item.className.toString().indexOf('x-boundlist-selected') == -1;
if ( ! record.data.parent) {
var d = dataview.dataSource.data.items;
for (var i in d) {
var s = d[i].data;
if (s.parent == record.data.id) {
if (chk) { // select
dataview.getSelectionModel().select(d[i],true);
} else { // deselect
dataview.getSelectionModel().deselect(d[i]);
}
}
}
}
},
Regarding your first issue, it is easy to add the label using the displayTpl config option. But this will only add the text you need, without any style (grey color, etc). The combo is using a text input, which does not accept html tags. If you don't need the user to type text, than you may want to change the combo basic behavior and use another element instead of the text input.

Categories