From cd1ede511e044e92459a21ba43e87956e5b10297 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Wed, 12 Dec 2018 11:43:43 -0500 Subject: [PATCH 01/22] Made Recall interface a little less terrible. Added Stash deletion. --- index.html | 49 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/index.html b/index.html index f85a5be4..21a9e031 100644 --- a/index.html +++ b/index.html @@ -392,14 +392,12 @@ @@ -584,20 +582,31 @@ }); $('#stash-data').on('click', function(){ - localforage.setItem('stash-'+$('#stash-name').val(), JSON.stringify(session)); + localforage.setItem('stash-'+Date.now()+'-'+$('#stash-name').val(), JSON.stringify(session)); }); + var table; $('#RecallDataTab').on('click', function(){ + table = new Tabulator('#recall-stashes-available', { + height: '100%', + layout: "fitColumns", + selectable: 1, + columns: [ + {title:"Name", field:"name"}, + {title:"Date", field:"date", align:"right", sorter:"date"} + ] + }); localforage.keys().then(function(keys){ - var h = $('#recall-stashes-available'); + var rows = []; keys.forEach(function(k){ if(!k.substring(0, 5) === 'stash') return; - $('' + k.slice(6) + '').on('click', function(){ - localforage.getItem($(this).data('stash')).then(function(json){ - app.applySession(JSON.parse(json)); - }); - }).appendTo(h); + rows.push({ + fullname: k, + name: k.substring(20), + date: (new Date(parseFloat(k.substring(6,19)))).toISOString() + }); }); + table.setData(rows); $('#session-recall-modal').modal('show'); }).catch(function(err){ // This code runs if there were any errors @@ -605,6 +614,20 @@ }); }); + $('#recall-delete-stash').on('click', function(){ + var key = table.getSelectedData()[0].fullname; + localforage.removeItem(key).then(function(){ + alertify.success('That stash has been deleted.'); + }); + }); + + $('#recall-load-stash').on('click', function(){ + var key = table.getSelectedData()[0].fullname; + localforage.getItem(key).then(function(json){ + app.applySession(JSON.parse(json)); + $('#session-recall-modal').modal('hide'); + }); + }); $('#OpenTab').on('change', function(e){ if(e.target.files.length > 0){ From 0021164f06bd78a59e8a8f0654ddef7608c48d0a Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Wed, 12 Dec 2018 14:23:49 -0500 Subject: [PATCH 02/22] Reordered index for slightly more orderly loading --- index.html | 77 +++++++++++++++++++++++++----------------------------- 1 file changed, 35 insertions(+), 42 deletions(-) diff --git a/index.html b/index.html index 21a9e031..2f8792be 100644 --- a/index.html +++ b/index.html @@ -476,31 +476,15 @@ $(function(){ 'use strict'; - $.getJSON('package.json', function(r){ - app.manifest = r; - $('#version').html(r.version); - }); - - $.get('.git/HEAD', function(ref){ - var branch = ref.split('/').pop(); - $('#branch') - .attr('href', 'https://github.com/CDCgov/MicrobeTRACE/tree/' + branch) - .text(branch); - $.get('.git/' + ref.split(' ').pop(), function(r){ - $('#commit') - .attr('href', 'https://github.com/CDCgov/MicrobeTrace/commit/' + r) - .text(r.slice(0,7)); + // Before anything else gets done, ask the user to accept the legal agreement + if(!localStorage.getItem('licenseAccepted')){ + $('#acceptAgreement').on('click', function(){ + localStorage.setItem('licenseAccepted', new Date()); + }); + $('#licenseAgreement').modal({ + backdrop: 'static', + keyboard: false }); - }).fail(function(){ - $('#branch').parent().remove(); - }); - - if(window.navigator.onLine){ - $('#HelpTab') - .removeClass('viewbutton') - .attr('href', 'https://github.com/CDCgov/MicrobeTrace/wiki') - .attr('target', '_blank'); - $('.ifOnline').show(); } if ('serviceWorker' in window.navigator) { @@ -529,24 +513,6 @@ app.launchView('files'); - // Before anything else gets done, ask the user to accept the legal agreement - if(!localStorage.getItem('licenseAccepted')){ - $('#acceptAgreement').on('click', function(){ - // Set that agreement in localStorage - localStorage.setItem('licenseAccepted', new Date()); - }); - // $('#rejectAgreement').on('click', function(){ - // // If you don't agree, no app for you! - // //TODO: Show a message indicating you are not permitted to use the app without agreeing to the terms of use. - // window.location.href = "https://www.cdc.gov"; - // }); - // No hacking around the agreement. - $('#licenseAgreement').modal({ - backdrop: 'static', - keyboard: false - }); - } - // Let's set up the Nav Bar $('#FileTab').on('click', function(){ $('#exit-button').on('click', app.reset); @@ -902,6 +868,33 @@ } }); + if(window.navigator.onLine){ + $('#HelpTab') + .removeClass('viewbutton') + .attr('href', 'https://github.com/CDCgov/MicrobeTrace/wiki') + .attr('target', '_blank'); + $('.ifOnline').show(); + } + + $.getJSON('package.json', function(r){ + app.manifest = r; + $('#version').html(r.version); + }); + + $.get('.git/HEAD', function(ref){ + var branch = ref.split('/').pop(); + $('#branch') + .attr('href', 'https://github.com/CDCgov/MicrobeTRACE/tree/' + branch) + .text(branch); + $.get('.git/' + ref.split(' ').pop(), function(r){ + $('#commit') + .attr('href', 'https://github.com/CDCgov/MicrobeTrace/commit/' + r) + .text(r.slice(0,7)); + }); + }).fail(function(){ + $('#branch').parent().remove(); + }); + $('#group-key-wrapper').on('contextmenu', function(e){ e.preventDefault(); $('#group-key-context').css({ From 4478a3ef70d6fe0385f55de3a293138110274e60 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Wed, 12 Dec 2018 14:25:36 -0500 Subject: [PATCH 03/22] Implemented Autostashing (resolves #72) --- components/files.html | 41 +++++++++++++++++++++++++++++++++++++++++ index.html | 39 ++++++++++++++++++++++----------------- 2 files changed, 63 insertions(+), 17 deletions(-) diff --git a/components/files.html b/components/files.html index 1b0e9602..027b642f 100644 --- a/components/files.html +++ b/components/files.html @@ -172,6 +172,21 @@ +
+
+ +
+
+
+ + +
+
+
@@ -438,6 +453,19 @@ } }); + $('#stash-auto-yes').parent().on('click', function(){ + localStorage.setItem('stash-auto', 'true'); + }); + + if(localStorage.getItem('stash-auto') === 'true'){ + $('#stash-auto-yes').parent().trigger('click'); + } + + $('#stash-auto-no').parent().on('click', function(){ + if(temp.autostash) clearInterval(temp.autostash.interval); + localStorage.setItem('stash-auto', 'false'); + }); + if(localStorage.getItem('default-View')){ $('#default-View').val(localStorage.getItem('default-View')); } @@ -883,6 +911,19 @@ }] }, true); } + if(localStorage.getItem('stash-auto') === 'true'){ + temp.autostash = { + time: Date.now(), + interval: setInterval(function(){ + var newTime = Date.now(); + localforage.setItem('stash-' + newTime + '-autostash', JSON.stringify(session)).then(function(){ + localforage.removeItem('stash-' + temp.autostash.time + '-autostash').then(function(){ + temp.autostash.time = newTime; + }); + }); + }, 60000) + }; + } $('.hideForHIVTrace').css('display', 'flex'); setTimeout(function(){ let files = layout.contentItems.find(function(item){ return item.componentName === 'files'; }); diff --git a/index.html b/index.html index 2f8792be..9f6b31ed 100644 --- a/index.html +++ b/index.html @@ -32,10 +32,10 @@
@@ -267,7 +267,7 @@
-
+
From 522210938d12988bcb3603bfffb8e0b313677ba1 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Mon, 17 Dec 2018 16:49:57 -0500 Subject: [PATCH 18/22] Switched overflowing radio list for select --- components/2d_network.html | 61 ++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/components/2d_network.html b/components/2d_network.html index d24f1187..c8c70e79 100644 --- a/components/2d_network.html +++ b/components/2d_network.html @@ -40,12 +40,24 @@
-
+
+
+
Orientation
+
+ +
+
@@ -151,6 +163,8 @@
+
+
@@ -164,8 +178,6 @@
- -
@@ -733,10 +745,42 @@ if(labelVar === 'None'){ nodes.text(''); } else { - let size = session.style.widgets['node-label-size']; + let size = session.style.widgets['node-label-size'], + orientation = session.style.widgets['node-label-orientation']; nodes .text(n => n[labelVar]) .style('font-size', size + 'px'); + switch(orientation){ + case 'Left': + nodes + .attr('text-anchor', 'end') + .attr('dx', -8) + .attr('dy', size/2); + break; + case 'Top': + nodes + .attr('text-anchor', 'middle') + .attr('dx', 0) + .attr('dy', -size); + break; + case 'Bottom': + nodes + .attr('text-anchor', 'middle') + .attr('dx', 0) + .attr('dy', size); + break; + case 'Middle': + nodes + .attr('text-anchor', 'middle') + .attr('dx', 0) + .attr('dy', size/2); + break; + default: //'right' + nodes + .attr('text-anchor', 'start') + .attr('dx', 8) + .attr('dy', size/2); + } } } @@ -752,9 +796,9 @@ $('#node-label-variable').on('change', e => { session.style.widgets['node-label-variable'] = e.target.value; if(e.target.value === 'None'){ - $('#node-label-row').slideUp(); + $('.node-label-row').slideUp(); } else { - $('#node-label-row').css('display', 'flex'); + $('.node-label-row').css('display', 'flex'); } redrawLabels(); }); @@ -764,6 +808,11 @@ redrawLabels(); }); + $('#node-label-orientation').on('change', e => { + session.style.widgets['node-label-orientation'] = e.target.value; + redrawLabels(); + }); + $('#node-tooltip-variable').on('change', e => { session.style.widgets['node-tooltip-variable'] = e.target.value; }); From 8058523a21328e194bc2b97be43e6260fc3f3e46 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Tue, 18 Dec 2018 09:43:17 -0500 Subject: [PATCH 19/22] Removed network autofitting on layoutchange Per request from @billswitzer2 --- components/2d_network.html | 1 - 1 file changed, 1 deletion(-) diff --git a/components/2d_network.html b/components/2d_network.html index c8c70e79..ecb0797b 100644 --- a/components/2d_network.html +++ b/components/2d_network.html @@ -1083,7 +1083,6 @@ let wrapper = $('#network').parent(); $('#network-export-width' ).val(wrapper.width()); $('#network-export-height').val(wrapper.height()); - setTimeout(fit, 1200); }); if(session.files.length > 1) $('#link-color-variable').val('origin').change(); From 3236c92ccd8bf2b7a0535100d6af167bd7aa0ebb Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Tue, 18 Dec 2018 11:20:37 -0500 Subject: [PATCH 20/22] Added Link Labels Resolves #45 --- components/2d_network.html | 73 +++++++++++++++++++++++++++++++------- scripts/common.js | 1 + 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/components/2d_network.html b/components/2d_network.html index ecb0797b..76eef76a 100644 --- a/components/2d_network.html +++ b/components/2d_network.html @@ -121,6 +121,10 @@
+
+
+
+
Color
@@ -150,6 +154,10 @@
+
+
+
+
@@ -179,20 +187,16 @@
-
-
-
-
-
-
+
+
-
-
+
+
@@ -341,11 +345,11 @@ height = $('#network').parent().parent().parent().height(); d3.select('svg#network') - .html(null) //Let's make sure the canvas is blank. - .attr('height', height) - .attr('width', width) - .on('click', hideContextMenu) - .call(zoom); + .html(null) //Let's make sure the canvas is blank. + .attr('height', height) + .attr('width', width) + .on('click', hideContextMenu) + .call(zoom); d3.select('svg#network') .append('g') @@ -450,8 +454,17 @@ .on('mouseenter', showLinkToolTip) .on('mouseout', hideTooltip); + let llinks = getLLinks(); + let linklabel = svg.select('g#links').selectAll('text').data(llinks); + linklabel.exit().remove(); + linklabel.enter().append('text') + .attr('text-anchor', 'middle') + .attr('dy', session.style.widgets['link-width'] + 2) + .text(l => l[session.style.widgets['link-label-variable']]); + let nodes = svg.select('g#nodes').selectAll('g.node').data(session.network.nodes); let links = svg.select('g#links').selectAll('line').data(vlinks); + let linklabels = svg.select('g#links').selectAll('text').data(llinks); force.nodes(session.network.nodes).on('tick', function(){ nodes .attr('transform', d => d.fixed ? `translate(${d.fx}, ${d.fy})` : `translate(${d.x}, ${d.y})`); @@ -460,6 +473,12 @@ .attr('y1', l => l.source.y) .attr('x2', l => l.target.x) .attr('y2', l => l.target.y); + if(session.style.widgets['link-label-variable'] !== 'None'){ + linklabels + .attr('x', l => (l.source.x + l.target.x)/2) + .attr('y', l => (l.source.y + l.target.y)/2) + .attr('transform', l => 'rotate('+calcAngle(l.source, l.target)+' '+(l.source.x + l.target.x)/2+' '+(l.source.y + l.target.y)/2+')'); + } }); force.force('link').links(vlinks); @@ -470,6 +489,13 @@ force.alpha(0.3).alphaTarget(0).restart(); } + function calcAngle(source, target){ + let opposite = source.x - target.x; + let adjacent = source.y - target.y; + let degrees = Math.atan(opposite / adjacent) * 180 / Math.PI; + return (degrees < 180) ? 90-degrees : 270-degrees; + } + function getVLinks(){ let vlinks = app.getVisibleLinks(true); let output = []; @@ -507,6 +533,16 @@ return output; } + function getLLinks(){ + let vlinks = app.getVisibleLinks(true); + let n = vlinks.length; + for(let i = 0; i < n; i++){ + vlinks[i].source = session.network.nodes.find(d => d.id === vlinks[i].source); + vlinks[i].target = session.network.nodes.find(d => d.id === vlinks[i].target); + } + return vlinks; + } + let selected, multidrag = false; function dragstarted(n){ @@ -891,6 +927,17 @@ session.style.widgets['link-directed'] = false; }); + $('#link-label-variable').on('change', e => { + let label = e.target.value; + session.style.widgets['link-label-variable'] = label; + if(label === 'None'){ + svg.select('g#links').selectAll('text').text(''); + } else { + svg.select('g#links').selectAll('text').data(getLLinks()).text(l => l[label]); + force.alpha(0.01).alphaTarget(0).restart(); + } + }); + $('#link-length').on('input', e => { let v = parseFloat(e.target.value); force.force('link').distance(e.target.value); diff --git a/scripts/common.js b/scripts/common.js index eba2607e..77eebbcb 100644 --- a/scripts/common.js +++ b/scripts/common.js @@ -43,6 +43,7 @@ app.defaultWidgets = { 'link-color': '#a6cee3', 'link-color-variable': 'None', 'link-directed': false, + 'link-label-variable': 'None', 'link-length': 0.125, 'link-opacity': 0, 'link-tooltip-variable': 'None', From d80dc01d3b166b90b993068229de19e9a02dc244 Mon Sep 17 00:00:00 2001 From: Tony Boyles Date: Tue, 18 Dec 2018 12:21:49 -0500 Subject: [PATCH 21/22] Set Link Lists to cast their distance Columns as session.state.linkSortVariable --- components/files.html | 10 +++++----- scripts/common.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/files.html b/components/files.html index 25eed6b4..ad2531cb 100644 --- a/components/files.html +++ b/components/files.html @@ -319,15 +319,15 @@ var optionsrow = $('
'); var options = '' + headers.map(function(h){ return ''; }).join('\n'); optionsrow.append(` -