diff --git a/package.json b/package.json
index 6d785b4..b1c2290 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
"react-router-dom": "^6.8.1",
"react-scripts": "5.0.1",
"react-spinners": "^0.13.8",
+ "react-toastify": "^9.1.1",
"react-tooltip": "^5.7.5",
"react-use": "^17.4.0",
"tailwindcss": "^3.2.6",
diff --git a/src/App.js b/src/App.js
index 5c9c305..8db5a14 100644
--- a/src/App.js
+++ b/src/App.js
@@ -13,10 +13,32 @@ 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 { ToastContainer, toast } from 'react-toastify';
+import 'react-toastify/dist/ReactToastify.css';
import qs from "qs"
+import { U } from "ve-sequence-utils/lib/DNAComplementMap";
var colorHash = new ColorHash({lightness: [0.75, 0.9, 0.7,0.8]});
+
+const filterFeatures = (features, search) => {
+ return features.filter((feature) => {
+ // if feature name contains search string
+ if(feature.name.toLowerCase().includes(search.toLowerCase())){
+ return true;
+ }
+ const product = feature.notes && feature.notes.product ? feature.notes.product[0] : "";
+ if(product.toLowerCase().includes(search.toLowerCase())){
+ return true;
+ }
+ const locus_tag = feature.notes && feature.notes.locus_tag ? feature.notes.locus_tag[0] : "";
+ if(locus_tag.toLowerCase().includes(search.toLowerCase())){
+ return true;
+ }
+ return false;
+ });
+}
+
const useQueryState = query => {
const location = useLocation()
const navigate = useNavigate()
@@ -247,7 +269,7 @@ const getReverseComplement = (sequence) => {
return sequence.split("").map((base) => baseToComplement[base]).reverse().join("");
}
-const SingleRow = ({ parsedSequence, rowStart, rowEnd, setHoveredInfo, rowId, searchInput , zoomLevel, whereMouseWentDown, setWhereMouseWentDown,
+const SingleRow = ({ parsedSequence, rowStart, rowEnd, setHoveredInfo, rowId, intSearchInput,annotSearchInput , zoomLevel, whereMouseWentDown, setWhereMouseWentDown,
whereMouseWentUp, setWhereMouseWentUp,
whereMouseCurrentlyIs,setWhereMouseCurrentlyIs}) => {
@@ -257,7 +279,9 @@ whereMouseCurrentlyIs,setWhereMouseCurrentlyIs}) => {
const sep = 10 * zoomFactor;
- const isSelected = searchInput>=rowStart && searchInput<=rowEnd;
+
+
+
@@ -276,6 +300,11 @@ whereMouseCurrentlyIs,setWhereMouseCurrentlyIs}) => {
(feature.start <= rowStart && feature.end >= rowEnd))
)
);
+
+ const searchFeatures = !annotSearchInput ? [] : filterFeatures(relevantFeatures,annotSearchInput)
+
+ const isSelected = (intSearchInput>=rowStart && intSearchInput<=rowEnd) || searchFeatures.length>0;
+
if (rowStart==0){
//console.log(relevantFeatures);
}
@@ -521,17 +550,17 @@ const codonZoomThreshold = -2
// create a tick specifically at searchInput
let searchTick = null;
- if (searchInput != null && searchInput >= rowStart && searchInput <= rowEnd) {
+ if (intSearchInput != null && intSearchInput >= rowStart && intSearchInput <= rowEnd) {
searchTick = (
-
+
{//rect behind tick
}
-
-
+
- {searchInput+1}
+ {intSearchInput+1}
);
@@ -634,23 +663,49 @@ const codonZoomThreshold = -2
);
};
-function SearchPanel({ searchPanelOpen,setSearchPanelOpen,searchInput,setSearchInput }) {
+function SearchPanel({ searchPanelOpen,setSearchPanelOpen,searchInput,setSearchInput,searchType, setSearchType }) {
const handleInputChange = (event) => {
setSearchInput(event.target.value);
+ // if event.target.value has non-numeric characters, then set searchType to annot
+ if (event.target.value.match(/[^0-9]/)) {
+ setSearchType("annot");
+ console.log("setting searchType to annot");
+ }
};
+
+ const searchOption = [
+ { value: "nuc", label: "nucleotide" },
+ { value: "annot", label: "annotation" },
+ ];
return (
{searchPanelOpen ? ((<>
+
+
+
+
{
if(!intSearchInput) return;
@@ -929,6 +986,24 @@ function GensploreView({genbankString, searchInput, setSearchInput}) {
}, [intSearchInput, rowWidth]);
+ useEffect(() => {
+ if(!annotSearchInput) return;
+ const strippedAnnotInput = annotSearchInput.replace(/\s/g, "");
+ if (strippedAnnotInput === "") return;
+ // search the features for one that matches
+ const matchingFeatures = filterFeatures(genbankData.parsedSequence.features, strippedAnnotInput);
+ if(matchingFeatures.length === 0){
+ toast.error("No matching features found");
+ return;
+ }
+ const firstMatchingFeature = matchingFeatures[0];
+ const row = Math.floor(firstMatchingFeature.start / rowWidth);
+ rowVirtualizer.scrollToIndex(row+1, {align:"center"});
+ setLastSearch(annotSearchInput);
+ }, [annotSearchInput]);
+
+
+
//console.log("virtualItems", virtualItems);
@@ -953,6 +1028,7 @@ function GensploreView({genbankString, searchInput, setSearchInput}) {
return (
+
{true && (
@@ -1036,7 +1114,8 @@ function GensploreView({genbankString, searchInput, setSearchInput}) {
rowWidth={rowWidth}
setHoveredInfo={setHoveredInfo}
rowId={virtualitem.index}
- searchInput={intSearchInput-1}
+ intSearchInput={intSearchInput-1}
+ annotSearchInput={annotSearchInput}
renderProperly={true}
zoomLevel={zoomLevel}
diff --git a/yarn.lock b/yarn.lock
index b505b49..aff83ac 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3154,6 +3154,11 @@ cliui@^7.0.2:
strip-ansi "^6.0.0"
wrap-ansi "^7.0.0"
+clsx@^1.1.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
+ integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
+
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@@ -7800,6 +7805,13 @@ react-spinners@^0.13.8:
resolved "https://registry.yarnpkg.com/react-spinners/-/react-spinners-0.13.8.tgz#5262571be0f745d86bbd49a1e6b49f9f9cb19acc"
integrity sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==
+react-toastify@^9.1.1:
+ version "9.1.1"
+ resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-9.1.1.tgz#9280caea4a13dc1739c350d90660a630807bf10b"
+ integrity sha512-pkFCla1z3ve045qvjEmn2xOJOy4ZciwRXm1oMPULVkELi5aJdHCN/FHnuqXq8IwGDLB7PPk2/J6uP9D8ejuiRw==
+ dependencies:
+ clsx "^1.1.1"
+
react-tooltip@^5.7.5:
version "5.7.5"
resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-5.7.5.tgz#f3487e000a24b6ff84c8181064809a57b43c2e99"