実装のきっかけ
現在個人開発を行なっており、その際にGeolocation APIで現在地の緯度経度を取得する処理を実装していました。
現在地の取得まで最大で5秒ほどかかることがあり、従来だと以下のように何のアニメーションも表示されないので、ユーザーに不安感を抱かせてしまうと思いました。
そこで、「現在地の取得」をクリックした際にローディングアニメーションが実行されるようにすればユーザーの不安感を軽減できるのではないかと思い、実装することにしました。
この記事の対象となる方
- Geolocation APIで現在地を取得する機能を実装している方
- その上でローディングアニメーションを実装したい方
開発環境
- Ruby 2.6.6
- Rails 6.1.0
コード
<body class="font-mono text-base sm:text-xl">
<div class="loading_zone">
<div class="spinner"></div>
</div>
<%= render "layouts/header" %>
<div>
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
<%= yield %>
</div>
<%= render "layouts/footer" %>
</body>
// ローディング画面のcss
.loading_zone {
position: fixed;
top: 0;
left: 0;
opacity: 0;
color: #f5f5f5;
}
.spinner {
margin: 300px auto;
width: 200px;
height: 200px;
background-color: #fff;
border-radius: 100%;
animation: sk-scaleout 1.0s infinite ease-in-out;
@media(max-width: 500px){
margin: 200px auto;
}
}
/* ローディングアニメーション */
@keyframes sk-scaleout {
0% {
transform: scale(0);
} 100% {
transform: scale(1.0);
opacity: 0;
}
}
.loading {
width: 100vw;
height: 100vh;
transition: all 1s;
background-color:gray;
opacity: 0.9;
z-index: 9999;
position: fixed;
}
function geoFindMe() {
const spinner = document.getElementsByClassName('loading_zone')[0];
spinner.classList.add('loading')
function success(position) {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
document.getElementById('location').value = `${latitude},${longitude}`;
spinner.classList.remove('loading');
}
function error() {
alert('エラーが発生しました。')
}
if(!navigator.geolocation) {
alert('Geolocation is not supported by your browser');
} else {
navigator.geolocation.getCurrentPosition(success, error);
}
}
document.querySelector('#get_current_spot').addEventListener('click', geoFindMe);
##何をやっているのか?
では一個づつ解説していきます。
<body class="font-mono text-base sm:text-xl">
<div class="loading_zone">
<div class="spinner"></div>
</div>
<%= render "layouts/header" %>
<div>
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
<%= yield %>
</div>
<%= render "layouts/footer" %>
</body>
application.html.erbの中にローディングアニメーション用のdivを用意しています。
// ローディング画面のcss
.loading_zone {
position: fixed;
top: 0;
left: 0;
opacity: 0;
color: #f5f5f5;
}
.spinner {
margin: 300px auto;
width: 200px;
height: 200px;
background-color: #fff;
border-radius: 100%;
animation: sk-scaleout 1.0s infinite ease-in-out;
@media(max-width: 500px){
margin: 200px auto;
}
}
/* ローディングアニメーション */
@keyframes sk-scaleout {
0% {
transform: scale(0);
} 100% {
transform: scale(1.0);
opacity: 0;
}
}
.loading {
width: 100vw;
height: 100vh;
transition: all 1s;
background-color: gray;
opacity: 0.9;
z-index: 9999;
position: fixed;
}
ここで見慣れない@keyframesというコードが出てきたと思います。
@keyframesはアニメーション開始から終了するまでどのようなアニメーションをするのか指定できるCSSの文法です。
0%を開始直後、100%を終了時としています。
@keyframesについて詳しく知りたい場合はこちらを参照ください!
.spinner {
margin: 300px auto;
width: 200px;
height: 200px;
background-color: #fff;
border-radius: 100%;
animation: sk-scaleout 1.0s infinite ease-in-out;
@media(max-width: 500px){
margin: 200px auto;
}
}
/* ローディングアニメーション */
@keyframes sk-scaleout {
0% {
transform: scale(0);
} 100% {
transform: scale(1.0);
opacity: 0;
}
}
つまり、上のコードは
1.アニメーション開始時
→何も表示されない
2.アニメーション開始〜終了直前まで
→円を表示する(最大サイズは直径200px)
3.アニメーション終了時
→opacityがゼロなので、消える。
以降1~3を繰り返す。
というアニメーションになっています。
最後にJavaScriptで、クリックしたときにアニメーションが表示されるように処理を書きます。
function geoFindMe() {
const spinner = document.getElementsByClassName('loading_zone')[0];
spinner.classList.add('loading')
function success(position) {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
document.getElementById('location').value = `${latitude},${longitude}`;
spinner.classList.remove('loading');
}
function error() {
alert('エラーが発生しました。')
spinner.classList.remove('loading');
}
if(!navigator.geolocation) {
alert('Geolocation is not supported by your browser');
} else {
navigator.geolocation.getCurrentPosition(success, error);
}
}
document.querySelector('#get_current_spot').addEventListener('click', geoFindMe);
clickした後に走るgeoFindMeという関数の中に詳しい設定を書きます。
loading_zoneクラスを持つdivに対して、処理が走っている間はloadingクラスを付与、処理が終わった後はloadingクラスを削除するようにコードを書きました。
最後に
以上で、ローディングアイコンの実装が完了しました!
最後まで読んでいただき、誠にありがとうございます。
少しでも参考になったと思ったらLGTMを頂けますと幸いです!