diff --git a/src/datatables/data/american_wire_gauge.ts b/src/datatables/data/american_wire_gauge.ts new file mode 100644 index 0000000..218ab9d --- /dev/null +++ b/src/datatables/data/american_wire_gauge.ts @@ -0,0 +1,62 @@ +export default { + title: 'American Wire Gauge', + columns: [ + { + diameter: { + title: 'Diameter', + type: 'number', + unit: 'mm' + } + } + ], + data: { + '0000': { diameter: 11.684 }, + '000': { diameter: 10.405 }, + '00': { diameter: 9.266 }, + '0': { diameter: 8.251 }, + '(4/0)': { diameter: 11.684 }, + '(3/0)': { diameter: 10.405 }, + '(2/0)': { diameter: 9.266 }, + '(1/0)': { diameter: 8.251 }, + '1': { diameter: 7.348 }, + '2': { diameter: 6.544 }, + '3': { diameter: 5.827 }, + '4': { diameter: 5.189 }, + '5': { diameter: 4.621 }, + '6': { diameter: 4.115 }, + '7': { diameter: 3.665 }, + '8': { diameter: 3.264 }, + '9': { diameter: 2.906 }, + '10': { diameter: 2.588 }, + '11': { diameter: 2.305 }, + '12': { diameter: 2.053 }, + '13': { diameter: 1.828 }, + '14': { diameter: 1.628 }, + '15': { diameter: 1.45 }, + '16': { diameter: 1.291 }, + '17': { diameter: 1.15 }, + '18': { diameter: 1.024 }, + '19': { diameter: 0.912 }, + '20': { diameter: 0.812 }, + '21': { diameter: 0.723 }, + '22': { diameter: 0.644 }, + '23': { diameter: 0.573 }, + '24': { diameter: 0.511 }, + '25': { diameter: 0.455 }, + '26': { diameter: 0.405 }, + '27': { diameter: 0.361 }, + '28': { diameter: 0.321 }, + '29': { diameter: 0.286 }, + '30': { diameter: 0.255 }, + '31': { diameter: 0.227 }, + '32': { diameter: 0.202 }, + '33': { diameter: 0.18 }, + '34': { diameter: 0.16 }, + '35': { diameter: 0.143 }, + '36': { diameter: 0.127 }, + '37': { diameter: 0.113 }, + '38': { diameter: 0.101 }, + '39': { diameter: 0.0897 }, + '40': { diameter: 0.0799 } + } +}; diff --git a/src/datatables/data/index.ts b/src/datatables/data/index.ts new file mode 100644 index 0000000..d9efaca --- /dev/null +++ b/src/datatables/data/index.ts @@ -0,0 +1,3 @@ +export const allDataTables: { [key: string]: { [key: string]: any } } = { + 'american-wire-gauge': {} +}; diff --git a/src/datatables/data/material_electrical_properties.ts b/src/datatables/data/material_electrical_properties.ts new file mode 100644 index 0000000..8b78de9 --- /dev/null +++ b/src/datatables/data/material_electrical_properties.ts @@ -0,0 +1,20 @@ +export default { + title: 'Material Electrical Properties', + columns: [ + { + resistivity_20c: { + title: 'Resistivity at 20°C', + type: 'number', + unit: 'Ω/m' + } + } + ], + data: { + copper: { + resistivity: 1.68e-8 + }, + aluminum: { + resistivity: 2.82e-8 + } + } +}; diff --git a/src/datatables/index.ts b/src/datatables/index.ts new file mode 100644 index 0000000..5c3ff98 --- /dev/null +++ b/src/datatables/index.ts @@ -0,0 +1,17 @@ +import type { DataTable } from './types.ts'; +import { allDataTables } from './data/index'; + +export async function getDataTable(name: string): Promise { + const x = await import(`./${name}`); + return x.default; +} + +export async function listDataTables(): Promise<{ name: string }[]> { + const x: { name: string }[] = []; + for (const key in allDataTables) { + x.push({ name: key }); + } + return x; +} + +export { DataTable }; diff --git a/src/datatables/types.ts b/src/datatables/types.ts new file mode 100644 index 0000000..37f4f48 --- /dev/null +++ b/src/datatables/types.ts @@ -0,0 +1,19 @@ +/* +Represents a set of rows indexed by a key. +Used for calculator presets + +*/ +export interface DataTable { + [key: string]: { + title: string; + /* A JSON schema properties */ + columns: { + [key: string]: any; + }; + data: { + [key: string]: { + [key: string]: any; + }; + }; + }; +} diff --git a/src/pages/tools/number/generic-calc/data/index.ts b/src/pages/tools/number/generic-calc/data/index.ts new file mode 100644 index 0000000..727349c --- /dev/null +++ b/src/pages/tools/number/generic-calc/data/index.ts @@ -0,0 +1,3 @@ +import ohmslaw from './ohms_law'; + +export default [ohmslaw]; diff --git a/src/pages/tools/number/generic-calc/data/ohms_law.ts b/src/pages/tools/number/generic-calc/data/ohms_law.ts new file mode 100644 index 0000000..25bbc66 --- /dev/null +++ b/src/pages/tools/number/generic-calc/data/ohms_law.ts @@ -0,0 +1,29 @@ +import type { GenericCalcType } from './types'; + +const ohmsLawCalc: GenericCalcType = { + title: "Ohm's Law", + name: 'ohms-law', + formula: 'V = I * R', + selections: [], + variables: [ + { + name: 'V', + title: 'Voltage', + unit: 'V', + default: 5 + }, + { + name: 'I', + title: 'Current', + unit: 'A', + default: 1 + }, + { + name: 'R', + title: 'Resistance', + unit: 'Ω' + } + ] +}; + +export default ohmsLawCalc; diff --git a/src/pages/tools/number/generic-calc/data/types.ts b/src/pages/tools/number/generic-calc/data/types.ts new file mode 100644 index 0000000..084413b --- /dev/null +++ b/src/pages/tools/number/generic-calc/data/types.ts @@ -0,0 +1,21 @@ +export interface GenericCalcType { + title: string; + name: string; + formula: string; + selections?: { + title: string; + source: string; + default: string; + bind: { + [key: string]: string; + }; + }[]; + variables: { + name: string; + title: string; + unit: string; + + // If absence, assume it's the default target var + default?: number; + }[]; +} diff --git a/src/pages/tools/number/generic-calc/data/wire_voltage_drop.ts b/src/pages/tools/number/generic-calc/data/wire_voltage_drop.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/pages/tools/number/generic-calc/index.tsx b/src/pages/tools/number/generic-calc/index.tsx index 4cabf41..2b8b69e 100644 --- a/src/pages/tools/number/generic-calc/index.tsx +++ b/src/pages/tools/number/generic-calc/index.tsx @@ -1,6 +1,7 @@ import { Box, - InputLabel, + Autocomplete, + TextField, Radio, Table, TableBody, @@ -13,54 +14,41 @@ import ToolContent from '@components/ToolContent'; import { ToolComponentProps } from '@tools/defineTool'; import ToolTextResult from '@components/result/ToolTextResult'; import TextFieldWithDesc from '@components/options/TextFieldWithDesc'; -import { GetGroupsType, UpdateField } from '@components/options/ToolOptions'; +import { UpdateField } from '@components/options/ToolOptions'; import { InitialValuesType } from './types'; +import type { GenericCalcType } from './data/types'; +import type { DataTable } from 'datatables'; +import { getDataTable } from 'datatables'; import nerdamer from 'nerdamer'; import 'nerdamer/Algebra'; import 'nerdamer/Solve'; import 'nerdamer/Calculus'; -const ohmsLawCalc: { - name: string; - formula: string; - variables: { - name: string; - title: string; - unit: string; - }[]; -} = { - name: "Ohm's Law Calculator", - formula: 'V = I * R', - variables: [ - { - name: 'V', - title: 'Voltage', - unit: 'V' - }, - { - name: 'I', - title: 'Current', - unit: 'A' - }, - { - name: 'R', - title: 'Resistance', - unit: 'Ω' - } - ] -}; - -export default function makeTool(): React.JSXElementConstructor { +export default async function makeTool( + calcData: GenericCalcType +): Promise> { const initialValues: InitialValuesType = { outputVariable: '', - vars: {} + vars: {}, + presets: {} }; + const dataTables: { [key: string]: DataTable } = {}; + + for (const selection of calcData.selections || []) { + dataTables[selection.source] = await getDataTable(selection.source); + } + return function GenericCalc({ title }: ToolComponentProps) { const [result, setResult] = useState(''); const [shortResult, setShortResult] = useState(''); + // For UX purposes we need to track what vars are + const [valsBoundToPreset, setValsBoundToPreset] = useState<{ + [key: string]: string; + }>({}); + const updateVarField = ( name: string, value: number, @@ -83,12 +71,89 @@ export default function makeTool(): React.JSXElementConstructor + ) => { + const newValsBoundToPreset = { ...valsBoundToPreset }; + + const newPresets = { ...currentValues.presets }; + newPresets[selection] = preset; + updateFieldFunc('presets', newPresets); + + // Clear old selection + for (const key in valsBoundToPreset) { + if (valsBoundToPreset[key] === selection) { + delete newValsBoundToPreset[key]; + } + } + + const selectionData = calcData.selections?.find( + (sel) => sel.title === selection + ); + + if (preset != '') { + if (selectionData) { + for (const key in selectionData.bind) { + newValsBoundToPreset[key] = selection; + updateVarField( + key, + dataTables[selectionData.source].data[preset][ + selectionData.bind[key] + ], + currentValues, + updateFieldFunc + ); + } + } else { + setValsBoundToPreset(newValsBoundToPreset); + throw new Error( + `Preset "${preset}" is not valid for selection "${selection}"` + ); + } + } + + setValsBoundToPreset(newValsBoundToPreset); + }; + + calcData.variables.forEach((variable) => { + if (variable.default === undefined) { + initialValues.vars[variable.name] = { + value: NaN, + unit: variable.unit + }; + initialValues.outputVariable = variable.name; + } else { + initialValues.vars[variable.name] = { + value: variable.default || 0, + unit: variable.unit + }; + } + }); + + calcData.selections?.forEach((selection) => { + initialValues.presets[selection.title] = selection.default; + if (selection.default == '') return; + for (const key in selection.bind) { + initialValues.vars[key] = { + value: + dataTables[selection.source].data[selection.default][ + selection.bind[key] + ], + unit: dataTables[selection.source].cols[selection.bind[key]].unit + }; + valsBoundToPreset[key] = selection.default; + } + }); + return ( + } initialValues={initialValues} toolInfo={{ @@ -97,6 +162,50 @@ export default function makeTool(): React.JSXElementConstructor [ + { + title: 'Presets', + component: ( + + + + + Option + Value + + + + {calcData.selections?.map((preset) => ( + + {preset.title} + + { + handleSelectedPresetChange( + preset.title, + newValue || '', + values, + updateField + ); + }} + renderInput={(params) => ( + + )} + > + + + ))} + +
+
+ ) + }, { title: 'Input Variables', component: ( @@ -110,20 +219,23 @@ export default function makeTool(): React.JSXElementConstructor - {ohmsLawCalc.variables.map((variable) => ( + {calcData.variables.map((variable) => ( {variable.name} updateVarField( variable.name, @@ -161,7 +273,7 @@ export default function makeTool(): React.JSXElementConstructor { if (key === values.outputVariable) return; diff --git a/src/pages/tools/number/generic-calc/meta.ts b/src/pages/tools/number/generic-calc/meta.ts index aff3a72..f095164 100644 --- a/src/pages/tools/number/generic-calc/meta.ts +++ b/src/pages/tools/number/generic-calc/meta.ts @@ -1,17 +1,32 @@ -import { defineTool } from '@tools/defineTool'; +import { DefinedTool, defineTool } from '@tools/defineTool'; import { lazy } from 'react'; +import type { GenericCalcType } from './data/types'; +import allGenericCalcs from './data/index'; -async function importComponent() { +async function importComponent(data: GenericCalcType) { const x = await import('./index'); - return { default: x.default() }; + return { default: await x.default(data) }; } -export const tool = defineTool('number', { - name: 'Generic calc', - path: 'generic-calc', - icon: '', - description: '', - shortDescription: '', - keywords: ['generic', 'calc'], - longDescription: '', - component: lazy(importComponent) + +const tools: DefinedTool[] = []; + +allGenericCalcs.forEach((x) => { + async function importComponent2() { + return await importComponent(x); + } + + tools.push( + defineTool('number', { + name: x.title, + path: 'generic-calc/x.name', + icon: '', + description: '', + shortDescription: '', + keywords: ['generic', 'calc'], + longDescription: '', + component: lazy(importComponent2) + }) + ); }); + +export { tools }; diff --git a/src/pages/tools/number/generic-calc/types.ts b/src/pages/tools/number/generic-calc/types.ts index 8953230..28f6076 100644 --- a/src/pages/tools/number/generic-calc/types.ts +++ b/src/pages/tools/number/generic-calc/types.ts @@ -6,5 +6,9 @@ export type InitialValuesType = { }; }; + // Track preset selections + presets: { + [key: string]: string; + }; outputVariable: string; }; diff --git a/src/pages/tools/number/index.ts b/src/pages/tools/number/index.ts index c03df53..f26f6fe 100644 --- a/src/pages/tools/number/index.ts +++ b/src/pages/tools/number/index.ts @@ -1,10 +1,10 @@ import { tool as numberSum } from './sum/meta'; import { tool as numberGenerate } from './generate/meta'; import { tool as numberArithmeticSequence } from './arithmetic-sequence/meta'; -import { tool as genericCalc } from './generic-calc/meta'; +import { tools as genericCalcTools } from './generic-calc/meta'; export const numberTools = [ numberSum, numberGenerate, numberArithmeticSequence, - genericCalc + ...genericCalcTools ];