/
45case
/
ptable
Обзор
Документация
Войти
/
45case
/
ptable
Код
Запросы
3
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
dev
src/entities/element/api/getElementProperties.ts
418 строк
12 KB
Olya
Страница Электроны + сайдбар с характеритстиками (Степень окисления, Конфигурация, Развёрнутая, Уровни энергии, ВЗМО)
24 июл 2026, 11:54
24 июл 2026, 11:54
3cf1d48
Код
Авторство
О чём код?
import ptablePropertiesJson from "./ptable-properties.json"; export type AtomicRadiusKind = "calculated" | "empirical" | "covalent" | "vanderwaals"; export type HardnessKind = "brinell" | "mohs" | "vickers"; export type ModulusKind = "bulk" | "shear" | "young"; export type DensityKind = "stp" | "liquid"; export type ConductivityKind = "thermal" | "electric"; export type HeatKind = "specific" | "vaporization" | "fusion"; export type AbundanceKind = | "universe" | "solar" | "meteor" | "crust" | "ocean" | "human"; export interface ElementPhysicalProperties { /** Abundance by environment, mass % (ptable `abundance`). */ abundanceByKind: Readonly<Partial<Record<AbundanceKind, number>>>; /** Convenience: universe abundance. */ abundanceUniversePercent: number | null; atomicMass: number | null; /** Raw ptable `weight` string (for display abridgment). */ atomicMassWeight: string | null; atomicNumber: number; boilingPointKelvin: number | null; /** Conductivity by kind: thermal W/(m·K), electric MS/m. */ conductivityByKind: Readonly<Partial<Record<ConductivityKind, number>>>; /** Convenience: thermal conductivity. */ thermalConductivityWmK: number | null; /** Density in kg/m³ by kind (ptable `density`). */ densitiesKgM3: Readonly<Partial<Record<DensityKind, number>>>; /** Convenience: STP density. */ densityStpKgM3: number | null; discoveredYear: number | null; electronAffinityKJmol: number | null; electronegativityPauling: number | null; electronsPerShell: number[]; /** Heat by kind: specific J/(kg·K); vaporization/fusion kJ/mol. */ heatByKind: Readonly<Partial<Record<HeatKind, number>>>; /** Convenience: specific heat. */ specificHeatJkgK: number | null; /** Ionization energies by order (1–30), kJ/mol. */ ionizationEnergiesKJmol: Readonly<Record<number, number>>; /** Convenience: 1st ionization energy. */ firstIonizationEnergyKJmol: number | null; /** Hardness by scale (ptable `hardness`; Brinell/Vickers in MPa). */ hardnessByKind: Readonly<Partial<Record<HardnessKind, number>>>; /** Convenience: Brinell hardness. */ hardnessBrinellMPa: number | null; meltingPointKelvin: number | null; /** Elastic moduli in GPa by kind (ptable `modulus`). */ moduliGPa: Readonly<Partial<Record<ModulusKind, number>>>; /** Convenience: bulk modulus. */ modulusBulkGPa: number | null; /** Atomic radii in pm by kind (ptable `radius`). */ radiiPm: Readonly<Partial<Record<AtomicRadiusKind, number>>>; /** Convenience: calculated radius. */ radiusCalculatedPm: number | null; symbol: string; } /** Raw element record shape from ptable `properties.json` (index = atomic number). */ type PtableElementRecord = { abundance?: Partial<Record<AbundanceKind, string>>; affinity?: string; atomic?: string; boil?: string; conductivity?: Partial<Record<ConductivityKind, string>>; density?: Partial<Record<DensityKind, string>>; discover?: string; electroneg?: string; electrons?: number[]; hardness?: Partial<Record<HardnessKind, string>>; heat?: Partial<Record<HeatKind, string>>; ionize?: Record<string, string>; melt?: string; modulus?: Partial<Record<ModulusKind, string>>; radius?: Partial<Record<AtomicRadiusKind, string>>; symbol?: string; weight?: string; }; function parseOptionalNumber(value: string | undefined): number | null { if (value == null || value === "") { return null; } const parsed = Number(value); return Number.isFinite(parsed) ? parsed : null; } /** Parse ptable `ionize` map (`"1"`…`"30"` → kJ/mol). */ function parseIonizationEnergies( ionize: Record<string, string> | undefined, ): Record<number, number> { const result: Record<number, number> = {}; if (!ionize) { return result; } for (const [key, raw] of Object.entries(ionize)) { const order = Number(key); const value = parseOptionalNumber(raw); if (Number.isInteger(order) && order >= 1 && order <= 30 && value != null) { result[order] = value; } } return result; } export function getIonizationEnergyKJmol( properties: ElementPhysicalProperties | null | undefined, order: number, ): number | null { if (!properties || !Number.isInteger(order) || order < 1 || order > 30) { return null; } return properties.ionizationEnergiesKJmol[order] ?? null; } const ATOMIC_RADIUS_KINDS: readonly AtomicRadiusKind[] = [ "calculated", "empirical", "covalent", "vanderwaals", ]; function parseRadiiPm( radius: Partial<Record<AtomicRadiusKind, string>> | undefined, ): Partial<Record<AtomicRadiusKind, number>> { const result: Partial<Record<AtomicRadiusKind, number>> = {}; if (!radius) { return result; } for (const kind of ATOMIC_RADIUS_KINDS) { const value = parseOptionalNumber(radius[kind]); if (value != null) { result[kind] = value; } } return result; } export function getAtomicRadiusPm( properties: ElementPhysicalProperties | null | undefined, kind: AtomicRadiusKind, ): number | null { if (!properties) { return null; } return properties.radiiPm[kind] ?? null; } const HARDNESS_KINDS: readonly HardnessKind[] = ["brinell", "mohs", "vickers"]; function parseHardnessByKind( hardness: Partial<Record<HardnessKind, string>> | undefined, ): Partial<Record<HardnessKind, number>> { const result: Partial<Record<HardnessKind, number>> = {}; if (!hardness) { return result; } for (const kind of HARDNESS_KINDS) { const value = parseOptionalNumber(hardness[kind]); if (value != null) { result[kind] = value; } } return result; } export function getHardnessValue( properties: ElementPhysicalProperties | null | undefined, kind: HardnessKind, ): number | null { if (!properties) { return null; } return properties.hardnessByKind[kind] ?? null; } const MODULUS_KINDS: readonly ModulusKind[] = ["bulk", "shear", "young"]; function parseModuliGPa( modulus: Partial<Record<ModulusKind, string>> | undefined, ): Partial<Record<ModulusKind, number>> { const result: Partial<Record<ModulusKind, number>> = {}; if (!modulus) { return result; } for (const kind of MODULUS_KINDS) { const value = parseOptionalNumber(modulus[kind]); if (value != null) { result[kind] = value; } } return result; } export function getModulusGPa( properties: ElementPhysicalProperties | null | undefined, kind: ModulusKind, ): number | null { if (!properties) { return null; } return properties.moduliGPa[kind] ?? null; } const DENSITY_KINDS: readonly DensityKind[] = ["stp", "liquid"]; function parseDensitiesKgM3( density: Partial<Record<DensityKind, string>> | undefined, ): Partial<Record<DensityKind, number>> { const result: Partial<Record<DensityKind, number>> = {}; if (!density) { return result; } for (const kind of DENSITY_KINDS) { const value = parseOptionalNumber(density[kind]); if (value != null) { result[kind] = value; } } return result; } export function getDensityKgM3( properties: ElementPhysicalProperties | null | undefined, kind: DensityKind, ): number | null { if (!properties) { return null; } return properties.densitiesKgM3[kind] ?? null; } const CONDUCTIVITY_KINDS: readonly ConductivityKind[] = ["thermal", "electric"]; function parseConductivityByKind( conductivity: Partial<Record<ConductivityKind, string>> | undefined, ): Partial<Record<ConductivityKind, number>> { const result: Partial<Record<ConductivityKind, number>> = {}; if (!conductivity) { return result; } for (const kind of CONDUCTIVITY_KINDS) { const value = parseOptionalNumber(conductivity[kind]); if (value != null) { result[kind] = value; } } return result; } export function getConductivityValue( properties: ElementPhysicalProperties | null | undefined, kind: ConductivityKind, ): number | null { if (!properties) { return null; } return properties.conductivityByKind[kind] ?? null; } const HEAT_KINDS: readonly HeatKind[] = ["specific", "vaporization", "fusion"]; function parseHeatByKind( heat: Partial<Record<HeatKind, string>> | undefined, ): Partial<Record<HeatKind, number>> { const result: Partial<Record<HeatKind, number>> = {}; if (!heat) { return result; } for (const kind of HEAT_KINDS) { const value = parseOptionalNumber(heat[kind]); if (value != null) { result[kind] = value; } } return result; } export function getHeatValue( properties: ElementPhysicalProperties | null | undefined, kind: HeatKind, ): number | null { if (!properties) { return null; } return properties.heatByKind[kind] ?? null; } const ABUNDANCE_KINDS: readonly AbundanceKind[] = [ "universe", "solar", "meteor", "crust", "ocean", "human", ]; function parseAbundanceByKind( abundance: Partial<Record<AbundanceKind, string>> | undefined, ): Partial<Record<AbundanceKind, number>> { const result: Partial<Record<AbundanceKind, number>> = {}; if (!abundance) { return result; } for (const kind of ABUNDANCE_KINDS) { const value = parseOptionalNumber(abundance[kind]); if (value != null) { result[kind] = value; } } return result; } export function getAbundanceValue( properties: ElementPhysicalProperties | null | undefined, kind: AbundanceKind, ): number | null { if (!properties) { return null; } return properties.abundanceByKind[kind] ?? null; } function mapPtableRecord(record: PtableElementRecord): ElementPhysicalProperties | null { const atomicNumber = parseOptionalNumber(record.atomic); if (atomicNumber == null || !record.symbol) { return null; } const ionizationEnergiesKJmol = parseIonizationEnergies(record.ionize); const radiiPm = parseRadiiPm(record.radius); const hardnessByKind = parseHardnessByKind(record.hardness); const moduliGPa = parseModuliGPa(record.modulus); const densitiesKgM3 = parseDensitiesKgM3(record.density); const conductivityByKind = parseConductivityByKind(record.conductivity); const heatByKind = parseHeatByKind(record.heat); const abundanceByKind = parseAbundanceByKind(record.abundance); return { abundanceByKind, abundanceUniversePercent: abundanceByKind.universe ?? null, atomicMass: parseOptionalNumber(record.weight), atomicMassWeight: record.weight?.trim() ? record.weight.trim() : null, atomicNumber, boilingPointKelvin: parseOptionalNumber(record.boil), conductivityByKind, thermalConductivityWmK: conductivityByKind.thermal ?? null, densitiesKgM3, densityStpKgM3: densitiesKgM3.stp ?? null, discoveredYear: parseOptionalNumber(record.discover), electronAffinityKJmol: parseOptionalNumber(record.affinity), electronegativityPauling: parseOptionalNumber(record.electroneg), electronsPerShell: Array.isArray(record.electrons) ? record.electrons : [], heatByKind, specificHeatJkgK: heatByKind.specific ?? null, ionizationEnergiesKJmol, firstIonizationEnergyKJmol: ionizationEnergiesKJmol[1] ?? null, hardnessByKind, hardnessBrinellMPa: hardnessByKind.brinell ?? null, meltingPointKelvin: parseOptionalNumber(record.melt), moduliGPa, modulusBulkGPa: moduliGPa.bulk ?? null, radiiPm, radiusCalculatedPm: radiiPm.calculated ?? null, symbol: record.symbol, }; } const records = (ptablePropertiesJson as PtableElementRecord[]) .map(mapPtableRecord) .filter((item): item is ElementPhysicalProperties => item != null); const byAtomicNumber = new Map(records.map((item) => [item.atomicNumber, item])); export function getElementPropertiesByAtomicNumber( atomicNumber: number, ): ElementPhysicalProperties | null { return byAtomicNumber.get(atomicNumber) ?? null; } export function getAllElementProperties(): readonly ElementPhysicalProperties[] { return records; }