Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(classifier): automatically sync drawing annotations #5923

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,6 @@ function InteractionLayer({
mark.setSubTaskVisibility(false)
// Add a time value for tools that care about time. For most tools, this value is ignored.
mark.setVideoTime(timeStamp, duration)
const markIDs = annotation.value?.map((mark) => mark.id)
annotation.update([...markIDs, mark.id])
}

function onPointerDown(event) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getRoot, getSnapshot, resolveIdentifier, types } from 'mobx-state-tree'
import { autorun } from 'mobx'
import { addDisposer, getRoot, getSnapshot, resolveIdentifier, types } from 'mobx-state-tree'
import DrawingTask from './DrawingTask'
import Annotation from '../../models/Annotation'
import * as markTypes from '@plugins/drawingTools/models/marks'
Expand All @@ -11,33 +12,55 @@ const Drawing = types.model('Drawing', {
value: types.array(types.safeReference(GenericMark))
})
.views(self => ({
toSnapshot () {
/**
Resolve `annotation.task`, which is a task key, to its corresponding task object.
*/
get actualTask() {
return resolveIdentifier(DrawingTask, getRoot(self), self.task)
},

/**
Generate a snapshot in the format expected by Panoptes, Caesar etc.
See ADR 25.
https://github.com/zooniverse/front-end-monorepo/blob/master/docs/arch/adr-25.md
*/
toSnapshot() {
const snapshot = getSnapshot(self)
// resolve mark references (IDs) in the snapshot to mark snapshots
const actualTask = resolveIdentifier(DrawingTask, getRoot(self), self.task)
const value = actualTask.marks.map(mark => getSnapshot(mark))
const drawingSnapshot = Object.assign({}, snapshot, { value })
// flatten subtask annotations into a single annotations array
// then return the flattened array
// Replace mark references (IDs) with mark snapshots.
const markSnapshots = self.value.map(mark => getSnapshot(mark))
const drawingSnapshot = { ...snapshot, value: markSnapshots }
// Flatten subtask annotations into a single annotations array
// then return the flattened array.
const drawingAnnotations = [drawingSnapshot]
drawingSnapshot.value.forEach((markSnapshot, markIndex) => {
const mark = Object.assign({}, markSnapshot)
// map subtask keys to mark.details
markSnapshots.forEach((markSnapshot, markIndex) => {
const mark = { ...markSnapshot }
// `mark.details` is an array of subtask keys.
mark.details = mark.annotations.map(annotation => ({ task: annotation.task }))
// push mark.annotations to the returned array
// Push mark subtask annotations to the returned array.
mark.annotations.forEach(markAnnotation => {
const finalAnnotation = Object.assign({}, markAnnotation, { markIndex })
// strip annotation IDs
const { id, ...rest } = finalAnnotation
drawingAnnotations.push(rest)
// Strip annotation IDs and add markIndex.
const { id, ...rest } = markAnnotation
const finalAnnotation = { ...rest, markIndex }
drawingAnnotations.push(finalAnnotation)
})
// remove annotations from individual marks
// Remove annotations from individual marks.
const { annotations, ...rest } = mark
drawingSnapshot.value[markIndex] = rest
})
return drawingAnnotations
}
}))
.actions(self => ({
afterAttach() {
function _onMarksChange() {
// A drawing annotation stores an array of mark IDs for the corresponding task.
const newValue = self.actualTask.marks.map(mark => mark.id)
self.update(newValue)
}

addDisposer(self, autorun(_onMarksChange))
}
}))

const DrawingAnnotation = types.compose('DrawingAnnotation', Annotation, Drawing)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ describe('Model > DrawingAnnotation', function () {
})
const point2 = pointTool.createMark({
x: 150,
y: 200
y: 200,
frame: 1
})
const questionTask = pointTool.tasks[0]
point1.addAnnotation(questionTask, 0)
Expand Down Expand Up @@ -181,7 +182,7 @@ describe('Model > DrawingAnnotation', function () {
}
const point2Snapshot = {
details: [{ task: 'T0.0.0' }],
frame: 0,
frame: 1,
toolIndex: 0,
toolType: 'point',
x: 150,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { getRoot, getSnapshot, resolveIdentifier, types } from 'mobx-state-tree'
import { autorun } from 'mobx'
import { addDisposer, getRoot, getSnapshot, resolveIdentifier, types } from 'mobx-state-tree'
import TranscriptionTask from './TranscriptionTask'
import { TranscriptionLine } from '@plugins/drawingTools/models/marks'
import Annotation from '../../../models/Annotation'
Expand All @@ -8,35 +9,55 @@ const Transcription = types.model('Transcription', {
value: types.array(types.safeReference(TranscriptionLine))
})
.views(self => ({
// This is a copy of DrawingAnnotation's toSnapshot with the exception of
// Changing the task type to TranscriptionTask
/**
Resolve `annotation.task`, which is a task key, to its corresponding task object.
*/
get actualTask() {
return resolveIdentifier(TranscriptionTask, getRoot(self), self.task)
},

/**
Generate a snapshot in the format expected by Panoptes, Caesar etc.
See ADR 25.
https://github.com/zooniverse/front-end-monorepo/blob/master/docs/arch/adr-25.md
*/
toSnapshot() {
const snapshot = getSnapshot(self)
// resolve mark references (IDs) in the snapshot to mark snapshots
const actualTask = resolveIdentifier(TranscriptionTask, getRoot(self), self.task)
const value = actualTask.marks.map(mark => getSnapshot(mark))
const drawingSnapshot = Object.assign({}, snapshot, { value })
// flatten subtask annotations into a single annotations array
// then return the flattened array
// Replace mark references (IDs) with mark snapshots.
const markSnapshots = self.value.map(mark => getSnapshot(mark))
const drawingSnapshot = { ...snapshot, value: markSnapshots }
// Flatten subtask annotations into a single annotations array
// then return the flattened array.
const drawingAnnotations = [drawingSnapshot]
drawingSnapshot.value.forEach((markSnapshot, markIndex) => {
const mark = Object.assign({}, markSnapshot)
// map subtask keys to mark.details
markSnapshots.forEach((markSnapshot, markIndex) => {
const mark = { ...markSnapshot }
// `mark.details` is an array of subtask keys.
mark.details = mark.annotations.map(annotation => ({ task: annotation.task }))
// push mark.annotations to the returned array
// Push mark subtask annotations to the returned array.
mark.annotations.forEach(markAnnotation => {
const finalAnnotation = Object.assign({}, markAnnotation, { markIndex })
// strip annotation IDs
const { id, ...rest } = finalAnnotation
drawingAnnotations.push(rest)
// Strip annotation IDs and add markIndex.
const { id, ...rest } = markAnnotation
const finalAnnotation = { ...rest, markIndex }
drawingAnnotations.push(finalAnnotation)
})
// remove annotations from individual marks
// Remove annotations from individual marks.
const { annotations, ...rest } = mark
drawingSnapshot.value[markIndex] = rest
})
return drawingAnnotations
}
}))
.actions(self => ({
afterAttach() {
function _onMarksChange() {
// A drawing annotation stores an array of mark IDs for the corresponding task.
const newValue = self.actualTask.marks.map(mark => mark.id)
self.update(newValue)
}

addDisposer(self, autorun(_onMarksChange))
}
}))

const TranscriptionAnnotation = types.compose('TranscriptionAnnotation', Annotation, Transcription)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ describe('Model > TranscriptionAnnotation', function () {
x1: 150,
x2: 175,
y1: 200,
y2: 238
y2: 238,
frame: 1
})
const textTask = transcriptionLineTool.tasks[0]
transcriptionLine1.addAnnotation(textTask, 'foo')
Expand Down Expand Up @@ -137,7 +138,7 @@ describe('Model > TranscriptionAnnotation', function () {
}
const transcriptionLine2Snapshot = {
details: [{ task: 'T0.0.0' }],
frame: 0,
frame: 1,
toolIndex: 0,
toolType: 'transcriptionLine',
x1: 150,
Expand Down