Commit eceb74e3 authored by Romain Loth's avatar Romain Loth

settings refacto + urlparams 2/2

renamed (topPapers to relatedDocs, divFlags to moduleFlags...), fixed several config effects that were disconnected (sizeMult, tagcloud sizes, colorsByAtt), generalized the TW.conf prefix
parent d76ab522
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
/* --------------------- crowdsourcingTerms --------------------- */ /* --------------------- crowdsourcingTerms --------------------- */
/* ---------------------------------------------------------------- */ /* ---------------------------------------------------------------- */
// update message in the search bar
TW.conf.strSearchBar = "Select or suggest topics";
$("#searchinput").attr('placeholder', TW.conf.strSearchBar) ;
/* 3 possible events affect crowdsourcing */ /* 3 possible events affect crowdsourcing */
......
This is a stub for a future documentation for developers. This is a stub for a future documentation for developers.
## Graph input choices
Tina allows 3 main ways of input :
- a local file from the client machine
activated by `sourcemode=localfile` or by opening the entry point explorerjs.html via file protocol (<=> locally)
- a static file from the remote server
`sourcemode=serverfile`
- a dataset from a remote server API
`sourcemode=api`
The `sourcemode` value is by default the one in settings_explorerjs.js (`TW.conf.sourcemode`), unless an url argument of the same name is present.
The `serverfile` option has an extended version called `servermenu`. It opens a list of files called `db.json` on the server, providing a menu to choose from it.
The detailed implementation of these choices can be found in the function `syncRemoteGraphData()` in main.js.
## Graph initialization ## Graph initialization
This will still evolve but the main steps for any graph initialization messily use functions across several modules, so it can be useful to list them here together: This will still evolve but the main steps for any graph initialization messily use functions across several modules, so it can be useful to list them here together:
...@@ -29,7 +45,7 @@ This will still evolve but the main steps for any graph initialization messily u ...@@ -29,7 +45,7 @@ This will still evolve but the main steps for any graph initialization messily u
- any attribute listed in the sourcenode.attributes will be indexed if the TW.scanClusters flag is true - any attribute listed in the sourcenode.attributes will be indexed if the TW.scanClusters flag is true
- the mapping from attribute values to matching nodes is in TW.Clusters.aType.anAttr.aValue.map - the mapping from attribute values to matching nodes is in TW.Clusters.aType.anAttr.aValue.map
- coloration: "`age`" "`growth_rate`" + any attribute of type float or int - coloration: "`age`" "`growth_rate`" + any attribute of type float or int
- clustering: "`cluster_index`" ou nom figurant dans `TW.nodeClusAtt` - clustering: "`cluster_index`" ou nom figurant dans `TW.conf.nodeClusAtt`
- vocabulary: (en cours) any attribute of type string and where the amount of distinct values is < TW.somesettings - vocabulary: (en cours) any attribute of type string and where the amount of distinct values is < TW.somesettings
......
...@@ -77,14 +77,14 @@ ...@@ -77,14 +77,14 @@
</li> </li>
<li style="margin-left:10px;"> <li style="margin-left:10px;">
<a href="#" class="navbar-middle navbar-brand"> <a href="#" class="navbar-middle navbar-brand">
<!-- will be replaced by TW.branding --> <!-- will be replaced by TW.conf.branding -->
<span id="twbrand">TinaWebJS</span> <span id="twbrand">TinaWebJS</span>
</a> </a>
</li> </li>
<li class="disabled"> <li class="disabled">
<a class="navbar-middle"> <a class="navbar-middle">
<span class="label label-default label-lg">MAP: </span> <span class="label label-default label-lg">MAP: <span id="maplabel"></span></span>
</a> </a>
</li> </li>
...@@ -188,7 +188,7 @@ ...@@ -188,7 +188,7 @@
<div id="sliderlabelsize" class="settingslider"></div> <div id="sliderlabelsize" class="settingslider"></div>
</a></li> </a></li>
<li class="dropdown"> <li id="setcolorsMenu" class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false"> <a class="dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true" aria-expanded="false">
Set Colors <img title="Set Colors" src="libs/img2/colors.png" width="20px"><span class="caret"></span> Set Colors <img title="Set Colors" src="libs/img2/colors.png" width="20px"><span class="caret"></span>
</a> </a>
......
...@@ -14,8 +14,8 @@ function newPopup(url) { ...@@ -14,8 +14,8 @@ function newPopup(url) {
// to add the button in the html with the sigmaUtils.clustersBy(x) listener. // to add the button in the html with the sigmaUtils.clustersBy(x) listener.
function changeGraphAppearanceByFacets( manualflag ) { function changeGraphAppearanceByFacets( manualflag ) {
if ( !isUndef(manualflag) && !TW.colorByAtt ) TW.colorByAtt = manualflag; if ( !isUndef(manualflag) && !TW.conf.colorByAtt ) TW.conf.colorByAtt = manualflag;
if(!TW.colorByAtt) return; if(!TW.conf.colorByAtt) return;
// for GUI html: if present, rename raw attribute key by a proper label // for GUI html: if present, rename raw attribute key by a proper label
var AttsTranslations = { var AttsTranslations = {
...@@ -93,13 +93,13 @@ function changeGraphAppearanceByFacets( manualflag ) { ...@@ -93,13 +93,13 @@ function changeGraphAppearanceByFacets( manualflag ) {
} }
// creates TW.legendsBins bins // creates TW.conf.legendsBins bins
// @sortedValues array, mandatory // @sortedValues array, mandatory
function intervalsInventory(sortedValues) { function intervalsInventory(sortedValues) {
var binmins = [] var binmins = []
var len = sortedValues.length var len = sortedValues.length
for (var l=0 ; l < TW.legendsBins ; l++) { for (var l=0 ; l < TW.conf.legendsBins ; l++) {
let nthVal = Math.floor(len * l / TW.legendsBins) let nthVal = Math.floor(len * l / TW.conf.legendsBins)
binmins.push(sortedValues[nthVal]) binmins.push(sortedValues[nthVal])
} }
// console.info("legendRefTicks", binmins) // console.info("legendRefTicks", binmins)
...@@ -328,7 +328,7 @@ function set_ClustersLegend ( daclass, groupedByTicks ) { ...@@ -328,7 +328,7 @@ function set_ClustersLegend ( daclass, groupedByTicks ) {
//For CNRS //For CNRS
// function getTopPapers(type){ // function getTopPapers(type){
// if(TW.getAdditionalInfo){ // if(TW.conf.getRelatedDocs){
// console.log("getTopPapers") // console.log("getTopPapers")
// jsonparams=JSON.stringify(getSelections()); // jsonparams=JSON.stringify(getSelections());
// bi=(Object.keys(categories).length==2)?1:0; // bi=(Object.keys(categories).length==2)?1:0;
...@@ -336,18 +336,18 @@ function set_ClustersLegend ( daclass, groupedByTicks ) { ...@@ -336,18 +336,18 @@ function set_ClustersLegend ( daclass, groupedByTicks ) {
// jsonparams = jsonparams.split('&').join('__and__'); // jsonparams = jsonparams.split('&').join('__and__');
// //dbsPaths.push(getGlobalDBs()); // //dbsPaths.push(getGlobalDBs());
// thisgexf=JSON.stringify(decodeURIComponent(getUrlParam.file)); // thisgexf=JSON.stringify(decodeURIComponent(getUrlParam.file));
// image='<img style="display:block; margin: 0px auto;" src="'+TW.companionAPI+'img/ajax-loader.gif"></img>'; // image='<img style="display:block; margin: 0px auto;" src="'+TW.conf.relatedDocsAPI+'img/ajax-loader.gif"></img>';
// $("#tab-container-top").show(); // $("#tab-container-top").show();
// $("#topPapers").show(); // $("#topPapers").show();
// $("#topPapers").html(image); // $("#topPapers").html(image);
// $.ajax({ // $.ajax({
// type: 'GET', // type: 'GET',
// url: TW.companionAPI+'info_div.php', // url: TW.conf.relatedDocsAPI+'info_div.php',
// data: "type="+type+"&bi="+bi+"&query="+jsonparams+"&gexf="+thisgexf+"&index="+TW.field[getUrlParam.file], // data: "type="+nodetype+"&bi="+bi+"&query="+jsonparams+"&gexf="+thisgexf+"&index="+TW.field[getUrlParam.file],
// //contentType: "application/json", // //contentType: "application/json",
// //dataType: 'json', // //dataType: 'json',
// success : function(data){ // success : function(data){
// console.log(TW.companionAPI+'info_div.php?'+"type="+type+"&bi="+bi+"&query="+jsonparams+"&gexf="+thisgexf+"&index="+TW.field[getUrlParam.file]); // console.log(TW.conf.relatedDocsAPI+'info_div.php?'+"type="+nodetype+"&bi="+bi+"&query="+jsonparams+"&gexf="+thisgexf+"&index="+TW.field[getUrlParam.file]);
// $("#topPapers").html(data); // $("#topPapers").html(data);
// }, // },
// error: function(){ // error: function(){
...@@ -359,8 +359,11 @@ function set_ClustersLegend ( daclass, groupedByTicks ) { ...@@ -359,8 +359,11 @@ function set_ClustersLegend ( daclass, groupedByTicks ) {
// a custom variant of twitter plugin written for politoscope // a custom variant of twitter plugin written for politoscope
function getTopPapers(type){ // NB: this variant only for nodetype semantic
if(TW.getAdditionalInfo){ function getTopPapers(nodetypeLegacy){
if (nodetypeLegacy == 'semantic' && TW.conf.getRelatedDocs) {
jsonparams=getSelections(); jsonparams=getSelections();
var joined_q = jsonparams.map(function(w) {return '('+w+')'}).join(' AND ') var joined_q = jsonparams.map(function(w) {return '('+w+')'}).join(' AND ')
...@@ -370,7 +373,7 @@ function getTopPapers(type){ ...@@ -370,7 +373,7 @@ function getTopPapers(type){
// //
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
url: TW.companionAPI, url: TW.conf.relatedDocsAPI,
data: {'query': joined_q}, data: {'query': joined_q},
contentType: "application/json", contentType: "application/json",
success : function(data){ success : function(data){
...@@ -385,7 +388,7 @@ function getTopPapers(type){ ...@@ -385,7 +388,7 @@ function getTopPapers(type){
} }
} }
else { else {
topTweetsHtml = `<p class="micromessage centered">The query <span class=code>${joined_q}</span> delivers no results on Twitter with the topic #Presidentielles2017 and most related hashtags</p>` topTweetsHtml = `<p class="micromessage centered">The query <span class=code>${joined_q}</span> delivers no results on Twitter.</p>`
} }
$("#topPapers").html(topTweetsHtml); $("#topPapers").html(topTweetsHtml);
...@@ -399,9 +402,7 @@ function getTopPapers(type){ ...@@ -399,9 +402,7 @@ function getTopPapers(type){
} }
function clickInsideTweet(e, tweetSrcUrl) { function clickInsideTweet(e, tweetSrcUrl) {
console.log('>>>>> event target tag', e.target.tag) console.debug('inside tweet tagName', e.target.tagName)
console.log("event")
console.log(e)
var tgt = e.target var tgt = e.target
if (tgt.tagName.toLowerCase() == "a") if (tgt.tagName.toLowerCase() == "a")
window.open(tgt.href, "Link in tweet") window.open(tgt.href, "Link in tweet")
...@@ -506,7 +507,7 @@ function RenderTweet( tweet) { ...@@ -506,7 +507,7 @@ function RenderTweet( tweet) {
//FOR UNI-PARTITE //FOR UNI-PARTITE
// function selectionUni(currentNode){ // function selectionUni(currentNode){
// console.log("\tin selectionUni:"+currentNode.id); // console.log("\tin selectionUni:"+currentNode.id);
// if(checkBox==false && TW.circleSize==0) { // if(TW.checkBox==false && TW.circleSize==0) {
// highlightSelectedNodes(false); // highlightSelectedNodes(false);
// opossites = []; // opossites = [];
// selections = []; // selections = [];
...@@ -793,23 +794,26 @@ function flashNodesArray (nodesArray) { ...@@ -793,23 +794,26 @@ function flashNodesArray (nodesArray) {
// BASIC MODULARITY // BASIC MODULARITY
// ================= // =================
// ProcessDivsFlags is for adding/removing features from TinawebJS // activateModules is for adding/removing features from TinawebJS
// each flag is simultaneously 3 things: // each flag is simultaneously 3 things:
// - the key of a bool config value in DivsFlags (settings_explorerjs) // - the key of a bool config value in TW.conf.ModulesFlags (settings_explorerjs)
// - the dirname of the submodule's files (with a mandatory init.js) // - the dirname of the submodule's files (with a mandatory init.js)
// - the css class of all html elements added by the submodule // - the css class of all html elements added by the submodule
function ProcessDivsFlags() { function activateModules() {
for(var key in TW.conf.DivsFlags) { for(var key in TW.conf.ModulesFlags) {
if(TW.conf.DivsFlags[key]===false) {
if(TW.conf.ModulesFlags[key]===false) {
$("."+key).remove() ; // hide elements of module's class $("."+key).remove() ; // hide elements of module's class
} }
else { else {
// console.log("extras:ProcessDivsFlags: key is true: "+key) // console.log("extras:activateModules: key is true: "+key)
// load JS+CSS items corresponding to the flagname // load JS+CSS items corresponding to the flagname
my_src_dir = key let my_src_dir = key
// synchronous ajax
let moduleIsPresent = linkCheck(my_src_dir+"/init.js")
// TODO check if async not a problem if (moduleIsPresent) {
if (linkCheck(my_src_dir+"/init.js")) {
loadJS(my_src_dir+"/init.js") ; loadJS(my_src_dir+"/init.js") ;
} }
else { else {
......
...@@ -6,29 +6,50 @@ TW.conf = (function(TW){ ...@@ -6,29 +6,50 @@ TW.conf = (function(TW){
let TWConf = {} let TWConf = {}
TWConf.branding = 'test bipart' // <----- the name displayed in upper left TWConf.branding = 'ProjectExplorer' // <--- the name displayed in upper left
// ========================== // ==========================
// TINA POSSIBLE DATA SOURCES // TINA POSSIBLE DATA SOURCES
// ========================== // ==========================
// Graph data source
// -----------------
// the graph input depends on TWConf.sourcemode (or manual url arg 'sourcemode') // the graph input depends on TWConf.sourcemode (or manual url arg 'sourcemode')
TWConf.sourcemode = "api" // accepted: "api" | "serverfile" | "servermenu" | "localfile" TWConf.sourcemode = "api" // accepted: "api" | "serverfile" | "servermenu" | "localfile"
// server-side gexf default source // server-side .gexf|.json default source
TWConf.sourceFile = "data/politoscope/ProgrammeDesCandidats.enrichi.gexf" TWConf.sourceFile = "data/politoscope/ProgrammeDesCandidats.enrichi.gexf"
// or remote bridge to default source api ajax queries // ...or server-side gexf default source list
TWConf.sourceMenu = "db.json"
// ...or remote bridge to default source api ajax queries
TWConf.sourceAPI={}; TWConf.sourceAPI={};
TWConf.sourceAPI["forNormalQuery"] = "services/api/graph"; TWConf.sourceAPI["forNormalQuery"] = "services/api/graph";
TWConf.sourceAPI["forFilteredQuery"] = "services/api/graph"; TWConf.sourceAPI["forFilteredQuery"] = "services/api/graph";
// Related documents (topPapers) data source
// -----------------------------------------
TWConf.getRelatedDocs = true
TWConf.relatedDocsAPI = "http://127.0.0.1:5000/twitter_search"
// £TODO : allow to choose between twitter or elasticsearch topPapers (choic of post-process function in extras_explorer)
// TWConf.relatedDocsType
// =========== // ===========
// DATA FACETS // DATA FACETS
// =========== // ===========
// create facets ?
TWConf.scanClusters = true
// to handle node attributes from data // to handle node attributes from data
// => clusters (discrete numeric or str vars), // => clusters (discrete numeric or str vars),
// => colors (continuous numeric vars) // => colors (continuous numeric vars)
...@@ -36,73 +57,120 @@ TW.conf = (function(TW){ ...@@ -36,73 +57,120 @@ TW.conf = (function(TW){
// for continuous attrvalues/colors (cf. clustersBy), how many levels in legend? // for continuous attrvalues/colors (cf. clustersBy), how many levels in legend?
TWConf.legendsBins = 7 ; TWConf.legendsBins = 7 ;
// max discrete levels in facet legend (if attribute has more distinct values then binning)
TWConf.maxDiscreteValues = 40
// £TODO transform for new specifications
// some specific attributes may have other number of levels // some specific attributes may have other number of levels
TWConf.customLegendsBins = { TWConf.customLegendsBins = {
'age': 8, 'age': 8,
'growth_rate': 12 'growth_rate': 12
} }
// default clustering (used to show as initial color)
TWConf.nodeClusAtt = "modularity_class"
// ===================
// TINA ACTIVE MODULES
// ===================
TWConf.DivsFlags = {} ;
// flag name is div class to be removed if false
// *and* subdirectory to import if true
// see also ProcessDivsFlags()
TWConf.DivsFlags["histogramModule"] = false ;
TWConf.DivsFlags["histogramDailyVariantModule"] = false ;
// TODO more generic module integrating the variants cf. experiments/histogramModule_STUB_GENERIQUE
TWConf.DivsFlags["crowdsourcingModule"] = false ;
TWConf.libspath = 'libs' // FIXME path vars should not be used after page load !
// ============= // =============
// TINA BEHAVIOR // TINA BEHAVIOR
// ============= // =============
// Node typology // Node typology (searched in nodes data, overridden if data has other types)
// (FIXME cf. comment in sortNodeTypes and swActual functions
// about the limits of how these 2 values and
// TW.categories are used in older functions)
TWConf.catSoc = "Document"; TWConf.catSoc = "Document";
TWConf.catSem = "NGram"; TWConf.catSem = "NGram";
// Events handling // Active modules
TWConf.deselectOnclickStage = true // will a click on the background remove selection ? (except when dragging) // --------------
TWConf.ModulesFlags = {} ;
// flag name is div class to be removed if false
// *and* subdirectory to import if true
// see also activateModules()
TWConf.ModulesFlags["histogramModule"] = false ;
TWConf.ModulesFlags["histogramDailyVariantModule"] = false ;
// TODO more generic module integrating the variants cf. experiments/histogramModule_STUB_GENERIQUE
TWConf.ModulesFlags["crowdsourcingModule"] = true ;
// debug flags & log levels // Other optional functionalities
TWConf.debug = { // -----------------------------
initialShowAll: false, // show all nodes on bipartite case init (docs + terms in one view) TWConf.filterSliders = true // show sliders for nodes/edges subsets
// show verbose console logs... TWConf.colorsByAtt = false; // show "Set colors" menu
logFetchers: false, // ...about ajax/fetching of graph data
logParsers: false, // ...about parsing said data TWConf.deselectOnclickStage = true // click on background remove selection ?
logFacets: false, // ...about parsing node attribute:value facets // (except when dragging)
logSettings: false, // ...about settings at Tina and Sigma init time
logSelections: false TWConf.histogramStartThreshold = 10 ; // for daily histo module
} // (from how many docs are significant)
// Layouts // £TODO these exist only in git branches
// ------- // (geomap: ademe, timeline: tweetoscope)
// ==> ask if need to be restored
// TW.geomap = false;
// TW.twittertimeline = false;
// Layout options
// --------------
TWConf.fa2Available=true; // show/hide fa2Button TWConf.fa2Available=true; // show/hide fa2Button
TWConf.disperseAvailable=true; // show/hide disperseButton TWConf.disperseAvailable=true; // show/hide disperseButton
// if fa2Available, the auto-run config: // if fa2Available, the auto-run config:
TWConf.fa2Enabled= true; // fa2 auto-run at start and after graph modified ? TWConf.fa2Enabled= false; // fa2 auto-run at start and after graph modified ?
TWConf.fa2Milliseconds=5000; // duration of auto-run TWConf.fa2Milliseconds=5000; // duration of auto-run
TWConf.minNodesForAutoFA2 = 5 // graph size threshold to auto-run TWConf.minNodesForAutoFA2 = 5 // graph size threshold to auto-run
// Full-text search // Full-text search
// ---------------- // ----------------
TWConf.minLengthAutoComplete = 1; TWConf.maxSearchResults = 10; // how many "top papers" to display
TWConf.maxSearchResults = 10; TWConf.minLengthAutoComplete = 1; // how many chars to type for autocomp
TWConf.strSearchBar = "Select topics";
// =======================
// TINA RENDERING SETTINGS
// =======================
TWConf.overSampling = true // costly hi-def rendering (true => pixelRatio x 2)
// relative sizes (iff graph display with both nodetypes)
TWConf.sizeMult = [];
TWConf.sizeMult[0] = 1.5; // ie for node type 0
TWConf.sizeMult[1] = 1.0; // ie for node type 1
// circle selection cursor
TWConf.circleSizeMin = 0;
TWConf.circleSizeMax = 100;
// SIGMA BEHAVIOR SETTINGS // size range for neighbor nodes "tagcloud"
TWConf.tagcloudFontsizeMin = 12;
TWConf.tagcloudFontsizeMax = 24;
TWConf.tagcloudSameLimit = 50 // display at most how many neighbors of the same type
TWConf.tagcloudOpposLimit = 10 // display at most how many neighbors of the opposite type
TWConf.defaultNodeColor = "rgb(40,40,40)"
// selected/deselected rendering
TWConf.nodesGreyBorderColor = "rgba(100, 100, 100, 0.5)"; // not selected nodes
TWConf.selectedColor = "default" // "node" for a background like the node's color,
// "default" for note-like yellow
TWConf.edgeDefaultOpacity = 0.4 // opacity when true_color
TWConf.edgeGreyColor = "rgba(150, 150, 150, 0.5)"; // not selected edges
// ========================
// SIGMA RENDERING SETTINGS // SIGMA RENDERING SETTINGS
// ========================
// triggers overriding sigma.canvas renderers: nodes.def, labels.def, edges.def // triggers overriding sigma.canvas renderers: nodes.def, labels.def, edges.def
TWConf.ourRendering = true ; TWConf.ourRendering = true ;
...@@ -147,46 +215,34 @@ TW.conf = (function(TW){ ...@@ -147,46 +215,34 @@ TW.conf = (function(TW){
}; };
// ======================= // ===========
// TINA RENDERING SETTINGS // DEBUG FLAGS
// ======================= // ===========
TWConf.overSampling = false // costly hi-def rendering (true => pixelRatio x 2) TWConf.debug = {
initialShowAll: false, // show all nodes on bipartite case init (docs + terms in one view)
TWConf.sizeMult = [];
TWConf.sizeMult[0] = 1.0; // ie for node type 0
TWConf.sizeMult[1] = 1.0; // ie for node type 1
TWConf.circleSizeMin= 0;
TWConf.circleSizeMax= 100;
// ========
// A RANGER £TODO
// ========
TWConf.nodeClusAtt = "modularity_class"
TWConf.filterSliders = true // show verbose console logs...
logFetchers: false, // ...about ajax/fetching of graph data
logParsers: false, // ...about parsing said data
logFacets: true, // ...about parsing node attribute:value facets
logSettings: false, // ...about settings at Tina and Sigma init time
logSelections: true
}
TWConf.histogramStartThreshold = 10 ;
TWConf.defaultNodeColor = "rgb(40,40,40)" // £TODO: fix these 2 settings with a better dir structure
TWConf.edgeDefaultOpacity = 0.4 // opacity when true_color // + but avoid path injection
TWConf.edgeGreyColor = "rgba(150, 150, 150, 0.5)"; // + find a place for modules *INSIDE* tinawebJS dir for easier deployment
TWConf.nodesGreyBorderColor = "rgba(100, 100, 100, 0.5)"; TWConf.ModulesPath = ''
TWConf.selectedColor = "default" // "node" for a background like the node's color, TWConf.libspath = 'libs'
// "default" for note-like yellow
console.warn("current conf:", TWConf)
return TWConf return TWConf
})() })()
// INITIALIZED VARS (£TODO move to main or Tina) // INITIALIZED VARS
// ================ // ================
TW.Nodes = []; TW.Nodes = [];
TW.Edges = []; TW.Edges = [];
...@@ -214,9 +270,6 @@ var bipartiteN2D = {}; ...@@ -214,9 +270,6 @@ var bipartiteN2D = {};
TW.categories = []; TW.categories = [];
TW.catDict = {}; TW.catDict = {};
TW.nodeslength = 0 // <=== £TODO harmonize use with TW.partialGraph.graph.nNodes()
var gexfFile; var gexfFile;
//var zoom=0; //var zoom=0;
TW.checkBox=false; TW.checkBox=false;
...@@ -248,8 +301,6 @@ var lastFilter = [] ...@@ -248,8 +301,6 @@ var lastFilter = []
lastFilter["#slidercat0edgesweight"] = {"orig":"-" , "last":"-"} lastFilter["#slidercat0edgesweight"] = {"orig":"-" , "last":"-"}
lastFilter["#slidercat1edgesweight"] = {"orig":"-" , "last":"-"} lastFilter["#slidercat1edgesweight"] = {"orig":"-" , "last":"-"}
var desirableTagCloudFont_MIN=12;
var desirableTagCloudFont_MAX=20;
var desirableNodeSizeMIN=1; var desirableNodeSizeMIN=1;
var desirableNodeSizeMAX=12; var desirableNodeSizeMAX=12;
......
...@@ -147,7 +147,7 @@ function SelectionEngine() { ...@@ -147,7 +147,7 @@ function SelectionEngine() {
// ==================== // ====================
this.MultipleSelection2 = (function(nodes,nodesDict,edgesDict) { this.MultipleSelection2 = (function(nodes,nodesDict,edgesDict) {
if (TW.conf.debug.selections) { if (TW.conf.debug.logSelections) {
var tMS2_deb = performance.now() var tMS2_deb = performance.now()
console.log("IN SelectionEngine.MultipleSelection2:") console.log("IN SelectionEngine.MultipleSelection2:")
...@@ -214,7 +214,12 @@ function SelectionEngine() { ...@@ -214,7 +214,12 @@ function SelectionEngine() {
if (typeof sameSideNeighbors[t] == 'undefined') { if (typeof sameSideNeighbors[t] == 'undefined') {
sameSideNeighbors[t]=0 sameSideNeighbors[t]=0
} }
sameSideNeighbors[t]++
if (TW.Edges[s+";"+t])
sameSideNeighbors[t] += TW.Edges[s+";"+t].weight || 1
if (TW.Edges[t+";"+s])
sameSideNeighbors[t] += TW.Edges[t+";"+s].weight || 1
} }
} }
} }
...@@ -290,6 +295,8 @@ function SelectionEngine() { ...@@ -290,6 +295,8 @@ function SelectionEngine() {
for(var n in bipaNeighs) { for(var n in bipaNeighs) {
if (typeof oppositeSideNeighbors[bipaNeighs[n]] == "undefined") if (typeof oppositeSideNeighbors[bipaNeighs[n]] == "undefined")
oppositeSideNeighbors[bipaNeighs[n]] = 0; oppositeSideNeighbors[bipaNeighs[n]] = 0;
// £TODO weighted increment
oppositeSideNeighbors[bipaNeighs[n]]++; oppositeSideNeighbors[bipaNeighs[n]]++;
} }
} }
...@@ -312,7 +319,7 @@ function SelectionEngine() { ...@@ -312,7 +319,7 @@ function SelectionEngine() {
return b-a return b-a
}); });
if (TW.conf.debug.selections) { if (TW.conf.debug.logSelections) {
console.debug('selections', selections) console.debug('selections', selections)
console.debug('oppos', oppos) console.debug('oppos', oppos)
console.debug('same', same) console.debug('same', same)
...@@ -325,11 +332,13 @@ function SelectionEngine() { ...@@ -325,11 +332,13 @@ function SelectionEngine() {
updateRelatedNodesPanel( selections , same, oppos ); updateRelatedNodesPanel( selections , same, oppos );
if (TW.conf.debug.selections) { if (TW.conf.debug.logSelections) {
var tMS2_fin = performance.now() var tMS2_fin = performance.now()
console.log("end MultipleSelection2, own time:", tMS2_fin-tMS2_deb) console.log("end MultipleSelection2, own time:", tMS2_fin-tMS2_deb)
} }
}).index() }).index()
}; };
...@@ -737,6 +746,10 @@ TinaWebJS = function ( sigmacanvas ) { ...@@ -737,6 +746,10 @@ TinaWebJS = function ( sigmacanvas ) {
TW.partialGraph.camera.goTo({x:0, y:0, ratio:1.2}) TW.partialGraph.camera.goTo({x:0, y:0, ratio:1.2})
}); });
if (!TW.conf.colorsByAtt) {
$("#setcolorsMenu").hide()
}
if (TW.conf.fa2Available) { if (TW.conf.fa2Available) {
$("#layoutButton").click(function () { $("#layoutButton").click(function () {
sigma_utils.smartForceAtlas() sigma_utils.smartForceAtlas()
......
...@@ -7,6 +7,9 @@ function writeBrand (brandString) { ...@@ -7,6 +7,9 @@ function writeBrand (brandString) {
document.getElementById('twbrand').innerHTML = brandString document.getElementById('twbrand').innerHTML = brandString
} }
function writeLabel (aMapLabel) {
document.getElementById('maplabel').innerHTML = aMapLabel
}
function createFilechooserEl () { function createFilechooserEl () {
...@@ -45,6 +48,7 @@ function createFilechooserEl () { ...@@ -45,6 +48,7 @@ function createFilechooserEl () {
rdr.onload = function() { rdr.onload = function() {
if (! rdr.result || !rdr.result.length) { if (! rdr.result || !rdr.result.length) {
alert('the selected file is not readable') alert('the selected file is not readable')
writeLabel(`Local file: unreadable!`)
} }
else { else {
// we might have a previous graph opened // we might have a previous graph opened
...@@ -59,6 +63,8 @@ function createFilechooserEl () { ...@@ -59,6 +63,8 @@ function createFilechooserEl () {
mainStartGraph(theFormat, JSON.parse(rdr.result), TW.instance) mainStartGraph(theFormat, JSON.parse(rdr.result), TW.instance)
else else
mainStartGraph(theFormat, rdr.result, TW.instance) mainStartGraph(theFormat, rdr.result, TW.instance)
writeLabel(`Local file: ${clientLocalGraphFile.name}`)
} }
} }
rdr.readAsText(clientLocalGraphFile) rdr.readAsText(clientLocalGraphFile)
...@@ -787,6 +793,10 @@ function EdgeWeightFilter(sliderDivID , typestr , criteria) { ...@@ -787,6 +793,10 @@ function EdgeWeightFilter(sliderDivID , typestr , criteria) {
// NodeWeightFilter ( "#sliderBNodeWeight" , "NGram" , "size") // NodeWeightFilter ( "#sliderBNodeWeight" , "NGram" , "size")
function NodeWeightFilter( sliderDivID , tgtNodeType , criteria) { function NodeWeightFilter( sliderDivID , tgtNodeType , criteria) {
if (typeof tgtNodeType == "undefined") {
throw 'no nodetype'
}
if(TW.partialGraph.graph.nNodes() < 2) { if(TW.partialGraph.graph.nNodes() < 2) {
console.warn('not enough nodes for subsets: skipping GUI slider init') console.warn('not enough nodes for subsets: skipping GUI slider init')
showDisabledSlider(sliderDivID) showDisabledSlider(sliderDivID)
...@@ -903,8 +913,6 @@ function showDisabledSlider(someDivId) { ...@@ -903,8 +913,6 @@ function showDisabledSlider(someDivId) {
//=========================== </ FILTERS-SLIDERS > ===========================// //=========================== </ FILTERS-SLIDERS > ===========================//
//============================= < SEARCH > =============================// //============================= < SEARCH > =============================//
function updateSearchLabels(id,name,type){ function updateSearchLabels(id,name,type){
TW.labels.push({ TW.labels.push({
...@@ -959,3 +967,19 @@ function searchLabel(string){ ...@@ -959,3 +967,19 @@ function searchLabel(string){
} }
} }
//============================ < / SEARCH > ============================// //============================ < / SEARCH > ============================//
//============================= < OTHER ACTIONS > =============================//
function jsActionOnGexfSelector(gexfBasename){
let gexfPath = TW.gexfPaths[gexfBasename] || gexfBasename+".gexf"
let serverPrefix = ''
var pathcomponents = window.location.pathname.split('/')
for (var i in pathcomponents) {
if (pathcomponents[i] != 'explorerjs.html')
serverPrefix += '/'+pathcomponents[i]
}
var newDataRes = AjaxSync({ URL: window.location.origin+serverPrefix+'/'+gexfPath });
mainStartGraph(newDataRes["format"], newDataRes["data"], TW.instance)
writeLabel(gexfBasename)
}
//============================= </OTHER ACTIONS > =============================//
...@@ -143,38 +143,16 @@ getUrlParam = (function () { ...@@ -143,38 +143,16 @@ getUrlParam = (function () {
function ArraySortByValue(array, sortFunc){ function ArraySortByValue(array, sortFunc){
var tmp = []; var tmp = [];
// oposMAX=0;
for (var k in array) { for (var k in array) {
if (array.hasOwnProperty(k)) { tmp.push({
tmp.push({ key: k,
key: k, value: array[k]
value: array[k] });
});
// if((array[k]) > oposMAX) oposMAX= array[k];
}
}
tmp.sort(function(o1, o2) {
return sortFunc(o1.value, o2.value);
});
return tmp;
}
function ArraySortByKey(array, sortFunc){
var tmp = [];
for (var k in array) {
if (array.hasOwnProperty(k)) {
tmp.push({
key: k,
value: array[k]
});
}
} }
// reverse numeric on prop 'value'
tmp.sort(function(o1, o2) { tmp.sort(function(o1, o2) {
return sortFunc(o1.key, o2.key); return (parseFloat(o2.value) - parseFloat(o1.value));
}); });
return tmp; return tmp;
} }
......
...@@ -74,19 +74,10 @@ var AjaxSync = (function(TYPE, URL, DATA, DT) { ...@@ -74,19 +74,10 @@ var AjaxSync = (function(TYPE, URL, DATA, DT) {
return Result; return Result;
}).index(); }).index();
function jsActionOnGexfSelector(gexfBasename){
let gexfPath = TW.gexfPaths[gexfBasename] || gexfBasename+".gexf"
let serverPrefix = ''
var pathcomponents = window.location.pathname.split('/')
for (var i in pathcomponents) {
if (pathcomponents[i] != 'explorerjs.html')
serverPrefix += '/'+pathcomponents[i]
}
var newDataRes = AjaxSync({ URL: window.location.origin+serverPrefix+'/'+gexfPath });
mainStartGraph(newDataRes["format"], newDataRes["data"], TW.instance)
}
// === [ what to do at start ] === // // === [ what to do at start ] === //
console.log("Starting TWJS")
// NB this method-holding instance could be initialized just once or even removed? // NB this method-holding instance could be initialized just once or even removed?
var sigma_utils = new SigmaUtils(); var sigma_utils = new SigmaUtils();
...@@ -103,12 +94,12 @@ TW.instance.initSearchListeners(); ...@@ -103,12 +94,12 @@ TW.instance.initSearchListeners();
// show the custom name of the app // show the custom name of the app
writeBrand(TW.conf.branding) writeBrand(TW.conf.branding)
console.log("Starting TWJS")
// choosing the input // choosing the input
// ------------------- // -------------------
// if page is being run locally ==> only possible source shall be via file input // if page is being run locally ==> only possible source shall be via file input
if (window.location.protocol == 'file:') { if (window.location.protocol == 'file:'
|| (!isUndef(getUrlParam.sourcemode) && getUrlParam.sourcemode == 'localfile')) {
let inputDiv = document.getElementById('localInput') let inputDiv = document.getElementById('localInput')
inputDiv.style.display = 'block' inputDiv.style.display = 'block'
...@@ -120,15 +111,15 @@ if (window.location.protocol == 'file:') { ...@@ -120,15 +111,15 @@ if (window.location.protocol == 'file:') {
inputDiv.appendChild(remark) inputDiv.appendChild(remark)
// user can open a gexf or json from his fs // user can open a gexf or json from his fs
// POSS we could actually provide this local file chooser in all cases
var graphFileInput = createFilechooserEl() var graphFileInput = createFilechooserEl()
inputDiv.appendChild(graphFileInput) inputDiv.appendChild(graphFileInput)
} }
// traditional cases: remote read from API or prepared server-side file // traditional cases: remote read from API or prepared server-side file
else { else {
// NB it will use global urlParams and TW.settings to choose the source // NB it will use global urlParams and TW.settings to choose the source
var [inFormat, inData] = syncRemoteGraphData() var [inFormat, inData, mapLabel] = syncRemoteGraphData()
mainStartGraph(inFormat, inData, TW.instance) mainStartGraph(inFormat, inData, TW.instance)
writeLabel(mapLabel)
} }
// === [ / what to do at start ] === // // === [ / what to do at start ] === //
...@@ -256,7 +247,7 @@ function syncRemoteGraphData () { ...@@ -256,7 +247,7 @@ function syncRemoteGraphData () {
// cases (2) and (3) : we'll read a file from server // cases (2) and (3) : we'll read a file from server
// sourcemode == "serverfile" or "servermenu" (several files with <select>) // sourcemode == "serverfile" or "servermenu" (several files with <select>)
else { else {
console.log("input case: server-side file, using db.json or getUrlParam.file or TW.conf.sourceFile") console.log("input case: server-side file, using TW.conf.sourceMenu or getUrlParam.file or TW.conf.sourceFile")
// -> @mode is servermenu, files are listed in db.json file (preRes ajax) // -> @mode is servermenu, files are listed in db.json file (preRes ajax)
// --> if @file also in url, choose the db.json one matching <=== £TODO THIS CASE STILL TO FIX // --> if @file also in url, choose the db.json one matching <=== £TODO THIS CASE STILL TO FIX
...@@ -272,9 +263,9 @@ function syncRemoteGraphData () { ...@@ -272,9 +263,9 @@ function syncRemoteGraphData () {
// menufile case : a list of source files in ./db.json // menufile case : a list of source files in ./db.json
if (sourcemode == 'servermenu') { if (sourcemode == 'servermenu') {
console.log("no @file arg nor TW.mainfile: trying FILEMENU db.json") console.log("no @file arg nor TW.mainfile: trying FILEMENU TW.conf.sourceMenu")
// we'll first retrieve the menu of available files in db.json, then get the real data in a second ajax // we'll first retrieve the menu of available files in db.json, then get the real data in a second ajax
var infofile = "db.json" var infofile = TW.conf.sourceMenu
if (TW.conf.debug.logFetchers) console.info(`attempting to load infofile ${infofile}`) if (TW.conf.debug.logFetchers) console.info(`attempting to load infofile ${infofile}`)
var preRES = AjaxSync({ URL: infofile, DT:"json" }); var preRES = AjaxSync({ URL: infofile, DT:"json" });
...@@ -297,9 +288,11 @@ function syncRemoteGraphData () { ...@@ -297,9 +288,11 @@ function syncRemoteGraphData () {
// the first or a specified one (ie both mode and file params are present) // the first or a specified one (ie both mode and file params are present)
if( isUndef(getUrlParam.file) ) { if( isUndef(getUrlParam.file) ) {
the_file = first_path+"/"+first_file the_file = first_path+"/"+first_file
mapLabel = first_file
} else { } else {
// £POSS; match on the full paths from db.json // £POSS; match on the full paths from db.json
the_file = first_path+"/"+getUrlParam.file the_file = first_path+"/"+getUrlParam.file
mapLabel = getUrlParam.file
} }
var files_selector = '<select onchange="jsActionOnGexfSelector(this.value);">' var files_selector = '<select onchange="jsActionOnGexfSelector(this.value);">'
...@@ -723,7 +716,7 @@ function mainStartGraph(inFormat, inData, twInstance) { ...@@ -723,7 +716,7 @@ function mainStartGraph(inFormat, inData, twInstance) {
TW.partialGraph.camera.goTo({x:0, y:0, ratio:0.9, angle: 0}) TW.partialGraph.camera.goTo({x:0, y:0, ratio:0.9, angle: 0})
// mostly json data are extracts provided by DB apis => no positions // mostly json data are extracts provided by DB apis => no positions
if (inFormat == "json") TW.conf.fa2Enabled = true // if (inFormat == "json") TW.conf.fa2Enabled = true
// will run fa2 if enough nodes and TW.conf.fa2Enabled == true // will run fa2 if enough nodes and TW.conf.fa2Enabled == true
sigma_utils.smartForceAtlas() sigma_utils.smartForceAtlas()
...@@ -761,13 +754,13 @@ function mainStartGraph(inFormat, inData, twInstance) { ...@@ -761,13 +754,13 @@ function mainStartGraph(inFormat, inData, twInstance) {
// load optional modules // load optional modules
ProcessDivsFlags() ; activateModules() ;
// show any already existing panel // show any already existing panel
document.getElementById("graph-panels").style.display = "block" document.getElementById("graph-panels").style.display = "block"
// grey message in the search bar from settings // grey message in the search bar from settings
$("#searchinput").attr('placeholder', TW.strSearchBar) ; $("#searchinput").attr('placeholder', TW.conf.strSearchBar) ;
setTimeout( function() { setTimeout( function() {
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
// settings: {norender: Bool} // settings: {norender: Bool}
function cancelSelection (fromTagCloud, settings) { function cancelSelection (fromTagCloud, settings) {
if (TW.conf.debug.selections) { console.log("\t***in cancelSelection"); } if (TW.conf.debug.logSelections) { console.log("\t***in cancelSelection"); }
if (!settings) settings = {} if (!settings) settings = {}
highlightSelectedNodes(false); //Unselect the selected ones :D highlightSelectedNodes(false); //Unselect the selected ones :D
...@@ -111,6 +111,24 @@ function getActivetypesKey() { ...@@ -111,6 +111,24 @@ function getActivetypesKey() {
return lastState.activetypes.map(Number).join('|') return lastState.activetypes.map(Number).join('|')
} }
// transitional function:
// ----------------------
// Goal: determine if a single nodetype or global activetype is semantic or social
// Explanation: some older functions (eg topPapers) used this distinction
// (via semi-deprecated global swclickActual),
// but the specification changed twice since then:
// - 1st change: types described as type 0 and type 1 and possible default type
// - 2nd change default type of monopartite case changed from document to semantic
function swActual(aNodetype) {
if (TW.categories.length == 1) {
return 'semantic'
}
else if (TW.categories.length == 2) {
return (aNodetype == TW.categories[0]) ? 'social' : 'semantic'
}
}
function highlightSelectedNodes(flag){ function highlightSelectedNodes(flag){
if (TW.conf.debug.logSelections) if (TW.conf.debug.logSelections)
...@@ -242,17 +260,21 @@ function htmlfied_alternodes(elems) { ...@@ -242,17 +260,21 @@ function htmlfied_alternodes(elems) {
var js1='onclick="graphTagCloudElem(\''; var js1='onclick="graphTagCloudElem(\'';
var js2="');\"" var js2="');\""
var frecMAX=elems[0].value var frecMAX=elems[0].value
console.log("htmlfied_alternodes elems", elems)
console.log("htmlfied_alternodes frecMAX", frecMAX)
for(var i in elems){ for(var i in elems){
var id=elems[i].key var id=elems[i].key
var frec=elems[i].value var frec=elems[i].value
var fontSize var fontSize
var htmlfied_alternode var htmlfied_alternode
if(frecMAX==1) fontSize=desirableTagCloudFont_MIN; if(frecMAX==1) fontSize=TW.conf.tagcloudFontsizeMin;
else { else {
fontSize= fontSize=
desirableTagCloudFont_MIN+ TW.conf.tagcloudFontsizeMin+
(frec-1)* (frec-1)*
((desirableTagCloudFont_MAX-desirableTagCloudFont_MIN)/(frecMAX-1)); ((TW.conf.tagcloudFontsizeMax-TW.conf.tagcloudFontsizeMin)/(frecMAX-1));
} }
if(!isUndef(TW.Nodes[id])){ if(!isUndef(TW.Nodes[id])){
...@@ -316,22 +338,6 @@ function clearHover() { ...@@ -316,22 +338,6 @@ function clearHover() {
) )
} }
// TODO rm ? function doesn't make sense, probably replaced by htmlfied_tagcloud
// function htmlfied_samenodes(elems) {
// var sameNodes=[]
// js1=' onmouseover="manualForceLabel(this.id,true, true);" ';
// js2=' onmouseout="manualForceLabel(this.id,true, true);" ';
// if(elems.length>0) {
// var A = getVisibleNodes()
// for (var a in A){
// n = A[a]
// if(!n.active && n.color.charAt(0)=="#" ) {
// sameNodes.push('<li onmouseover="manualForceLabel(\''+n.id+'\',true, true)" onmouseout="manualForceLabel(\''+n.id+'\',false, true)" ><a>'+ n.label+ '</a></li>')
// }
// }
// }
// return sameNodes
// }
// nodes information div // nodes information div
function htmlfied_nodesatts(elems){ function htmlfied_nodesatts(elems){
...@@ -369,9 +375,9 @@ function htmlfied_nodesatts(elems){ ...@@ -369,9 +375,9 @@ function htmlfied_nodesatts(elems){
if(node.type==TW.conf.catSem){ if(node.type==TW.conf.catSem){
information += '<li><b>' + node.label + '</b></li>'; information += '<li><b>' + node.label + '</b></li>';
google='<a href=http://www.google.com/#hl=en&source=hp&q=%20'+node.label.replace(" ","+")+'%20><img src="'+'img/google.png"></img></a>'; let google='<a href=http://www.google.com/#hl=en&source=hp&q=%20'+node.label.replace(" ","+")+'%20><img src="'+'img/google.png"></img></a>';
wiki = '<a href=http://en.wikipedia.org/wiki/'+node.label.replace(" ","_")+'><img src="'+'img/wikipedia.png"></img></a>'; let wiki = '<a href=http://en.wikipedia.org/wiki/'+node.label.replace(" ","_")+'><img src="'+'img/wikipedia.png"></img></a>';
flickr= '<a href=http://www.flickr.com/search/?w=all&q='+node.label.replace(" ","+")+'><img src="'+'img/flickr.png"></img></a>'; let flickr= '<a href=http://www.flickr.com/search/?w=all&q='+node.label.replace(" ","+")+'><img src="'+'img/flickr.png"></img></a>';
information += '<li>'+google+"&nbsp;"+wiki+"&nbsp;"+flickr+'</li><br>'; information += '<li>'+google+"&nbsp;"+wiki+"&nbsp;"+flickr+'</li><br>';
semnodes.push(information) semnodes.push(information)
} }
...@@ -388,33 +394,40 @@ function manualSelectNode ( nodeid ) { ...@@ -388,33 +394,40 @@ function manualSelectNode ( nodeid ) {
// (MultipleSelection2 will do the re-rendering) // (MultipleSelection2 will do the re-rendering)
} }
function htmlfied_tagcloud(elems , limit) { function htmlProportionalLabels(elems , limit, selectableFlag) {
if(elems.length==0) return false; if(elems.length==0) return false;
var oppositesNodes=[] let resHtml=[]
var fontSize=desirableTagCloudFont_MIN
let frecMAX=elems[0].value let fontSize // <-- normalized for display
// we assume already sorted
let frecMax = elems[0].value
let frecMin = elems.slice(-1)[0].value
for(var i in elems){ for(var i in elems){
if(i==limit) if(i==limit)
break break
let id=elems[i].key let id=elems[i].key
let frec=elems[i].value let frec=elems[i].value
if(frecMAX > 1) {
fontSize= // FIXME: works but is optimizable (precompute stable part)
desirableTagCloudFont_MIN+ fontSize = ((frec - frecMin) * (TW.conf.tagcloudFontsizeMax - TW.conf.tagcloudFontsizeMin) / (frecMax - frecMin)) + TW.conf.tagcloudFontsizeMin
(frec-1)*
((desirableTagCloudFont_MAX-desirableTagCloudFont_MIN)/(frecMAX-1));
}
// debug // debug
// console.log('htmlfied_tagcloud (',id, TW.Nodes[id].label,') freq',frec,' fontSize', fontSize) // console.log('htmlfied_tagcloud (',id, TW.Nodes[id].label,') freq',frec,' fontSize', fontSize)
if(!isUndef(TW.Nodes[id])){ if(!isUndef(TW.Nodes[id])){
var jspart = ' onclick="manualSelectNode(\''+id+'\')" onmouseover="manualForceLabel(\''+id+'\',true, true)" onmouseout="manualForceLabel(\''+id+'\',false, true)"' var jspart = ''
let htmlfied_alternode = '<span class="tagcloud-item" style="font-size:'+fontSize+'px;" '+jspart+'>'+ TW.Nodes[id].label+ '</span>';
oppositesNodes.push(htmlfied_alternode) if (selectableFlag) {
jspart = ' onclick="manualSelectNode(\''+id+'\')" onmouseover="manualForceLabel(\''+id+'\',true, true)" onmouseout="manualForceLabel(\''+id+'\',false, true)"'
}
let htmlLabel = '<span class="tagcloud-item" style="font-size:'+fontSize+'px;" '+jspart+'>'+ TW.Nodes[id].label+ '</span>';
resHtml.push(htmlLabel)
} }
} }
return oppositesNodes return resHtml
} }
//missing: getTopPapers for both node types //missing: getTopPapers for both node types
...@@ -449,13 +462,13 @@ function updateRelatedNodesPanel( sels , same, oppos ) { ...@@ -449,13 +462,13 @@ function updateRelatedNodesPanel( sels , same, oppos ) {
if(oppos.length>0) { if(oppos.length>0) {
alterNodesDIV+='<div id="oppositesBox">';//tagcloud alterNodesDIV+='<div id="oppositesBox">';//tagcloud
alterNodesDIV+= htmlfied_alternodes( oppos ).join("\n") alterNodesDIV+= htmlProportionalLabels( oppos , TW.conf.tagcloudOpposLimit, false).join("\n")
alterNodesDIV+= '</div>'; alterNodesDIV+= '</div>';
} }
if(getNodeIDs(sels).length>0) { if(getNodeIDs(sels).length>0) {
sameNodesDIV+='<div id="sameNodes">';//tagcloud sameNodesDIV+='<div id="sameNodes">';//tagcloud
var sameNeighTagcloudHtml = htmlfied_tagcloud( same , TW.tagcloud_limit) var sameNeighTagcloudHtml = htmlProportionalLabels( same , TW.conf.tagcloudSameLimit, true )
sameNodesDIV+= (sameNeighTagcloudHtml!=false) ? sameNeighTagcloudHtml.join("\n") : "No related items."; sameNodesDIV+= (sameNeighTagcloudHtml!=false) ? sameNeighTagcloudHtml.join("\n") : "No related items.";
sameNodesDIV+= '</div>'; sameNodesDIV+= '</div>';
} }
...@@ -481,7 +494,7 @@ function updateRelatedNodesPanel( sels , same, oppos ) { ...@@ -481,7 +494,7 @@ function updateRelatedNodesPanel( sels , same, oppos ) {
$("#tips").html(""); $("#tips").html("");
if(TW.categories.length==1) getTopPapers("semantic"); if(TW.categories.length==1) getTopPapers("semantic");
else getTopPapers(swclickActual); else getTopPapers(swActual(getActivetypes()[0]));
} }
function printStates() { function printStates() {
...@@ -577,7 +590,7 @@ function graphTagCloudElem(nodes) { ...@@ -577,7 +590,7 @@ function graphTagCloudElem(nodes) {
nodesDict:nodes_2_colour, nodesDict:nodes_2_colour,
edgesDict:edges_2_colour edgesDict:edges_2_colour
}); });
overNodes=true; // deprecated TW.selectionActive = true
} }
var present = TW.partialGraph.states.slice(-1)[0]; // Last var present = TW.partialGraph.states.slice(-1)[0]; // Last
...@@ -799,7 +812,6 @@ function add1Elem(id) { ...@@ -799,7 +812,6 @@ function add1Elem(id) {
if(!n.lock) { if(!n.lock) {
updateSearchLabels(id,n.label,n.type); updateSearchLabels(id,n.label,n.type);
nodeslength++;
} }
// TW.partialGraph.graph.addNode(anode); // TW.partialGraph.graph.addNode(anode);
TW.partialGraph.graph.addNode(n); TW.partialGraph.graph.addNode(n);
......
...@@ -248,7 +248,7 @@ function sortNodeTypes(observedTypesDict) { ...@@ -248,7 +248,7 @@ function sortNodeTypes(observedTypesDict) {
// POSSible: allow more than 2 cats // POSSible: allow more than 2 cats
for(var i in observedTypes) { for(var i in observedTypes) {
let c = observedTypes[i] let c = observedTypes[i]
if(c == TW.conf.catSoc || (c != TW.catSem && c.indexOf("term")==-1)) {// NOT a term-category if(c == TW.conf.catSoc || (c != TW.conf.catSem && c.indexOf("term")==-1)) {// NOT a term-category
newcats[0] = c; newcats[0] = c;
catDict[c] = 0; catDict[c] = 0;
} }
...@@ -299,6 +299,7 @@ function facetsBinning (valuesIdx, Atts_2_Exclude) { ...@@ -299,6 +299,7 @@ function facetsBinning (valuesIdx, Atts_2_Exclude) {
// console.log(`======= ${cat}::${at} =======`) // console.log(`======= ${cat}::${at} =======`)
// skip non-numeric or already done // skip non-numeric or already done
// £TODO finish changes to Atts_2_Exclude from 69e7c039
if (Atts_2_Exclude[at] || at == "clust_default") { if (Atts_2_Exclude[at] || at == "clust_default") {
continue continue
} }
...@@ -307,7 +308,7 @@ function facetsBinning (valuesIdx, Atts_2_Exclude) { ...@@ -307,7 +308,7 @@ function facetsBinning (valuesIdx, Atts_2_Exclude) {
facetIdx[cat][at] = [] facetIdx[cat][at] = []
// if n possible values doesn't need binify // if n possible values doesn't need binify
if (Object.keys(valuesIdx[cat][at].map).length <= TW.maxDiscreteValues) { if (Object.keys(valuesIdx[cat][at].map).length <= TW.conf.maxDiscreteValues) {
for (var pval in valuesIdx[cat][at].map) { for (var pval in valuesIdx[cat][at].map) {
facetIdx[cat][at].push({ facetIdx[cat][at].push({
'labl': `${cat}||${at}||${pval}`, 'labl': `${cat}||${at}||${pval}`,
...@@ -592,7 +593,7 @@ function dictfyGexf( gexf , categories ){ ...@@ -592,7 +593,7 @@ function dictfyGexf( gexf , categories ){
// console.debug("node.attributes", node.attributes) // console.debug("node.attributes", node.attributes)
// creating a faceted index from node.attributes // creating a faceted index from node.attributes
if (TW.scanClusters) { if (TW.conf.scanClusters) {
[tmpVals, Atts_2_Exclude] = updateValueFacets(tmpVals, Atts_2_Exclude, node) [tmpVals, Atts_2_Exclude] = updateValueFacets(tmpVals, Atts_2_Exclude, node)
} }
...@@ -615,6 +616,7 @@ function dictfyGexf( gexf , categories ){ ...@@ -615,6 +616,7 @@ function dictfyGexf( gexf , categories ){
// clusters and other facets => type => name => [{label,val/range,nodeids}] // clusters and other facets => type => name => [{label,val/range,nodeids}]
// £TODO finish changes to Atts_2_Exclude from 69e7c039 (new specif: dtype str is accepted for classes)
TW.Clusters = facetsBinning(tmpVals, Atts_2_Exclude) TW.Clusters = facetsBinning(tmpVals, Atts_2_Exclude)
......
'use strict'; 'use strict';
SigmaUtils = function () { SigmaUtils = function () {
this.nbCats = 0;
// input = GEXFstring // input = GEXFstring
this.FillGraph = function( initialActivetypes , catDict , nodes, edges , graph ) { this.FillGraph = function( initialActivetypes , catDict , nodes, edges , graph ) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment