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.