MRevenant commited on
Commit
0067887
·
verified ·
1 Parent(s): e354b80

You are "Artisan Forge," a master digital craftsman and mechanical engineer specializing in metal fabrication. You are creating a comprehensive, interactive, and visually stunning web-based calculator for tube and pipe bending. The tool must be professional, intuitive, and powerful enough for both seasoned fabricators and engineering students. It should not only calculate but also *teach* and *visualize* the concepts. **Core Objective:** Design a single-page web application using HTML, CSS, and JavaScript. The page must include all features below in a clean, organized, and responsive layout. **Feature Set (Implement in Detail):** **1. Input Section (The Anvil):** * Create a form with clearly labeled input fields with appropriate units: * **Outer Diameter (OD):** (mm or in) - dropdown for unit selection. * **Wall Thickness (WT):** (mm or in) * **Bend Radius (CLR):** (mm or in) - Note: This is the Centerline Radius. * **Bend Angle (α):** (degrees) - Slider input (0° to 180°) alongside numeric input. * **Material:** Dropdown menu (e.g., Mild Steel, Stainless Steel 304, Aluminum 6061-T6, Copper). Each material must have a predefined **Tensile Strength (TS)** and **Modulus of Elasticity (E)** stored in a JavaScript object. * **K-Factor Input:** Auto-calculated but with an option for a user-defined "Expert Override" input field. **2. Calculated Results (The Measurements):** * Calculate and display the following results clearly: * **Bend Allowance (BA):** The length of the neutral axis within the bend. * **Bend Deduction (BD):** The difference between the sum of the flange lengths and the initial flat length. * **Elongation (%):** The percentage of stretching on the outer fiber. `Elongation % = ((OD / (2 * CLR)) * 100)`. **CRITICAL:** Compare this value to the material's typical maximum elongation (e.g., Mild Steel ~20-30%). Implement a color-coded system (Green/Yellow/Red) to warn users of potential cracking. * **Bending Force (F):** Calculate the force required for air bending (in tons). `F = (k * TS * width * thickness^2) / (die_width)`. Assume `k=1.33` for a air bending and provide tooltips explaining the variables. Let the user input `Die Width` or provide a reasonable default based on material and thickness. **3. K-Factor Visualization (The Soul of the Bend):** * This is the **"special" visual element**. Create an interactive SVG or Canvas graphic. * Draw a cross-section of the tube being bent. * Clearly label the Neutral Axis, Inside of Bend (Compression), and Outside of Bend (Tension). * The K-Factor is the ratio `(t - distance from inside face to neutral axis) / t`. Visually represent this ratio with a dynamic bar or a movable line that adjusts as the user changes inputs (especially Thickness and Radius). * **Animation:** When the user inputs a new Bend Radius, animate the graphic to show the tube bending and the neutral axis shifting inward. The shift should be proportional to the calculated K-Factor. A smaller radius should show a more significant shift. **4. Safety Factor & Warnings (The Guardian):** * This is the **"sense"** feature for practicality and safety. * Based on the calculated **Elongation %** and the selected material's known ductility limits, display a clear warning message. * *Green Checkmark:* "Elongation within safe limits." * *Yellow Exclamation:* "Approaching material limits. Consider a larger bend radius." * *Red X:* "Warning! Elongation exceeds typical material limits. High risk of cracking or failure." * For the **Bending Force,** compare the calculated tonnage to a range of common press brake capacities (e.g., 20-ton, 50-ton, 100-ton). Display a message: "Required force: X tons. Suitable for a [e.g., 50-ton] press brake." **5. Flange Length Calculator (The Practicality):** * Allow users to input their desired **Leg Length A** and **Leg Length B** (the straight sections on either side of the bend). * Calculate and output the **Total Flat Length** required before bending: `Flat_Length = Leg_A + Leg_B + BD - (2 * CLR)`. **UI/UX & Design (The Aesthetic):** * **Theme:** Use a dark theme interface reminiscent of a modern CNC machine control panel (dark slate gray background, light blue/green text for highlights, amber for warnings). * **Layout:** Use a grid layout. Left column for inputs, center column for results and warnings, right column for the K-Factor visualization. * **Interactivity:** Use real-time calculation. Results update instantly as the user types or moves sliders. * **Tooltips:** Add small (i) icons next to every technical term (K-Factor, BA, BD, CLR). On hover, show a brief, simple explanation. **JavaScript Logic:** * Pre-define material properties in an object: `materials = { "Mild Steel": { tensileStrength: 400, modulus: 210000, maxElongation: 22 }, ... }` * Write functions for each calculation: `calculateKFactor()`, `calculateBA()`, `calculateBD()`, `calculateElongation()`, `calculateForce()`. * Use event listeners (`oninput`, `onchange`) on all form elements to trigger a `updateCalculations()` function that runs all other functions and updates the DOM. **Final Instruction:** Output the complete, ready-to-run code in a single code block. Include all HTML structure, CSS styling, and JavaScript logic. The code must be clean, well-commented, and functional upon execution. - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +1214 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Artisan Prompt
3
- emoji: 📚
4
- colorFrom: green
5
- colorTo: blue
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: artisan-prompt
3
+ emoji: 🐳
4
+ colorFrom: blue
5
+ colorTo: gray
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1214 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Artisan Forge | Tube & Pipe Bending Calculator</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
9
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
10
+ <style>
11
+ /* Custom styles for the CNC-like interface */
12
+ .cnc-panel {
13
+ background-color: #1a202c;
14
+ color: #e2e8f0;
15
+ border: 1px solid #2d3748;
16
+ box-shadow: 0 0 15px rgba(16, 185, 129, 0.2);
17
+ }
18
+
19
+ .cnc-button {
20
+ background-color: #2d3748;
21
+ color: #81e6d9;
22
+ border: 1px solid #4a5568;
23
+ transition: all 0.3s ease;
24
+ }
25
+
26
+ .cnc-button:hover {
27
+ background-color: #4a5568;
28
+ color: #b2f5ea;
29
+ }
30
+
31
+ .input-highlight {
32
+ border-color: #38b2ac;
33
+ background-color: #2d3748;
34
+ }
35
+
36
+ .tooltip {
37
+ position: relative;
38
+ display: inline-block;
39
+ }
40
+
41
+ .tooltip .tooltiptext {
42
+ visibility: hidden;
43
+ width: 200px;
44
+ background-color: #2d3748;
45
+ color: #e2e8f0;
46
+ text-align: center;
47
+ border-radius: 6px;
48
+ padding: 5px;
49
+ position: absolute;
50
+ z-index: 1;
51
+ bottom: 125%;
52
+ left: 50%;
53
+ margin-left: -100px;
54
+ opacity: 0;
55
+ transition: opacity 0.3s;
56
+ border: 1px solid #4a5568;
57
+ font-size: 0.8rem;
58
+ }
59
+
60
+ .tooltip:hover .tooltiptext {
61
+ visibility: visible;
62
+ opacity: 1;
63
+ }
64
+
65
+ #kFactorVisualization {
66
+ background-color: #2d3748;
67
+ border: 1px solid #4a5568;
68
+ border-radius: 0.375rem;
69
+ }
70
+
71
+ .safe {
72
+ color: #68d391;
73
+ }
74
+
75
+ .warning {
76
+ color: #f6e05e;
77
+ }
78
+
79
+ .danger {
80
+ color: #fc8181;
81
+ }
82
+
83
+ .slidecontainer {
84
+ width: 100%;
85
+ }
86
+
87
+ .slider {
88
+ -webkit-appearance: none;
89
+ width: 100%;
90
+ height: 8px;
91
+ border-radius: 5px;
92
+ background: #4a5568;
93
+ outline: none;
94
+ }
95
+
96
+ .slider::-webkit-slider-thumb {
97
+ -webkit-appearance: none;
98
+ appearance: none;
99
+ width: 18px;
100
+ height: 18px;
101
+ border-radius: 50%;
102
+ background: #38b2ac;
103
+ cursor: pointer;
104
+ }
105
+
106
+ .slider::-moz-range-thumb {
107
+ width: 18px;
108
+ height: 18px;
109
+ border-radius: 50%;
110
+ background: #38b2ac;
111
+ cursor: pointer;
112
+ }
113
+
114
+ /* Animation for the bend visualization */
115
+ @keyframes bendAnimation {
116
+ 0% { transform: rotate(0deg); }
117
+ 100% { transform: rotate(var(--bend-angle)); }
118
+ }
119
+
120
+ .bend-animation {
121
+ transform-origin: left center;
122
+ animation: bendAnimation 1s ease-out forwards;
123
+ }
124
+ </style>
125
+ </head>
126
+ <body class="bg-gray-900 text-gray-200 min-h-screen">
127
+ <div class="container mx-auto px-4 py-8">
128
+ <header class="text-center mb-8">
129
+ <h1 class="text-4xl font-bold text-teal-400 mb-2">Artisan Forge</h1>
130
+ <h2 class="text-2xl text-teal-300">Tube & Pipe Bending Calculator</h2>
131
+ <p class="text-gray-400 mt-2">Precision calculations for professional metal fabrication</p>
132
+ </header>
133
+
134
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
135
+ <!-- Input Section (Left Column) -->
136
+ <div class="cnc-panel p-6 rounded-lg">
137
+ <h3 class="text-xl font-semibold text-teal-300 mb-4 border-b border-gray-700 pb-2">
138
+ <i class="fas fa-tools mr-2"></i>Bend Parameters
139
+ </h3>
140
+
141
+ <div class="space-y-4">
142
+ <!-- Unit Selection -->
143
+ <div class="flex items-center space-x-4 mb-4">
144
+ <div>
145
+ <label class="block text-sm font-medium mb-1">Units</label>
146
+ <select id="unitSystem" class="cnc-button rounded px-3 py-2 w-full">
147
+ <option value="metric">Metric (mm)</option>
148
+ <option value="imperial">Imperial (in)</option>
149
+ </select>
150
+ </div>
151
+ </div>
152
+
153
+ <!-- Outer Diameter -->
154
+ <div>
155
+ <label for="outerDiameter" class="block text-sm font-medium mb-1 flex items-center">
156
+ Outer Diameter (OD)
157
+ <span class="tooltip ml-1">
158
+ <i class="fas fa-info-circle text-blue-400"></i>
159
+ <span class="tooltiptext">The external diameter of the tube or pipe</span>
160
+ </span>
161
+ </label>
162
+ <div class="flex">
163
+ <input type="number" id="outerDiameter" min="0" step="0.01"
164
+ class="input-highlight rounded-l px-3 py-2 w-full focus:outline-none focus:ring-1 focus:ring-teal-500">
165
+ <span id="odUnit" class="cnc-button rounded-r px-3 py-2">mm</span>
166
+ </div>
167
+ </div>
168
+
169
+ <!-- Wall Thickness -->
170
+ <div>
171
+ <label for="wallThickness" class="block text-sm font-medium mb-1 flex items-center">
172
+ Wall Thickness (WT)
173
+ <span class="tooltip ml-1">
174
+ <i class="fas fa-info-circle text-blue-400"></i>
175
+ <span class="tooltiptext">Thickness of the tube/pipe wall</span>
176
+ </span>
177
+ </label>
178
+ <div class="flex">
179
+ <input type="number" id="wallThickness" min="0" step="0.01"
180
+ class="input-highlight rounded-l px-3 py-2 w-full focus:outline-none focus:ring-1 focus:ring-teal-500">
181
+ <span id="wtUnit" class="cnc-button rounded-r px-3 py-2">mm</span>
182
+ </div>
183
+ </div>
184
+
185
+ <!-- Bend Radius -->
186
+ <div>
187
+ <label for="bendRadius" class="block text-sm font-medium mb-1 flex items-center">
188
+ Bend Radius (CLR)
189
+ <span class="tooltip ml-1">
190
+ <i class="fas fa-info-circle text-blue-400"></i>
191
+ <span class="tooltiptext">Centerline Radius - distance from bend center to tube centerline</span>
192
+ </span>
193
+ </label>
194
+ <div class="flex">
195
+ <input type="number" id="bendRadius" min="0" step="0.01"
196
+ class="input-highlight rounded-l px-3 py-2 w-full focus:outline-none focus:ring-1 focus:ring-teal-500">
197
+ <span id="clrUnit" class="cnc-button rounded-r px-3 py-2">mm</span>
198
+ </div>
199
+ </div>
200
+
201
+ <!-- Bend Angle -->
202
+ <div>
203
+ <label for="bendAngle" class="block text-sm font-medium mb-1 flex items-center">
204
+ Bend Angle (α)
205
+ <span class="tooltip ml-1">
206
+ <i class="fas fa-info-circle text-blue-400"></i>
207
+ <span class="tooltiptext">Angle of the bend in degrees (0-180°)</span>
208
+ </span>
209
+ </label>
210
+ <div class="slidecontainer mb-2">
211
+ <input type="range" min="0" max="180" value="90" class="slider" id="bendAngleSlider">
212
+ </div>
213
+ <div class="flex">
214
+ <input type="number" id="bendAngle" min="0" max="180" step="1"
215
+ class="input-highlight rounded-l px-3 py-2 w-full focus:outline-none focus:ring-1 focus:ring-teal-500">
216
+ <span class="cnc-button rounded-r px-3 py-2">°</span>
217
+ </div>
218
+ </div>
219
+
220
+ <!-- Material Selection -->
221
+ <div>
222
+ <label for="material" class="block text-sm font-medium mb-1 flex items-center">
223
+ Material
224
+ <span class="tooltip ml-1">
225
+ <i class="fas fa-info-circle text-blue-400"></i>
226
+ <span class="tooltiptext">Material affects elongation limits and bending force</span>
227
+ </span>
228
+ </label>
229
+ <select id="material" class="cnc-button rounded px-3 py-2 w-full">
230
+ <option value="Mild Steel">Mild Steel</option>
231
+ <option value="Stainless Steel 304">Stainless Steel 304</option>
232
+ <option value="Aluminum 6061-T6">Aluminum 6061-T6</option>
233
+ <option value="Copper">Copper</option>
234
+ <option value="Brass">Brass</option>
235
+ </select>
236
+ </div>
237
+
238
+ <!-- Die Width -->
239
+ <div>
240
+ <label for="dieWidth" class="block text-sm font-medium mb-1 flex items-center">
241
+ Die Width
242
+ <span class="tooltip ml-1">
243
+ <i class="fas fa-info-circle text-blue-400"></i>
244
+ <span class="tooltiptext">Width of the die opening in the press brake</span>
245
+ </span>
246
+ </label>
247
+ <div class="flex">
248
+ <input type="number" id="dieWidth" min="0" step="0.1" value="30"
249
+ class="input-highlight rounded-l px-3 py-2 w-full focus:outline-none focus:ring-1 focus:ring-teal-500">
250
+ <span id="dieWidthUnit" class="cnc-button rounded-r px-3 py-2">mm</span>
251
+ </div>
252
+ </div>
253
+
254
+ <!-- K-Factor -->
255
+ <div>
256
+ <label for="kFactor" class="block text-sm font-medium mb-1 flex items-center">
257
+ K-Factor
258
+ <span class="tooltip ml-1">
259
+ <i class="fas fa-info-circle text-blue-400"></i>
260
+ <span class="tooltiptext">Ratio of neutral axis position to material thickness</span>
261
+ </span>
262
+ </label>
263
+ <div class="flex items-center">
264
+ <input type="number" id="kFactor" min="0" max="1" step="0.001"
265
+ class="input-highlight rounded-l px-3 py-2 w-full focus:outline-none focus:ring-1 focus:ring-teal-500">
266
+ <button id="kFactorLock" class="cnc-button px-3 py-2 border-l-0 rounded-r">
267
+ <i class="fas fa-lock"></i>
268
+ </button>
269
+ </div>
270
+ <div class="text-xs text-gray-400 mt-1">Auto-calculated. Click lock to override.</div>
271
+ </div>
272
+
273
+ <!-- Flange Lengths -->
274
+ <div class="pt-4 border-t border-gray-700">
275
+ <h4 class="text-sm font-medium mb-2 text-teal-300">Flange Lengths (Optional)</h4>
276
+ <div class="grid grid-cols-2 gap-4">
277
+ <div>
278
+ <label for="legLengthA" class="block text-xs font-medium mb-1">Leg Length A</label>
279
+ <div class="flex">
280
+ <input type="number" id="legLengthA" min="0" step="1"
281
+ class="input-highlight rounded-l px-3 py-2 w-full focus:outline-none focus:ring-1 focus:ring-teal-500">
282
+ <span id="flangeUnit" class="cnc-button rounded-r px-3 py-2">mm</span>
283
+ </div>
284
+ </div>
285
+ <div>
286
+ <label for="legLengthB" class="block text-xs font-medium mb-1">Leg Length B</label>
287
+ <div class="flex">
288
+ <input type="number" id="legLengthB" min="0" step="1"
289
+ class="input-highlight rounded-l px-3 py-2 w-full focus:outline-none focus:ring-1 focus:ring-teal-500">
290
+ <span class="cnc-button rounded-r px-3 py-2">mm</span>
291
+ </div>
292
+ </div>
293
+ </div>
294
+ </div>
295
+ </div>
296
+ </div>
297
+
298
+ <!-- Results Section (Middle Column) -->
299
+ <div class="cnc-panel p-6 rounded-lg">
300
+ <h3 class="text-xl font-semibold text-teal-300 mb-4 border-b border-gray-700 pb-2">
301
+ <i class="fas fa-calculator mr-2"></i>Calculated Results
302
+ </h3>
303
+
304
+ <div class="space-y-6">
305
+ <!-- Bend Allowance -->
306
+ <div class="bg-gray-800 p-4 rounded-lg">
307
+ <div class="flex justify-between items-center mb-2">
308
+ <h4 class="font-medium flex items-center">
309
+ Bend Allowance (BA)
310
+ <span class="tooltip ml-1">
311
+ <i class="fas fa-info-circle text-blue-400"></i>
312
+ <span class="tooltiptext">Length of the neutral axis within the bend</span>
313
+ </span>
314
+ </h4>
315
+ <div class="text-lg font-mono" id="bendAllowance">0.00</div>
316
+ </div>
317
+ <div class="text-xs text-gray-400">BA = α × (π/180) × (CLR + K×t)</div>
318
+ </div>
319
+
320
+ <!-- Bend Deduction -->
321
+ <div class="bg-gray-800 p-4 rounded-lg">
322
+ <div class="flex justify-between items-center mb-2">
323
+ <h4 class="font-medium flex items-center">
324
+ Bend Deduction (BD)
325
+ <span class="tooltip ml-1">
326
+ <i class="fas fa-info-circle text-blue-400"></i>
327
+ <span class="tooltiptext">Difference between flange lengths and flat length</span>
328
+ </span>
329
+ </h4>
330
+ <div class="text-lg font-mono" id="bendDeduction">0.00</div>
331
+ </div>
332
+ <div class="text-xs text-gray-400">BD = 2 × (CLR + t) × tan(α/2) - BA</div>
333
+ </div>
334
+
335
+ <!-- Elongation Warning -->
336
+ <div class="bg-gray-800 p-4 rounded-lg" id="elongationContainer">
337
+ <div class="flex justify-between items-center mb-2">
338
+ <h4 class="font-medium flex items-center">
339
+ Elongation
340
+ <span class="tooltip ml-1">
341
+ <i class="fas fa-info-circle text-blue-400"></i>
342
+ <span class="tooltiptext">Percentage of stretching on the outer fiber</span>
343
+ </span>
344
+ </h4>
345
+ <div class="text-lg font-mono" id="elongation">0.00</div>
346
+ </div>
347
+ <div class="text-xs text-gray-400 mb-2">Elongation % = (OD / (2 × CLR)) × 100</div>
348
+ <div class="flex items-center" id="elongationWarning">
349
+ <i class="fas fa-check-circle mr-2 safe"></i>
350
+ <span class="text-sm safe">Elongation within safe limits</span>
351
+ </div>
352
+ <div class="mt-2 text-xs text-gray-400" id="materialMaxElongation">Material limit: 22%</div>
353
+ </div>
354
+
355
+ <!-- Bending Force -->
356
+ <div class="bg-gray-800 p-4 rounded-lg">
357
+ <div class="flex justify-between items-center mb-2">
358
+ <h4 class="font-medium flex items-center">
359
+ Bending Force
360
+ <span class="tooltip ml-1">
361
+ <i class="fas fa-info-circle text-blue-400"></i>
362
+ <span class="tooltiptext">Force required for air bending</span>
363
+ </span>
364
+ </h4>
365
+ <div class="text-lg font-mono" id="bendingForce">0.00</div>
366
+ </div>
367
+ <div class="text-xs text-gray-400 mb-2">F = (1.33 × TS × t² × width) / die_width</div>
368
+ <div class="text-sm" id="forceSuggestion">Suitable for a 20-ton press brake</div>
369
+ </div>
370
+
371
+ <!-- Flange Length Results -->
372
+ <div class="bg-gray-800 p-4 rounded-lg" id="flangeResultsContainer">
373
+ <div class="flex justify-between items-center mb-2">
374
+ <h4 class="font-medium">Total Flat Length</h4>
375
+ <div class="text-lg font-mono" id="totalFlatLength">0.00</div>
376
+ </div>
377
+ <div class="text-xs text-gray-400">Flat Length = Leg_A + Leg_B + BD - (2 × CLR)</div>
378
+ </div>
379
+
380
+ <!-- Safety Notes -->
381
+ <div class="bg-gray-800 p-4 rounded-lg">
382
+ <h4 class="font-medium text-teal-300 mb-2">Safety Notes</h4>
383
+ <ul class="text-sm space-y-2">
384
+ <li class="flex items-start">
385
+ <i class="fas fa-info-circle text-blue-400 mt-1 mr-2"></i>
386
+ <span>Always verify calculations with physical tests before full production</span>
387
+ </li>
388
+ <li class="flex items-start">
389
+ <i class="fas fa-info-circle text-blue-400 mt-1 mr-2"></i>
390
+ <span>Consider springback - materials may return slightly after bending</span>
391
+ </li>
392
+ <li class="flex items-start">
393
+ <i class="fas fa-info-circle text-blue-400 mt-1 mr-2"></i>
394
+ <span>Use proper tooling and safety equipment when bending</span>
395
+ </li>
396
+ </ul>
397
+ </div>
398
+ </div>
399
+ </div>
400
+
401
+ <!-- Visualization Section (Right Column) -->
402
+ <div class="cnc-panel p-6 rounded-lg">
403
+ <h3 class="text-xl font-semibold text-teal-300 mb-4 border-b border-gray-700 pb-2">
404
+ <i class="fas fa-project-diagram mr-2"></i>Bend Visualization
405
+ </h3>
406
+
407
+ <div class="space-y-6">
408
+ <!-- K-Factor Visualization -->
409
+ <div>
410
+ <h4 class="font-medium mb-2 flex items-center">
411
+ K-Factor Visualization
412
+ <span class="tooltip ml-1">
413
+ <i class="fas fa-info-circle text-blue-400"></i>
414
+ <span class="tooltiptext">Shows neutral axis position relative to thickness</span>
415
+ </span>
416
+ </h4>
417
+ <div class="relative h-48" id="kFactorVisualization">
418
+ <canvas id="kFactorCanvas" class="absolute inset-0 w-full h-full"></canvas>
419
+ </div>
420
+ <div class="text-center mt-2 text-sm">
421
+ <span id="kFactorValue">K-Factor: 0.42</span>
422
+ </div>
423
+ </div>
424
+
425
+ <!-- Bend Animation -->
426
+ <div>
427
+ <h4 class="font-medium mb-2 flex items-center">
428
+ Bend Animation
429
+ <span class="tooltip ml-1">
430
+ <i class="fas fa-info-circle text-blue-400"></i>
431
+ <span class="tooltiptext">Shows the bending process with neutral axis</span>
432
+ </span>
433
+ </h4>
434
+ <div class="relative h-48" id="bendAnimationContainer">
435
+ <canvas id="bendAnimationCanvas" class="absolute inset-0 w-full h-full"></canvas>
436
+ </div>
437
+ <div class="text-center mt-2">
438
+ <button id="animateBend" class="cnc-button px-4 py-2 rounded text-sm">
439
+ <i class="fas fa-play mr-2"></i>Animate Bend
440
+ </button>
441
+ </div>
442
+ </div>
443
+
444
+ <!-- Material Properties -->
445
+ <div class="bg-gray-800 p-4 rounded-lg">
446
+ <h4 class="font-medium text-teal-300 mb-2">Material Properties</h4>
447
+ <table class="w-full text-sm">
448
+ <tbody>
449
+ <tr>
450
+ <td class="py-1">Tensile Strength</td>
451
+ <td class="py-1 text-right font-mono" id="matTensileStrength">400 MPa</td>
452
+ </tr>
453
+ <tr>
454
+ <td class="py-1">Modulus of Elasticity</td>
455
+ <td class="py-1 text-right font-mono" id="matModulus">210,000 MPa</td>
456
+ </tr>
457
+ <tr>
458
+ <td class="py-1">Max Elongation</td>
459
+ <td class="py-1 text-right font-mono" id="matMaxElongation">22%</td>
460
+ </tr>
461
+ </tbody>
462
+ </table>
463
+ </div>
464
+ </div>
465
+ </div>
466
+ </div>
467
+
468
+ <footer class="mt-12 text-center text-gray-500 text-sm">
469
+ <p>Artisan Forge - Tube & Pipe Bending Calculator v1.0</p>
470
+ <p class="mt-1">For educational and professional use. Always verify with physical tests.</p>
471
+ </footer>
472
+ </div>
473
+
474
+ <script>
475
+ // Material properties database
476
+ const materials = {
477
+ "Mild Steel": {
478
+ tensileStrength: 400, // MPa
479
+ modulus: 210000, // MPa
480
+ maxElongation: 22, // %
481
+ color: "#9CA3AF" // gray
482
+ },
483
+ "Stainless Steel 304": {
484
+ tensileStrength: 515, // MPa
485
+ modulus: 193000, // MPa
486
+ maxElongation: 40, // %
487
+ color: "#E5E7EB" // light gray
488
+ },
489
+ "Aluminum 6061-T6": {
490
+ tensileStrength: 310, // MPa
491
+ modulus: 68900, // MPa
492
+ maxElongation: 12, // %
493
+ color: "#6EE7B7" // teal
494
+ },
495
+ "Copper": {
496
+ tensileStrength: 210, // MPa
497
+ modulus: 117000, // MPa
498
+ maxElongation: 45, // %
499
+ color: "#D97706" // amber
500
+ },
501
+ "Brass": {
502
+ tensileStrength: 340, // MPa
503
+ modulus: 102000, // MPa
504
+ maxElongation: 35, // %
505
+ color: "#F59E0B" // yellow
506
+ }
507
+ };
508
+
509
+ // DOM elements
510
+ const unitSystem = document.getElementById('unitSystem');
511
+ const outerDiameter = document.getElementById('outerDiameter');
512
+ const wallThickness = document.getElementById('wallThickness');
513
+ const bendRadius = document.getElementById('bendRadius');
514
+ const bendAngle = document.getElementById('bendAngle');
515
+ const bendAngleSlider = document.getElementById('bendAngleSlider');
516
+ const material = document.getElementById('material');
517
+ const dieWidth = document.getElementById('dieWidth');
518
+ const kFactor = document.getElementById('kFactor');
519
+ const kFactorLock = document.getElementById('kFactorLock');
520
+ const legLengthA = document.getElementById('legLengthA');
521
+ const legLengthB = document.getElementById('legLengthB');
522
+
523
+ // Result elements
524
+ const bendAllowance = document.getElementById('bendAllowance');
525
+ const bendDeduction = document.getElementById('bendDeduction');
526
+ const elongation = document.getElementById('elongation');
527
+ const elongationWarning = document.getElementById('elongationWarning');
528
+ const materialMaxElongation = document.getElementById('materialMaxElongation');
529
+ const bendingForce = document.getElementById('bendingForce');
530
+ const forceSuggestion = document.getElementById('forceSuggestion');
531
+ const totalFlatLength = document.getElementById('totalFlatLength');
532
+ const flangeResultsContainer = document.getElementById('flangeResultsContainer');
533
+
534
+ // Visualization elements
535
+ const kFactorValue = document.getElementById('kFactorValue');
536
+ const animateBend = document.getElementById('animateBend');
537
+
538
+ // Material property displays
539
+ const matTensileStrength = document.getElementById('matTensileStrength');
540
+ const matModulus = document.getElementById('matModulus');
541
+ const matMaxElongation = document.getElementById('matMaxElongation');
542
+
543
+ // Unit displays
544
+ const odUnit = document.getElementById('odUnit');
545
+ const wtUnit = document.getElementById('wtUnit');
546
+ const clrUnit = document.getElementById('clrUnit');
547
+ const dieWidthUnit = document.getElementById('dieWidthUnit');
548
+ const flangeUnit = document.getElementById('flangeUnit');
549
+
550
+ // Canvas elements
551
+ const kFactorCanvas = document.getElementById('kFactorCanvas');
552
+ const kFactorCtx = kFactorCanvas.getContext('2d');
553
+ const bendAnimationCanvas = document.getElementById('bendAnimationCanvas');
554
+ const bendAnimationCtx = bendAnimationCanvas.getContext('2d');
555
+
556
+ // State variables
557
+ let isKFactorLocked = false;
558
+ let currentKFactor = 0.42;
559
+
560
+ // Initialize the app
561
+ function init() {
562
+ // Set up event listeners
563
+ unitSystem.addEventListener('change', updateUnits);
564
+ outerDiameter.addEventListener('input', updateCalculations);
565
+ wallThickness.addEventListener('input', updateCalculations);
566
+ bendRadius.addEventListener('input', updateCalculations);
567
+ bendAngle.addEventListener('input', updateBendAngleFromInput);
568
+ bendAngleSlider.addEventListener('input', updateBendAngleFromSlider);
569
+ material.addEventListener('change', updateMaterialProperties);
570
+ dieWidth.addEventListener('input', updateCalculations);
571
+ kFactor.addEventListener('input', updateKFactorFromInput);
572
+ kFactorLock.addEventListener('click', toggleKFactorLock);
573
+ legLengthA.addEventListener('input', updateCalculations);
574
+ legLengthB.addEventListener('input', updateCalculations);
575
+ animateBend.addEventListener('click', animateBendProcess);
576
+
577
+ // Set up canvas
578
+ resizeCanvases();
579
+ window.addEventListener('resize', resizeCanvases);
580
+
581
+ // Set default values
582
+ outerDiameter.value = 50;
583
+ wallThickness.value = 2;
584
+ bendRadius.value = 75;
585
+ bendAngle.value = 90;
586
+ bendAngleSlider.value = 90;
587
+
588
+ // Initialize calculations
589
+ updateMaterialProperties();
590
+ updateCalculations();
591
+ }
592
+
593
+ // Update all unit displays
594
+ function updateUnits() {
595
+ const isMetric = unitSystem.value === 'metric';
596
+ const unit = isMetric ? 'mm' : 'in';
597
+
598
+ odUnit.textContent = unit;
599
+ wtUnit.textContent = unit;
600
+ clrUnit.textContent = unit;
601
+ dieWidthUnit.textContent = unit;
602
+ flangeUnit.textContent = unit;
603
+
604
+ updateCalculations();
605
+ }
606
+
607
+ // Update material property displays
608
+ function updateMaterialProperties() {
609
+ const selectedMaterial = material.value;
610
+ const matProps = materials[selectedMaterial];
611
+
612
+ matTensileStrength.textContent = `${matProps.tensileStrength} MPa`;
613
+ matModulus.textContent = `${matProps.modulus.toLocaleString()} MPa`;
614
+ matMaxElongation.textContent = `${matProps.maxElongation}%`;
615
+
616
+ updateCalculations();
617
+ }
618
+
619
+ // Update bend angle from slider
620
+ function updateBendAngleFromSlider() {
621
+ bendAngle.value = bendAngleSlider.value;
622
+ updateCalculations();
623
+ }
624
+
625
+ // Update bend angle from input
626
+ function updateBendAngleFromInput() {
627
+ let angle = parseFloat(bendAngle.value);
628
+ if (isNaN(angle)) angle = 0;
629
+ if (angle < 0) angle = 0;
630
+ if (angle > 180) angle = 180;
631
+
632
+ bendAngle.value = angle;
633
+ bendAngleSlider.value = angle;
634
+ updateCalculations();
635
+ }
636
+
637
+ // Toggle K-Factor lock
638
+ function toggleKFactorLock() {
639
+ isKFactorLocked = !isKFactorLocked;
640
+ kFactorLock.innerHTML = isKFactorLocked ? '<i class="fas fa-lock-open"></i>' : '<i class="fas fa-lock"></i>';
641
+ kFactorLock.title = isKFactorLocked ? 'Click to unlock and auto-calculate' : 'Click to lock and override';
642
+ updateCalculations();
643
+ }
644
+
645
+ // Update K-Factor from input
646
+ function updateKFactorFromInput() {
647
+ let factor = parseFloat(kFactor.value);
648
+ if (isNaN(factor)) factor = 0.42;
649
+ if (factor < 0) factor = 0;
650
+ if (factor > 1) factor = 1;
651
+
652
+ currentKFactor = factor;
653
+ updateCalculations();
654
+ }
655
+
656
+ // Calculate K-Factor based on inputs
657
+ function calculateKFactor() {
658
+ if (isKFactorLocked) return currentKFactor;
659
+
660
+ const t = parseFloat(wallThickness.value);
661
+ const r = parseFloat(bendRadius.value);
662
+
663
+ if (isNaN(t) || isNaN(r) || t === 0 || r === 0) return 0.42;
664
+
665
+ // Empirical formula for K-Factor
666
+ const ratio = r / t;
667
+ let factor;
668
+
669
+ if (ratio < 1) {
670
+ factor = 0.3;
671
+ } else if (ratio < 2) {
672
+ factor = 0.33;
673
+ } else if (ratio < 3) {
674
+ factor = 0.4;
675
+ } else if (ratio < 4) {
676
+ factor = 0.45;
677
+ } else {
678
+ factor = 0.5;
679
+ }
680
+
681
+ currentKFactor = factor;
682
+ kFactor.value = factor.toFixed(3);
683
+ return factor;
684
+ }
685
+
686
+ // Calculate Bend Allowance
687
+ function calculateBendAllowance() {
688
+ const angle = parseFloat(bendAngle.value);
689
+ const r = parseFloat(bendRadius.value);
690
+ const t = parseFloat(wallThickness.value);
691
+ const k = calculateKFactor();
692
+
693
+ if (isNaN(angle) || isNaN(r) || isNaN(t)) return 0;
694
+
695
+ // BA = angle × (π/180) × (radius + K × thickness)
696
+ const ba = angle * (Math.PI / 180) * (r + k * t);
697
+ return ba;
698
+ }
699
+
700
+ // Calculate Bend Deduction
701
+ function calculateBendDeduction() {
702
+ const angle = parseFloat(bendAngle.value);
703
+ const r = parseFloat(bendRadius.value);
704
+ const t = parseFloat(wallThickness.value);
705
+ const ba = calculateBendAllowance();
706
+
707
+ if (isNaN(angle) || isNaN(r) || isNaN(t)) return 0;
708
+
709
+ // BD = 2 × (radius + thickness) × tan(angle/2) - BA
710
+ const bd = 2 * (r + t) * Math.tan(angle * Math.PI / 360) - ba;
711
+ return bd;
712
+ }
713
+
714
+ // Calculate Elongation
715
+ function calculateElongation() {
716
+ const od = parseFloat(outerDiameter.value);
717
+ const r = parseFloat(bendRadius.value);
718
+
719
+ if (isNaN(od) || isNaN(r) || r === 0) return 0;
720
+
721
+ // Elongation % = (OD / (2 × CLR)) × 100
722
+ const elongationPercent = (od / (2 * r)) * 100;
723
+ return elongationPercent;
724
+ }
725
+
726
+ // Calculate Bending Force
727
+ function calculateBendingForce() {
728
+ const selectedMaterial = material.value;
729
+ const matProps = materials[selectedMaterial];
730
+ const t = parseFloat(wallThickness.value);
731
+ const dw = parseFloat(dieWidth.value);
732
+ const od = parseFloat(outerDiameter.value);
733
+
734
+ if (isNaN(t) || isNaN(dw) || isNaN(od) || dw === 0) return 0;
735
+
736
+ // Convert units if necessary
737
+ let width = od * Math.PI; // Approximate width as circumference
738
+ if (unitSystem.value === 'imperial') {
739
+ // Convert from inches to mm for calculation (material props are in MPa)
740
+ width *= 25.4;
741
+ t *= 25.4;
742
+ dw *= 25.4;
743
+ }
744
+
745
+ // F = (1.33 × TS × t² × width) / die_width
746
+ // Result will be in Newtons (divide by 9806.65 to get metric tons)
747
+ const forceNewtons = (1.33 * matProps.tensileStrength * Math.pow(t, 2) * width) / dw;
748
+ const forceTons = forceNewtons / 9806.65;
749
+
750
+ if (unitSystem.value === 'imperial') {
751
+ // Convert to US tons (1 metric ton = 1.10231 US tons)
752
+ return forceTons * 1.10231;
753
+ }
754
+
755
+ return forceTons;
756
+ }
757
+
758
+ // Calculate Total Flat Length
759
+ function calculateTotalFlatLength() {
760
+ const legA = parseFloat(legLengthA.value);
761
+ const legB = parseFloat(legLengthB.value);
762
+ const bd = calculateBendDeduction();
763
+ const r = parseFloat(bendRadius.value);
764
+
765
+ if (isNaN(legA) || isNaN(legB)) return null;
766
+
767
+ // Flat Length = Leg_A + Leg_B + BD - (2 × CLR)
768
+ const flatLength = legA + legB + bd - (2 * r);
769
+ return flatLength;
770
+ }
771
+
772
+ // Update all calculations and displays
773
+ function updateCalculations() {
774
+ // Calculate all values
775
+ const k = calculateKFactor();
776
+ const ba = calculateBendAllowance();
777
+ const bd = calculateBendDeduction();
778
+ const elongationPercent = calculateElongation();
779
+ const force = calculateBendingForce();
780
+ const flatLength = calculateTotalFlatLength();
781
+
782
+ // Get material properties
783
+ const selectedMaterial = material.value;
784
+ const matProps = materials[selectedMaterial];
785
+
786
+ // Update displays
787
+ kFactorValue.textContent = `K-Factor: ${k.toFixed(3)}`;
788
+
789
+ // Format values with units
790
+ const isMetric = unitSystem.value === 'metric';
791
+ const lengthUnit = isMetric ? 'mm' : 'in';
792
+ const forceUnit = isMetric ? 'tons' : 'US tons';
793
+
794
+ bendAllowance.textContent = `${ba.toFixed(2)} ${lengthUnit}`;
795
+ bendDeduction.textContent = `${bd.toFixed(2)} ${lengthUnit}`;
796
+ elongation.textContent = `${elongationPercent.toFixed(2)}%`;
797
+
798
+ // Update elongation warning
799
+ updateElongationWarning(elongationPercent, matProps.maxElongation);
800
+
801
+ // Update bending force
802
+ bendingForce.textContent = `${force.toFixed(2)} ${forceUnit}`;
803
+ updateForceSuggestion(force);
804
+
805
+ // Update flat length if provided
806
+ if (flatLength !== null) {
807
+ totalFlatLength.textContent = `${flatLength.toFixed(2)} ${lengthUnit}`;
808
+ flangeResultsContainer.classList.remove('hidden');
809
+ } else {
810
+ flangeResultsContainer.classList.add('hidden');
811
+ }
812
+
813
+ // Update visualizations
814
+ drawKFactorVisualization();
815
+ drawBendAnimation();
816
+ }
817
+
818
+ // Update elongation warning based on material limits
819
+ function updateElongationWarning(elongationPercent, maxElongation) {
820
+ const warningIcon = elongationWarning.querySelector('i');
821
+ const warningText = elongationWarning.querySelector('span');
822
+
823
+ // Clear all classes
824
+ warningIcon.className = 'fas mr-2';
825
+ warningText.className = 'text-sm';
826
+
827
+ // Set warning level
828
+ if (elongationPercent > maxElongation) {
829
+ // Danger - exceeds limits
830
+ warningIcon.classList.add('fa-times-circle', 'danger');
831
+ warningText.classList.add('danger');
832
+ warningText.textContent = 'Warning! Elongation exceeds material limits. High risk of cracking.';
833
+ elongationWarning.parentElement.classList.add('border', 'border-red-500');
834
+ } else if (elongationPercent > maxElongation * 0.8) {
835
+ // Warning - approaching limits
836
+ warningIcon.classList.add('fa-exclamation-circle', 'warning');
837
+ warningText.classList.add('warning');
838
+ warningText.textContent = 'Approaching material limits. Consider a larger bend radius.';
839
+ elongationWarning.parentElement.classList.add('border', 'border-yellow-500');
840
+ } else {
841
+ // Safe - within limits
842
+ warningIcon.classList.add('fa-check-circle', 'safe');
843
+ warningText.classList.add('safe');
844
+ warningText.textContent = 'Elongation within safe limits.';
845
+ elongationWarning.parentElement.classList.remove('border', 'border-red-500', 'border-yellow-500');
846
+ }
847
+
848
+ // Update material max elongation display
849
+ materialMaxElongation.textContent = `Material limit: ${maxElongation}%`;
850
+ }
851
+
852
+ // Update press brake suggestion
853
+ function updateForceSuggestion(force) {
854
+ if (isNaN(force)) {
855
+ forceSuggestion.textContent = 'Enter valid parameters to calculate force';
856
+ return;
857
+ }
858
+
859
+ const isMetric = unitSystem.value === 'metric';
860
+ const commonPresses = isMetric ?
861
+ [10, 20, 40, 60, 80, 100, 150, 200] :
862
+ [11, 22, 44, 66, 88, 110, 165, 220]; // US tons
863
+
864
+ let suitablePress = commonPresses.find(capacity => capacity >= force * 1.2); // 20% safety margin
865
+
866
+ if (!suitablePress) {
867
+ suitablePress = commonPresses[commonPresses.length - 1];
868
+ forceSuggestion.textContent = `Required force: ${force.toFixed(1)} ${isMetric ? 'tons' : 'US tons'}. Exceeds standard press brakes (max ${suitablePress} ${isMetric ? 'tons' : 'US tons'}).`;
869
+ } else {
870
+ forceSuggestion.textContent = `Required force: ${force.toFixed(1)} ${isMetric ? 'tons' : 'US tons'}. Suitable for a ${suitablePress}${isMetric ? '-ton' : ' US-ton'} press brake.`;
871
+ }
872
+ }
873
+
874
+ // Draw K-Factor visualization
875
+ function drawKFactorVisualization() {
876
+ const canvas = kFactorCanvas;
877
+ const ctx = kFactorCtx;
878
+ const width = canvas.width;
879
+ const height = canvas.height;
880
+
881
+ // Clear canvas
882
+ ctx.clearRect(0, 0, width, height);
883
+
884
+ const od = parseFloat(outerDiameter.value);
885
+ const t = parseFloat(wallThickness.value);
886
+ const k = calculateKFactor();
887
+
888
+ if (isNaN(od) || isNaN(t) || t === 0) return;
889
+
890
+ // Calculate dimensions
891
+ const tubeRadius = od / 2;
892
+ const innerRadius = tubeRadius - t;
893
+ const neutralAxisRadius = innerRadius + (t * k);
894
+
895
+ // Scale to fit canvas
896
+ const scale = Math.min(width / (od * 1.5), height / (od * 1.5));
897
+ const centerX = width / 2;
898
+ const centerY = height / 2;
899
+
900
+ // Draw tube cross-section
901
+ ctx.beginPath();
902
+ ctx.arc(centerX, centerY, tubeRadius * scale, 0, Math.PI * 2);
903
+ ctx.fillStyle = '#4A5568';
904
+ ctx.fill();
905
+
906
+ ctx.beginPath();
907
+ ctx.arc(centerX, centerY, innerRadius * scale, 0, Math.PI * 2);
908
+ ctx.fillStyle = '#1A202C';
909
+ ctx.fill();
910
+
911
+ // Draw neutral axis
912
+ ctx.beginPath();
913
+ ctx.arc(centerX, centerY, neutralAxisRadius * scale, 0, Math.PI * 2);
914
+ ctx.strokeStyle = '#38B2AC';
915
+ ctx.lineWidth = 2;
916
+ ctx.setLineDash([5, 3]);
917
+ ctx.stroke();
918
+ ctx.setLineDash([]);
919
+
920
+ // Draw indicators
921
+ ctx.font = '10px Arial';
922
+ ctx.fillStyle = '#E2E8F0';
923
+ ctx.textAlign = 'center';
924
+
925
+ // Inside of bend (compression)
926
+ ctx.fillText('Compression', centerX, centerY - (innerRadius + t/2) * scale - 10);
927
+
928
+ // Outside of bend (tension)
929
+ ctx.fillText('Tension', centerX, centerY + (innerRadius + t/2) * scale + 20);
930
+
931
+ // Neutral axis label
932
+ ctx.fillText('Neutral Axis', centerX, centerY - neutralAxisRadius * scale - 10);
933
+
934
+ // Draw dimension lines
935
+ ctx.strokeStyle = '#E2E8F0';
936
+ ctx.lineWidth = 1;
937
+
938
+ // Wall thickness dimension
939
+ ctx.beginPath();
940
+ ctx.moveTo(centerX + tubeRadius * scale + 10, centerY);
941
+ ctx.lineTo(centerX + innerRadius * scale - 10, centerY);
942
+ ctx.stroke();
943
+
944
+ ctx.beginPath();
945
+ ctx.moveTo(centerX + tubeRadius * scale + 5, centerY - 5);
946
+ ctx.lineTo(centerX + tubeRadius * scale + 5, centerY + 5);
947
+ ctx.stroke();
948
+
949
+ ctx.beginPath();
950
+ ctx.moveTo(centerX + innerRadius * scale - 5, centerY - 5);
951
+ ctx.lineTo(centerX + innerRadius * scale - 5, centerY + 5);
952
+ ctx.stroke();
953
+
954
+ ctx.fillText(`t = ${t.toFixed(2)}`, centerX + (tubeRadius + innerRadius) * scale / 2, centerY + 15);
955
+
956
+ // K-Factor dimension
957
+ ctx.beginPath();
958
+ ctx.moveTo(centerX + innerRadius * scale, centerY);
959
+ ctx.lineTo(centerX + neutralAxisRadius * scale, centerY);
960
+ ctx.stroke();
961
+
962
+ ctx.fillText(`K·t = ${(k * t).toFixed(2)}`, centerX + (innerRadius + neutralAxisRadius) * scale / 2, centerY - 5);
963
+ }
964
+
965
+ // Draw bend animation
966
+ function drawBendAnimation() {
967
+ const canvas = bendAnimationCanvas;
968
+ const ctx = bendAnimationCtx;
969
+ const width = canvas.width;
970
+ const height = canvas.height;
971
+
972
+ // Clear canvas
973
+ ctx.clearRect(0, 0, width, height);
974
+
975
+ const od = parseFloat(outerDiameter.value);
976
+ const t = parseFloat(wallThickness.value);
977
+ const r = parseFloat(bendRadius.value);
978
+ const angle = parseFloat(bendAngle.value);
979
+ const k = calculateKFactor();
980
+
981
+ if (isNaN(od) || isNaN(t) || isNaN(r) || isNaN(angle)) return;
982
+
983
+ // Calculate dimensions
984
+ const tubeRadius = od / 2;
985
+ const innerRadius = tubeRadius - t;
986
+ const neutralAxisRadius = innerRadius + (t * k);
987
+
988
+ // Scale to fit canvas
989
+ const scale = Math.min(width / (od + r * 2), height / (od + r * 2));
990
+ const startX = width * 0.2;
991
+ const startY = height / 2;
992
+
993
+ // Draw straight tube section
994
+ ctx.beginPath();
995
+ ctx.rect(startX, startY - tubeRadius * scale, r * scale * 1.5, od * scale);
996
+ ctx.fillStyle = '#4A5568';
997
+ ctx.fill();
998
+
999
+ ctx.beginPath();
1000
+ ctx.rect(startX, startY - innerRadius * scale, r * scale * 1.5, t * 2 * scale);
1001
+ ctx.fillStyle = '#1A202C';
1002
+ ctx.fill();
1003
+
1004
+ // Draw bend center
1005
+ const centerX = startX + r * scale * 1.5;
1006
+ const centerY = startY;
1007
+
1008
+ // Draw bent section
1009
+ const startAngle = 0;
1010
+ const endAngle = angle * Math.PI / 180;
1011
+
1012
+ // Outer bend
1013
+ ctx.beginPath();
1014
+ ctx.arc(centerX, centerY, (r + tubeRadius) * scale, startAngle, endAngle);
1015
+ ctx.lineTo(centerX + (r + tubeRadius) * scale * Math.cos(endAngle), centerY + (r + tubeRadius) * scale * Math.sin(endAngle) - tubeRadius * scale);
1016
+ ctx.arc(centerX, centerY, (r - tubeRadius) * scale, endAngle, startAngle, true);
1017
+ ctx.closePath();
1018
+ ctx.fillStyle = '#4A5568';
1019
+ ctx.fill();
1020
+
1021
+ // Inner bend (hollow)
1022
+ ctx.beginPath();
1023
+ ctx.arc(centerX, centerY, (r + innerRadius) * scale, startAngle, endAngle);
1024
+ ctx.lineTo(centerX + (r + innerRadius) * scale * Math.cos(endAngle), centerY + (r + innerRadius) * scale * Math.sin(endAngle) - innerRadius * scale);
1025
+ ctx.arc(centerX, centerY, (r - innerRadius) * scale, endAngle, startAngle, true);
1026
+ ctx.closePath();
1027
+ ctx.fillStyle = '#1A202C';
1028
+ ctx.fill();
1029
+
1030
+ // Neutral axis
1031
+ ctx.beginPath();
1032
+ ctx.arc(centerX, centerY, r * scale, startAngle, endAngle);
1033
+ ctx.strokeStyle = '#38B2AC';
1034
+ ctx.lineWidth = 2;
1035
+ ctx.setLineDash([5, 3]);
1036
+ ctx.stroke();
1037
+ ctx.setLineDash([]);
1038
+
1039
+ // Labels
1040
+ ctx.font = '12px Arial';
1041
+ ctx.fillStyle = '#E2E8F0';
1042
+ ctx.textAlign = 'center';
1043
+
1044
+ // Bend radius label
1045
+ ctx.beginPath();
1046
+ ctx.moveTo(centerX, centerY);
1047
+ ctx.lineTo(centerX + r * scale * Math.cos(endAngle / 2), centerY + r * scale * Math.sin(endAngle / 2));
1048
+ ctx.strokeStyle = '#E2E8F0';
1049
+ ctx.lineWidth = 1;
1050
+ ctx.stroke();
1051
+
1052
+ ctx.fillText(`CLR = ${r.toFixed(2)}`,
1053
+ centerX + r * scale * Math.cos(endAngle / 2) / 2,
1054
+ centerY + r * scale * Math.sin(endAngle / 2) / 2 - 5);
1055
+
1056
+ // Angle label
1057
+ ctx.beginPath();
1058
+ ctx.arc(centerX, centerY, r * scale * 0.3, startAngle, endAngle);
1059
+ ctx.strokeStyle = '#E2E8F0';
1060
+ ctx.lineWidth = 1;
1061
+ ctx.stroke();
1062
+
1063
+ ctx.fillText(`${angle.toFixed(0)}°`,
1064
+ centerX + r * scale * 0.3 * Math.cos(endAngle / 2),
1065
+ centerY + r * scale * 0.3 * Math.sin(endAngle / 2) + 15);
1066
+ }
1067
+
1068
+ // Animate the bending process
1069
+ function animateBendProcess() {
1070
+ const canvas = bendAnimationCanvas;
1071
+ const ctx = bendAnimationCtx;
1072
+ const width = canvas.width;
1073
+ const height = canvas.height;
1074
+
1075
+ // Clear canvas
1076
+ ctx.clearRect(0, 0, width, height);
1077
+
1078
+ const od = parseFloat(outerDiameter.value);
1079
+ const t = parseFloat(wallThickness.value);
1080
+ const r = parseFloat(bendRadius.value);
1081
+ const angle = parseFloat(bendAngle.value);
1082
+ const k = calculateKFactor();
1083
+
1084
+ if (isNaN(od) || isNaN(t) || isNaN(r) || isNaN(angle)) return;
1085
+
1086
+ // Calculate dimensions
1087
+ const tubeRadius = od / 2;
1088
+ const innerRadius = tubeRadius - t;
1089
+ const neutralAxisRadius = innerRadius + (t * k);
1090
+
1091
+ // Scale to fit canvas
1092
+ const scale = Math.min(width / (od + r * 2), height / (od + r * 2));
1093
+ const startX = width * 0.2;
1094
+ const startY = height / 2;
1095
+
1096
+ // Draw straight tube section (will remain static)
1097
+ ctx.beginPath();
1098
+ ctx.rect(startX, startY - tubeRadius * scale, r * scale * 1.5, od * scale);
1099
+ ctx.fillStyle = '#4A5568';
1100
+ ctx.fill();
1101
+
1102
+ ctx.beginPath();
1103
+ ctx.rect(startX, startY - innerRadius * scale, r * scale * 1.5, t * 2 * scale);
1104
+ ctx.fillStyle = '#1A202C';
1105
+ ctx.fill();
1106
+
1107
+ // Bend center
1108
+ const centerX = startX + r * scale * 1.5;
1109
+ const centerY = startY;
1110
+
1111
+ // Animation variables
1112
+ let currentAngle = 0;
1113
+ const targetAngle = angle * Math.PI / 180;
1114
+ const animationDuration = 1000; // ms
1115
+ const startTime = performance.now();
1116
+
1117
+ function animate(timestamp) {
1118
+ const elapsed = timestamp - startTime;
1119
+ const progress = Math.min(elapsed / animationDuration, 1);
1120
+ currentAngle = progress * targetAngle;
1121
+
1122
+ // Clear the bending area
1123
+ ctx.clearRect(centerX - (r + tubeRadius) * scale,
1124
+ centerY - (r + tubeRadius) * scale,
1125
+ (r + tubeRadius) * scale * 2,
1126
+ (r + tubeRadius) * scale * 2);
1127
+
1128
+ // Draw bent section
1129
+ // Outer bend
1130
+ ctx.beginPath();
1131
+ ctx.arc(centerX, centerY, (r + tubeRadius) * scale, 0, currentAngle);
1132
+ ctx.lineTo(centerX + (r + tubeRadius) * scale * Math.cos(currentAngle),
1133
+ centerY + (r + tubeRadius) * scale * Math.sin(currentAngle) - tubeRadius * scale);
1134
+ ctx.arc(centerX, centerY, (r - tubeRadius) * scale, currentAngle, 0, true);
1135
+ ctx.closePath();
1136
+ ctx.fillStyle = '#4A5568';
1137
+ ctx.fill();
1138
+
1139
+ // Inner bend (hollow)
1140
+ ctx.beginPath();
1141
+ ctx.arc(centerX, centerY, (r + innerRadius) * scale, 0, currentAngle);
1142
+ ctx.lineTo(centerX + (r + innerRadius) * scale * Math.cos(currentAngle),
1143
+ centerY + (r + innerRadius) * scale * Math.sin(currentAngle) - innerRadius * scale);
1144
+ ctx.arc(centerX, centerY, (r - innerRadius) * scale, currentAngle, 0, true);
1145
+ ctx.closePath();
1146
+ ctx.fillStyle = '#1A202C';
1147
+ ctx.fill();
1148
+
1149
+ // Neutral axis
1150
+ ctx.beginPath();
1151
+ ctx.arc(centerX, centerY, r * scale, 0, currentAngle);
1152
+ ctx.strokeStyle = '#38B2AC';
1153
+ ctx.lineWidth = 2;
1154
+ ctx.setLineDash([5, 3]);
1155
+ ctx.stroke();
1156
+ ctx.setLineDash([]);
1157
+
1158
+ // Angle label
1159
+ ctx.font = '12px Arial';
1160
+ ctx.fillStyle = '#E2E8F0';
1161
+ ctx.textAlign = 'center';
1162
+
1163
+ ctx.beginPath();
1164
+ ctx.arc(centerX, centerY, r * scale * 0.3, 0, currentAngle);
1165
+ ctx.strokeStyle = '#E2E8F0';
1166
+ ctx.lineWidth = 1;
1167
+ ctx.stroke();
1168
+
1169
+ const degrees = (currentAngle * 180 / Math.PI).toFixed(0);
1170
+ ctx.fillText(`${degrees}°`,
1171
+ centerX + r * scale * 0.3 * Math.cos(currentAngle / 2),
1172
+ centerY + r * scale * 0.3 * Math.sin(currentAngle / 2) + 15);
1173
+
1174
+ if (progress < 1) {
1175
+ requestAnimationFrame(animate);
1176
+ }
1177
+ }
1178
+
1179
+ requestAnimationFrame(animate);
1180
+ }
1181
+
1182
+ // Resize canvases to maintain aspect ratio
1183
+ function resizeCanvases() {
1184
+ const containers = document.querySelectorAll('#kFactorVisualization, #bendAnimationContainer');
1185
+
1186
+ containers.forEach(container => {
1187
+ const canvas = container.querySelector('canvas');
1188
+ const width = container.clientWidth;
1189
+ const height = container.clientHeight;
1190
+
1191
+ // Set display size
1192
+ canvas.style.width = width + 'px';
1193
+ canvas.style.height = height + 'px';
1194
+
1195
+ // Set actual size in memory (scaled for retina displays)
1196
+ const scale = window.devicePixelRatio || 1;
1197
+ canvas.width = width * scale;
1198
+ canvas.height = height * scale;
1199
+
1200
+ // Normalize coordinate system to use CSS pixels
1201
+ const ctx = canvas.getContext('2d');
1202
+ ctx.scale(scale, scale);
1203
+ });
1204
+
1205
+ // Redraw visualizations
1206
+ drawKFactorVisualization();
1207
+ drawBendAnimation();
1208
+ }
1209
+
1210
+ // Initialize the application
1211
+ window.addEventListener('load', init);
1212
+ </script>
1213
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=MRevenant/artisan-prompt" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1214
+ </html>