### 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(`