File size: 10,110 Bytes
e5b4770
 
 
 
 
 
818742a
 
 
 
 
e5b4770
8b3189f
e5b4770
 
818742a
e5b4770
 
 
 
 
818742a
e863a23
818742a
e5b4770
818742a
e5b4770
 
 
 
 
 
 
818742a
e5b4770
818742a
e5b4770
 
 
 
818742a
e5b4770
 
 
 
 
 
 
 
818742a
e5b4770
818742a
 
 
e5b4770
 
 
818742a
 
e5b4770
 
818742a
 
 
 
 
e5b4770
 
818742a
e5b4770
 
818742a
e5b4770
 
 
 
 
 
 
 
 
 
 
 
 
818742a
e5b4770
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
818742a
 
e5b4770
 
 
 
 
 
 
 
 
 
818742a
 
e5b4770
 
818742a
e5b4770
 
818742a
e5b4770
 
 
 
 
818742a
e5b4770
 
818742a
e5b4770
 
 
 
 
 
 
818742a
e5b4770
 
 
 
 
 
818742a
 
 
e5b4770
 
 
818742a
e5b4770
 
818742a
 
e5b4770
818742a
e5b4770
818742a
e5b4770
 
818742a
 
e5b4770
818742a
 
 
 
 
e5b4770
818742a
 
 
 
e5b4770
 
818742a
e5b4770
 
