Skip to main content
caution

This section refers to the old versions of the MonkJs SDK (version 3.X.X and below). For the v4 docs, please refer to this page.

Capture

Interface guiding user in a 360° vehicle capture coverage.

npm latest package

yarn add @monkvision/corejs @monkvision/sights @monkvision/toolkit @monkvision/camera
import { Capture } from '@monkvision/camera';

This package is also using the compression JPEG encoder libjpeg-turbo compiled on WebAssembly binary. It is necessary to download this wasm binary to make this package work, then move it to the static folder of your project, for ReactJs it is the public folder and for expo, you will have to create a web folder from the root of the project. It is a temporary solution until we can host it.

Basic usage

Here is an example of uploading one image to an inspection on the browser with the task damage_detection set.

import React, { useCallback, useState } from 'react';
import { Capture, Controls, Constants } from '@monkvision/camera';
import { SafeAreaView, StatusBar } from 'react-native';

export default function Inspector({ inspectionId }) {
const [loading, setLoading] = useState();

const controls = [{
disabled: loading,
...Controls.CaptureButtonProps,
}];

return (
<View>
<CssBaseline />
<Capture
mapTasksToSights={mapTasksToSights}
inspectionId={id}
controls={controls}
loading={loading}
onReady={() => setLoading(false)}
onStartUploadPicture={() => setLoading(true)}
onFinishUploadPicture={() => setLoading(false)}
onChange={handleChange}
sightIds={Constants.defaultSightIds}
/>
</View>
);
}

Calling mediaDevices.getUserMedia()

On iOS, calling mediaDevices.getUserMedia() to get a video stream causes previous streams created this way to be closed, and since this package gets its camera preview from this method, if this mediaDevices.getUserMedia() is called another time after Monk's stream has been created, the camera preview will not be able to be rendered.

Monk's camera package contains a safeguard that should restart the stream if it has been closed previously, but this behavior is to be avoided if possible. This is why we recommended avoiding calling mediaDevices.getUserMedia() after the Camera component is rendered.

Using the Zoomed Picture button

Here is an example on how to include the "Zoomed Picture Button" in your layout in order to activate the Zoomed Pictures features in the Capture workflow.

import React, { useCallback, useState } from 'react';
import { SafeAreaView, StatusBar } from 'react-native';
import { Capture, Controls, Constants } from '@monkvision/camera';

export default function Inspector({ inspectionId }) {
const [loading, setLoading] = useState();

const controls = [[ // Note the double array here, it allows us to create a group of controls
{ disabled: cameraLoading, ...Controls.AddDamageButtonProps },
{ disabled: cameraLoading, ...Controls.CaptureButtonProps },
]];

return (
<View>
<CssBaseline />
<Capture
mapTasksToSights={mapTasksToSights}
inspectionId={id}
controls={controls}
loading={loading}
onReady={() => setLoading(false)}
onStartUploadPicture={() => setLoading(true)}
onFinishUploadPicture={() => setLoading(false)}
onChange={handleChange}
sightIds={Constants.defaultSightIds}
/>
</View>
);
}

Props

The Capture component is based on 4 principal states uploads, compliance, sights and settings, and can be used as a controlled component by providing these states as props (optional), see the format in the state section

ref

By passing a ref to the Capture component, we can access a set of methods, including the camera element, see the api section.

  const captureRef = useRef();
console.log(captureRef.current);
// { camera, checkComplianceAsync, createDamageDetectionAsync, setPictureAsync, startUploadAsync, takePictureAync, goNextSigh, goPrevSight }

<Capture ref={captureRef} {...otherProps} />

controls

PropTypes.arrayOf(PropTypes.oneOfType([
PropTypes.shape({
component: PropTypes.element,
disabled: PropTypes.bool,
onCustomTakePicture: PropTypes.func,
onPress: PropTypes.func,
}),
PropTypes.arrayOf(PropTypes.shape({
component: PropTypes.element,
disabled: PropTypes.bool,
onCustomTakePicture: PropTypes.func,
onPress: PropTypes.func,
})),
]))

An array of either :

  • control elements
  • arrays of control elements

If given a control element, the control element will be rendered in its own control group. If given an array of control elements, the control elements will be rendered in the same control group.

If given an onCustomTakePicture method, it will bypass the built-in capture handler and simply take a picture for you

If given an onPress method, it will bypass the built-in capture handler and the optional onCustomTakePicture method

const controls = [{
disabled: loading,
onPress: handleCapture,
...Controls.CaptureButtonProps,
}];

additionalPictures

PropTypes.shape({
dispatch: PropTypes.func.isRequired,
name: PropTypes.string.isRequired,
state: PropTypes.shape({
takenPictures: PropTypes.arrayOf(PropTypes.shape({
labelKey: PropTypes.string.isRequired,
picture: PropTypes.any,
previousSight: PropTypes.string.isRequired,
})),
}).isRequired,
}).isRequired

Additional pictures to be send along with the default taken sights

compliance

PropTypes.shape({
dispatch: PropTypes.func,
name: PropTypes.string,
state: PropTypes.objectOf(PropTypes.shape({
error: PropTypes.objectOf(PropTypes.any),
id: PropTypes.string,
imageId: PropTypes.string,
requestCount: PropTypes.number,
result: PropTypes.objectOf(PropTypes.any),
status: PropTypes.string,
})),
}).isRequired

compressionOptions

PropTypes.shape({
quality: PropTypes.number,
})

enableCarCoverage

PropTypes.bool

enableComplianceCheck

PropTypes.bool

it will enables the compliance checking on captured images of sights.

enableCompression

PropTypes.bool

it will enables the compression on captured images of sights.

isFocused

PropTypes.bool

offline

PropTypes.objectOf(PropTypes.any)

onComplianceChange

PropTypes.func

const handleOnComplianceChange = () => console.log('Picture quality check has changed');

onPictureTaken

PropTypes.func

const handleOnPictureTaken = () => console.log('Picture has been taken');

onPictureUploaded

PropTypes.func

const handleOnPictureUploaded = () => console.log('Picture has been uploaded');

onSightsChange

PropTypes.func

const handleOnSightsChange = () => console.log('Sights has been uploaded');

onUploadsChange

PropTypes.func

const handleOnUploadsChange = () => console.log('Uploads has been changed');

onWarningMessage

PropTypes.func

const handleOnWarningMessage = () => console.log('Warning messages');

onCaptureClose

PropTypes.func

const handleOnCaptureClose = () => console.log('Capture Closed');

onSettingsChange

PropTypes.func

const handleOnSettingsChange = () => console.log('Settings has been changed');

PropTypes.element

A rendered element to be display has footer of the Sights scroll list

fullscreen

PropTypes.objectOf(PropTypes.any)

Props inherited from Button

enableQHDWhenSupported

PropTypes.bool

Automatically enable QHD resolution, by default it's true (for web only).

initialState

PropTypes.state

PropTypes.shape({
compliance: PropTypes.objectOf(PropTypes.any),
settings: PropTypes.objectOf(PropTypes.any),
sights: PropTypes.objectOf(PropTypes.any),
uploads: PropTypes.objectOf(PropTypes.any),
})

InitialState to begin with. Very useful if you persist the state on each change from onChange callback. See the state section for more details.

resolutionOptions

PropTypes.shape({
QHDDelay: PropTypes.number,
})

vehicleType

PropTypes.oneOf([
'suv',
'cuv',
'sedan',
'hatchback',
'van',
'minivan',
'pickup',
])

List of possible types of vehicles for capture tour inspection.

selectedMode

PropTypes.string

It's unique value for type of the operation which we want to execute.

inspectionId

PropTypes.string

ID of an inspection if you want to use component's API like startUploadAsync.

loading

PropTypes.bool

A boolean showing an ActivityIndicator and disabling controls if true

isSubmitting

PropTypes.bool

A boolean disabling the submit button if true, inside Upload Center (picture quality check screen).

PropTypes.shape({
allowNavigate: PropTypes.bool,
allowRetake: PropTypes.bool,
allowSkip: PropTypes.bool,
allowSkipImageQualityCheck: PropTypes.bool,
retakeMaxTry: PropTypes.number,
retakeMinTry: PropTypes.number,
})

allowNavigate

PropTypes.bool

A boolean allowing user to navigate between sight. Default value is false.

allowRetake

PropTypes.bool

A boolean allowing user to retake a picture if not compliant. Default value uis true.

allowSkip

PropTypes.bool

A boolean allowing user to skip a sight if he is not capable of taking it. Default value is false.

allowSkipImageQualityCheck

PropTypes.bool

A boolean allowing user to skip the compliance check (image quality check). Default value is true.

retakeMaxTry

PropTypes.number

A number setting the max limit of retake tries. Default value is 1.

retakeMinTry

PropTypes.number

A number setting the min limit of retake tries. Default value is 1.

Current scenario is user has to retake at least 1 (retakeMinTry) picture, but can retake only 1 (retakeMaxTry) before being redirected to the next stage, only if picture is not compliant to Image Quality Check or Car 360° coverage.

onChange

PropTypes.func

Will call a function when the Component state has changed.

const handleChange = (state, api) => console.log(state);

onReady

PropTypes.func

Will call a function when the Component camera is ready to be used.

const handleReady = (state, api) => console.log(state);

onCaptureTourStart

PropTypes.func

Will call a function when the Capture tour starts.

const handleCaptureTourStart = () => console.log('Capture tour has started');

onCaptureTourFinish

PropTypes.func

Will call a function when the Capture tour finishes.

