add Dagre D3 note or descriptor outside of node - javascript

Is there an easy way to add a note or discriptor to a node? So the node label is in the node, but a secondary descriptor is above or below the node?
I am thinking I might need to create the nodes and then loop over then and try to add the descriptor, but thought I would see if there is an easier way.
const g = new dagreD3.graphlib.Graph({ compound: true })
.setGraph({})
.setDefaultEdgeLabel(() => {});
g.setNode('N1', {
label: 'N1',
shape: 'circle',
});
d3.selectAll('g.node').each(function(d) {
...
});
edit: Ended up doing something similar to what
KateJean answered with. Used the label to create an overlay.
'label=<' +
'<table border="0">' +
'<tr>' +
'<td height="16"></td>' +
'</tr>' +
'<tr>' +
'<td cellspacing="0" cellpadding="0" height="30" width="100">' +
`<font color="${color}"><b>${category}</b></font>` +
'</td>' +
'</tr>' +
'<tr>' +
`<td>${name}</td>` +
'</tr>' +
'</table>' +
'>'

I forked this a while ago to play around with (not my original work, so apologies to the original author), but I think the solution in this fiddle may be what you're looking for.
You can define a header element and a body and use that as your "label" element. Here, bootstrap is used for the styling.
https://jsfiddle.net/KateJean/9gtezLfq/
var g = new dagreD3.graphlib.Graph().setGraph({});
for (var i = 0; i < 7; i++) {
var html = '<div class="panel panel-primary">'
html += '<div class="panel-heading">' + i + ' Panel</div>'
html += '<div class="panel-body"><p style= "color: black;">Test<p></div>'
html += '</div>'
g.setNode(i, {
labelType: "html",
label: html,
padding: 0
})
}

Related

.html() jQuery function return NaN

I have
<div id="tablePlace"></div>
And
if ($('#radioOne').is(':checked') == true) {
$("#tablePlace").html(" ");
$("#tablePlace").append(htmlTable); //htmlTable is a string that contains an html table code
loadNestedTable(temp);
}
It works but in the div I find NaN.
If I comment $("#tablePlace").append(htmlTable);, NaN doesn't appear.
Why?
UPDATE
htmlValue code:
var tab = '<table id="decretoSingolo">'+
+'<thead>'
+ '<tr>'
+ '<th>Ente</th>'
+ '<th>CUP</th>'
+ '<th>Decreto impegno</th>'
+ '<th>Data decreto impegno</th>'
+ '<th>Importo impegno</th>'
+ '<th>Finanziato MIUR</th>'
+ '<th>Importo pagato</th>'
+ '<th>Importo in pagamento</th>'
+ '</tr>'
+ '</thead>'
+ '<tbody>'
+ '</tbody>'
+'</table>'
+'<div style="display:none">'
+ '<table id="dettagliDecretoSingolo">'
+ '<thead>'
+ '<tr>'
+ '<th>Progressivo pagamento</th>'
+ '<th>Data decreto</th>'
+ '<th>Numero decreto pagamento</th>'
+ '<th>Tipo pagamento</th>'
+ '<th>Importo in pagamento</th>'
+ '<th>Nota decreto</th>'
+ '</tr>'
+ '</thead>'
+ '<tbody>'
+ '</tbody>'
+ '</table>'
+'</div>';
htmlTable value:
<table id="myTable">NaN<tr><th>Ente</th><th>CUP</th><th>Decreto impegno</th><th>Data decreto impegno</th><th>Importo impegno</th><th>Finanziato</th><th>Importo pagato</th><th>Importo in pagamento</th></tr></thead><tbody></tbody></table><div style="display:none"><table id="myTableDetails"><thead><tr><th>Progressivo pagamento</th><th>Data decreto</th><th>Numero decreto pagamento</th><th>Tipo pagamento</th><th>Importo</th><th>Nota</th></tr></thead><tbody></tbody></table></div>
NaN appears after .append(). There is a problem in the htmlTable code?
The problem is that you have a unary + in your code:
var tab = '<table id="decretoSingolo">'+
+'<thead>'
// ^--- Here
To fix it:
Remove one of the +s. Usually it's best to use the + at the end of the previous line, to avoid issues with automatic semicolon insertion.
Why you're getting NaN:
It's a unary + because it follows the + at the end of the previous line, with whitespace in-between them (so it's not ++ as I initially suggested).
That unary + will try to take its operand (the string that follows it) and convert it to a number, and if that can't be done will yield NaN. Then the operands to the + on the previous line are a string and a number, so that addition operator converts the string to number and adds it to NaN (which yields NaN).
You can see it here:
var tab = '<table id="decretoSingolo">'+
+'<thead>'
+ '<tr>';
document.body.innerHTML = tab;
Side note: There's no need to do .html(" ") and then .append(htmlTable), just do .html(htmlTable).
You have double plus sign + in the following lines, remove one :
var tabellaDecretoSingolo = '<table id="decretoSingolo">'+
+'<thead>'
+ '<tr>'
Should be :
var tabellaDecretoSingolo = '<table id="decretoSingolo">'
+'<thead>'
+ '<tr>'
Hope this helps.
First, you can optimise your javascript:
if ($('#radioOne').is(':checked') == true) {
$("#tablePlace").html(" ");
$("#tablePlace").append(htmlTable); //htmlTable is a string that contains an html table code
loadNestedTable(temp);
}
by
if ($('#radioOne').is(':checked') == true) {
$("#tablePlace").html(htmlTable); //html() replace all content of your element child.
loadNestedTable(temp);
}
Also, you've a problem when you define your "htmlTable" value
<table id="myTable">NaN<tr> [...]
check after your ">" of your element if you don't add a NAN var...

