https://github.com/janeliascicomp/videoannotation
https://github.com/janeliascicomp/videoannotation
Last synced: 8 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/janeliascicomp/videoannotation
- Owner: JaneliaSciComp
- License: bsd-3-clause
- Created: 2023-03-23T21:52:46.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2025-06-09T20:32:07.000Z (8 months ago)
- Last Synced: 2025-06-09T21:29:51.281Z (8 months ago)
- Language: JavaScript
- Size: 24 MB
- Stars: 1
- Watchers: 7
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
## Quick Start
We will use ***React, Next.js*** and our library to create a simple video annotation web like this:

If you’re new to React or Next.js, check out [React](https://react.dev/learn) and [Next.js](https://nextjs.org/learn/foundations/about-nextjs).
### Step 1: Initialize a new project
First of all, you need to install [Node.js](https://nodejs.org/en/) (>=19.0.0).
Then clone this repo.
Then outside of the repo dir, run
```bash
npx create-next-app@13.2.4 # The version used to create the page
```
Answer the popup questions. For my test, I used these settings. You can also customize your own.

### Step 2: Copy our library to your project and install dependencies
> [!NOTE]
> This step will be replaced by `npm install ourLib` after we release this library
Copy ***package.json, components, utils*** and ***styles*** folders from the repo dir to the root dir of the project you just created.
In the root dir of your project, install the dependencies.
```bash
npm install
```
### Step 3: Run the development server
```bash
npm run dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
### Step 4: Modify `pages/index.js`
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
For the web in the image above, the index.js file should look like this
```javascript
import React, {useState} from 'react';
import Head from 'next/head';
import Workspace from '../components/Workspace.js';
import Canvas from '../components/Canvas.js';
import VideoUploader from '../components/VideoUploader.js';
import BtnContainer from '../components/BtnContainer.js';
import AnnotationTable from '../components/AnnotationTable.js';
import DownloadBtn from '../components/DownloadBtn.js';
import ProjectManager from '../components/ProjectManager.js';
import ModalJsonUploader from '../components/ModalJsonUploader.js';
import VideoManager from '../components/VideoManager.js';
import CanvasAdditionalDataController from '../components/CanvasAdditionalDataController.js';
import DropdownMenu from '../components/DropdownMenu.js';
import ProjectList from '../components/ProjectList.js';
import SaveAnnotationBtn from '../components/SaveAnnotationBtn.js';
import InfoBar from '../components/InfoBar.js';
import {Row, Col} from 'react-bootstrap'; // Third party components. Refer to the tutorial on https://react-bootstrap.netlify.app/docs/layout/grid
import { Menu, Modal } from 'antd'; // Third party components. Refer to the tutorial on https://ant.design/components/menu, and https://ant.design/components/modal
import { drawCircle, drawLine } from '../utils/canvasUtils.js'; // canvasUtils.js is a wrapper of fabric.js. It provides functions to operate on canvas easily. Currently, only these two functions are provided.
// Client side components. They cannot be rendered on the server side, thus need to be explicitly marked as client side comp.
import dynamic from 'next/dynamic';
const AdditionalDataChart = dynamic(() => import('../components/AdditionalDataChart.js'), { ssr: false });
const AnnotationChart = dynamic(() => import('../components/AnnotationChart.js'), { ssr: false });
export default function Home() {
// The ..open/set..Open states are to allow the child modal components to control the visibility of themselves inside.
const [newProjectManagerOpen, setNewProjectManagerOpen] = useState(false);
const [editProjectManagerOpen, setEditProjectManagerOpen] = useState(false);
const [configUploaderOpen, setConfigUploaderOpen] = useState(false);
const [projectListOpen, setProjectListOpen] = useState(false);
const [videoManagerOpen, setVideoManagerOpen] = useState(false);
const [annotationUploaderOpen, setAnnotationUploaderOpen] = useState(false);
const [canvasAdditionalDataControllerOpen, setCanvasAdditionalDataControllerOpen] = useState(false);
const [info, setInfo] = useState(''); // To display feedback info
const projectDropdownItems = [
{
label: 'Exisiting Projects',
compName: 'ProjectList', // When pass a component, it is required to have a compName prop whose value should be equivalent to the name of the component, e.g. 's compName is 'ProjectList'.
component: ,
// preventDefault: true, // when use some built-in components as the children of DropdownMenu, there may be some pre-defined behaviors, such as opening a modal window. To prevent the default behavior, set this to true.
},
{
label: 'New Project',
compName: 'ProjectManager',
component: ,
},
{
label: 'Upload Project',
compName: 'ModalJsonUploader',
component: ,
},
{
label: 'Edit Project',
compName: 'ProjectManager',
component: ,
},
{
label: 'Download Configuration',
compName: 'DownloadBtn',
component: ,
},
];
function projectDropdownClickHandler(e) {
/**
* Click event handler for DropdownMenu. Will be called after the default behavior of each child.
* e is the event object which has a key property corresponding to the index(integer) of each child in the 'menu' prop. This may be different with the 'key' prop of the component passed to each child.
* */
// console.log(e);
// TODO: customize click handler
// const label = projectDropdownItems[e.key].label;
// switch (label) {
// case 'Exisiting Projects':
// setInfo('Exisiting Projects');
// break;
// case 'New Project':
// setInfo('New Project');
// break;
// case 'Upload Project':
// setInfo('Upload Project');
// break;
// case 'Save Annotation':
// setInfo('Save Annotation');
// break;
// case 'Edit Project':
// setInfo('Edit Project');
// break;
// case 'Download Configuration':
// setInfo('Download Configuration');
// break;
// }
}
const projectDropdown = ;
const videoDropdownItems = [
{
label: 'Video Manager',
compName: 'VideoManager',
component: setVideoManagerOpen(false)}
style={{overflowX: 'auto'}}
footer={null}
>
,
},
{
label: 'Additional Data For Canvas',
compName: 'CanvasAdditionalDataController',
component: setCanvasAdditionalDataControllerOpen(false)}
style={{overflowX: 'auto'}}
footer={null}
>
,
},
];
function drawDataAsCircle(params) {
/**
* OnLoad event handler for the additional data for canvas.
*
* params: {
* target: fabric obj needed for the drawing. Just pass it to the imported func from canvasUtils.js
* data: [additional data in needed range]
* }
*/
for (let c of params.data) {
c.push(3); // add radius
drawCircle(params.target, c, 'red');
}
}
function drawDataAsLine(params) {
for (let l of params.data) {
drawLine(params.target, l, 'white');
}
}
function videoDropdownClickHandler(e) {
// TODO: customize click handler
}
const videoDropdown =
const annotationDropdownItems = [
{
label: 'Save Annotation',
compName: 'SaveAnnotationBtn',
component: ,
},
{
label: 'Download Annotation',
compName: 'DownloadBtn',
component: ,
},
{
label: 'Upload Annotation',
compName: 'ModalJsonUploader',
component: ,
},
];
function annotationDropdownClickHandler(e) {
// TODO: customize click handler
}
const annotationDropdown =
const menubarItems = [
{
label: projectDropdown,
key: '0',
},
{
label: videoDropdown,
key: '1',
},
{
label: annotationDropdown,
key: '2',
},
]
return (
Annotator
{/* If state info is null, InfoBar will only display predefined information for events. Otherwise, will display both predefined and contents of the info state */}
)
}
```
> [!NOTE]
> In order to process the video, you need to set up a backend server. We will cover this in another [repo](https://github.com/JaneliaSciComp/videoAnnotation_backend/tree/main).
Here we used react-bootstrap for the layout. Check out the [tutorial](https://react-bootstrap.netlify.app/docs/layout/grid), and also [Ant Design](https://ant.design/components)'s components.