Simplify findmydevice map controls
This commit is contained in:
@@ -13,7 +13,6 @@ Home Assistant에 기록된 Galaxy Z Fold7의 위치, 배터리, 활동 상태,
|
|||||||
- 현재 위치 지도 표시
|
- 현재 위치 지도 표시
|
||||||
- GPS 정확도 원 표시
|
- GPS 정확도 원 표시
|
||||||
- 사용자 지정 기간 이동 경로 표시
|
- 사용자 지정 기간 이동 경로 표시
|
||||||
- 지도 타입 전환, 교통/거리뷰 레이어 토글
|
|
||||||
- 이동 기록 요약, 경로 전체 보기, 경로 재생, 시간 슬라이더
|
- 이동 기록 요약, 경로 전체 보기, 경로 재생, 시간 슬라이더
|
||||||
- 부드러운 렌더링용 경로선, GPS 튐 보정 토글, 체류 지점 자동 표시
|
- 부드러운 렌더링용 경로선, GPS 튐 보정 토글, 체류 지점 자동 표시
|
||||||
- 현재 위치 기준 집 50m, 500m/1km 반경 표시와 선택 지점 Naver 지도 열기
|
- 현재 위치 기준 집 50m, 500m/1km 반경 표시와 선택 지점 Naver 지도 열기
|
||||||
@@ -52,9 +51,9 @@ Home Assistant에 기록된 Galaxy Z Fold7의 위치, 배터리, 활동 상태,
|
|||||||
|
|
||||||
Naver Map에는 단일 Polyline 중심의 부드러운 경로선을 먼저 그리고 시작/종료 마커와 체류 지점 마커를 표시합니다. 중간 점 마커는 긴 기간 조회에서 브라우저 부하가 커지므로 표시하지 않습니다. 기록 조회 시 지도는 경로 전체가 보이도록 자동으로 범위를 맞추며, 종료 지점 정보창을 먼저 열어 최근 위치를 바로 확인할 수 있게 합니다.
|
Naver Map에는 단일 Polyline 중심의 부드러운 경로선을 먼저 그리고 시작/종료 마커와 체류 지점 마커를 표시합니다. 중간 점 마커는 긴 기간 조회에서 브라우저 부하가 커지므로 표시하지 않습니다. 기록 조회 시 지도는 경로 전체가 보이도록 자동으로 범위를 맞추며, 종료 지점 정보창을 먼저 열어 최근 위치를 바로 확인할 수 있게 합니다.
|
||||||
|
|
||||||
지도 기능은 NAVER 지도 API v3의 기본 컨트롤, 지도 유형, `TrafficLayer`, `StreetLayer`, `Polyline`, `PointingIcon`, `Circle`, `fitBounds`를 활용합니다. 지도 아래 도구 패널에서 일반/위성 지도 전환, 교통 레이어, 거리뷰 가능 구역 레이어, 경로 전체 보기, 경로 재생, GPS 튐 보정, Naver 지도 열기를 제어합니다.
|
지도 기능은 NAVER 지도 API v3의 기본 컨트롤, `Polyline`, `PointingIcon`, `Circle`, `fitBounds`를 활용합니다. 지도 아래 도구 패널에서 경로 전체 보기, 경로 재생, GPS 튐 보정, Naver 지도 열기를 제어합니다.
|
||||||
|
|
||||||
히스토리 요약 패널은 이동 거리, 기록 시간, 평균 속도, 최대 기록 공백, 지점 수, 체류 지점 수, 집 반경, 집 체류 시간, 외출 시간, 외출 횟수, 마지막 복귀 시각과 현재 상태를 표시합니다. 경로선 클릭으로 요약 패널을 숨기거나 다시 볼 수 있고, 각 히스토리 마커 정보창에는 기록 시각, 시작점 기준 누적 거리, 좌표를 함께 표시합니다.
|
히스토리 요약 패널은 이동 거리, 기록 시간, 평균 속도, 최대 기록 공백, 지점 수, 체류 지점 수, 집 반경, 집 체류 시간, 외출 시간, 외출 횟수, 마지막 복귀 시각과 현재 상태를 표시합니다. 각 히스토리 마커 정보창에는 기록 시각, 시작점 기준 누적 거리, 좌표를 함께 표시합니다.
|
||||||
|
|
||||||
경로선은 Douglas-Peucker 단순화와 가벼운 좌표 smoothing을 거쳐 긴 기간에서도 완만한 단일 선으로 표시합니다. 2km 이상 순간 이동하면서 180km/h를 넘는 GPS 튐은 기본적으로 제외하며, 지도 아래 `GPS 튐 보정` 버튼으로 원본 렌더링 경로와 보정 경로를 전환할 수 있습니다.
|
경로선은 Douglas-Peucker 단순화와 가벼운 좌표 smoothing을 거쳐 긴 기간에서도 완만한 단일 선으로 표시합니다. 2km 이상 순간 이동하면서 180km/h를 넘는 GPS 튐은 기본적으로 제외하며, 지도 아래 `GPS 튐 보정` 버튼으로 원본 렌더링 경로와 보정 경로를 전환할 수 있습니다.
|
||||||
|
|
||||||
|
|||||||
+1
-52
@@ -165,10 +165,6 @@ const deviceLang = (navigator.language || navigator.userLanguage || "en").starts
|
|||||||
history: "기록",
|
history: "기록",
|
||||||
startTime: "시작",
|
startTime: "시작",
|
||||||
endTime: "종료",
|
endTime: "종료",
|
||||||
mapNormal: "일반",
|
|
||||||
mapSatellite: "위성",
|
|
||||||
mapTraffic: "교통",
|
|
||||||
mapStreet: "거리뷰",
|
|
||||||
mapFit: "전체",
|
mapFit: "전체",
|
||||||
mapPlay: "재생",
|
mapPlay: "재생",
|
||||||
mapPause: "정지",
|
mapPause: "정지",
|
||||||
@@ -376,10 +372,6 @@ const deviceLang = (navigator.language || navigator.userLanguage || "en").starts
|
|||||||
history: "History",
|
history: "History",
|
||||||
startTime: "Start",
|
startTime: "Start",
|
||||||
endTime: "End",
|
endTime: "End",
|
||||||
mapNormal: "Normal",
|
|
||||||
mapSatellite: "Satellite",
|
|
||||||
mapTraffic: "Traffic",
|
|
||||||
mapStreet: "Street",
|
|
||||||
mapFit: "Fit",
|
mapFit: "Fit",
|
||||||
mapPlay: "Play",
|
mapPlay: "Play",
|
||||||
mapPause: "Pause",
|
mapPause: "Pause",
|
||||||
@@ -448,9 +440,6 @@ const deviceLang = (navigator.language || navigator.userLanguage || "en").starts
|
|||||||
stayPoints: [],
|
stayPoints: [],
|
||||||
homeStats: null,
|
homeStats: null,
|
||||||
filterOutliers: true,
|
filterOutliers: true,
|
||||||
layers: {},
|
|
||||||
layerActive: {},
|
|
||||||
activeMapType: 'normal',
|
|
||||||
openInfoWindow: null,
|
openInfoWindow: null,
|
||||||
mapClickHandlerAdded: false,
|
mapClickHandlerAdded: false,
|
||||||
initialInfoOpened: false,
|
initialInfoOpened: false,
|
||||||
@@ -1137,16 +1126,9 @@ function initMap(latlng, accuracy = 50) {
|
|||||||
createMainMarker(latlng);
|
createMainMarker(latlng);
|
||||||
createAccuracyCircle(latlng, accuracy);
|
createAccuracyCircle(latlng, accuracy);
|
||||||
updateHomeCircle();
|
updateHomeCircle();
|
||||||
initMapLayers();
|
|
||||||
ensureMapTools();
|
ensureMapTools();
|
||||||
}
|
}
|
||||||
|
|
||||||
function initMapLayers() {
|
|
||||||
if (!mapState.map || mapState.layers.traffic) return;
|
|
||||||
mapState.layers.traffic = new naver.maps.TrafficLayer();
|
|
||||||
mapState.layers.street = new naver.maps.StreetLayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
function ensureMapTools() {
|
function ensureMapTools() {
|
||||||
const container = document.getElementById('mapContainer') || document.getElementById('map')?.parentElement;
|
const container = document.getElementById('mapContainer') || document.getElementById('map')?.parentElement;
|
||||||
if (!container || document.getElementById('mapTools')) return;
|
if (!container || document.getElementById('mapTools')) return;
|
||||||
@@ -1161,10 +1143,6 @@ function ensureMapTools() {
|
|||||||
tools.id = 'mapTools';
|
tools.id = 'mapTools';
|
||||||
tools.className = 'map-tools';
|
tools.className = 'map-tools';
|
||||||
tools.innerHTML = `
|
tools.innerHTML = `
|
||||||
<button type="button" class="map-tool active" data-map-action="normal"></button>
|
|
||||||
<button type="button" class="map-tool" data-map-action="satellite"></button>
|
|
||||||
<button type="button" class="map-tool" data-map-action="traffic"></button>
|
|
||||||
<button type="button" class="map-tool" data-map-action="street"></button>
|
|
||||||
<button type="button" class="map-tool" data-map-action="fit"></button>
|
<button type="button" class="map-tool" data-map-action="fit"></button>
|
||||||
<button type="button" class="map-tool" data-map-action="play"></button>
|
<button type="button" class="map-tool" data-map-action="play"></button>
|
||||||
<button type="button" class="map-tool active" data-map-action="filter"></button>
|
<button type="button" class="map-tool active" data-map-action="filter"></button>
|
||||||
@@ -1206,10 +1184,6 @@ function ensureMapTools() {
|
|||||||
function updateMapToolLabels() {
|
function updateMapToolLabels() {
|
||||||
const t = translations[langCode] || translations.ko;
|
const t = translations[langCode] || translations.ko;
|
||||||
const labelMap = {
|
const labelMap = {
|
||||||
normal: t.mapNormal,
|
|
||||||
satellite: t.mapSatellite,
|
|
||||||
traffic: t.mapTraffic,
|
|
||||||
street: t.mapStreet,
|
|
||||||
fit: t.mapFit,
|
fit: t.mapFit,
|
||||||
play: mapState.playbackTimer ? t.mapPause : t.mapPlay,
|
play: mapState.playbackTimer ? t.mapPause : t.mapPlay,
|
||||||
filter: t.historyFiltered,
|
filter: t.historyFiltered,
|
||||||
@@ -1227,27 +1201,6 @@ function updateMapToolLabels() {
|
|||||||
|
|
||||||
function handleMapTool(action) {
|
function handleMapTool(action) {
|
||||||
if (!mapState.map) return;
|
if (!mapState.map) return;
|
||||||
if (action === 'normal' || action === 'satellite') {
|
|
||||||
mapState.activeMapType = action;
|
|
||||||
const mapTypes = naver.maps.MapTypeId || {};
|
|
||||||
const typeId = action === 'satellite'
|
|
||||||
? (mapTypes.HYBRID || mapTypes.SATELLITE || 'satellite')
|
|
||||||
: (mapTypes.NORMAL || 'normal');
|
|
||||||
mapState.map.setMapTypeId(typeId);
|
|
||||||
document.querySelectorAll('[data-map-action="normal"], [data-map-action="satellite"]').forEach(button => {
|
|
||||||
button.classList.toggle('active', button.dataset.mapAction === action);
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (action === 'traffic' || action === 'street') {
|
|
||||||
const layer = mapState.layers[action];
|
|
||||||
if (!layer) return;
|
|
||||||
const nextActive = !mapState.layerActive[action];
|
|
||||||
layer.setMap(nextActive ? mapState.map : null);
|
|
||||||
mapState.layerActive[action] = nextActive;
|
|
||||||
document.querySelector(`[data-map-action="${action}"]`)?.classList.toggle('active', nextActive);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (action === 'fit') {
|
if (action === 'fit') {
|
||||||
fitHistoryOrCurrentBounds();
|
fitHistoryOrCurrentBounds();
|
||||||
return;
|
return;
|
||||||
@@ -1698,11 +1651,7 @@ function drawSpeedTrack(points) {
|
|||||||
strokeLineJoin: 'round',
|
strokeLineJoin: 'round',
|
||||||
endIcon: naver.maps.PointingIcon?.BLOCK_ARROW,
|
endIcon: naver.maps.PointingIcon?.BLOCK_ARROW,
|
||||||
endIconSize: 16,
|
endIconSize: 16,
|
||||||
clickable: true
|
clickable: false
|
||||||
});
|
|
||||||
naver.maps.Event.addListener(line, 'click', () => {
|
|
||||||
const panel = document.getElementById('historySummaryPanel');
|
|
||||||
if (panel) panel.hidden = !panel.hidden;
|
|
||||||
});
|
});
|
||||||
mapState.trackLines.push(line);
|
mapState.trackLines.push(line);
|
||||||
mapState.trackLine = line;
|
mapState.trackLine = line;
|
||||||
|
|||||||
Reference in New Issue
Block a user