63 |
64 | {/* Wrap input in span, and attach tooltip to span. This is a work around because React Tooltip
65 | does not display the tooltip attached to an input when the input is disabled. */}
66 |
67 |
76 |
77 |
100 |
101 | );
102 | }
103 | }
104 |
105 | CalcVarInput.defaultProps = {
106 | width: 150,
107 | };
108 |
109 | CalcVarInput.propTypes = {
110 | id: PropTypes.string.isRequired,
111 | calc: PropTypes.object.isRequired,
112 | width: PropTypes.number,
113 | };
114 |
--------------------------------------------------------------------------------
/pages/_document.js:
--------------------------------------------------------------------------------
1 | // _document is only rendered on the server side and not on the client side
2 | // Event handlers like onClick can't be added to this file
3 |
4 | // ./pages/_document.js
5 | import Document, { Html, Head, Main, NextScript } from 'next/document'
6 |
7 | import { GA_MEASUREMENT_ID } from '../lib/gtag'
8 |
9 | class MyDocument extends Document {
10 | static async getInitialProps(ctx) {
11 | const initialProps = await Document.getInitialProps(ctx)
12 | return { ...initialProps }
13 | }
14 |
15 | render() {
16 | return (
17 |
18 |
19 |
20 | {/* Providing "async" to the MathJax script loading can cause problems with the global object MathJax not being available in time for when specific pages want
21 | to render their equations. */}
22 |
59 |
65 |
66 | {/* Global Site Tag (gtag.js) - Google Analytics
67 | See https://github.com/vercel/next.js/tree/canary/examples/with-google-analytics for where
68 | this code came from */}
69 |
73 |
85 |
86 | {/* Umami analytics. Tracking is disabled in dev. by setting
87 | umami.disabled in local storage to 1. */}
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | )
97 | }
98 | }
99 |
100 | export default MyDocument
101 |
--------------------------------------------------------------------------------
/docs/js/main.js:
--------------------------------------------------------------------------------
1 | var apiRoot = "https://api.github.com/";
2 |
3 | // Display the stats
4 | function showStats(data) {
5 |
6 | var err = false;
7 | var errMessage = '';
8 |
9 | if(data.status == 404) {
10 | err = true;
11 | errMessage = "The project does not exist!";
12 | }
13 |
14 | if(data.length == 0) {
15 | err = true;
16 | errMessage = "There are no releases for this project";
17 | }
18 |
19 | var html = '';
20 |
21 | if(err) {
22 | html = "
" + errMessage + "
";
23 | } else {
24 | html += "
";
25 | var latest = true;
26 | var totalDownloadCount = 0;
27 |
28 | $.each(data, function(index, item) {
29 | var releaseTag = item.tag_name;
30 | var releaseURL = item.html_url;
31 | var releaseAssets = item.assets;
32 | var hasAssets = releaseAssets.length != 0;
33 | var releaseAuthor = item.author;
34 | var publishDate = item.published_at.split("T")[0];
35 |
36 | if(latest) {
37 | html += "
A suite of useful embedded-engineering related calculators.
42 |
43 |
44 |
45 |
46 |
As-you-type Updating
47 |
48 |
No more pressing the "Calculate" button! All parts of the calculator update as you type.
49 |
50 |
51 |
52 |
53 |
Metric Prefix Support
54 |
55 |
Enter values in the same concise format engineers use, using metric prefixes (e.g. u, m, k, M, G, e.t.c). Makes
56 | widely-varying values easy to enter and understand.
57 |
58 |
59 |
60 |
61 |
Metric/Imperial Unit Support
62 |
63 |
Dynamic unit-changing support (including various metric and imperial units where appropriate).
64 |
65 |
66 |
67 |
68 |
Continuous Sanity Checks
69 |
70 |
Continuously checking validators which make sure calculator variables are within range and sensible.
71 |
72 |
73 |
74 |
75 |
Helpful Tooltip Info
76 |
77 |
Helpful tooltip information for each calculator variable.
78 |
79 |
80 |
81 |
82 |
Smart Calculator Resizing
83 |
84 |
Smart calculator resizing to cater for various screen sizes and resolutions.
85 |
86 |
87 |
Expandable Info For Each Calculator
88 |
89 |
Want to know the exact equations each calculator is using? Interested in the theory behind each calculator? Expand
90 | each calculators "Info" section to get a detailed description of whats going on.
Before NinjaCalc was a web app (v2.0.0), it used to be a downloadable Java app. You can still download the old Java app (at v1.3.0) from the links below:
157 | The following calculator works out either charge, capacitance, or
158 | voltage given the other two parameters, using the equation:
159 |
160 |
161 |
$$ Q = CV $$
162 |
163 |
164 | where:
165 |
166 | \( Q \) = charge in the capacitor
167 |
168 | \( C \) = capacitance of the capacitor
169 |
170 | \( V \) = voltage across the capacitor
171 |
172 |
145 | The following calculator works out either voltage, current or
146 | resistance, given the other two parameters, using the equation:
147 |
148 |
149 |
$$ V = IR $$
150 |
151 |
152 | where:
153 |
154 | \( V \) = voltage across the resistor, in \(V\)
155 |
156 | \( I \) = current through the resistor, in \(A\)
157 |
158 | \( R \) = resistance of the resistor, in \(\Omega\)
159 |
160 |
168 | The following calculator helps you works out the component values
169 | to design a low-pass, single-stage, passive RC filter. The cut-off
170 | frequency, \( f_c \), is given by:
171 |
172 |
173 |
{String.raw`$$ f_c = \frac{1}{2\pi RC} $$`}
174 |
175 |
176 | where:
177 |
178 | \( f_c \) = the cutoff frequency of the low-pass RC filter (a.k.a
179 | knee frequency, -3dB point)
180 |
181 | \( R \) = resistance of the resistor
182 |
183 | \( C \) = capacitance of the capacitor
184 |
185 |
Via Diameter is the diameter of the drilled hole which is then plated to form the via (i.e. the via's outer diameter). Standard Via Plating Thickness is approximately 25um (18um copper is the defined minimum in the IPC 600J-Class 2 standard). For a via going from the top layer to the bottom layer on a standard 1.6mm thick FR-4 PCB, the Via Height would be 1.6mm. A copper thermal conductivity of {'\\(401Wm^{-1}K^{-1}\\)'} is a good general estimate for copper plated into the via by electrolysis.
145 |
146 |
147 | The cross-sectional area {String.raw`\( A_{via} \)`} in units {String.raw`\( m^2 \)`} is calculated with:
148 | {String.raw`$$ A_{via} = \pi \cdot t_{plating} \cdot ( d_{via} - t_{plating} ) $$`}
149 |
150 | where:
151 | {String.raw`\( t_{plating} \)`} is the plating thinkness in {String.raw`\( m \)`}
152 | {String.raw`\( d_{via} \)`} is the outer diameter of the via in {String.raw`\( m \)`}
153 |
154 |
155 |
156 |
157 |
The thermal resistance {String.raw`\( \theta_{via} \)`} (with units {String.raw`\( °C \cdot W^{-1} \)`}) is then calculated with:
158 | {String.raw`$$ \theta_{via} = \frac{h_{via}}{\lambda_{copper} \cdot A_{via}} $$`}
159 |
160 | where:
161 | {String.raw`\( h_{via} \)`} is the height of the via in {String.raw`\( m \)`}
162 | {String.raw`\( \lambda_{copper} \)`} is the thermal conductivity of copper in {String.raw`\( W \cdot m^{-1} \cdot K^{-1} \)`}
163 |
164 |
165 |
166 |
Degrees Kelvin is interchangable with degrees Celcius in this calculator as we are always dealing with temperature differences.
189 | Enter your desired resistance, and this calculator will find the
190 | closest preferred value (purchasable resistance) in each
191 | one of the EIA E series, from E6 to E192. The percentage
192 | difference between your desired resistance and the preferred value
193 | is also shown for each E series.
194 |
210 | Note that although the E48 series has more values per decade than
211 | say, the E24 series, you might find a closer resistance in the E24
212 | series due to the E6, E12 and E24 using a different number
213 | sequence to the E48, E96 and E192 series.
214 |
215 |
216 |
217 | If your desired resistance is exactly half-way (in percentage
218 | terms) between two preferred values, this calculator will choose
219 | the higher resistance.
220 |
221 |
222 |
223 |
228 |
229 | );
230 | };
231 | }
232 |
233 | export default UI;
234 |
--------------------------------------------------------------------------------
/docs/scss/.scss-lint.yml:
--------------------------------------------------------------------------------
1 | # This is the lint file for .scss files. It uses https://github.com/causes/scss-lint
2 | # to search through .scss files and point out errors.
3 | # You can view these errors in your editor.
4 | #
5 | # Here's a link to all the default configurations
6 | # https://github.com/causes/scss-lint/blob/master/config/default.yml
7 | # below is our settings.
8 |
9 | linters:
10 | BangFormat:
11 | enabled: true
12 | space_before_bang: true
13 | space_after_bang: false
14 |
15 | BorderZero:
16 | enabled: true
17 | convention: zero # or `none`
18 |
19 | ColorKeyword:
20 | enabled: true
21 |
22 | ColorVariable:
23 | enabled: false
24 |
25 | Comment:
26 | enabled: false
27 |
28 | DebugStatement:
29 | enabled: true
30 |
31 | DeclarationOrder:
32 | enabled: true
33 |
34 | DuplicateProperty:
35 | enabled: true
36 |
37 | ElsePlacement:
38 | enabled: true
39 | style: same_line # or 'new_line'
40 |
41 | EmptyLineBetweenBlocks:
42 | enabled: true
43 | ignore_single_line_blocks: true
44 |
45 | EmptyRule:
46 | enabled: false
47 |
48 | FinalNewline:
49 | enabled: true
50 | present: true
51 |
52 | HexLength:
53 | enabled: true
54 | style: short # or 'long'
55 |
56 | HexNotation:
57 | enabled: true
58 | style: lowercase # or 'uppercase'
59 |
60 | HexValidation:
61 | enabled: true
62 |
63 | IdSelector:
64 | enabled: true
65 |
66 | ImportantRule:
67 | enabled: true
68 |
69 | ImportPath:
70 | enabled: true
71 | leading_underscore: false
72 | filename_extension: false
73 |
74 | Indentation:
75 | enabled: true
76 | allow_non_nested_indentation: false
77 | character: space # or 'tab'
78 | width: 2
79 |
80 | LeadingZero:
81 | enabled: true
82 | style: include_zero
83 |
84 | MergeableSelector:
85 | enabled: true
86 | force_nesting: true
87 |
88 | NameFormat:
89 | enabled: false
90 | convention: hyphenated_lowercase # or 'BEM', or a regex pattern
91 |
92 | NestingDepth:
93 | enabled: false
94 | max_depth: 3
95 |
96 | PlaceholderInExtend:
97 | enabled: false
98 |
99 | PropertySortOrder:
100 | enabled: false
101 | ignore_unspecified: true
102 | severity: warning
103 | order:
104 | - position
105 | - top
106 | - right
107 | - bottom
108 | - left
109 | - z-index
110 | - display
111 | - float
112 | - width
113 | - min-width
114 | - max-width
115 | - height
116 | - min-height
117 | - max-height
118 | - box-sizing
119 | - padding
120 | - padding-top
121 | - padding-right
122 | - padding-bottom
123 | - padding-left
124 | - margin
125 | - margin-top
126 | - margin-right
127 | - margin-bottom
128 | - margin-left
129 | - overflow
130 | - overflow-x
131 | - overflow-y
132 | - clip
133 | - clear
134 | - font
135 | - font-family
136 | - font-size
137 | - font-style
138 | - font-weight
139 | - font-variant
140 | - font-size-adjust
141 | - font-stretch
142 | - font-effect
143 | - font-emphasize
144 | - font-emphasize-position
145 | - font-emphasize-style
146 | - font-smooth
147 | - hyphens
148 | - line-height
149 | - color
150 | - text-align
151 | - text-align-last
152 | - text-emphasis
153 | - text-emphasis-color
154 | - text-emphasis-style
155 | - text-emphasis-position
156 | - text-decoration
157 | - text-indent
158 | - text-justify
159 | - text-outline
160 | - text-overflow
161 | - text-overflow-ellipsis
162 | - text-overflow-mode
163 | - text-shadow
164 | - text-transform
165 | - text-wrap
166 | - letter-spacing
167 | - word-break
168 | - word-spacing
169 | - word-wrap
170 | - tab-size
171 | - white-space
172 | - vertical-align
173 | - list-style
174 | - list-style-position
175 | - list-style-type
176 | - list-style-image
177 | - pointer-events
178 | - fill
179 | - fill-opacity
180 | - stroke
181 | - stroke-opacity
182 | - stroke-width
183 | - shape-rendering
184 | - cursor
185 | - visibility
186 | - zoom
187 | - flex-direction
188 | - flex-order
189 | - flex-pack
190 | - flex-align
191 | - table-layout
192 | - empty-cells
193 | - caption-side
194 | - border-spacing
195 | - border-collapse
196 | - content
197 | - quotes
198 | - counter-reset
199 | - counter-increment
200 | - resize
201 | - user-select
202 | - nav-index
203 | - nav-up
204 | - nav-right
205 | - nav-down
206 | - nav-left
207 | - background
208 | - background-color
209 | - background-image
210 | - filter
211 | - background-repeat
212 | - background-attachment
213 | - background-position
214 | - background-position-x
215 | - background-position-y
216 | - background-clip
217 | - background-origin
218 | - background-size
219 | - border
220 | - border-color
221 | - border-style
222 | - border-width
223 | - border-top
224 | - border-top-color
225 | - border-top-style
226 | - border-top-width
227 | - border-right
228 | - border-right-color
229 | - border-right-style
230 | - border-right-width
231 | - border-bottom
232 | - border-bottom-color
233 | - border-bottom-style
234 | - border-bottom-width
235 | - border-left
236 | - border-left-color
237 | - border-left-style
238 | - border-left-width
239 | - border-radius
240 | - border-top-left-radius
241 | - border-top-right-radius
242 | - border-bottom-right-radius
243 | - border-bottom-left-radius
244 | - border-image
245 | - border-image-source
246 | - border-image-slice
247 | - border-image-width
248 | - border-image-outset
249 | - border-image-repeat
250 | - outline
251 | - outline-width
252 | - outline-style
253 | - outline-color
254 | - outline-offset
255 | - box-shadow
256 | - opacity
257 | - transition
258 | - transition-delay
259 | - transition-timing-function
260 | - transition-duration
261 | - transition-property
262 | - transform
263 | - transform-origin
264 | - animation
265 | - animation-name
266 | - animation-duration
267 | - animation-fill-mode
268 | - animation-play-state
269 | - animation-timing-function
270 | - animation-delay
271 | - animation-iteration-count
272 | - animation-direction
273 |
274 | PropertySpelling:
275 | enabled: true
276 | extra_properties: []
277 |
278 | QualifyingElement:
279 | enabled: true
280 | allow_element_with_attribute: false
281 | allow_element_with_class: false
282 | allow_element_with_id: false
283 |
284 | SelectorDepth:
285 | enabled: true
286 | max_depth: 4
287 |
288 | SelectorFormat:
289 | enabled: false
290 | convention: hyphenated_lowercase # or 'BEM', or 'hyphenated_BEM', or 'snake_case', or 'camel_case', or a regex pattern
291 |
292 | Shorthand:
293 | enabled: true
294 |
295 | SingleLinePerProperty:
296 | enabled: true
297 | allow_single_line_rule_sets: true
298 |
299 | SingleLinePerSelector:
300 | enabled: true
301 |
302 | SpaceAfterComma:
303 | enabled: true
304 |
305 | SpaceAfterPropertyColon:
306 | enabled: true
307 | style: one_space # or 'no_space', or 'at_least_one_space', or 'aligned'
308 |
309 | SpaceAfterPropertyName:
310 | enabled: true
311 |
312 | SpaceBeforeBrace:
313 | enabled: true
314 | style: space # or 'new_line'
315 | allow_single_line_padding: true
316 |
317 | SpaceBetweenParens:
318 | enabled: true
319 | spaces: 0
320 |
321 | StringQuotes:
322 | enabled: true
323 | style: double_quotes
324 |
325 | TrailingSemicolon:
326 | enabled: true
327 |
328 | TrailingZero:
329 | enabled: false
330 |
331 | UnnecessaryMantissa:
332 | enabled: true
333 |
334 | UnnecessaryParentReference:
335 | enabled: true
336 |
337 | UrlFormat:
338 | enabled: true
339 |
340 | UrlQuotes:
341 | enabled: true
342 |
343 | VariableForProperty:
344 | enabled: false
345 | properties: []
346 |
347 | VendorPrefix:
348 | enabled: true
349 | identifier_list: base
350 | additional_identifiers: []
351 | excluded_identifiers: []
352 |
353 | ZeroUnit:
354 | enabled: true
355 |
--------------------------------------------------------------------------------
/utils/standard-resistance-finder.js:
--------------------------------------------------------------------------------
1 | export class StandardResistanceFinder {
2 | constructor () {
3 | // ============================================ //
4 | // ==================== ENUMS ================= //
5 | // ============================================ //
6 | this.eSeriesOptions = {
7 | E6: { value: 0, name: 'E6' },
8 | E12: { value: 1, name: 'E12' },
9 | E24: { value: 2, name: 'E24' },
10 | E48: { value: 3, name: 'E48' },
11 | E96: { value: 4, name: 'E96' },
12 | E192: { value: 5, name: 'E192' }
13 | }
14 |
15 | this.searchMethods = {
16 | CLOSEST: 0,
17 | CLOSEST_EQUAL_OR_HIGHER: 1,
18 | CLOSEST_EQUAL_OR_LOWER: 2
19 | }
20 |
21 | this.e24Values = [100, 110, 120, 130, 150, 160, 180, 200, 220, 240, 270, 300, 330, 360, 390, 430, 470, 510, 560, 620, 680, 750, 820, 910, 1000]
22 |
23 | // Create E6 and E12 values from elements in E24 array
24 | this.e6Values = []
25 | this.e12Values = []
26 | var i
27 | for (i = 0; i < this.e24Values.length; i++) {
28 | if (i % 2 === 0) {
29 | this.e12Values.push(this.e24Values[i])
30 | }
31 |
32 | if (i % 4 === 0) {
33 | this.e6Values.push(this.e24Values[i])
34 | }
35 | }
36 |
37 | this.e192Values = [
38 | 100, 101, 102, 104, 105, 106, 107, 109, 110, 111, 113, 114, 115, 117, 118, 120,
39 | 121, 123, 124, 126, 127, 129, 130, 132, 133, 135, 137, 138, 140, 142, 143, 145,
40 | 147, 149, 150, 152, 154, 156, 158, 160, 162, 164, 165, 167, 169, 172, 174, 176,
41 | 178, 180, 182, 184, 187, 189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213,
42 | 215, 218, 221, 223, 226, 229, 232, 234, 237, 240, 243, 246, 249, 252, 255, 258,
43 | 261, 264, 267, 271, 274, 277, 280, 284, 287, 291, 294, 298, 301, 305, 309, 312,
44 | 316, 320, 324, 328, 332, 336, 340, 344, 348, 352, 357, 361, 365, 370, 374, 379,
45 | 383, 388, 392, 397, 402, 407, 412, 417, 422, 427, 432, 437, 442, 448, 453, 459,
46 | 464, 470, 475, 481, 487, 493, 499, 505, 511, 517, 523, 530, 536, 542, 549, 556,
47 | 562, 569, 576, 583, 590, 597, 604, 612, 619, 626, 634, 642, 649, 657, 665, 673,
48 | 681, 690, 698, 706, 715, 723, 732, 741, 750, 759, 768, 777, 787, 796, 806, 816,
49 | 825, 835, 845, 856, 866, 876, 887, 898, 909, 920, 931, 942, 953, 965, 976, 988,
50 | 1000,
51 | ]
52 |
53 | // Create E48 and E96 values from elements in E192 array
54 | this.e48Values = []
55 | this.e96Values = []
56 | for (i = 0; i < this.e192Values.length; i++) {
57 | if (i % 2 === 0) {
58 | this.e96Values.push(this.e192Values[i])
59 | }
60 |
61 | if (i % 4 === 0) {
62 | this.e48Values.push(this.e192Values[i])
63 | }
64 | }
65 | }
66 |
67 | /**
68 | * Finds the closest E-series resistance.
69 | *
70 | * @param {number} desiredResistance The actual resistance you want.
71 | * @param {eSeriesOptions} eSeries The E series you want to look in.
72 | * @param {searchMethods} searchMethod The search method you want to perform
73 | * @returns The closest value to the resistance you provided based on the specified E series and search method.
74 | */
75 | find = (desiredResistance, eSeries, searchMethod) => {
76 | if (!eSeries)
77 | throw new Error('eSeries variable provided to StandardResistanceFinder.find() must be a valid object.')
78 |
79 | // Check for special case where desired resistance is 0. Strictly speaking, this does not belong
80 | // in any E-series, but 0R links are common place so we will return 0.0 anyway.
81 | if (desiredResistance === 0.0) {
82 | return 0.0
83 | }
84 |
85 | var selectedRange = []
86 |
87 | // Find out what resistance series was selected
88 | switch (eSeries.value) {
89 | case this.eSeriesOptions.E6.value:
90 | selectedRange = this.e6Values
91 | break
92 | case this.eSeriesOptions.E12.value:
93 | selectedRange = this.e12Values
94 | break
95 | case this.eSeriesOptions.E24.value:
96 | selectedRange = this.e24Values
97 | break
98 | case this.eSeriesOptions.E48.value:
99 | selectedRange = this.e48Values
100 | break
101 | case this.eSeriesOptions.E96.value:
102 | selectedRange = this.e96Values
103 | break
104 | case this.eSeriesOptions.E192.value:
105 | selectedRange = this.e192Values
106 | break
107 | default:
108 | throw new Error('Provided eSeriesOption "' + eSeries.name + '" is not supported.')
109 | }
110 | // console.log('selectedRange =')
111 | // console.log(selectedRange)
112 |
113 | var order = this.findOrder(desiredResistance) - 2
114 | // console.log('order = ' + order)
115 |
116 | var scaledDesiredResistance = this.scaleWrtOrder(desiredResistance, order)
117 | // console.log('scaledDesiredResistance = ' + scaledDesiredResistance)
118 |
119 | var closestScaledResistance = this.findClosestMatch(scaledDesiredResistance, selectedRange, searchMethod)
120 | // console.log('closestScaledResistance = ' + closestScaledResistance)
121 |
122 | var scaleFactor = Math.pow(10, order)
123 | // console.log('scaleFactor = ' + scaleFactor)
124 |
125 | var closestResistance = closestScaledResistance * scaleFactor
126 | // console.log('closestResistance = ' + closestResistance)
127 |
128 | return closestResistance
129 | }
130 |
131 | /**
132 | * Finds the order of magnitude of a given resistance.
133 | * e.g. if var in range 1-10, order = 0, if var in range 10-100, order = 1
134 | * @param desRes The resistance you wish to find the magnitude of.
135 | * @return The magnitude of the resistance.
136 | */
137 | findOrder = (desiredResistance) => {
138 | var order = Math.log10(desiredResistance)
139 | order = Math.floor(order)
140 | return order
141 | }
142 |
143 | scaleWrtOrder = (desiredResistance, order) => {
144 | return desiredResistance / Math.pow(10, order)
145 | }
146 |
147 | findClosestMatch = (val, array, searchMethod) => {
148 | var i = 0
149 |
150 | switch (searchMethod) {
151 | case this.searchMethods.CLOSEST:
152 | // Iterate through array until we hit the first element which is bigger than the value we are
153 | // trying to find.
154 | // NOTE: Start of 2nd element of array!
155 | i = 1
156 | while (true) {
157 | if (array[i] > val) {
158 | break
159 | }
160 |
161 | if (i === array.length - 1) {
162 | break
163 | }
164 | i++
165 | }
166 |
167 | // At this point either:
168 | // 1) We have stopped somewhere in the middle of the array. val will be higher than array[i-1]
169 | // and lower than array[i]. We need to find which one is closer (based on percentage difference)
170 | // 2) We have stopped either on the second or last element of the array. If it is the second, val will
171 | // be closest to array[i-1], if it is the last, val will be closest to array[i].
172 | console.log('Stopped when i = ' + i)
173 | console.log('Closest value 1 = ' + array[i - 1])
174 | console.log('Closest value 2 = ' + array[i])
175 | console.log('val=', val)
176 |
177 | var lowerPercDiff = ((array[i - 1] - val) / val) * 100.0
178 | console.log('Percentage diff 1 = ' + lowerPercDiff)
179 | var higherPercDiff = ((array[i] - val) / val) * 100.0
180 | console.log('Percentage diff 2 = ' + higherPercDiff)
181 |
182 | if (Math.abs(lowerPercDiff) < Math.abs(higherPercDiff)) {
183 | return array[i - 1]
184 | } else {
185 | return array[i]
186 | }
187 | case this.searchMethods.CLOSEST_EQUAL_OR_LOWER:
188 | // console.log('Finding closest equal or lower value to "' + val + '" in array =')
189 | // console.log(array)
190 |
191 | // First make sure there is a lower value in the array
192 | if (array[0] > val) {
193 | throw new Error('StandardResistanceFinder.Find() called with searchMethod = CLOSEST_EQUAL_OR_LOWER, but there way no value in the array lower than the provided value of ' + val)
194 | }
195 |
196 | i = 1
197 | while (i < array.length) {
198 | if (array[i] > val) {
199 | // We have found the first value in the array which is bigger than the value, so the closest smaller value must of been the value before this
200 | return array[i - 1]
201 | }
202 | i++
203 | }
204 | break
205 |
206 | case this.searchMethods.CLOSEST_EQUAL_OR_HIGHER:
207 |
208 | i = 0
209 | while (i < array.length) {
210 | if (array[i] >= val) {
211 | // We have found the first value in the array which is bigger than the value, so the closest smaller value must of been the value before this
212 | return array[i]
213 | }
214 | i++
215 | }
216 |
217 | // Special case here where the first larger number is the first number of the next series
218 | throw new Error('StandardResistanceFinder.Find() called with searchMethod = CLOSEST_EQUAL_OR_HIGHER, but there was no value in the array which was equal of higher than the provided value of ' + val)
219 | }
220 |
221 | throw new Error('Code reached invalid place. Case must not of been handled correctly in switch statement.')
222 | }
223 | }
224 |
--------------------------------------------------------------------------------
/pages/calculators/electronics/ics/555-timer-astable-rt-rb-c/index.js:
--------------------------------------------------------------------------------
1 | import Head from 'next/head'
2 | import React from 'react'
3 |
4 | import Nav from '~/components/nav'
5 | import Layout from '~/components/layout-calc'
6 | import VarRow from '~/components/calc-var-row'
7 | import { Calc } from '~/utils/calc'
8 | import { CalcVar } from '~/utils/calc-var'
9 | import CalcHelper from '~/utils/calc-helper'
10 | import TileImage from './tile-image.png'
11 |
12 | export var metadata = {
13 | id: '555-timer-astable-rt-rb-c', // Make sure this has the same name as the directory this file is in
14 | name: '555 Timer, Astable (Freq/Duty Cycle In, Rt/Rb/C Out)',
15 | description: 'Calculate the resistor and capacitors values for a 555 timer in astable configuration.',
16 | categories: ['Electronics', 'ICs'],
17 | tags: ['555', 'timer'],
18 | image: TileImage,
19 | }
20 |
21 | class UI extends React.Component {
22 |
23 | constructor(props) {
24 | super(props)
25 | this.state = {
26 | calc: new Calc({
27 | calcVars: {
28 | freq_Hz: new CalcVar({
29 | name: 'Frequency',
30 | type: 'numeric',
31 | direction: 'input',
32 | dispVal: '10k',
33 | metricPrefixes: true,
34 | units: [
35 | ['Hz', 1e0],
36 | ],
37 | selUnit: 'Hz',
38 | validation: {
39 | fns: [
40 | (value) => {
41 | console.log('validator() called with value=' + value)
42 | if (value <= 0) { return ['error', 'Frequency must be greater than 0,'] }
43 | return ['ok', '']
44 | },
45 | ]
46 | },
47 | helpText: 'The desired frequency of the 555 output waveform.',
48 | }), // freq_Hz
49 | dutyCycle_ratio: new CalcVar({
50 | name: 'Duty Cycle',
51 | type: 'numeric',
52 | direction: 'input',
53 | dispVal: '60',
54 | metricPrefixes: false,
55 | units: [
56 | ['%', 1e-2],
57 | ],
58 | selUnit: '%',
59 | validations: {
60 | fns: [
61 | (value) => {
62 | if (value < 50e-2) return ['error', 'Duty cycle must be greater or equal to 50%.']
63 | if (value > 100e-2) return ['error', 'Duty cycle must be less or equal to 100%.']
64 | return ['ok', '']
65 | },
66 | ]
67 | },
68 | helpText: 'The desired duty cycle. Because of the design of the 555, the duty cycle must be greater than 50%.'
69 | }), // dutyCycle_ratio
70 | capacitance_F: new CalcVar({
71 | name: 'Capacitance',
72 | type: 'numeric',
73 | direction: 'input',
74 | dispVal: '10n',
75 | metricPrefixes: true,
76 | units: [
77 | ['F', 1e0],
78 | ],
79 | selUnit: 'F',
80 | validation: {
81 | fns: [
82 | (value) => {
83 | if (value <= 0) return ['error', 'Capacitance must be greater than zero.']
84 | if (value < 1e-12) return ['warning', 'This is an extremely small capacitance.']
85 | if (value > 1e-3) return ['warning', 'This is an extremely large capacitance.']
86 | return ['ok', '']
87 | },
88 | ]
89 | },
90 | helpText: 'The capacitance of the capacitor connected to the 555.',
91 | }), // capacitance_F
92 | period_s: new CalcVar({
93 | name: 'Period',
94 | type: 'numeric',
95 | direction: 'output',
96 | metricPrefixes: true,
97 | units: [
98 | ['s', 1e0],
99 | ],
100 | selUnit: 's',
101 | sigFig: 3,
102 | }), // period_s
103 | timeHigh_s: new CalcVar({
104 | name: 'Time High',
105 | type: 'numeric',
106 | direction: 'output',
107 | metricPrefixes: true,
108 | units: [
109 | ['s', 1e0],
110 | ],
111 | selUnit: 's',
112 | sigFig: 3,
113 | }), // timeHigh_s
114 | timeLow_s: new CalcVar({
115 | name: 'Time Low',
116 | type: 'numeric',
117 | direction: 'output',
118 | metricPrefixes: true,
119 | units: [
120 | ['s', 1e0],
121 | ],
122 | selUnit: 's',
123 | sigFig: 3,
124 | }), // timeLow_s
125 | r1_Ohms: new CalcVar({
126 | name: 'R1',
127 | type: 'numeric',
128 | direction: 'output',
129 | metricPrefixes: true,
130 | units: [
131 | ['Ω', 1e0],
132 | ],
133 | selUnit: 'Ω',
134 | sigFig: 3,
135 | }), // r1_Ohms
136 | r2_Ohms: new CalcVar({
137 | name: 'R2',
138 | type: 'numeric',
139 | direction: 'output',
140 | metricPrefixes: true,
141 | units: [
142 | ['Ω', 1e0],
143 | ],
144 | selUnit: 'Ω',
145 | sigFig: 3,
146 | }), // r2_Ohms
147 | }, // calcVars
148 | eqFn: (calc) => {
149 | const calcVars = calc.calcVars
150 | const period_s = 1/calcVars.freq_Hz.rawVal
151 | calcVars.period_s.rawVal = period_s
152 |
153 | const timeHigh_s = calcVars.dutyCycle_ratio.rawVal * period_s
154 | calcVars.timeHigh_s.rawVal = timeHigh_s
155 |
156 | const timeLow_s = period_s - timeHigh_s
157 | calcVars.timeLow_s.rawVal = timeLow_s
158 |
159 | const r1_Ohms = timeLow_s / (0.693*calcVars.capacitance_F.rawVal)
160 | calcVars.r1_Ohms.rawVal = r1_Ohms
161 |
162 | const r2_Ohms = timeHigh_s/(0.693*calcVars.capacitance_F.rawVal) - r1_Ohms
163 | calcVars.r2_Ohms.rawVal = r2_Ohms
164 | },
165 | }), // calc
166 | } // this.state
167 | CalcHelper.initCalc(this.state.calc)
168 | }
169 |
170 | componentDidMount() {
171 | // MathJax not defined during tests
172 | if (typeof MathJax !== 'undefined')
173 | MathJax.Hub.Queue(["Typeset", MathJax.Hub])
174 | console.log('Calculator555TimerRtRbC mounted.')
175 | } // componentDidMount()
176 |
177 | valueChanged = (e) => {
178 | let calc = this.state.calc
179 | CalcHelper.handleValueChanged(calc, e)
180 | this.setState({
181 | calc: calc
182 | })
183 | }
184 |
185 | unitsChanged = (e) => {
186 | let calc = this.state.calc
187 | CalcHelper.handleUnitsChanged(calc, e)
188 | this.setState({
189 | calc: calc
190 | })
191 | }
192 |
193 | render = () => {
194 |
195 | // Area of ring = pi * inner diameter * thickness
196 | const calcVars = this.state.calc.calcVars
197 | const varWidth = 100
198 |
199 | return (
200 |
201 |
202 | {metadata.name}
203 |
204 |
205 |
206 |
This calculator calculates the resistances and capacitances needed to operate a 555 timer in astable mode. The duty cycle cannot be set lower than 50%, if you want to do this you will have to attach an inverter to the output.
227 |
233 |
234 | )
235 | }
236 | }
237 |
238 | export default UI
--------------------------------------------------------------------------------
/docs/css/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */
2 |
3 | /**
4 | * 1. Set default font family to sans-serif.
5 | * 2. Prevent iOS text size adjust after orientation change, without disabling
6 | * user zoom.
7 | */
8 |
9 | html {
10 | font-family: sans-serif; /* 1 */
11 | -ms-text-size-adjust: 100%; /* 2 */
12 | -webkit-text-size-adjust: 100%; /* 2 */
13 | }
14 |
15 | /**
16 | * Remove default margin.
17 | */
18 |
19 | body {
20 | margin: 0;
21 | }
22 |
23 | /* HTML5 display definitions
24 | ========================================================================== */
25 |
26 | /**
27 | * Correct `block` display not defined for any HTML5 element in IE 8/9.
28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11
29 | * and Firefox.
30 | * Correct `block` display not defined for `main` in IE 11.
31 | */
32 |
33 | article,
34 | aside,
35 | details,
36 | figcaption,
37 | figure,
38 | footer,
39 | header,
40 | hgroup,
41 | main,
42 | menu,
43 | nav,
44 | section,
45 | summary {
46 | display: block;
47 | }
48 |
49 | /**
50 | * 1. Correct `inline-block` display not defined in IE 8/9.
51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
52 | */
53 |
54 | audio,
55 | canvas,
56 | progress,
57 | video {
58 | display: inline-block; /* 1 */
59 | vertical-align: baseline; /* 2 */
60 | }
61 |
62 | /**
63 | * Prevent modern browsers from displaying `audio` without controls.
64 | * Remove excess height in iOS 5 devices.
65 | */
66 |
67 | audio:not([controls]) {
68 | display: none;
69 | height: 0;
70 | }
71 |
72 | /**
73 | * Address `[hidden]` styling not present in IE 8/9/10.
74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
75 | */
76 |
77 | [hidden],
78 | template {
79 | display: none;
80 | }
81 |
82 | /* Links
83 | ========================================================================== */
84 |
85 | /**
86 | * Remove the gray background color from active links in IE 10.
87 | */
88 |
89 | a {
90 | background-color: transparent;
91 | }
92 |
93 | /**
94 | * Improve readability when focused and also mouse hovered in all browsers.
95 | */
96 |
97 | a:active,
98 | a:hover {
99 | outline: 0;
100 | }
101 |
102 | /* Text-level semantics
103 | ========================================================================== */
104 |
105 | /**
106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
107 | */
108 |
109 | abbr[title] {
110 | border-bottom: 1px dotted;
111 | }
112 |
113 | /**
114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
115 | */
116 |
117 | b,
118 | strong {
119 | font-weight: bold;
120 | }
121 |
122 | /**
123 | * Address styling not present in Safari and Chrome.
124 | */
125 |
126 | dfn {
127 | font-style: italic;
128 | }
129 |
130 | /**
131 | * Address variable `h1` font-size and margin within `section` and `article`
132 | * contexts in Firefox 4+, Safari, and Chrome.
133 | */
134 |
135 | h1 {
136 | font-size: 2em;
137 | margin: 0.67em 0;
138 | }
139 |
140 | /**
141 | * Address styling not present in IE 8/9.
142 | */
143 |
144 | mark {
145 | background: #ff0;
146 | color: #000;
147 | }
148 |
149 | /**
150 | * Address inconsistent and variable font size in all browsers.
151 | */
152 |
153 | small {
154 | font-size: 80%;
155 | }
156 |
157 | /**
158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers.
159 | */
160 |
161 | sub,
162 | sup {
163 | font-size: 75%;
164 | line-height: 0;
165 | position: relative;
166 | vertical-align: baseline;
167 | }
168 |
169 | sup {
170 | top: -0.5em;
171 | }
172 |
173 | sub {
174 | bottom: -0.25em;
175 | }
176 |
177 | /* Embedded content
178 | ========================================================================== */
179 |
180 | /**
181 | * Remove border when inside `a` element in IE 8/9/10.
182 | */
183 |
184 | img {
185 | border: 0;
186 | }
187 |
188 | /**
189 | * Correct overflow not hidden in IE 9/10/11.
190 | */
191 |
192 | svg:not(:root) {
193 | overflow: hidden;
194 | }
195 |
196 | /* Grouping content
197 | ========================================================================== */
198 |
199 | /**
200 | * Address margin not present in IE 8/9 and Safari.
201 | */
202 |
203 | figure {
204 | margin: 1em 40px;
205 | }
206 |
207 | /**
208 | * Address differences between Firefox and other browsers.
209 | */
210 |
211 | hr {
212 | box-sizing: content-box;
213 | height: 0;
214 | }
215 |
216 | /**
217 | * Contain overflow in all browsers.
218 | */
219 |
220 | pre {
221 | overflow: auto;
222 | }
223 |
224 | /**
225 | * Address odd `em`-unit font size rendering in all browsers.
226 | */
227 |
228 | code,
229 | kbd,
230 | pre,
231 | samp {
232 | font-family: monospace, monospace;
233 | font-size: 1em;
234 | }
235 |
236 | /* Forms
237 | ========================================================================== */
238 |
239 | /**
240 | * Known limitation: by default, Chrome and Safari on OS X allow very limited
241 | * styling of `select`, unless a `border` property is set.
242 | */
243 |
244 | /**
245 | * 1. Correct color not being inherited.
246 | * Known issue: affects color of disabled elements.
247 | * 2. Correct font properties not being inherited.
248 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
249 | */
250 |
251 | button,
252 | input,
253 | optgroup,
254 | select,
255 | textarea {
256 | color: inherit; /* 1 */
257 | font: inherit; /* 2 */
258 | margin: 0; /* 3 */
259 | }
260 |
261 | /**
262 | * Address `overflow` set to `hidden` in IE 8/9/10/11.
263 | */
264 |
265 | button {
266 | overflow: visible;
267 | }
268 |
269 | /**
270 | * Address inconsistent `text-transform` inheritance for `button` and `select`.
271 | * All other form control elements do not inherit `text-transform` values.
272 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
273 | * Correct `select` style inheritance in Firefox.
274 | */
275 |
276 | button,
277 | select {
278 | text-transform: none;
279 | }
280 |
281 | /**
282 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
283 | * and `video` controls.
284 | * 2. Correct inability to style clickable `input` types in iOS.
285 | * 3. Improve usability and consistency of cursor style between image-type
286 | * `input` and others.
287 | */
288 |
289 | button,
290 | html input[type="button"], /* 1 */
291 | input[type="reset"],
292 | input[type="submit"] {
293 | -webkit-appearance: button; /* 2 */
294 | cursor: pointer; /* 3 */
295 | }
296 |
297 | /**
298 | * Re-set default cursor for disabled elements.
299 | */
300 |
301 | button[disabled],
302 | html input[disabled] {
303 | cursor: default;
304 | }
305 |
306 | /**
307 | * Remove inner padding and border in Firefox 4+.
308 | */
309 |
310 | button::-moz-focus-inner,
311 | input::-moz-focus-inner {
312 | border: 0;
313 | padding: 0;
314 | }
315 |
316 | /**
317 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in
318 | * the UA stylesheet.
319 | */
320 |
321 | input {
322 | line-height: normal;
323 | }
324 |
325 | /**
326 | * It's recommended that you don't attempt to style these elements.
327 | * Firefox's implementation doesn't respect box-sizing, padding, or width.
328 | *
329 | * 1. Address box sizing set to `content-box` in IE 8/9/10.
330 | * 2. Remove excess padding in IE 8/9/10.
331 | */
332 |
333 | input[type="checkbox"],
334 | input[type="radio"] {
335 | box-sizing: border-box; /* 1 */
336 | padding: 0; /* 2 */
337 | }
338 |
339 | /**
340 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain
341 | * `font-size` values of the `input`, it causes the cursor style of the
342 | * decrement button to change from `default` to `text`.
343 | */
344 |
345 | input[type="number"]::-webkit-inner-spin-button,
346 | input[type="number"]::-webkit-outer-spin-button {
347 | height: auto;
348 | }
349 |
350 | /**
351 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
352 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
353 | * (include `-moz` to future-proof).
354 | */
355 |
356 | input[type="search"] {
357 | -webkit-appearance: textfield; /* 1 */ /* 2 */
358 | box-sizing: content-box;
359 | }
360 |
361 | /**
362 | * Remove inner padding and search cancel button in Safari and Chrome on OS X.
363 | * Safari (but not Chrome) clips the cancel button when the search input has
364 | * padding (and `textfield` appearance).
365 | */
366 |
367 | input[type="search"]::-webkit-search-cancel-button,
368 | input[type="search"]::-webkit-search-decoration {
369 | -webkit-appearance: none;
370 | }
371 |
372 | /**
373 | * Define consistent border, margin, and padding.
374 | */
375 |
376 | fieldset {
377 | border: 1px solid #c0c0c0;
378 | margin: 0 2px;
379 | padding: 0.35em 0.625em 0.75em;
380 | }
381 |
382 | /**
383 | * 1. Correct `color` not being inherited in IE 8/9/10/11.
384 | * 2. Remove padding so people aren't caught out if they zero out fieldsets.
385 | */
386 |
387 | legend {
388 | border: 0; /* 1 */
389 | padding: 0; /* 2 */
390 | }
391 |
392 | /**
393 | * Remove default vertical scrollbar in IE 8/9/10/11.
394 | */
395 |
396 | textarea {
397 | overflow: auto;
398 | }
399 |
400 | /**
401 | * Don't inherit the `font-weight` (applied by a rule above).
402 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
403 | */
404 |
405 | optgroup {
406 | font-weight: bold;
407 | }
408 |
409 | /* Tables
410 | ========================================================================== */
411 |
412 | /**
413 | * Remove most spacing between table cells.
414 | */
415 |
416 | table {
417 | border-collapse: collapse;
418 | border-spacing: 0;
419 | }
420 |
421 | td,
422 | th {
423 | padding: 0;
424 | }
425 |
--------------------------------------------------------------------------------
/pages/calculators/electronics/basics/resistor-divider/index.js:
--------------------------------------------------------------------------------
1 | import Head from "next/head"
2 | import React from "react"
3 |
4 | import Layout from "components/layout-calc"
5 | import VarRowV2 from 'components/calc-var-row'
6 | import { Calc } from 'utils/calc'
7 | import { CalcVar } from 'utils/calc-var'
8 | import { UnitsMultiplicative } from 'utils/calc-units'
9 | import CalcHelper from "utils/calc-helper"
10 | import TileImage from "./tile-image.png"
11 | import { Validators } from 'utils/validators'
12 |
13 | export var metadata = {
14 | id: "resistor-divider", // Make sure this has the same name as the directory this file is in
15 | name: "Resistor Divider",
16 | description: "Resistor dividers are a simple, widely-used circuit primitive for reducing a voltage based on a fixed ratio.",
17 | categories: [ 'Electronics', 'Basics' ],
18 | tags: [ 'resistor', 'resistance', 'voltage', 'divider', 'reduce', 'adc', 'translate', 'level', 'shift' ],
19 | image: TileImage,
20 | };
21 |
22 | class UI extends React.Component {
23 | constructor(props) {
24 | super(props);
25 | this.state = {
26 | calc: new Calc({
27 | calcVars: {
28 | vin: new CalcVar({
29 | name: "Input Voltage",
30 | type: 'numeric',
31 | direction: "input",
32 | dispVal: "5",
33 | metricPrefixes: true,
34 | units: [
35 | new UnitsMultiplicative("V", 1e0),
36 | ],
37 | selUnit: "V",
38 | validation: {
39 | fns: [
40 | Validators.isNumber,
41 | Validators.isPositive,
42 | ],
43 | },
44 | helpText: 'The voltage to the top of the resistor divider (i.e. across both resistors).',
45 | }), // vin
46 | rtop: new CalcVar({
47 | name: "Top Resistance",
48 | type: 'numeric',
49 | direction: "input",
50 | dispVal: "10k",
51 | metricPrefixes: true,
52 | units: [
53 | new UnitsMultiplicative("Ω", 1e0),
54 | ],
55 | selUnit: "Ω",
56 | validation: {
57 | fns: [
58 | Validators.isNumber,
59 | Validators.isPositive,
60 | ],
61 | },
62 | helpText: 'The resistance of the first (top) resistor.',
63 | }), // rtop
64 | rbot: new CalcVar({
65 | name: "Bottom Resistance",
66 | type: 'numeric',
67 | direction: "input",
68 | dispVal: "10k",
69 | metricPrefixes: true,
70 | units: [
71 | new UnitsMultiplicative("Ω", 1e0),
72 | ],
73 | selUnit: "Ω",
74 | validation: {
75 | fns: [
76 | Validators.isNumber,
77 | Validators.isPositive,
78 | ],
79 | },
80 | helpText: 'The resistance of the second (bottom) resistor.',
81 | }), // rbot
82 | vout: new CalcVar({
83 | name: "Output Voltage",
84 | type: 'numeric',
85 | direction: "output",
86 | metricPrefixes: true,
87 | units: [
88 | new UnitsMultiplicative('V', 1e0),
89 | ],
90 | selUnit: "V",
91 | validation: {
92 | fns: [
93 | Validators.isNumber,
94 | Validators.isPositive,
95 | (value, calc) => {
96 | if (calc.calcVars.vout.rawVal >= calc.calcVars.vin.rawVal) {
97 | return [ 'error', 'Vout must be less than Vin.']
98 | } else {
99 | return [ 'ok', '' ]
100 | }
101 | },
102 | ],
103 | },
104 | helpText: 'The voltage between the two resistors (i.e. across the bottom resistor).',
105 | }), // vout
106 | }, // calcVars
107 | eqFn: (calc) => {
108 | const calcVars = calc.calcVars
109 | let vin = calcVars.vin.rawVal
110 | let rtop = calcVars.rtop.rawVal
111 | let rbot = calcVars.rbot.rawVal
112 | let vout = calcVars.vout.rawVal
113 | if (calcVars.vin.direction == "output") {
114 | calcVars.vin.rawVal = ((vout * (rtop + rbot)) / rbot)
115 | } else if (calcVars.rtop.direction == "output") {
116 | calcVars.rtop.rawVal = ((rbot * (vin - vout)) / vout)
117 | } else if (calcVars.rbot.direction == "output") {
118 | calcVars.rbot.rawVal = ((rtop * vout) / (vin - vout))
119 | } else if (calcVars.vout.direction == "output") {
120 | calcVars.vout.rawVal = ((vin * rbot) / (rtop + rbot))
121 | } else {
122 | throw Error("No variable was an output.")
123 | }
124 | },
125 | }), // calc
126 | } // this.state
127 | CalcHelper.initCalc(this.state.calc)
128 | }
129 |
130 | componentDidMount() {
131 | MathJax.Hub.Queue(["Typeset", MathJax.Hub])
132 | } // componentDidMount()
133 |
134 | valueChanged = (e) => {
135 | let calc = this.state.calc;
136 | CalcHelper.handleValueChanged(calc, e);
137 | this.setState({
138 | calc: calc,
139 | });
140 | };
141 |
142 | unitsChanged = (e) => {
143 | let calc = this.state.calc;
144 | CalcHelper.handleUnitsChanged(calc, e);
145 | this.setState({
146 | calc: calc,
147 | });
148 | };
149 |
150 | rbChanged = (e) => {
151 | console.log("rbChanged() called. e.target=");
152 | console.log(e.target);
153 | let calc = this.state.calc;
154 | let varName = e.target.value;
155 | for (let calcVarId in calc.calcVars) {
156 | console.log(calcVarId);
157 | if (calcVarId == e.target.value) {
158 | console.log("Setting " + calcVarId + " as output.");
159 | calc.calcVars[calcVarId].direction = "output";
160 | } else {
161 | console.log("Setting " + calcVarId + " as input.");
162 | calc.calcVars[calcVarId].direction = "input";
163 | }
164 | }
165 | this.setState({
166 | calc: calc,
167 | });
168 | };
169 |
170 | render = () => {
171 | // Area of ring = pi * inner diameter * thickness
172 | const calcVars = this.state.calc.calcVars;
173 | const varWidth = 100;
174 |
175 | return (
176 |
177 |
178 | {metadata.name}
179 |
180 |
181 |
182 |
183 |
184 |
185 |
Variable
186 |
Value
187 |
Units
188 |
Output
189 |
Description
190 |
191 |
192 |
193 |
202 |
211 |
220 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 | The following calculator works out either \( V_{'{'}in{'}'} \), \( R_1 \), \( R_2 \), or \( V_{'{'}out{'}'}\), given the other three parameters, using the resistive voltage divider equation:
237 |
238 | $$ V_{'{'}out{'}'}=\frac{'{'}R_2{'}'}{'{'}R_1+R_2{'}'}V_{'{'}in{'}'} $$
239 |
240 |
241 | where:
242 | \( V_{'{'}in{'}'} \) = input voltage
243 | \( R_1 \) = resistance of resistor 1 (see diagram)
244 | \( R_2 \) = resistance of resistor 2 (see diagram)
245 | \( V_{'{'}out{'}'} \) = output voltage
246 |
247 |
248 | {String.raw`It is assumed that the output impedance on \( V_{out} \) is significantly higher than \( R_2 \) so that it doesn't matter (for example, \( V_{out} \) is connected to an op-amp input, analogue microcontroller input or similar).
249 | The quiescent current through the divider, \( I_q \), is also calculated, which can be useful to know when designing power-saving circuits. The equation to find \( I_q \) is:
250 |
251 | $$ I_q = \frac{V_{in}}{R_1+R_2} $$`}
252 |
253 |
254 |
255 |
260 |
261 | );
262 | };
263 | }
264 |
265 | export default UI;
266 |
--------------------------------------------------------------------------------
/pages/index.js:
--------------------------------------------------------------------------------
1 | import React from "react"
2 | import Head from "next/head"
3 | import Link from "next/link"
4 | import { SpringGrid, makeResponsive, measureItems } from 'react-stonecutter'
5 | // Using CSSGrid here does not seem to work, only SprintGrid produces
6 | // animations when tiles appear/dissappear
7 | const Grid = makeResponsive(measureItems(SpringGrid), {
8 | maxWidth: 1920,
9 | // minPadding is important to fix the problem if the grid items start going of the right-hand side of the screen.
10 | // make sure this value is set to the same width as the left-hand column (essentially the number of pixels that
11 | // the grid layout doesn't get)
12 | minPadding: 220,
13 | });
14 |
15 | import Layout from '~/components/layout'
16 | import TreeView from '~/components/tree-view/tree-view'
17 |
18 | import * as CalcCapacitorCharge from "./calculators/electronics/basics/capacitor-charge"
19 | import * as CalcLedCurrentLimitingResistor from './calculators/electronics/basics/led-current-limiting-resistor'
20 | import * as CalcOhmsLaw from "./calculators/electronics/basics/ohms-law"
21 | import * as CalcResistorDivider from "./calculators/electronics/basics/resistor-divider"
22 | import * as CalcStandardResistanceFinder from "./calculators/electronics/basics/standard-resistance-finder"
23 |
24 | import * as CalcWireGauge from "./calculators/electronics/cabling/wire-gauge-calculator"
25 |
26 | import * as CalcFilterLowPassRC from "./calculators/electronics/filters/filter-low-pass-rc"
27 |
28 | import * as Calc555TimerRtRbC from "./calculators/electronics/ics/555-timer-astable-rt-rb-c"
29 | import * as CalcMp4558 from "./calculators/electronics/ics/mp4558-design-tool"
30 |
31 | import * as CalcMicrostripImpedance from "./calculators/electronics/pcb-design/microstrip-impedance"
32 | import * as CalcTrackCurrentIpc2152 from "./calculators/electronics/pcb-design/track-current-ipc2152"
33 | import * as CalcTrackCurrentIpc2221a from "./calculators/electronics/pcb-design/track-current-ipc2221a"
34 | import * as CalcViaCurrentIpc2221a from "./calculators/electronics/pcb-design/via-current-ipc2221a"
35 | import * as CalcViaThermalResistance from "./calculators/electronics/pcb-design/via-thermal-resistance"
36 |
37 | import * as CalcDewPointMagnus from "./calculators/electronics/sensors/dew-point-magnus"
38 | import * as CalcNtcThermistor from "./calculators/electronics/sensors/ntc-thermistor"
39 |
40 | import * as CalcBuckConverter from "./calculators/electronics/smps/buck-converter"
41 |
42 | import * as Calc3DRotations from './calculators/mathematics/geometry/3d-rotations'
43 |
44 | // SOFTWARE
45 | import * as CalcCrcCalculator from './calculators/software/crc-calculator'
46 | import * as CalcMovingAverageFilterDesigner from './calculators/software/moving-average-filter-designer'
47 |
48 | class Home extends React.Component {
49 | constructor(props) {
50 | super(props);
51 |
52 | this.state = {
53 | calculators: [],
54 | filterByCategories: 'All',
55 | searchText: '',
56 | }
57 |
58 | // ADD CALCULATORS TO STATE
59 |
60 | // electronics/basics
61 | this.addCalc(CalcCapacitorCharge)
62 | this.addCalc(CalcLedCurrentLimitingResistor)
63 | this.addCalc(CalcOhmsLaw)
64 | this.addCalc(CalcResistorDivider)
65 | this.addCalc(CalcStandardResistanceFinder)
66 | // electronics/cabling
67 | this.addCalc(CalcWireGauge)
68 | // electronics/filters
69 | this.addCalc(CalcFilterLowPassRC)
70 | // electronics/ics
71 | this.addCalc(Calc555TimerRtRbC)
72 | this.addCalc(CalcMp4558)
73 | // electronics/pcb-design
74 | this.addCalc(CalcMicrostripImpedance)
75 | this.addCalc(CalcTrackCurrentIpc2152)
76 | this.addCalc(CalcTrackCurrentIpc2221a)
77 | this.addCalc(CalcViaCurrentIpc2221a)
78 | this.addCalc(CalcViaThermalResistance)
79 | // electronics/sensor
80 | this.addCalc(CalcDewPointMagnus)
81 | this.addCalc(CalcNtcThermistor)
82 | // electronics/smps
83 | this.addCalc(CalcBuckConverter)
84 | // mathematics
85 | this.addCalc(Calc3DRotations)
86 | // software
87 | this.addCalc(CalcCrcCalculator)
88 | this.addCalc(CalcMovingAverageFilterDesigner)
89 | }
90 |
91 | componentDidMount = () => {
92 | // Enable Umami analytics script in production and disable
93 | // in dev. environment. Use the umami.disabled key in local storage for doing so
94 | if (process.env.NODE_ENV === 'production') {
95 | // It's not good enough just to set the key to 0, it needs to be removed
96 | window.localStorage.removeItem('umami.disabled');
97 | } else {
98 | console.log('Detected dev. environment, setting umami.disabled in local storage to "1".');
99 | window.localStorage.setItem('umami.disabled', '1');
100 | }
101 | }
102 |
103 | addCalc = (calcModule) => {
104 | let calculators = this.state.calculators
105 | calculators.push(calcModule)
106 | }
107 |
108 | categoryTreeNodeClicked = (categories) => {
109 | this.setState({
110 | filterByCategories: categories
111 | })
112 | }
113 |
114 | onSearchTextChange = (event) => {
115 | this.setState({
116 | searchText: event.target.value,
117 | })
118 | }
119 |
120 | /**
121 | * Returns the URL to get to a specific calculator.
122 | *
123 | * @param {object} calcMetadata Metadata object of calculator you want the URL for.
124 | * @returns Absolute path (URL) to calculator (excl. domain).
125 | */
126 | getPath = (calcMetadata) => {
127 | let path = ''
128 | path += 'calculators/'
129 | for (const category of calcMetadata.categories) {
130 | // Make the category path suitable
131 | // "PCB Design" -> "pcb-design"
132 | // "Electronics" -> "electronics"
133 | path += category.toLowerCase().replace(' ', '-') + '/'
134 | }
135 | // No tailing forward slash!
136 | path += calcMetadata.id
137 | return path
138 | }
139 |
140 | render() {
141 | let filteredCalculators = null
142 |
143 | // Filter calculators by selected category
144 | if (this.state.filterByCategories == 'All') {
145 | filteredCalculators = this.state.calculators
146 | } else {
147 | filteredCalculators = this.state.calculators.filter((calculator) => {
148 | // Remove the 'All'
149 | let filterNoAll = this.state.filterByCategories.slice()
150 | filterNoAll.shift()
151 | for(let i in filterNoAll) {
152 | if(filterNoAll[i] != calculator.metadata.categories[i]) {
153 | return false
154 | }
155 | }
156 | return true
157 | })
158 | }
159 |
160 | // Filter calculators by search text
161 | if(this.state.searchText != ''){
162 | const searchTextLower = this.state.searchText.toLowerCase()
163 | filteredCalculators = filteredCalculators.filter((calculator) => {
164 | for (const tag of calculator.metadata.tags) {
165 | if(tag.toLowerCase().includes(searchTextLower)) {
166 | return true
167 | }
168 | }
169 | // If we reach here, there was no match
170 | return false
171 | })
172 | }
173 |
174 | const TILE_WIDTH = 200
175 | const TILE_HEIGHT = 300
176 |
177 | const calcList = filteredCalculators.map((calculator, idx) => {
178 | return (