Pp commited on
Commit
818742a
·
verified ·
1 Parent(s): 10667d9

Update script.js

Browse files
Files changed (1) hide show
  1. script.js +58 -88
script.js CHANGED
@@ -4,26 +4,26 @@ document.addEventListener('DOMContentLoaded', () => {
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;
@@ -31,13 +31,14 @@ document.addEventListener('DOMContentLoaded', () => {
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');
@@ -46,19 +47,29 @@ document.addEventListener('DOMContentLoaded', () => {
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
  });
@@ -72,185 +83,144 @@ document.addEventListener('DOMContentLoaded', () => {
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
  });
 
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');
8
+ const dialClickSound = document.getElementById('dial-click-sound');
9
+
10
+ if (!dialClickSound) console.error("Audio element #dial-click-sound not found!");
11
+ if (!dialReturnSound) console.warn("Audio element #dial-return-sound not found (optional).");
12
 
13
  const numbers = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];
14
  const numHoles = 10;
15
 
16
+ // --- Config ---
17
  const holeAngleOffset = -55;
18
  const holeAngleSeparation = 30;
19
  const fingerStopTargetAngle = holeAngleOffset + (numHoles * holeAngleSeparation) + 1;
 
20
  const dialPlateRadius = dial.offsetWidth / 2;
21
  const holeRadius = dialPlateRadius * 0.72;
22
+ const numberPlacementRadius = holeRadius * 0.65; // Inner radius
23
+ const DIAL_RETURN_DURATION_MS = 550;
24
+ const CLICK_START_DELAY_MS = 50;
 
 
 
25
 
26
+ // --- State ---
27
  let isDragging = false;
28
  let startAngle = 0;
29
  let currentRotation = 0;
 
31
  let maxRotationAngle = 0;
32
  let dialedDigit = null;
33
  let holeData = {};
34
+ let clickTimer = null;
35
 
36
+ // --- Generate Holes and Numbers on Dial Plate ---
37
  numbers.forEach((num, index) => {
38
  const angle = holeAngleOffset + index * holeAngleSeparation;
39
  const rad = angle * (Math.PI / 180);
40
 
41
+ // --- Create Hole ---
42
  const holeX = holeRadius * Math.cos(rad);
43
  const holeY = holeRadius * Math.sin(rad);
44
  const hole = document.createElement('div');
 
47
  hole.style.transform = `translate(${holeX}px, ${holeY}px)`;
48
  dial.appendChild(hole);
49
 
50
+ // --- Create Number ---
51
  const numRad = angle * (Math.PI / 180);
52
+ const numX = numberPlacementRadius * Math.cos(numRad); // Use inner radius
53
+ const numY = numberPlacementRadius * Math.sin(numRad); // Use inner radius
54
+
55
  const numElement = document.createElement('div');
56
  numElement.classList.add('dial-plate-number');
57
  numElement.textContent = num;
58
+
59
+ // 1. Position using left/top relative to dial center
60
  numElement.style.left = `calc(50% + ${numX}px)`;
61
  numElement.style.top = `calc(50% + ${numY}px)`;
62
+
63
+ // 2. Apply ONLY the centering translation. NO ROTATION.
64
+ numElement.style.transform = `translate(-50%, -50%)`; // REMOVED rotate() part
65
+ // The numbers will now inherit the rotation of the parent #dial div.
66
+
67
  dial.appendChild(numElement);
68
 
69
+ // Store info
70
  holeData[index] = { element: hole, number: num, startAngle: angle };
71
 
72
+ // Attach Event Listeners
73
  hole.addEventListener('mousedown', startDrag);
74
  hole.addEventListener('touchstart', startDrag, { passive: false });
75
  });
 
83
  fingerStop.style.top = `calc(50% + ${stopY}px - 22.5px)`;
84
  fingerStop.style.transform = `rotate(${fingerStopTargetAngle + 90}deg)`;
85
 
86
+ // --- Drag Logic (Remains the same) ---
87
  function startDrag(e) {
88
  if (isDragging) return;
 
89
  if (clickTimer) clearInterval(clickTimer);
 
90
  const evt = e.touches ? e.touches[0] : e;
91
  activeHole = evt.target.closest('.hole');
92
  if (!activeHole) return;
 
93
  const holeInfo = Object.values(holeData).find(data => data.element === activeHole);
94
  if (!holeInfo) return;
 
95
  isDragging = true;
96
  dialedDigit = holeInfo.number;
97
  activeHole.classList.add('dragging');
98
  dial.style.transition = 'none';
 
99
  const rect = dial.getBoundingClientRect();
100
  const centerX = rect.left + rect.width / 2;
101
  const centerY = rect.top + rect.height / 2;
102
  startAngle = getAngle(evt.clientX, evt.clientY, centerX, centerY) - currentRotation;
103
  maxRotationAngle = 0;
 
104
  document.addEventListener('mousemove', drag);
105
  document.addEventListener('mouseup', endDrag);
106
  document.addEventListener('touchmove', drag, { passive: false });
107
  document.addEventListener('touchend', endDrag);
 
108
  if (e.touches) e.preventDefault();
109
  }
110
 
111
  function drag(e) {
112
  if (!isDragging || !activeHole) return;
 
113
  const evt = e.touches ? e.touches[0] : e;
114
  const rect = dial.getBoundingClientRect();
115
  const centerX = rect.left + rect.width / 2;
116
  const centerY = rect.top + rect.height / 2;
117
  let currentMouseAngle = getAngle(evt.clientX, evt.clientY, centerX, centerY);
118
  let potentialRotation = currentMouseAngle - startAngle;
 
119
  let delta = potentialRotation - currentRotation;
120
  if (delta > 180) delta -= 360;
121
  if (delta < -180) delta += 360;
122
  potentialRotation = currentRotation + delta;
123
  potentialRotation = Math.max(0, potentialRotation);
 
124
  const holeInfo = Object.values(holeData).find(data => data.element === activeHole);
125
  let holeStartAngle = holeInfo.startAngle;
126
  let maxAllowedRotation = fingerStopTargetAngle - holeStartAngle;
127
  if (maxAllowedRotation < 0) maxAllowedRotation += 360;
 
128
  potentialRotation = Math.min(potentialRotation, maxAllowedRotation);
 
129
  currentRotation = potentialRotation;
130
  maxRotationAngle = Math.max(maxRotationAngle, currentRotation);
131
  dial.style.transform = `rotate(${currentRotation}deg)`;
 
132
  if (e.touches) e.preventDefault();
133
  }
134
 
135
  function endDrag() {
136
  if (!isDragging) return;
 
137
  document.removeEventListener('mousemove', drag);
138
  document.removeEventListener('mouseup', endDrag);
139
  document.removeEventListener('touchmove', drag);
140
  document.removeEventListener('touchend', endDrag);
141
+ let numberSuccessfullyDialed = false;
142
+ let digitToPlaySoundFor = null;
 
143
  if (activeHole) {
144
  activeHole.classList.remove('dragging');
145
  const holeInfo = Object.values(holeData).find(data => data.element === activeHole);
 
146
  const rotationThreshold = 10;
147
  let holeStartAngle = holeInfo.startAngle;
148
  let expectedStopRotation = fingerStopTargetAngle - holeStartAngle;
149
  if (expectedStopRotation < 0) expectedStopRotation += 360;
150
  const tolerance = 2;
 
151
  if (maxRotationAngle > rotationThreshold && maxRotationAngle >= expectedStopRotation - tolerance) {
 
152
  appendNumber(dialedDigit);
153
+ numberSuccessfullyDialed = true;
154
+ digitToPlaySoundFor = dialedDigit;
 
155
  }
156
  }
157
+ dial.style.transition = `transform ${DIAL_RETURN_DURATION_MS / 1000}s cubic-bezier(0.15, 0.85, 0.25, 1)`;
 
 
158
  dial.style.transform = 'rotate(0deg)';
 
 
159
  if (numberSuccessfullyDialed) {
160
+ playDialClickSounds(digitToPlaySoundFor);
161
  }
 
 
 
162
  isDragging = false;
163
  startAngle = 0;
164
  currentRotation = 0;
165
  activeHole = null;
166
+ dialedDigit = null;
167
  }
168
 
169
+ // --- Helper Functions (Remain the same) ---
170
  function getAngle(x, y, centerX, centerY) {
171
  const deltaX = x - centerX;
172
  const deltaY = y - centerY;
173
  let angle = Math.atan2(deltaY, deltaX) * (180 / Math.PI);
174
  return angle;
175
  }
 
176
  function appendNumber(num) {
177
+ if (display.textContent.length < 10) { display.textContent += num; }
 
 
178
  }
 
179
  function clearDisplay() {
180
  display.textContent = '';
 
181
  if (clickTimer) clearInterval(clickTimer);
182
  }
183
 
184
+ // --- Sound Playback Logic using <audio> (Remains the same) ---
185
+ function playDialClickSounds(digit) {
186
+ if (!digit) return;
187
  if (clickTimer) clearInterval(clickTimer);
 
 
188
  if (dialReturnSound) {
189
  dialReturnSound.currentTime = 0;
190
+ dialReturnSound.play().catch(e => {});
191
  }
 
 
192
  if (dialClickSound) {
193
+ const numClicks = (digit === '0') ? 10 : parseInt(digit);
194
+ if (numClicks <= 0) return;
 
 
 
195
  const durationForClicks = DIAL_RETURN_DURATION_MS - CLICK_START_DELAY_MS;
196
+ if (durationForClicks <= 0) { console.error("Duration for clicks too short."); return; }
197
  const clickInterval = durationForClicks / numClicks;
198
+ if (clickInterval < 30) { console.warn(`Calculated click interval (${clickInterval.toFixed(1)}ms) is very fast.`); }
199
  let clickCount = 0;
 
 
200
  setTimeout(() => {
201
+ if (isDragging) return;
202
+ clickTimer = setInterval(() => {
203
  if (clickCount < numClicks) {
204
+ const clickAudio = document.getElementById('dial-click-sound');
205
+ if(clickAudio){
206
+ clickAudio.currentTime = 0;
207
+ clickAudio.play().catch(e => {});
208
+ } else { clearInterval(clickTimer); clickTimer = null; return; }
209
  clickCount++;
210
+ } else { clearInterval(clickTimer); clickTimer = null; }
211
+ }, Math.max(30, clickInterval));
212
+ }, CLICK_START_DELAY_MS);
213
+ } else { console.error("Click sound element not found."); }
 
 
 
214
  }
215
 
216
+ // --- Event Listeners (Remain the same) ---
 
217
  callButton.addEventListener('click', () => {
218
  const currentNumber = display.textContent;
219
+ if (currentNumber) { alert(`Dialing ${currentNumber}...`); }
 
 
220
  });
221
  clearButton.addEventListener('click', clearDisplay);
222
 
223
  // --- Initial Setup ---
224
  dial.style.transform = 'rotate(0deg)';
225
+ console.log("Dialer Initialized (Numbers Inner & Static Orientation).");
226
  });