Install NodeJS from https://nodejs.org/en/
Feel free to use any package manager tool on your system for installation (
Get the source code from our github repo: https://github.com/lidaof/eg-react
For MacOSX with Apple M1 Chip, please use NodeJS version 16 and above, then try with
npm install --force.
Start the browser¶
npm install(just for the first time)
This step will install dependent packages.
npm install gives you error, you might try
npm install --force.
That’s it! You are done with your mirror site. The browser is now accessible from http://localhost:3000/browser.
Example commands for installation on a RHEL system¶
$ cat /etc/redhat-release Red Hat Enterprise Linux Server release 7.9 (Maipo) # remove system nodejs (optional) sudo yum remove nodejs #install n for node version control curl -L https://git.io/n-install | bash source .bashrc $ node -v v14.17.0 # get the browser code go to frontend folder git clone https://github.com/lidaof/eg-react.git cd eg-react/frontend/ npm install --force npm install react-app-rewired npm start # if get error like: System limit for number of file watchers reached, run this command below echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p # details see: https://stackoverflow.com/questions/55763428/react-native-error-enospc-system-limit-for-number-of-file-watchers-reached
Setup your own backend API (optional)¶
By default, your local browser mirror site uses our API service at
while if you find the species or assembly you are interested is not listed by our API, you can either contact us to add
it or build your own API. To build your own API, please follow the steps below:
Install MongoDB from https://www.mongodb.com/
start mongdb server
Then prepare your gene annotation files like the ones for
Make sure MongoDB is running
npm run setup
This step will load the gene annotation data to the MongoDB database
Now your own backend API is running, change
AWS_API variable to empty string in
After this you are using your own API for gene annotation tracks and gene search.
Our current API in serice in
export const AWS_API = “https://lambda.epigenomegateway.org/v2”;
This API is for testing only:
If you installed a local browser mirror, you also need setup a Firebase instance to enable
function, signup a Firebase account at https://firebase.google.com/, which is free.
.env file under
frontend/ folder with following content:
REACT_APP_FIREBASE_KEY="Your own info" REACT_APP_FIREBASE_DOMAIN="Your own info" REACT_APP_FIREBASE_DATABASE="Your own info" REACT_APP_FIREBASE_STORAGE_BUCKET="Your own info"
The detailed steps of how to get the information above are illustrated in the following screenshots:
Signup a firebase account at Google if you don’t have one, then login into your account, create a new prioject:
Type in the project name and click the Create project button:
Click the Web button to add a Web app:
Type in a web app name and click the Register app button:
The firebase configuration info will be displayed:
Use without firebase¶
Firebase setup is necessary for using with Session and Live function, if browser mirror users think they won’t be necessary, the firebase setup setup can be avoided then.
frontend folder, create a
.env file, add the line below:
npm start, the browser will start without session/live function.
The browser is also available as Docker images, to run the browser instance, get Docker from https://www.docker.com/, our official docker image page is at https://cloud.docker.com/repository/docker/epgg/eg-react, the image is based on Ubuntu 18.04, to run the image, run following commands:
docker run -it -p 3000:3000 epgg/eg-react
The first 3000 port is the port will be used on your local computer, you can change it to any other port.
After the docker image is running, to start the browser:
cd eg-react/frontend npm start
Open your web browser and locate to http://localhost:3000 to see the browser.
To embed the browser in any HTML file, create a HTML page with following contents: (the example shows how to embed a mouse browser with 2 bigWig tracks from ENCODE data portal)
The key API is the function
renderBrowserInElement, it accepts the contents array as first argument, and container as second argument which is a DOM element.
Frontend code architeture¶
This section explains how frontend code is organized, intend to be used for development purpose. Regular browser users don’t need to care about this section.
The client code is in the
frontend folder. Here is a quick tour of
components: All React components.
genomeNavigator: The navigation bar at the top that allows users to navigate
track: Track-related components
trackManagers: UI that manages adding tracks
dataSources: API calls, AJAX calls, database connections, etc. that get data to display.
model: Data models.
stories: Stories for Storybook on which unit tests depend.
vendor: 3rd-party libraries that are not in NPM.
Suggested order of reading¶
If you plan to understand the app as a whole here is a suggested order to read the code in:
Feature: A feature or annotation in the genome.
NavigationContext: A list of
Features that represent everywhere a user can navigate. If the
Features are actually entire chromosomes then the user can effectively navigate the whole genome.
DisplayedRegionModel: An interval in a
App: The root component of the app.
App, descend into interested components.
Making a new track type¶
Make a new TrackConfig¶
Make a new class that extends
TrackConfigor one of its subclasses. This class packages many essential track
getComponent()- Gets the component that renders the main visualizer and legend of the track.
getMenuComponents()- Specifies context menu items in an array of components. You can choose existing ones in the
contextMenudirectory or make new ones.
getOptions()- The visualizer probably renders with default options like a color. This method returns a plain object containing those options.
You do not have to implement these methods immediately as the base
TrackConfig class provides minimal defaults.
Just work on making the browser render some temporary placeholder at first.
Specify when to use the TrackConfig¶
Import your new TrackConfig into
Add an appropriate entry to
TYPE_NAME_TO_SUBTYPE, which maps track type name to track renderer.
Write a new track visualizer component (implement
Make a new component expecting to receive a bunch of props from
Track.jsdocuments the props to expect.
If you need data assume it will come through the
dataprop. We will add data fetch in the next step.
Your new component may
renderanything though it is highly recommended you render a
<Track>component, if not one of the more specialized components like
<NumericalTrack>. Pass all track container props to these sub-components.
In addition to track container props you need to provide certain props to these sub-components, all of which the respective files document.
<Track>requires a legend and visualizer element. Use the track container props, which includes view region and width, to render a visualizer and pass it to
Add data fetch¶
Available data sources are in the
dataSources folder. If none of them fulfill your needs, write a new class that
fulfills the interface of
DataSource.js. More can be found in that file.
How do we give your visualizer data? Higher-order components!
track/commonComponents contains track-specific HOCs; their names start with
configStaticDataSource requests a callback that returns a
DataSource and then returns a function that wraps React
components. After you use this function, a component will automatically receive three props
error. These update with the browser’s current view region. In particular, the HOC guarantees synchronization of the
data prop with the current view region if
isLoading is false.
3. Specify default options¶
Default option objects look like the
options prop of
TrackModel objects. Context menu items will read these options
if the track model does not specify them. Make sure these options are consistent with the way you are rendering your
track component! The
configOptionMerging HOC should help with that.
Once you have a default options object, call
setDefaultOptions() in the constructor of
TrackConfig to use them.
Querying the width or height of any element, for example through
Such queries take on the order of 2 to 20 ms. While it is fine to do it once or twice, avoid doing it in a loop.
Suppose you aim to plot 500 data points on a SVG and for each point you query the SVG’s width. That is already a
second or more of computation – very noticable to the user!
React (and other) gotchas¶
On Macs, control + click is the same as a right click which fires a
contextmenuevent. Note that
clickevents do not fire on
mouseupevents will still fire though.
When using native DOM events they take priority over React events. This is because React waits for events to bubble to the root component before handling them. This can cause undesirable effects: for example, calling
stopPropagation()on a React event will not actually stop native events. This StackOverflow post may also help if you have propagation problems: https://stackoverflow.com/questions/24415631/reactjs-syntheticevent-stoppropagation-only-works-with-react-events
React always unmounts components if their parents change type. The
Reparentablecomponent works around this by using app-unique IDs, but it can cause side effects with React’s native events. Use with care.
Webpack does not support circular dependencies, and while compilation may be successful, an import may resolve as
Lessons trying to refactor into WebWorkers¶
Data fetch and track display options are intimately related. For example, what if someone wants HiC data and selects the 5KB resolution option?
Thus, for each track type, we have one object that gets the track component, default rendering options, and data fetch/processing.
Webpack hangs forever if it encounters a cyclic dependency involving a webworker.
The code as in (2) causes a cyclic depdendency. This cycle is [config object] –> [data source] –> [worker] –> [track config deserializer] –> [config object]
We cannot have our cake and eat it too.
Unfortunately, this means we cannot pipeline all expensive computation in worker context, while also ensuring track component and data source live in the same place.