Pp commited on
Commit
e5b4770
·
verified ·
1 Parent(s): 10412e5

Create script.js

Browse files
Files changed (1) hide show
  1. script.js +256 -0
script.js ADDED
@@ -0,0 +1,256 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ document.addEventListener('DOMContentLoaded', () => {
2
+ const dial = document.getElementById('dial');
3
+ const fingerStop = document.getElementById('finger-stop');
4
+ const display = document.getElementById('dialed-numbers');
5
+ const callButton = document.getElementById('call-button');
6
+ const clearButton = document.getElementById('clear-button');
7
+ const dialReturnSound = document.getElementById('dial-return-sound'); // Optional return whoosh
8
+ const dialClickSound = document.getElementById('dial-click-sound'); // The click sound
9
+
10
+ const numbers = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];
11
+ const numHoles = 10;
12
+
13
+ // --- Angle & Radius Configuration ---
14
+ const holeAngleOffset = -55;
15
+ const holeAngleSeparation = 30;
16
+ const fingerStopTargetAngle = holeAngleOffset + (numHoles * holeAngleSeparation) + 1;
17
+
18
+ const dialPlateRadius = dial.offsetWidth / 2;
19
+ const holeRadius = dialPlateRadius * 0.72;
20
+ const numberPlacementRadius = holeRadius * 1.25;
21
+
22
+ // --- Timing Configuration ---
23
+ // !! IMPORTANT: This duration MUST closely match the 'transition-duration' in the CSS for #dial !!
24
+ const DIAL_RETURN_DURATION_MS = 550; // e.g., 0.55s transition = 550ms
25
+ const CLICK_START_DELAY_MS = 50; // Small delay before clicks start after release
26
+
27
+ let isDragging = false;
28
+ let startAngle = 0;
29
+ let currentRotation = 0;
30
+ let activeHole = null;
31
+ let maxRotationAngle = 0;
32
+ let dialedDigit = null;
33
+ let holeData = {};
34
+ let clickTimer = null; // Variable to hold the interval timer ID
35
+
36
+ // --- Generate Holes and Numbers (Same as before) ---
37
+ numbers.forEach((num, index) => {
38
+ const angle = holeAngleOffset + index * holeAngleSeparation;
39
+ const rad = angle * (Math.PI / 180);
40
+
41
+ const holeX = holeRadius * Math.cos(rad);
42
+ const holeY = holeRadius * Math.sin(rad);
43
+ const hole = document.createElement('div');
44
+ hole.classList.add('hole');
45
+ hole.dataset.number = num;
46
+ hole.style.transform = `translate(${holeX}px, ${holeY}px)`;
47
+ dial.appendChild(hole);
48
+
49
+ const numRad = angle * (Math.PI / 180);
50
+ const numX = numberPlacementRadius * Math.cos(numRad);
51
+ const numY = numberPlacementRadius * Math.sin(numRad);
52
+ const numElement = document.createElement('div');
53
+ numElement.classList.add('dial-plate-number');
54
+ numElement.textContent = num;
55
+ numElement.style.left = `calc(50% + ${numX}px)`;
56
+ numElement.style.top = `calc(50% + ${numY}px)`;
57
+ numElement.style.transform = `translate(-50%, -50%) rotate(${-angle}deg)`;
58
+ dial.appendChild(numElement);
59
+
60
+ holeData[index] = { element: hole, number: num, startAngle: angle };
61
+
62
+ hole.addEventListener('mousedown', startDrag);
63
+ hole.addEventListener('touchstart', startDrag, { passive: false });
64
+ });
65
+
66
+ // --- Position Finger Stop (Same as before) ---
67
+ const stopRad = fingerStopTargetAngle * (Math.PI / 180);
68
+ const stopRadius = dialPlateRadius * 0.95;
69
+ const stopX = stopRadius * Math.cos(stopRad);
70
+ const stopY = stopRadius * Math.sin(stopRad);
71
+ fingerStop.style.left = `calc(50% + ${stopX}px - 9px)`;
72
+ fingerStop.style.top = `calc(50% + ${stopY}px - 22.5px)`;
73
+ fingerStop.style.transform = `rotate(${fingerStopTargetAngle + 90}deg)`;
74
+
75
+ // --- Drag Logic (Same as before) ---
76
+ function startDrag(e) {
77
+ if (isDragging) return;
78
+ // Stop any previous clicking sound if user drags again quickly
79
+ if (clickTimer) clearInterval(clickTimer);
80
+
81
+ const evt = e.touches ? e.touches[0] : e;
82
+ activeHole = evt.target.closest('.hole');
83
+ if (!activeHole) return;
84
+
85
+ const holeInfo = Object.values(holeData).find(data => data.element === activeHole);
86
+ if (!holeInfo) return;
87
+
88
+ isDragging = true;
89
+ dialedDigit = holeInfo.number;
90
+ activeHole.classList.add('dragging');
91
+ dial.style.transition = 'none';
92
+
93
+ const rect = dial.getBoundingClientRect();
94
+ const centerX = rect.left + rect.width / 2;
95
+ const centerY = rect.top + rect.height / 2;
96
+ startAngle = getAngle(evt.clientX, evt.clientY, centerX, centerY) - currentRotation;
97
+ maxRotationAngle = 0;
98
+
99
+ document.addEventListener('mousemove', drag);
100
+ document.addEventListener('mouseup', endDrag);
101
+ document.addEventListener('touchmove', drag, { passive: false });
102
+ document.addEventListener('touchend', endDrag);
103
+
104
+ if (e.touches) e.preventDefault();
105
+ }
106
+
107
+ function drag(e) {
108
+ if (!isDragging || !activeHole) return;
109
+
110
+ const evt = e.touches ? e.touches[0] : e;
111
+ const rect = dial.getBoundingClientRect();
112
+ const centerX = rect.left + rect.width / 2;
113
+ const centerY = rect.top + rect.height / 2;
114
+ let currentMouseAngle = getAngle(evt.clientX, evt.clientY, centerX, centerY);
115
+ let potentialRotation = currentMouseAngle - startAngle;
116
+
117
+ let delta = potentialRotation - currentRotation;
118
+ if (delta > 180) delta -= 360;
119
+ if (delta < -180) delta += 360;
120
+ potentialRotation = currentRotation + delta;
121
+ potentialRotation = Math.max(0, potentialRotation);
122
+
123
+ const holeInfo = Object.values(holeData).find(data => data.element === activeHole);
124
+ let holeStartAngle = holeInfo.startAngle;
125
+ let maxAllowedRotation = fingerStopTargetAngle - holeStartAngle;
126
+ if (maxAllowedRotation < 0) maxAllowedRotation += 360;
127
+
128
+ potentialRotation = Math.min(potentialRotation, maxAllowedRotation);
129
+
130
+ currentRotation = potentialRotation;
131
+ maxRotationAngle = Math.max(maxRotationAngle, currentRotation);
132
+ dial.style.transform = `rotate(${currentRotation}deg)`;
133
+
134
+ if (e.touches) e.preventDefault();
135
+ }
136
+
137
+ function endDrag() {
138
+ if (!isDragging) return;
139
+
140
+ document.removeEventListener('mousemove', drag);
141
+ document.removeEventListener('mouseup', endDrag);
142
+ document.removeEventListener('touchmove', drag);
143
+ document.removeEventListener('touchend', endDrag);
144
+
145
+ let numberSuccessfullyDialed = false; // Flag to check if we should play sounds
146
+
147
+ if (activeHole) {
148
+ activeHole.classList.remove('dragging');
149
+ const holeInfo = Object.values(holeData).find(data => data.element === activeHole);
150
+
151
+ const rotationThreshold = 10;
152
+ let holeStartAngle = holeInfo.startAngle;
153
+ let expectedStopRotation = fingerStopTargetAngle - holeStartAngle;
154
+ if (expectedStopRotation < 0) expectedStopRotation += 360;
155
+ const tolerance = 2;
156
+
157
+ if (maxRotationAngle > rotationThreshold && maxRotationAngle >= expectedStopRotation - tolerance) {
158
+ console.log(`Dialed: ${dialedDigit} (Max rotation: ${maxRotationAngle.toFixed(1)}, Expected stop: ${expectedStopRotation.toFixed(1)})`);
159
+ appendNumber(dialedDigit);
160
+ numberSuccessfullyDialed = true; // Mark success for sound playback
161
+ } else {
162
+ console.log(`Drag ended early for ${dialedDigit}. Max rotation: ${maxRotationAngle.toFixed(1)}, Expected stop: ${expectedStopRotation.toFixed(1)}`);
163
+ }
164
+ }
165
+
166
+ // --- Animate Dial Return ---
167
+ dial.style.transition = 'transform 0.55s cubic-bezier(0.15, 0.85, 0.25, 1)';
168
+ dial.style.transform = 'rotate(0deg)';
169
+
170
+ // --- Play Sounds ONLY if a number was successfully dialed ---
171
+ if (numberSuccessfullyDialed) {
172
+ playDialSounds(dialedDigit); // Play clicking sound sequence
173
+ }
174
+
175
+
176
+ // Reset state
177
+ isDragging = false;
178
+ startAngle = 0;
179
+ currentRotation = 0;
180
+ activeHole = null;
181
+ dialedDigit = null; // Reset dialed digit only after sounds are initiated
182
+ }
183
+
184
+ // --- Helper Functions ---
185
+ function getAngle(x, y, centerX, centerY) {
186
+ const deltaX = x - centerX;
187
+ const deltaY = y - centerY;
188
+ let angle = Math.atan2(deltaY, deltaX) * (180 / Math.PI);
189
+ return angle;
190
+ }
191
+
192
+ function appendNumber(num) {
193
+ if (display.textContent.length < 10) {
194
+ display.textContent += num;
195
+ }
196
+ }
197
+
198
+ function clearDisplay() {
199
+ display.textContent = '';
200
+ // Also stop any clicking sounds if clear is pressed mid-return
201
+ if (clickTimer) clearInterval(clickTimer);
202
+ }
203
+
204
+ // --- Sound Playback Logic ---
205
+ function playDialSounds(digit) {
206
+ // Stop any previous clicks first
207
+ if (clickTimer) clearInterval(clickTimer);
208
+
209
+ // Play the main return sound (optional)
210
+ if (dialReturnSound) {
211
+ dialReturnSound.currentTime = 0;
212
+ dialReturnSound.play().catch(e => console.warn("Return sound failed:", e));
213
+ }
214
+
215
+ // Play the clicking sounds
216
+ if (dialClickSound) {
217
+ const numClicks = (digit === '0') ? 10 : parseInt(digit); // 0 is 10 clicks
218
+ if (numClicks <= 0) return; // Should not happen, but safety check
219
+
220
+ // Calculate time between clicks based on number of clicks and total return time
221
+ // Subtract the initial delay from the total duration available for clicks
222
+ const durationForClicks = DIAL_RETURN_DURATION_MS - CLICK_START_DELAY_MS;
223
+ const clickInterval = durationForClicks / numClicks;
224
+
225
+ let clickCount = 0;
226
+
227
+ // Use setTimeout to delay the start of the clicking sequence
228
+ setTimeout(() => {
229
+ clickTimer = setInterval(() => {
230
+ if (clickCount < numClicks) {
231
+ dialClickSound.currentTime = 0; // Rewind click sound
232
+ dialClickSound.play().catch(e => console.warn("Click sound failed:", e));
233
+ clickCount++;
234
+ } else {
235
+ clearInterval(clickTimer); // Stop the interval once all clicks are done
236
+ clickTimer = null;
237
+ }
238
+ }, clickInterval); // Time between each click
239
+ }, CLICK_START_DELAY_MS); // Initial delay before first click
240
+ }
241
+ }
242
+
243
+
244
+ // --- Event Listeners for Buttons ---
245
+ callButton.addEventListener('click', () => {
246
+ const currentNumber = display.textContent;
247
+ if (currentNumber) {
248
+ alert(`Dialing ${currentNumber}...`);
249
+ }
250
+ });
251
+ clearButton.addEventListener('click', clearDisplay);
252
+
253
+ // --- Initial Setup ---
254
+ dial.style.transform = 'rotate(0deg)';
255
+
256
+ });