Rev. 2.73

불러오고 있습니다...

불러오고 있습니다...

출발지: 도착지:
KML:

이번엔 구글어스 API와 한국지도 길찾기를 연동해 보았습니다. 위 화면이 보이지 않는 분은 플러그인을 별도로 설치해야 합니다. KML을 다루는 것과 시점 조작, 그리고 마커 생성 등에 대한 기초적인 사용방법을 익힐수 있었습니다. 맵과, 어스의 인스턴스를 개별적으로 생성한 후 두 인스턴스를 의동기화 시키는 방법으로 구현하였는데, 어스의 마커 이동과 카메라의 이동에서 싱크가 맞지 않는 문제가 발생하더군요. 결국 "google.earth.addEventListener"를 사용해서 프레임 단위로 모션을 처리하여 해결하습니다. 시스템 사양에 따라 처리하는 프레임 수가 다르며, 비효율적으로 작성된 함수를 대입한 경우 프레임 수는 더욱 떨어집니다. 따라서 프레임 수를 근거로 한 주행 속도와 남은 시간 및 거리 그리고 변속 위치 등을 산출해야 했습니다.(스스로 계산했다는 것이 믿기지 않음 ㅡ.ㅡ) 아래는 어스의 리스너에 의해 지속적으로 호출이 일어나는 함수에 포함된 계산식입니다.

var animate = function() {
  // 속도가 변경된 경우 현재 위치 계산
  if (curSpeed != newSpeed) {
    var distIdx = Math.round((curSpeed*i - newSpeed*i) / (curSpeed = newSpeed)); // 오차값
    balance = (balance / i) * (i += distIdx); // 인덱스 및 스택 값 재설정
  }

  // polyline으로부터 주행방향 좌표계산(GLatLng)
  var newLoc = Route.getPointAtDistance(curSpeed * i, polyline);

  // 모의주행 종료
  if (status == 'stop' || !newLoc) {
    status = 'idle';
    stopDrive();
    return statusEl.update('모의주행이 종료 되었습니다.');
  }

  // 초당 프레임 수 계산
  var now = new Date().getTime();
  balance += now - lastMillis; // 평균 프레임 산출을 위한 스택
  var fps = 1000 / (balance / i);

  // 화면 및 마커 이동
  drive(curLoc, geh.getHeading(curLoc, newLoc));
  marker.setPoint(curLoc);

  // 1초에 한번씩 진입(프레임 저하 방지)
  if (i % parseInt(fps) == 0) {
    map.panTo(newLoc); // 지도 패닝(프레임 저하 요소)
    var distRange = totalRange - curSpeed * i; // 남은 거리
    var speedPerHour = curSpeed * fps * 60 * 60; // 시속
    var timesLeft = new Date((distRange / speedPerHour) * 60 * 60 * 1000); // 남은 시간
    var houres = parseInt(timesLeft.getTime() / 60 / 60 /1000);
    // 메시지 업데이트
    statusEl.update([
      fps.toFixed(1) + ' FPS',
      '현재 시속 ' + Route.toKm(speedPerHour) + '로 주행 중이며',
      '도착지까지 남은 거리와 시간은 ' + Route.toKm(distRange),
      (houres > 0 ? houres + '시간 ' : '') +
      timesLeft.getMinutes() + '분 ' +
      timesLeft.getSeconds() + '초 입니다.'
    ].join(', '));
  }

  lastMillis = now;
  curLoc = newLoc;
  i++;
};

지역변수로 선언되어있지 않은 것은 상위 지역변수이거나 전역변수로 볼 수 있습니다.

길을 찾는 순서는 종전의 방식과 비슷하며, 맵에서 설정한 마커를 클릭하거나 이동하여 어스의 시점을 옮길 수 있고, 모의주행이 시작되면 어스의 화면이 3D 주행모드로 전환됩니다. 추가적으로 KML경로를 입력하면 실시간 반영됩니다. 예를 들어 aero님의 작업물인 "Daum Map On Google Earth" KML을 로드하려면 "http://aero.dnip.net/dmoge/daum_on_google2.kml"을 입력하세요. 다음의 고화질 위성사진이 오버레이 되는 것을 볼수 있습니다. 그리고 주행속도를 실시간으로 변경할 수 있게 하였으며, 한국지역 뿐만아니라 외국지역의 길찾기도 가능하게 하였습니다.(필라델피아, 뉴욕 등으로 검색해 보세요.) 이 작업을 끝으로, 지도 API로 해보고 싶었던 것들은 모두 해 보았네요. ㅎㅎ

