@microblink/blinkid-in-browser-sdk
Version:
A simple ID scanning library for WebAssembly-enabled browsers.
438 lines (437 loc) • 18.4 kB
JavaScript
/**
* Copyright (c) Microblink Ltd. All rights reserved.
*/
import { Component, Event, Host, h, Method, Prop, Watch } from '@stencil/core';
import { CameraExperience, CameraExperienceState, CameraExperienceStateDuration } from '../../../utils/data-structures';
export class MbCameraExperience {
constructor() {
/**
* Unless specifically granted by your license key, you are not allowed to
* modify or remove the Microblink logo displayed on the bottom of the camera
* overlay.
*/
this.showOverlay = true;
/**
* Camera horizontal state passed from root component.
*
* Horizontal camera image can be mirrored
*/
this.cameraFlipped = false;
/**
* Show scanning line on camera
*/
this.showScanningLine = false;
this.cameraStateInProgress = false;
this.flipCameraStateInProgress = false;
}
apiStateHandler(apiState, _oldValue) {
if (apiState === '' && (this.type === CameraExperience.CardSingleSide || this.type === CameraExperience.CardCombined))
this.cardIdentityElement.classList.add('visible');
else
this.cardIdentityElement.classList.remove('visible');
}
/**
* Method is exposed outside which allow us to control Camera Flip state from parent component.
*/
async setCameraFlipState(isFlipped) {
if (isFlipped)
this.cameraFlipBtn.classList.add('flipped');
else
this.cameraFlipBtn.classList.remove('flipped');
}
/**
* Set camera scanning state.
*/
setState(state, isBackSide = false, force = false) {
return new Promise((resolve) => {
if (!force && (!state || this.cameraStateInProgress || this.flipCameraStateInProgress)) {
resolve();
return;
}
this.cameraStateInProgress = true;
if (state === CameraExperienceState.Flip) {
this.flipCameraStateInProgress = true;
}
const stateClass = this.getStateClass(state);
switch (this.type) {
case CameraExperience.CardSingleSide:
case CameraExperience.CardCombined:
this.cameraCursorIdentityCard.setAttribute('class', `reticle ${stateClass}`);
break;
case CameraExperience.Barcode:
this.cameraCursorBarcode.setAttribute('class', `rectangle ${stateClass}`);
break;
case CameraExperience.BlinkCard:
stateClass === 'is-default' && this.showScanningLine ? this.scanningLine.classList.add('is-active') : this.scanningLine.classList.remove('is-active');
this.cameraCursorBlinkCard.setAttribute('class', `rectangle ${stateClass}`);
break;
}
this.setMessage(state, isBackSide, this.type);
window.setTimeout(() => {
if (this.flipCameraStateInProgress && state === CameraExperienceState.Flip) {
this.flipCameraStateInProgress = false;
}
this.cameraStateInProgress = false;
resolve();
}, CameraExperienceStateDuration.get(state));
});
}
render() {
return (h(Host, { class: this.showOverlay ? '' : 'no-overlay' },
h("div", { class: "gradient-overlay top" }),
h("div", { id: "barcode", class: this.type === CameraExperience.Barcode ? 'visible' : '' },
h("div", { class: "rectangle-container" },
h("div", { class: "rectangle", ref: el => this.cameraCursorBarcode = el },
h("div", { class: "rectangle__el" }),
h("div", { class: "rectangle__el" }),
h("div", { class: "rectangle__el" }),
h("div", { class: "rectangle__el" })))),
h("div", { id: "card-identity", ref: (el) => this.cardIdentityElement = el, class: this.type === CameraExperience.CardSingleSide || this.type === CameraExperience.CardCombined ? 'visible' : '' },
h("div", { class: "reticle-container" },
h("div", { class: "reticle", ref: el => this.cameraCursorIdentityCard = el },
h("div", { class: "reticle__cursor" },
h("div", { class: "reticle__el" }),
h("div", { class: "reticle__el" }),
h("div", { class: "reticle__el" }),
h("div", { class: "reticle__el" })),
h("img", { class: "reticle__done", src: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHZpZXdCb3g9IjAgMCA0OCA0OCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTIwLjk3MiAzMy40NkMyMC43MDk1IDMzLjQ2MDUgMjAuNDQ5NCAzMy40MDkyIDIwLjIwNjggMzMuMzA5QzE5Ljk2NDEgMzMuMjA4OCAxOS43NDM2IDMzLjA2MTYgMTkuNTU4IDMyLjg3NkwxMS4wNzQgMjQuMzlDMTAuODgyOSAyNC4yMDU2IDEwLjczMDMgMjMuOTg1MSAxMC42MjU0IDIzLjc0MTFDMTAuNTIwNCAyMy40OTcyIDEwLjQ2NSAyMy4yMzQ4IDEwLjQ2MjUgMjIuOTY5MkMxMC40NiAyMi43MDM3IDEwLjUxMDQgMjIuNDQwMyAxMC42MTA4IDIyLjE5NDRDMTAuNzExMiAyMS45NDg2IDEwLjg1OTYgMjEuNzI1MiAxMS4wNDcyIDIxLjUzNzNDMTEuMjM0OSAyMS4zNDkzIDExLjQ1ODEgMjEuMjAwNyAxMS43MDM4IDIxLjA5OTlDMTEuOTQ5NSAyMC45OTkyIDEyLjIxMjggMjAuOTQ4NCAxMi40Nzg0IDIwLjk1MDVDMTIuNzQzOSAyMC45NTI2IDEzLjAwNjQgMjEuMDA3NiAxMy4yNTA1IDIxLjExMjNDMTMuNDk0NiAyMS4yMTY5IDEzLjcxNTQgMjEuMzY5MSAxMy45IDIxLjU2TDIwLjk3IDI4LjYzTDMzLjcgMTUuOTA0QzM0LjA3NSAxNS41Mjg3IDM0LjU4MzggMTUuMzE3OCAzNS4xMTQzIDE1LjMxNzZDMzUuNjQ0OCAxNS4zMTc0IDM2LjE1MzcgMTUuNTI4IDM2LjUyOSAxNS45MDNDMzYuOTA0MyAxNi4yNzggMzcuMTE1MiAxNi43ODY4IDM3LjExNTQgMTcuMzE3M0MzNy4xMTU2IDE3Ljg0NzggMzYuOTA1IDE4LjM1NjcgMzYuNTMgMTguNzMyTDIyLjM4NiAzMi44NzZDMjIuMjAwNCAzMy4wNjE2IDIxLjk3OTkgMzMuMjA4OCAyMS43MzcyIDMzLjMwOUMyMS40OTQ2IDMzLjQwOTIgMjEuMjM0NSAzMy40NjA1IDIwLjk3MiAzMy40NloiIGZpbGw9ImJsYWNrIi8+Cjwvc3ZnPgo=" })),
h("p", { class: "message", ref: el => this.cameraMessageIdentityCard = el }))),
h("div", { id: "blinkcard", class: this.type === CameraExperience.BlinkCard ? 'visible' : '' },
h("div", { class: "rectangle-container" },
h("div", { class: "rectangle", ref: el => this.cameraCursorBlinkCard = el },
h("div", { class: "rectangle__cursor" },
h("div", { class: "rectangle__el" }),
h("div", { class: "rectangle__el" }),
h("div", { class: "rectangle__el" }),
h("div", { class: "rectangle__el" })),
h("div", { class: "scanning-line", ref: el => this.scanningLine = el })),
h("p", { class: "message", ref: el => this.cameraMessageBlinkCard = el }))),
h("div", { class: "gradient-overlay bottom" }),
h("div", { class: "controls" },
this.apiState !== 'error' &&
h("a", { href: "javascript:void(0)", onClick: (ev) => this.handleStop(ev), class: "close-button" },
h("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", xmlns: "http://www.w3.org/2000/svg" },
h("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M18.7071 5.29289C19.0976 5.68342 19.0976 6.31658 18.7071 6.70711L6.70711 18.7071C6.31658 19.0976 5.68342 19.0976 5.29289 18.7071C4.90237 18.3166 4.90237 17.6834 5.29289 17.2929L17.2929 5.29289C17.6834 4.90237 18.3166 4.90237 18.7071 5.29289Z", fill: "white" }),
h("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M5.29289 5.29289C5.68342 4.90237 6.31658 4.90237 6.70711 5.29289L18.7071 17.2929C19.0976 17.6834 19.0976 18.3166 18.7071 18.7071C18.3166 19.0976 17.6834 19.0976 17.2929 18.7071L5.29289 6.70711C4.90237 6.31658 4.90237 5.68342 5.29289 5.29289Z", fill: "white" }))),
h("button", { type: "button", id: "flipBtn", class: !this.cameraFlipped ? '' : 'flipped', onClick: () => this.flipCamera(), ref: el => this.cameraFlipBtn = el },
h("svg", { width: "28", height: "28", viewBox: "0 0 28 28", fill: "none", xmlns: "http://www.w3.org/2000/svg" },
h("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M16 5C16.5523 5 17 5.44772 17 6V24C17 24.5523 16.5523 25 16 25C15.4477 25 15 24.5523 15 24V6C15 5.44772 15.4477 5 16 5Z", fill: "white" }),
h("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M19.7702 9.02676C20.2216 8.9202 20.687 9.13798 20.8944 9.55279L25.8944 19.5528C26.0494 19.8628 26.0329 20.2309 25.8507 20.5257C25.6684 20.8206 25.3466 21 25 21H20C19.4477 21 19 20.5523 19 20V10C19 9.53623 19.3189 9.13331 19.7702 9.02676ZM21 14.2361V19H23.382L21 14.2361Z", fill: "white" }),
h("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M12.2298 9.02676C12.6811 9.13331 13 9.53623 13 10V20C13 20.5523 12.5523 21 12 21H7C6.65342 21 6.33156 20.8206 6.14935 20.5257C5.96714 20.2309 5.95058 19.8628 6.10557 19.5528L11.1056 9.55279C11.313 9.13798 11.7784 8.9202 12.2298 9.02676ZM8.61803 19H11V14.2361L8.61803 19Z", fill: "white" }),
h("path", { "fill-rule": "evenodd", "clip-rule": "evenodd", d: "M19.7702 9.02676C20.2216 8.9202 20.687 9.13798 20.8944 9.55279L25.8944 19.5528C26.0494 19.8628 26.0329 20.2309 25.8507 20.5257C25.6684 20.8206 25.3466 21 25 21H20C19.4477 21 19 20.5523 19 20V10C19 9.53623 19.3189 9.13331 19.7702 9.02676Z", fill: "white" }))))));
}
flipCamera() {
this.flipCameraAction.emit();
}
handleStop(ev) {
ev.preventDefault();
ev.stopPropagation();
this.close.emit();
}
getStateClass(state) {
let stateClass = 'is-default';
switch (state) {
case CameraExperienceState.Classification:
stateClass = 'is-classification';
break;
case CameraExperienceState.Default:
stateClass = 'is-default';
break;
case CameraExperienceState.Detection:
stateClass = 'is-detection';
break;
case CameraExperienceState.MoveFarther:
stateClass = 'is-error-move-farther';
break;
case CameraExperienceState.MoveCloser:
stateClass = 'is-error-move-closer';
break;
case CameraExperienceState.AdjustAngle:
stateClass = 'is-error-adjust-angle';
break;
case CameraExperienceState.Flip:
stateClass = 'is-flip';
break;
case CameraExperienceState.Done:
stateClass = 'is-done';
break;
case CameraExperienceState.DoneAll:
stateClass = 'is-done-all';
break;
default:
// Reset class
}
return stateClass;
}
setMessage(state, isBackSide, type) {
const message = this.getStateMessage(state, isBackSide);
switch (type) {
case CameraExperience.CardSingleSide:
case CameraExperience.CardCombined:
while (this.cameraMessageIdentityCard.firstChild) {
this.cameraMessageIdentityCard.removeChild(this.cameraMessageIdentityCard.firstChild);
}
if (message)
this.cameraMessageIdentityCard.appendChild(message);
this.cameraMessageIdentityCard.setAttribute('class', message && message !== null ? 'message is-active' : 'message');
break;
case CameraExperience.BlinkCard:
while (this.cameraMessageBlinkCard.firstChild) {
this.cameraMessageBlinkCard.removeChild(this.cameraMessageBlinkCard.firstChild);
}
if (message)
this.cameraMessageBlinkCard.appendChild(message);
this.cameraMessageBlinkCard.setAttribute('class', message && message !== null ? 'message is-active' : 'message');
break;
default:
// Do nothing
}
}
getStateMessage(state, isBackSide = false) {
const getStateMessageAsHTML = (message) => {
if (message) {
const messageArray = typeof message === 'string' ? [message] : message;
const children = [];
while (messageArray.length) {
const sentence = messageArray.shift();
children.push(document.createTextNode(sentence));
if (messageArray.length) {
children.push(document.createElement('br'));
}
}
const spanElement = document.createElement('span');
while (children.length) {
spanElement.appendChild(children.shift());
}
return spanElement;
}
};
switch (state) {
case CameraExperienceState.Default:
const key = isBackSide ? 'camera-feedback-scan-back' : 'camera-feedback-scan-front';
return getStateMessageAsHTML(this.translationService.i(key));
case CameraExperienceState.MoveFarther:
return getStateMessageAsHTML(this.translationService.i('camera-feedback-move-farther'));
case CameraExperienceState.MoveCloser:
return getStateMessageAsHTML(this.translationService.i('camera-feedback-move-closer'));
case CameraExperienceState.AdjustAngle:
return getStateMessageAsHTML(this.translationService.i('camera-feedback-adjust-angle'));
case CameraExperienceState.Flip:
return getStateMessageAsHTML(this.translationService.i('camera-feedback-flip'));
case CameraExperienceState.Classification:
case CameraExperienceState.Detection:
case CameraExperienceState.Done:
case CameraExperienceState.DoneAll:
default:
return null;
}
}
static get is() { return "mb-camera-experience"; }
static get encapsulation() { return "shadow"; }
static get originalStyleUrls() { return {
"$": ["mb-camera-experience.scss"]
}; }
static get styleUrls() { return {
"$": ["mb-camera-experience.css"]
}; }
static get properties() { return {
"type": {
"type": "string",
"mutable": false,
"complexType": {
"original": "CameraExperience",
"resolved": "CameraExperience.Barcode | CameraExperience.BlinkCard | CameraExperience.CardCombined | CameraExperience.CardSingleSide",
"references": {
"CameraExperience": {
"location": "import",
"path": "../../../utils/data-structures"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Choose desired camera experience.\n\nEach experience type must be implemented in this component."
},
"attribute": "type",
"reflect": false
},
"showOverlay": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Unless specifically granted by your license key, you are not allowed to\nmodify or remove the Microblink logo displayed on the bottom of the camera\noverlay."
},
"attribute": "show-overlay",
"reflect": false,
"defaultValue": "true"
},
"translationService": {
"type": "unknown",
"mutable": false,
"complexType": {
"original": "TranslationService",
"resolved": "TranslationService",
"references": {
"TranslationService": {
"location": "import",
"path": "../../../utils/translation.service"
}
}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Instance of TranslationService passed from root component."
}
},
"apiState": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Api state passed from root component."
},
"attribute": "api-state",
"reflect": false
},
"cameraFlipped": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Camera horizontal state passed from root component.\n\nHorizontal camera image can be mirrored"
},
"attribute": "camera-flipped",
"reflect": false,
"defaultValue": "false"
},
"showScanningLine": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": "Show scanning line on camera"
},
"attribute": "show-scanning-line",
"reflect": false,
"defaultValue": "false"
}
}; }
static get events() { return [{
"method": "close",
"name": "close",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": "Emitted when user clicks on 'X' button."
},
"complexType": {
"original": "void",
"resolved": "void",
"references": {}
}
}, {
"method": "flipCameraAction",
"name": "flipCameraAction",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": "Emitted when user clicks on Flip button."
},
"complexType": {
"original": "void",
"resolved": "void",
"references": {}
}
}]; }
static get methods() { return {
"setCameraFlipState": {
"complexType": {
"signature": "(isFlipped: boolean) => Promise<void>",
"parameters": [{
"tags": [],
"text": ""
}],
"references": {
"Promise": {
"location": "global"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "Method is exposed outside which allow us to control Camera Flip state from parent component.",
"tags": []
}
},
"setState": {
"complexType": {
"signature": "(state: CameraExperienceState, isBackSide?: boolean, force?: boolean) => Promise<void>",
"parameters": [{
"tags": [],
"text": ""
}, {
"tags": [],
"text": ""
}, {
"tags": [],
"text": ""
}],
"references": {
"Promise": {
"location": "global"
},
"CameraExperienceState": {
"location": "import",
"path": "../../../utils/data-structures"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "Set camera scanning state.",
"tags": []
}
}
}; }
static get watchers() { return [{
"propName": "apiState",
"methodName": "apiStateHandler"
}]; }
}