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

Video annotation: Extending the Point Tool #2099

Merged
merged 37 commits into from
May 5, 2021
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
da24b67
Format changes via Prettier
ErikOstlund Mar 24, 2021
0a22a69
Removed unused import and variable
ErikOstlund Mar 24, 2021
3696e8c
Passing ‘played’ down
ErikOstlund Mar 29, 2021
81e743d
Moved getFixedNumber method to helper directory
ErikOstlund Mar 29, 2021
c2da488
Added video timeStamp to mark
ErikOstlund Mar 29, 2021
ee89378
Format changes via Prettier
ErikOstlund Mar 29, 2021
97934b1
Spin off TemporalPoint from Point
shaunanoordin Apr 1, 2021
6416712
Add missing TemporalPointTool mark
shaunanoordin Apr 1, 2021
5f95861
Trim down TemporalPoint models/marks to inherit from Point
shaunanoordin Apr 1, 2021
263cce0
Change temporalPointTool to inherit from PointTool instead of Tool
shaunanoordin Apr 1, 2021
589fee2
Add new default Mark.videoTime and Mark.setVideoTime
shaunanoordin Apr 1, 2021
383c673
Update Drawing Tools README to add videoTime info
shaunanoordin Apr 1, 2021
66d5ee6
ESlint/Prettier fixes per Zooniverse Style Guide
ErikOstlund Apr 2, 2021
81372a6
Added extra safe-guard for videoTime
ErikOstlund Apr 2, 2021
c12c720
ESlint/Prettier fixes per Zooniverse Style Guide
ErikOstlund Apr 2, 2021
a88dc76
Added the Point icon for the TemporalPoint tool
ErikOstlund Apr 6, 2021
39fdbec
Removed console.log
ErikOstlund Apr 12, 2021
8459550
Merge branch 'master' of github.com:zooniverse/front-end-monorepo int…
ErikOstlund Apr 12, 2021
4816091
Merge branch 'master' into video-annotation-timestamp
ErikOstlund Apr 13, 2021
8fbc850
Fixed ‘setVideoTime’ is not a function error
ErikOstlund Apr 19, 2021
2e9d261
Merge branch 'master' into video-annotation-timestamp
ErikOstlund Apr 19, 2021
22789ec
Merge branch 'master' into video-annotation-timestamp
ErikOstlund Apr 21, 2021
5fd5b29
Merge branch 'master' into video-annotation-timestamp
ErikOstlund Apr 22, 2021
ae61a23
Merge branch 'master' into video-annotation-timestamp
ErikOstlund Apr 22, 2021
6a622ea
Merge branch 'master' into video-annotation-timestamp
ErikOstlund Apr 23, 2021
fdc3958
Merge branch 'master' into video-annotation-timestamp
ErikOstlund Apr 26, 2021
ef3b7ab
Merge branch 'master' into video-annotation-timestamp
ErikOstlund Apr 26, 2021
1246aaf
Merge branch 'master' into video-annotation-timestamp
ErikOstlund Apr 28, 2021
f762994
Merge branch 'master' into video-annotation-timestamp
ErikOstlund Apr 28, 2021
d83a7c1
Merge branch 'master' into video-annotation-timestamp
ErikOstlund Apr 29, 2021
8500b62
Merge branch 'master' into video-annotation-timestamp
ErikOstlund May 4, 2021
0687896
Removed TemporalPoint component
ErikOstlund May 4, 2021
de552f6
Merge branch 'video-annotation-timestamp' of github.com:zooniverse/fr…
ErikOstlund May 4, 2021
5e14c70
Missed a few property names to update
ErikOstlund May 4, 2021
03d4280
Removed unused imports
ErikOstlund May 4, 2021
c3013cf
Merge branch 'master' into video-annotation-timestamp
ErikOstlund May 4, 2021
d204909
Merge branch 'master' into video-annotation-timestamp
ErikOstlund May 5, 2021
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 @@ -6,15 +6,20 @@ import SVGContext from '@plugins/drawingTools/shared/SVGContext'
import DrawingToolMarks from './components/DrawingToolMarks'
import TranscribedLines from './components/TranscribedLines'
import SubTaskPopup from './components/SubTaskPopup'
import getFixedNumber from '../../helpers/getFixedNumber'

const DrawingCanvas = styled('rect')`
${props => props.disabled ?
css`cursor: not-allowed;` :
css`cursor: crosshair;`
}
${(props) =>
props.disabled
? css`
cursor: not-allowed;
`
: css`
cursor: crosshair;
`}
`

