Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
kieftrav committed Dec 3, 2024
1 parent 8b2a0d7 commit 99bf9c2
Show file tree
Hide file tree
Showing 11 changed files with 237 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Volumetric Task

The volumetric task is a task type designed for use with structured volumetric JSON, as part of an NIH neuron mapping project. The task is a drawing/click-oriented task that constructs volumetric annotation data based on the clicked point in 3D space.

The volumetric task requires subjects with a location of application/json mime type. The subject's location content is used to initialize the structured subject data to be annotated.

The volumetric task does not support a required property.

The volumetric task does not support tags (i.e. insertion, deletion).

The volumetric task is disabled until the subject's JSON content is loaded.
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { Box, Text } from 'grommet'
import { Blank } from 'grommet-icons'
import { observer } from 'mobx-react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import { Markdownz } from '@zooniverse/react-components'
import InputIcon from './../../../components/InputIcon'
import InputStatus from '../../../components/InputStatus'
import TaskInput from '../../../components/TaskInput'

const ToolIcon = ({ type }) => {
const arrow = '48 50, 48 15, 40 15, 50 0, 60 15, 52 15, 52 50'
return (
<Blank viewBox='0 0 100 100'>
<polygon points={arrow} fill='blue' transform='rotate(0 50 50)' />
<polygon points={arrow} fill='green' transform='rotate(135 50 50)' />
<polygon points={arrow} fill='red' transform='rotate(225 50 50)' />
</Blank>
)
}

const StyledText = styled(Text)`
margin: 0;
padding: 0;
width: 100%;
> *:first-child {
margin-top: 0;
}
`
function VolumetricTask(props) {
const { task } = props
const { setActiveTool } = task
function onChange(index, event) {
if (event.target.checked) {
setActiveTool(index)
}
}

const ANNOTATION_COUNT = 3

console.log('Volumetric Task', JSON.parse(JSON.stringify((task))))
console.log('task.tools', task.annotations)

return (
<Box>
<StyledText as='legend' size='small'>
<Markdownz>{task.instruction}</Markdownz>
</StyledText>

<ToolIcon type={'volumetric'} style={{ width: '100px', height: '100px' }} />

<TaskInput
checked={true}
disabled={false}
label={'3D Viewer'}
labelIcon={
<InputIcon
icon={<ToolIcon type={'volumetric'} />}
color={'white'}
/>
}
labelStatus={<InputStatus count={ANNOTATION_COUNT} />}

name='volumetric-tool'
required={task.required}
type='radio'
/>
</Box>
)
}

VolumetricTask.defaultProps = {
task: {}
}

VolumetricTask.propTypes = {
task: PropTypes.shape({
help: PropTypes.string,
instruction: PropTypes.string,
required: PropTypes.bool
})
}

export default observer(VolumetricTask)
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { MockTask } from '@stories/components'
import VolumetricTask from './VolumetricTask'

export default {
title: 'Tasks / Volumetric',
component: VolumetricTask,
args: {},
argTypes: {}
}

const tasks = {
T0: {
taskKey: 'T0',
type: 'volumetric'
}
}

export function Default () {
return (<MockTask tasks={tasks} />)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { default as TaskComponent } from './components/VolumetricTask'
import { default as TaskModel } from './models/VolumetricTask'
import { default as AnnotationModel } from './models/VolumetricAnnotation'

export default {
TaskComponent,
TaskModel,
AnnotationModel
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { types } from 'mobx-state-tree'
import Annotation from '../../../models/Annotation'

const Volumetric = types
.model('Volumetric', {
taskType: types.literal('volumetric'),
value: types.optional(types.string, ''),
})

const VolumetricAnnotation = types.compose('VolumetricAnnotation', Annotation, Volumetric)
export default VolumetricAnnotation
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import cuid from 'cuid'
import { types } from 'mobx-state-tree'
import Task from '../../../models/Task'
import VolumetricAnnotation from './VolumetricAnnotation'

const Volumetric = types.model('Volumetric', {
annotation: types.safeReference(VolumetricAnnotation),
type: types.literal('volumetric'),
})
.views(self => ({
defaultAnnotation (id = cuid()) {
return VolumetricAnnotation.create({
id,
task: self.taskKey,
taskType: self.type
})
}
}))

const VolumetricTask = types.compose('VolumetricTask', Task, Volumetric)

export default VolumetricTask
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import VolumetricTask from '@plugins/tasks/experimental/volumetric'

describe.only('Model > VolumetricTask', function () {
const volumetricTask = {
taskKey: 'T0',
type: 'volumetric'
}

const singleChoiceTask = {
answers: [
{ label: 'yes', next: 'S2' },
{ label: 'no', next: 'S3' }
],
strings: {
question: 'Do you exist?'
},
required: '',
taskKey: 'T1',
type: 'single'
}

it('should exist', function () {
const task = VolumetricTask.TaskModel.create(volumetricTask)
expect(task).to.be.ok()
expect(task).to.be.an('object')
})

it('should error for invalid tasks', function () {
let errorThrown = false
try {
VolumetricTask.TaskModel.create(singleChoiceTask)
} catch (e) {
errorThrown = true
}
expect(errorThrown).to.be.true()
})

describe('Views > defaultAnnotation', function () {
let task

before(function () {
task = VolumetricTask.TaskModel.create(volumetricTask)
})

it('should be a valid annotation', function () {
const annotation = task.defaultAnnotation()
expect(annotation.id).to.be.ok()
expect(annotation.task).to.equal('T0')
expect(annotation.taskType).to.equal('volumetric')
})

it('should generate unique annotations', function () {
const firstAnnotation = task.defaultAnnotation()
const secondAnnotation = task.defaultAnnotation()
expect(firstAnnotation.id).to.not.equal(secondAnnotation.id)
})
})

describe('with an annotation', function () {
let annotation
let task

before(function () {
task = VolumetricTask.TaskModel.create(volumetricTask)
annotation = task.defaultAnnotation()
})

it('should start up with an empty string', function () {
expect(annotation.value).to.equal('')
})

it('should update annotations', function () {
annotation.update('Hello there!')
expect(annotation.value).to.equal('Hello there!')
})
})
})
1 change: 1 addition & 0 deletions packages/lib-classifier/src/plugins/tasks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export { default as text } from './text'
export { default as highlighter } from './experimental/highlighter'
export { default as textFromSubject } from './experimental/textFromSubject'
export { default as transcription } from './experimental/transcription'
export { default as volumetric } from './experimental/volumetric'
2 changes: 1 addition & 1 deletion packages/lib-classifier/src/store/Project/Project.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const Project = types
},

get isVolumetricViewer() {
return self.experimental_tools.includes('volumetricViewer')
return self.experimental_tools.includes('volumetricProject')
},
}))

Expand Down

0 comments on commit 99bf9c2

Please sign in to comment.