지도 레이어 토글과 현재 위치 주소 보강
This commit is contained in:
+161
-3
@@ -178,6 +178,10 @@ const deviceLang = (navigator.language || navigator.userLanguage || "en").starts
|
||||
mapFit: "전체",
|
||||
mapPlay: "재생",
|
||||
mapPause: "정지",
|
||||
mapTraffic: "교통",
|
||||
mapCadastral: "지적",
|
||||
mapSatellite: "위성",
|
||||
mapHistory: "기록",
|
||||
historySummary: "기록 요약",
|
||||
historyDistance: "이동 거리",
|
||||
historyDuration: "기록 시간",
|
||||
@@ -385,6 +389,10 @@ const deviceLang = (navigator.language || navigator.userLanguage || "en").starts
|
||||
mapFit: "Fit",
|
||||
mapPlay: "Play",
|
||||
mapPause: "Pause",
|
||||
mapTraffic: "Traffic",
|
||||
mapCadastral: "Cadastral",
|
||||
mapSatellite: "Satellite",
|
||||
mapHistory: "History",
|
||||
historySummary: "History Summary",
|
||||
historyDistance: "Distance",
|
||||
historyDuration: "Duration",
|
||||
@@ -445,6 +453,13 @@ const deviceLang = (navigator.language || navigator.userLanguage || "en").starts
|
||||
playbackSpeed: 1,
|
||||
playbackSpeedOptions: [1],
|
||||
rangeCircles: [],
|
||||
layers: {},
|
||||
mapLayerState: {
|
||||
traffic: false,
|
||||
cadastral: false,
|
||||
satellite: false,
|
||||
history: true,
|
||||
},
|
||||
homeCircle: null,
|
||||
homeCircles: [],
|
||||
homeCenter: null,
|
||||
@@ -477,6 +492,7 @@ let langCode = localStorage.getItem("currentLang") || deviceLang,
|
||||
radiusInterval,
|
||||
_overrideRange,
|
||||
wakeLock = null;
|
||||
const reverseGeocodeCache = new Map();
|
||||
|
||||
const PLAYBACK_SPEEDS = [2, 5, 10, 20, 50, 100, 500];
|
||||
const PLAYBACK_MIN_VISIBLE_STEPS = 80;
|
||||
@@ -1207,12 +1223,71 @@ function setCookieHours(name, value, hours) {
|
||||
document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}; expires=${d.toUTCString()}; path=/; SameSite=Lax`;
|
||||
}
|
||||
|
||||
function isUsefulAddress(value) {
|
||||
const text = String(value || '').trim();
|
||||
return !!text && text !== '-' && text.toLowerCase() !== 'not_home' && text.toUpperCase() !== 'N/A';
|
||||
}
|
||||
|
||||
function formatLatLngAddress(lat, lng) {
|
||||
return `${Number(lat).toFixed(5)}, ${Number(lng).toFixed(5)}`;
|
||||
}
|
||||
|
||||
function setCurrentPositionText(value) {
|
||||
const el = document.getElementById('currentPosition');
|
||||
if (!el) return;
|
||||
el.textContent = value || '-';
|
||||
el.title = value || '';
|
||||
}
|
||||
|
||||
function updateCurrentAddress(data) {
|
||||
if (!hasValidCoords(data.latitude, data.longitude)) {
|
||||
setCurrentPositionText(isUsefulAddress(data.address) ? data.address : '-');
|
||||
return;
|
||||
}
|
||||
if (isUsefulAddress(data.address)) {
|
||||
setCurrentPositionText(data.address);
|
||||
return;
|
||||
}
|
||||
|
||||
const lat = Number(data.latitude);
|
||||
const lng = Number(data.longitude);
|
||||
const fallback = formatLatLngAddress(lat, lng);
|
||||
setCurrentPositionText(fallback);
|
||||
|
||||
if (!naver.maps.Service?.reverseGeocode) return;
|
||||
const key = `${lat.toFixed(5)},${lng.toFixed(5)}`;
|
||||
if (reverseGeocodeCache.has(key)) {
|
||||
setCurrentPositionText(reverseGeocodeCache.get(key));
|
||||
return;
|
||||
}
|
||||
|
||||
naver.maps.Service.reverseGeocode({
|
||||
coords: new naver.maps.LatLng(lat, lng),
|
||||
orders: ([
|
||||
naver.maps.Service.OrderType?.ROAD_ADDR,
|
||||
naver.maps.Service.OrderType?.ADDR,
|
||||
].filter(Boolean).join(',') || 'roadaddr,addr')
|
||||
}, (status, response) => {
|
||||
const okStatus = naver.maps.Service.Status?.OK || 'OK';
|
||||
if (status !== okStatus) return;
|
||||
const address = response?.v2?.address;
|
||||
const resolved = address?.roadAddress || address?.jibunAddress || '';
|
||||
if (!resolved) return;
|
||||
reverseGeocodeCache.set(key, resolved);
|
||||
if (Math.abs(Number(lastLat) - lat) < 0.00001 && Math.abs(Number(lastLng) - lng) < 0.00001) {
|
||||
setCurrentPositionText(resolved);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateDOM(data) {
|
||||
highAccuracyModeActive = !!data.highAccuracyMode;
|
||||
syncUpdateBtn();
|
||||
|
||||
const textMap = {
|
||||
currentPosition: data.address,
|
||||
currentPosition: isUsefulAddress(data.address)
|
||||
? data.address
|
||||
: (hasValidCoords(data.latitude, data.longitude) ? formatLatLngAddress(data.latitude, data.longitude) : '-'),
|
||||
lastUpdateTime: data.updated ? getRelativeTime(data.updated) : "-",
|
||||
nowActivity: data.activity,
|
||||
connectionType: data.connection,
|
||||
@@ -1230,7 +1305,10 @@ function updateDOM(data) {
|
||||
|
||||
for (const [id, value] of Object.entries(textMap)) {
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.textContent = value || "-";
|
||||
if (el) {
|
||||
el.textContent = value || "-";
|
||||
el.title = value || "";
|
||||
}
|
||||
}
|
||||
|
||||
toggleOptionalRow('WbatteryStatus', data.wstate);
|
||||
@@ -1426,6 +1504,7 @@ function initMap(latlng, accuracy = 50) {
|
||||
createMainMarker(latlng);
|
||||
createAccuracyCircle(latlng, accuracy);
|
||||
updateHomeCircles();
|
||||
ensureMapLayers();
|
||||
naver.maps.Event.addListener(mapState.map, 'zoom_changed', () => {
|
||||
renderStayMarkers();
|
||||
if (mapState.map.getZoom() < CURRENT_STAY_MIN_ZOOM) {
|
||||
@@ -1445,6 +1524,12 @@ function initMap(latlng, accuracy = 50) {
|
||||
ensureMapTools();
|
||||
}
|
||||
|
||||
function ensureMapLayers() {
|
||||
if (!mapState.map || Object.keys(mapState.layers).length) return;
|
||||
if (naver.maps.TrafficLayer) mapState.layers.traffic = new naver.maps.TrafficLayer();
|
||||
if (naver.maps.CadastralLayer) mapState.layers.cadastral = new naver.maps.CadastralLayer();
|
||||
}
|
||||
|
||||
function ensureMapTools() {
|
||||
const container = document.getElementById('mapContainer') || document.getElementById('map')?.parentElement;
|
||||
if (!container || document.getElementById('mapTools')) return;
|
||||
@@ -1461,6 +1546,10 @@ function ensureMapTools() {
|
||||
tools.innerHTML = `
|
||||
<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="traffic"></button>
|
||||
<button type="button" class="map-tool" data-map-action="cadastral"></button>
|
||||
<button type="button" class="map-tool" data-map-action="satellite"></button>
|
||||
<button type="button" class="map-tool active" data-map-action="history"></button>
|
||||
<button type="button" class="map-tool active" data-map-action="filter"></button>
|
||||
<button type="button" class="map-tool" data-map-action="naver"></button>
|
||||
`;
|
||||
@@ -1502,6 +1591,10 @@ function updateMapToolLabels() {
|
||||
const labelMap = {
|
||||
fit: t.mapFit,
|
||||
play: mapState.playbackTimer ? `${t.mapPause} ${mapState.playbackSpeed}x` : t.mapPlay,
|
||||
traffic: t.mapTraffic,
|
||||
cadastral: t.mapCadastral,
|
||||
satellite: t.mapSatellite,
|
||||
history: t.mapHistory,
|
||||
filter: t.historyFiltered,
|
||||
naver: t.openNaverMap,
|
||||
};
|
||||
@@ -1511,10 +1604,67 @@ function updateMapToolLabels() {
|
||||
button.title = labelMap[action] || action;
|
||||
});
|
||||
document.querySelector('[data-map-action="filter"]')?.classList.toggle('active', mapState.filterOutliers);
|
||||
document.querySelector('[data-map-action="traffic"]')?.classList.toggle('active', mapState.mapLayerState.traffic);
|
||||
document.querySelector('[data-map-action="cadastral"]')?.classList.toggle('active', mapState.mapLayerState.cadastral);
|
||||
document.querySelector('[data-map-action="satellite"]')?.classList.toggle('active', mapState.mapLayerState.satellite);
|
||||
document.querySelector('[data-map-action="history"]')?.classList.toggle('active', mapState.mapLayerState.history);
|
||||
const timelineTitle = document.getElementById('historyTimelineTitle');
|
||||
if (timelineTitle) timelineTitle.textContent = t.historyTimeline;
|
||||
}
|
||||
|
||||
function setHistoryLayerVisible(visible) {
|
||||
const map = visible ? mapState.map : null;
|
||||
mapState.trackLine?.setMap?.(map);
|
||||
mapState.trackLines?.forEach(line => line.setMap?.(map));
|
||||
mapState.smallMarkers?.forEach(marker => marker.setMap?.(map));
|
||||
mapState.historyStartMarker?.setMap?.(map);
|
||||
mapState.historyEndMarker?.setMap?.(map);
|
||||
if (visible) {
|
||||
renderStayMarkers();
|
||||
} else {
|
||||
mapState.stayMarkers?.forEach(marker => marker.setMap?.(null));
|
||||
stopCurrentStayBadge();
|
||||
}
|
||||
renderHistorySummary();
|
||||
updateTimelinePanel();
|
||||
}
|
||||
|
||||
function toggleMapLayer(action) {
|
||||
if (action === 'traffic') {
|
||||
if (!mapState.layers.traffic) {
|
||||
mapState.mapLayerState.traffic = false;
|
||||
return true;
|
||||
}
|
||||
mapState.mapLayerState.traffic = !mapState.mapLayerState.traffic;
|
||||
mapState.layers.traffic?.setMap(mapState.mapLayerState.traffic ? mapState.map : null);
|
||||
return true;
|
||||
}
|
||||
if (action === 'cadastral') {
|
||||
if (!mapState.layers.cadastral) {
|
||||
mapState.mapLayerState.cadastral = false;
|
||||
return true;
|
||||
}
|
||||
mapState.mapLayerState.cadastral = !mapState.mapLayerState.cadastral;
|
||||
mapState.layers.cadastral?.setMap(mapState.mapLayerState.cadastral ? mapState.map : null);
|
||||
return true;
|
||||
}
|
||||
if (action === 'satellite') {
|
||||
mapState.mapLayerState.satellite = !mapState.mapLayerState.satellite;
|
||||
if (naver.maps.MapTypeId) {
|
||||
const hybridType = naver.maps.MapTypeId.HYBRID || 'hybrid';
|
||||
const normalType = naver.maps.MapTypeId.NORMAL || 'normal';
|
||||
mapState.map.setMapTypeId(mapState.mapLayerState.satellite ? hybridType : normalType);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (action === 'history') {
|
||||
mapState.mapLayerState.history = !mapState.mapLayerState.history;
|
||||
setHistoryLayerVisible(mapState.mapLayerState.history);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function handleMapTool(action) {
|
||||
if (!mapState.map) return;
|
||||
if (action === 'fit') {
|
||||
@@ -1533,6 +1683,10 @@ function handleMapTool(action) {
|
||||
updateMapToolLabels();
|
||||
return;
|
||||
}
|
||||
if (toggleMapLayer(action)) {
|
||||
updateMapToolLabels();
|
||||
return;
|
||||
}
|
||||
if (action === 'naver') {
|
||||
openSelectedPointInNaverMap();
|
||||
}
|
||||
@@ -2563,7 +2717,7 @@ function renderStayMarkers() {
|
||||
mapState.stayMarkers.forEach(marker => marker.setMap(null));
|
||||
mapState.stayMarkers = [];
|
||||
}
|
||||
if (!mapState.stayPoints?.length) return;
|
||||
if (!mapState.mapLayerState.history || !mapState.stayPoints?.length) return;
|
||||
|
||||
buildStayMarkerGroups(mapState.stayPoints).forEach(group => {
|
||||
const isCluster = group.stays.length > 1;
|
||||
@@ -2635,6 +2789,9 @@ function renderHistoryPoints(rawPoints) {
|
||||
}
|
||||
|
||||
renderStayMarkers();
|
||||
if (!mapState.mapLayerState.history) {
|
||||
setHistoryLayerVisible(false);
|
||||
}
|
||||
|
||||
if (!mapState.historyBoundsFitted) {
|
||||
fitHistoryOrCurrentBounds();
|
||||
@@ -2715,6 +2872,7 @@ function updateDOMWithData(data) {
|
||||
lastLat = data.latitude;
|
||||
lastLng = data.longitude;
|
||||
lastUpdateISOTime = data.updated;
|
||||
updateCurrentAddress(data);
|
||||
const currentPoint = {
|
||||
lat: data.latitude,
|
||||
lng: data.longitude,
|
||||
|
||||
Reference in New Issue
Block a user