show/hide table column on mouseenter with dynamic div id

I have a table where I want to show the last column only if the column before is hovered. The table data is parsed with JSON.
<script type="text/javascript">
$( document ).ready(function() {
var tag_id = $('#tag_id_hidden').val();
$.getJSON("/tags/get_who_tagged/" + '{{tag.tag_id}}' + "/", function(data) {
var lines = '';
for (var i = 0; i < data.length; i++) {
lines += '<tr id="' + data[i]['entity_id'] + '">';
lines += '<td id="button_id"><button id="prefix_' + data[i]["entity_id"] + '" class="js-programmatic-set-val" value="' + data[i]["entity_id"] + '" name="' + data[i]["title"] + '"><i class="fa fa-plus"></i></button></td>';
lines += '<td>' + data[i]['title'] + '</td>';
lines += '<td id="hover_' + data[i]["entity_id"] + '">' + data[i]['count'] + '</td>';
lines += '<td id="hidden_' + data[i]["entity_id"] + '" style="display:none;">'
for (var j = 0; j < data[i]['usernames'].length; j++) {
lines += data[i]['usernames'][j]['username'] + ', '
}
lines += '</td>';
lines += '</tr>';
//$("#count_user_table").empty();
$('#count_user_table tbody').html(lines);
}
});
});
</script>
<script>
$(document).on("mouseenter", "#hover_9242411", function() {$("#hidden_9242411").show();
});
$(document).on("mouseleave", "#hover_9242411", function() {$("#hidden_9242411").hide();
});
</script>
in the example above the code is working but I have to reference the id as "#hover_9242411" and "#hidden_9242411". the part after hover_/hidden_ is dynamically added to each column with a for loop. How can I dynamically reference the second part (9242411)?
Consider modifying your hover cell to something like this:
'<td id="hover_' + data[i]["entity_id"] + '" class="hover-cell" data-target="#hidden_' + data[i]["entity_id"] + '">'
You could then simply use:
$(document).on("mouseover", ".hover-cell", function() {
var target = $(this).data('target');
$(target).show();
});
Fiddle
If it will always be the previous column showing/hiding the next column, you could write your event handlers like this
$('#mytable').on('mouseenter', 'td.hover-column', function(){
$(this).next().show();
}).on('mouseleave', 'td.hover-column', function(){
$(this).next().hide();
});
For that example to work you would need to add a class to the hover column (the one that you want to hover over in order to show the next column). I also gave an id to the table and assigned the event handler to it so the event doesnt have to bubble all the way to the top.
Here is a fiddle
If later on you find that you arent showing/hiding the NEXT column but some other one, you could also put a specific class on that hidden column and instead of using
$(this).next().show();
you could use something like
$(this).closest('tr').find('td.hidden-column').show();