Deprecated

* 다음의 길찾기 정보가 새롭게 갱신되어 위 데모는 더이상 작동하지 않습니다. 참고로 iRoute에서는 새롭게 변경된 다음의 길찾기 정보를 사용하고 있습니다.

Comments

출발지: 도착지:

구글맵 API다음 지도의 길찾기 검색 결과를 훔쳐(?)와서 조악한 길찾기 애플리케이션을 만들어 보았습니다. 이번 작업 역시 maps.js를 사용하였으며, 다음 지도는 콩나물 좌표계를 기본으로 사용기 때문에 'congnamul' 좌표계로 변환할 수 있게 하고, 소소한 유틸리티 메서드들을 추가하였습니다. 이거 이러다가 라이브러리화 될지도 모르겠네요. 시작과 끝점의 중앙값과 적절한 줌레벨을 얻기 위한 GLatLngBounds 클래스 사용법에 대하여 확실히 공부 할 수 있었습니다. "모의주행"은 폴리 라인(Polyline)의 교차점을 단위로 띄엄띄엄 이동하는 매우 저수준의 애니메이션으로 작업 되었습니다. 시간 대비 속도 및 거리등을 환산하여 조금 더 재미있게 발전시켜 볼 예정입니다. PC용으로 나온 GPS리시버를 로컬서버 데몬에 올리고 브라우저와 통신에 성공하기만 하면 웹기반 네비게이션 애플리케이션도 만들 수 있을 것 같아요!

Updates:

* 2009.02.09 미터법에 근거한 자동차가 달리는 애니메이션이 추가되었습니다.
* 2009.02.09 상태 표시창이 추가되었습니다.
* 2009.02.09 자동차가 달리는 속도를 산출하고 도착까지 남은 시간을 측정합니다.
* 2009.02.10 모의주행 도중 우측의 가이드 패널을 이용하여 해당 구간으로 즉시 이동할 수 있습니다.
* 2009.02.10 모의주행 시작시 두번씩 움직이는 오류를 수정하였습니다.

Deprecated

* 다음의 길찾기 정보가 새롭게 갱신되어 위 데모는 더이상 작동하지 않습니다. 참고로 iRoute에서는 새롭게 변경된 다음의 길찾기 정보를 사용하고 있습니다.

Comments

불러오고 있습니다...

지난해 11월 초, 구글맵은 한국어 서비스를 시작하였습니다. 그러나 구글맵 API에는 반영되어 있지 않았죠. 4개월째 접어든 지금도 마찬가지 입니다. 혹시나 해서 maps.google.co.kr을 살펴 보다가 한국의 상세 지도를 야매로(?) 가져오는데 성공했습니다. 기존의 맵 서비스가 업그래이드 된 형태인 줄로만 알고 겁을 집어먹었는데, 그게 아니더군요. 원리는 간단합니다. 한국 지역에 해당하는 영역의 좌표를 설정하고 관련 변수들(줌 레벨, 지도 데이터를 호출하는 url 등)을 오버라이드 하는 방식으로 한국 지도를 표시하고 있었습니다. 지금부터 그 트릭을 알려 드리지요.

우선 해야 할 일은 가장 최신 빌드(143c)의 구글맵 API를 로드해야 합니다. API 문서를 참고하여 적절한 방법으로 자바스크립트를 로드합니다. 여기에서 로드할 버전을 "2.x"로 입력하면 가장 최신 빌드를 로드 할 수 있습니다. "v"파라미터의 값이 되겠죠. 참고로 "2"만 입력하면, 140g빌드를 로드하며, "2.s"를 입력하면 73빌드를 로드합니다.

다음으로 main.js파일을 로드하는 함수 호출을 막아야합니다. 구글맵 API의 자바스크립트 파일은 여러등분으로 나뉘어 있습니다. 일반적으로 초기화 코드와 각종 변수들을 담고있는 maps, 그리고 API 코어를 담고있는 main.js 자바스크립트 파일 등입니다. 파일 호출을 막으려면 "async" 파라미터의 값을 "1"로 설정해야 합니다. 그리하면 document.write 메서드에 의해 main.js가 자동으로 호출되는 것을 막을 수 있습니다. 아래와 같이 자바스크립트를 호출하면 되겠죠.

... src="http://maps.google.com/maps?file=api&v=2.x&hl=ko&async=1&key=abcdefg"></script>