818742a
e5b4770
 
 
 
 
818742a
e5b4770
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
document.addEventListener('DOMContentLoaded', () => {
    const dial = document.getElementById('dial');
    const fingerStop = document.getElementById('finger-stop');
    const display = document.getElementById('dialed-numbers');
    const callButton = document.getElementById('call-button');
    const clearButton = document.getElementById('clear-button');
    const dialReturnSound = document.getElementById('dial-return-sound');
    const dialClickSound = document.getElementById('dial-click-sound');

    if (!dialClickSound) console.error("Audio element #dial-click-sound not found!");
    if (!dialReturnSound) console.warn("Audio element #dial-return-sound not found (optional).");

    const numbers = ['0', '9', '8', '7', '6', '5', '4', '3', '2', '1'];
    const numHoles = 10;

    // --- Config ---
    const holeAngleOffset = -55;
    const holeAngleSeparation = 30;
    const fingerStopTargetAngle = holeAngleOffset + (numHoles * holeAngleSeparation) + 1;
    const dialPlateRadius = dial.offsetWidth / 2;
    const holeRadius = dialPlateRadius * 0.72;
    const numberPlacementRadius = holeRadius * 0.65; // Inner radius
    const DIAL_RETURN_DURATION_MS = 550;
    const CLICK_START_DELAY_MS = 50;

    // --- State ---
    let isDragging = false;
    let startAngle = 0;
    let currentRotation = 0;
    let activeHole = null;
    let maxRotationAngle = 0;
    let dialedDigit = null;
    let holeData = {};
    let clickTimer = null;

    // --- Generate Holes and Numbers on Dial Plate ---
    numbers.forEach((num, index) => {
        const angle = holeAngleOffset + index * holeAngleSeparation;
        const rad = angle * (Math.PI / 180);

        // --- Create Hole ---
        const holeX = holeRadius * Math.cos(rad);
        const holeY = holeRadius * Math.sin(rad);
        const hole = document.createElement('div');
        hole.classList.add('hole');
        hole.dataset.number = num;
        hole.style.transform = `translate(${holeX}px, ${holeY}px)`;
        dial.appendChild(hole);

        // --- Create Number ---
        const numRad = angle * (Math.PI / 180);
        const numX = numberPlacementRadius * Math.cos(numRad); // Use inner radius
        const numY = numberPlacementRadius * Math.sin(numRad); // Use inner radius

        const numElement = document.createElement('div');
        numElement.classList.add('dial-plate-number');
        numElement.textContent = num;

        // 1. Position using left/top relative to dial center
        numElement.style.left = `calc(50% + ${numX}px)`;
        numElement.style.top = `calc(50% + ${numY}px)`;

        // 2. Apply ONLY the centering translation. NO ROTATION.
        numElement.style.transform = `translate(-50%, -50%)`; // REMOVED rotate() part
        // The numbers will now inherit the rotation of the parent #dial div.

        dial.appendChild(numElement);

        // Store info
        holeData[index] = { element: hole, number: num, startAngle: angle };

        // Attach Event Listeners
        hole.addEventListener('mousedown', startDrag);
        hole.addEventListener('touchstart', startDrag, { passive: false });
    });

    // --- Position Finger Stop (Same as before) ---
    const stopRad = fingerStopTargetAngle * (Math.PI / 180);
    const stopRadius = dialPlateRadius * 0.95;
    const stopX = stopRadius * Math.cos(stopRad);
    const stopY = stopRadius * Math.sin(stopRad);
    fingerStop.style.left = `calc(50% + ${stopX}px - 9px)`;
    fingerStop.style.top = `calc(50% + ${stopY}px - 22.5px)`;
    fingerStop.style.transform = `rotate(${fingerStopTargetAngle + 90}deg)`;

    // --- Drag Logic (Remains the same) ---
    function startDrag(e) {
        if (isDragging) return;
        if (clickTimer) clearInterval(clickTimer);
        const evt = e.touches ? e.touches[0] : e;
        activeHole = evt.target.closest('.hole');
        if (!activeHole) return;
        const holeInfo = Object.values(holeData).find(data => data.element === activeHole);
        if (!holeInfo) return;
        isDragging = true;
        dialedDigit = holeInfo.number;
        activeHole.classList.add('dragging');
        dial.style.transition = 'none';
        const rect = dial.getBoundingClientRect();
        const centerX = rect.left + rect.width / 2;
        const centerY = rect.top + rect.height / 2;
        startAngle = getAngle(evt.clientX, evt.clientY, centerX, centerY) - currentRotation;
        maxRotationAngle = 0;
        document.addEventListener('mousemove', drag);
        document.addEventListener('mouseup', endDrag);
        document.addEventListener('touchmove', drag, { passive: false });
        document.addEventListener('touchend', endDrag);
        if (e.touches) e.preventDefault();
    }

    function drag(e) {
        if (!isDragging || !activeHole) return;
        const evt = e.touches ? e.touches[0] : e;
        const rect = dial.getBoundingClientRect();
        const centerX = rect.left + rect.width / 2;
        const centerY = rect.top + rect.height / 2;
        let currentMouseAngle = getAngle(evt.clientX, evt.clientY, centerX, centerY);
        let potentialRotation = currentMouseAngle - startAngle;
        let delta = potentialRotation - currentRotation;
        if (delta > 180) delta -= 360;
        if (delta < -180) delta += 360;
        potentialRotation = currentRotation + delta;
        potentialRotation = Math.max(0, potentialRotation);
        const holeInfo = Object.values(holeData).find(data => data.element === activeHole);
        let holeStartAngle = holeInfo.startAngle;
        let maxAllowedRotation = fingerStopTargetAngle - holeStartAngle;
        if (maxAllowedRotation < 0) maxAllowedRotation += 360;
        potentialRotation = Math.min(potentialRotation, maxAllowedRotation);
        currentRotation = potentialRotation;
        maxRotationAngle = Math.max(maxRotationAngle, currentRotation);
        dial.style.transform = `rotate(${currentRotation}deg)`;
        if (e.touches) e.preventDefault();
    }

    function endDrag() {
        if (!isDragging) return;
        document.removeEventListener('mousemove', drag);
        document.removeEventListener('mouseup', endDrag);
        document.removeEventListener('touchmove', drag);
        document.removeEventListener('touchend', endDrag);
        let numberSuccessfullyDialed = false;
        let digitToPlaySoundFor = null;
        if (activeHole) {
            activeHole.classList.remove('dragging');
            const holeInfo = Object.values(holeData).find(data => data.element === activeHole);
            const rotationThreshold = 10;
            let holeStartAngle = holeInfo.startAngle;
            let expectedStopRotation = fingerStopTargetAngle - holeStartAngle;
            if (expectedStopRotation < 0) expectedStopRotation += 360;
            const tolerance = 2;
            if (maxRotationAngle > rotationThreshold && maxRotationAngle >= expectedStopRotation - tolerance) {
                appendNumber(dialedDigit);
                numberSuccessfullyDialed = true;
                digitToPlaySoundFor = dialedDigit;
            }
        }
        dial.style.transition = `transform ${DIAL_RETURN_DURATION_MS / 1000}s cubic-bezier(0.15, 0.85, 0.25, 1)`;
        dial.style.transform = 'rotate(0deg)';
        if (numberSuccessfullyDialed) {
             playDialClickSounds(digitToPlaySoundFor);
        }
        isDragging = false;
        startAngle = 0;
        currentRotation = 0;
        activeHole = null;
        dialedDigit = null;
    }

    // --- Helper Functions (Remain the same) ---
    function getAngle(x, y, centerX, centerY) {
        const deltaX = x - centerX;
        const deltaY = y - centerY;
        let angle = Math.atan2(deltaY, deltaX) * (180 / Math.PI);
        return angle;
    }
    function appendNumber(num) {
        if (display.textContent.length < 10) { display.textContent += num; }
    }
    function clearDisplay() {
        display.textContent = '';
        if (clickTimer) clearInterval(clickTimer);
    }

    // --- Sound Playback Logic using <audio> (Remains the same) ---
    function playDialClickSounds(digit) {
        if (!digit) return;
        if (clickTimer) clearInterval(clickTimer);
        if (dialReturnSound) {
            dialReturnSound.currentTime = 0;
            dialReturnSound.play().catch(e => {});
        }
        if (dialClickSound) {
            const numClicks = (digit === '0') ? 10 : parseInt(digit);
            if (numClicks <= 0) return;
            const durationForClicks = DIAL_RETURN_DURATION_MS - CLICK_START_DELAY_MS;
            if (durationForClicks <= 0) { console.error("Duration for clicks too short."); return; }
            const clickInterval = durationForClicks / numClicks;
            if (clickInterval < 30) { console.warn(`Calculated click interval (${clickInterval.toFixed(1)}ms) is very fast.`); }
            let clickCount = 0;
            setTimeout(() => {
                 if (isDragging) return;
                 clickTimer = setInterval(() => {
                    if (clickCount < numClicks) {
                        const clickAudio = document.getElementById('dial-click-sound');
                        if(clickAudio){
                             clickAudio.currentTime = 0;
                             clickAudio.play().catch(e => {});
                        } else { clearInterval(clickTimer); clickTimer = null; return; }
                        clickCount++;
                    } else { clearInterval(clickTimer); clickTimer = null; }
                }, Math.max(30, clickInterval));
            }, CLICK_START_DELAY_MS);
        } else { console.error("Click sound element not found."); }
    }

    // --- Event Listeners (Remain the same) ---
    callButton.addEventListener('click', () => {
        const currentNumber = display.textContent;
        if (currentNumber) { alert(`Dialing ${currentNumber}...`); }
    });
    clearButton.addEventListener('click', clearDisplay);

    // --- Initial Setup ---
    dial.style.transform = 'rotate(0deg)';
    console.log("Dialer Initialized (Numbers Inner & Static Orientation).");
});