서울 목포 집 판정과 체류 제외 정리
This commit is contained in:
+89
-48
@@ -443,7 +443,9 @@ const deviceLang = (navigator.language || navigator.userLanguage || "en").starts
|
||||
playbackSpeedOptions: [1],
|
||||
rangeCircles: [],
|
||||
homeCircle: null,
|
||||
homeCircles: [],
|
||||
homeCenter: null,
|
||||
homeCenters: [],
|
||||
rawHistoryPoints: [],
|
||||
historyPoints: [],
|
||||
historyRawCount: null,
|
||||
@@ -1413,7 +1415,7 @@ function initMap(latlng, accuracy = 50) {
|
||||
|
||||
createMainMarker(latlng);
|
||||
createAccuracyCircle(latlng, accuracy);
|
||||
updateHomeCircle();
|
||||
updateHomeCircles();
|
||||
ensureMapTools();
|
||||
}
|
||||
|
||||
@@ -1605,30 +1607,35 @@ function speedLabel(kmh) {
|
||||
}
|
||||
|
||||
const HOME_RADIUS_M = 50;
|
||||
const HOME_NEAR_RADIUS_M = 90;
|
||||
const HOME_JITTER_ABSORB_RADIUS_M = 1200;
|
||||
const HOME_JITTER_SAMPLE_SECONDS = 30 * 60;
|
||||
const TRACK_MAX_GAP_SECONDS = 30 * 60;
|
||||
const AWAY_MAX_GAP_SECONDS = 2 * 60 * 60;
|
||||
|
||||
function homeConfigFromData(data) {
|
||||
const home = data?.home || {};
|
||||
const radius = Number(home.radius_m || HOME_RADIUS_M);
|
||||
function normalizeHomeConfig(home) {
|
||||
const radius = Number(home?.radius_m || HOME_RADIUS_M);
|
||||
return {
|
||||
lat: Number(home.latitude),
|
||||
lng: Number(home.longitude),
|
||||
name: String(home?.name || ''),
|
||||
label: String(home?.label || home?.name || ''),
|
||||
lat: Number(home?.latitude),
|
||||
lng: Number(home?.longitude),
|
||||
radius: Number.isFinite(radius) && radius > 0 ? radius : HOME_RADIUS_M,
|
||||
};
|
||||
}
|
||||
|
||||
function homeRadiusMeters() {
|
||||
return mapState.homeCenter?.radius || HOME_RADIUS_M;
|
||||
function homeConfigsFromData(data) {
|
||||
const homes = Array.isArray(data?.homes) && data.homes.length
|
||||
? data.homes
|
||||
: (data?.home ? [data.home] : []);
|
||||
return homes
|
||||
.map(normalizeHomeConfig)
|
||||
.filter(home => hasValidCoords(home.lat, home.lng));
|
||||
}
|
||||
|
||||
function updateConfiguredHome(data) {
|
||||
const home = homeConfigFromData(data);
|
||||
if (hasValidCoords(home.lat, home.lng)) {
|
||||
updateHomeCenter(home.lat, home.lng, home.radius);
|
||||
const homes = homeConfigsFromData(data);
|
||||
if (homes.length) {
|
||||
updateHomeCenters(homes);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -1645,10 +1652,11 @@ function pointWithLatLng(point, lat, lng, extra = {}) {
|
||||
}
|
||||
|
||||
function normalizeHomeJitterPoint(point) {
|
||||
if (!mapState.filterOutliers || !mapState.homeCenter || !point) return point;
|
||||
const distance = distanceFromHome(point);
|
||||
if (!mapState.filterOutliers || !mapState.homeCenters?.length || !point) return point;
|
||||
const nearest = nearestHome(point);
|
||||
const distance = nearest.distance;
|
||||
if (distance > HOME_JITTER_ABSORB_RADIUS_M) return point;
|
||||
return pointWithLatLng(point, mapState.homeCenter.lat, mapState.homeCenter.lng, {
|
||||
return pointWithLatLng(point, nearest.home.lat, nearest.home.lng, {
|
||||
homeJitter: true,
|
||||
originalLat: point.lat,
|
||||
originalLng: point.lng,
|
||||
@@ -1699,7 +1707,7 @@ function filterHistoryOutliers(points) {
|
||||
function buildStayPoints(points) {
|
||||
const stays = [];
|
||||
let start = 0;
|
||||
const radius = 80;
|
||||
const radius = 100;
|
||||
|
||||
for (let i = 1; i <= points.length; i++) {
|
||||
const base = points[start];
|
||||
@@ -1713,6 +1721,10 @@ function buildStayPoints(points) {
|
||||
const slice = points.slice(start, i);
|
||||
const lat = slice.reduce((sum, p) => sum + Number(p.lat), 0) / slice.length;
|
||||
const lng = slice.reduce((sum, p) => sum + Number(p.lng), 0) / slice.length;
|
||||
if (isHomePoint({ lat, lng })) {
|
||||
start = Math.max(0, i - 1);
|
||||
continue;
|
||||
}
|
||||
stays.push({
|
||||
lat,
|
||||
lng,
|
||||
@@ -1729,51 +1741,80 @@ function buildStayPoints(points) {
|
||||
return stays;
|
||||
}
|
||||
|
||||
function updateHomeCenter(lat, lng, radius = HOME_RADIUS_M) {
|
||||
if (!hasValidCoords(lat, lng)) return;
|
||||
mapState.homeCenter = {
|
||||
lat: Number(lat),
|
||||
lng: Number(lng),
|
||||
latlng: new naver.maps.LatLng(Number(lat), Number(lng)),
|
||||
radius: Math.max(1, Number(radius) || HOME_RADIUS_M)
|
||||
};
|
||||
updateHomeCircle();
|
||||
function updateHomeCenters(homes) {
|
||||
mapState.homeCenters = homes.map(home => ({
|
||||
...home,
|
||||
latlng: new naver.maps.LatLng(Number(home.lat), Number(home.lng)),
|
||||
radius: Math.max(1, Number(home.radius) || HOME_RADIUS_M)
|
||||
}));
|
||||
mapState.homeCenter = mapState.homeCenters[0] || null;
|
||||
updateHomeCircles();
|
||||
}
|
||||
|
||||
function updateHomeCircle() {
|
||||
if (!mapState.map || !mapState.homeCenter) return;
|
||||
if (!mapState.homeCircle) {
|
||||
mapState.homeCircle = new naver.maps.Circle({
|
||||
map: mapState.map,
|
||||
center: mapState.homeCenter.latlng,
|
||||
radius: homeRadiusMeters(),
|
||||
strokeColor: '#5856d6',
|
||||
strokeOpacity: 0.8,
|
||||
strokeWeight: 2,
|
||||
fillColor: '#5856d6',
|
||||
fillOpacity: 0.08
|
||||
});
|
||||
} else {
|
||||
mapState.homeCircle.setCenter(mapState.homeCenter.latlng);
|
||||
mapState.homeCircle.setRadius(homeRadiusMeters());
|
||||
function updateHomeCenter(lat, lng, radius = HOME_RADIUS_M) {
|
||||
if (!hasValidCoords(lat, lng)) return;
|
||||
updateHomeCenters([{ lat: Number(lat), lng: Number(lng), radius }]);
|
||||
}
|
||||
|
||||
function updateHomeCircles() {
|
||||
if (!mapState.map || !mapState.homeCenters?.length) return;
|
||||
if (mapState.homeCircle && !mapState.homeCircles.includes(mapState.homeCircle)) {
|
||||
mapState.homeCircle.setMap(null);
|
||||
mapState.homeCircle = null;
|
||||
}
|
||||
while (mapState.homeCircles.length > mapState.homeCenters.length) {
|
||||
mapState.homeCircles.pop()?.setMap?.(null);
|
||||
}
|
||||
mapState.homeCenters.forEach((home, index) => {
|
||||
let circle = mapState.homeCircles[index];
|
||||
if (!circle) {
|
||||
circle = new naver.maps.Circle({
|
||||
map: mapState.map,
|
||||
center: home.latlng,
|
||||
radius: home.radius,
|
||||
strokeColor: '#5856d6',
|
||||
strokeOpacity: 0.8,
|
||||
strokeWeight: 2,
|
||||
fillColor: '#5856d6',
|
||||
fillOpacity: 0.08
|
||||
});
|
||||
mapState.homeCircles[index] = circle;
|
||||
} else {
|
||||
circle.setMap(mapState.map);
|
||||
circle.setCenter(home.latlng);
|
||||
circle.setRadius(home.radius);
|
||||
}
|
||||
});
|
||||
mapState.homeCircle = mapState.homeCircles[0] || null;
|
||||
}
|
||||
|
||||
function nearestHome(point) {
|
||||
if (!mapState.homeCenters?.length || !point) return { home: null, distance: Infinity };
|
||||
return mapState.homeCenters.reduce((nearest, home) => {
|
||||
const distance = distanceMeters(home, point);
|
||||
return distance < nearest.distance ? { home, distance } : nearest;
|
||||
}, { home: null, distance: Infinity });
|
||||
}
|
||||
|
||||
function isHomePoint(point) {
|
||||
const nearest = nearestHome(point);
|
||||
return !!nearest.home && nearest.distance <= nearest.home.radius;
|
||||
}
|
||||
|
||||
function distanceFromHome(point) {
|
||||
if (!mapState.homeCenter || !point) return Infinity;
|
||||
return distanceMeters(mapState.homeCenter, point);
|
||||
return nearestHome(point).distance;
|
||||
}
|
||||
|
||||
function classifyHomePoint(point) {
|
||||
const distance = distanceFromHome(point);
|
||||
if (distance <= homeRadiusMeters()) return 'home';
|
||||
if (mapState.filterOutliers && distance <= HOME_JITTER_ABSORB_RADIUS_M) return 'home';
|
||||
if (distance <= HOME_NEAR_RADIUS_M) return 'near';
|
||||
const nearest = nearestHome(point);
|
||||
if (!nearest.home) return 'away';
|
||||
if (nearest.distance <= nearest.home.radius) return 'home';
|
||||
if (mapState.filterOutliers && nearest.distance <= HOME_JITTER_ABSORB_RADIUS_M) return 'home';
|
||||
return 'away';
|
||||
}
|
||||
|
||||
function buildHomeStats(points) {
|
||||
if (!mapState.homeCenter || !Array.isArray(points) || points.length < 2) return null;
|
||||
if (!mapState.homeCenters?.length || !Array.isArray(points) || points.length < 2) return null;
|
||||
const t = translations[langCode] || translations.ko;
|
||||
const minAwaySeconds = 5 * 60;
|
||||
let homeSeconds = 0;
|
||||
|
||||
Reference in New Issue
Block a user