Javascript를 사용하는 모바일 브라우저의 Real Compass

글쎄, 어느 날 나는 무슬림 친구로부터 그의 현재 지리적 위치에서 Qibla 또는 임의의 지리적 위치까지 화살표를 표시하는 지도를 코딩하라는 도전을 받았습니다.

그것은 최선의 해결책이 아니었습니다. 나침반이 더 나은 방법으로 문제를 해결하고 사람들의 삶을 더 쉽게 만들어 줄 것이기 때문입니다. 그래서 그의 웹페이지에 나침반을 넣을 수 있는 패키지/lib를 찾기 시작했습니다.

이 솔루션 Compass.js 또는 this one을 찾았지만 전혀 작동하지 않습니다. 마지막 커밋이 6-7년 전이었기 때문입니다.

모바일 브라우저용 진짜 나침반을 만들어 봅시다!



우리가 갖게 될 결과

몇 가지 html 요소가 필요합니다.

<div class="compass">
  <div class="arrow"></div>
  <div class="compass-circle"></div>
  <div class="my-point"></div>
</div>
<button class="start-btn">Start compass</button>


이를 위해 CSS를 추가하자

.compass {
  position: relative;
  width: 320px;
  height: 320px;
  border-radius: 50%;
  box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
  margin: auto;
}

.compass > .arrow {
  position: absolute;
  width: 0;
  height: 0;
  top: -20px;
  left: 50%;
  transform: translateX(-50%);
  border-style: solid;
  border-width: 30px 20px 0 20px;
  border-color: red transparent transparent transparent;
  z-index: 1;
}

.compass > .compass-circle,
.compass > .my-point {
  position: absolute;
  width: 80%;
  height: 80%;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  transition: transform 0.1s ease-out;
  background: url(https://cdn.onlinewebfonts.com/svg/img_467023.png) center
    no-repeat;
  background-size: contain;
}

.compass > .my-point {
  opacity: 0;
  width: 20%;
  height: 20%;
  background: rgb(8, 223, 69);
  border-radius: 50%;
  transition: opacity 0.5s ease-out;
}


자바스크립트 시간!



먼저 html 요소를 정의하고 이를 시작하는 버튼에 대한 이벤트를 추가합니다.
iOS를 시작하려면 사용자가 조작해야 하지만DeviceOrientationEvent Android의 경우 조작 없이도 작동합니다.

const compassCircle = document.querySelector(".compass-circle");
const startBtn = document.querySelector(".start-btn");
const myPoint = document.querySelector(".my-point");
let compass;
const isIOS = !(
  navigator.userAgent.match(/(iPod|iPhone|iPad)/) &&
  navigator.userAgent.match(/AppleWebKit/)
);



function init() {
  startBtn.addEventListener("click", startCompass);
}

function startCompass() {
  if (isIOS) {
    DeviceOrientationEvent.requestPermission()
      .then((response) => {
        if (response === "granted") {
          window.addEventListener("deviceorientation", handler, true);
        } else {
          alert("has to be allowed!");
        }
      })
      .catch(() => alert("not supported"));
  } else {
    window.addEventListener("deviceorientationabsolute", handler, true);
  }
}

function handler(e) {
  compass = e.webkitCompassHeading || Math.abs(e.alpha - 360);
  compassCircle.style.transform = `translate(-50%, -50%) rotate(${-compass}deg)`;
}

init();


완료! 우리 나침반은 iOS와 Android 모두에서 작동합니다.

나침반을 업그레이드하여 목표에 도달하세요



이 단계에서 우리는 포인트(Qibla)에 대한 올바른 각도/도를 찾아야 합니다.
포인트 좌표를 입력하고 현재 지리적 위치에서 정도를 계산합니다.

어떻게 작동합니까?
  • 현재 지리적 위치를 가져오고 있습니다
  • .
  • 점 좌표 정의(방향을 전환해야 하는 위치)
  • 우리 위치에서 정의된 지점까지의 각도 계산
  • 올바른 위치에 있을 때 표시 지점

  • pointDegree 및 이에 대한 기능을 정의합니다.

    let pointDegree;
    
    function locationHandler(position) {
      const { latitude, longitude } = position.coords;
      pointDegree = calcDegreeToPoint(latitude, longitude);
    
      if (pointDegree < 0) {
        pointDegree = pointDegree + 360;
      }
    }
    
    function calcDegreeToPoint(latitude, longitude) {
      // Qibla geolocation
      const point = {
        lat: 21.422487,
        lng: 39.826206,
      };
    
      const phiK = (point.lat * Math.PI) / 180.0;
      const lambdaK = (point.lng * Math.PI) / 180.0;
      const phi = (latitude * Math.PI) / 180.0;
      const lambda = (longitude * Math.PI) / 180.0;
      const psi =
        (180.0 / Math.PI) *
        Math.atan2(
          Math.sin(lambdaK - lambda),
          Math.cos(phi) * Math.tan(phiK) -
            Math.sin(phi) * Math.cos(lambdaK - lambda)
        );
      return Math.round(psi);
    }
    


    Geolocation API를 수신하기 위해 위치 처리기를 init 함수에 넣습니다. 포인트 상태를 업데이트할 코드를 handler에 추가합니다.

    function init() {
      startBtn.addEventListener("click", startCompass);
      navigator.geolocation.getCurrentPosition(locationHandler);
    }
    
    function handler(e) {
      compass = e.webkitCompassHeading || Math.abs(e.alpha - 360);
      compassCircle.style.transform = `translate(-50%, -50%) rotate(${-compass}deg)`;
    
      // ±15 degree
      if (
        (pointDegree < Math.abs(compass) && pointDegree + 15 > Math.abs(compass)) ||
        pointDegree > Math.abs(compass + 15) ||
        pointDegree < Math.abs(compass)
      ) {
        myPoint.style.opacity = 0;
      } else if (pointDegree) {
        myPoint.style.opacity = 1;
      }
    }
    


    끝났어! 모바일 브라우저에는 실제 나침반이 있습니다.

    데모 링크



    여기 source link

    @gigantz 작성

    좋은 웹페이지 즐겨찾기