onCameraPermissionSuccess

PropTypes.func

Callback called when we successfully got permission from the web browser to use the camera. The argument given as a parameter will be the video stream created.

onCameraPermissionError

PropTypes.func

Callback called when we could not get the permission from the web browser to use the camera. The argument given as a parameter will be the error received from the browser.

const handleCaptureTourFinish = () => console.log('Capture tour has finished');

onComplianceCheckStart

PropTypes.func

Will call a function when the picture qualty check starts.

const handleComplianceCheckStart = () => console.log('Picture quality check has started');

onComplianceCheckFinish

PropTypes.func

Will call a function when the picture qualty check finishes.

const handleComplianceCheckFinish = () => console.log('Picture quality check has finished');

onStartUploadPicture

PropTypes.func

Will call a function when start uploading every picture.

const handleStartUploadPicture = (state, api) => console.log('Started uploading a picture');

onFinishUploadPicture

PropTypes.func

Will call a function when the uploading is finished for every picture.

const handleFinishUploadPicture = (state, api) => console.log('Finished uploading a picture');

primaryColor

PropTypes.string

Custom color for better user experience (default is white)

task

PropTypes.oneOfType([PropTypes.string, PropTypes.object])

A string or object specifying the task that will be used in all sights, by default it's damage_detection

<Capture task="wheel_analysis" />
// or
<Capture task={{ name: 'images_ocr', image_details: { image_type: 'VIN' } }} />

mapTasksToSights

PropTypes.arrayOf( PropTypes.shape({ id: PropTypes.string, tasks: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object])), }), )

An array of objects containing the id of a sight and an array of tasks, useful in case we want to run multiple tasks on one image.

Every image will run the task coming from the task prop by default, unless you specify its id using mapTasksToSights.

[
{ id: 'sLu0CfOt', tasks: [{ name: 'images_ocr', image_details: { image_type: 'VIN' } }] },
{ id: 'WKJlxkiF', tasks: ['damage_detection'] },
{ id: 'cDe2q69X', tasks: ['damage_detection', 'wheel_analysis'] },
]

States and Methods

state

console.log(state); // { isReady, settings, sights, uploads, compliance };

settings

const settings = useSettings({ camera, initialState });
console.log(settings); // { state, distpatch }
console.log(settings.state); // { resolution, compression, ratio, zoom, type }

See Expo Camera Props

sights

const sights = useSights({ sightIds });
console.log(sights); // { state, distpatch }
console.log(sights.state); // {current: { id, index, metadata }, ids, remainingPictures, takenPictures, tour }

uploads

const uploads = useUploads({ sightIds });
console.log(uploads); // { state, distpatch }
console.log(uploads.state); // { sightId: { picture: null, status: 'idle', error: null, uploadCount: 0 } }

compliance

const compliance = useCompliance({ sightIds });
console.log(compliance); // { state, distpatch }
console.log(compliance.state); // { sightId: { id: '', status: 'idle', error: null, requestCount: 0, result: null, imageId: null } }

api

console.log(API); // { camera, checkComplianceAsync, createDamageDetectionAsync, goPrevSight, goNextSight, setPictureAsync, startUploadAsync, takePictureAsync, uploadAdditionalDamage };

camera

See Expo Camera API

checkComplianceAsync

Call a promise starting to check a compliance of Sight

const checkComplianceParams = { compliance, inspectionId, sightId };
const checkComplianceAsync = useCheckComplianceAsync(checkComplianceParams);

goPrevSight

Dispatch action to return to the previous Sight in the sightIds prop order

createDamageDetectionAsync

Call a promise starting to create damage detection of Sight

const createDamageDetectionAsync = useCreateDamageDetectionAsync();

goNextSight

Dispatch action to go to the next Sight in the sightIds prop order

takePictureAsync

Call a promise starting to take a picture from the Native or browser camera

setLoading(true);
const picture = await takePictureAsync();
console.log('Picture has been taken!')
setLoading(false);

// Don't set Loading to true if you want Async uploads
const uploadResult = await startUploadAsync(picture);
console.log('Upload has succeed!')

setPictureAsync,

Set picture in the component state

const picture = await takePictureAsync();
setPictureAsync(picture);

startUploadAsync

Call a promise starting to upload a picture to Monk API

const uploadResult = await startUploadAsync(picture);
console.log('Upload has succeed!')

uploadAdditionalDamage

Upload additional damage to tour on the current inspection.

const uploadAdditionalDamage = useUploadAdditionalDamage({ inspectionId });
console.log('Upload additional damage has succeed!')

Style

controlsContainerStyle

PropTypes.style

Style of the control's container (layout side right).

sightsContainerStyle

PropTypes.style

Style of the sight's scroll list container (layout side left).

thumbnailStyle

PropTypes.style

Style of a thumbnail in a sights list.