PageSourceSearch

https://www.teachings.ai/js/animals.js

js teachings.ai collected 2026-10-05 16:24:40 UTC 7,416 bytes, 202 lines download raw bytes

1document.addEventListener('DOMContentLoaded', () => {
2    const currentAnimalNameText = document.getElementById('current-animal-name');
3    const animalImageContainer = document.getElementById('animal-image-container');
4    const prevAnimalButton = document.getElementById('prev-animal');
5    const nextAnimalButton = document.getElementById('next-animal');
6
7    const canvas = document.getElementById('drawing-canvas');
8    const ctx = canvas.getContext('2d', { willReadFrequently: true });
9
10    const animals = [
11        "Lion", "Elephant", "Monkey", "Zebra", "Giraffe",
12        "Tiger", "Bear", "Kangaroo", "Dolphin", "Penguin",
13        "Dog", "Cat", "Cow", "Horse", "Donkey" 
14    ];
15    let currentIndex = 0;
16    let isDrawing = false;
17    let isRevealed = false;
18
19    // Base paths for assets
20    const imageBasePath = CDN + 'assets/images/animals/';
21    const audioNameBasePath = CDN + 'assets/audio/animals/'; 
22    const audioSoundBasePath = CDN + 'assets/audio/animal_sounds/'; 
23    const audioFormat = '.mp3'; 
24    const imageFormat = '.png'; 
25
26    function setupCanvas() {
27        canvas.width = animalImageContainer.clientWidth;
28        canvas.height = animalImageContainer.clientHeight;
29
30        ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
31        ctx.fillRect(0, 0, canvas.width, canvas.height);
32
33        ctx.lineWidth = canvas.width * 0.15;
34        ctx.lineCap = 'round';
35        ctx.lineJoin = 'round';
36        ctx.globalCompositeOperation = 'destination-out';
37
38        canvas.style.opacity = '1';
39        canvas.style.transition = 'none';
40        isRevealed = false;
41
42        // --- Add "Scratch Here" text ---
43        ctx.globalCompositeOperation = 'source-over'; 
44        ctx.fillStyle = 'rgba(255, 255, 255, 0.8)'; 
45        // CORRECTED: Using string concatenation instead of template literal
46        ctx.font = 'bold ' + (canvas.width * 0.1) + 'px Poppins'; 
47        ctx.textAlign = 'center';
48        ctx.textBaseline = 'middle';
49        ctx.fillText('SCRATCH HERE', canvas.width / 2, canvas.height / 2); 
50        ctx.globalCompositeOperation = 'destination-out'; 
51    }
52
53    function getMousePos(e) {
54        const rect = canvas.getBoundingClientRect();
55        return {
56            x: e.clientX - rect.left,
57            y: e.clientY - rect.top
58        };
59    }
60
61    function getTouchPos(e) {
62        const rect = canvas.getBoundingClientRect();
63        return {
64            x: e.touches[0].clientX - rect.left,
65            y: e.touches[0].clientY - rect.top
66        };
67    }
68
69    function startDrawing(e) {
70        if (isRevealed) return; 
71        isDrawing = true;
72        ctx.beginPath();
73        const pos = e.touches ? getTouchPos(e) : getMousePos(e);
74        ctx.moveTo(pos.x, pos.y);
75    }
76
77    function draw(e) {
78        if (!isDrawing || isRevealed) return; 
79        e.preventDefault();
80        const pos = e.touches ? getTouchPos(e) : getMousePos(e);
81        ctx.lineTo(pos.x, pos.y);
82        ctx.stroke();
83    }
84
85    function checkRevealProgress() {
86        const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
87        const data = imageData.data; 
88        let transparentPixels = 0;
89        const totalPixels = data.length / 4; 
90
91        const sampleStep = 40; 
92        for (let i = 3; i < data.length; i += 4 * sampleStep) { 
93            if (data[i] < 50) { 
94                transparentPixels++;
95            }
96        }
97
98        const sampledTotalPixels = Math.floor(totalPixels / sampleStep);
99        const revealPercentage = (transparentPixels / sampledTotalPixels) * 100;
100
101        console.log('Revealed: ' + revealPercentage.toFixed(2) + '%');
102
103        const REVEAL_THRESHOLD = 50; 
104
105        if (revealPercentage >= REVEAL_THRESHOLD && !isRevealed) {
106            isRevealed = true;
107            canvas.style.opacity = '0'; 
108            canvas.style.transition = 'opacity 1s ease-out'; 
109            console.log('Image fully revealed!');
110            playAnimalAudio(); 
111        }
112    }
113
114    function stopDrawing() {
115        isDrawing = false;
116        if (!isRevealed) { 
117            checkRevealProgress();
118        }
119    }
120
121    canvas.addEventListener('mousedown', startDrawing);
122    canvas.addEventListener('mousemove', draw);
123    canvas.addEventListener('mouseup', stopDrawing);
124    canvas.addEventListener('mouseleave', stopDrawing); 
125
126    canvas.addEventListener('touchstart', startDrawing, { passive: false });
127    canvas.addEventListener('touchmove', draw, { passive: false });
128    canvas.addEventListener('touchend', stopDrawing);
129    canvas.addEventListener('touchcancel', stopDrawing);
130
131    function updateAnimalDisplay() {
132        const currentAnimal = animals[currentIndex];
133        currentAnimalNameText.textContent = currentAnimal;
134        
135        animalImageContainer.innerHTML = ''; 
136        
137        const img = document.createElement('img');
138        const imageSrc = imageBasePath + currentAnimal.toLowerCase() + imageFormat;
139        img.src = imageSrc;
140        img.alt = 'Image for ' + currentAnimal;
141        console.log('Attempting to load image: ' + imageSrc);
142        img.onload = () => {
143            console.log('Image loaded successfully: ' + imageSrc);
144            animalImageContainer.appendChild(canvas);
145            setupCanvas();
146        };
147        img.onerror = () => {
148            animalImageContainer.textContent = 'Image for ' + currentAnimal + ' not found. Please add ' + currentAnimal.toLowerCase() + imageFormat + ' to the assets/images/animals/ folder.';
149            console.error('Error loading image: ' + img.src);
150            animalImageContainer.appendChild(canvas);
151            setupCanvas();
152        };
153        animalImageContainer.appendChild(img);
154
155        console.log('Displaying animal: ' + currentAnimal);
156    }
157
158    function playAnimalAudio() {
159        const currentAnimal = animals[currentIndex];
160        const animalNameAudioSrc = audioNameBasePath + currentAnimal.toLowerCase() + audioFormat;
161        const animalSoundAudioSrc = audioSoundBasePath + currentAnimal.toLowerCase() + '_sound' + audioFormat; 
162
163        console.log('Attempting to play animal name audio: ' + animalNameAudioSrc);
164        const nameAudio = new Audio(animalNameAudioSrc);
165        
166        if (window.pauseBackgroundMusic) {
167            window.pauseBackgroundMusic();
168        }
169
170        nameAudio.play().catch(e => {
171            console.error('Error playing animal name audio for ' + currentAnimal + ':', e);
172            if (window.resumeBackgroundMusic) {
173                window.resumeBackgroundMusic();
174            }
175        });
176
177        nameAudio.onended = () => {
178            console.log('Animal name audio finished. Attempting to play animal sound: ' + animalSoundAudioSrc);
179            const soundAudio = new Audio(animalSoundAudioSrc);
180            soundAudio.play().catch(e => {
181                console.error('Error playing animal sound for ' + currentAnimal + ':', e);
182            }).finally(() => {
183                if (window.resumeBackgroundMusic) {
184                    window.resumeBackgroundMusic();
185                }
186            });
187        };
188    }
189
190    prevAnimalButton.addEventListener('click', () => {
191        currentIndex = (currentIndex - 1 + animals.length) % animals.length;
192        updateAnimalDisplay();
193    });
194
195    nextAnimalButton.addEventListener('click', () => {
196        currentIndex = (currentIndex + 1) % animals.length;
197        updateAnimalDisplay();
198    });
199
200    // Initial display
201    updateAnimalDisplay();
202});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.