1+ {{/*
2+ Hugo Shortcode to find the equation of a parabola (y = ax^2 + bx + c) given two points and the slope at each.
3+
4+ Usage:
5+ {{< parabola _from_slopes x1 ="3 " y1 ="2 " m1 ="31 " x2 ="2 " y2 ="3 " m2 ="14 " > }}
6+ */}}
7+
8+ < script src ="https://cdn.jsdelivr.net/npm/mathjs@11.11.2/lib/browser/math.min.js "> </ script >
9+
10+ < style >
11+ /* Scoped CSS for the solver */
12+ .parabola-slopes-solver-container {
13+ max-width : 800px ;
14+ margin : 2rem auto;
15+ padding : 2.5rem ;
16+ background-color : # fefefe ;
17+ border : 1px solid # e0e0e0 ;
18+ border-radius : 12px ;
19+ box-shadow : 0 6px 20px rgba (0 , 0 , 0 , 0.08 );
20+ font-family : 'Segoe UI' , Tahoma, Geneva, Verdana, sans-serif;
21+ color : # 333 ;
22+ }
23+
24+ .parabola-slopes-solver-container h3 {
25+ text-align : center;
26+ color : # 007bff ;
27+ margin-bottom : 2rem ;
28+ font-size : 1.8rem ;
29+ }
30+
31+ .equation-display {
32+ font-family : 'Times New Roman' , Times, serif;
33+ font-style : italic;
34+ font-size : 1.8rem ;
35+ text-align : center;
36+ margin-bottom : 2rem ;
37+ color : # 1a1a1a ;
38+ background-color : # f0f8ff ;
39+ padding : 1rem ;
40+ border-radius : 8px ;
41+ border : 1px dashed # cce5ff ;
42+ }
43+
44+ .input-row {
45+ display : flex;
46+ flex-wrap : wrap;
47+ gap : 1.5rem ;
48+ justify-content : center;
49+ margin-bottom : 2rem ;
50+ }
51+
52+ .input-group {
53+ display : flex;
54+ flex-direction : column;
55+ align-items : center;
56+ flex : 1 1 150px ;
57+ }
58+
59+ .input-group label {
60+ font-weight : 600 ;
61+ margin-bottom : 0.5rem ;
62+ color : # 555 ;
63+ text-align : center;
64+ }
65+
66+ .input-group input [type = "number" ] {
67+ width : 100% ;
68+ max-width : 150px ;
69+ padding : 0.8rem ;
70+ border : 1px solid # ccc ;
71+ border-radius : 6px ;
72+ font-size : 1.1rem ;
73+ text-align : center;
74+ transition : border-color 0.3s ease-in-out, box-shadow 0.3s ease-in-out;
75+ }
76+
77+ .input-group input : focus {
78+ outline : none;
79+ border-color : # 007bff ;
80+ box-shadow : 0 0 8px rgba (0 , 123 , 255 , 0.4 );
81+ }
82+
83+ .solver-button-container {
84+ text-align : center;
85+ }
86+
87+ .solver-button {
88+ padding : 1rem 2.5rem ;
89+ background-color : # 007bff ;
90+ color : # fff ;
91+ border : none;
92+ border-radius : 8px ;
93+ font-size : 1.1rem ;
94+ font-weight : bold;
95+ cursor : pointer;
96+ transition : background-color 0.3s ease-in-out, transform 0.1s ease-in-out;
97+ }
98+
99+ .solver-button : hover {
100+ background-color : # 0056b3 ;
101+ transform : translateY (-2px );
102+ }
103+
104+ .solver-result {
105+ margin-top : 2.5rem ;
106+ padding : 1.8rem ;
107+ background-color : # eaf6ff ;
108+ border-radius : 10px ;
109+ border : 1px solid # b3d9ff ;
110+ line-height : 1.8 ;
111+ font-size : 1.1rem ;
112+ color : # 1a2a3a ;
113+ word-wrap : break-word;
114+ }
115+
116+ .result-item {
117+ margin-bottom : 0.8rem ;
118+ }
119+
120+ .result-label {
121+ font-weight : 700 ;
122+ color : # 0056b3 ;
123+ }
124+
125+ .result-value {
126+ font-family : 'Courier New' , Courier, monospace;
127+ background-color : # fff ;
128+ padding : 0.2em 0.5em ;
129+ border-radius : 4px ;
130+ border : 1px solid # d4e3f1 ;
131+ }
132+
133+ .solver-error {
134+ color : # dc3545 ;
135+ font-weight : bold;
136+ }
137+
138+
139+ html : is (.dark ) {
140+ .parabola-slopes-solver-container {
141+ background-color : # 181c24 ;
142+ border-color : # 232a36 ;
143+ color : # e0e6ef ;
144+ box-shadow : 0 6px 20px rgba (0 , 0 , 0 , 0.32 );
145+ }
146+ .parabola-slopes-solver-container h3 {
147+ color : # 6cb6ff ;
148+ }
149+ .equation-display {
150+ background-color : # 232a36 ;
151+ color : # e0e6ef ;
152+ border-color : # 2d3a4d ;
153+ }
154+ .input-group label {
155+ color : # b3c6e0 ;
156+ }
157+ .input-group input [type = "number" ] {
158+ background-color : # 232a36 ;
159+ color : # e0e6ef ;
160+ border-color : # 2d3a4d ;
161+ }
162+ .input-group input : focus {
163+ border-color : # 6cb6ff ;
164+ box-shadow : 0 0 8px rgba (108 , 182 , 255 , 0.4 );
165+ }
166+ .solver-button {
167+ background-color : # 2563eb ;
168+ color : # fff ;
169+ }
170+ .solver-button : hover {
171+ background-color : # 174ea6 ;
172+ }
173+ .solver-result {
174+ background-color : # 232a36 ;
175+ border-color : # 2d3a4d ;
176+ color : # e0e6ef ;
177+ }
178+ .result-label {
179+ color : # 6cb6ff ;
180+ }
181+ .result-value {
182+ background-color : # 181c24 ;
183+ color : # e0e6ef ;
184+ border-color : # 2d3a4d ;
185+ }
186+ .solver-error {
187+ color : # ff6b6b ;
188+ }
189+ }
190+
191+ @media (max-width : 600px ) {
192+ .parabola-slopes-solver-container {
193+ padding : 1rem ;
194+ max-width : 100vw ;
195+ border-radius : 0 ;
196+ box-shadow : none;
197+ }
198+ .equation-display {
199+ font-size : 1.2rem ;
200+ padding : 0.5rem ;
201+ }
202+ .input-row {
203+ flex-direction : column;
204+ gap : 0.8rem ;
205+ margin-bottom : 1rem ;
206+ }
207+ .input-group {
208+ flex : 1 1 100% ;
209+ align-items : stretch;
210+ }
211+ .input-group input [type = "number" ] {
212+ max-width : 100% ;
213+ font-size : 1rem ;
214+ padding : 0.5rem ;
215+ }
216+ .solver-button {
217+ width : 100% ;
218+ padding : 0.8rem 0 ;
219+ font-size : 1rem ;
220+ }
221+ .solver-result {
222+ padding : 1rem ;
223+ font-size : 1rem ;
224+ }
225+ }
226+
227+ </ style >
228+
229+ < div class ="parabola-slopes-solver-container ">
230+ < h3 > Find Parabola Equation from Two Points and Slopes</ h3 >
231+
232+ < div class ="equation-display ">
233+ y = ax² + bx + c
234+ </ div >
235+
236+ < div class ="input-row ">
237+ < div class ="input-group ">
238+ < label > Point 1 (x₁, y₁):</ label >
239+ < input type ="number " id ="x1-input-{{ .Ordinal }} " value ="{{ .Get "x1 " | default "3" }}">
240+ < input type ="number " id ="y1-input-{{ .Ordinal }} " value ="{{ .Get "y1 " | default "2" }}">
241+ </ div >
242+ < div class ="input-group ">
243+ < label > Slope at x₁ (m₁):</ label >
244+ < input type ="number " id ="m1-input-{{ .Ordinal }} " value ="{{ .Get "m1 " | default "31" }}">
245+ </ div >
246+ < div class ="input-group ">
247+ < label > Point 2 (x₂, y₂):</ label >
248+ < input type ="number " id ="x2-input-{{ .Ordinal }} " value ="{{ .Get "x2 " | default "2" }}">
249+ < input type ="number " id ="y2-input-{{ .Ordinal }} " value ="{{ .Get "y2 " | default "3" }}">
250+ </ div >
251+ < div class ="input-group ">
252+ < label > Slope at x₂ (m₂):</ label >
253+ < input type ="number " id ="m2-input-{{ .Ordinal }} " value ="{{ .Get "m2 " | default "14" }}">
254+ </ div >
255+ </ div >
256+
257+ < div class ="solver-button-container ">
258+ < button class ="solver-button " onclick ="findCoefficientsFromSlopes('{{ .Ordinal }}') "> Find Coefficients</ button >
259+ </ div >
260+
261+ < div class ="solver-result " id ="results-output-{{ .Ordinal }} ">
262+ Results will appear here.
263+ </ div >
264+ </ div >
265+
266+ < script >
267+ // Global function to solve for a, b, and c using slopes and points.
268+ window . findCoefficientsFromSlopes = function ( ordinal ) {
269+ const x1 = parseFloat ( document . getElementById ( 'x1-input-' + ordinal ) . value ) ;
270+ const y1 = parseFloat ( document . getElementById ( 'y1-input-' + ordinal ) . value ) ;
271+ const m1 = parseFloat ( document . getElementById ( 'm1-input-' + ordinal ) . value ) ;
272+ const x2 = parseFloat ( document . getElementById ( 'x2-input-' + ordinal ) . value ) ;
273+ const y2 = parseFloat ( document . getElementById ( 'y2-input-' + ordinal ) . value ) ;
274+ const m2 = parseFloat ( document . getElementById ( 'm2-input-' + ordinal ) . value ) ;
275+ const output = document . getElementById ( 'results-output-' + ordinal ) ;
276+
277+ if ( typeof math === 'undefined' ) {
278+ output . innerHTML = '<span class="solver-error">Error: Math.js library not loaded.</span>' ;
279+ return ;
280+ }
281+
282+ try {
283+ if ( isNaN ( x1 ) || isNaN ( y1 ) || isNaN ( m1 ) || isNaN ( x2 ) || isNaN ( y2 ) || isNaN ( m2 ) ) {
284+ throw new Error ( "Please enter valid numbers for all inputs." ) ;
285+ }
286+
287+ if ( x1 === x2 ) {
288+ throw new Error ( "The x-coordinates of the two points must be different to find a unique solution." ) ;
289+ }
290+
291+ // --- Step 1: Solve for 'a' and 'b' using the slopes ---
292+ // System of equations:
293+ // 2*a*x1 + b = m1
294+ // 2*a*x2 + b = m2
295+
296+ // Coefficient matrix for [a, b]
297+ const A_matrix = [
298+ [ 2 * x1 , 1 ] ,
299+ [ 2 * x2 , 1 ]
300+ ] ;
301+
302+ // Constant vector [m1, m2]
303+ const B_vector = [ m1 , m2 ] ;
304+
305+ // Solve using Math.js
306+ const solution_ab = math . lusolve ( A_matrix , B_vector ) ;
307+
308+ if ( ! solution_ab || solution_ab . length === 0 ) {
309+ output . innerHTML = '<span class="solver-error">Could not find a unique solution for a and b from the slopes.</span>' ;
310+ return ;
311+ }
312+
313+ const a_solution = solution_ab [ 0 ] [ 0 ] ;
314+ const b_solution = solution_ab [ 1 ] [ 0 ] ;
315+
316+ // --- Step 2: Solve for 'c' using one of the points ---
317+ // Using Point 1: y1 = a*x1^2 + b*x1 + c
318+ // c = y1 - a*x1^2 - b*x1
319+ const c_solution = y1 - a_solution * Math . pow ( x1 , 2 ) - b_solution * x1 ;
320+
321+ // --- Step 3: Verify the consistency of the solutions with the second point ---
322+ // Check if Point 2 satisfies the equation with the found a, b, and c
323+ const y2_calculated = a_solution * Math . pow ( x2 , 2 ) + b_solution * x2 + c_solution ;
324+ const isConsistent = math . abs ( y2_calculated - y2 ) < 1e-9 ; // Use tolerance for floating-point comparison
325+
326+ // --- Format the final output ---
327+ const a_formatted = Number ( a_solution ) . toLocaleString ( undefined , { maximumFractionDigits : 6 } ) ;
328+ const b_formatted = Number ( b_solution ) . toLocaleString ( undefined , { maximumFractionDigits : 6 } ) ;
329+ const c_formatted = Number ( c_solution ) . toLocaleString ( undefined , { maximumFractionDigits : 6 } ) ;
330+ const y2_calculated_formatted = Number ( y2_calculated ) . toLocaleString ( undefined , { maximumFractionDigits : 6 } ) ;
331+
332+ let consistencyMessage = '' ;
333+ if ( isConsistent ) {
334+ consistencyMessage = `<span style="color: green; font-weight: bold;">The inputs are consistent. A unique parabola exists.</span>` ;
335+ } else {
336+ consistencyMessage = `<span style="color: #dc3545; font-weight: bold;">The inputs are inconsistent. No single parabola can pass through both points with the given slopes.</span>` ;
337+ }
338+
339+ const resultHTML = `
340+ <div class="result-item"><span class="result-label">Result from Slopes:</span> <span class="result-value">a = ${ a_formatted } </span>, <span class="result-value">b = ${ b_formatted } </span></div>
341+ <div class="result-item"><span class="result-label">Calculated 'c' from Point 1:</span> <span class="result-value">c = ${ c_formatted } </span></div>
342+ <hr style="margin: 1rem 0; border-color: #cce5ff;">
343+ <div class="result-item"><span class="result-label">Calculated Equation:</span> <span class="result-value">y = ${ a_formatted } x² ${ b_formatted >= 0 ? '+' : '' } ${ b_formatted } x ${ c_formatted >= 0 ? '+' : '' } ${ c_formatted } </span></div>
344+ <div class="result-item"><span class="result-label">Checking with Point 2 (${ x2 } , ${ y2 } ):</span><br>
345+ If x = ${ x2 } , the calculated y is <span class="result-value">${ y2_calculated_formatted } </span> (expected y is <span class="result-value">${ y2 } </span>).</div>
346+ <hr style="margin: 1rem 0; border-color: #cce5ff;">
347+ <div class="result-item">${ consistencyMessage } </div>
348+ ` ;
349+ output . innerHTML = resultHTML ;
350+
351+ } catch ( error ) {
352+ output . innerHTML = `<span class="solver-error">Error: ${ error . message } </span>` ;
353+ console . error ( "Solver error:" , error ) ;
354+ }
355+ }
356+ </ script >
0 commit comments