// Production steps of ECMA-262, Edition 6, 22.1.2.1 // Référence : https://people.mozilla.org/~jorendorff/es6-draft.html#sec-array.from if (!Array.from) { Array.from = (function () { var toStr = Object.prototype.toString; var isCallable = function (fn) { return typeof fn === 'function' || toStr.call(fn) === '[object Function]'; }; var toInteger = function (value) { var number = Number(value); if (isNaN(number)) { return 0; } if (number === 0 || !isFinite(number)) { return number; } return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number)); }; var maxSafeInteger = Math.pow(2, 53) - 1; var toLength = function (value) { var len = toInteger(value); return Math.min(Math.max(len, 0), maxSafeInteger); }; // La propriété length de la méthode vaut 1. return function from(arrayLike/*, mapFn, thisArg */) { // 1. Soit C, la valeur this var C = this; // 2. Soit items le ToObject(arrayLike). var items = Object(arrayLike); // 3. ReturnIfAbrupt(items). if (arrayLike == null) { throw new TypeError("Array.from doit utiliser un objet semblable à un tableau - null ou undefined ne peuvent pas être utilisés"); } // 4. Si mapfn est undefined, le mapping sera false. var mapFn = arguments.length > 1 ? arguments[1] : void undefined; var T; if (typeof mapFn !== 'undefined') { // 5. sinon // 5. a. si IsCallable(mapfn) est false, on lève une TypeError. if (!isCallable(mapFn)) { throw new TypeError('Array.from: lorsqu il est utilisé le deuxième argument doit être une fonction'); } // 5. b. si thisArg a été fourni, T sera thisArg ; sinon T sera undefined. if (arguments.length > 2) { T = arguments[2]; } } // 10. Soit lenValue pour Get(items, "length"). // 11. Soit len pour ToLength(lenValue). var len = toLength(items.length); // 13. Si IsConstructor(C) vaut true, alors // 13. a. Soit A le résultat de l'appel à la méthode interne [[Construct]] avec une liste en argument qui contient l'élément len. // 14. a. Sinon, soit A le résultat de ArrayCreate(len). var A = isCallable(C) ? Object(new C(len)) : new Array(len); // 16. Soit k égal à 0. var k = 0; // 17. On répète tant que k < len… var kValue; while (k < len) { kValue = items[k]; if (mapFn) { A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k); } else { A[k] = kValue; } k += 1; } // 18. Soit putStatus égal à Put(A, "length", len, true). A.length = len; // 20. On renvoie A. return A; }; }()); }; // https://tc39.github.io/ecma262/#sec-array.prototype.includes if (!Array.prototype.includes) { Object.defineProperty(Array.prototype, 'includes', { value: function(searchElement, fromIndex) { if (this == null) { throw new TypeError('"this" est nul ou non défini'); } // 1. Soit o égal à ? Object(cette valeur). var o = Object(this); // 2. Soit len égal à ? Length(? Get(o, "length")). var len = o.length >>> 0; // 3. Si len = 0, renvoyer "false". if (len === 0) { return false; } // 4. Soit n = ? ToInteger(fromIndex). // Pour la cohérence du code, on gardera le nom anglais "fromIndex" pour la variable auparavant appelée "indiceDépart" // (Si fromIndex n'est pas défini, cette étape produit la valeur 0.) var n = fromIndex | 0; // 5. Si n ≥ 0, // a. Alors k = n. // 6. Sinon, si n < 0, // a. Alors k = len + n. // b. Si k < 0, alors k = 0. var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); function sameValueZero(x, y) { return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)); } // 7. Répéter tant que k < len while (k < len) { // a. Soit elementK le résultat de ? Get(O, ! ToString(k)). // b. Si SameValueZero(searchElement, elementK) est vrai, renvoyer "true". if (sameValueZero(o[k], searchElement)) { return true; } // c. Augmenter la valeur de k de 1. k++; } // 8. Renvoyer "false" return false; } }); } // Add shim for Function.prototype.bind() from: // https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind#Compatibility // for fix some RStudio viewer bug (Desktop / windows) if (!Function.prototype.bind) { Function.prototype.bind = function (oThis) { if (typeof this !== "function") { // closest thing possible to the ECMAScript 5 internal IsCallable function throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function () {}, fBound = function () { return fToBind.apply(this instanceof fNOP && oThis ? this : oThis, aArgs.concat(Array.prototype.slice.call(arguments))); }; fNOP.prototype = this.prototype; fBound.prototype = new fNOP(); return fBound; }; } //-------------------------------------------- // functions to reset edges after hard to read //-------------------------------------------- // for edges function edgeAsHardToRead(edge, hideColor1, hideColor2, network, type){ //console.info("edgeAsHardToRead") if(type === "edge"){ //console.info("edge") //console.info(edge.id) // saving color information (if we have) if (edge.hiddenColor === undefined && edge.color !== hideColor1 && edge.color !== hideColor2) { edge.hiddenColor = edge.color; } // set "hard to read" color edge.color = hideColor1; // reset and save label if (edge.hiddenLabel === undefined) { edge.hiddenLabel = edge.label; edge.label = undefined; } edge.isHardToRead = true; } else { //console.info("cluster") //console.info(edge.id) //console.info(edge) // saving color information (if we have) if (edge.hiddenColor === undefined && edge.color !== hideColor1 && edge.color !== hideColor2) { //network.clustering.updateEdge(edge.id, {hiddenColor : edge.color}); edge.hiddenColor = edge.color; } // set "hard to read" color edge.color = hideColor1; //network.clustering.updateEdge(edge.id, {color : hideColor1}); //edge.color = hideColor1; // reset and save label if (edge.hiddenLabel === undefined) { edge.hiddenLabel = edge.label; edge.label = undefined; } edge.isHardToRead = true; } } function resetOneEdge(edge, hideColor1, hideColor2, type){ /*console.info("resetOneEdge") console.info(type) console.info(edge.id) console.info(edge) console.info("edge.hiddenColor") console.info(edge.hiddenColor)*/ var treat_egde = false; if(type === "cluster"){ if(edge.isHardToRead !== undefined){ // we have to reset this node if(edge.isHardToRead){ treat_egde = true; } else if(edge.isHardToRead === false && (edge.color.color === hideColor1 || edge.color.color === hideColor2)){ treat_egde = true; } } else if(edge.color.color === hideColor1 || edge.color.color === hideColor2){ treat_egde = true; } if(treat_egde){ // get back color if (edge.hiddenColor !== undefined) { edge.color = edge.hiddenColor; edge.hiddenColor = undefined; }else{ delete edge.color; } // finally, get back label if (edge.hiddenLabel !== undefined) { edge.label = edge.hiddenLabel; edge.hiddenLabel = undefined; } edge.isHardToRead = false; } } else { // get back color if (edge.hiddenColor !== undefined) { edge.color = edge.hiddenColor; edge.hiddenColor = undefined; }else{ edge.color = null; } // finally, get back label if (edge.hiddenLabel !== undefined) { edge.label = edge.hiddenLabel; edge.hiddenLabel = undefined; } edge.isHardToRead = false; } } function resetAllEdges(edges, hideColor1, hideColor2, network){ var edgesToReset = edges.get({ fields: ['id', 'color', 'hiddenColor', 'label', 'hiddenLabel'], filter: function (item) { return item.isHardToRead === true; }, returnType :'Array' }); var is_cluster_edges = false; var edges_in_clusters; if(network !== undefined){ edges_in_clusters = network.body.modules.clustering.clusteredEdges; if(Object.keys(edges_in_clusters).length > 0){ is_cluster_edges = true; edges_in_clusters = Object.keys(edges_in_clusters); } else { edges_in_clusters = []; } } var treat_edges_in_clusters = []; // all edges get their own color and their label back for (var i = 0; i < edgesToReset.length; i++) { resetOneEdge(edgesToReset[i], hideColor1, hideColor2,type = "edge"); if(is_cluster_edges){ if(indexOf.call(edges_in_clusters, edgesToReset[i].id, true) > -1){ var tmp_cluster_id = network.clustering.getClusteredEdges(edgesToReset[i].id); if(tmp_cluster_id.length > 1){ tmp_cluster_id = tmp_cluster_id[0]; treat_edges_in_clusters.push(tmp_cluster_id); resetOneEdge(network.body.edges[tmp_cluster_id].options, hideColor1, hideColor2, type = "cluster"); } } } } // some misunderstood bug on some cluster edges... so have a (bad) fix... var edges_in_clusters_ctrl = edges_in_clusters.filter(function(word,index){ if(word.match(/^clusterEdge/i)){ if(indexOf.call(treat_edges_in_clusters, word, true) === -1){ return true; } else { return false; } }else{ return false; } }); if(is_cluster_edges){ if(edges_in_clusters_ctrl.length > 0){ for (var j = 0; j < edges_in_clusters_ctrl.length; j++) { if(network.body.edges[edges_in_clusters_ctrl[j]] !== undefined){ resetOneEdge(network.body.edges[edges_in_clusters_ctrl[j]].options, hideColor1, hideColor2, type = "cluster"); } } } } edges.update(edgesToReset); } //-------------------------------------------- // functions to reset nodes after hard to read //-------------------------------------------- // for classic node function simpleResetNode(node, type){ if(type === "node"){ // get back color if (node.hiddenColor !== undefined) { node.color = node.hiddenColor; node.hiddenColor = undefined; }else{ if(node.group !== undefined){ node.color = undefined; } else { node.color = null; } } } else { if (Object.keys(node.options.hiddenColor).length > 2){ node.setOptions({color : node.options.hiddenColor, hiddenColor : undefined}); }else{ if(node.options.group !== undefined){ node.setOptions({color : undefined}); } else { node.setOptions({color : null}); } } } } // for icon node function simpleIconResetNode(node, type){ if(type === "node"){ // icon color node.icon.color = node.hiddenColor; node.hiddenColor = undefined; // get back color if (node.hiddenColorForLabel !== undefined) { node.color = node.hiddenColorForLabel; node.hiddenColorForLabel = undefined; }else{ if(node.group !== undefined){ node.color = undefined; } else { node.color = null; } } } else { node.setOptions({icon : { color : node.options.hiddenColor}, hiddenColor : undefined}); if (node.options.hiddenColorForLabel !== undefined) { node.setOptions({color : node.options.hiddenColorForLabel, hiddenColorForLabel : undefined}); }else{ if(node.options.group !== undefined){ node.setOptions({color : undefined}); } else { node.setOptions({color : null}); } } } } // for image node function simpleImageResetNode(node, imageType, type){ if(type === "node"){ // get back color if (node.hiddenColor !== undefined) { node.color = node.hiddenColor; node.hiddenColor = undefined; }else{ if(node.group !== undefined){ node.color = undefined; } else { node.color = null; } } // and set shape as image/circularImage node.shape = imageType; } else { if (Object.keys(node.options.hiddenColor).length > 2) { node.setOptions({color : node.options.hiddenColor, hiddenColor : undefined}); }else{ if(node.options.group !== undefined){ node.setOptions({color : undefined}); } else { node.setOptions({color : null}); } } node.setOptions({shape : imageType}); } } // Global function to reset one cluster function resetOneCluster(node, options, network){ if(node !== undefined){ if(node.options.isHardToRead !== undefined){ // we have to reset this node if(node.options.isHardToRead){ var final_shape; var shape_group = false; var is_group = false; // have a group information & a shape defined in group ? if(node.options.group !== undefined && options.groups !== undefined){ if(options.groups[node.options.group] !== undefined){ is_group = true; if(options.groups[node.options.group].shape !== undefined){ shape_group = true; } } } // have a global shape in nodes options ? var shape_options = false; if(options.nodes !== undefined){ if(options.nodes.shape !== undefined){ shape_options = true; } } // set final shape (individual > group > global) if(node.options.hiddenImage !== undefined){ final_shape = node.options.hiddenImage; } else if(node.options.shape !== undefined){ final_shape = node.options.shape; } else if(shape_group){ final_shape = options.groups[node.options.group].shape; } else if(shape_options){ final_shape = options.nodes.shape; } node.setOptions({bodyHiddenColor : network.body.nodes[node.id].options.color}); // and call good reset function if(final_shape === "icon"){ simpleIconResetNode(node, "cluster"); } else if(final_shape === "image"){ simpleImageResetNode(node, "image", "cluster"); } else if(final_shape === "circularImage"){ simpleImageResetNode(node, "circularImage", "cluster"); } else { simpleResetNode(node, "cluster"); } // finally, get back label if (node.options.hiddenLabel !== undefined) { node.setOptions({label : node.options.hiddenLabel, hiddenLabel : undefined}); } node.options.isHardToRead = false; } } } } // Global function to reset one node function resetOneNode(node, options, network){ if(node !== undefined){ if(node.isHardToRead !== undefined){ // we have to reset this node if(node.isHardToRead){ var final_shape; var shape_group = false; var is_group = false; // have a group information & a shape defined in group ? if(node.group !== undefined && options.groups !== undefined){ if(options.groups[node.group] !== undefined){ is_group = true; if(options.groups[node.group].shape !== undefined){ shape_group = true; } } } // have a global shape in nodes options ? var shape_options = false; if(options.nodes !== undefined){ if(options.nodes.shape !== undefined){ shape_options = true; } } // set final shape (individual > group > global) if(node.hiddenImage !== undefined){ final_shape = node.hiddenImage; } else if(node.shape !== undefined){ final_shape = node.shape; } else if(shape_group){ final_shape = options.groups[node.group].shape; } else if(shape_options){ final_shape = options.nodes.shape; } // reset body information network.body.nodes[node.id].options.color = node.bodyHiddenColor; // and call good reset function if(final_shape === "icon"){ simpleIconResetNode(node, "node"); } else if(final_shape === "image"){ simpleImageResetNode(node, "image", "node"); } else if(final_shape === "circularImage"){ simpleImageResetNode(node, "circularImage", "node"); } else { simpleResetNode(node, "node"); } // finally, get back label if (node.hiddenLabel !== undefined) { node.label = node.hiddenLabel; node.hiddenLabel = undefined; } node.isHardToRead = false; } } } } // Global function to reset all node function resetAllNodes(nodes, update, options, network, all){ if(all === false){ var nodesToReset = nodes.get({ filter: function (item) { return item.isHardToRead === true; }, returnType :'Array' }); } else { var nodesToReset = nodes.get({returnType :'Array'}); } var have_cluster_nodes = false; var nodes_in_clusters; if(network !== undefined){ nodes_in_clusters = network.body.modules.clustering.clusteredNodes; if(Object.keys(nodes_in_clusters).length > 0){ have_cluster_nodes = true; nodes_in_clusters = Object.keys(nodes_in_clusters); } else { nodes_in_clusters = []; } } for (var i = 0; i < nodesToReset.length; i++) { resetOneNode(nodesToReset[i], options, network, type = "node"); // reset coordinates nodesToReset[i].x = undefined; nodesToReset[i].y = undefined; if(have_cluster_nodes){ if(indexOf.call(nodes_in_clusters, nodesToReset[i].id, true) > -1){ var tmp_cluster_id = network.clustering.findNode(nodesToReset[i].id); // in case of multiple cluster... for(var j = 0; j < (tmp_cluster_id.length-1); j++) { resetOneCluster(network.body.nodes[tmp_cluster_id[j]], options, network); } } } } if(update){ nodes.update(nodesToReset); } } //-------------------------------------------- // functions to set nodes as hard to read //-------------------------------------------- // for classic node function simpleNodeAsHardToRead(node, hideColor1, hideColor2, type){ // classic nodes if(type === "node"){ // saving color information (if we have) if (node.hiddenColor === undefined && node.color !== hideColor1 && node.color !== hideColor2) { node.hiddenColor = node.color; } // set "hard to read" color node.color = hideColor1; // reset and save label if (node.hiddenLabel === undefined) { node.hiddenLabel = node.label; node.label = undefined; } // cluster } else { // saving color information (if we have) if (node.options.hiddenColor === undefined && node.options.color !== hideColor1 && node.options.color !== hideColor2) { node.setOptions({hiddenColor : node.options.color}); } // set "hard to read" color node.setOptions({color : hideColor1}); // reset and save label if (node.options.hiddenLabel === undefined) { node.setOptions({hiddenLabel : node.options.label}); node.setOptions({label : undefined}); } } } // for icon node function iconsNodeAsHardToRead(node, hideColor1, hideColor2, icon_color, type){ // classic nodes if(type === "node"){ // individual information if(node.icon !== undefined && node.icon !== null && node.icon !== {}){ node.iconDefined = true; } else { // information in group : have to as individual node.icon = {}; node.iconDefined = false; } // set "hard to read" color node.icon.color = hideColor1; node.hiddenColor = icon_color; // for edges....saving color information (if we have) if (node.hiddenColorForLabel === undefined && node.color !== hideColor1 && node.color !== hideColor2) { node.hiddenColorForLabel = node.color; } // set "hard to read" color node.color = hideColor1; // reset and save label if (node.hiddenLabel === undefined) { node.hiddenLabel = node.label; node.label = undefined; } } else { // individual information if(node.options.icon !== undefined && node.options.icon !== null && node.options.icon !== {}){ node.setOptions({iconDefined : true}); } else { // information in group : have to as individual node.setOptions({iconDefined : false, icon:{}}); } // set "hard to read" color node.setOptions({hiddenColor : icon_color, icon:{color : hideColor1}}); // for edges....saving color information (if we have) if (node.options.hiddenColorForLabel === undefined && node.options.color !== hideColor1 && node.options.color !== hideColor2) { node.setOptions({hiddenColorForLabel : node.options.color}); } // set "hard to read" color node.setOptions({color : hideColor1}); // reset and save label if (node.options.hiddenLabel === undefined) { node.setOptions({hiddenLabel : node.options.label, label : undefined}); } } } // for image node function imageNodeAsHardToRead(node, imageType, hideColor1, hideColor2, type){ // classic nodes if(type === "node"){ // saving color information (if we have) if (node.hiddenColor === undefined && node.color !== hideColor1 && node.color !== hideColor2) { node.hiddenColor = node.color; } // set "hard to read" color node.color = hideColor1; // reset and save label if (node.hiddenLabel === undefined) { node.hiddenLabel = node.label; node.label = undefined; } // keep shape information, and set a new if(imageType === "image"){ node.hiddenImage = imageType; node.shape = "square"; }else if(imageType === "circularImage"){ node.hiddenImage = imageType; node.shape = "dot"; } } else { // saving color information (if we have) if (node.options.hiddenColor === undefined && node.options.color !== hideColor1 && node.options.color !== hideColor2) { node.setOptions({hiddenColor : node.options.color}); } // set "hard to read" color node.setOptions({color : hideColor1}); // reset and save label if (node.options.hiddenLabel === undefined) { node.setOptions({hiddenLabel : node.options.label, label : undefined}); } if(imageType === "image"){ node.setOptions({hiddenImage : "image", shape : "square"}); } else if(imageType === "circularImage"){ node.setOptions({hiddenImage : "circularImage", shape : "dot"}); } node.hiddenImage = imageType; } } // Global function to set one node as hard to read function nodeAsHardToRead(node, options, hideColor1, hideColor2, network, type){ var final_shape; var shape_group = false; var is_group = false; if(node.isHardToRead === false || node.isHardToRead === undefined){ // have a group information & a shape defined in group ? if(node.group !== undefined && options.groups !== undefined){ if(options.groups[node.group] !== undefined){ is_group = true; if(options.groups[node.group].shape !== undefined){ shape_group = true; } } } // have a group information & a shape defined in group ? var shape_options = false; if(options.nodes !== undefined){ if(options.nodes.shape !== undefined){ shape_options = true; } } // set final shape (individual > group > global) if(node.shape !== undefined){ final_shape = node.shape; } else if(shape_group){ final_shape = options.groups[node.group].shape; } else if(shape_options){ final_shape = options.nodes.shape; } // information save in body nodes if(type === "node"){ node.bodyHiddenColor = clone(network.body.nodes[node.id].options.color); } else { node.setOptions({bodyHiddenColor : clone(network.body.nodes[node.id].options.color)}); } // and call good function if(final_shape === "icon"){ // find color for icon var icon_color = "#2B7CE9"; var find_color = false; // in nodes ? if(node.icon !== undefined){ if(node.icon.color !== undefined){ icon_color = node.icon.color; find_color = true; } } // or in group ? if(find_color === false && is_group && options.groups !== undefined && options.groups[node.group].icon !== undefined){ if(options.groups[node.group].icon.color !== undefined){ icon_color = options.groups[node.group].icon.color; find_color = true; } } // in global node ? if(find_color === false && options.nodes.icon !== undefined){ if(options.nodes.icon.color !== undefined){ icon_color = options.nodes.icon.color; } } iconsNodeAsHardToRead(node, hideColor1, hideColor2, icon_color, type); } else if(final_shape === "image"){ imageNodeAsHardToRead(node, "image", hideColor1, hideColor2, type); } else if(final_shape === "circularImage"){ imageNodeAsHardToRead(node, "circularImage", hideColor1, hideColor2, type); } else { simpleNodeAsHardToRead(node, hideColor1, hideColor2, type); } // finally set isHardToRead if(type === "node"){ node.isHardToRead = true; } else { node.setOptions({isHardToRead : true}); } // special case of just to label } else if(node.isHardToRead === true && node.label !== undefined){ if(type === "node"){ node.hiddenLabel = node.label; node.label = undefined; } else { node.setOptions({hiddenLabel : node.options.label, label : undefined}) } } } //---------------------------------------------------------------- // Revrite HTMLWidgets.dataframeToD3() for passing custom // properties directly in data.frame (color.background) for example //---------------------------------------------------------------- function visNetworkdataframeToD3(df, type) { // variables we have specially to control /*var nodesctrl = ["color", "fixed", "font", "icon", "shadow", "scaling", "shapeProperties", "chosen", "heightConstraint", "image", "margin", "widthConstraint"]; var edgesctrl = ["color", "font", "arrows", "shadow", "smooth", "scaling", "chosen", "widthConstraint"];*/ var names = []; var colnames = []; var length; var toctrl; var ctrlname; for (var name in df) { if (df.hasOwnProperty(name)) colnames.push(name); ctrlname = name.split("."); if(ctrlname.length === 1){ names.push( new Array(name)); } else { /*if(type === "nodes"){ toctrl = indexOf.call(nodesctrl, ctrlname[0], true); } else if(type === "edges"){ toctrl = indexOf.call(edgesctrl, ctrlname[0], true); } if(toctrl > -1){*/ names.push(ctrlname); /*} else { names.push(new Array(name)); }*/ } if (typeof(df[name]) !== "object" || typeof(df[name].length) === "undefined") { throw new Error("All fields must be arrays"); } else if (typeof(length) !== "undefined" && length !== df[name].length) { throw new Error("All fields must be arrays of the same length"); } length = df[name].length; } var results = []; var item; for (var row = 0; row < length; row++) { item = {}; for (var col = 0; col < names.length; col++) { if(df[colnames[col]][row] !== null){ if(names[col].length === 1){ if(names[col][0] === "dashes"){ item[names[col]] = eval(df[colnames[col]][row]); } else { item[names[col]] = df[colnames[col]][row]; } } else if(names[col].length === 2){ if(item[names[col][0]] === undefined){ item[names[col][0]] = {}; } if(names[col][0] === "icon" && names[col][1] === "code"){ item[names[col][0]][names[col][1]] = JSON.parse( '"'+'\\u' + df[colnames[col]][row] + '"'); } else if(names[col][0] === "icon" && names[col][1] === "color"){ item.color = df[colnames[col]][row]; item[names[col][0]][names[col][1]] = df[colnames[col]][row]; } else if(names[col][0] === "icon" && names[col][1] === "face"){ if(df[colnames[col]][row] === "'Font Awesome 5 Free'"){ item.icon.weight = "bold"; } item[names[col][0]][names[col][1]] = df[colnames[col]][row]; } else{ item[names[col][0]][names[col][1]] = df[colnames[col]][row]; } } else if(names[col].length === 3){ if(item[names[col][0]] === undefined){ item[names[col][0]] = {}; } if(item[names[col][0]][names[col][1]] === undefined){ item[names[col][0]][names[col][1]] = {}; } item[names[col][0]][names[col][1]][names[col][2]] = df[colnames[col]][row]; } else if(names[col].length === 4){ if(item[names[col][0]] === undefined){ item[names[col][0]] = {}; } if(item[names[col][0]][names[col][1]] === undefined){ item[names[col][0]][names[col][1]] = {}; } if(item[names[col][0]][names[col][1]][names[col][2]] === undefined){ item[names[col][0]][names[col][1]][names[col][2]] = {}; } item[names[col][0]][names[col][1]][names[col][2]][names[col][3]] = df[colnames[col]][row]; } } } results.push(item); } return results; } //---------------------------------------------------------------- // Some utils functions //---------------------------------------------------------------- //unique element in array function uniqueArray(arr, exclude_cluster, network) { var a = []; for (var i=0, l=arr.length; i -1; }, returnType :'Array' }); currentConnectedToNodes = []; var currentlength = otherLevelNodes.length; for (j = 0; j < connectedToNodes.length; j++) { otherLevelNodes = uniqueArray(otherLevelNodes.concat(connectedToNodes[j].to), false, network); currentConnectedToNodes = uniqueArray(currentConnectedToNodes.concat(connectedToNodes[j].to), false, network); } if (otherLevelNodes.length === currentlength) { break; } } var finalFirstLevelNodes = []; for (j = 0; j < firstLevelNodes.length; j++) { var findnode = network.clustering.findNode(firstLevelNodes[j]) if(findnode.length === 1){ finalFirstLevelNodes = finalFirstLevelNodes.concat(firstLevelNodes[j]); } else { finalFirstLevelNodes = finalFirstLevelNodes.concat(findnode[0]); } } var finalClusterNodes = []; for (j = 0; j < otherLevelNodes.length; j++) { var findnode = network.clustering.findNode(otherLevelNodes[j]) if(findnode.length === 1){ finalClusterNodes = finalClusterNodes.concat(otherLevelNodes[j]); } else { finalClusterNodes = finalClusterNodes.concat(findnode[0]); } } if(set_position){ network.storePositions(); } var clusterOptions = { joinCondition: function (nodesOptions) { return nodesOptions.id === selectedNode || indexOf.call(finalFirstLevelNodes, nodesOptions.id, true) > -1 || indexOf.call(finalClusterNodes, nodesOptions.id, true) > -1; }, processProperties: function(clusterOptions, childNodes) { var click_node = network.body.data.nodes.get({ filter: function (item) { return item.id == selectedNode; }, returnType :'Array' }); var is_hard_to_read = false; if(click_node[0].isHardToRead !== undefined){ is_hard_to_read = click_node[0].isHardToRead; } for (var i in click_node[0]) { if(i !== "id" && i !== "isHardToRead"){ if(i === "label" && is_hard_to_read){ clusterOptions[i]= click_node[0]["hiddenLabel"]; } else if(i === "color" && is_hard_to_read) { clusterOptions[i]= click_node[0]["hiddenColor"]; } else { clusterOptions[i]= click_node[0][i]; } } } // gestion des tree if(treeParams !== undefined){ if(treeParams.updateShape){ clusterOptions.label = clusterOptions.labelClust clusterOptions.color = clusterOptions.colorClust clusterOptions.shape = treeParams.shapeY } } if(clusterOptions.label !== undefined){ clusterOptions.label = clusterOptions.label + " " + labelSuffix; } else { clusterOptions.label = labelSuffix; } if(clusterOptions.borderWidth !== undefined){ clusterOptions.borderWidth = clusterOptions.borderWidth * 3; } else { clusterOptions.borderWidth = 3; } if(set_position){ if(click_node[0].x !== undefined){ clusterOptions.x = click_node[0].x; } if(click_node[0].y !== undefined){ clusterOptions.y = click_node[0].y; } } if(clusterParams !== undefined){ for (var j in clusterParams) { clusterOptions[j]= clusterParams[j]; } } return clusterOptions; }, clusterNodeProperties: { allowSingleNodeCluster: false } } network.cluster(clusterOptions); } } } if(resetHighlight){ document.getElementById("nodeSelect"+elid).value = ""; document.getElementById("nodeSelect"+elid).onchange(); } if(fit){ network.fit(); } } }; function uncollapsedNetwork(nodes, fit, resetHighlight, keepCoord, network, elid) { var selectedNode; var j; var arr_nodes = []; var cluster_node; var nodes_in_clusters = network.body.modules.clustering.clusteredNodes; if(Object.keys(nodes_in_clusters).length > 0){ nodes_in_clusters = Object.keys(nodes_in_clusters); } else { nodes_in_clusters = [] } if(nodes !== undefined && nodes !== null){ arr_nodes = nodes } else { arr_nodes = nodes_in_clusters; } for (var inodes = 0; inodes < arr_nodes.length; inodes++) { selectedNode = '' + arr_nodes[inodes]; if(selectedNode !== undefined){ if(network.isCluster(selectedNode)){ if(keepCoord){ network.openCluster(selectedNode, {releaseFunction : function(clusterPosition, containedNodesPositions) { return containedNodesPositions; } }); } else { network.openCluster(selectedNode) } } else { if(indexOf.call(nodes_in_clusters, selectedNode, true) > -1){ // not a cluster into a cluster... if(selectedNode.search(/^cluster/i) === -1){ cluster_node = network.clustering.findNode(selectedNode)[0]; if(network.isCluster(cluster_node)){ if(keepCoord){ network.openCluster(cluster_node, {releaseFunction : function(clusterPosition, containedNodesPositions) { return containedNodesPositions; } }); } else { network.openCluster(cluster_node) } } } } } } } if(resetHighlight){ document.getElementById("nodeSelect"+elid).value = ""; document.getElementById("nodeSelect"+elid).onchange(); } if(fit){ network.fit(); } }; //---------------------------------------------------------------- // All available functions/methods with visNetworkProxy //--------------------------------------------------------------- if (HTMLWidgets.shinyMode){ // collapsed method Shiny.addCustomMessageHandler('visShinyCollapse', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ collapsedNetwork(data.nodes, data.fit, data.resetHighlight, data.clusterOptions, data.labelSuffix, undefined, el.chart, data.id) } }); // uncollapsed method Shiny.addCustomMessageHandler('visShinyUncollapse', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ uncollapsedNetwork(data.nodes, data.fit, data.resetHighlight, data.keepCoord, el.chart, data.id) } }); // event method Shiny.addCustomMessageHandler('visShinyEvents', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; if(data.type === "once"){ for (var key in data.events) { eval('network.once("' + key + '",' + data.events[key] + ')'); } } else if(data.type === "on"){ for (var key in data.events) { eval('network.on("' + key + '",' + data.events[key] + ')'); } } else if(data.type === "off"){ for (var key in data.events) { eval('network.off("' + key + '",' + data.events[key] + ')'); } } } }); // moveNode method Shiny.addCustomMessageHandler('visShinyMoveNode', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; network.moveNode(data.nodeId, data.x, data.y); } }); // unselectAll method Shiny.addCustomMessageHandler('visShinyUnselectAll', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; // reset selection document.getElementById("nodeSelect"+data.id).value = ""; document.getElementById("nodeSelect"+data.id).onchange(); if(document.getElementById(data.id).selectActive === true){ document.getElementById("selectedBy"+data.id).value = ""; document.getElementById("selectedBy"+data.id).onchange(); } network.unselectAll(); } }); // updateOptions in the network Shiny.addCustomMessageHandler('visShinyOptions', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; var options = el.options; // configure if(data.options.configure !== undefined){ if(data.options.configure.container !== undefined){ var dom_conf = document.getElementById(data.options.configure.container); if(dom_conf !== null){ data.options.configure.container = dom_conf; } else { data.options.configure.container = undefined; } } } //************************* // pre-treatment for icons (unicode) //************************* if(data.options.groups){ for (var gr in data.options.groups){ if(data.options.groups[gr].icon){ if(data.options.groups[gr].icon.code){ data.options.groups[gr].icon.code = JSON.parse( '"'+'\\u' + data.options.groups[gr].icon.code + '"'); } if(data.options.groups[gr].icon.face){ if(data.options.groups[gr].icon.face === "'Font Awesome 5 Free'"){ data.options.groups[gr].icon.weight = "bold" } } if(data.options.groups[gr].icon.color){ data.options.groups[gr].color = data.options.groups[gr].icon.color; } } } } if(data.options.nodes){ if(data.options.nodes.icon){ if(data.options.nodes.icon.code){ data.options.nodes.icon.code = JSON.parse( '"'+'\\u' + data.options.nodes.icon.code + '"'); } if(data.options.nodes.icon.face){ if(data.options.nodes.icon.face === "'Font Awesome 5 Free'"){ data.options.nodes.icon.weight = "bold" } } if(data.options.nodes.icon.color){ data.options.nodes.color = data.options.nodes.icon.color; } } } update(options, data.options); network.setOptions(options); } }); // setData the network Shiny.addCustomMessageHandler('visShinySetData', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; var newnodes = new vis.DataSet(); var newedges = new vis.DataSet(); newnodes.add(visNetworkdataframeToD3(data.nodes, "nodes")); newedges.add(visNetworkdataframeToD3(data.edges, "edges")); var newdata = { nodes: newnodes, edges: newedges }; network.setData(newdata); } }); // fit to a specific node Shiny.addCustomMessageHandler('visShinyFit', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; network.fit(data.options); } }); // focus on a node in the network Shiny.addCustomMessageHandler('visShinyFocus', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; network.focus(data.focusId, data.options); } }); // stabilize the network Shiny.addCustomMessageHandler('visShinyStabilize', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; network.stabilize(data.options); } }); // startSimulation on network Shiny.addCustomMessageHandler('visShinyStartSimulation', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; network.startSimulation(); } }); // stopSimulation on network Shiny.addCustomMessageHandler('visShinyStopSimulation', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; network.stopSimulation(); } }); // get positions of the network Shiny.addCustomMessageHandler('visShinyGetPositions', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; var pos; if(data.nodes !== undefined){ pos = network.getPositions(data.nodes); }else{ pos = network.getPositions(); } // return positions in shiny Shiny.onInputChange(data.input, pos); } }); // get edges data Shiny.addCustomMessageHandler('visShinyGetEdges', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ // return data in shiny Shiny.onInputChange(data.input, el.edges.get({returnType:"Object"})); } }); // get nodes data Shiny.addCustomMessageHandler('visShinyGetNodes', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ if(data.addCoordinates){ el.chart.storePositions(); } // return data in shiny Shiny.onInputChange(data.input, el.nodes.get({returnType:"Object"})); } }); // get selected edges Shiny.addCustomMessageHandler('visShinyGetSelectedEdges', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; var pos = network.getSelectedEdges(); // return in shiny Shiny.onInputChange(data.input, pos); } }); // get selected nodes Shiny.addCustomMessageHandler('visShinyGetSelectedNodes', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; var pos = network.getSelectedNodes(); // return in shiny Shiny.onInputChange(data.input, pos); } }); // getConnectedEdges Shiny.addCustomMessageHandler('visShinyGetConnectedEdges', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; var pos = network.getConnectedEdges(data.nodeId); // return in shiny Shiny.onInputChange(data.input, pos); } }); // getConnectedNodes Shiny.addCustomMessageHandler('visShinyGetConnectedNodes', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; var pos = network.getConnectedNodes(data.nodeId); // return in shiny Shiny.onInputChange(data.input, pos); } }); // getBoundingBox Shiny.addCustomMessageHandler('visShinyGetBoundingBox', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; var pos = network.getBoundingBox(data.nodeId); // return in shiny Shiny.onInputChange(data.input, pos); } }); // get selection Shiny.addCustomMessageHandler('visShinyGetSelection', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; var pos; pos = network.getSelection(); // return in shiny Shiny.onInputChange(data.input, pos); } }); // get scale Shiny.addCustomMessageHandler('visShinyGetScale', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; var pos; pos = network.getScale(); // return in shiny Shiny.onInputChange(data.input, pos); } }); // store positions Shiny.addCustomMessageHandler('visShinyStorePositions', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; network.storePositions(); } }); // get view position Shiny.addCustomMessageHandler('visShinyGetViewPosition', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; var pos; pos = network.getViewPosition(); // return in shiny Shiny.onInputChange(data.input, pos); } }); // get view position Shiny.addCustomMessageHandler('visShinyGetOptionsFromConfigurator', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; // return in shiny Shiny.onInputChange(data.input, network.getOptionsFromConfigurator()); } }); // Redraw the network Shiny.addCustomMessageHandler('visShinyRedraw', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ el.chart.redraw(); } }); // select nodes Shiny.addCustomMessageHandler('visShinySelectNodes', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; if(data.selid !== null){ network.selectNodes(data.selid, data.highlightEdges); if(data.clickEvent){ el.myclick({nodes : data.selid}); } }else{ if(data.clickEvent){ el.myclick({nodes : []}); } } } }); // select edges Shiny.addCustomMessageHandler('visShinySelectEdges', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; if(data.selid !== null){ network.selectEdges(data.selid); } } }); // set selection Shiny.addCustomMessageHandler('visShinySetSelection', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(el){ var network = el.chart; if(data.selection.nodes !== null || data.selection.edges !== null){ network.setSelection(data.selection, data.options); } if(data.clickEvent){ if(data.selection.nodes !== null){ el.myclick({nodes : data.selection.nodes}); } else { el.myclick({nodes : []}); } } } }); function updateVisOptions(data){ // get container id var graph = document.getElementById("graph"+data.id); var el = document.getElementById(data.id); var do_loop_by = false; var option2; var selectList2; var selectList; var reset = false; if(graph){ // reset nodes before ? if(document.getElementById(el.id).highlight){ // need reset nodes if(document.getElementById(el.id).highlightActive === true){ reset = true; } } if(reset){ document.getElementById("nodeSelect"+data.id).value = ""; document.getElementById("nodeSelect"+data.id).onchange(); } // collapse init if(data.options.collapse !== undefined){ el.collapse = data.options.collapse.enabled; el.collapseFit = data.options.collapse.fit; el.collapseResetHighlight = data.options.collapse.resetHighlight; el.collapseKeepCoord = data.options.collapse.keepCoord; el.collapseLabelSuffix = data.options.collapse.labelSuffix; el.clusterOptions = data.options.collapse.clusterOptions; } // highlight init if(data.options.highlight !== undefined){ el.highlight = data.options.highlight.enabled; el.degree = data.options.highlight.degree; el.hoverNearest = data.options.highlight.hoverNearest; el.highlightColor = data.options.highlight.hideColor; el.highlightAlgorithm = data.options.highlight.algorithm; el.highlightLabelOnly = data.options.labelOnly; } // byselection init if(data.options.byselection !== undefined){ if(data.options.byselection.selected !== undefined){ document.getElementById("selectedBy"+data.id).value = data.options.byselection.selected; document.getElementById("selectedBy"+data.id).onchange(); } if(data.options.byselection.hideColor){ el.byselectionColor = data.options.byselection.hideColor; } if(data.options.byselection.highlight !== undefined){ el.byselectionHighlight = data.options.byselection.highlight; } } if(data.options.byselection !== undefined){ selectList2 = document.getElementById("selectedBy"+data.id) selectList2.options.length = 0; if(data.options.byselection.enabled === true){ option2 = document.createElement("option"); option2.value = ""; if(data.options.byselection.main === undefined){ option2.text = "Select by " + data.options.byselection.variable; } else { option2.text = data.options.byselection.main; } selectList2.appendChild(option2); if(data.options.byselection.values !== undefined){ for (var i = 0; i < data.options.byselection.values.length; i++) { option2 = document.createElement("option"); option2.value = data.options.byselection.values[i]; option2.text = data.options.byselection.values[i]; selectList2.appendChild(option2); } }else{ do_loop_by = true; } el.byselection_variable = data.options.byselection.variable; el.byselection_multiple = data.options.byselection.multiple; selectList2.style.display = 'inline'; if(data.options.byselection.style !== undefined){ selectList2.setAttribute('style', data.options.byselection.style); } el.byselection = true; } else { selectList2.style.display = 'none'; el.byselection = false; // reset selection if(el.selectActive === true){ document.getElementById("selectedBy"+data.id).value = ""; document.getElementById("selectedBy"+data.id).onchange(); } } }else{ // reset selection if(el.selectActive === true){ document.getElementById("selectedBy"+data.id).value = ""; document.getElementById("selectedBy"+data.id).onchange(); } } if(do_loop_by){ var allNodes = graph.nodes.get({returnType:"Object"}); var byselection_values = []; for (var nodeId in allNodes) { if(do_loop_by){ var current_sel_value = allNodes[nodeId][data.options.byselection.variable]; if(data.options.byselection.multiple){ current_sel_value = current_sel_value.split(",").map(Function.prototype.call, String.prototype.trim); }else{ current_sel_value = [current_sel_value]; } for(var ind_c in current_sel_value){ if(indexOf.call(byselection_values, current_sel_value[ind_c], false) === -1){ option2 = document.createElement("option"); option2.value = current_sel_value[ind_c]; option2.text = current_sel_value[ind_c]; selectList2.appendChild(option2); byselection_values.push(current_sel_value[ind_c]); } } } } } // node id selection init if(data.options.idselection !== undefined){ selectList = document.getElementById("nodeSelect"+data.id) selectList.options.length = 0; if(data.options.idselection.enabled === true){ setNodeIdList(selectList, data.options.idselection, graph.nodes) el.idselection = true; } else { selectList.style.display = 'none'; el.idselection = false; } if(data.options.idselection.useLabels !== undefined){ el.idselection_useLabels = data.options.idselection.useLabels } } if(data.options.idselection !== undefined){ if(data.options.idselection.enabled === true && data.options.idselection.selected !== undefined){ document.getElementById("nodeSelect"+data.id).value = data.options.idselection.selected; document.getElementById("nodeSelect"+data.id).onchange(); } } } }; Shiny.addCustomMessageHandler('visShinyCustomOptions', updateVisOptions); // udpate nodes data Shiny.addCustomMessageHandler('visShinyUpdateNodes', function(data){ // get container id var el = document.getElementById("graph"+data.id); var main_el = document.getElementById(data.id); if(data.legend === false){ if(el){ // get & transform nodes object var tmpnodes = visNetworkdataframeToD3(data.nodes, "nodes"); // reset some parameters / data before if (main_el.selectActive === true | main_el.highlightActive === true) { //reset nodes resetAllEdges(el.edges, el.highlightColor, el.byselectionColor, el.chart); resetAllNodes(el.nodes, true, el.options, el.chart, false); if (main_el.selectActive === true){ main_el.selectActive = false; resetList('selectedBy', data.id, 'selectedBy'); } if (main_el.highlightActive === true){ main_el.highlightActive = false; resetList('nodeSelect', data.id, 'selected'); } } // update nodes el.nodes.update(tmpnodes); // update options ? if(data.updateOptions){ var dataOptions = {}; dataOptions.options = {}; var updateOpts = false; if(document.getElementById("nodeSelect"+data.id).style.display === 'inline'){ updateOpts = true; dataOptions.id = data.id; dataOptions.options.idselection = {enabled : true, useLabels : main_el.idselection_useLabels}; } if(document.getElementById("selectedBy"+data.id).style.display === 'inline'){ updateOpts = true; dataOptions.id = data.id; dataOptions.options.byselection = {enabled : true, variable : main_el.byselection_variable, multiple : main_el.byselection_multiple}; } if(updateOpts){ updateVisOptions(dataOptions); } } } } else if(data.legend === true){ var legend_network = document.getElementById("legend"+data.id); if(legend_network){ // get & transform nodes object var tmpnodes = visNetworkdataframeToD3(data.nodes, "nodes"); // update nodes legend_network.network.body.data.nodes.update(tmpnodes); // fit legend_network.network.fit(); } } }); // udpate edges data Shiny.addCustomMessageHandler('visShinyUpdateEdges', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(data.legend === false){ if(el){ // get edges object var tmpedges = visNetworkdataframeToD3(data.edges, "edges"); // reset edges resetAllEdges(el.edges, el.highlightColor, el.byselectionColor, el.chart) el.edges.update(tmpedges); } } else if(data.legend === true){ var legend_network = document.getElementById("legend"+data.id); if(legend_network){ // get & transform nodes object var tmpedges = visNetworkdataframeToD3(data.edges, "edges"); // update edges legend_network.network.body.data.edges.update(tmpedges); // fit legend_network.network.fit(); } } }); // remove nodes Shiny.addCustomMessageHandler('visShinyRemoveNodes', function(data){ // get container id var el = document.getElementById("graph"+data.id); var main_el = document.getElementById(data.id); if(data.legend === false){ if(el){ // reset some parameters / date before if (main_el.selectActive === true | main_el.highlightActive === true) { //reset nodes resetAllNodes(el.nodes, true, el.options, el.chart, false); if (main_el.selectActive === true){ main_el.selectActive = false; resetList('selectedBy', data.id, 'selectedBy'); } if (main_el.highlightActive === true){ main_el.highlightActive = false; resetList('nodeSelect', data.id, 'selected'); } } // remove nodes el.nodes.remove(data.rmid); // update options ? if(data.updateOptions){ var dataOptions = {}; dataOptions.options = {}; var updateOpts = false; if(document.getElementById("nodeSelect"+data.id).style.display === 'inline'){ updateOpts = true; dataOptions.id = data.id; dataOptions.options.idselection = {enabled : true, useLabels : main_el.idselection_useLabels}; } if(document.getElementById("selectedBy"+data.id).style.display === 'inline'){ updateOpts = true; dataOptions.id = data.id; dataOptions.options.byselection = {enabled : true, variable : main_el.byselection_variable, multiple : main_el.byselection_multiple}; } if(updateOpts){ updateVisOptions(dataOptions); } } } } else if(data.legend === true){ var legend_network = document.getElementById("legend"+data.id); if(legend_network){ // remove nodes legend_network.network.body.data.nodes.remove(data.rmid); // fit legend_network.network.fit(); } } }); // remove edges Shiny.addCustomMessageHandler('visShinyRemoveEdges', function(data){ // get container id var el = document.getElementById("graph"+data.id); if(data.legend === false){ if(el){ // reset edges resetAllEdges(el.edges, el.highlightColor, el.byselectionColor, el.chart) el.edges.remove(data.rmid); } } else if(data.legend === true){ var legend_network = document.getElementById("legend"+data.id); if(legend_network){ // remove edges legend_network.network.body.data.edges.remove(data.rmid); // fit legend_network.network.fit(); } } }); // remove edges Shiny.addCustomMessageHandler('visShinySetTitle', function(data){ if(data.main !== null){ var div_title = document.getElementById("title" + data.id); if(div_title !== null){ if(data.main.hidden === true){ div_title.style.display = 'none'; } else { if(data.main.text !== undefined){ if(data.main.text !== null){ if(data.main.text.length > 0){ div_title.innerHTML = data.main.text; } else { div_title.innerHTML = ""; } } } if(data.main.style !== undefined){ if(data.main.style !== null){ if(data.main.style.length > 0){ div_title.setAttribute('style', data.main.style); } } } div_title.style.display = 'block'; } } } if(data.submain !== null){ var div_subtitle = document.getElementById("subtitle" + data.id); if(div_subtitle !== null){ if(data.submain.hidden === true){ div_subtitle.style.display = 'none'; } else { if(data.submain.text !== undefined){ if(data.submain.text !== null){ if(data.submain.text.length > 0){ div_subtitle.innerHTML = data.submain.text; } else { div_subtitle.innerHTML = ""; } } } if(data.submain.style !== undefined){ if(data.submain.style !== null){ if(data.submain.style.length > 0){ div_subtitle.setAttribute('style', data.submain.style); } } } div_subtitle.style.display = 'block'; } } } if(data.footer !== null){ var div_footer = document.getElementById("footer" + data.id); if(div_footer !== null){ if(data.footer.hidden === true){ div_footer.style.display = 'none'; } else { if(data.footer.text !== undefined){ if(data.footer.text !== null){ if(data.footer.text.length > 0){ div_footer.innerHTML = data.footer.text; } else { div_footer.innerHTML = ""; } } } if(data.footer.style !== undefined){ if(data.footer.style !== null){ if(data.footer.style.length > 0){ div_footer.setAttribute('style', data.footer.style); } } } div_footer.style.display = 'block'; } } } }); // updateTree Shiny.addCustomMessageHandler('visShinyUpdateTree', function(data){ // get container id var el = document.getElementById(data.id); if(el){ if(el.tree){ if(data.tree.updateShape != undefined){ el.tree.updateShape = data.tree.updateShape } if(data.tree.shapeVar != undefined){ el.tree.shapeVar = data.tree.shapeVar } if(data.tree.shapeY != undefined){ el.tree.shapeY = data.tree.shapeY } } } }); } //---------------------------------------------------------------- // HTMLWidgets.widget Definition //--------------------------------------------------------------- HTMLWidgets.widget({ name: 'visNetwork', type: 'output', initialize: function(el, width, height) { return { }; }, renderValue: function(el, x, instance) { var data; var nodes; var edges; // clustergin by zoom variables var clusterIndex = 0; var clusters = []; var lastClusterZoomLevel = 0; var clusterFactor; var ctrlwait = 0; // legend control var addlegend = false; // main div el.id var el_id = document.getElementById(el.id); // test background el_id.style.background = x.background; // clear el.id (for shiny...) el_id.innerHTML = ""; // shared control with proxy function (is there a better way ?) el_id.highlightActive = false; el_id.selectActive = false; el_id.idselection = x.idselection.enabled; el_id.byselection = x.byselection.enabled; if(x.highlight !== undefined){ el_id.highlight = x.highlight.enabled; el_id.highlightColor = x.highlight.hideColor; el_id.hoverNearest = x.highlight.hoverNearest; el_id.degree = x.highlight.degree; el_id.highlightAlgorithm = x.highlight.algorithm; el_id.highlightLabelOnly = x.highlight.labelOnly; } else { el_id.highlight = false; el_id.hoverNearest = false; el_id.highlightColor = 'rgba(200,200,200,0.5)'; el_id.degree = 1; el_id.highlightAlgorithm = "all"; el_id.highlightLabelOnly = true; } if(x.byselection.enabled){ el_id.byselectionColor = x.byselection.hideColor; el_id.byselectionHighlight = x.byselection.highlight; } else { el_id.byselectionColor = 'rgba(200,200,200,0.5)'; el_id.byselectionHighlight = false; } if(x.idselection.enabled){ el_id.idselection_useLabels = true; } else { el_id.idselection_useLabels = false; } if(x.collapse !== undefined){ if(x.collapse.enabled){ el_id.collapse = true; el_id.collapseFit = x.collapse.fit; el_id.collapseResetHighlight = x.collapse.resetHighlight; el_id.collapseKeepCoord = x.collapse.keepCoord; el_id.collapseLabelSuffix = x.collapse.labelSuffix; el_id.clusterOptions = x.collapse.clusterOptions; } } else { el_id.collapse = false; el_id.collapseFit = false; el_id.collapseResetHighlight = false; el_id.collapseKeepCoord = true; el_id.collapseLabelSuffix = " (cluster)"; el_id.clusterOptions = undefined; } if(x.tree !== undefined){ el_id.tree = x.tree; } // configure if(x.options.configure !== undefined){ if(x.options.configure.container !== undefined){ var dom_conf = document.getElementById(x.options.configure.container); if(dom_conf !== null){ x.options.configure.container = dom_conf; } else { x.options.configure.container = undefined; } } } var changeInput = function(id, data) { Shiny.onInputChange(el.id + '_' + id, data); }; //************************* //title //************************* var div_title = document.createElement('div'); div_title.id = "title"+el.id; div_title.setAttribute('style','font-family:Georgia, Times New Roman, Times, serif;font-weight:bold;font-size:20px;text-align:center;'); div_title.style.display = 'none'; el_id.appendChild(div_title); if(x.main !== null){ div_title.innerHTML = x.main.text; div_title.setAttribute('style', x.main.style + ";background-color: inherit;"); div_title.style.display = 'block'; } //************************* //subtitle //************************* var div_subtitle = document.createElement('div'); div_subtitle.id = "subtitle"+el.id; div_subtitle.setAttribute('style', 'font-family:Georgia, Times New Roman, Times, serif;font-size:12px;text-align:center;'); div_subtitle.style.display = 'none'; el_id.appendChild(div_subtitle); if(x.submain !== null){ div_subtitle.innerHTML = x.submain.text; div_subtitle.setAttribute('style', x.submain.style + ";background-color: inherit;"); div_title.style.display = 'block'; } //************************* //init idselection //************************* function onIdChange(id, init) { if(id === ""){ instance.network.selectNodes([]); }else{ instance.network.selectNodes([id]); } if(el_id.highlight){ neighbourhoodHighlight(instance.network.getSelection().nodes, "click", el_id.highlightAlgorithm, true); }else{ if(init){ selectNode = document.getElementById('nodeSelect'+el.id); if(x.idselection.values !== undefined){ if(indexOf.call(x.idselection.values, id, true) > -1){ selectNode.value = id; }else{ selectNode.value = ""; } }else{ selectNode.value = id; } } } if (window.Shiny){ changeInput('selected', document.getElementById("nodeSelect"+el.id).value); } if(el_id.byselection){ resetList('selectedBy', el.id, 'selectedBy'); } } // id nodes selection : add a list on top left // actually only with nodes + edges data (not dot and gephi) var idList = document.createElement("select"); idList.setAttribute('class', 'dropdown'); idList.style.display = 'none'; idList.id = "nodeSelect"+el.id; el_id.appendChild(idList); idList.onchange = function(){ if(instance.network){ onIdChange(document.getElementById("nodeSelect"+el.id).value, false); } }; var hr = document.createElement("hr"); hr.setAttribute('style', 'height:0px; visibility:hidden; margin-bottom:-1px;'); el_id.appendChild(hr); //************************* //selectedBy //************************* function onByChange(value) { if(instance.network){ selectedHighlight(value); } if (window.Shiny){ changeInput('selectedBy', value); } if(el_id.idselection){ resetList('nodeSelect', el.id, 'selected'); } } // selectedBy : add a list on top left // actually only with nodes + edges data (not dot and gephi) //Create and append select list var byList = document.createElement("select"); byList.setAttribute('class', 'dropdown'); byList.style.display = 'none'; byList.id = "selectedBy"+el.id; el_id.appendChild(byList); byList.onchange = function(){ onByChange(document.getElementById("selectedBy"+el.id).value); }; if(el_id.byselection){ el_id.byselection_values = x.byselection.values; el_id.byselection_variable = x.byselection.variable; el_id.byselection_multiple = x.byselection.multiple; var option2; //Create and append select list var selectList2 = document.getElementById("selectedBy"+el.id); selectList2.setAttribute('style', x.byselection.style); selectList2.style.display = 'inline'; option2 = document.createElement("option"); option2.value = ""; if(x.byselection.main === undefined){ option2.text = "Select by " + x.byselection.variable; } else { option2.text = x.byselection.main; } selectList2.appendChild(option2); //Create and append the options for (var i2 = 0; i2 < x.byselection.values.length; i2++) { option2 = document.createElement("option"); option2.value = x.byselection.values[i2]; option2.text = x.byselection.values[i2]; selectList2.appendChild(option2); } if (window.Shiny){ changeInput('selectedBy', document.getElementById("selectedBy"+el.id).value); } } //************************* // pre-treatment for icons (unicode) //************************* if(x.options.groups){ for (var gr in x.options.groups){ if(x.options.groups[gr].icon){ if(x.options.groups[gr].icon.code){ x.options.groups[gr].icon.code = JSON.parse( '"'+'\\u' + x.options.groups[gr].icon.code + '"'); } if(x.options.groups[gr].icon.face){ if(x.options.groups[gr].icon.face === "'Font Awesome 5 Free'"){ x.options.groups[gr].icon.weight = "bold" } } if(x.options.groups[gr].icon.color){ x.options.groups[gr].color = x.options.groups[gr].icon.color; } } } } if(x.options.nodes.icon){ if(x.options.nodes.icon.code){ x.options.nodes.icon.code = JSON.parse( '"'+'\\u' + x.options.nodes.icon.code + '"'); } if(x.options.nodes.icon.face){ if(x.options.nodes.icon.face === "'Font Awesome 5 Free'"){ x.options.nodes.icon.weight = "bold" } } if(x.options.nodes.icon.color){ x.options.nodes.color = x.options.nodes.icon.color; } } //************************* //page structure //************************* // divide page var maindiv = document.createElement('div'); maindiv.id = "maindiv"+el.id; maindiv.setAttribute('style', 'height:95%;background-color: inherit;'); el_id.appendChild(maindiv); var graph = document.createElement('div'); graph.id = "graph"+el.id; if(x.legend !== undefined){ if((x.groups && x.legend.useGroups) || (x.legend.nodes !== undefined) || (x.legend.edges !== undefined)){ addlegend = true; } } //legend if(addlegend){ var legendwidth = x.legend.width*100; var legend = document.createElement('div'); var pos = x.legend.position; var pos2 = "right"; if(pos == "right"){ pos2 = "left"; } legend.id = "legend"+el.id; legend.setAttribute('style', 'float:' + pos + '; width:'+legendwidth+'%;height:100%'); //legend title if(x.legend.main !== undefined){ var legend_title = document.createElement('div'); legend_title.innerHTML = x.legend.main.text; legend_title.setAttribute('style', x.legend.main.style); legend.appendChild(legend_title); legend.id = "legend_main"+el.id; var legend_network = document.createElement('div'); legend_network.id = "legend"+el.id; legend_network.setAttribute('style', 'height:100%'); legend.appendChild(legend_network); } document.getElementById("maindiv"+el.id).appendChild(legend); graph.setAttribute('style', 'float:' + pos2 + '; width:'+(100-legendwidth)+'%;height:100%;background-color: inherit;'); }else{ graph.setAttribute('style', 'float:right; width:100%;height:100%;background-color: inherit;'); } document.getElementById("maindiv"+el.id).appendChild(graph); //************************* //legend definition //************************* if(addlegend){ var legendnodes = new vis.DataSet(); var legendedges = null; var datalegend; var tmpnodes; // set some options var optionslegend = { interaction:{ dragNodes: false, dragView: false, selectable: false, zoomView: x.legend.zoom }, physics:{ stabilization: false } }; function range(start, length, step, rep){ var a=[], b=start; while(a.length < length){ for (var i = 0; i < rep; i++){ a.push(b); if(a.length === length){ break; } } b+=step; } return a; }; var mynetwork = document.getElementById('legend'+el.id); var lx = mynetwork.clientWidth / 2 + 50; var ly = mynetwork.clientHeight / 2 + 50; var edge_ly = ly; var ncol = x.legend.ncol; var step_x = x.legend.stepX; var step_y = x.legend.stepY; var tmp_ly; var tmp_lx = lx; var tmp_lx2; var all_tmp_y = []; if(tmp_lx === 0){ tmp_lx = 1 } // construct nodes data if needed if(x.legend.nodes !== undefined){ if(x.legend.nodesToDataframe){ // data in data.frame tmpnodes = visNetworkdataframeToD3(x.legend.nodes, "nodes") } else { // data in list tmpnodes = x.legend.nodes; } // only one element if(tmpnodes.length === undefined){ tmpnodes = new Array(tmpnodes); } } // array of y position if(x.groups && x.legend.useGroups && x.legend.nodes !== undefined){ all_tmp_y = range(ly, x.groups.length + tmpnodes.length, step_y, ncol); } else if(x.groups && x.legend.useGroups && x.legend.nodes === undefined){ all_tmp_y = range(ly, x.groups.length, step_y, ncol); } else if(x.legend.useGroups === false && x.legend.nodes !== undefined){ all_tmp_y = range(ly, tmpnodes.length, step_y, ncol); } // want to view groups in legend if(x.groups && x.legend.useGroups){ // create data for (var g1 = 0; g1 < x.groups.length; g1++){ if(g1 === 0){ tmp_lx = lx; } else { tmp_lx = lx + g1%ncol * step_x; } tmp_ly = all_tmp_y[g1]; if(tmp_ly === 0){ tmp_ly = 1 } legendnodes.add({id: null, x : tmp_lx, y : tmp_ly, label: x.groups[g1], group: x.groups[g1], value: 1, mass:1}); edge_ly = tmp_ly; } // control icon size if(x.options.groups){ optionslegend.groups = clone(x.options.groups); for (var grp in optionslegend.groups) { if(optionslegend.groups[grp].shape === "icon"){ optionslegend.groups[grp].icon.size = 50; } } } } // want to add custom nodes if(x.legend.nodes !== undefined){ // control icon for (var nd in tmpnodes){ if(tmpnodes[nd].icon && !x.legend.nodesToDataframe){ tmpnodes[nd].icon.code = JSON.parse( '"'+'\\u' + tmpnodes[nd].icon.code + '"'); } if(tmpnodes[nd].icon && tmpnodes[nd].icon.face){ if(tmpnodes[nd].icon.face === "'Font Awesome 5 Free'"){ tmpnodes[nd].icon.weight = "bold" } } } // group control for y var add_gr_y = 0; if(x.groups && x.legend.useGroups){ add_gr_y = x.groups.length; } // set coordinates for (var g = 0; g < tmpnodes.length; g++){ if((g+legendnodes.length) === 0){ tmp_lx = lx; } else { tmp_lx = lx + (g+legendnodes.length)%ncol * step_x; } tmp_ly = all_tmp_y[add_gr_y + g]; if(tmp_lx === 0){ tmp_lx = 1 } if(tmp_ly === 0){ tmp_ly = 1 } tmpnodes[g].x = tmp_lx; tmpnodes[g].y = tmp_ly; if(tmpnodes[g].value === undefined && tmpnodes[g].size === undefined){ tmpnodes[g].value = 1; } /*if(tmpnodes[g].id !== undefined){ tmpnodes[g].id = null; }*/ tmpnodes[g].mass = 1; edge_ly = tmp_ly; } legendnodes.add(tmpnodes); } // want to add custom edges if(x.legend.edges !== undefined){ if(x.legend.edgesToDataframe){ // data in data.frame legendedges = visNetworkdataframeToD3(x.legend.edges, "edges") } else { // data in list legendedges = x.legend.edges; } // only one element if(legendedges.length === undefined){ legendedges = new Array(legendedges); } // set coordinates and options for (var edg = 0; edg < (legendedges.length); edg++){ var tmp_int = Math.floor(Math.random() * 1001); legendedges[edg].from = edg + "tmp_leg_edges_" + tmp_int + "_1"; legendedges[edg].to = edg + "tmp_leg_edges_" + tmp_int + "_2"; legendedges[edg].physics = false; legendedges[edg].smooth = false; legendedges[edg].value = undefined; if(legendedges[edg].arrows === undefined){ legendedges[edg].arrows = 'to'; } if(legendedges[edg].width === undefined){ legendedges[edg].width = 1; } tmp_ly = edge_ly + (edg+1)*step_y; if(tmp_ly === 0){ tmp_ly = 1 } if(ncol === 1){ tmp_lx = lx - mynetwork.clientWidth/3; tmp_lx2 = lx + mynetwork.clientWidth/3; } else { tmp_lx = lx; tmp_lx2 = lx + (ncol-1) * step_x; } if(tmp_lx === 0){ tmp_lx = 1 } if(tmp_lx2 === 0){ tmp_lx2 = 1 } legendnodes.add({id: edg + "tmp_leg_edges_" + tmp_int + "_1", x : tmp_lx, y : tmp_ly, size : 0.0001, hidden : false, shape : "square", mass:1}); legendnodes.add({id: edg + "tmp_leg_edges_" + tmp_int + "_2", x : tmp_lx2, y : tmp_ly, size : 0.0001, hidden : false, shape : "square", mass:1}); } } // render legend network datalegend = { nodes: legendnodes, edges: legendedges }; instance.legend = new vis.Network(document.getElementById("legend"+el.id), datalegend, optionslegend); //link network for update for re-use and update document.getElementById("legend"+el.id).network = instance.legend; } //************************* // Main Network rendering //************************* if(x.nodes){ // network nodes = new vis.DataSet(); edges = new vis.DataSet(); var tmpnodes; if(x.nodesToDataframe){ // data in data.frame tmpnodes = visNetworkdataframeToD3(x.nodes, "nodes") } else { // data in list tmpnodes = x.nodes; } // only one element if(tmpnodes.length === undefined){ tmpnodes = new Array(tmpnodes); } // update coordinates if igraph if(x.igraphlayout !== undefined){ // to improved var zoomLevel = -232.622349 / (tmpnodes.length + 91.165919) +2.516861; var igclientWidth = document.getElementById("graph"+el.id).clientWidth; var scalex = 100; var scaley = 100; // current div visibled if(igclientWidth !== 0){ var factor = igclientWidth / 1890; zoomLevel = zoomLevel/factor; var scalex = (igclientWidth / 2) * zoomLevel; var scaley = scalex; if(x.igraphlayout.type !== "square"){ scaley = (document.getElementById("graph"+el.id).clientHeight / 2) * zoomLevel; } } else { // current div not visibled.... igclientWidth = parseInt(el_id.style.width); if(igclientWidth !== 0){ var factor = igclientWidth / 1890; zoomLevel = zoomLevel/factor; var scalex = (igclientWidth / 2) * zoomLevel; var scaley = scalex; if(x.igraphlayout.type !== "square"){ scaley = (parseInt(el_id.style.height) / 2) * zoomLevel; } } } for (var nd in tmpnodes) { tmpnodes[nd].x = tmpnodes[nd].x * scalex; tmpnodes[nd].y = tmpnodes[nd].y * scaley; } } nodes.add(tmpnodes); var tmpedges; if(x.edgesToDataframe){ // data in data.frame tmpedges = visNetworkdataframeToD3(x.edges, "edges") } else { // data in list tmpedges = x.edges; } // only one element if(tmpedges !== null){ if(tmpedges.length === undefined){ tmpedges = new Array(tmpedges); } edges.add(tmpedges); } // reset tmpnodes tmpnodes = null; data = { nodes: nodes, edges: edges }; //save data for re-use and update document.getElementById("graph"+el.id).nodes = nodes; document.getElementById("graph"+el.id).edges = edges; }else if(x.dot){ data = { dot: x.dot }; }else if(x.gephi){ data = { gephi: x.gephi }; } var options = x.options; //************************* //manipulation //************************* if(x.options.manipulation.enabled){ var style = document.createElement('style'); style.type = 'text/css'; style.appendChild(document.createTextNode(x.opts_manipulation.datacss)); document.getElementsByTagName("head")[0].appendChild(style); var div_addnode = document.createElement('div'); div_addnode.id = 'addnode-popUp'; div_addnode.classList.add('network-popUp'); div_addnode.innerHTML = x.opts_manipulation.tab_add_node; el_id.appendChild(div_addnode); var div_editnode = document.createElement('div'); div_editnode.id = 'editnode-popUp'; div_editnode.classList.add('network-popUp'); div_editnode.innerHTML = x.opts_manipulation.tab_edit_node; el_id.appendChild(div_editnode); var div_editedge = document.createElement('div'); div_editedge.id = 'editedge-popUp'; div_editedge.classList.add('network-popUp'); div_editedge.innerHTML = x.opts_manipulation.tab_edit_edge; el_id.appendChild(div_editedge); if(x.options.manipulation.addNode === undefined){ options.manipulation.addNode = function(data, callback) { document.getElementById('addnode-operation').innerHTML = "Add Node"; for (var nodecol = 0; nodecol < x.opts_manipulation.addNodeCols.length; nodecol++){ document.getElementById('addnode-' + x.opts_manipulation.addNodeCols[nodecol]).value = data[x.opts_manipulation.addNodeCols[nodecol]]; } document.getElementById('addnode-saveButton').onclick = saveNode.bind(this, data, callback, "addNode"); document.getElementById('addnode-cancelButton').onclick = clearPopUp.bind(); document.getElementById('addnode-popUp').style.display = 'block'; }; } else if(typeof(x.options.manipulation.addNode) === typeof(true)){ if(x.options.manipulation.addNode){ options.manipulation.addNode = function(data, callback) { document.getElementById('addnode-operation').innerHTML = "Add Node"; for (var nodecol = 0; nodecol < x.opts_manipulation.addNodeCols.length; nodecol++){ document.getElementById('addnode-' + x.opts_manipulation.addNodeCols[nodecol]).value = data[x.opts_manipulation.addNodeCols[nodecol]]; } document.getElementById('addnode-saveButton').onclick = saveNode.bind(this, data, callback, "addNode"); document.getElementById('addnode-cancelButton').onclick = clearPopUp.bind(); document.getElementById('addnode-popUp').style.display = 'block'; }; } else { options.manipulation.addNode = false; } } else { options.manipulation.addNode = x.options.manipulation.addNode; } if(x.options.manipulation.editNode === undefined){ options.manipulation.editNode = function(data, callback) { var node_data = nodes.get(data.id); document.getElementById('editnode-operation').innerHTML = "Edit Node"; for (var nodecol = 0; nodecol < x.opts_manipulation.editNodeCols.length; nodecol++){ document.getElementById('editnode-' + x.opts_manipulation.editNodeCols[nodecol]).value = node_data[x.opts_manipulation.editNodeCols[nodecol]]; } document.getElementById('editnode-saveButton').onclick = saveNode.bind(this, data, callback, "editNode"); document.getElementById('editnode-cancelButton').onclick = cancelEdit.bind(this,callback); document.getElementById('editnode-popUp').style.display = 'block'; }; } else if(typeof(x.options.manipulation.editNode) === typeof(true)){ if(x.options.manipulation.editNode){ options.manipulation.editNode = function(data, callback) { var node_data = nodes.get(data.id); document.getElementById('editnode-operation').innerHTML = "Edit Node"; for (var nodecol = 0; nodecol < x.opts_manipulation.editNodeCols.length; nodecol++){ document.getElementById('editnode-' + x.opts_manipulation.editNodeCols[nodecol]).value = node_data[x.opts_manipulation.editNodeCols[nodecol]]; } document.getElementById('editnode-saveButton').onclick = saveNode.bind(this, data, callback, "editNode"); document.getElementById('editnode-cancelButton').onclick = cancelEdit.bind(this,callback); document.getElementById('editnode-popUp').style.display = 'block'; }; } else { options.manipulation.editNode = false; } } else { options.manipulation.editNode = x.options.manipulation.editNode; } if(x.options.manipulation.deleteNode === undefined){ options.manipulation.deleteNode = function(data, callback) { var r = confirm("Do you want to delete " + data.nodes.length + " node(s) and " + data.edges.length + " edges ?"); if (r === true) { deleteSubGraph(data, callback); } else { clearPopUp(); callback(null); } }; } else if(typeof(x.options.manipulation.deleteNode) === typeof(true)){ if(x.options.manipulation.deleteNode){ options.manipulation.deleteNode = function(data, callback) { var r = confirm("Do you want to delete " + data.nodes.length + " node(s) and " + data.edges.length + " edges ?"); if (r === true) { deleteSubGraph(data, callback); } else { clearPopUp(); callback(null); } }; } else { options.manipulation.deleteNode = false; } } else { options.manipulation.deleteNode = x.options.manipulation.deleteNode; } if(x.options.manipulation.deleteEdge === undefined){ options.manipulation.deleteEdge = function(data, callback) { var r = confirm("Do you want to delete " + data.edges.length + " edges ?"); if (r === true) { deleteSubGraph(data, callback); } else { clearPopUp(); callback(null); } }; } else if(typeof(x.options.manipulation.deleteEdge) === typeof(true)){ if(x.options.manipulation.deleteEdge){ options.manipulation.deleteEdge = function(data, callback) { var r = confirm("Do you want to delete " + data.edges.length + " edges ?"); if (r === true) { deleteSubGraph(data, callback); } else { clearPopUp(); callback(null); } }; } else { options.manipulation.deleteEdge = false; } } else { options.manipulation.deleteEdge = x.options.manipulation.deleteEdge; } if(x.options.manipulation.addEdge === undefined){ options.manipulation.addEdge = function(data, callback) { if (data.from == data.to) { var r = confirm("Do you want to connect the node to itself?"); if (r === true) { saveEdge(data, callback, "addEdge"); } } else { saveEdge(data, callback, "addEdge"); } }; } else if(typeof(x.options.manipulation.addEdge) === typeof(true)){ if(x.options.manipulation.addEdge){ options.manipulation.addEdge = function(data, callback) { if (data.from == data.to) { var r = confirm("Do you want to connect the node to itself?"); if (r === true) { saveEdge(data, callback, "addEdge"); } } else { saveEdge(data, callback, "addEdge"); } }; } else { options.manipulation.addEdge = false; } } else { options.manipulation.addEdge = x.options.manipulation.addEdge; } if(x.options.manipulation.editEdge === undefined){ if(x.opts_manipulation.tab_edit_edge){ options.manipulation.editEdge = {editWithoutDrag : function(data, callback) { var edge_data = edges.get(data.id); document.getElementById('editedge-operation').innerHTML = "Edit Edge"; for (var edgecol = 0; edgecol < x.opts_manipulation.editEdgeCols.length; edgecol++){ document.getElementById('editedge-' + x.opts_manipulation.editEdgeCols[edgecol]).value = edge_data[x.opts_manipulation.editEdgeCols[edgecol]]; } document.getElementById('editedge-saveButton').onclick = saveEdge.bind(this, data, callback, "editEdgeCols"); document.getElementById('editedge-cancelButton').onclick = cancelEdit.bind(this,callback); document.getElementById('editedge-popUp').style.display = 'block'; } } } else { options.manipulation.editEdge = function(data, callback) { if (data.from == data.to) { var r = confirm("Do you want to connect the node to itself?"); if (r === true) { saveEdge(data, callback, "editEdge"); } } else { saveEdge(data, callback, "editEdge"); } }; } } else if(typeof(x.options.manipulation.editEdge) === typeof(true)){ if(x.options.manipulation.editEdge){ if(x.opts_manipulation.tab_edit_edge){ options.manipulation.editEdge = {editWithoutDrag : function(data, callback) { var edge_data = edges.get(data.id); document.getElementById('editedge-operation').innerHTML = "Edit Edge"; for (var edgecol = 0; edgecol < x.opts_manipulation.editEdgeCols.length; edgecol++){ document.getElementById('editedge-' + x.opts_manipulation.editEdgeCols[edgecol]).value = edge_data[x.opts_manipulation.editEdgeCols[edgecol]]; } document.getElementById('editedge-saveButton').onclick = saveEdge.bind(this, data, callback, "editEdgeCols"); document.getElementById('editedge-cancelButton').onclick = cancelEdit.bind(this,callback); document.getElementById('editedge-popUp').style.display = 'block'; } } } else { options.manipulation.editEdge = function(data, callback) { if (data.from == data.to) { var r = confirm("Do you want to connect the node to itself?"); if (r === true) { saveEdge(data, callback, "editEdge"); } } else { saveEdge(data, callback, "editEdge"); } }; } } else { options.manipulation.editEdge = false; } } else { options.manipulation.editEdge = x.options.manipulation.editEdge; } } // create network instance.network = new vis.Network(document.getElementById("graph"+el.id), data, options); if (window.Shiny){ Shiny.onInputChange(el.id + '_initialized', true); } //************************* //add values to idselection //************************* if(el_id.idselection){ var selectList = document.getElementById("nodeSelect"+el.id) setNodeIdList(selectList, x.idselection, nodes) if (window.Shiny){ changeInput('selected', document.getElementById("nodeSelect"+el.id).value); } } //console.info(instance.network) //save data for re-use and update document.getElementById("graph"+el.id).chart = instance.network; document.getElementById("graph"+el.id).options = options; ///////// // popup ///////// // Temporary variables to hold mouse x-y pos.s var tempX = 0 var tempY = 0 // Main function to retrieve mouse x-y pos.s function getMouseXY(e) { tempX = e.clientX tempY = e.clientY // catch possible negative values in NS if (tempX < 0){tempX = 0} if (tempY < 0){tempY = 0} } document.addEventListener('mousemove', getMouseXY); //this.body.emitter.emit("showPopup",{id:this.popupObj.id,x:t.x+3,y:t.y-5})) // popup for title var popupState = false; var popupTimeout = null; var vispopup = document.createElement("div"); // disable vis.js tooltip var style = document.createElement('style'); style.type = 'text/css'; style.innerHTML = 'div.vis-tooltip {display : none}'; document.getElementsByTagName('head')[0].appendChild(style); var popupStyle = 'position: fixed;visibility:hidden;padding: 5px;font-family: verdana;font-size:14px;font-color:#000000;background-color: #f5f4ed;-moz-border-radius: 3px;-webkit-border-radius: 3px;border-radius: 3px;border: 1px solid #808074;box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2);max-width:400px;word-break: break-all' if(x.tooltipStyle !== undefined){ popupStyle = x.tooltipStyle } var popupStay = 300; if(x.tooltipStay !== undefined){ popupStay = x.tooltipStay } vispopup.setAttribute('style', popupStyle) document.getElementById("graph"+el.id).appendChild(vispopup); // add some event listeners to avoid it disappearing when the mouse if over it. vispopup.addEventListener('mouseover',function () { if (popupTimeout !== null) { clearTimeout(popupTimeout); popupTimeout = null; } }); // set the timeout when the mouse leaves it. vispopup.addEventListener('mouseout',function () { if (popupTimeout === null) { myHidePopup(100); } }); // use the popup event to show instance.network.on("showPopup", function(params) { popupState = true; myShowPopup(params); }) // use the hide event to hide it instance.network.on("hidePopup", function(params) { // avoid double firing of this event, bug in 4.2.0 if (popupState === true) { popupState = false; myHidePopup(popupStay); } }) // hiding the popup through css and a timeout function myHidePopup(delay) { popupTimeout = setTimeout(function() {vispopup.style.visibility = 'hidden';}, delay); } // showing the popup function myShowPopup(id) { // get the data from the vis.DataSet var nodeData = nodes.get([id]); var edgeData = edges.get([id]); // a node ? if(nodeData[0] !== null && nodeData[0] !== undefined){ vispopup.innerHTML = nodeData[0].title; // show and place the tooltip. vispopup.style.visibility = 'visible'; vispopup.style.top = tempY - 20 + "px"; vispopup.style.left = tempX + 5 + "px"; } else if(edgeData[0] !== null && edgeData[0] !== undefined){ // so it's perhaps a edge ? vispopup.innerHTML = edgeData[0].title; // show and place the tooltip. vispopup.style.visibility = 'visible'; vispopup.style.top = tempY - 20 + "px"; vispopup.style.left = tempX + 5 + "px"; } else { // or a cluster ? var node_cluster = instance.network.body.nodes[id] if(node_cluster !== undefined){ vispopup.innerHTML = node_cluster.options.title; // show and place the tooltip. vispopup.style.visibility = 'visible'; vispopup.style.top = tempY - 20 + "px"; vispopup.style.left = tempX + 5 + "px"; } } // for sparkline. Eval script... var any_script= vispopup.getElementsByTagName('script') for (var n = 0; n < any_script.length; n++){ if(any_script[n].getAttribute("type") === "text/javascript"){ eval(any_script[n].innerHTML); } } } //************************* // Events //************************* if(x.events !== undefined){ for (var key in x.events) { instance.network.on(key, x.events[key]); } } if(x.OnceEvents !== undefined){ for (var key in x.OnceEvents) { instance.network.once(key, x.OnceEvents[key]); } } if(x.ResetEvents !== undefined){ for (var key in x.ResetEvents) { instance.network.off(key); } } //************************* // Selected Highlight //************************* function selectedHighlight(value) { // get current nodes var allNodes = nodes.get({returnType:"Object"}); // first resetEdges resetAllEdges(edges, el_id.byselectionColor, el_id.highlightColor, instance.network); var connectedNodes = []; // get variable var sel = el_id.byselection_variable; // need to make an update? var update = !(el_id.selectActive === false && value === ""); if (value !== "") { var updateArray = []; el_id.selectActive = true; // mark all nodes as hard to read. for (var nodeId in allNodes) { var value_in = false; // unique selection if(el_id.byselection_multiple === false){ if(sel == "label"){ value_in = ((allNodes[nodeId]["label"] + "") === value) || ((allNodes[nodeId]["hiddenLabel"] + "") === value); }else if(sel == "color"){ value_in = ((allNodes[nodeId]["color"] + "") === value) || ((allNodes[nodeId]["hiddenColor"] + "") === value); }else { value_in = (allNodes[nodeId][sel] + "") === value; } }else{ // multiple selection if(sel == "label"){ var current_value = allNodes[nodeId]["label"] + ""; var value_split = current_value.split(",").map(Function.prototype.call, String.prototype.trim); var current_value2 = allNodes[nodeId]["hiddenLabel"] + ""; var value_split2 = current_value.split(",").map(Function.prototype.call, String.prototype.trim); value_in = (value_split.indexOf(value) !== -1) || (value_split2.indexOf(value) !== -1); }else if(sel == "color"){ var current_value = allNodes[nodeId]["color"] + ""; var value_split = current_value.split(",").map(Function.prototype.call, String.prototype.trim); var current_value2 = allNodes[nodeId]["hiddenColor"] + ""; var value_split2 = current_value.split(",").map(Function.prototype.call, String.prototype.trim); value_in = (value_split.indexOf(value) !== -1) || (value_split2.indexOf(value) !== -1); }else { var current_value = allNodes[nodeId][sel] + ""; var value_split = current_value.split(",").map(Function.prototype.call, String.prototype.trim); value_in = value_split.indexOf(value) !== -1; } } if(value_in === false){ // not in selection, so as hard to read nodeAsHardToRead(allNodes[nodeId], options, el_id.byselectionColor, el_id.highlightColor, instance.network, "node"); } else { // in selection, so reset if needed connectedNodes = connectedNodes.concat(allNodes[nodeId].id); resetOneNode(allNodes[nodeId], options, instance.network); } allNodes[nodeId].x = undefined; allNodes[nodeId].y = undefined; // update data if (allNodes.hasOwnProperty(nodeId) && update) { updateArray.push(allNodes[nodeId]); } } if(update){ // set some edges as hard to read var edgesHardToRead = edges.get({ fields: ['id', 'color', 'hiddenColor', 'hiddenLabel', 'label'], filter: function (item) { return (indexOf.call(connectedNodes, item.from, true) === -1) ; }, returnType :'Array' }); // all in degree nodes get their own color and their label back for (i = 0; i < edgesHardToRead.length; i++) { edgeAsHardToRead(edgesHardToRead[i], el_id.byselectionColor, el_id.highlightColor, instance.network, type = "edge") } edges.update(edgesHardToRead); nodes.update(updateArray); // select for highlight if(el_id.highlight && x.nodes && el_id.byselectionHighlight){ neighbourhoodHighlight(connectedNodes, "click", el_id.highlightAlgorithm, false); instance.network.selectNodes(connectedNodes) } } } else if (el_id.selectActive === true) { //reset nodes resetAllNodes(nodes, update, options, instance.network, false) el_id.selectActive = false } } //************************* //Highlight //************************* var is_hovered = false; var is_clicked = false; function neighbourhoodHighlight(params, action_type, algorithm, reset_selectedBy) { var nodes_in_clusters = instance.network.body.modules.clustering.clusteredNodes; var have_cluster_nodes = false; if(Object.keys(nodes_in_clusters).length > 0){ have_cluster_nodes = true; nodes_in_clusters = Object.keys(nodes_in_clusters); edges_in_clusters = Object.keys(instance.network.body.modules.clustering.clusteredEdges); } else { nodes_in_clusters = []; edges_in_clusters = []; } var selectNode; // get nodes data var allNodes = nodes.get({returnType:"Object"}); // cluster var array_cluster_id; // update var update = !(el_id.highlightActive === false && params.length === 0) | (el_id.selectActive === true && params.length === 0); if(!(action_type == "hover" && is_clicked)){ // first resetEdges resetAllEdges(edges, el_id.highlightColor, el_id.byselectionColor, instance.network); if (params.length > 0) { var is_cluster = instance.network.isCluster(params[0]); var selectedNode; if(is_cluster){ selectedNode = instance.network.getNodesInCluster(params[0]); } else { selectedNode = params; } var updateArray = []; if(el_id.idselection){ selectNode = document.getElementById('nodeSelect'+el.id); if(is_cluster === false){ if(x.idselection.values !== undefined){ if(indexOf.call(x.idselection.values, selectedNode[0], true) > -1){ selectNode.value = selectedNode[0]; }else{ selectNode.value = ""; } }else{ selectNode.value = selectedNode[0]; } if (window.Shiny){ changeInput('selected', selectNode.value); } } } el_id.highlightActive = true; var i,j; var degrees = el_id.degree; // mark all nodes as hard to read. for (var nodeId in instance.network.body.nodes) { if(instance.network.isCluster(nodeId)){ nodeAsHardToRead(instance.network.body.nodes[nodeId], options, el_id.highlightColor, el_id.byselectionColor, instance.network, "cluster"); }else { var tmp_node = allNodes[nodeId]; if(tmp_node !== undefined){ nodeAsHardToRead(tmp_node, options, el_id.highlightColor, el_id.byselectionColor, instance.network, "node"); tmp_node.x = undefined; tmp_node.y = undefined; } } } if(algorithm === "all"){ var connectedNodes; if(degrees > 0){ connectedNodes = []; for (j = 0; j < selectedNode.length; j++) { connectedNodes = connectedNodes.concat(instance.network.getConnectedNodes(selectedNode[j], true)); } connectedNodes = uniqueArray(connectedNodes, true, instance.network); }else{ connectedNodes = selectedNode; } var allConnectedNodes = []; // get the nodes to color if(degrees >= 2){ for (i = 2; i <= degrees; i++) { var previous_connectedNodes = connectedNodes; var currentlength = connectedNodes.length; for (j = 0; j < currentlength; j++) { connectedNodes = uniqueArray(connectedNodes.concat(instance.network.getConnectedNodes(connectedNodes[j])), true, instance.network); } if (connectedNodes.length === previous_connectedNodes.length) { break; } } } // nodes to just label for (j = 0; j < connectedNodes.length; j++) { allConnectedNodes = allConnectedNodes.concat(instance.network.getConnectedNodes(connectedNodes[j])); } allConnectedNodes = uniqueArray(allConnectedNodes, true, instance.network); if(el_id.highlightLabelOnly === true){ // all higher degree nodes get a different color and their label back array_cluster_id = []; for (i = 0; i < allConnectedNodes.length; i++) { if (allNodes[allConnectedNodes[i]].hiddenLabel !== undefined) { allNodes[allConnectedNodes[i]].label = allNodes[allConnectedNodes[i]].hiddenLabel; allNodes[allConnectedNodes[i]].hiddenLabel = undefined; if(have_cluster_nodes){ if(indexOf.call(nodes_in_clusters, allConnectedNodes[i], true) > -1){ array_cluster_id = array_cluster_id.concat(instance.network.clustering.findNode(allConnectedNodes[i])[0]); } } } } if(array_cluster_id.length > 0){ array_cluster_id = uniqueArray(array_cluster_id, false, instance.network); for (i = 0; i < array_cluster_id.length; i++) { instance.network.body.nodes[array_cluster_id[i]].setOptions({label : instance.network.body.nodes[array_cluster_id[i]].options.hiddenLabel, hiddenLabel:undefined}) } } } // all in degree nodes get their own color and their label back + main nodes connectedNodes = connectedNodes.concat(selectedNode); if (window.Shiny){ Shiny.onInputChange(el.id + '_highlight_color_id', uniqueShiny(connectedNodes)); } if(el_id.highlightLabelOnly === true){ if (window.Shiny){ Shiny.onInputChange(el.id + '_highlight_label_id', allConnectedNodes.filter(function(x){ return !connectedNodes.includes(x)})); } } array_cluster_id = []; for (i = 0; i < connectedNodes.length; i++) { resetOneNode(allNodes[connectedNodes[i]], options, instance.network); if(have_cluster_nodes){ if(indexOf.call(nodes_in_clusters, connectedNodes[i], true) > -1){ array_cluster_id = array_cluster_id.concat(instance.network.clustering.findNode(connectedNodes[i])[0]); } } } if(array_cluster_id.length > 0){ array_cluster_id = uniqueArray(array_cluster_id, false, instance.network); for (i = 0; i < array_cluster_id.length; i++) { resetOneCluster(instance.network.body.nodes[array_cluster_id[i]], options, instance.network); } } // set some edges as hard to read var edgesHardToRead = edges.get({ fields: ['id', 'color', 'hiddenColor', 'hiddenLabel', 'label'], filter: function (item) { return ((indexOf.call(connectedNodes, item.from, true) === -1)) ; }, returnType :'Array' }); // all in degree nodes get their own color and their label back array_cluster_id = []; var tmp_cluster_id; for (i = 0; i < edgesHardToRead.length; i++) { edgeAsHardToRead(edgesHardToRead[i], el_id.highlightColor, el_id.byselectionColor, instance.network, type = "edge") if(have_cluster_nodes){ if(indexOf.call(edges_in_clusters, edgesHardToRead[i].id, true) > -1){ tmp_cluster_id = instance.network.clustering.getClusteredEdges(edgesHardToRead[i].id); if(tmp_cluster_id.length > 1){ array_cluster_id = array_cluster_id.concat(tmp_cluster_id[0]); } } } } if(array_cluster_id.length > 0){ array_cluster_id = uniqueArray(array_cluster_id, false, instance.network); for (i = 0; i < array_cluster_id.length; i++) { edgeAsHardToRead(instance.network.body.edges[array_cluster_id[i]].options, el_id.highlightColor, el_id.byselectionColor, instance.network, type = "cluster") } } edges.update(edgesHardToRead); } else if(algorithm === "hierarchical"){ var degree_from = degrees.from; var degree_to = degrees.to; degrees = Math.max(degree_from, degree_to); var allConnectedNodes = []; var currentConnectedFromNodes = []; var currentConnectedToNodes = []; var connectedFromNodes = []; var connectedToNodes = []; if(degree_from > 0){ connectedFromNodes = edges.get({ fields: ['from'], filter: function (item) { return ((indexOf.call(selectedNode, item.to, true) !== -1)) ; }, returnType :'Array' }); } if(degree_to > 0){ connectedToNodes = edges.get({ fields: ['to'], filter: function (item) { return ((indexOf.call(selectedNode, item.from, true) !== -1)) ; }, returnType :'Array' }); } for (j = 0; j < connectedFromNodes.length; j++) { allConnectedNodes = allConnectedNodes.concat(connectedFromNodes[j].from); currentConnectedFromNodes = currentConnectedFromNodes.concat(connectedFromNodes[j].from); } for (j = 0; j < connectedToNodes.length; j++) { allConnectedNodes = allConnectedNodes.concat(connectedToNodes[j].to); currentConnectedToNodes = currentConnectedToNodes.concat(connectedToNodes[j].to); } var go_from; var go_to; if(degrees > 1){ for (i = 2; i <= degrees; i++) { go_from = false; go_to = false; if(currentConnectedFromNodes.length > 0 && i <= degree_from){ connectedFromNodes = edges.get({ fields: ['from'], filter: function (item) { return indexOf.call(currentConnectedFromNodes, item.to, true) > -1; }, returnType :'Array' }); go_from = true; } if(currentConnectedToNodes.length > 0 && i <= degree_to){ connectedToNodes = edges.get({ fields: ['to'], filter: function (item) { return indexOf.call(currentConnectedToNodes, item.from, true) > -1; }, returnType :'Array' }); go_to = true; } if(go_from === true){ currentConnectedFromNodes = []; for (j = 0; j < connectedFromNodes.length; j++) { allConnectedNodes = allConnectedNodes.concat(connectedFromNodes[j].from); currentConnectedFromNodes = currentConnectedFromNodes.concat(connectedFromNodes[j].from); } } if(go_to === true){ currentConnectedToNodes = []; for (j = 0; j < connectedToNodes.length; j++) { allConnectedNodes = allConnectedNodes.concat(connectedToNodes[j].to); currentConnectedToNodes = currentConnectedToNodes.concat(connectedToNodes[j].to); } } if (go_from === false && go_to === false) { break;} } } allConnectedNodes = uniqueArray(allConnectedNodes, true, instance.network).concat(selectedNode); var nodesWithLabel = []; if(el_id.highlightLabelOnly === true){ if(degrees > 0){ // nodes to just label for (j = 0; j < currentConnectedToNodes.length; j++) { nodesWithLabel = nodesWithLabel.concat(instance.network.getConnectedNodes(currentConnectedToNodes[j])); } for (j = 0; j < currentConnectedFromNodes.length; j++) { nodesWithLabel = nodesWithLabel.concat(instance.network.getConnectedNodes(currentConnectedFromNodes[j])); } nodesWithLabel = uniqueArray(nodesWithLabel, true, instance.network); } else{ nodesWithLabel = currentConnectedToNodes; nodesWithLabel = nodesWithLabel.concat(currentConnectedFromNodes); nodesWithLabel = uniqueArray(nodesWithLabel, true, instance.network); } } // all higher degree nodes get a different color and their label back array_cluster_id = []; for (i = 0; i < nodesWithLabel.length; i++) { if (allNodes[nodesWithLabel[i]].hiddenLabel !== undefined) { allNodes[nodesWithLabel[i]].label = allNodes[nodesWithLabel[i]].hiddenLabel; allNodes[nodesWithLabel[i]].hiddenLabel = undefined; if(have_cluster_nodes){ if(indexOf.call(nodes_in_clusters, nodesWithLabel[i], true) > -1){ array_cluster_id = array_cluster_id.concat(instance.network.clustering.findNode(nodesWithLabel[i])[0]); } } } } if(array_cluster_id.length > 0){ array_cluster_id = uniqueArray(array_cluster_id, false, instance.network); for (i = 0; i < array_cluster_id.length; i++) { instance.network.body.nodes[array_cluster_id[i]].setOptions({label : instance.network.body.nodes[array_cluster_id[i]].options.hiddenLabel, hiddenLabel:undefined}) } } // all in degree nodes get their own color and their label back array_cluster_id = []; for (i = 0; i < allConnectedNodes.length; i++) { resetOneNode(allNodes[allConnectedNodes[i]], options, instance.network); if(have_cluster_nodes){ if(indexOf.call(nodes_in_clusters, allConnectedNodes[i], true) > -1){ array_cluster_id = array_cluster_id.concat(instance.network.clustering.findNode(allConnectedNodes[i])[0]); } } } if(array_cluster_id.length > 0){ array_cluster_id = uniqueArray(array_cluster_id, false, instance.network); for (i = 0; i < array_cluster_id.length; i++) { resetOneCluster(instance.network.body.nodes[array_cluster_id[i]], options, instance.network); } } if (window.Shiny){ Shiny.onInputChange(el.id + '_highlight_color_id', uniqueShiny(allConnectedNodes)); } if(el_id.highlightLabelOnly === true){ if (window.Shiny){ Shiny.onInputChange(el.id + '_highlight_label_id', nodesWithLabel.filter(function(x) {return !allConnectedNodes.includes(x)})); } } // set some edges as hard to read var edgesHardToRead = edges.get({ fields: ['id', 'color', 'hiddenColor', 'hiddenLabel', 'label'], filter: function (item) { return ((indexOf.call(allConnectedNodes, item.from, true) === -1) || (indexOf.call(allConnectedNodes, item.to, true) === -1)) ; }, returnType :'Array' }); array_cluster_id = []; for (i = 0; i < edgesHardToRead.length; i++) { edgeAsHardToRead(edgesHardToRead[i], el_id.highlightColor, el_id.byselectionColor, instance.network, type = "edge") if(have_cluster_nodes){ if(indexOf.call(edges_in_clusters, edgesHardToRead[i].id, true) > -1){ var tmp_cluster_id = instance.network.clustering.getClusteredEdges(edgesHardToRead[i].id); if(tmp_cluster_id.length > 1){ array_cluster_id = array_cluster_id.concat(tmp_cluster_id[0]); } } } } if(array_cluster_id.length > 0){ array_cluster_id = uniqueArray(array_cluster_id, false, instance.network); for (i = 0; i < array_cluster_id.length; i++) { edgeAsHardToRead(instance.network.body.edges[array_cluster_id[i]].options, el_id.highlightColor, el_id.byselectionColor, instance.network, type = "cluster"); } } edges.update(edgesHardToRead); } if(update){ if(!(action_type == "hover")){ is_clicked = true; } // transform the object into an array var updateArray = []; for (nodeId in allNodes) { if (allNodes.hasOwnProperty(nodeId)) { updateArray.push(allNodes[nodeId]); } } nodes.update(updateArray); }else{ is_clicked = false; } } else if (el_id.highlightActive === true | el_id.selectActive === true) { // reset nodeSelect list if actived if(el_id.idselection){ resetList("nodeSelect", el.id, 'selected'); } //reset nodes resetAllNodes(nodes, update, options, instance.network, false) el_id.highlightActive = false; is_clicked = false; if (window.Shiny){ Shiny.onInputChange(el.id + '_highlight_label_id', null) Shiny.onInputChange(el.id + '_highlight_color_id', null) } } } // reset selectedBy list if actived if(el_id.byselection && reset_selectedBy){ resetList("selectedBy", el.id, 'selectedBy'); } } function onClickIDSelection(selectedItems) { var selectNode; if(el_id.idselection){ if (selectedItems.nodes.length !== 0) { selectNode = document.getElementById('nodeSelect'+el.id); if(x.idselection.values !== undefined){ if(indexOf.call(x.idselection.values, selectedItems.nodes[0], true) > -1){ selectNode.value = selectedItems.nodes; }else{ selectNode.value = ""; } }else{ selectNode.value = selectedItems.nodes; } if (window.Shiny){ changeInput('selected', selectNode.value); } }else{ resetList("nodeSelect", el.id, 'selected'); } } if(el_id.byselection){ // reset selectedBy list if actived if (selectedItems.nodes.length === 0) { resetList("selectedBy", el.id, 'selectedBy'); selectedHighlight(""); } } } // shared click function (selectedNodes) document.getElementById("graph"+el.id).myclick = function(params){ if(el_id.highlight && x.nodes){ neighbourhoodHighlight(params.nodes, "click", el_id.highlightAlgorithm, true); }else if((el_id.idselection || el_id.byselection) && x.nodes){ onClickIDSelection(params) } }; // Set event in relation with highlightNearest instance.network.on("click", function(params){ if(el_id.highlight && x.nodes){ neighbourhoodHighlight(params.nodes, "click", el_id.highlightAlgorithm, true); }else if((el_id.idselection || el_id.byselection) && x.nodes){ onClickIDSelection(params) } }); instance.network.on("hoverNode", function(params){ if(el_id.hoverNearest && x.nodes){ neighbourhoodHighlight([params.node], "hover", el_id.highlightAlgorithm, true); } }); instance.network.on("blurNode", function(params){ if(el_id.hoverNearest && x.nodes){ neighbourhoodHighlight([], "hover", el_id.highlightAlgorithm, true); } }); //************************* //collapse //************************* instance.network.on("doubleClick", function(params){ if(el_id.collapse){ collapsedNetwork(params.nodes, el_id.collapseFit, el_id.collapseResetHighlight, el_id.clusterOptions, el_id.collapseLabelSuffix, el_id.tree, instance.network, el.id) } }); if(el_id.collapse){ instance.network.on("doubleClick", networkOpenCluster); } //************************* //footer //************************* var div_footer = document.createElement('div'); div_footer.id = "footer"+el.id; div_footer.setAttribute('style', 'font-family:Georgia, Times New Roman, Times, serif;font-size:12px;text-align:center;background-color: inherit;'); div_footer.style.display = 'none'; document.getElementById("graph" + el.id).appendChild(div_footer); if(x.footer !== null){ div_footer.innerHTML = x.footer.text; div_footer.setAttribute('style', x.footer.style + ';background-color: inherit;'); div_footer.style.display = 'block'; } //************************* // export //************************* if(x.export !== undefined){ var downloaddiv = document.createElement('div'); downloaddiv.setAttribute('style', 'float:right; width:100%;background-color: inherit;'); var downloadbutton = document.createElement("button"); downloadbutton.setAttribute('style', x.export.css); downloadbutton.style.position = "relative"; downloadbutton.id = "download"+el.id; downloadbutton.appendChild(document.createTextNode(x.export.label)); downloaddiv.appendChild(downloadbutton); var hr = document.createElement("hr"); hr.setAttribute('style', 'height:5px; visibility:hidden; margin-bottom:-1px;'); downloaddiv.appendChild(hr); document.getElementById("maindiv"+el.id).appendChild(downloaddiv); document.getElementById("download"+el.id).onclick = function() { // height control for export var addHeightExport = document.getElementById("graph" + el.id).offsetHeight + idList.offsetHeight + byList.offsetHeight + downloaddiv.offsetHeight; if(div_title.style.display !== 'none'){ addHeightExport = addHeightExport + div_title.offsetHeight; } if(div_subtitle.style.display !== 'none'){ addHeightExport = addHeightExport + div_subtitle.offsetHeight; } if(div_footer.style.display !== 'none'){ addHeightExport = addHeightExport + div_footer.offsetHeight; } else { addHeightExport = addHeightExport + 15; } downloadbutton.style.display = 'none'; var export_background = x.export.background; if(x.background !== "transparent" && x.background !== "rgba(0, 0, 0, 0)"){ export_background = x.background } if(x.export.type !== "pdf"){ html2canvas(el_id, { background: export_background, height : addHeightExport, onrendered: function(canvas) { canvas.toBlobHD(function(blob) { saveAs(blob, x.export.name); }, "image/"+x.export.type); } }); } else { html2canvas(el_id, { background: export_background, height : addHeightExport, onrendered: function(canvas) { var myImage = canvas.toDataURL("image/png", 1.0); //var imgWidth = (canvas.width * 25.4) / 24; //var imgHeight = (canvas.height * 25.4) / 24; var table = new jsPDF('l', 'pt', [canvas.width, canvas.height]); table.addImage(myImage, 'JPEG', 0, 0, canvas.width, canvas.height); table.save(x.export.name); } }); } downloadbutton.style.display = 'block'; }; } //************************* // dataManipulation //************************* function clearPopUp() { if(x.opts_manipulation.tab_add_node){ document.getElementById('addnode-saveButton').onclick = null; document.getElementById('addnode-cancelButton').onclick = null; document.getElementById('addnode-popUp').style.display = 'none'; } if(x.opts_manipulation.tab_edit_node){ document.getElementById('editnode-saveButton').onclick = null; document.getElementById('editnode-cancelButton').onclick = null; document.getElementById('editnode-popUp').style.display = 'none'; } if(x.opts_manipulation.tab_edit_edge){ document.getElementById('editedge-saveButton').onclick = null; document.getElementById('editedge-cancelButton').onclick = null; document.getElementById('editedge-popUp').style.display = 'none'; } } function saveNode(data, callback, cmd) { var iname; var prediv; if(cmd === "addNode"){ iname = "addNodeCols"; prediv = 'addnode-'; } else { iname = "editNodeCols"; prediv = 'editnode-'; } var obj = {id : data.id} for (var nodecol = 0; nodecol < x.opts_manipulation[iname].length; nodecol++){ var add_node_val = document.getElementById(prediv + x.opts_manipulation[iname][nodecol]).value; var add_node_type = document.getElementById(prediv + x.opts_manipulation[iname][nodecol]).type; if(add_node_type && add_node_type === "number"){ add_node_val = parseFloat(add_node_val) } if(add_node_val !== "undefined"){ obj[x.opts_manipulation[iname][nodecol]] = add_node_val } } var update_obj = clone(obj); update_obj.x = data.x; update_obj.y = data.y; nodes.update(update_obj); if (window.Shiny){ obj.cmd = cmd; Shiny.onInputChange(el.id + '_graphChange', obj); } clearPopUp(); callback(null); } function saveEdge(data, callback, cmd) { if(cmd === "editEdge"){ callback(data); //must be first called for egde id ! if (window.Shiny){ var obj = {cmd: cmd, id: data.id, from: data.from, to: data.to}; Shiny.onInputChange(el.id + '_graphChange', obj); } } else if(cmd === "addEdge"){ callback(data); //must be first called for egde id ! if (window.Shiny){ var obj = {cmd: cmd, id: data.id, from: data.from, to: data.to}; Shiny.onInputChange(el.id + '_graphChange', obj); } } else if(cmd === "editEdgeCols"){ for (var edgecol = 0; edgecol < x.opts_manipulation.editEdgeCols.length; edgecol++){ var add_edge_val = document.getElementById("editedge-" + x.opts_manipulation.editEdgeCols[edgecol]).value; var add_edge_type = document.getElementById("editedge-" + x.opts_manipulation.editEdgeCols[edgecol]).type; if(add_edge_type && add_edge_type === "number"){ add_edge_val = parseFloat(add_edge_val) } if(add_edge_val !== "undefined"){ data[x.opts_manipulation.editEdgeCols[edgecol]] = add_edge_val } } if (window.Shiny){ var obj = {cmd: "editEdge", id : data.id} for (var edgecol = 0; edgecol < x.opts_manipulation.editEdgeCols.length; edgecol++){ if(data[x.opts_manipulation.editEdgeCols[edgecol]] !== "undefined"){ obj[x.opts_manipulation.editEdgeCols[edgecol]] = data[x.opts_manipulation.editEdgeCols[edgecol]]; } } Shiny.onInputChange(el.id + '_graphChange', obj); } callback(data); clearPopUp(); } } function deleteSubGraph(data, callback) { if (window.Shiny){ var obj = {cmd: "deleteElements", nodes: data.nodes, edges: data.edges} Shiny.onInputChange(el.id + '_graphChange', obj); } callback(data); } function cancelEdit(callback) { clearPopUp(); callback(null); } //************************* // CLUSTERING //************************* if(x.clusteringGroup || x.clusteringColor || x.clusteringHubsize || x.clusteringConnection){ var clusterbutton = document.createElement("input"); clusterbutton.id = "backbtn"+el.id; clusterbutton.setAttribute('type', 'button'); clusterbutton.setAttribute('value', 'Reinitialize clustering'); clusterbutton.setAttribute('style', 'background-color:#FFFFFF;border: none'); el_id.appendChild(clusterbutton); clusterbutton.onclick = function(){ // reset some parameters / data before if (el_id.selectActive === true | el_id.highlightActive === true) { //reset nodes neighbourhoodHighlight([], "click", el_id.highlightAlgorithm, true); if (el_id.selectActive === true){ el_id.selectActive = false; resetList('selectedBy',el.id, 'selectedBy'); } if (el_id.highlightActive === true){ el_id.highlightActive = false; resetList('nodeSelect', el.id, 'selected'); } } //instance.network.setData(data); if(x.clusteringColor){ clusterByColor(); } if(x.clusteringGroup){ clusterByGroup(x.clusteringGroup.groups); } if(x.clusteringHubsize){ clusterByHubsize(); } if(x.clusteringConnection){ clusterByConnection(); } instance.network.fit(); } } if(x.clusteringGroup || x.clusteringColor || x.clusteringOutliers || x.clusteringHubsize || x.clusteringConnection){ // if we click on a node, we want to open it up! instance.network.on("doubleClick", function (params){ if (params.nodes.length === 1) { if (instance.network.isCluster(params.nodes[0]) === true) { is_clicked = false; instance.network.openCluster(params.nodes[0], {releaseFunction : function(clusterPosition, containedNodesPositions) { return containedNodesPositions; }}); // must be better... resetAllEdges(edges, el_id.highlightColor, el_id.byselectionColor, instance.network); resetAllNodes(nodes, true, options, instance.network, true); } else { if(x.clusteringGroup){ var array_group = nodes.get({ fields: ['group'], filter: function (item) { return item.id === params.nodes[0] ; }, returnType :'Array' }); clusterByGroup([array_group[0].group]); } } } }); } //************************* //clustering Connection //************************* if(x.clusteringConnection){ function clusterByConnection() { for (var i = 0; i < x.clusteringConnection.nodes.length; i++) { instance.network.clusterByConnection(x.clusteringConnection.nodes[i]) } } clusterByConnection(); } //************************* //clustering hubsize //************************* if(x.clusteringHubsize){ function clusterByHubsize() { var clusterOptionsByData = { processProperties: function(clusterOptions, childNodes) { var cluster_level = 9999999 for (var i = 0; i < childNodes.length; i++) { //totalMass += childNodes[i].mass; if(childNodes[i].level){ cluster_level = Math.min(cluster_level, childNodes[i].level) } if(i === 0){ //clusterOptions.shape = childNodes[i].shape; clusterOptions.color = childNodes[i].color.background; }else{ //if(childNodes[i].shape !== clusterOptions.shape){ //clusterOptions.shape = 'database'; //} if(childNodes[i].color.background !== clusterOptions.color){ clusterOptions.color = 'grey'; } } } clusterOptions.label = "[" + childNodes.length + "]"; if(cluster_level !== 9999999){ clusterOptions.level = cluster_level } return clusterOptions; }, clusterNodeProperties: {borderWidth:3, shape:'box', font:{size:30}} } if(x.clusteringHubsize.size > 0){ instance.network.clusterByHubsize(x.clusteringHubsize.size, clusterOptionsByData); }else{ instance.network.clusterByHubsize(undefined, clusterOptionsByData); } } clusterByHubsize(); } if(x.clusteringColor){ //************************* //clustering color //************************* function clusterByColor() { var colors = x.clusteringColor.colors var clusterOptionsByData; for (var i = 0; i < colors.length; i++) { var color = colors[i]; var sh = x.clusteringColor.shape[i]; var force = x.clusteringColor.force[i]; clusterOptionsByData = { joinCondition: function (childOptions) { return childOptions.color.background == color; // the color is fully defined in the node. }, processProperties: function (clusterOptions, childNodes, childEdges) { var totalMass = 0; var cluster_level = 9999999; for (var i = 0; i < childNodes.length; i++) { totalMass += childNodes[i].mass; if(childNodes[i].level){ cluster_level = Math.min(cluster_level, childNodes[i].level) } if(force === false){ if(i === 0){ clusterOptions.shape = childNodes[i].shape; }else{ if(childNodes[i].shape !== clusterOptions.shape){ clusterOptions.shape = sh; } } } else { clusterOptions.shape = sh; } } clusterOptions.value = totalMass; if(cluster_level !== 9999999){ clusterOptions.level = cluster_level } return clusterOptions; }, clusterNodeProperties: {id: 'cluster:' + color, borderWidth: 3, color:color, label: x.clusteringColor.label + color} } instance.network.cluster(clusterOptionsByData); } } clusterByColor(); } //************************* //clustering groups //************************* if(x.clusteringGroup){ function clusterByGroup(groups) { var clusterOptionsByData; for (var i = 0; i < groups.length; i++) { var group = groups[i]; var j = x.clusteringGroup.groups.indexOf(group); if(j !== -1) { var col = x.clusteringGroup.color[j]; var sh = x.clusteringGroup.shape[j]; var force = x.clusteringGroup.force[j]; var sc_size = x.clusteringGroup.scale_size[j]; clusterOptionsByData = { joinCondition: function (childOptions) { return childOptions.group == group; // }, processProperties: function (clusterOptions, childNodes, childEdges) { var totalMass = 0; var cluster_level = 9999999; for (var i = 0; i < childNodes.length; i++) { totalMass += childNodes[i].mass; if(childNodes[i].level){ cluster_level = Math.min(cluster_level, childNodes[i].level) } if(force === false){ if(i === 0){ clusterOptions.shape = childNodes[i].shape; clusterOptions.color = childNodes[i].color.background; }else{ if(childNodes[i].shape !== clusterOptions.shape){ clusterOptions.shape = sh; } if(childNodes[i].color.background !== clusterOptions.color){ clusterOptions.color = col; } } } else { clusterOptions.shape = sh; clusterOptions.color = col; } } if(sc_size){ clusterOptions.value = totalMass; } if(cluster_level !== 9999999){ clusterOptions.level = cluster_level } return clusterOptions; }, clusterNodeProperties: {id: 'cluster:' + group, borderWidth: 3, label:x.clusteringGroup.label + group} } instance.network.cluster(clusterOptionsByData); } } } clusterByGroup(x.clusteringGroup.groups); } //************************* //clustering by zoom //************************* if(x.clusteringOutliers){ clusterFactor = x.clusteringOutliers.clusterFactor; // set the first initial zoom level instance.network.on('initRedraw', function() { if (lastClusterZoomLevel === 0) { lastClusterZoomLevel = instance.network.getScale(); } }); // we use the zoom event for our clustering instance.network.on('zoom', function (params) { if(ctrlwait === 0){ if (params.direction == '-') { if (params.scale < lastClusterZoomLevel*clusterFactor) { makeClusters(params.scale); lastClusterZoomLevel = params.scale; } } else { openClusters(params.scale); } } }); } // make the clusters function makeClusters(scale) { ctrlwait = 1; var clusterOptionsByData = { processProperties: function (clusterOptions, childNodes) { clusterIndex = clusterIndex + 1; var childrenCount = 0; var cluster_level = 9999999; for (var i = 0; i < childNodes.length; i++) { childrenCount += childNodes[i].childrenCount || 1; if(childNodes[i].level){ cluster_level = Math.min(cluster_level, childNodes[i].level) } } clusterOptions.childrenCount = childrenCount; clusterOptions.label = "# " + childrenCount + ""; clusterOptions.font = {size: childrenCount*5+30} clusterOptions.id = 'cluster:' + clusterIndex; clusters.push({id:'cluster:' + clusterIndex, scale:scale}); if(cluster_level !== 9999999){ clusterOptions.level = cluster_level } return clusterOptions; }, clusterNodeProperties: {borderWidth: 3, shape: 'database', font: {size: 30}} } instance.network.clusterOutliers(clusterOptionsByData); if (x.clusteringOutliers.stabilize) { instance.network.stabilize(); }; ctrlwait = 0; } // open them back up! function openClusters(scale) { ctrlwait = 1; var newClusters = []; var declustered = false; for (var i = 0; i < clusters.length; i++) { if (clusters[i].scale < scale) { instance.network.openCluster(clusters[i].id); lastClusterZoomLevel = scale; declustered = true; } else { newClusters.push(clusters[i]) } } clusters = newClusters; if (x.clusteringOutliers.stabilize) { instance.network.stabilize(); }; ctrlwait = 0; } //****************** // init selection //****************** if(el_id.idselection && x.nodes && x.idselection.selected !== undefined){ onIdChange(''+ x.idselection.selected, true); } if(el_id.byselection && x.nodes && x.byselection.selected !== undefined){ onByChange(x.byselection.selected); selectNode = document.getElementById('selectedBy'+el.id); selectNode.value = x.byselection.selected; } // try to fix icons loading css bug... function iconsRedraw() { setTimeout(function(){ if(instance.network) instance.network.redraw(); if(instance.legend) instance.legend.redraw(); }, 250); }; if(x.iconsRedraw !== undefined){ if(x.iconsRedraw){ iconsRedraw(); instance.network.once("stabilized", function(){iconsRedraw();}) } } }, resize: function(el, width, height, instance) { if(instance.network) instance.network.fit(); if(instance.legend) instance.legend.fit(); } });