### Launch MicrobeTrace Webserver
Source: https://github.com/cdcgov/hantanet/blob/master/test/security/README.md
Starts the local development server to enable testing of security payloads.
```sh
npm start
```
--------------------------------
### Initial Gantt Chart Setup
Source: https://github.com/cdcgov/hantanet/blob/master/components/gantt.html
Performs initial setup for the Gantt chart, including refreshing the view and setting the background colors. This is executed after a short delay to ensure the DOM is ready.
```javascript
setTimeout(function () {
refresh();
setBackground();
}, 80);
```
--------------------------------
### Initial Map Load and Configuration
Source: https://github.com/cdcgov/hantanet/blob/master/components/geo_map.html
Performs initial setup for the map based on stored temporary data. This includes toggling the visibility of country, state, and county layers, and setting the basemap or satellite view. It then centers the map on the bounds of the nodes.
```javascript
function initialLoadUpdate() { if (temp.mapData['map-countries-show'] == false) $('#map-countries-hide').trigger('click'); if (temp.mapData['map-states-show'] == false) $('#map-states-hide').trigger('click'); if (temp.mapData['map-counties-show'] == true) $('#map-counties-show').trigger('click'); if (temp.mapData['map-basemap-show'] == true) $('#map-basemap-show').trigger('click'); if (temp.mapData['map-satellite-show'] == true) $('#map-satellite-show').trigger('click'); delete temp.mapData['map-countries-show']; delete temp.mapData['map-states-show']; delete temp.mapData['map-counties-show']; delete temp.mapData['map-basemap-show']; delete temp.mapData['map-satellite-show']; map.flyToBounds(layers.nodes.getBounds()); }
```
```javascript
setTimeout(function () { matchCoordinates(function () { rerollNodes(); drawLinks(); drawNodes(); initialLoadUpdate(); }); if (layers.nodes.length) map.flyToBounds(layers.nodes.getBounds()); }, 40);
```
--------------------------------
### Launch Application Process
Source: https://github.com/cdcgov/hantanet/blob/master/components/files.html
Initiates the application launch sequence, including setting start time, disabling the launch button, and displaying processing messages. It uses a Promise to ensure the loading modal is shown before proceeding. Uses jQuery and Bootstrap modal.
```javascript
$('#launch').on('click', () => {
session.meta.startTime = Date.now();
$('#launch').prop('disabled', true);
document.getElementById('loading-information').innerHTML="
Processing file(s)...
";
new Promise(function(resolve, reject) {
$('#loading-information-modal').on('shown.bs.modal', function (e) {
session.messages = [];
$('#loading-information').html('');
resolve("done");
});
$('#loading-information-modal').modal({ backdrop: false, keyboard: false });
setTimeout(() => reject(new Error("Problem loading information modal!")), 5000);
}).then( result => launch() // error => {alert(error); launch();} // informational modal doesn't load );
});
```
--------------------------------
### Run MicrobeTrace Benchmark Test
Source: https://github.com/cdcgov/hantanet/blob/master/test/benchmark/README.md
Execute the core benchmark test script for MicrobeTrace. This script runs sessions with sequence counts ranging from 100 to 3200. Note that the server started by this script does not automatically shut down.
```sh
nodejs tests/benchmark/run.js
```
--------------------------------
### Get Visible Links
Source: https://github.com/cdcgov/hantanet/blob/master/components/2d_network.html
Retrieves visible links from the network, processing origin information. Useful for filtering and preparing link data for rendering or analysis.
```javascript
function getLLinks() { let vlinks = MT.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; }
```
--------------------------------
### Node Dragging Logic
Source: https://github.com/cdcgov/hantanet/blob/master/components/2d_network.html
Manages the start, drag, and end events for node dragging, including single node and multi-node (polygon selection) dragging. Updates node positions and force simulation.
```javascript
let selected, multidrag = false;
function dragstarted(n) {
if (!d3.event.active) force.alphaTarget(0.3).restart();
function setNode(d) {
d.fx = d.x;
d.fy = d.y;
}
multidrag = n.selected;
selected = svg.select('g.nodes')
.selectAll('g')
.data(session.network.nodes)
.filter(d => d.selected);
if (multidrag) {
selected.each(setNode);
} else {
setNode(n);
}
}
function dragged(n) {
function updateNode(d) {
d.fx += d3.event.dx;
d.fy += d3.event.dy;
}
if (multidrag) {
selected.each(updateNode);
} else {
updateNode(n);
}
}
function dragended(n) {
if (!d3.event.active) force.alphaTarget(0);
function unsetNode(d) {
if (!d.fixed) {
d.fx = null;
d.fy = null;
} else {
// save node location back to temp network for pinned network
if(session.style.widgets["timeline-date-field"] != 'None') {
let node = session.network.timelineNodes.find(d2 => d2._id == d._id);
if(node) {
node.x = d.x;
node.y = d.y;
node.fx = d.fx;
node.fy = d.fy;
}
}
}
}
if (multidrag) {
selected.each(unsetNode);
} else {
unsetNode(n);
}
}
```
--------------------------------
### Initialize PIXI Application and Viewport
Source: https://github.com/cdcgov/hantanet/blob/master/components/pixi.html
Sets up the PIXI application with specified dimensions and resolution, and initializes a Viewport for interactive zooming and panning. Appends the PIXI view to the DOM.
```javascript
const SCREEN_WIDTH = $('#pixi').parent().width();
const SCREEN_HEIGHT = $('#pixi').parent().parent().parent().height();
const RESOLUTION = window.devicePixelRatio;
const app = new PIXI.Application({
width: SCREEN_WIDTH,
height: SCREEN_HEIGHT,
resolution: RESOLUTION,
transparent: true,
antialias: true
});
document.getElementById('pixi').appendChild(app.view);
const viewport = new Viewport.Viewport({
screenWidth: SCREEN_WIDTH,
screenHeight: SCREEN_HEIGHT,
worldWidth: SCREEN_WIDTH,
worldHeight: SCREEN_HEIGHT
});
vport.wheel().drag().decelerate();
app.stage.addChild(viewport);
```
--------------------------------
### Initialize File View and Event Listeners
Source: https://github.com/cdcgov/hantanet/blob/master/components/files.html
Sets up Google Analytics tracking, UI panel toggles, and drag-and-drop event handlers for file management.
```javascript
(function () { ga('set', 'page', '/files'); ga('set', 'title', 'Files View'); ga('send', 'pageview'); 'use strict'; $('#file-panel').parent().css('z-index', 1000); $('#file-settings-toggle').on('click', function () { const pane = $('#file-settings-pane'); if ($(this).hasClass('active')) { pane.animate({ left: '-400px' }, () => pane.hide()); } else { pane.show(0, () => pane.animate({ left: '0px' })); } }); if (session.files.length > 0) { $('#file-prompt, #warning-prompt').remove(); session.files.forEach(addToTable); } $('#data-files').on('change', function () { processFiles(this.files); }); $('#file-panel').on('dragover', evt => { evt.stopPropagation(); evt.preventDefault(); evt.originalEvent.dataTransfer.dropEffect = 'copy'; }).on('drop', evt => { evt.stopPropagation(); evt.preventDefault(); processFiles(evt.originalEvent.dataTransfer.files); }); function processFiles(files){ const n = files.length; $('#file-prompt, #warning-prompt').remove(); for (let i = 0; i < n; i++) processFile(files[i]); $('#launch').prop('disabled', false).focus(); } function processFile(rawfile) { const extension = rawfile.name.split('.').pop().toLowerCase(); if (extension == 'zip') { let new_zip = new JSZip(); new_zip .loadAsync(rawfile) .then(zip => { zip.forEach((relativePath, zipEntry) => { zipEntry.async("string").then(c => { MT.processJSON(c, zipEntry.name.split('.').pop()) }); }); }); return; } if (extension == 'microbetrace' || extension == 'hivtrace') { let reader = new FileReader(); reader.onloadend = out => MT.processJSON(out.target.result, extension); reader.readAsText(rawfile, 'UTF-8'); return; } if (extension == 'svg') { let reader = new FileReader(); reader.onloadend = out => MT.processSVG(out.target.result); reader.readAsText(rawfile, 'UTF-8'); return; } fileto.promise(rawfile, (extension == 'xlsx' || extension == 'xls') ? 'ArrayBuffer' : 'Text').then(file => { file.name = filterXSS(file.name); file.extension = file.name.split('.').pop().toLowerCase(); session.files.push(file); addToTable(file); }); } function addToTable(file) { const extension = file.extension ? file.extension : filterXSS(file.name).split('.').pop().toLowerCase(); //#291 restore to previous filetype selection if available const isFasta = 'fasta' == file.format || extension.indexOf('fas') > -1; const isNewick = 'newick' == file.format ||extension.indexOf('nwk') > -1 || extension.indexOf('newick') > -1; const isXL = (extension == 'xlsx' || extension == 'xls'); const isNode = 'node' == file.format || file.name.toLowerCase().includes('node'); if (isXL) { let workbook = XLSX.read(file.contents, { type: 'array' }); let data = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[0]], {raw: false, dateNF: 'yyyy-mm-dd'}); let headers = []; data.forEach(row => { Object.keys(row).forEach(key => { const safeKey = filterXSS(key); if (!headers.includes(safeKey)) headers.push(safeKey); }); }); addTableTile(headers); } else { Papa.parse(file.contents, { delimiter: ",", // newline: "\r\n", header: true, preview: 1, complete: output => addTableTile(output.meta.fields.map(filterXSS)) }); } //For the love of all that's good... //TODO: Rewrite this as a [Web Component](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements) or [something](https://reactjs.org/docs/react-component.html) or something. function addTableTile(headers) { let root = $('').data('filename', file.name); let fnamerow = $(''); $('') .append($('').on('click', () => { session.files.splice(session.files.findIndex(f => f.name == file.name), 1); root.slideUp(() => root.remove()); })) .append($('').on('click', () => { saveAs(new Blob([file.contents], { type: file.type | 'text' }), file.name); })) .append('' + file.name + '') .append(`