🎨 format
This commit is contained in:
@@ -1,15 +1,15 @@
|
||||
export class throttler {
|
||||
private _throttlePause: boolean;
|
||||
constructor() {
|
||||
this._throttlePause = false;
|
||||
}
|
||||
throttle = (callback: Function, time: number) => {
|
||||
if (this._throttlePause) return;
|
||||
private _throttlePause: boolean
|
||||
constructor() {
|
||||
this._throttlePause = false
|
||||
}
|
||||
throttle = (callback: Function, time: number) => {
|
||||
if (this._throttlePause) return
|
||||
|
||||
this._throttlePause = true;
|
||||
setTimeout(() => {
|
||||
callback();
|
||||
this._throttlePause = false;
|
||||
}, time);
|
||||
};
|
||||
this._throttlePause = true
|
||||
setTimeout(() => {
|
||||
callback()
|
||||
this._throttlePause = false
|
||||
}, time)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export const daisyColor = (name: string, opacity: number = 100) => {
|
||||
const color = getComputedStyle(document.documentElement).getPropertyValue(name).trim();
|
||||
if (opacity >= 100) return color;
|
||||
const alpha = Math.min(Math.max(opacity, 0), 100) / 100;
|
||||
return `${color.replace(/(\/\s*\d+(\.\d+)?\))|\)$/, '')} / ${alpha})`;
|
||||
};
|
||||
const color = getComputedStyle(document.documentElement).getPropertyValue(name).trim()
|
||||
if (opacity >= 100) return color
|
||||
const alpha = Math.min(Math.max(opacity, 0), 100) / 100
|
||||
return `${color.replace(/(\/\s*\d+(\.\d+)?\))|\)$/, '')} / ${alpha})`
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
export * from './result';
|
||||
export * from './string-utilities';
|
||||
export * from './svelte-utilities';
|
||||
export * from './math-utilities';
|
||||
export * from './buffer-utilities';
|
||||
export * from './model-utilities';
|
||||
export * from './position-utilities';
|
||||
export * from './string-utilities';
|
||||
export * from './color-utilities';
|
||||
export * from './result'
|
||||
export * from './string-utilities'
|
||||
export * from './svelte-utilities'
|
||||
export * from './math-utilities'
|
||||
export * from './buffer-utilities'
|
||||
export * from './model-utilities'
|
||||
export * from './position-utilities'
|
||||
export * from './string-utilities'
|
||||
export * from './color-utilities'
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
export const toUint8 = (number: number, min: number, max: number) => {
|
||||
number = Math.max(min, Math.min(max, number));
|
||||
let scaled = ((number - min) / (max - min)) * 255;
|
||||
return Math.round(scaled) & 0xff;
|
||||
};
|
||||
number = Math.max(min, Math.min(max, number))
|
||||
let scaled = ((number - min) / (max - min)) * 255
|
||||
return Math.round(scaled) & 0xff
|
||||
}
|
||||
|
||||
export const toInt8 = (number: number, min: number, max: number) => {
|
||||
number = Math.max(min, Math.min(max, number));
|
||||
let scaled = ((number - min) / (max - min)) * 255 - 128;
|
||||
return Math.max(-128, Math.min(127, Math.round(scaled))) | 0;
|
||||
};
|
||||
number = Math.max(min, Math.min(max, number))
|
||||
let scaled = ((number - min) / (max - min)) * 255 - 128
|
||||
return Math.max(-128, Math.min(127, Math.round(scaled))) | 0
|
||||
}
|
||||
|
||||
export const fromInt8 = (int8: number, min: number, max: number) => {
|
||||
int8 = Math.max(-128, Math.min(127, int8));
|
||||
const scaled = (int8 + 128) / 255;
|
||||
const number = scaled * (max - min) + min;
|
||||
return number;
|
||||
};
|
||||
int8 = Math.max(-128, Math.min(127, int8))
|
||||
const scaled = (int8 + 128) / 255
|
||||
const number = scaled * (max - min) + min
|
||||
return number
|
||||
}
|
||||
|
||||
@@ -10,84 +10,85 @@ import { get } from 'svelte/store'
|
||||
let model_xml: XMLDocument
|
||||
|
||||
export const populateModelCache = async () => {
|
||||
await cacheModelFiles()
|
||||
const modelRes = await loadModel(get(currentVariant).model)
|
||||
if (modelRes.isOk()) {
|
||||
const [urdf, JOINT_NAME] = modelRes.inner
|
||||
jointNames.set(JOINT_NAME)
|
||||
model.set(urdf)
|
||||
} else {
|
||||
console.error(modelRes.inner, { exception: modelRes.exception })
|
||||
}
|
||||
await cacheModelFiles()
|
||||
const modelRes = await loadModel(get(currentVariant).model)
|
||||
if (modelRes.isOk()) {
|
||||
const [urdf, JOINT_NAME] = modelRes.inner
|
||||
jointNames.set(JOINT_NAME)
|
||||
model.set(urdf)
|
||||
} else {
|
||||
console.error(modelRes.inner, { exception: modelRes.exception })
|
||||
}
|
||||
}
|
||||
|
||||
export const cacheModelFiles = async () => {
|
||||
const data = await fetch(get(currentVariant).stl)
|
||||
const data = await fetch(get(currentVariant).stl)
|
||||
|
||||
const files = uzip.parse(await data.arrayBuffer())
|
||||
const files = uzip.parse(await data.arrayBuffer())
|
||||
|
||||
for (const [path, data] of Object.entries(files) as [path: string, data: Uint8Array][]) {
|
||||
const url = new URL(path, window.location.href)
|
||||
fileService?.saveFile(url.toString(), data)
|
||||
}
|
||||
for (const [path, data] of Object.entries(files) as [path: string, data: Uint8Array][]) {
|
||||
const url = new URL(path, window.location.href)
|
||||
fileService?.saveFile(url.toString(), data)
|
||||
}
|
||||
}
|
||||
|
||||
export const loadModel = async (url: string): Promise<Result<[URDFRobot, string[]], string>> => {
|
||||
const urdfLoader = new URDFLoader()
|
||||
urdfLoader.workingPath = LoaderUtils.extractUrlBase(url)
|
||||
const urdfLoader = new URDFLoader()
|
||||
urdfLoader.workingPath = LoaderUtils.extractUrlBase(url)
|
||||
|
||||
let xml = url.endsWith('.xacro') ? await loadXacro(url) : await fetch(url).then(res => res.text())
|
||||
let xml =
|
||||
url.endsWith('.xacro') ? await loadXacro(url) : await fetch(url).then(res => res.text())
|
||||
|
||||
if (typeof xml === 'string') {
|
||||
xml = new window.DOMParser().parseFromString(xml, 'text/xml')
|
||||
}
|
||||
|
||||
return new Promise(resolve => {
|
||||
model_xml = xml
|
||||
try {
|
||||
const model = urdfLoader.parse(xml)
|
||||
setupRobot(model)
|
||||
const joints = Object.entries(model.joints)
|
||||
.filter(joint => joint[1].jointType !== 'fixed')
|
||||
.map(joint => joint[0])
|
||||
|
||||
resolve(Result.ok([model, joints]))
|
||||
} catch (error) {
|
||||
resolve(Result.err('Failed to load model', error))
|
||||
if (typeof xml === 'string') {
|
||||
xml = new window.DOMParser().parseFromString(xml, 'text/xml')
|
||||
}
|
||||
})
|
||||
|
||||
return new Promise(resolve => {
|
||||
model_xml = xml
|
||||
try {
|
||||
const model = urdfLoader.parse(xml)
|
||||
setupRobot(model)
|
||||
const joints = Object.entries(model.joints)
|
||||
.filter(joint => joint[1].jointType !== 'fixed')
|
||||
.map(joint => joint[0])
|
||||
|
||||
resolve(Result.ok([model, joints]))
|
||||
} catch (error) {
|
||||
resolve(Result.err('Failed to load model', error))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const loadXacro = async (url: string): Promise<XMLDocument> =>
|
||||
new Promise((resolve, reject) => {
|
||||
new XacroLoader().load(url, resolve, reject)
|
||||
})
|
||||
new Promise((resolve, reject) => {
|
||||
new XacroLoader().load(url, resolve, reject)
|
||||
})
|
||||
|
||||
function setupRobot(robot: URDFRobot) {
|
||||
robot.rotation.x = -Math.PI / 2
|
||||
robot.rotation.z = Math.PI / 2
|
||||
robot.scale.setScalar(10)
|
||||
robot.traverse(c => (c.castShadow = true))
|
||||
robot.updateMatrixWorld(true)
|
||||
robot.rotation.x = -Math.PI / 2
|
||||
robot.rotation.z = Math.PI / 2
|
||||
robot.scale.setScalar(10)
|
||||
robot.traverse(c => (c.castShadow = true))
|
||||
robot.updateMatrixWorld(true)
|
||||
}
|
||||
|
||||
export function getToeWorldPositions(robot: URDFRobot): Vector3[] {
|
||||
const toes: Vector3[] = []
|
||||
robot.traverse(c => {
|
||||
if (c.name.includes('toe') && !c.name.includes('_link'))
|
||||
toes.push(c.getWorldPosition(new Vector3()))
|
||||
})
|
||||
return toes
|
||||
const toes: Vector3[] = []
|
||||
robot.traverse(c => {
|
||||
if (c.name.includes('toe') && !c.name.includes('_link'))
|
||||
toes.push(c.getWorldPosition(new Vector3()))
|
||||
})
|
||||
return toes
|
||||
}
|
||||
|
||||
export const extractFootColor = () => {
|
||||
const colorElem = model_xml.querySelector('material[name=foot_color] > color') as Element
|
||||
const colorAttrStr = colorElem.getAttribute('rgba') as string
|
||||
const colorStr = colorAttrStr
|
||||
.split(' ')
|
||||
.slice(0, 3)
|
||||
.map(val => Math.floor(+val * 255))
|
||||
.join(', ')
|
||||
const colorElem = model_xml.querySelector('material[name=foot_color] > color') as Element
|
||||
const colorAttrStr = colorElem.getAttribute('rgba') as string
|
||||
const colorStr = colorAttrStr
|
||||
.split(' ')
|
||||
.slice(0, 3)
|
||||
.map(val => Math.floor(+val * 255))
|
||||
.join(', ')
|
||||
|
||||
return new Color(`rgb(${colorStr})`)
|
||||
return new Color(`rgb(${colorStr})`)
|
||||
}
|
||||
|
||||
@@ -1,84 +1,86 @@
|
||||
class SunCalculator {
|
||||
calculateSunElevation(lat: number = 55, lon: number = 12) {
|
||||
const now = new Date();
|
||||
const JD = this.getJulianDate(now);
|
||||
const solarDec = this.getSolarDeclination(JD);
|
||||
const solarTime = this.getSolarTime(now, lon);
|
||||
calculateSunElevation(lat: number = 55, lon: number = 12) {
|
||||
const now = new Date()
|
||||
const JD = this.getJulianDate(now)
|
||||
const solarDec = this.getSolarDeclination(JD)
|
||||
const solarTime = this.getSolarTime(now, lon)
|
||||
|
||||
const hourAngle = (solarTime - 12) * 15;
|
||||
const elevation = Math.asin(
|
||||
Math.sin(this.degToRad(lat)) * Math.sin(solarDec) +
|
||||
Math.cos(this.degToRad(lat)) * Math.cos(solarDec) * Math.cos(this.degToRad(hourAngle))
|
||||
);
|
||||
const hourAngle = (solarTime - 12) * 15
|
||||
const elevation = Math.asin(
|
||||
Math.sin(this.degToRad(lat)) * Math.sin(solarDec) +
|
||||
Math.cos(this.degToRad(lat)) *
|
||||
Math.cos(solarDec) *
|
||||
Math.cos(this.degToRad(hourAngle))
|
||||
)
|
||||
|
||||
return this.radToDeg(elevation);
|
||||
}
|
||||
return this.radToDeg(elevation)
|
||||
}
|
||||
|
||||
getJulianDate(date: Date) {
|
||||
const Y = date.getUTCFullYear();
|
||||
const M = date.getUTCMonth() + 1;
|
||||
const D =
|
||||
date.getUTCDate() +
|
||||
date.getUTCHours() / 24 +
|
||||
date.getUTCMinutes() / 1440 +
|
||||
date.getUTCSeconds() / 86400;
|
||||
const A = Math.floor((14 - M) / 12);
|
||||
const Y1 = Y + 4800 - A;
|
||||
const M1 = M + 12 * A - 3;
|
||||
return (
|
||||
D +
|
||||
Math.floor((153 * M1 + 2) / 5) +
|
||||
365 * Y1 +
|
||||
Math.floor(Y1 / 4) -
|
||||
Math.floor(Y1 / 100) +
|
||||
Math.floor(Y1 / 400) -
|
||||
32045
|
||||
);
|
||||
}
|
||||
getJulianDate(date: Date) {
|
||||
const Y = date.getUTCFullYear()
|
||||
const M = date.getUTCMonth() + 1
|
||||
const D =
|
||||
date.getUTCDate() +
|
||||
date.getUTCHours() / 24 +
|
||||
date.getUTCMinutes() / 1440 +
|
||||
date.getUTCSeconds() / 86400
|
||||
const A = Math.floor((14 - M) / 12)
|
||||
const Y1 = Y + 4800 - A
|
||||
const M1 = M + 12 * A - 3
|
||||
return (
|
||||
D +
|
||||
Math.floor((153 * M1 + 2) / 5) +
|
||||
365 * Y1 +
|
||||
Math.floor(Y1 / 4) -
|
||||
Math.floor(Y1 / 100) +
|
||||
Math.floor(Y1 / 400) -
|
||||
32045
|
||||
)
|
||||
}
|
||||
|
||||
getSolarDeclination(JulianDate: number) {
|
||||
const n = JulianDate - 2451545;
|
||||
const L = (280.46 + 0.9856474 * n) % 360;
|
||||
const g = this.degToRad((357.528 + 0.9856003 * n) % 360);
|
||||
const lambda = this.degToRad(L + 1.915 * Math.sin(g) + 0.02 * Math.sin(2 * g));
|
||||
return Math.asin(Math.sin(lambda) * Math.sin(this.degToRad(23.44)));
|
||||
}
|
||||
getSolarDeclination(JulianDate: number) {
|
||||
const n = JulianDate - 2451545
|
||||
const L = (280.46 + 0.9856474 * n) % 360
|
||||
const g = this.degToRad((357.528 + 0.9856003 * n) % 360)
|
||||
const lambda = this.degToRad(L + 1.915 * Math.sin(g) + 0.02 * Math.sin(2 * g))
|
||||
return Math.asin(Math.sin(lambda) * Math.sin(this.degToRad(23.44)))
|
||||
}
|
||||
|
||||
getSolarTime(date: Date, lon: number) {
|
||||
const EoT = this.getEquationOfTime(date);
|
||||
const offset = date.getTimezoneOffset() / 60;
|
||||
const standardMeridian = Math.round(lon / 15) * 15;
|
||||
const solarTime =
|
||||
date.getUTCHours() +
|
||||
(date.getUTCMinutes() + (4 * (standardMeridian - lon) + EoT)) / 60 -
|
||||
offset;
|
||||
return (solarTime + 24) % 24;
|
||||
}
|
||||
getSolarTime(date: Date, lon: number) {
|
||||
const EoT = this.getEquationOfTime(date)
|
||||
const offset = date.getTimezoneOffset() / 60
|
||||
const standardMeridian = Math.round(lon / 15) * 15
|
||||
const solarTime =
|
||||
date.getUTCHours() +
|
||||
(date.getUTCMinutes() + (4 * (standardMeridian - lon) + EoT)) / 60 -
|
||||
offset
|
||||
return (solarTime + 24) % 24
|
||||
}
|
||||
|
||||
getEquationOfTime(date: Date) {
|
||||
const JD = this.getJulianDate(date);
|
||||
const n = JD - 2451545;
|
||||
const g = this.degToRad((357.528 + 0.9856003 * n) % 360);
|
||||
const q = this.degToRad((280.46 + 0.9856474 * n) % 360);
|
||||
return (
|
||||
4 *
|
||||
this.radToDeg(
|
||||
0.000075 +
|
||||
0.001868 * Math.cos(q) -
|
||||
0.032077 * Math.sin(g) -
|
||||
0.014615 * Math.cos(2 * q) -
|
||||
0.040849 * Math.sin(2 * g)
|
||||
)
|
||||
);
|
||||
}
|
||||
getEquationOfTime(date: Date) {
|
||||
const JD = this.getJulianDate(date)
|
||||
const n = JD - 2451545
|
||||
const g = this.degToRad((357.528 + 0.9856003 * n) % 360)
|
||||
const q = this.degToRad((280.46 + 0.9856474 * n) % 360)
|
||||
return (
|
||||
4 *
|
||||
this.radToDeg(
|
||||
0.000075 +
|
||||
0.001868 * Math.cos(q) -
|
||||
0.032077 * Math.sin(g) -
|
||||
0.014615 * Math.cos(2 * q) -
|
||||
0.040849 * Math.sin(2 * g)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
degToRad(deg: number) {
|
||||
return deg * (Math.PI / 180);
|
||||
}
|
||||
degToRad(deg: number) {
|
||||
return deg * (Math.PI / 180)
|
||||
}
|
||||
|
||||
radToDeg(rad: number) {
|
||||
return rad * (180 / Math.PI);
|
||||
}
|
||||
radToDeg(rad: number) {
|
||||
return rad * (180 / Math.PI)
|
||||
}
|
||||
}
|
||||
|
||||
export const sunCalculator = new SunCalculator();
|
||||
export const sunCalculator = new SunCalculator()
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
export class Err<T, U> {
|
||||
#inner: T;
|
||||
#exception?: U;
|
||||
#inner: T
|
||||
#exception?: U
|
||||
|
||||
constructor(inner: T, exception?: U) {
|
||||
this.#inner = inner;
|
||||
this.#exception = exception;
|
||||
}
|
||||
constructor(inner: T, exception?: U) {
|
||||
this.#inner = inner
|
||||
this.#exception = exception
|
||||
}
|
||||
|
||||
get inner(): T {
|
||||
return this.#inner;
|
||||
}
|
||||
get inner(): T {
|
||||
return this.#inner
|
||||
}
|
||||
|
||||
get exception(): U | undefined {
|
||||
return this.#exception;
|
||||
}
|
||||
get exception(): U | undefined {
|
||||
return this.#exception
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard for `Ok`
|
||||
* @returns `true` if `Ok`; `false` if `Err`
|
||||
*/
|
||||
isOk(): false {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Type guard for `Ok`
|
||||
* @returns `true` if `Ok`; `false` if `Err`
|
||||
*/
|
||||
isOk(): false {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard for `Err`
|
||||
* @returns `true` if `Err`; `false` if `Ok`
|
||||
*/
|
||||
isErr(): this is Err<T, U> {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Type guard for `Err`
|
||||
* @returns `true` if `Err`; `false` if `Ok`
|
||||
*/
|
||||
isErr(): this is Err<T, U> {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an `Err`
|
||||
* @param inner
|
||||
* @returns `Err(inner)`
|
||||
*/
|
||||
static new<E, F>(inner: E, exception: F): Err<E, F> {
|
||||
return new Err<E, F>(inner, exception);
|
||||
}
|
||||
/**
|
||||
* Create an `Err`
|
||||
* @param inner
|
||||
* @returns `Err(inner)`
|
||||
*/
|
||||
static new<E, F>(inner: E, exception: F): Err<E, F> {
|
||||
return new Err<E, F>(inner, exception)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * from './err';
|
||||
export * from './ok';
|
||||
export * from './result';
|
||||
export * from './err'
|
||||
export * from './ok'
|
||||
export * from './result'
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
export class Ok<T> {
|
||||
#inner: T;
|
||||
#inner: T
|
||||
|
||||
constructor(inner: T) {
|
||||
this.#inner = inner;
|
||||
}
|
||||
constructor(inner: T) {
|
||||
this.#inner = inner
|
||||
}
|
||||
|
||||
get inner(): T {
|
||||
return this.#inner;
|
||||
}
|
||||
get inner(): T {
|
||||
return this.#inner
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard for `Ok`
|
||||
* @returns `true` if `Ok`; `false` if `Err`
|
||||
*/
|
||||
isOk(): this is Ok<T> {
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Type guard for `Ok`
|
||||
* @returns `true` if `Ok`; `false` if `Err`
|
||||
*/
|
||||
isOk(): this is Ok<T> {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Type guard for `Err`
|
||||
* @returns `true` if `Err`; `false` if `Ok`
|
||||
*/
|
||||
isErr(): false {
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Type guard for `Err`
|
||||
* @returns `true` if `Err`; `false` if `Ok`
|
||||
*/
|
||||
isErr(): false {
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an `Ok`
|
||||
* @param inner
|
||||
* @returns `Ok(inner)`
|
||||
*/
|
||||
static new<T>(inner: T): Ok<T> {
|
||||
return new Ok<T>(inner);
|
||||
}
|
||||
/**
|
||||
* Create an `Ok`
|
||||
* @param inner
|
||||
* @returns `Ok(inner)`
|
||||
*/
|
||||
static new<T>(inner: T): Ok<T> {
|
||||
return new Ok<T>(inner)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an empty `Ok`
|
||||
* @returns `Ok(void)`
|
||||
*/
|
||||
static void(): Ok<void> {
|
||||
return new Ok(undefined);
|
||||
}
|
||||
/**
|
||||
* Create an empty `Ok`
|
||||
* @returns `Ok(void)`
|
||||
*/
|
||||
static void(): Ok<void> {
|
||||
return new Ok(undefined)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import { Err } from './err';
|
||||
import { Ok } from './ok';
|
||||
import { Err } from './err'
|
||||
import { Ok } from './ok'
|
||||
|
||||
export type Result<T = unknown, E = unknown, F = unknown> = Ok<T> | Err<E, F>;
|
||||
export type Result<T = unknown, E = unknown, F = unknown> = Ok<T> | Err<E, F>
|
||||
|
||||
export namespace Result {
|
||||
/**
|
||||
* @returns `Ok<T>`
|
||||
*/
|
||||
export function ok<T = unknown>(value: T) {
|
||||
return Ok.new(value);
|
||||
}
|
||||
/**
|
||||
* @returns `Ok<T>`
|
||||
*/
|
||||
export function ok<T = unknown>(value: T) {
|
||||
return Ok.new(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns `Err<E, F>`
|
||||
*/
|
||||
export function err<E = unknown, F = unknown>(error: E, exception?: F) {
|
||||
return Err.new(error, exception);
|
||||
}
|
||||
/**
|
||||
* @returns `Err<E, F>`
|
||||
*/
|
||||
export function err<E = unknown, F = unknown>(error: E, exception?: F) {
|
||||
return Err.new(error, exception)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
export const humanFileSize = (size: number): string => {
|
||||
const units = ['B', 'kB', 'MB', 'GB', 'TB']
|
||||
const i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024))
|
||||
return Number((size / Math.pow(1024, i)).toFixed(2)) * 1 + units[i]
|
||||
const units = ['B', 'kB', 'MB', 'GB', 'TB']
|
||||
const i = size == 0 ? 0 : Math.floor(Math.log(size) / Math.log(1024))
|
||||
return Number((size / Math.pow(1024, i)).toFixed(2)) * 1 + units[i]
|
||||
}
|
||||
|
||||
export const capitalize = (str: string): string => {
|
||||
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
|
||||
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()
|
||||
}
|
||||
|
||||
export const convertSeconds = (seconds: number) => {
|
||||
// Calculate the number of seconds, minutes, hours, and days
|
||||
let minutes = Math.floor(seconds / 60)
|
||||
let hours = Math.floor(minutes / 60)
|
||||
const days = Math.floor(hours / 24)
|
||||
// Calculate the number of seconds, minutes, hours, and days
|
||||
let minutes = Math.floor(seconds / 60)
|
||||
let hours = Math.floor(minutes / 60)
|
||||
const days = Math.floor(hours / 24)
|
||||
|
||||
// Calculate the remaining hours, minutes, and seconds
|
||||
hours = hours % 24
|
||||
minutes = minutes % 60
|
||||
seconds = seconds % 60
|
||||
// Calculate the remaining hours, minutes, and seconds
|
||||
hours = hours % 24
|
||||
minutes = minutes % 60
|
||||
seconds = seconds % 60
|
||||
|
||||
// Create the formatted string
|
||||
let result = ''
|
||||
if (days > 0) {
|
||||
result += days + ' day' + (days > 1 ? 's' : '') + ' '
|
||||
}
|
||||
if (hours > 0) {
|
||||
result += hours + ' hour' + (hours > 1 ? 's' : '') + ' '
|
||||
}
|
||||
if (minutes > 0) {
|
||||
result += minutes + ' minute' + (minutes > 1 ? 's' : '') + ' '
|
||||
}
|
||||
result += seconds + ' second' + (seconds > 1 ? 's' : '')
|
||||
// Create the formatted string
|
||||
let result = ''
|
||||
if (days > 0) {
|
||||
result += days + ' day' + (days > 1 ? 's' : '') + ' '
|
||||
}
|
||||
if (hours > 0) {
|
||||
result += hours + ' hour' + (hours > 1 ? 's' : '') + ' '
|
||||
}
|
||||
if (minutes > 0) {
|
||||
result += minutes + ' minute' + (minutes > 1 ? 's' : '') + ' '
|
||||
}
|
||||
result += seconds + ' second' + (seconds > 1 ? 's' : '')
|
||||
|
||||
return result
|
||||
return result
|
||||
}
|
||||
|
||||
export const compareIp = (ip1: string, ip2: string) => {
|
||||
const ip1Parts = ip1.split('.').map(Number)
|
||||
const ip2Parts = ip2.split('.').map(Number)
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if (ip1Parts[i] !== ip2Parts[i]) {
|
||||
return ip1Parts[i] > ip2Parts[i] ? 1 : -1
|
||||
const ip1Parts = ip1.split('.').map(Number)
|
||||
const ip2Parts = ip2.split('.').map(Number)
|
||||
for (let i = 0; i < 4; i++) {
|
||||
if (ip1Parts[i] !== ip2Parts[i]) {
|
||||
return ip1Parts[i] > ip2Parts[i] ? 1 : -1
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { writable } from 'svelte/store';
|
||||
import { browser } from '$app/environment';
|
||||
import { writable } from 'svelte/store'
|
||||
import { browser } from '$app/environment'
|
||||
|
||||
export const persistentStore = <T>(key: string, initialValue: T) => {
|
||||
const savedValue = browser ? localStorage.getItem(key) : null;
|
||||
const data: T = savedValue !== null ? JSON.parse(savedValue) : initialValue;
|
||||
const store = writable<T>();
|
||||
const savedValue = browser ? localStorage.getItem(key) : null
|
||||
const data: T = savedValue !== null ? JSON.parse(savedValue) : initialValue
|
||||
const store = writable<T>()
|
||||
|
||||
store.subscribe(value => {
|
||||
if (browser) localStorage.setItem(key, JSON.stringify(value));
|
||||
});
|
||||
store.subscribe(value => {
|
||||
if (browser) localStorage.setItem(key, JSON.stringify(value))
|
||||
})
|
||||
|
||||
store.set(data);
|
||||
store.set(data)
|
||||
|
||||
return store;
|
||||
};
|
||||
return store
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user