現在位置を取得し、近くのランドマークを探す
現在位置とjsonデータのランドマーク位置の距離を比較して、50,000m以下のものを結果に表示させます。
現在位置が近すぎたり、遠すぎたりする場合は、src/assets/ts/GetNearPlace.tsx
の11行目const NUM = 50000;
を変更してみてください。
本当はwordpressで取得する予定だったのですが、Reactでやってみたくて作りました。
現在位置を取得する
現在位置(経度と緯度)の取得にはGeoLocationAPIを使います。
const [latitude, setLatitude] = useState(0);
const [longitude, setLongitude] = useState(0);
//中略
//成功
const getSuccess = (pos: any) => {
//現在地の緯度経度。保存しておく。
setLatitude(pos.coords.latitude);
setLongitude(pos.coords.longitude);
};
//エラー
const geoError = () => {
let pos = {
coords: {
latitude: 0,
longitude: 0
}
};
console.log("取得失敗");
};
//中略
navigator.geolocation.getCurrentPosition(getSuccess, geoError, {
enableHighAccuracy: true
});
参考サイト
位置情報 API – Web API | MDN
https://developer.mozilla.org/ja/docs/Web/API/Geolocation_API
Geolocation.getCurrentPosition() – Web API | MDN
https://developer.mozilla.org/ja/docs/Web/API/Geolocation/getCurrentPosition
現在位置とランドマークの位置を比較する
2地点の距離を比較するにはいくつかの法則がある様ですが、(自分は文系なのでちょっと・・・)今回はヒュベニの公式を用いて比較していきます。
対象の経度緯度がわかれば2地点間の距離を出すことができるので、あらかじめjsonにランドマークの軽度緯度を設定しておき、ヒュベニの公式でそれぞれ比較し現在位位置との距離が50,000m以内の場合画面に表示させる様にします。
ヒュベニの公式は下記参考サイトさんの記述をコピらせていただきました。
GoogleMapsで測った距離と比較すると、数mほどの誤差がある様です。
参考サイト
地球上の2地点間の距離を取得するアルゴリズム(ヒュベニ or 球面三角法)比較【JavaScript】 | 404 motivation not found
https://tech-blog.s-yoshiki.com/entry/8/?referer=https://www.google.com/
APIで取得する場合
API取得する場合はこんな感じでしょうか。(こちらは検証していないのでミスがあるかもしれません)
fetch("URL")
.then(response => {
if (response.ok) {
return response.json();
} else {
return Promise.reject(new Error('エラーです'));
}
})
.then(data => {
for (let i = 0; i < data.length; i++) {
let lat2 = data[i].lat;//軽度
let lng2 = data[i].lng;//緯度
let result = hubeny(latitude, longitude, lat2, lng2);
if (result < NUM) {
let resultData: resultArrayType = PlaceData[i];
resultData["result"] = result;
resultArray.push(resultData);
}
}
setPosts(resultArray);
});
ローディング
ローディングのフワッとした動きはCSSで実装し、クラスの付け替えをReactで行っています。
type Props = {
loading: boolean;
};
export const LoadingArea: React.VFC<Props> = (props) => {
//loadingの値によってclassNameを付け替え
return (
<div id="loading-area" className={props.loading ? "is-show" : ""}></div>
);
};
export default LoadingArea;
export default function App() {
//useState
const [loading, setLoading] = useState(false);
return (
<div className="App">
<div className="show-place-button-area">
<PlaceSearchButton onClick={() => searchPlace()} />
<ul>
//setLoadingをpropsで渡す
<GetNearPlace showPlace={showPlace} setLoading={setLoading} />
</ul>
</div>
<LoadingArea loading={loading} />
</div>
);
}
//trueにするとloading開始
props.setLoading(true);
//falseにするとloading終了
props.setLoading(false);