feat(conversion): add unit and currency conversion systems with UnitConverter, UnitDefinitions, CurrencyConverter, and ExchangeRateService
This commit is contained in:
@@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* Currency converter for the scientific calculator
|
||||||
|
* Handles conversion between currencies using predefined exchange rates.
|
||||||
|
* Uses ExchangeRateService to get the rates.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const ExchangeRateService = require('./ExchangeRateService');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a value from one currency to another.
|
||||||
|
* @param {number} value - The value to convert.
|
||||||
|
* @param {string} fromCurrency - The currency code to convert from (e.g., 'USD').
|
||||||
|
* @param {string} toCurrency - The currency code to convert to (e.g., 'EUR').
|
||||||
|
* @returns {{value: number, error: string|null}} - Result object with either the converted value or an error.
|
||||||
|
*/
|
||||||
|
function convert(value, fromCurrency, toCurrency) {
|
||||||
|
// Validate input value
|
||||||
|
if (typeof value !== 'number' || isNaN(value)) {
|
||||||
|
return { value: null, error: 'Invalid value: must be a number' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate currency codes (must be 3 uppercase letters)
|
||||||
|
const currencyCodeRegex = /^[A-Z]{3}$/;
|
||||||
|
if (!currencyCodeRegex.test(fromCurrency)) {
|
||||||
|
return { value: null, error: `Invalid fromCurrency code: ${fromCurrency}. Must be a 3-letter uppercase code (e.g., USD).` };
|
||||||
|
}
|
||||||
|
if (!currencyCodeRegex.test(toCurrency)) {
|
||||||
|
return { value: null, error: `Invalid toCurrency code: ${toCurrency}. Must be a 3-letter uppercase code (e.g., EUR).` };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the exchange rates
|
||||||
|
const rates = ExchangeRateService.getRates();
|
||||||
|
const fromRate = rates[fromCurrency];
|
||||||
|
const toRate = rates[toCurrency];
|
||||||
|
|
||||||
|
if (fromRate === undefined) {
|
||||||
|
return { value: null, error: `Exchange rate for ${fromCurrency} not available.` };
|
||||||
|
}
|
||||||
|
if (toRate === undefined) {
|
||||||
|
return { value: null, error: `Exchange rate for ${toCurrency} not available.` };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid division by zero
|
||||||
|
if (fromRate === 0) {
|
||||||
|
return { value: null, error: 'Cannot convert from a currency with zero rate.' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion: value in target currency = value * (toRate / fromRate)
|
||||||
|
// Explanation: If we have 1 USD = 0.9 EUR, then rates: { USD: 1, EUR: 0.9 } (assuming base is USD?).
|
||||||
|
// Actually, we store rates as: 1 unit of currency = rate units of base currency.
|
||||||
|
// Let's define: we have a base currency (e.g., USD) and rates are the value of 1 unit of that currency in base.
|
||||||
|
// Then to convert from currency A to currency B:
|
||||||
|
// value_in_base = value * rate[A]
|
||||||
|
// value_in_target = value_in_base / rate[B]
|
||||||
|
// So: result = value * (rate[A] / rate[B])
|
||||||
|
// However, note that in our ExchangeRateService, we store the rate as the amount of base currency per unit of the currency.
|
||||||
|
// For example, if base is USD, then rate for EUR is 0.9 (meaning 1 EUR = 0.9 USD).
|
||||||
|
// Then to convert 100 EUR to USD: 100 * 0.9 = 90 USD.
|
||||||
|
// To convert 100 USD to EUR: 100 * (1 / 0.9) = 111.11 EUR.
|
||||||
|
// So the formula is: result = value * (rate[from] / rate[to])
|
||||||
|
|
||||||
|
const result = value * (fromRate / toRate);
|
||||||
|
return { value: result, error: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
convert,
|
||||||
|
};
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
/**
|
||||||
|
* Exchange rate service for the scientific calculator
|
||||||
|
* Manages currency exchange rates with timestamps in localStorage.
|
||||||
|
* Designed to run in a browser environment.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Default exchange rates (1 unit of currency = X USD)
|
||||||
|
// These are example rates and should be updated by the user
|
||||||
|
const DEFAULT_RATES = {
|
||||||
|
USD: 1.0, // US Dollar
|
||||||
|
EUR: 0.9, // Euro
|
||||||
|
GBP: 0.75, // British Pound
|
||||||
|
JPY: 0.007, // Japanese Yen
|
||||||
|
CAD: 0.75, // Canadian Dollar
|
||||||
|
AUD: 0.7, // Australian Dollar
|
||||||
|
INR: 0.012 // Indian Rupee
|
||||||
|
};
|
||||||
|
|
||||||
|
// How long until rates are considered stale (in milliseconds)
|
||||||
|
// 24 hours = 24 * 60 * 60 * 1000 = 86,400,000 ms
|
||||||
|
const STALE_THRESHOLD = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
// Key for storing rates in localStorage
|
||||||
|
const STORAGE_KEY = 'calculator_exchange_rates';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the exchange rates object from localStorage.
|
||||||
|
* @returns {Object|null} The rates object (with rates and timestamp) or null if not found/invalid.
|
||||||
|
*/
|
||||||
|
function _loadFromStorage() {
|
||||||
|
try {
|
||||||
|
const stored = localStorage.getItem(STORAGE_KEY);
|
||||||
|
if (stored === null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const parsed = JSON.parse(stored);
|
||||||
|
// Validate the structure
|
||||||
|
if (parsed && typeof parsed === 'object' &&
|
||||||
|
parsed.rates && typeof parsed.rates === 'object' &&
|
||||||
|
typeof parsed.timestamp === 'number') {
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (e) {
|
||||||
|
// If there's any error (e.g., invalid JSON), return null
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the exchange rates object to localStorage.
|
||||||
|
* @param {Object} ratesObj - The rates object to save (should have rates and timestamp).
|
||||||
|
*/
|
||||||
|
function _saveToStorage(ratesObj) {
|
||||||
|
try {
|
||||||
|
const toStore = {
|
||||||
|
rates: ratesObj.rates,
|
||||||
|
timestamp: ratesObj.timestamp
|
||||||
|
};
|
||||||
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(toStore));
|
||||||
|
} catch (e) {
|
||||||
|
// In a real app, you might want to log this error
|
||||||
|
console.warn('Failed to save exchange rates to localStorage:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the exchange rate for a given currency.
|
||||||
|
* @param {string} currency - The currency code (e.g., 'USD').
|
||||||
|
* @returns {number|null} The rate (amount of USD per unit of currency) or null if not found.
|
||||||
|
*/
|
||||||
|
function getRate(currency) {
|
||||||
|
if (typeof currency !== 'string' || currency.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stored = _loadFromStorage();
|
||||||
|
let rates = null;
|
||||||
|
|
||||||
|
if (stored === null) {
|
||||||
|
// No stored rates, use defaults and save them
|
||||||
|
rates = { ...DEFAULT_RATES };
|
||||||
|
_saveToStorage({ rates, timestamp: Date.now() });
|
||||||
|
} else {
|
||||||
|
rates = stored.rates;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rates[currency] !== undefined ? rates[currency] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the exchange rate for a given currency.
|
||||||
|
* @param {string} currency - The currency code (e.g., 'USD').
|
||||||
|
* @param {number} rate - The rate (amount of USD per unit of currency).
|
||||||
|
*/
|
||||||
|
function setRate(currency, rate) {
|
||||||
|
if (typeof currency !== 'string' || currency.length === 0 ||
|
||||||
|
typeof rate !== 'number' || isNaN(rate)) {
|
||||||
|
return; // Invalid input, do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
const stored = _loadFromStorage();
|
||||||
|
let rates = {};
|
||||||
|
|
||||||
|
if (stored !== null) {
|
||||||
|
rates = { ...stored.rates };
|
||||||
|
} else {
|
||||||
|
rates = { ...DEFAULT_RATES }; // Start with defaults if none stored
|
||||||
|
}
|
||||||
|
|
||||||
|
rates[currency] = rate;
|
||||||
|
_saveToStorage({ rates, timestamp: Date.now() });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a copy of the current exchange rates object.
|
||||||
|
* @returns {Object} A copy of the rates object (currency code -> rate).
|
||||||
|
*/
|
||||||
|
function getRates() {
|
||||||
|
const stored = _loadFromStorage();
|
||||||
|
if (stored === null) {
|
||||||
|
// Return a copy of the default rates
|
||||||
|
return { ...DEFAULT_RATES };
|
||||||
|
}
|
||||||
|
// Return a copy of the stored rates
|
||||||
|
return { ...stored.rates };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the stored rates are considered stale.
|
||||||
|
* @returns {boolean} True if no rates are stored or if they are older than STALE_THRESHOLD.
|
||||||
|
*/
|
||||||
|
function isRateStale() {
|
||||||
|
const stored = _loadFromStorage();
|
||||||
|
if (stored === null) {
|
||||||
|
return true; // No rates stored
|
||||||
|
}
|
||||||
|
const age = Date.now() - stored.timestamp;
|
||||||
|
return age > STALE_THRESHOLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the timestamp of the last update (in milliseconds since epoch).
|
||||||
|
* @returns {number|null} The timestamp or null if no rates stored.
|
||||||
|
*/
|
||||||
|
function getLastUpdatedTimestamp() {
|
||||||
|
const stored = _loadFromStorage();
|
||||||
|
return stored !== null ? stored.timestamp : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a human-readable string indicating how long ago the rates were updated.
|
||||||
|
* @returns {string} A string like "Updated 5 minutes ago" or "Never updated".
|
||||||
|
*/
|
||||||
|
function getTimeSinceUpdate() {
|
||||||
|
const timestamp = getLastUpdatedTimestamp();
|
||||||
|
if (timestamp === null) {
|
||||||
|
return 'Never updated';
|
||||||
|
}
|
||||||
|
|
||||||
|
const diffMs = Date.now() - timestamp;
|
||||||
|
const diffSec = Math.round(diffMs / 1000);
|
||||||
|
const diffMin = Math.round(diffSec / 60);
|
||||||
|
const diffHours = Math.round(diffMin / 60);
|
||||||
|
const diffDays = Math.round(diffHours / 24);
|
||||||
|
|
||||||
|
if (diffSec < 5) {
|
||||||
|
return 'Just now';
|
||||||
|
} else if (diffSec < 60) {
|
||||||
|
return `${diffSec} seconds ago`;
|
||||||
|
} else if (diffMin < 60) {
|
||||||
|
return `${diffMin} minutes ago`;
|
||||||
|
} else if (diffHours < 24) {
|
||||||
|
return `${diffHours} hours ago`;
|
||||||
|
} else {
|
||||||
|
return `${diffDays} days ago`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the exchange rates to the default values.
|
||||||
|
* This is useful for testing or if the user wants to revert to defaults.
|
||||||
|
*/
|
||||||
|
function resetToDefaults() {
|
||||||
|
_saveToStorage({
|
||||||
|
rates: { ...DEFAULT_RATES },
|
||||||
|
timestamp: Date.now()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getRate,
|
||||||
|
setRate,
|
||||||
|
getRates,
|
||||||
|
isRateStale,
|
||||||
|
getLastUpdatedTimestamp,
|
||||||
|
getTimeSinceUpdate,
|
||||||
|
resetToDefaults
|
||||||
|
};
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
/**
|
||||||
|
* Unit converter for the scientific calculator
|
||||||
|
* Handles conversion between units within the same category.
|
||||||
|
* Uses predefined conversion factors from UnitDefinitions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const UnitDefinitions = require('./UnitDefinitions');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a value from one unit to another within the same category.
|
||||||
|
* @param {number} value - The value to convert.
|
||||||
|
* @param {string} fromUnit - The unit to convert from.
|
||||||
|
* @param {string} toUnit - The unit to convert to.
|
||||||
|
* @param {string} category - The category of the units (optional, will be inferred if not provided).
|
||||||
|
* @returns {{value: number, error: string|null}} - Result object with either the converted value or an error.
|
||||||
|
*/
|
||||||
|
function convert(value, fromUnit, toUnit, category) {
|
||||||
|
// Validate input value
|
||||||
|
if (typeof value !== 'number' || isNaN(value)) {
|
||||||
|
return { value: null, error: 'Invalid value: must be a number' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate unit strings
|
||||||
|
if (typeof fromUnit !== 'string' || typeof toUnit !== 'string') {
|
||||||
|
return { value: null, error: 'Invalid unit: must be a string' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine category if not provided
|
||||||
|
let cat = category;
|
||||||
|
if (!cat) {
|
||||||
|
cat = getCategoryForUnit(fromUnit);
|
||||||
|
if (!cat || getCategoryForUnit(toUnit) !== cat) {
|
||||||
|
return { value: null, error: 'Units are not in the same category or are invalid' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the unit definitions for the category
|
||||||
|
const categoryDefs = UnitDefinitions[cat];
|
||||||
|
if (!categoryDefs) {
|
||||||
|
return { value: null, error: `Unknown category: ${cat}` };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the definitions for the specific units
|
||||||
|
const fromDef = categoryDefs[fromUnit];
|
||||||
|
const toDef = categoryDefs[toUnit];
|
||||||
|
|
||||||
|
if (!fromDef || !toDef) {
|
||||||
|
return { value: null, error: `One or both units (${fromUnit}, ${toUnit}) not found in category ${cat}` };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle temperature conversions (which have a different structure)
|
||||||
|
if (fromDef.type === 'temperature' || toDef.type === 'temperature') {
|
||||||
|
return convertTemperature(value, fromDef, toDef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For non-temperature units, we use the factor method
|
||||||
|
// The factor is the multiplier to get to the base unit.
|
||||||
|
// So: value in base unit = value * fromFactor
|
||||||
|
// Then: value in target unit = (value in base unit) / toFactor
|
||||||
|
// Therefore: result = value * (fromFactor / toFactor)
|
||||||
|
const fromFactor = fromDef;
|
||||||
|
const toFactor = toDef;
|
||||||
|
|
||||||
|
// Avoid division by zero
|
||||||
|
if (toFactor === 0) {
|
||||||
|
return { value: null, error: 'Cannot convert to a unit with zero factor' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = value * (fromFactor / toFactor);
|
||||||
|
return { value: result, error: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to convert between temperature units.
|
||||||
|
* @param {number} value - The value to convert.
|
||||||
|
* @param {Object} fromDef - The definition of the source unit (from UnitDefinitions).
|
||||||
|
* @param {Object} toDef - The definition of the target unit (from UnitDefinitions).
|
||||||
|
* @returns {{value: number, error: string|null}} - Result object.
|
||||||
|
*/
|
||||||
|
function convertTemperature(value, fromDef, toDef) {
|
||||||
|
// First, convert the input value to Kelvin
|
||||||
|
let kelvin;
|
||||||
|
if (fromDef.type === 'temperature') {
|
||||||
|
if (fromDef.offset !== undefined) {
|
||||||
|
// For Celsius and Fahrenheit, we have an offset
|
||||||
|
if (fromDef.factor !== undefined) {
|
||||||
|
// Fahrenheit: K = (F + 459.67) * 5/9
|
||||||
|
kelvin = (value + fromDef.offset) * fromDef.factor;
|
||||||
|
} else {
|
||||||
|
// Celsius: K = C + 273.15
|
||||||
|
kelvin = value + fromDef.offset;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Kelvin: already in Kelvin
|
||||||
|
kelvin = value;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This should not happen if we check the type correctly
|
||||||
|
return { value: null, error: 'Internal error: invalid temperature unit definition' };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now convert from Kelvin to the target unit
|
||||||
|
let result;
|
||||||
|
if (toDef.type === 'temperature') {
|
||||||
|
if (toDef.offset !== undefined) {
|
||||||
|
if (toDef.factor !== undefined) {
|
||||||
|
// Fahrenheit: F = (K * 9/5) - 459.67
|
||||||
|
result = (kelvin / toDef.factor) - toDef.offset;
|
||||||
|
} else {
|
||||||
|
// Celsius: C = K - 273.15
|
||||||
|
result = kelvin - toDef.offset;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Kelvin: already in Kelvin
|
||||||
|
result = kelvin;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This should not happen
|
||||||
|
return { value: null, error: 'Internal error: invalid temperature unit definition' };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { value: result, error: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function to determine the category of a unit.
|
||||||
|
* @param {string} unit - The unit string.
|
||||||
|
* @returns {string|null} The category name, or null if not found.
|
||||||
|
*/
|
||||||
|
function getCategoryForUnit(unit) {
|
||||||
|
for (const category in UnitDefinitions) {
|
||||||
|
if (UnitDefinitions[category].hasOwnProperty(unit)) {
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all available units and their categories.
|
||||||
|
* @returns {Object} An object mapping categories to arrays of unit strings.
|
||||||
|
*/
|
||||||
|
function getAllUnits() {
|
||||||
|
const result = {};
|
||||||
|
for (const category in UnitDefinitions) {
|
||||||
|
result[category] = Object.keys(UnitDefinitions[category]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
convert,
|
||||||
|
getAllUnits,
|
||||||
|
};
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
/**
|
||||||
|
* Unit definitions and conversion factors for the scientific calculator
|
||||||
|
* Each unit is defined by its factor relative to a base unit in its category.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const UnitDefinitions = {
|
||||||
|
// Electrical
|
||||||
|
electrical: {
|
||||||
|
// Voltage
|
||||||
|
V: 1, // Volt
|
||||||
|
mV: 1e-3, // Millivolt
|
||||||
|
kV: 1e3, // Kilovolt
|
||||||
|
μV: 1e-6, // Microvolt
|
||||||
|
// Current
|
||||||
|
A: 1, // Ampere
|
||||||
|
mA: 1e-3, // Milliampere
|
||||||
|
μA: 1e-6, // Microampere
|
||||||
|
nA: 1e-9, // Nanoampere
|
||||||
|
// Resistance
|
||||||
|
Ω: 1, // Ohm
|
||||||
|
kΩ: 1e3, // Kiloohm
|
||||||
|
MΩ: 1e6, // Megaohm
|
||||||
|
// Capacitance
|
||||||
|
F: 1, // Farad
|
||||||
|
μF: 1e-6, // Microfarad
|
||||||
|
pF: 1e-12, // Picofarad
|
||||||
|
nF: 1e-9, // Nanofarad
|
||||||
|
// Power
|
||||||
|
W: 1, // Watt
|
||||||
|
kW: 1e3, // Kilowatt
|
||||||
|
MW: 1e6, // Megawatt
|
||||||
|
// Energy
|
||||||
|
J: 1, // Joule
|
||||||
|
kWh: 3.6e6, // Kilowatt-hour
|
||||||
|
Wh: 3600, // Watt-hour
|
||||||
|
// Charge
|
||||||
|
C: 1, // Coulomb
|
||||||
|
Ah: 3600, // Ampere-hour
|
||||||
|
mAh: 3.6, // Milliampere-hour
|
||||||
|
},
|
||||||
|
|
||||||
|
// Mechanical
|
||||||
|
mechanical: {
|
||||||
|
// Force
|
||||||
|
N: 1, // Newton
|
||||||
|
kN: 1e3, // Kilonewton
|
||||||
|
// Mass/force
|
||||||
|
kgf: 9.80665, // Kilogram-force (standard gravity)
|
||||||
|
lbf: 4.44822, // Pound-force
|
||||||
|
// Pressure
|
||||||
|
Pa: 1, // Pascal
|
||||||
|
kPa: 1e3, // Kilopascal
|
||||||
|
MPa: 1e6, // Megapascal
|
||||||
|
bar: 1e5, // Bar
|
||||||
|
psi: 6894.76, // Pound per square inch
|
||||||
|
// Velocity
|
||||||
|
'm/s': 1, // Meter per second
|
||||||
|
'km/h': 1/3.6, // Kilometer per hour
|
||||||
|
mph: 0.44704, // Mile per hour
|
||||||
|
// Acceleration
|
||||||
|
'm/s²': 1, // Meter per second squared
|
||||||
|
g: 9.80665, // Standard gravity
|
||||||
|
// Torque
|
||||||
|
'Nm': 1, // Newton meter
|
||||||
|
'ft·lb': 1.35582, // Foot-pound
|
||||||
|
// Frequency
|
||||||
|
Hz: 1, // Hertz
|
||||||
|
RPM: 1/60, // Revolutions per minute (to Hz)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Thermal
|
||||||
|
thermal: {
|
||||||
|
// Temperature (special handling required)
|
||||||
|
K: { type: 'temperature', offset: 0 }, // Kelvin
|
||||||
|
°C: { type: 'temperature', offset: 273.15 }, // Celsius
|
||||||
|
°F: { type: 'temperature', offset: 459.67, factor: 5/9 }, // Fahrenheit
|
||||||
|
// Specific heat
|
||||||
|
'J/(kg·K)': 1, // Joule per kilogram Kelvin
|
||||||
|
'J/(g·°C)': 1, // Same as above (since 1 g = 0.001 kg and 1°C change = 1 K change)
|
||||||
|
// Thermal conductivity
|
||||||
|
'W/(m·K)': 1, // Watt per meter Kelvin
|
||||||
|
// Power (same as electrical)
|
||||||
|
W: 1, // Watt
|
||||||
|
kW: 1e3, // Kilowatt
|
||||||
|
},
|
||||||
|
|
||||||
|
// Volume
|
||||||
|
volume: {
|
||||||
|
L: 1, // Liter
|
||||||
|
mL: 1e-3, // Milliliter
|
||||||
|
μL: 1e-6, // Microliter
|
||||||
|
cm³: 1e-3, // Cubic centimeter (1 mL)
|
||||||
|
in³: 1.63871e-5, // Cubic inch
|
||||||
|
ft³: 0.0283168, // Cubic foot
|
||||||
|
tsp: 4.92892e-3, // Teaspoon
|
||||||
|
tbsp: 1.47868e-2, // Tablespoon
|
||||||
|
'fl oz': 2.95735e-2, // Fluid ounce
|
||||||
|
cup: 2.36588e-1, // Cup
|
||||||
|
pt: 4.73176e-1, // Pint
|
||||||
|
qt: 0.946353, // Quart
|
||||||
|
gal: 3.78541, // Gallon
|
||||||
|
},
|
||||||
|
|
||||||
|
// Mass
|
||||||
|
mass: {
|
||||||
|
kg: 1, // Kilogram
|
||||||
|
g: 1e-3, // Gram
|
||||||
|
mg: 1e-6, // Milligram
|
||||||
|
μg: 1e-9, // Microgram
|
||||||
|
lb: 0.453592, // Pound
|
||||||
|
oz: 0.0283495, // Ounce
|
||||||
|
},
|
||||||
|
|
||||||
|
// Time
|
||||||
|
time: {
|
||||||
|
s: 1, // Second
|
||||||
|
ms: 1e-3, // Millisecond
|
||||||
|
μs: 1e-6, // Microsecond
|
||||||
|
ns: 1e-9, // Nanosecond
|
||||||
|
min: 60, // Minute
|
||||||
|
h: 3600, // Hour
|
||||||
|
d: 86400, // Day
|
||||||
|
yr: 3.15576e7, // Year (Julian year)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Frequency (note: Hz is also in mechanical, but we'll keep it here for consistency)
|
||||||
|
frequency: {
|
||||||
|
Hz: 1, // Hertz
|
||||||
|
kHz: 1e3, // Kilohertz
|
||||||
|
MHz: 1e6, // Megahertz
|
||||||
|
GHz: 1e9, // Gigahertz
|
||||||
|
RPM: 1/60, // Revolutions per minute (to Hz)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Data
|
||||||
|
data: {
|
||||||
|
bit: 1, // Bit
|
||||||
|
byte: 8, // Byte
|
||||||
|
KB: 8e3, // Kilobyte (SI)
|
||||||
|
MB: 8e6, // Megabyte (SI)
|
||||||
|
GB: 8e9, // Gigabyte (SI)
|
||||||
|
TB: 8e12, // Terabyte (SI)
|
||||||
|
// Note: For binary prefixes (KiB, MiB, etc.), the user can specify if needed.
|
||||||
|
// We are using SI (decimal) prefixes as default.
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = UnitDefinitions;
|
||||||
Reference in New Issue
Block a user