Skip to content

Commit

Permalink
Update README, add comments
Browse files Browse the repository at this point in the history
  • Loading branch information
rileyt-ohsu committed Jun 29, 2018
1 parent 1e8a1a7 commit 26169c8
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 37 deletions.
198 changes: 176 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,186 @@
The first component is the ImageRecognition component. This component takes an array of image links and shuffle them into a grid. When this grid is done displaying, it calls a function in the componentWillUnmount() function that returns a timestamp, the time displayed, the correct image name, the correct image coordinate in the grid, and the 2D array of the image links. (empty strings indicate no image at that box).
# ORCATECH Image Recognition Test

The second component is ImageRecognitionQuestion. This component takes the correct image name, coordinate, and image links grid from the first component. This component will display a grid and an image prompt. The user can select a box in the grid. Every time the user selects a box, the selection handler will be called with data on the click. This function's data will include the timestamp, whether it was a selection or deselection, the selected coordinate, the image at the coordinate if there is any, and whether the answer is correct or incorrect. When the component is about to be unmounted, a function is called that has data on the timestamp, an array of the user box selection history, the correct image name, the correct image coordinate, the image links grid, and whether the user correctly answered the question based on the last user selection.
[![Build Status](https://travis-ci.org/orcatechteam/react-neuropsych-imgrecog.svg?branch=v0.0.1)](https://travis-ci.org/orcatechteam/react-neuropsych-imgrecog)

index.js
This just tests the two components, it first displays the first component for some time, and the unmounts it and displays the second question.
This repository holds a set of react components for administering and collecting data from an image recognition test. The test is performed by showing the user a grid of images, have them perform a different task, then show them the same grid without the images and ask where a particular image was.

## Components

**Image Recognition Props**
There are two main components for this test: Display and Question.

### Display

| Name | Type | Description|
| ------------- | ------------- | ------------- |
| dimension | Int | The dimensions of the grid. (4x4, 5x5, etc...) |
| images | Array | An array of the names of the images that will be displayed in the grid. This array does not need to be as large as the total number of boxes in the grid because the additional boxes will just be empty spaces. However, the length of this array must be less than or equal to the number of boxes in the grid. |
| showLabels | Boolean | Whether you would like the grid to have the labels for the rows and columns |
| onComplete | Function | Callback that is called right before the component is unmounted. It is passed a data object with these properties: </br>**timeDisplayed**: the time the component was displayed for</br>**correctImgName**: the name of the image the user will be asked about later</br>**correctCoordinate**: the coordinates of the correctImgName (ex: B4)</br>**imageLinksGrid**: A 2D array representation of the grid that was displayed to the user. Empty strings are boxes where no image was displayed.</br>**timestamp**: A timestamp |
This component takes an array of image links and shuffles them into a grid. When this grid is done displaying, it calls the onComplete handler in the componentWillUnmount() lifecycle with a data object outlined below.

**Props**

**Image Recognition Question Props**
| Name | Type | Description |
| ------------- | -------- | --------------------------------------------------------------------------- |
| dimension | Int | The dimensions of the grid. (4x4, 5x5, etc...) |
| images | Array | An array of the names of the images that will be displayed in the grid. This array does not need to be as large as the total number of boxes in the grid because the additional boxes will just be empty spaces. However, the length of this array must be less than or equal to the number of boxes in the grid. |
| showLabels | Boolean | Whether you would like the grid to have the labels for the rows and columns |
| onComplete | Function | Callback that is called with the data object right before the component is unmounted |

### Question

| Name | Type | Description |
| ------------- | ------------- | ------------- |
| dimension | Int | The dimensions of the grid. (4x4, 5x5, etc...) |
| images | Array | An array of the names of the images that will be displayed in the grid. This array does not need to be as large as the total number of boxes in the grid because the additional boxes will just be empty spaces. However, the length of this array must be less than or equal to the number of boxes in the grid. |
| showLabels | Boolean | Whether you would like the grid to have the labels for the rows and columns |
| correctImgName | String | The name of the image the user will be asked to find in the grid |
| correctCoordinate | String | The coordinate of the `correctImgName`|
| imageLinksGrid | Array | 2D array representation of the grid that was displayed to the user in the previous component. |
| onSelect | Function | Callback for everytime the user selects a box. It is passed the data with these properties <br/>**timestamp**: A timestamp <br/>**coordinate**: The coordinate of the selected box <br/>**image**: The image at the coordinate if there is any</br>**action**: Whether this was a selection of deselection <br/>**status**: Whether the selection is correct or incorrect<br/> |
| onComplete | Function | Callback called right before the component is unmounted. The data passed includes these properties: <br/>**timestamp**: A timestamp<br/>**clicks**: An array of the all the users box selections. Each object in the array is in the same format as the data passed in the `onComplete` callback.<br/>**correctImgName**: The name of the image the user will be asked to find in the grid.</br>**correctCoordinate**: The coordinate of the `correctImgName`</br>**imageLinksGrid**: 2D array representation of the grid that was displayed to the user in the previous component.</br>**status**: Whether the selection is correct or incorrect
This component takes a data object from the first component to display a grid with an image prompt. The user can then select a box in the grid. Every time the user selects a box, the onSelect handler will be called with an updated data object. When the component is about to be unmounted the onComplete handler is collect with the final data object.

**Props**

| Name | Type | Description |
| ---------- | ---------| --------------------------------------------------------------------------- |
| data | Data | The data object from the onComplete handler of the Display component |
| showLabels | Boolean | Whether you would like the grid to have the labels for the rows and columns |
| onSelect | Function | Callback called with data object everytime the user selects a box. |
| onComplete | Function | Callback called with data object right before the component is unmounted. |

## Data

### Data

This is the top level data object returned from the Display component and received by all onComplete and onSelect handlers

```javascript

class Data {

// A unix timestamp representing when the display component was mounted
displayStart = undefined;

// A unix timestamp representing when the display component was unmounted
displayStop = undefined;

// A unix timestamp representing when the question component was mounted
questionStart = undefined;

// A unix timestamp representing when the question component was unmounted
questionStop = undefined;

// the correct coordinate
coord = undefined;

// the currently selected coordinate
selected = undefined;

// True is they selected the correct coordinate
// False if they selected the wrong coordinate
// Undefined if a selection has not been made
correct = undefined;

// a grid of Coordinate objects
//
// from display this is a 2D array of NxN dimensions where N is the dimension
// property given to the display component
//
// from questions the 2D array is flattened into an array of size N*N
grid = new Array();

// a list of selections made by the user when they were given an empty grid.
selections = [];
}
```

### Coordinate

This represents a box in the grid. A Coordinate has a row and column position as well as the image displayed at it's position. Coordinate positions are relative to an origin in the upper left hand corner of the grid.

```javascript
// Coordinate is a coordinate within a 2D grid and optionally contains an image.
// The point of origin for the grid is the upper left hand corner
class Coordinate {
// The row number this coordinate resides in
row = undefined;

// The column number this coordinate resides in
col = undefined;

// An optional image associated with this coordinate. This will be the image
// file name or an empty string
img = undefined;
}
```

### Selection

This represents a Coordinate selection made by the user in the Question component

```javascript
{
// the time in which the selection was made as a unix timestamp
stamp: (new Date()).getTime(),

// the coordinate selected by the user
pickedCoord: this.props.data.selected,

// the correct coordinate (images matches the prompt)
correctCoord: this.props.data.coord,

// True if pickedCoord === correctCoord, false otherwise
correct: this.props.data.correct
}
```

## Testing

To test the functionality, run:

```sh
make build && make serve
```

and an example test will be hosted at http://localhost:8081/index.html. The page will displays the first component for a short period then unmounts it and displays the second question.

## Example

This example displays the first component for 5 seconds and then shows the second component. When testing you will want the user to perform an intermediate task to prevent them from keeping the cursor in the same position.

```javascript
import React from 'react';
import ReactDOM from 'react-dom';
import { Question, Display } from '@orcatech/react-neuropsych-imgrecog';

const images = [
'large_black_triangle.png',
'large_green_triangle.png',
'large_red_triangle.png',
'large_grey_triangle.png',
'small_blue_triangle.png',
'small_orange_triangle.png',
'small_purple_triangle.png'
],
dimension = 4,
timeout = 5000,
display = document.getElementById('display'),
question = document.getElementById('question');

// handler for when the user clicks on a box in the question component
let handleQuestionSelect = (data) => {
console.log(data);
}

// handler for when the question component is unmounted
let handleQuestionComplete = (data) => {
console.log(data);
}

// handler for when the display component is unmounted
let handleDisplayComplete = (data) => {
console.log(data);
ReactDOM.render(
<Question
showLabels={true}
data={data}
onComplete={handleQuestionComplete}
onSelect={handleQuestionSelect}/>, question);
}

ReactDOM.render(
<Display
showLabels={false}
dimension={dimension}
images={images}
onComplete={handleDisplayComplete}/>, display);

// stop displaying the first component after 5 seconds
setTimeout(() => { ReactDOM.unmountComponentAtNode(display) }, timeout);
```
35 changes: 21 additions & 14 deletions src/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,31 +16,38 @@ const shuffle = (inputArray) => {

export default class Data {

// the time the grid was first display with images
displayStart = 0
// A unix timestamp representing when the display component was mounted
displayStart = undefined;

// the time the grid with images was removed
displayStop = 0
// A unix timestamp representing when the display component was unmounted
displayStop = undefined;

// the time when the empty grid was shown
questionStart = 0
// A unix timestamp representing when the question component was mounted
questionStart = undefined;

// the time when the final selection was made
questionStop = 0
// A unix timestamp representing when the question component was unmounted
questionStop = undefined;

// the correct coordinate
coord = undefined;

// the selected cooordinate
selected = undefined
// the currently selected coordinate
selected = undefined;

// if they selected the correct coord
// True is they selected the correct coordinate
// False if they selected the wrong coordinate
// Undefined if a selection has not been made
correct = undefined;

// a 2D grid of coordinates to image links
// a grid of Coordinate objects
//
// from display this is a 2D array of NxN dimensions where N is the dimension
// property given to the display component
//
// from questions the 2D array is flattened into an array of size N*N
grid = new Array();

// a list of selections made by the user when they were given an empty grid
// a list of selections made by the user when they were given an empty grid.
selections = [];

constructor(images, dimension) {
Expand Down Expand Up @@ -75,4 +82,4 @@ export default class Data {

console.log('Correct: (row: ' + this.coord.row + ', col: ' + this.coord.col + ', img: ' + this.coord.img + ')');
}
}
}
15 changes: 14 additions & 1 deletion src/grid-coord.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
// Coordinate is a coordinate within a 2D grid and optionally contains an image.
// The point of origin for the grid is the upper left hand corner
export default class Coord {

// The row number this coordinate resides in
row = undefined;

// The column number this coordinate resides in
col = undefined;

// An optional image associated with this coordinate. This will be the image
// file name or an empty string
img = undefined;

constructor(col, row, img) {
this.col = col;
this.row = row;
Expand All @@ -8,4 +21,4 @@ export default class Coord {
key() {
return this.col + "," + this.row;
}
}
}

0 comments on commit 26169c8

Please sign in to comment.