const epsilon = 0.1; const Utils = { blobToBase64: blob => { const reader = new FileReader(); reader.readAsDataURL(blob); return new Promise(resolve => { reader.onloadend = () => { resolve(reader.result); }; }); }, adjustMinMax(r){ return { x1: Math.min(r.x1, r.x2), x2: Math.max(r.x1, r.x2), y1: Math.min(r.y1, r.y2), y2: Math.max(r.y1, r.y2) } }, intersectPointRect(p, r){ //r = this.adjustMinMax(r); return p[0] >= r.x1 && p[0] <= r.x2 && p[1] >= r.y1 && p[1] <= r.y2; }, intersectPointLine(p, l){ //l = this.adjustMinMax(l); let dx = l.x2 - l.x1, dy = l.y2 - l.y1; let c = dy / dx; return this.intersectPointRect(p, l) && c * p[0] - p[1] <= epsilon }, intersectLineRect(l, r){ return this.intersectPointRect([l.x1, l.y1], r) || this.intersectPointRect([l.x2, l.y2], r); }, intersectRectRect(r1, r2){ return this.intersectPointRect([r1.x1, r1.y1], r2) || this.intersectPointRect([r1.x1, r1.y2], r2) || this.intersectPointRect([r1.x2, r1.y1], r2) || this.intersectPointRect([r1.x2, r1.y2], r2); }, round(n, p = 2){ let pp = Math.pow(10, p); return Math.round(n*pp)/pp; }, deg2rad(deg){ return deg * (Math.PI / 180); }, rad2deg(rad){ return rad * 180 / Math.PI; }, shuffleArray(arr){ return arr.map(value => ({ value, sort: Math.random() })) .sort((a, b) => a.sort - b.sort).map(({ value }) => value) }, deepMerge(target, source, transformFn) { Object.entries(source).forEach(([key, value]) => { if (transformFn){ value = transformFn(key, value) } if (value && typeof value === 'object') { let dflt = Array.isArray(value) ? [] : {}; this.deepMerge(target[key] = target[key] || dflt, value, transformFn); return; } target[key] = value; }); return target; }, drawOnCanvas(svg, width, height){ return new Promise((resolve, reject)=>{ let url = URL.createObjectURL(new Blob([svg],{ type:"image/svg+xml;charset=utf-8" })); let img = new Image(); let canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; let ctx = canvas.getContext('2d'); img.addEventListener('load', function () { ctx.drawImage(this, 0, 0, canvas.width, canvas.height); URL.revokeObjectURL(url); resolve(canvas); }, { once: true }) img.src = url; }) }, async wait(ms, opts = {}){ await new Promise((resolve, reject)=>{ opts.id = setTimeout(resolve, ms) opts.resolve = resolve; opts.reject = reject; }) }, async killWait(opts){ if (opts.id){ clearTimeout(opts.id); if (opts.onKill == 'resolve') { await opts.resolve() }else { await opts.reject() } delete opts.id; delete opts.resolve; delete opts.reject; } }, async waitFor(expFn){ while (!expFn()){ await Utils.wait(200); } }, escapeRegExp(string) { return string && string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string }, toSafeJSON(data){ data = Utils.deepMerge({}, data, (k, v)=>{ return k.startsWith('__') ? undefined : v; }) return JSON.stringify(data); } } export default Utils;