join() JS for HTML tables

I need to use join() as JS own method to add a table format to the values in those arrays.
This is an example of my two arrays to diplay, and the table layout should look like this.
This is the part of my code; ovbiously is not working ok, because Im getting a wrong "L" table style format when it runs.
I know its look terrible to parse HTML like that, but this code is in
Google Apps Scripts, so this table is gonna be send it by email.
Any idea how to get the proper format?
Thanks.
|-------|-------|
| user | skill |
|-------|-------|
| user | skill |
|-------|-------|
body +=
"<table style=" + STYLE.TABLE + ">" +
outUsers.join("<tr><td style=" + STYLE.TD + ">") + "</td></tr>" +
outSkills.join("<tr><td style=" + STYLE.TD + ">") + "</td></tr>" +
"</table>";
In this case Array.prototype.join() doesn't do the job I'd use Array.prototype.reduce() instead
Here is an example of what it could look like:
EDIT according to PHPglue comment to have both users and skills on the same row:
var body ='';
var outUsers = ['me', 'you', 'her'],
outSkills = ['eating', 'sleeping', 'working hard'],
STYLE = {
TABLE: "border: red;",
TD: "border: blue;"
},
getTR = function (prev, curr, index) {
return prev + '<tr>' + openingTD + curr + '</td>' + openingTD + outSkills[index] + '</td></tr>';
};
var openingTD = '<td style="' + STYLE.TD + '">';
body += '<table style="' + STYLE.TABLE + '">' +
outUsers.reduce(getTR, '') +
"</table>";
I think this is what you need to see:
var table = '<table><tbody>';
for(var i=0,l=outUsers.length; i<l; i++){
table += '<tr><td>'+outUsers[i]+'</td><td>'+outSkills[i]+'</td></tr>';
}
table += '</tbody></table>';
You should style with CSS. You should read my comments above, as well.

Make an iteration more functional in JavaScript / JQuery

I wrote a simple bit of JavaScript to create a HTML table.
It is populated by iterating over an array
var resultSet;
for (var i = 0, i < questions.length;; i++){
...
resultSet += '<tr>' + '<td>' + i + '</td><td>' + questions[i].question + '</td><td>' + questions[i].userAnswer + '</td><td>' +
questions[i].correctAnswer + '</td>' + '</tr>';
}
So this an imperative approach. I was reading about Scala where an example to something similar would be:
questions.map(n => '<tr>' + '<td>' + '</td><td>' + questions[i].question + ...);
Which is a functional. The emphasis being on the what rather than the how.
So I am wondering how to make my JavaScript more functional?
Use of JQuery of course permitted.
Javascript has Array.forEach however with limited compatibility: While all other browsers support it, IE only supports it from IE9 on - so you might need a shim for the other IEs.
Basically you could write:
questions.forEach(function(a){
resultSet += '<tr><td>' + a.question + '</td><td>' +
a.userAnswer + '</td><td>' +
a.correctAnswer + '</td></tr>';
});
jQuery provides .each() which gives you the same functionality:
$.each(questions, function(index, value) {
/* Do your stuff*/
});
First, correct Scala will be
questions.map(q => '<tr>' + '<td>' + '</td><td>' + q.question + ...);
where q is an element of questions, not an index.
JavaScript also has map (see Browser Compatibility at the end for browsers which support this method). So it's the same:
questions.map(function(q) {
return '<tr>' + '<td>' + '</td><td>' + q.question + ...
});

Javascript and VERY LONG string

