eyedropper-polyfill
Version:
EyeDropper API Polyfill
81 lines (80 loc) • 3.88 kB
JavaScript
import c from "html2canvas-pro";
function l() {
return "EyeDropper" in window;
}
const r = "[EyeDropper]", s = { canvasError: r + " Error getting canvas", color: r + " Cannot get color" };
function n(i) {
if (typeof i != "number" || Number.isNaN(i)) throw new Error();
return i + "px";
}
const a = { value: !1 };
class d {
colorSelectionResult;
previousDocumentCursor;
canvas;
canvasCtx;
resolve;
lastPoint;
magnification = { size: 4, scale: 12 };
constructor() {
this.onMouseMove = this.onMouseMove.bind(this), this.onClick = this.onClick.bind(this);
}
async open(t = {}) {
return a.value ? Promise.reject(new DOMException("Invalid state", "InvalidStateError")) : new Promise((o, e) => {
if (t.signal) {
if (t.signal.aborted) return this.stop(), e(t.signal.reason || new DOMException("Aborted", "AbortError"));
t.signal.addEventListener("abort", () => {
this.stop(), t.signal && e(t.signal.reason || new DOMException("Aborted", "AbortError"));
});
}
this.resolve = o, this.start();
});
}
async start() {
document.body.style.overflow = "hidden", this.setWaitingCursor(), await this.createScreenshot(), this.revertWaitingCursor(), this.bindEvents();
}
stop() {
document.body.style.overflow = "", this.unbindEvents(), this.removeScreenshot(), this.colorSelectionResult = void 0, this.lastPoint = void 0, a.value = !1;
}
async createScreenshot() {
this.canvas = await c(document.body, { allowTaint: !0, useCORS: !0, height: document.body.scrollHeight, width: document.body.scrollWidth }), this.addCanvasStyle(this.canvas), this.canvasCtx = this.canvas.getContext("2d", { willReadFrequently: !0 }), document.body.appendChild(this.canvas);
}
removeScreenshot() {
if (!this.canvas) throw new Error(s.canvasError);
document.body.removeChild(this.canvas), this.canvas = void 0, this.canvasCtx = void 0;
}
setWaitingCursor() {
this.previousDocumentCursor = document.documentElement.style.cursor, document.documentElement.style.cursor = "wait";
}
revertWaitingCursor() {
this.previousDocumentCursor ? document.documentElement.style.cursor = this.previousDocumentCursor : document.documentElement.style.cursor = "", this.previousDocumentCursor = void 0;
}
bindEvents() {
window.addEventListener("mousemove", this.onMouseMove), window.addEventListener("click", this.onClick);
}
unbindEvents() {
window.removeEventListener("mousemove", this.onMouseMove), window.removeEventListener("click", this.onClick);
}
onClick() {
if (!this.lastPoint) throw new Error(s.color);
this.detectColor(this.lastPoint);
var t = this.colorSelectionResult;
this.stop(), t && this.resolve && this.resolve(t);
}
onMouseMove(e) {
if (!this.canvas || !this.canvasCtx) throw new Error(s.canvasError);
var o = window.devicePixelRatio, e = (this.lastPoint = { x: (e.clientX + window.scrollX) * o, y: (e.clientY + window.scrollY) * o }, [n(this.lastPoint.x / o), n(this.lastPoint.y / o)].join(" "));
Object.assign(this.canvas.style, { opacity: 1, transformOrigin: e, clipPath: `circle(${n(this.magnification.size)} at ${e})` });
}
detectColor(t) {
if (!this.canvasCtx) throw new Error(s.canvasError);
t = this.canvasCtx.getImageData(t.x, t.y, 1, 1).data, t = ((1 << 24) + (t[0] << 16) + (t[1] << 8) + t[2]).toString(16).slice(1), this.colorSelectionResult = { sRGBHex: "#" + t };
}
addCanvasStyle(t) {
Object.assign(t.style, { position: "fixed", top: "0px", marginTop: -window.scrollY + "px", left: "0px", zIndex: 999999, opacity: 0, transform: `scale(${this.magnification.scale})`, imageRendering: "pixelated" });
}
}
function h() {
if (!Reflect.defineProperty(window, "EyeDropper", { value: d })) throw Error("Error attaching `EyeDropper` polyfill: couldn't attach `EyeDropper` to `window`");
}
l() || h();