UNPKG

@glair/web-components

Version:
229 lines (228 loc) 7.27 kB
import { html as u } from "lit"; import { query as B, property as m, state as y, customElement as R } from "lit/decorators.js"; import { TailwindElement as _ } from "./tailwind.element.js"; const v = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGIAAABiCAYAAACrpQYOAAABBklEQVR4Ae3TUQ2EQBTAwH2XE4wvdKFj8UBI6MeMhaaz974Wn/stEoSIECJCiAghIoSIECJCiAghIoSIECJCiIj/euaYmXPxGkdECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQEUJECBEhRIQQETcExQXG6zjxjAAAAABJRU5ErkJggg=="; function J(e) { const t = x(e); return t && t.toDataURL("image/jpeg", 0.92); } function x(e) { const { ref: t, width: s = 480, height: i = 480, mirrored: r = !1, screenshotArea: h } = e; let p = s * h.width / 100, Q = i * h.height / 100, c = document.createElement("canvas"); c.width = p, c.height = Q; let g = c.getContext("2d"); if (g && c) { r && (g.translate(c.width, 0), g.scale(-1, 1)); const b = () => { let n, d, l, E; const A = s / i, I = t.videoWidth / t.videoHeight; return A > I ? (n = t.videoWidth, d = t.videoWidth * (1 / A), l = 0, E = (t.videoHeight - d) / 2) : (n = t.videoHeight * A, d = t.videoHeight, l = (t.videoWidth - n) / 2, E = 0), { takeWidth: n, takeHeight: d, translateX: l, translateY: E } = (() => (l = l + Math.round(h.x / 100 * n), E = E + Math.round(h.y / 100 * d), n = n * h.width / 100, d = d * h.height / 100, r && (l = t.videoWidth - (l + n)), { takeWidth: n, takeHeight: d, translateX: l, translateY: E }))(), { takeWidth: n, takeHeight: d, translateX: l, translateY: E }; }, { takeWidth: f, takeHeight: C, translateX: w, translateY: U } = b(); g.drawImage( t, w, U, f, C, 0, 0, p, Q ), r && (g.scale(-1, 1), g.translate(-c.width, 0)); } return c; } var O = Object.defineProperty, M = Object.getOwnPropertyDescriptor, o = (e, t, s, i) => { for (var r = i > 1 ? void 0 : i ? M(t, s) : t, h = e.length - 1, p; h >= 0; h--) (p = e[h]) && (r = (i ? p(t, s, r) : p(r)) || r); return i && r && O(t, s, r), r; }; let a = class extends _ { constructor() { super(...arguments), this.width = 480, this.height = 480, this.facingMode = "user", this.mirrored = !1, this.screenshotArea = JSON.stringify({ x: 0, y: 0, width: 100, height: 100, enableOverlay: !1 }), this._isUserMedia = !1, this._stream = null, this._screenshotAreaObj = { x: 0, y: 0, width: 100, height: 100, enableOverlay: !1 }, this._isMounted = !0; } async connectedCallback() { super.connectedCallback(), await this.requestUserMedia(), this._screenshotAreaObj = this.preProcessScreenshotArea(); } async disconnectedCallback() { super.disconnectedCallback(), this._isMounted = !1, this.stopStream(); } async requestUserMedia() { try { const e = await navigator.mediaDevices.getUserMedia({ video: { facingMode: this.facingMode } }); this._stream = e, this.videoEl.srcObject = e, this._isUserMedia = !0, this._isMounted || this.stopStream(); } catch (e) { console.log("Error occured", e); } } preProcessScreenshotArea() { const e = JSON.parse(this.screenshotArea); function t(s, i) { return s + i > 100; } return t(e.x, e.width) && (e.width = 100 - e.x), t(e.y, e.height) && (e.height = 100 - e.y), e; } stopStream() { var e; (e = this._stream) == null || e.getTracks().forEach((t) => { var s; (s = this._stream) == null || s.removeTrack(t), t.stop(); }); } async screenshot() { return J({ ref: this.videoEl, width: this.width, height: this.height, mirrored: this.mirrored, screenshotArea: this._screenshotAreaObj }); } // https://stackoverflow.com/questions/4000818/scale-html5-video-and-break-aspect-ratio-to-fill-whole-site render() { return u` <div class="relative bg-gray-200"> <video autoplay muted playsinline class="object-cover" style="width: ${this.width}px; height: ${this.height}px; transform: scaleX(${this.mirrored ? "-1" : "1"});" ></video> ${this.userMediaError()} ${this.userMedia()} ${this.screenshotOverlay()} </div> `; } userMediaError() { return u` <div style="${this._isUserMedia ? "display: none" : "display: revert"}"> <slot name="user-media-error"> <div class="absolute top-[50%] left-[50%] flex w-[300px] translate-y-[-50%] translate-x-[-50%] flex-col rounded-sm border bg-white py-4 px-8" > <p class="text-[20px]">Camera blocked</p> <p class="my-4"> Please allow camera access in your browser settings and try again. </p> <div class="flex flex-col items-end"> <button type="button" class="text-md text-[#009CDE]" .onclick=${() => location.reload()} > Try Again </button> </div> </div> </slot> </div> `; } userMedia() { return u` <div style="${this._isUserMedia ? "display: revert" : "display: none"}"> <slot name="user-media"> <img src=${v} alt="overlay" width="50" class="absolute top-12 left-12" /> <img src=${v} alt="overlay" width="50" class="absolute bottom-12 left-12 -rotate-90" /> <img src=${v} alt="overlay" width="50" class="absolute top-12 right-12 rotate-90" /> <img src=${v} alt="overlay" width="50" class="absolute bottom-12 right-12 rotate-180" /> </slot> </div> `; } screenshotOverlay() { var e, t, s, i, r; return (e = this._screenshotAreaObj) != null && e.enableOverlay ? u` <div class="absolute border border-dashed border-red-500" style="top: ${(t = this._screenshotAreaObj) == null ? void 0 : t.y}%; left: ${(s = this._screenshotAreaObj) == null ? void 0 : s.x}%; width: ${(i = this._screenshotAreaObj) == null ? void 0 : i.width}%; height: ${(r = this._screenshotAreaObj) == null ? void 0 : r.height}%" ></div> ` : u``; } }; o([ B("video") ], a.prototype, "videoEl", 2); o([ m({ type: Number }) ], a.prototype, "width", 2); o([ m({ type: Number }) ], a.prototype, "height", 2); o([ m({ type: String }) ], a.prototype, "facingMode", 2); o([ m({ type: Boolean }) ], a.prototype, "mirrored", 2); o([ m({ type: String }) ], a.prototype, "screenshotArea", 2); o([ y() ], a.prototype, "_isUserMedia", 2); o([ y() ], a.prototype, "_stream", 2); o([ y() ], a.prototype, "_screenshotAreaObj", 2); o([ y() ], a.prototype, "_isMounted", 2); a = o([ R("glair-webcam") ], a); export { a as Webcam };