diff --git a/gps.js b/gps.js
new file mode 100644
index 0000000..e8c5163
--- /dev/null
+++ b/gps.js
@@ -0,0 +1,323 @@
+document.addEventListener("DOMContentLoaded", ()=>{
+ var distanceThresh = 10;
+ var gpsWatchID = null, gpsCount = {};
+ var mymap, infobox, gpsMarker, btnGet, btnSTOP;
+ var direction;
+ var gsiLayer = L.tileLayer(
+ '//cyberjapandata.gsi.go.jp/xyz/std/{z}/{x}/{y}.png', {
+ attribution:
+ '国土地理院'
+ });
+ var osmLayer = L.tileLayer(
+ '//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
+ attribution:
+ '© OpenStreetMap contributors'});
+ let area = null;
+ var baseLayers = {
+ OpenStreetMap: osmLayer,
+ 地理院地図: gsiLayer,
+ };
+ var goals = {};
+ function workerInit() {
+ if ('serviceWorker' in navigator) {
+ navigator.serviceWorker.register('./serviceworker.js')
+ .then(function() {
+ console.log('service worker registered');
+ });
+ }
+ }
+ var stoPrefix = "gps_";
+ var LS = {
+ "getItem": (i)=>{return localStorage.getItem(stoPrefix+i);},
+ "removeItem": (i)=>{return localStorage.removeItem(stoPrefix+i);},
+ "setItem": (k,v)=>{return localStorage.setItem(stoPrefix+k, v);},
+ "reset": ()=>{
+ for (let p of Object.keys(localStorage)) {
+ console.log(`LS=${p}`);
+ if (p.startsWith(stoPrefix))
+ localStorage.removeItem(p);
+ }
+ }
+ }
+ function loadGoals(areaname, json) {
+ // uMapでレイヤをエリアごとわけてゴールとなるマーカーを設置し
+ // 名称にはピンの名前、概要(description)に答となる文字列を入れる。
+ // data/そのエリア.geojson に保存して上記 area 変数に入れる
+ if (!json) return;
+ fetch(json).then((resp)=>{return resp.json();}).then((r)=>{
+ //console.log(JSON.stringify(r));
+ let goal={}, name;
+ if (r.features) {
+ for (let m of r.features) {
+ if (m.properties && (name=m.properties.name)
+ && m.geometry && m.geometry.type=="Point") {
+ goal[name] = {
+ description: m.properties.description,
+ coordinates: m.geometry.coordinates
+ };
+ }
+ }
+ // {description: "desc", coordinates: [lon, lat]}
+ goals[areaname] = goal;
+ if (Object.keys(area)[0] == areaname)
+ switchArea(areaname);
+ }
+ });
+ }
+ function setAreaBounds(areaname) {
+ let areaval = area[areaname];
+ if (!areaval) return;
+ let map = areaval.map, bounds = areaval.bounds;
+ console.log(`bounds=${bounds}`);
+ if (bounds)
+ mymap.setMaxBounds(bounds);
+ else if (map.getBounds)
+ mymap.setMaxBounds(map.getBounds());
+ else
+ mymap.setMaxBounds(null);
+ }
+ var vMarkers = [];
+ function switchArea(areaname, label) {
+ let visibleMode = location.href.match(/\?markers$/);
+ if (visibleMode) {
+ while (vMarkers.length > 0) {
+ vMarkers.pop().remove();
+ }
+ }
+ if (label && !visibleMode) {
+ if (confirm(`${label}マップに切り替えます`)) {
+ for (let b of document.querySelectorAll(".areaselect"))
+ b.classList.add("hidden");
+ } else
+ return;
+ }
+ console.log(areaname);
+ let newlayer = area[areaname];
+ // https://groups.google.com/g/leaflet-js/c/1gQyZhOADCg
+ for (let base in baseLayers) {
+ let layer = baseLayers[base];
+ if (mymap.hasLayer(layer) && layer != newlayer)
+ mymap.removeLayer(layer);
+ }
+ newlayer.map.addTo(mymap);
+ setAreaBounds(areaname);
+ gpsMarker.setLatLng(mymap.getCenter());
+ if (goals[areaname]) {
+ let sel = document.getElementById("goals");
+ sel.name = areaname;
+ let opts = "";
+ let glist = goals[areaname];
+ for (let point of Object.keys(glist)) {
+ let val = glist[point], coord = val.coordinates;
+ opts += `\n`;
+ if (visibleMode) {
+ let lon = coord[0], lat = coord[1]
+ let mrk = L.marker([lat, lon]).bindPopup(point).addTo(mymap);
+ vMarkers.push(mrk);
+ }
+ }
+ sel.innerHTML = opts;
+ }
+ }
+ function loadArea() {
+ var btnList = document.getElementById("buttons");
+ fetch("area.json").then((resp)=>{
+ if (resp.ok) return resp.json()
+ }).then((json)=>{
+ area = json;
+ console.log(`area = ${area}`);
+ for (var a of Object.keys(area)) {
+ if (a.startsWith(".")) continue;
+ let btn = document.createElement("button");
+ btn.setAttribute("class", "areaselect");
+ btn.innerText = area[a].name;
+ console.log(area[a].name);
+ let x=a;
+ btn.addEventListener('click', (e)=>{
+ switchArea(x, area[x].name);});
+ btnList.appendChild(btn);
+ // console.log(`Loading ${area[a].map}`);
+ switch (area[a].map) {
+ case "gsi":
+ area[a].map = gsiLayer; break;
+ case "osm":
+ area[a].map = osmLayer; break;
+ default:
+ // console.log(`Loading ${area[a].map}`);
+ area[a].map = L.imageOverlay(
+ area[a].map, area[a].bounds)
+ }
+ if (area[a].map) baseLayers[a] = area[a].map;
+ loadGoals(a, area[a].geojson);
+ }
+ });
+ }
+ function mapInit() {
+ infobox = document.getElementById("info");
+ mymap = L.map("mymap", baseLayers).setView([38.891, 139.824], 18);
+ mymap.on('click', (e)=>{onSuccess2(e)});
+ L.control.scale().addTo(mymap); // 縮尺表示追加
+ let arrowIcon = L.divIcon({
+ // iconUrl: 'img/arrow.png',
+ iconSize: [53, 53],
+ iconAncor: [26, 26],
+ popupAnchor: [0, -23],
+ className: "gps-arrow-icon",
+ html: '

'
+ }); //arrowIcon.html = "FOO";
+ gpsMarker = L.marker(mymap.getCenter(),{
+ icon: arrowIcon
+ }).addTo(mymap).bindPopup("");
+ gpsMarker.setPopupContent("foo");
+ btnGet = document.getElementById("get");
+ btnSTOP = document.getElementById("stop");
+ direction = document.getElementById("arrowicon");
+ if (btnGet) btnGet.addEventListener("click", getGPS, false);
+ if (btnSTOP)btnSTOP.addEventListener("click", stopGPS, false);
+ // Create Area Selection Button
+ loadArea();
+ mymap.on('baselayerchange', (e)=>{
+ setAreaBounds(e.name);
+ });
+ /* 方角も取れるようだ
+ if (DeviceOrientationEvent) {
+ window.addEventListener("deviceorientation", (e) => {
+ document.getElementById("orientation").innerText =
+ `方角=${e.alpha}`;
+ });
+ }
+ */
+ L.control.layers(baseLayers).addTo(mymap);
+ }
+ function storageInit() {
+ if (location.href.endsWith("?init")
+ && confirm("ゲームデータをリセットしますか")) {
+ LS.reset();
+ alert("リセットしました");
+ location.href = location.href.replace("?init", "");
+ }
+ }
+ function dispInfo(msg) {
+ info.innerText = msg;
+ }
+ function clearWatchGPS() { // 位置取得ボタンを元に戻す
+ navigator.geolocation.clearWatch(gpsWatchID);
+ gpsWatchID = null;
+ btnGet.classList.remove('running');
+ btnGet.disabled = false;
+ }
+ function getGPS(ev) {
+ if (gpsWatchID) {
+ dispInfo("既に探索中です.");
+ return;
+ }
+ gpsWatchID = navigator.geolocation.watchPosition(
+ onSuccess, onError, {
+ maximumAge: 0, timeout: 8000, enableHighAccuracy: true
+ });
+ setTimeout(clearWatchGPS, 10000);
+ btnGet.classList.add('running');
+ btnGet.disabled = true;
+ dispInfo("取得中...");
+ }
+ function stopGPS(ev) {
+ clearWatchGPS();
+ dispInfo("GPS捕捉を停止しました.");
+ }
+ function onSuccessL(latlng) {
+ mymap.panTo(latlng); // 地図の中心を取得した位置に
+ let lat = latlng.lat, lng = latlng.lng;
+ let str = `ここは北緯${lat.toFixed(5)}, 東経${lng.toFixed(5)}. `;
+ gpsMarker.openPopup().setLatLng(latlng);// マーカのポイント変更
+ let sel = document.getElementById("goals");
+ console.log("val="+sel.value);
+ if (sel && sel.value && sel.value.indexOf(",") > -1) {
+ // GPSに頼った数をカウントする
+ let useGPS = LS.getItem("useGPS"),
+ helpCount = useGPS ? parseInt(useGPS) : 0;
+ let countUp;
+ if (gpsCount[gpsWatchID])
+ countUp = 0; // 一度カウントしたwatchIDではノーカウント
+ else if (gpsWatchID == null)
+ countUp = 1; // おそらくタップ×2の位置取得
+ else {
+ countUp = 1;
+ gpsCount[gpsWatchID] = 1;
+ }
+ if (useGPS) {
+ helpCount += countUp;
+ } else {
+ helpCount = 1;
+ }
+ LS.setItem("useGPS", helpCount); // セッションを越えた回数記憶
+ str += ` (位置取得${helpCount}回)`;
+ let areaname = sel.name;
+ let idx = sel.selectedIndex, pname = sel.options[idx].text;
+ let goallng = sel.value.split(",")[0],
+ goallat = sel.value.split(",")[1];
+ let distance = latlng.distanceTo([goallat, goallng]);
+ let popup = `${pname}まであと${distance.toFixed(1)}m.
`;
+ popup += (goallat < lat ? "南へ" : "北へ");
+ let northSouthDiff = latlng.distanceTo([goallat, lng]);
+ popup += `${northSouthDiff.toFixed(1)}m`;
+ popup += (goallng < lng ? "西へ" : "東へ");
+ let eastWestDiff = latlng.distanceTo([lat, goallng]);
+ popup += `${eastWestDiff.toFixed(1)}m`;
+ if (distance < distanceThresh) {
+ direction.classList.add("hidden");
+ let plist = goals[areaname],
+ desc = plist[pname].description, msg = "見つかった!";
+ if (desc && desc > "") {
+ msg += "
この場所に隠されているものは
" +
+ "「"+ desc + "」
です。
" +
+ "★見つけたアイテムは必ず回収して下さい★"
+ //console.log(`pname=${pname}, gp=${goals[pname]}`)
+ }
+ gpsMarker.setPopupContent(msg);
+ } else {
+ direction.classList.remove("hidden");
+ direction = document.querySelector('.gps-arrow-icon');
+ console.log(`dirrrr = ${direction.src}`)
+ let rad,
+ dy = northSouthDiff*Math.sign(goallat-lat),
+ dx = eastWestDiff*Math.sign(goallng-lng);
+ if (dx>0) { // Math.atanは分母が0でもよい
+ rad = Math.atan(dy/dx); //第1第4象限はそのまま
+ } else { //第2,3象限は +π
+ rad = Math.PI + Math.atan(dy/dx);
+ }
+ console.log(`dx=${dx}, dy=${dy}, atan = ${rad}`);
+ // rad = Math.PI/2-rad; //12時からの時計回りに変換
+ rad = -rad; //3時からの時計回りに変換
+ //https://www.webdesignleaves.com/pr/css/css_basic_12.html
+ direction.style.setProperty('--rotation', `${rad}rad`);
+ gpsMarker.setPopupContent(popup);
+ }
+ } else { // No goal selected
+ direction.classList.add("hidden");
+ gpsMarker.setPopupContent("上から探すゴールを選んで下さい");
+ }
+ dispInfo(str);
+ console.log(latlng);
+ }
+ var lastloc = null;
+ function onSuccess2(ev) {
+ if (lastloc && ev.latlng.distanceTo(lastloc) < 10) {
+ onSuccessL(ev.latlng); // 同一箇所を2連続タップしたら
+ }
+ lastloc = ev.latlng;
+ }
+ function onSuccess(pos) { // 成功時のコールバック。関数名は何でもよい。
+ // pos.coords に位置情報が入る。LeafletのLatLngに変換する。
+ onSuccessL(L.latLng([pos.coords.latitude, pos.coords.longitude]));
+ }
+ function onError(err) {// 失敗時のコールバック
+ gpsMarker.setPopupContent("取得失敗:"+restN).openPopup();
+ dispInfo("空がよく見える位置で試して下さい");
+ dispInfo("GPS捕捉を中止しました.")
+ clearWatchGPS();
+ }
+ workerInit();
+ mapInit();
+ storageInit();
+ });