끝으로 maps에 들어있는 "GLoad" 함수를 아래와 같이 오버라이드 한 후 main.js 파일 로드 함수인 "GLoadMapsScript"를 호출해 줍니다. "GLoad"함수는 main.js가 로드되고 초기화 된 직후 실행하는 콜백함수이기 때문에 main.js가 로드되기 전에 미리 바꿔치기 하는 것이죠. main.js가 모두 초기화 된 후의 맵 인스턴스를 생성하는 코드는 생략합니다. 기존에 작성한 코드 또는 구글의 API 문서를 참고하시기 바랍니다.

GLoad = function(callback) {
  var apiCallback = callback || GLoadApi;
  GApiInit();
  var opts = {
    zoom_override: [
      {country: "kr", maptype: 0, override: [{max_zoom: 18, rect: {lo: {lat_e7: 329890840, lng_e7: 1246055600}, hi: {lat_e7: 386930130, lng_e7: 1284960940}}}, {max_zoom: 18, rect: {lo: {lat_e7: 344646740, lng_e7: 1284960940}, hi: {lat_e7: 386930130, lng_e7: 1288476560}}}, {max_zoom: 18, rect: {lo: {lat_e7: 350277470, lng_e7: 1288476560}, hi: {lat_e7: 386930130, lng_e7: 1310531620}}}, {max_zoom: 18, rect: {lo: {lat_e7: 370277730, lng_e7: 1310531620}, hi: {lat_e7: 386930130, lng_e7: 1320034790}}}]},
      {country: "kr", maptype: 1, override: [{max_zoom: 15, rect: {lo: {lat_e7: 329890840, lng_e7: 1246055600}, hi: {lat_e7: 386930130, lng_e7: 1284960940}}}, {max_zoom: 15, rect: {lo: {lat_e7: 344646740, lng_e7: 1284960940}, hi: {lat_e7: 386930130, lng_e7: 1288476560}}}, {max_zoom: 15, rect: {lo: {lat_e7: 350277470, lng_e7: 1288476560}, hi: {lat_e7: 386930130, lng_e7: 1310531620}}}, {max_zoom: 15, rect: {lo: {lat_e7: 370277730, lng_e7: 1310531620}, hi: {lat_e7: 386930130, lng_e7: 1320034790}}}]},
      {country: "kr", maptype: 2, override: [{max_zoom: 15, rect: {lo: {lat_e7: 329890840, lng_e7: 1246055600}, hi: {lat_e7: 386930130, lng_e7: 1284960940}}}, {max_zoom: 15, rect: {lo: {lat_e7: 344646740, lng_e7: 1284960940}, hi: {lat_e7: 386930130, lng_e7: 1288476560}}}, {max_zoom: 15, rect: {lo: {lat_e7: 350277470, lng_e7: 1288476560}, hi: {lat_e7: 386930130, lng_e7: 1310531620}}}, {max_zoom: 15, rect: {lo: {lat_e7: 370277730, lng_e7: 1310531620}, hi: {lat_e7: 386930130, lng_e7: 1320034790}}}]}
    ],
    tile_override: [
      {country: "kr", maptype: 0, min_zoom: 7, rect: [{lo: {lat_e7: 329890840, lng_e7: 1246055600}, hi: {lat_e7: 386930130, lng_e7: 1284960940}}, {lo: {lat_e7: 344646740, lng_e7: 1284960940}, hi: {lat_e7: 386930130, lng_e7: 1288476560}}, {lo: {lat_e7: 350277470, lng_e7: 1288476560}, hi: {lat_e7: 386930130, lng_e7: 1310531620}}, {lo: {lat_e7: 370277730, lng_e7: 1310531620}, hi: {lat_e7: 386930130, lng_e7: 1320034790}}], uris: ["http://mt0.gmaptiles.co.kr/mt?v=kr1.8\x26hl=ko\x26", "http://mt1.gmaptiles.co.kr/mt?v=kr1.8\x26hl=ko\x26", "http://mt2.gmaptiles.co.kr/mt?v=kr1.8\x26hl=ko\x26", "http://mt3.gmaptiles.co.kr/mt?v=kr1.8\x26hl=ko\x26"], max_zoom: 18, mapprint_url: "http://www.gmaptiles.co.kr/mapprint"},
      {country: "kr", maptype: 2, min_zoom: 7, rect: [{lo: {lat_e7: 329890840, lng_e7: 1246055600}, hi: {lat_e7: 386930130, lng_e7: 1284960940}}, {lo: {lat_e7: 344646740, lng_e7: 1284960940}, hi: {lat_e7: 386930130, lng_e7: 1288476560}}, {lo: {lat_e7: 350277470, lng_e7: 1288476560}, hi: {lat_e7: 386930130, lng_e7: 1310531620}}, {lo: {lat_e7: 370277730, lng_e7: 1310531620}, hi: {lat_e7: 386930130, lng_e7: 1320034790}}], uris: ["http://mt0.gmaptiles.co.kr/mt?v=kr1t.8\x26hl=ko\x26", "http://mt1.gmaptiles.co.kr/mt?v=kr1t.8\x26hl=ko\x26", "http://mt2.gmaptiles.co.kr/mt?v=kr1t.8\x26hl=ko\x26", "http://mt3.gmaptiles.co.kr/mt?v=kr1t.8\x26hl=ko\x26"]},
      {country: "kr", maptype: 3, min_zoom: 7, rect: [{lo: {lat_e7: 329890840, lng_e7: 1246055600}, hi: {lat_e7: 386930130, lng_e7: 1284960940}}, {lo: {lat_e7: 344646740, lng_e7: 1284960940}, hi: {lat_e7: 386930130, lng_e7: 1288476560}}, {lo: {lat_e7: 350277470, lng_e7: 1288476560}, hi: {lat_e7: 386930130, lng_e7: 1310531620}}, {lo: {lat_e7: 370277730, lng_e7: 1310531620}, hi: {lat_e7: 386930130, lng_e7: 1320034790}}], uris: ["http://mt0.gmaptiles.co.kr/mt?v=kr1p.7\x26hl=ko\x26", "http://mt1.gmaptiles.co.kr/mt?v=kr1p.7\x26hl=ko\x26", "http://mt2.gmaptiles.co.kr/mt?v=kr1p.7\x26hl=ko\x26", "http://mt3.gmaptiles.co.kr/mt?v=kr1p.7\x26hl=ko\x26"]}
    ],
    jsmain: "http://maps.google.co.kr/intl/ko_kr/mapfiles/143c/maps2.api/main.js"
  };

  var jsinit = window.GJsLoaderInit;
  jsinit && jsinit(opts.jsmain);

  apiCallback(["http://mt0.google.com/mt?v\x3dw2.89\x26hl\x3dko\x26", "http://mt1.google.com/mt?v\x3dw2.89\x26hl\x3dko\x26", "http://mt2.google.com/mt?v\x3dw2.89\x26hl\x3dko\x26", "http://mt3.google.com/mt?v\x3dw2.89\x26hl\x3dko\x26"], ["http://khm0.google.co.kr/kh?v\x3d36\x26hl\x3dko\x26", "http://khm1.google.co.kr/kh?v\x3d36\x26hl\x3dko\x26", "http://khm2.google.co.kr/kh?v\x3d36\x26hl\x3dko\x26", "http://khm3.google.co.kr/kh?v\x3d36\x26hl\x3dko\x26"], ["http://mt0.google.com/mt?v\x3dw2t.88\x26hl\x3dko\x26", "http://mt1.google.com/mt?v\x3dw2t.88\x26hl\x3dko\x26", "http://mt2.google.com/mt?v\x3dw2t.88\x26hl\x3dko\x26", "http://mt3.google.com/mt?v\x3dw2t.88\x26hl\x3dko\x26"], "", "", "", false, "G", opts, ["http://mt0.google.com/mt?v\x3dw2p.87\x26hl\x3dko\x26", "http://mt1.google.com/mt?v\x3dw2p.87\x26hl\x3dko\x26", "http://mt2.google.com/mt?v\x3dw2p.87\x26hl\x3dko\x26", "http://mt3.google.com/mt?v\x3dw2p.87\x26hl\x3dko\x26"], {}, {});
};

GLoadMapsScript();

아래 파일은 "다음 지도 API 사용해 보기"에서 만들었던 Maps 클래스에 적용해 본 것입니다. 온라인 카 네비게이션 만들어 보려고 했더니, GDirections 클래스는 아쉽게도 한국지역을 지원하고 있지 않습니다. 쩝, 간만에 코딩하니 재미나네요.

Downloads:

* original - maps.js (40.1kb)
* minified - maps.js (29.2kb)

Updates:

* 2009.02.05 한국지역 외 상세 지도가 나오지 않는 현상을 수정하였습니다.
* 2009.08.13 구글맵 API v3을 지원합니다.
* 2009.08.13 main.js파일을 171b빌드로 교체 하였습니다.

Comments