i am having problems with the below code:
function showTableData()
{
var tableArray;
var x = 0;
var theHTML;
for (i = 0; i < 7032; i++)
{
if (x = 0)
{
theHTML = '<tr>' +
'<th scope="row" class="spec">' + partNum[i] + '</th>' +
'<td>' + Msrp[i] + '</td>' +
'<td>' + blah[i] + '</td>' +
'<td>' + blahs[i] + '</td>' +
'</tr>' + theHTML;
x++;
}else{
theHTML = '<tr>' +
'<th scope="row" class="specalt">' + partNum[i] + '</th>' +
'<td class="alt">' + Msrp[i] + '</td>' +
'<td class="alt">' + blah[i] + '</td>' +
'<td class="alt">' + blahs[i] + '</td>' +
'</tr>' + theHTML;
x--;
}
}
theHTML = '<table id="mytable" cellspacing="0">' +
'<tr>' +
'<th scope="col" abbr="Configurations" class="nobg">Part Number</th>' +
'<th scope="col" abbr="Dual 1.8">Msrp Price</th>' +
'<th scope="col" abbr="Dual 2">blahs Price</th>' +
'<th scope="col" abbr="Dual 2.5">Low Price</th>' +
'</tr>' + theHTML + '</table>';
$('#example').append(theHTML);
}
</script>
<div id="example">
</div>
The problem being that the $('#example').append(theHTML); never executes (or shows on the page). I think its because the string is soooooo long! It has over 7,000 items in the array so im not sure if thats the reason or if its something else?
Any help would be great! Thanks!
David
Apart from the if (x = 0) that should really be if (i % 2 === 0), you really should improve performance here by using Array.join() method instead of concatenating strings. This will have a similar effect to a StringBuilder in C# or Java.
For example:
function showTableData()
{
var tableArray;
var theHTML = [];
theHTML.push('<table id="mytable" cellspacing="0">',
'<tr>',
'<th scope="col" abbr="Configurations" class="nobg">Part Number</th>',
'<th scope="col" abbr="Dual 1.8">Msrp Price</th>',
'<th scope="col" abbr="Dual 2">blahs Price</th>',
'<th scope="col" abbr="Dual 2.5">Low Price</th>',
'</tr>');
for (var i = 0; i < 7032; i++)
{
if (i % 2 == 0)
{
theHTML.push('<tr>',
'<th scope="row" class="spec">', partNum[i], '</th>',
'<td>', Msrp[i], '</td>',
'<td>', blah[i], '</td>',
'<td>', blahs[i], '</td>',
'</tr>');
} else {
theHTML.push('<tr>',
'<th scope="row" class="specalt">', partNum[i], '</th>',
'<td class="alt">', Msrp[i], '</td>',
'<td class="alt">', blah[i], '</td>',
'<td class="alt">', blahs[i], '</td>',
'</tr>');
}
}
theHTML.push('</table>');
$('#example').append(theHTML.join(''));
}
</script>
<div id="example">
</div>
The reason why appending string 'my' + ' appended' + ' string' is slower than joining strings ['my', ' joined', ' string'].join('') is because JavaScript strings are immutable so in the former example there is a third string created every time 2 strings are concatenated, which is a very expensive operation compared to adding new entries into an array.
See also a Javascript StringBuilder project built using the same priciples of Array.push() and Array.join().
The performance improvement on this project for 10,000 concatenations in IE was down from over 1 minute to 0.23 seconds.
UPDATE: Additional calls to Array.join() added to replace string concatenation within the for-loop, this is to improve client rendering speeds further. + Added better link to StringBuilder.
FURTHER UPDATE: Added suggestions by Hemlock:
Removed use of globally scoped variable by defining var i = 0 in for-loop
Pushed several strings at a time using multiple parameters of Array.push().
one error i saw was that if (x = 0) should be if (x == 0), other than that it seems to work for me: http://jsfiddle.net/9vvJ6/
This line:
if (x = 0)
shouldn't it be
if (x == 0)
Might be the error here causing the rest of the script not being able to be executed.
If you're already using jQuery here, you might want to consider jQuery templates here, it would most likely clean up your code quite a bit and make your life easier. There can be performance tradeoffs (but I think string interpolation is faster than string concatenation in JavaScript, so this could even be faster?), but what you may or may not lose in performance, it's a much more elegant solution. You could keep your entire template in one place (maybe an external file, or parts of it hidden in the DOM of your document, I haven't used it enough to tell you what the best practice is), and then use jQuery templates to do the string replacement. There are multiple jQuery-based template frameworks, but the one I linked to is becoming an official part of jQuery.
The problem is with .append jquery function. You can not use .html or .append function for long string. Instead you need to use .innerHTML
Try this
document.getElementById('example').innerHTML=theHTML.join('');

Categories

Resources