function InteractionLayer ({
function InteractionLayer({
activeMark,
activeTool,
activeToolIndex,
Expand All @@ -25,18 +30,22 @@ function InteractionLayer ({
move,
setActiveMark,
scale,
width
width,
played
}) {
const [ creating, setCreating ] = React.useState(false)
const [creating, setCreating] = React.useState(false)
const { svg, getScreenCTM } = React.useContext(SVGContext)

useEffect(function onDeleteMark() {
if (creating && !activeMark) {
setCreating(false)
}
}, [activeMark])
useEffect(
function onDeleteMark() {
if (creating && !activeMark) {
setCreating(false)
}
},
[activeMark]
)

function convertEvent (event) {
function convertEvent(event) {
const type = event.type

const svgEventOffset = getEventOffset(event)
Expand All @@ -51,15 +60,17 @@ function InteractionLayer ({
return svgCoordinateEvent
}

function getEventOffset (event) {
function getEventOffset(event) {
const svgPoint = svg.createSVGPoint()
svgPoint.x = event.clientX
svgPoint.y = event.clientY
const svgEventOffset = svgPoint.matrixTransform(getScreenCTM().inverse())
return svgEventOffset
}

function createMark (event) {
function createMark(event) {
// TODO: add case for played = undefined
const timeStamp = getFixedNumber(played, 5)
const mark = activeTool.createMark({
id: cuid(),
frame,
Expand All @@ -70,21 +81,24 @@ function InteractionLayer ({
setActiveMark(mark)
setCreating(true)
mark.setSubTaskVisibility(false)
// Add a time value for tools that care about time. For most tools, this value is ignored.
mark.setVideoTime(timeStamp)
}

function onPointerDown (event) {
function onPointerDown(event) {
if (disabled || move) {
return true
}
const { target, pointerId } = event
target.setPointerCapture(pointerId)

if (!activeTool.type) {
return false;
return false
}

if (creating) {
activeTool.handlePointerDown && activeTool.handlePointerDown(convertEvent(event), activeMark)
activeTool.handlePointerDown &&
activeTool.handlePointerDown(convertEvent(event), activeMark)
if (activeMark.finished) onFinish(event)
return true
}
Expand All @@ -93,13 +107,14 @@ function InteractionLayer ({
return false
}

function onPointerMove (event) {
function onPointerMove(event) {
if (creating) {
activeTool.handlePointerMove && activeTool.handlePointerMove(convertEvent(event), activeMark)
activeTool.handlePointerMove &&
activeTool.handlePointerMove(convertEvent(event), activeMark)
}
}

function onFinish (event) {
function onFinish(event) {
if (event.preventDefault) event.preventDefault()
setCreating(false)
if (activeMark && !activeMark.isValid) {
Expand All @@ -110,12 +125,13 @@ function InteractionLayer ({

function onPointerUp(event) {
if (creating) {
activeTool.handlePointerUp && activeTool.handlePointerUp(convertEvent(event), activeMark)
activeTool.handlePointerUp &&
activeTool.handlePointerUp(convertEvent(event), activeMark)
if (activeMark.finished) onFinish(event)
}
}

function inactivateMark () {
function inactivateMark() {
setActiveMark(undefined)
}

Expand All @@ -131,24 +147,21 @@ function InteractionLayer ({
onPointerMove={onPointerMove}
onPointerUp={onPointerUp}
/>
<TranscribedLines
scale={scale}
/>
<SubTaskPopup
onDelete={inactivateMark}
/>
{marks &&
<TranscribedLines scale={scale} />
<SubTaskPopup onDelete={inactivateMark} />
{marks && (
<DrawingToolMarks
activeMark={activeMark}
marks={marks}
onDelete={inactivateMark}
onDeselectMark={inactivateMark}
onFinish={onFinish}
onSelectMark={mark => setActiveMark(mark)}
onSelectMark={(mark) => setActiveMark(mark)}
onMove={(mark, difference) => mark.move(difference)}
scale={scale}
played={played}
/>
}
)}
</g>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import InteractionLayer, { DrawingCanvas } from './InteractionLayer'
import TranscribedLines from './components/TranscribedLines'
import SubTaskPopup from './components/SubTaskPopup'
import DrawingTask from '@plugins/tasks/DrawingTask'
import { Line, Point, TranscriptionLine } from '@plugins/drawingTools/components'
import {
Line,
Point,
TranscriptionLine
} from '@plugins/drawingTools/components'

describe('Component > InteractionLayer', function () {
let wrapper
Expand All @@ -17,7 +21,8 @@ describe('Component > InteractionLayer', function () {
initialDrag: sinon.stub(),
initialPosition: sinon.stub(),
setCoordinates: sinon.stub(),
setSubTaskVisibility: sinon.stub()
setSubTaskVisibility: sinon.stub(),
setVideoTime: sinon.stub()
}
const mockSVGPoint = {
x: 100,
Expand Down Expand Up @@ -112,7 +117,9 @@ describe('Component > InteractionLayer', function () {
describe('onPointerDown', function () {
let mockedContext
before(function () {
mockedContext = sinon.stub(React, 'useContext').callsFake(() => { return { svg, getScreenCTM } })
mockedContext = sinon.stub(React, 'useContext').callsFake(() => {
return { svg, getScreenCTM }
})
})

after(function () {
Expand Down Expand Up @@ -184,7 +191,9 @@ describe('Component > InteractionLayer', function () {
}
wrapper.find(DrawingCanvas).simulate('pointerdown', fakeEvent)
wrapper.simulate('pointermove', fakeEvent)
expect(fakeEvent.target.setPointerCapture.withArgs('fakePointer')).to.have.been.calledOnce()
expect(
fakeEvent.target.setPointerCapture.withArgs('fakePointer')
).to.have.been.calledOnce()
})

describe('with a TranscriptionLine mark already in progress', function () {
Expand All @@ -205,7 +214,9 @@ describe('Component > InteractionLayer', function () {
})
activeTool = mockDrawingTask.activeTool
sinon.stub(activeTool, 'createMark').callsFake(() => mockMark)
sinon.stub(activeTool, 'handlePointerDown').callsFake(() => mockMark)
sinon
.stub(activeTool, 'handlePointerDown')
.callsFake(() => mockMark)

wrapper = shallow(
<InteractionLayer
Expand Down Expand Up @@ -236,7 +247,9 @@ describe('Component > InteractionLayer', function () {
describe('onPointerUp', function () {
let mockedContext
before(function () {
mockedContext = sinon.stub(React, 'useContext').callsFake(() => { return { svg, getScreenCTM } })
mockedContext = sinon.stub(React, 'useContext').callsFake(() => {
return { svg, getScreenCTM }
})
})

after(function () {
Expand Down Expand Up @@ -284,12 +297,13 @@ describe('Component > InteractionLayer', function () {
sinon.stub(activeTool, 'createMark').callsFake(() => mockMark)
activeTool.createMark.resetHistory()
wrapper = shallow(
<InteractionLayer
activeTool={activeTool}
disabled
height={400}
width={600}
/>, {
<InteractionLayer
activeTool={activeTool}
disabled
height={400}
width={600}
/>,
{
wrappingComponent: SVGContext.Provider,
wrappingComponentProps: { value: { svg, getScreenCTM } }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
import { inject, observer } from 'mobx-react'
import { getType } from 'mobx-state-tree'
import PropTypes from 'prop-types'
import React, { Component } from 'react'

import InteractionLayer from './InteractionLayer'
import PreviousMarks from './components/PreviousMarks'
import SHOWN_MARKS from '@helpers/shownMarks'

function storeMapper (stores) {
const {
activeStepTasks
} = stores.classifierStore.workflowSteps
const {
frame,
move
} = stores.classifierStore.subjectViewer
const {
active: classification
} = stores.classifierStore.classifications
function storeMapper(stores) {
const { activeStepTasks } = stores.classifierStore.workflowSteps
const { frame, move } = stores.classifierStore.subjectViewer

const [activeInteractionTask] = activeStepTasks.filter(task => task.type === 'drawing' || task.type === 'transcription')
const [activeInteractionTask] = activeStepTasks.filter(
(task) => task.type === 'drawing' || task.type === 'transcription'
)

return {
activeInteractionTask,
Expand All @@ -31,14 +24,15 @@ function storeMapper (stores) {
@inject(storeMapper)
@observer
class InteractionLayerContainer extends Component {
render () {
render() {
const {
activeInteractionTask,
frame,
height,
move,
scale,
width
width,
played
} = this.props

const {
Expand All @@ -52,12 +46,15 @@ class InteractionLayerContainer extends Component {
taskKey
} = activeInteractionTask

const newMarks = shownMarks === SHOWN_MARKS.NONE ? marks.slice(hidingIndex) : marks
const visibleMarksPerFrame = newMarks?.filter(mark => mark.frame === frame)
const newMarks =
shownMarks === SHOWN_MARKS.NONE ? marks.slice(hidingIndex) : marks
const visibleMarksPerFrame = newMarks?.filter(
(mark) => mark.frame === frame
)

return (
<>
{activeInteractionTask && activeTool &&
{activeInteractionTask && activeTool && (
<InteractionLayer
activeMark={activeMark}
activeTool={activeTool}
Expand All @@ -69,10 +66,11 @@ class InteractionLayerContainer extends Component {
marks={visibleMarksPerFrame}
move={move}
scale={scale}
played={played}
setActiveMark={setActiveMark}
width={width}
/>
}
)}
<PreviousMarks scale={scale} />
</>
)
Expand All @@ -96,6 +94,7 @@ InteractionLayerContainer.wrappedComponent.propTypes = {
interactionTaskAnnotations: PropTypes.array,
move: PropTypes.bool,
scale: PropTypes.number,
played: PropTypes.number,
width: PropTypes.number.isRequired
}

Expand All @@ -114,7 +113,8 @@ InteractionLayerContainer.wrappedComponent.defaultProps = {
frame: 0,
interactionTaskAnnotations: [],
move: false,
scale: 1
scale: 1,
played: undefined // used for tracking video progress from 0 - 1. if undefined, subject is not a video
}

export default InteractionLayerContainer
Loading