mirror of
https://github.com/filecoin-project/slate.git
synced 2024-11-25 19:55:26 +03:00
195 lines
5.9 KiB
JavaScript
195 lines
5.9 KiB
JavaScript
const iselement = (el) => el instanceof HTMLElement && el.nodeType === 1;
|
|
const isobject = (ob) => ob !== null && typeof ob === "object";
|
|
const isstring = (st) => typeof st === "string" || st instanceof String;
|
|
|
|
// (NOTE: daniel) helper function to create dom elements with classnames
|
|
const g = (attrArg = {}, tagArg = "div") => (...cttArr) => {
|
|
let el = document.createElement(tagArg);
|
|
let attrObj = isobject(attrArg) ? attrArg : { class: attrArg };
|
|
Object.keys(attrObj).forEach((key) => {
|
|
const val = attrObj[key];
|
|
if (!val) return;
|
|
if (/^\$/.test(key)) el.setAttribute("data-" + key.slice(1), val);
|
|
else if (/^_/.test(key)) el.addEventListener(key.slice(1), val);
|
|
else if (key === "style" && isobject(val)) {
|
|
el.setAttribute(
|
|
"style",
|
|
Object.keys(val)
|
|
.map((i) => `${i}:${val[i]}`)
|
|
.join(";")
|
|
);
|
|
} else el.setAttribute(key, val);
|
|
});
|
|
cttArr.forEach((cttItem) => {
|
|
if (iselement(cttItem)) el.appendChild(cttItem);
|
|
else if (tagArg.toLowerCase() === "img" && isstring(cttItem))
|
|
el.setAttribute("src", cttItem);
|
|
else if (cttItem !== undefined) el.innerHTML += cttItem;
|
|
});
|
|
return el;
|
|
};
|
|
|
|
// (NOTE: daniel) check maximum length of string
|
|
const maxLenNum = (aNum, bNum) => (aNum > bNum ? aNum : bNum).toString().length;
|
|
|
|
// (NOTE: daniel) reverse and convert string to number
|
|
const num2PadNumArr = (num, len, chars) => {
|
|
const charsArr = chars.map(String);
|
|
const padLeftStr = (rawStr, lenNum) =>
|
|
rawStr.length < lenNum ? padLeftStr("0" + rawStr, lenNum) : rawStr;
|
|
const str2NumArr = (rawStr) =>
|
|
rawStr.split("").map((i) => Number(charsArr.indexOf(i)));
|
|
|
|
return str2NumArr(padLeftStr(num.toString(), len)).reverse();
|
|
};
|
|
|
|
// (NOTE: daniel) helper function to generate numbers in a range
|
|
function range(start, stop, step) {
|
|
return Array.from(
|
|
{ length: (stop - start) / step + 1 },
|
|
(_, i) => start + i * step
|
|
);
|
|
}
|
|
|
|
const alphabets = range("a".charCodeAt(0), "z".charCodeAt(0), 1).map((x) =>
|
|
String.fromCharCode(x)
|
|
);
|
|
|
|
// (NOTE: daniel) odometer class
|
|
export default class Odometer {
|
|
constructor({
|
|
node,
|
|
from = 0,
|
|
to = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
|
duration = 0.5,
|
|
delay,
|
|
easeFn = (pos) =>
|
|
(pos /= 0.5) < 1
|
|
? 0.5 * Math.pow(pos, 3)
|
|
: 0.5 * (Math.pow(pos - 2, 3) + 2),
|
|
systemArr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...alphabets],
|
|
direct = true,
|
|
separator = "-",
|
|
seperateOnly = 0,
|
|
separateEvery = 3,
|
|
}) {
|
|
this.beforeArr = [];
|
|
this.afterArr = [];
|
|
this.ctnrArr = [];
|
|
this.duration = duration * 1000;
|
|
this.systemArr = systemArr;
|
|
this.easeFn = easeFn;
|
|
this.from = from;
|
|
this.to = to || 0;
|
|
this.node = node;
|
|
this.direct = direct;
|
|
this.separator = separator;
|
|
this.seperateOnly = seperateOnly;
|
|
this.separateEvery = seperateOnly ? 0 : separateEvery;
|
|
this.format = [8, 13, 18, 23];
|
|
this.init(maxLenNum(this.from, this.to));
|
|
if (to === undefined) return;
|
|
if (delay) setTimeout(() => this.start({ to: this.to }), delay * 1000);
|
|
else this.start({ to: this.to });
|
|
}
|
|
|
|
init(digits) {
|
|
this.node.classList.add("odometer");
|
|
this.node.style.position = "relative";
|
|
this.node.style.overflow = "hidden";
|
|
this.node.style.userSelect = "none";
|
|
this.node.style.cursor = "pointer";
|
|
|
|
for (let i = 0; i < digits; i++) {
|
|
const ctnr = g(`digits`)(
|
|
...this.systemArr.map((i) => g("digit")(i)),
|
|
g("digit")(this.systemArr[0])
|
|
);
|
|
|
|
ctnr.style.position = "relative";
|
|
ctnr.style.display = "inline-block";
|
|
ctnr.style.verticalAlign = "top";
|
|
ctnr.style.textAlign = "center";
|
|
this.ctnrArr.unshift(ctnr);
|
|
this.node.appendChild(ctnr);
|
|
this.beforeArr.push(0);
|
|
}
|
|
|
|
const format = () => {
|
|
for (let i = 0; i < this.format.length; i++) {
|
|
const sprtr = g("separator")("-");
|
|
sprtr.style.display = "inline-block";
|
|
|
|
this.node.insertBefore(sprtr, this.node.childNodes[this.format[i]]);
|
|
}
|
|
};
|
|
|
|
format();
|
|
|
|
const resize = () => {
|
|
this.height = this.ctnrArr[0].clientHeight / (this.systemArr.length + 1);
|
|
this.node.style.height = this.height + "px";
|
|
|
|
if (this.afterArr.length) {
|
|
this.frame(1);
|
|
} else {
|
|
for (let d = 0; d < this.ctnrArr.length; d++) {
|
|
this._draw({
|
|
digit: d,
|
|
per: 1,
|
|
alter: ~~(this.from / Math.pow(10, d)),
|
|
});
|
|
}
|
|
}
|
|
};
|
|
resize();
|
|
window.addEventListener("resize", resize);
|
|
}
|
|
|
|
_draw({ per, alter, digit }) {
|
|
const newHeight =
|
|
this.ctnrArr[0].clientHeight / (this.systemArr.length + 1);
|
|
if (newHeight && this.height !== newHeight) this.height = newHeight;
|
|
const from = this.beforeArr[digit];
|
|
const modNum = (((per * alter + from) % 36) + 36) % 36;
|
|
const translateY = `translateY(${-modNum * this.height}px)`;
|
|
this.ctnrArr[digit].style.webkitTransform = translateY;
|
|
this.ctnrArr[digit].style.transform = translateY;
|
|
}
|
|
|
|
frame(per) {
|
|
let temp = 0;
|
|
for (let d = this.ctnrArr.length - 1; d >= 0; d--) {
|
|
let alter = this.afterArr[d] - this.beforeArr[d];
|
|
temp += alter;
|
|
this._draw({
|
|
digit: d,
|
|
per: this.easeFn(per),
|
|
alter: this.direct ? alter : temp,
|
|
});
|
|
temp *= 10;
|
|
}
|
|
}
|
|
|
|
start({ to, duration, easeFn, direct }) {
|
|
if (easeFn) this.easeFn = easeFn;
|
|
if (direct !== undefined) this.direct = direct;
|
|
const len = this.ctnrArr.length;
|
|
this.beforeArr = num2PadNumArr(this.from, len, this.systemArr);
|
|
this.afterArr = num2PadNumArr(to, len, this.systemArr);
|
|
const start = Date.now();
|
|
const dur = duration * 1000 || this.duration;
|
|
|
|
const tick = () => {
|
|
let elapsed = Date.now() - start;
|
|
this.frame(elapsed / dur);
|
|
if (elapsed < dur) requestAnimationFrame(tick);
|
|
else {
|
|
this.from = to;
|
|
this.frame(1);
|
|
}
|
|
};
|
|
requestAnimationFrame(tick);
|
|
}
|
|
}
|