diff --git a/package.json b/package.json
index 2d6342d..6d785b4 100644
--- a/package.json
+++ b/package.json
@@ -9,6 +9,7 @@
"@testing-library/user-event": "^13.5.0",
"autoprefixer": "^10.4.13",
"bio-parsers": "^9.3.0",
+ "color-hash": "^2.0.2",
"postcss": "^8.4.21",
"qs": "^6.11.0",
"rc-slider": "^10.1.1",
diff --git a/src/App.js b/src/App.js
index f870784..2569ebb 100644
--- a/src/App.js
+++ b/src/App.js
@@ -11,10 +11,11 @@ import { useVirtualizer, useWindowVirtualizer} from '@tanstack/react-virtual';
import Slider, {Range} from "rc-slider";
import {AiOutlineZoomIn,AiOutlineZoomOut} from 'react-icons/ai';
import {GiDna1} from 'react-icons/gi';
-
+import ColorHash from 'color-hash';
import { useNavigate, useLocation } from "react-router-dom"
import qs from "qs"
+var colorHash = new ColorHash({lightness: [0.75, 0.9, 0.7,0.8]});
const useQueryState = query => {
const location = useLocation()
@@ -78,12 +79,14 @@ const Tooltip = ({ hoveredInfo }) => {
{hoveredInfo && {hoveredInfo.label}}
{hoveredInfo && hoveredInfo.product && (
{hoveredInfo.product}
+
)}
+
);
};
-const getColor = (feature) => {
+const getColor = (feature, product) => {
switch (feature.type) {
case "CDS":
switch (feature.name){
@@ -131,7 +134,7 @@ const getColor = (feature) => {
return "#ff7f50";
default:
- return "#c39797";
+ return colorHash.hex(feature.name+ product+feature.type);
}
case "gene":
return "blue";
@@ -142,7 +145,7 @@ const getColor = (feature) => {
case "3'UTR":
return "orange";
default:
- return "black";
+ return colorHash.hex(feature.name+ product+feature.type);
}
};
@@ -312,7 +315,7 @@ whereMouseCurrentlyIs,setWhereMouseCurrentlyIs}) => {
const seqLength = locations.reduce((acc, location) => acc + location.end - location.start + 1, 0);
const codonMap = [];
- if (feature.type=="CDS" ){
+ if (feature.type=="CDS" | feature.type=="mat_peptide"){
for (let j = rowStart; j < rowEnd; j++) {
let positionSoFar = 0;
@@ -431,18 +434,25 @@ const codonZoomThreshold = -2
const extraFeat=5*zoomFactor;
const codonPad =15*zoomFactor;
+ const product = feature.notes ? feature.notes.product : "";
+ let betterName = product ? product : feature.name;
+ const altName = betterName == feature.name ? "" : feature.name;
+ if (betterName=="Untitled Feature") betterName=feature.type;
+
+
return (
{
if (zoomLevel< codonZoomThreshold) setHoveredInfo({
label: `${feature.name}: ${feature.type}`,
- product: feature.notes && feature.notes.product ? feature.notes.product : null,
+ product: altName,
+ locusTag: feature.notes && feature.notes.locus_tag ? feature.notes.locus_tag : null,
})}
}
onMouseLeave={() => {
@@ -452,7 +462,7 @@ const codonZoomThreshold = -2
/>
- {feature.name == "Untitled Feature" ? feature.type : feature.name}
+ {betterName}
{
feature.codonMap.map((codon, j) => {
@@ -461,8 +471,9 @@ const codonZoomThreshold = -2
zoomLevel> codonZoomThreshold && setHoveredInfo({
- label: `${codon.gene}: ${codon.aminoAcid}${codon.codonIndex+1}`,
- product: feature.notes && feature.notes.product ? feature.notes.product : null,
+ label: `${betterName}: ${codon.aminoAcid}${codon.codonIndex+1}`,
+ product: altName,
+ locusTag: feature.notes && feature.notes.locus_tag ? feature.notes.locus_tag : null,
})
}
@@ -868,6 +879,7 @@ function GensploreView({genbankString, searchInput, setSearchInput}) {
const virtualItems = rowVirtualizer.getVirtualItems();
const [centeredNucleotide, setCenteredNucleotide] = useState(null);
+
const setZoomLevel = (x) => {
const middleRow = virtualItems[Math.floor(virtualItems.length / 2)].index
@@ -1051,13 +1063,27 @@ function GensploreView({genbankString, searchInput, setSearchInput}) {
const App = () => {
+ const addlExamples = [
+ ["Monkeypox clade II","NC_063383.1"],
+ ["HIV-1","NC_001802.1"],
+
+
+ ]
// option to either load from URL or upload a file
const [genbankString, setGenbankString] = useState(null);
const [loading, setLoading] = useState(false);
const loadFromUrl = async (url) => {
+ setGenbankString(null);
setLoading(true);
const response = await fetch(url);
+ // check for errors
+ if (!response.ok) {
+ setLoading(false);
+ window.alert("Error loading file: for large Genbank files, try using the 'Load from file' option instead.");
+ return;
+ }
+
const text = await response.text();
setGenbankString(text);
setLoading(false);
@@ -1089,7 +1115,17 @@ const App = () => {
const [beingDraggedOver, setBeingDraggedOver] = useState(false);
const [genbankId, setGenbankId] = useState(null);
+ const loadFromGenbankId = async (id) => {
+
+ const strippedOfWhitespace = id.replace(/\s/g, '')
+ // if no length, do nothing
+ if (strippedOfWhitespace.length<= 3) {
+ return
+ }
+ const url = `https://genbank-api.vercel.app/api/genbank/${strippedOfWhitespace}`
+ setGbUrl(url)
+ }
// create UI for loading from URL or file
@@ -1126,6 +1162,9 @@ onDrop={(e) => {
}}
+
+
+
>
View code on GitHub
@@ -1168,14 +1207,7 @@ onDrop={(e) => {
+
-
-
-
-
)}
>);
};
+
export default App;
diff --git a/yarn.lock b/yarn.lock
index 8b71bf4..b505b49 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3187,6 +3187,11 @@ color-convert@^2.0.1:
dependencies:
color-name "~1.1.4"
+color-hash@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/color-hash/-/color-hash-2.0.2.tgz#abf735705da71874ddec7dcef50cd7479e7d64e9"
+ integrity sha512-6exeENAqBTuIR1wIo36mR8xVVBv6l1hSLd7Qmvf6158Ld1L15/dbahR9VUOiX7GmGJBCnQyS0EY+I8x+wa7egg==
+
color-name@1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"