Vanilla JS 30

30 Day Vanilla JS Coding Challenge Study - 8주차

  • Geolocation based Speedometer and Compass
  • Follow Along Links
  • Speech Synthesis

21. Geolocation based Speedometer and Compass

영상: https://youtu.be/X7Cbtra0C6I

Geolocation 기반의 속도계 & 나침반

1
2
3
4
5
6
7
8
9
10
11
const arrow = document.querySelector('.arrow');
const speed = document.querySelector('.speed-value');

navigator.geolocation.watchPosition((data) => {
// DOM에 속도계 반영
speed.textContent = data.coords.speed;
// CSS에 접근하여 나침반 시각화
arrow.style.transform = `rotate(${data.coords.heading}deg)`;
}, (err) => {
console.error(err);
});

22. Follow Along Links

영상: https://youtu.be/POP_qri7RA8

getBoundingClientRect()를 활용한 마우스 오버 링크 스타일링

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const triggers = document.querySelectorAll('a');
const highlight = document.createElement('span');
highlight.classList.add('highlight');
document.body.appendChild(highlight);

function highlightLink() {
// viewport에서의 상대적인 위치를 반환
const linkCoords = this.getBoundingClientRect();
const coords = {
width: linkCoords.width,
height: linkCoords.height,
top: linkCoords.top + window.scrollY,
left: linkCoords.left + window.scrollX
};

highlight.style.width = `${coords.width}px`;
highlight.style.height = `${coords.height}px`;
highlight.style.transform = `translate(${coords.left}px, ${coords.top}px)`;
}

triggers.forEach(a => a.addEventListener('mouseenter', highlightLink));

23. Speech Synthesis

영상: https://youtu.be/saCpKH_xdgs

SpeechSynthesisUtterance API를 활용한 다국어 TTS

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
// 스피치 인스턴스 생성
const msg = new SpeechSynthesisUtterance();
let voices = [];
const voicesDropdown = document.querySelector('[name="voice"]');
const options = document.querySelectorAll('[type="range"], [name="text"]');
const speakButton = document.querySelector('#speak');
const stopButton = document.querySelector('#stop');
msg.text = document.querySelector('[name="text"]').value;

function populateVoices() {
// 디바이스의 모든 음성 객체 리스트 반환
voices = this.getVoices();
voicesDropdown.innerHTML = voices
.filter(voice => voice.lang.includes('en'))
.map(voice => `<option value="${voice.name}">${voice.name} (${voice.lang})</option>`)
.join('');
}

function setVoice() {
msg.voice = voices.find(voice => voice.name === this.value);
toggle();
}

function toggle(startOver = true) {
// 말을 멈추거나 취소한다
speechSynthesis.cancel();
if (startOver) {
// 발언을 추가한다
speechSynthesis.speak(msg);
}
}

function setOption() {
console.log(this.name, this.value);
msg[this.name] = this.value;
toggle();
}

// getVoices() 메서드 반환될 SpeechSynthesisVoice 리스트 변경시
speechSynthesis.addEventListener('voiceschanged', populateVoices);
voicesDropdown.addEventListener('change', setVoice);
options.forEach(option => option.addEventListener('change', setOption));
speakButton.addEventListener('click', toggle);
stopButton.addEventListener('click', () => toggle(false));
Share Comments