iobroker.life360ng 1.2.0 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -292,6 +292,12 @@ Note: The original [repository](https://github.com/MiGoller/ioBroker.life360) is
292
292
  <!--
293
293
  ### **WORK IN PROGRESS**
294
294
  -->
295
+ ### 1.2.2 (2026-05-03)
296
+ - (skvarel) Modified map - Endpoint of the past days as a dot instead of a pin
297
+
298
+ ### 1.2.1 (2026-05-02)
299
+ - (skvarel) Modified map pin with opacity and size
300
+
295
301
  ### 1.2.0 (2026-05-01)
296
302
  - (skvarel) Added GPS route tracking with per-person and family map (OpenStreetMap)
297
303
  - (skvarel) Added adapter documentation
@@ -305,13 +311,6 @@ Note: The original [repository](https://github.com/MiGoller/ioBroker.life360) is
305
311
  - (skvarel) Improved help tab in the config
306
312
  - (skvarel) Added new screenshots of browser DevTools
307
313
 
308
- ### 1.0.20 (2026-04-13)
309
- - (skvarel) Removed react and mui
310
- - (skvarel) Edit readme
311
-
312
- ### 1.0.19 (2026-04-12)
313
- - (skvarel) Translations adjusted
314
-
315
314
  ## Older changes
316
315
  - [CHANGELOG_OLD.md](CHANGELOG_OLD.md)
317
316
 
@@ -47,6 +47,8 @@
47
47
  "tracker_info_txt": "Änderungen an den Farben werden beim nächsten GPS-Update automatisch übernommen.\nDie Karten-URL ist unter tracker.<Person>.url im Objektbaum zu finden.",
48
48
  "tracker_marker_opacity": "Deckkraft Marker",
49
49
  "tracker_marker_opacity_help": "Deckkraft des Positionsmarkers (0.0 = transparent, 1.0 = voll sichtbar)",
50
+ "tracker_marker_size": "Marker Größe",
51
+ "tracker_marker_size_help": "Größenfaktor des Positionsmarkers (0.5 = halb, 1.0 = Standard, 2.0 = doppelt)",
50
52
  "tracker_min_distance": "Mindestabstand (Meter)",
51
53
  "tracker_min_distance_help": "Neuer Punkt wird erst ab diesem Abstand gespeichert (5-500m)",
52
54
  "tracker_person_circle_map": "Kreiskarte",
@@ -50,6 +50,8 @@
50
50
  "tracker_route_opacity_help": "Opacity of the route line (0.0 - 1.0)",
51
51
  "tracker_marker_opacity": "Marker opacity",
52
52
  "tracker_marker_opacity_help": "Opacity of the position marker (0.0 = transparent, 1.0 = fully visible)",
53
+ "tracker_marker_size": "Marker size",
54
+ "tracker_marker_size_help": "Size factor for the position marker (0.5 = half, 1.0 = default, 2.0 = double)",
53
55
  "section_tracker_info": "Note",
54
56
  "tracker_info_txt": "Color changes take effect automatically on the next GPS update.\nThe map URL can be found under tracker.<Person>.url in the object tree.",
55
57
  "tracker_person_name": "Name",
@@ -47,6 +47,8 @@
47
47
  "tracker_info_txt": "Los cambios de color entran en vigor automáticamente en la próxima actualización del GPS.\nLa URL del mapa se puede encontrar en tracker.<Persona>.url en el árbol de objetos.",
48
48
  "tracker_marker_opacity": "Opacidad del marcador",
49
49
  "tracker_marker_opacity_help": "Opacidad del marcador de posición (0,0 = transparente, 1,0 = totalmente visible)",
50
+ "tracker_marker_size": "Tamaño del marcador",
51
+ "tracker_marker_size_help": "Factor de tamaño del marcador de posición (0,5 = mitad, 1,0 = predeterminado, 2,0 = doble)",
50
52
  "tracker_min_distance": "Distancia mínima (metros)",
51
53
  "tracker_min_distance_help": "Un nuevo punto se guarda sólo después de superar esta distancia (5-500 m)",
52
54
  "tracker_person_circle_map": "mapa circular",
@@ -47,6 +47,8 @@
47
47
  "tracker_info_txt": "Les changements de couleur prennent effet automatiquement lors de la prochaine mise à jour du GPS.\nL'URL de la carte se trouve sous tracker.<Person>.url dans l'arborescence des objets.",
48
48
  "tracker_marker_opacity": "Opacité du marqueur",
49
49
  "tracker_marker_opacity_help": "Opacité du marqueur de position (0,0 = transparent, 1,0 = entièrement visible)",
50
+ "tracker_marker_size": "Taille du marqueur",
51
+ "tracker_marker_size_help": "Facteur de taille du marqueur de position (0,5 = moitié, 1,0 = défaut, 2,0 = double)",
50
52
  "tracker_min_distance": "Distance minimale (mètres)",
51
53
  "tracker_min_distance_help": "Un nouveau point n'est enregistré qu'après avoir dépassé cette distance (5-500m)",
52
54
  "tracker_person_circle_map": "Carte circulaire",
@@ -47,6 +47,8 @@
47
47
  "tracker_info_txt": "Le modifiche al colore diventano effettive automaticamente al successivo aggiornamento GPS.\nL'URL della mappa può essere trovato sotto tracker.<Person>.url nell'albero degli oggetti.",
48
48
  "tracker_marker_opacity": "Opacità del marcatore",
49
49
  "tracker_marker_opacity_help": "Opacità dell'indicatore di posizione (0.0 = trasparente, 1.0 = completamente visibile)",
50
+ "tracker_marker_size": "Dimensione marcatore",
51
+ "tracker_marker_size_help": "Fattore di dimensione del marcatore di posizione (0,5 = metà, 1,0 = predefinito, 2,0 = doppio)",
50
52
  "tracker_min_distance": "Distanza minima (metri)",
51
53
  "tracker_min_distance_help": "Un nuovo punto viene salvato solo dopo aver superato questa distanza (5-500 m)",
52
54
  "tracker_person_circle_map": "Mappa circolare",
@@ -47,6 +47,8 @@
47
47
  "tracker_info_txt": "Kleurveranderingen worden automatisch van kracht bij de volgende GPS-update.\nDe kaart-URL kunt u vinden onder tracker.<Persoon>.url in de objectboom.",
48
48
  "tracker_marker_opacity": "Dekking van de markering",
49
49
  "tracker_marker_opacity_help": "Dekking van de positiemarkering (0,0 = transparant, 1,0 = volledig zichtbaar)",
50
+ "tracker_marker_size": "Markergrootte",
51
+ "tracker_marker_size_help": "Grootte-factor van de positiemarkering (0,5 = half, 1,0 = standaard, 2,0 = dubbel)",
50
52
  "tracker_min_distance": "Minimale afstand (meter)",
51
53
  "tracker_min_distance_help": "Pas nadat deze afstand is overschreden (5-500m) wordt een nieuw punt opgeslagen",
52
54
  "tracker_person_circle_map": "Cirkel kaart",
@@ -47,6 +47,8 @@
47
47
  "tracker_info_txt": "Zmiany kolorów zaczną obowiązywać automatycznie przy następnej aktualizacji GPS.\nAdres URL mapy można znaleźć pod tracker.<Person>.url w drzewie obiektów.",
48
48
  "tracker_marker_opacity": "Nieprzezroczystość znacznika",
49
49
  "tracker_marker_opacity_help": "Nieprzezroczystość znacznika pozycji (0,0 = przezroczysty, 1,0 = całkowicie widoczny)",
50
+ "tracker_marker_size": "Rozmiar znacznika",
51
+ "tracker_marker_size_help": "Współczynnik rozmiaru znacznika pozycji (0,5 = połowa, 1,0 = domyślny, 2,0 = podwójny)",
50
52
  "tracker_min_distance": "Minimalna odległość (metry)",
51
53
  "tracker_min_distance_help": "Nowy punkt zostaje zapisany dopiero po przekroczeniu tej odległości (5-500m)",
52
54
  "tracker_person_circle_map": "Mapa koła",
@@ -47,6 +47,8 @@
47
47
  "tracker_info_txt": "As alterações de cor entram em vigor automaticamente na próxima atualização do GPS.\nA URL do mapa pode ser encontrada em tracker.<Person>.url na árvore de objetos.",
48
48
  "tracker_marker_opacity": "Opacidade do marcador",
49
49
  "tracker_marker_opacity_help": "Opacidade do marcador de posição (0,0 = transparente, 1,0 = totalmente visível)",
50
+ "tracker_marker_size": "Tamanho do marcador",
51
+ "tracker_marker_size_help": "Fator de tamanho do marcador de posição (0,5 = metade, 1,0 = padrão, 2,0 = duplo)",
50
52
  "tracker_min_distance": "Distância mínima (metros)",
51
53
  "tracker_min_distance_help": "Um novo ponto é salvo somente após esta distância ter sido ultrapassada (5-500m)",
52
54
  "tracker_person_circle_map": "Mapa circular",
@@ -47,6 +47,8 @@
47
47
  "tracker_info_txt": "Изменения цвета вступят в силу автоматически при следующем обновлении GPS.\nURL-адрес карты можно найти в разделе tracker.<Person>.url в дереве объектов.",
48
48
  "tracker_marker_opacity": "Непрозрачность маркера",
49
49
  "tracker_marker_opacity_help": "Непрозрачность маркера положения (0,0 = прозрачный, 1,0 = полностью видимый)",
50
+ "tracker_marker_size": "Размер маркера",
51
+ "tracker_marker_size_help": "Коэффициент размера маркера положения (0,5 = половина, 1,0 = стандартный, 2,0 = двойной)",
50
52
  "tracker_min_distance": "Минимальное расстояние (метры)",
51
53
  "tracker_min_distance_help": "Новая точка сохраняется только после превышения этого расстояния (5-500м).",
52
54
  "tracker_person_circle_map": "Круговая карта",
@@ -47,6 +47,8 @@
47
47
  "tracker_info_txt": "Зміни кольору набувають чинності автоматично під час наступного оновлення GPS.\nURL-адресу карти можна знайти в tracker.<Person>.url у дереві об’єктів.",
48
48
  "tracker_marker_opacity": "Непрозорість маркера",
49
49
  "tracker_marker_opacity_help": "Непрозорість маркера позиції (0,0 = прозорий, 1,0 = повністю видимий)",
50
+ "tracker_marker_size": "Розмір маркера",
51
+ "tracker_marker_size_help": "Коефіцієнт розміру маркера позиції (0,5 = половина, 1,0 = стандартний, 2,0 = подвійний)",
50
52
  "tracker_min_distance": "Мінімальна відстань (метри)",
51
53
  "tracker_min_distance_help": "Нова точка зберігається тільки після перевищення цієї відстані (5-500 м)",
52
54
  "tracker_person_circle_map": "Кругова карта",
@@ -47,6 +47,8 @@
47
47
  "tracker_info_txt": "颜色更改会在下次 GPS 更新时自动生效。\n地图 URL 可以在对象树中的 tracker.<Person>.url 下找到。",
48
48
  "tracker_marker_opacity": "标记不透明度",
49
49
  "tracker_marker_opacity_help": "位置标记的不透明度(0.0 = 透明,1.0 = 完全可见)",
50
+ "tracker_marker_size": "标记大小",
51
+ "tracker_marker_size_help": "位置标记的大小因子(0.5 = 一半,1.0 = 默认,2.0 = 双倍)",
50
52
  "tracker_min_distance": "最小距离(米)",
51
53
  "tracker_min_distance_help": "仅在超过此距离 (5-500m) 后才会保存新点",
52
54
  "tracker_person_circle_map": "圆形地图",
@@ -346,6 +346,20 @@
346
346
  "md": 3,
347
347
  "lg": 3,
348
348
  "xl": 3
349
+ },
350
+ "tracker_marker_size": {
351
+ "type": "number",
352
+ "label": "tracker_marker_size",
353
+ "help": "tracker_marker_size_help",
354
+ "default": 1,
355
+ "min": 0.5,
356
+ "max": 3,
357
+ "step": 0.1,
358
+ "xs": 12,
359
+ "sm": 6,
360
+ "md": 3,
361
+ "lg": 3,
362
+ "xl": 3
349
363
  }
350
364
  }
351
365
  },
package/io-package.json CHANGED
@@ -1,8 +1,34 @@
1
1
  {
2
2
  "common": {
3
3
  "name": "life360ng",
4
- "version": "1.2.0",
4
+ "version": "1.2.2",
5
5
  "news": {
6
+ "1.2.2": {
7
+ "en": "Modified map - Endpoint of the past days as a dot instead of a pin",
8
+ "de": "Geänderte Karte - Endpunkt der letzten Tage als Punkt anstelle eines Stiftes",
9
+ "ru": "Модифицированная карта - конечная точка прошлых дней как точка вместо булавки",
10
+ "pt": "Mapa modificado - Ponto final dos últimos dias como um ponto em vez de um pino",
11
+ "nl": "Gewijzigde kaart - Eindpunt van de afgelopen dagen als punt in plaats van een pin",
12
+ "fr": "Carte modifiée - Point d'arrivée des derniers jours comme point au lieu d'une broche",
13
+ "it": "Mappa modificata - Fine dei giorni passati come punto invece di un perno",
14
+ "es": "Mapa modificado - Endpoint of the past days as a dot instead of a pin",
15
+ "pl": "Zmodyfikowana mapa - Punkt końcowy ostatnich dni jako kropka zamiast szpilki",
16
+ "uk": "Модифікована карта - Кінцева точка минулих днів як точка замість шпильки",
17
+ "zh-cn": "修改地图 - 过去几天作为点而不是针的终点"
18
+ },
19
+ "1.2.1": {
20
+ "en": "Modified map pin with opacity and size",
21
+ "de": "Geänderter Kartenstift mit Deckkraft und Größe",
22
+ "ru": "Модифицированный значок карты с непрозрачностью и размером",
23
+ "pt": "Pino de mapa modificado com opacidade e tamanho",
24
+ "nl": "Gewijzigde kaartspeld met dekking en grootte",
25
+ "fr": "Pin de carte modifié avec opacité et taille",
26
+ "it": "Perno mappa modificato con opacità e dimensione",
27
+ "es": "Pin de mapa modificado con opacidad y tamaño",
28
+ "pl": "Zmodyfikowany pin mapy z nieprzezroczystości i wielkości",
29
+ "uk": "Модифікований картковий шпилька з непрозорістю і розміром",
30
+ "zh-cn": "修改带有不透明度和大小的地图针"
31
+ },
6
32
  "1.2.0": {
7
33
  "en": "Added GPS route tracking with per-person and family map (OpenStreetMap)\nAdded adapter documentation",
8
34
  "de": "GPS-Tracking mit Per-Personen- und Familienkarte (OpenStreetMap) hinzugefügt\nZusätzliche Adapterdokumentation",
@@ -67,32 +93,6 @@
67
93
  "pl": "Korekta tłumaczeń",
68
94
  "uk": "Переклади",
69
95
  "zh-cn": "经调整的翻译"
70
- },
71
- "1.0.18": {
72
- "en": "Fixed info.connection role in io-package.json\nRemoved @ts-nocheck and unused variable from lib files; fixed CRLF line endings\nESLint now covers all lib files with strict no-warnings enforcement\nAdded Copilot instructions for guided development",
73
- "de": "Fixed info.connection Rolle in io-package.json\nEntfernt @ts-nocheck und ungenutzte Variable aus lib-Dateien; Feste CRLF-Linie endet\nESLint deckt jetzt alle lib-Dateien mit strengen No-Warnings Durchsetzung\nZusätzlich Copilot Anleitung für geführte Entwicklung",
74
- "ru": "Фиксированная роль info.connection в io-package.json\nУдаленный @ts-nocheck и неиспользуемая переменная из файлов lib; фиксированные окончания строк CRLF\nESLint теперь охватывает все файлы lib со строгим соблюдением без предупреждения\nДобавлены инструкции Copilot для управляемой разработки",
75
- "pt": "Fixado info.connection role in io-package.json\nRemovido @ ts- nocheck e variável não utilizada dos arquivos lib; finalizações de linha CRLF corrigidas\nESLint agora cobre todos os arquivos de lib com aplicação estrita sem avisos\nAdicionado instruções Copilot para desenvolvimento guiado",
76
- "nl": "Vaste info.connectie rol in io-package.json\nVerwijderde @ts-nocheck en ongebruikte variabele uit lib-bestanden; vaste CRLF regeleinden\nESLint behandelt nu alle lib-bestanden met strikte no-warnings handhaving\nToegevoegd Copilot instructies voor geleide ontwikkeling",
77
- "fr": "Fixed info.connection role in io-package.json\nSupprimé @ts-nocheck et variable inutilisée des fichiers lib; ligne CRLF corrigée se termine\nESLint couvre désormais tous les fichiers lib avec une stricte application sans avertissement\nAjout des instructions de copilote pour le développement guidé",
78
- "it": "Risolto ruolo di info.connection in io-package.json\nRimuoveto @ts-nocheck e variabile inutilizzata da file lib; fisse terminazioni linea CRLF\nESLint ora copre tutti i file lib con rigorose esecuzioni no-warnings\nAggiunta istruzioni Copilota per lo sviluppo guidato",
79
- "es": "Función de conexión en io-package.json\nEliminado @ts-nocheck y la variable no utilizada de los archivos lib; terminaciones de línea fija CRLF\nESLint ahora cubre todos los archivos de lib con estricta aplicación de no alerta\nInstrucciones de Copiloto adicionales para el desarrollo guiado",
80
- "pl": "Naprawiono funkcję info.connection w jo- package.json\nUsunięto @ ts- nocheck i nieużywaną zmienną z plików lib; stałe zakończenia linii CRLF\nESLINT teraz obejmuje wszystkie pliki lib ze ścisłym zero-ostrzeżeń egzekwowania\nDodano instrukcje kopiowania dla rozwoju z przewodnikiem",
81
- "uk": "Виправлено info.connection роль в io-package.json\nВилучено @ts-nocheck і невикористана змінна з файлів lib; виправлено закінчення лінії CRLF\nESLint тепер охоплює всі файли з суворим захистом від викривлення\nДодано інструкції Copilot для керованого розвитку",
82
- "zh-cn": "固定信息. 连接角色在io-package.json\n从 lib 文件中删除了 @ ts- nocheck 和未使用的变量; 固定的 CRLF 行结束\nESLint现在以严格的不警告执行覆盖所有 lib 文件\n为指导性开发添加的副驾驶指令"
83
- },
84
- "1.0.17": {
85
- "en": "Configuration revised, translations adjusted and repo cleaned up",
86
- "de": "Konfiguration überarbeitet, Übersetzungen angepasst und repo aufgeräumt",
87
- "ru": "Конфигурация пересмотрена, переводы скорректированы и репо очищены",
88
- "pt": "Configuração revista, traduções ajustadas e recuperação limpas",
89
- "nl": "Configuratie herzien, vertalingen aangepast en repo opgeschoond",
90
- "fr": "Configuration révisée, traduction ajustée et repo nettoyée",
91
- "it": "Configurazione revisionata, traduzioni regolate e ripulite",
92
- "es": "Configuración revisada, traducciones ajustadas y recuperadas",
93
- "pl": "Konfiguracja poprawiona, poprawiona i poprawiona wersja tłumaczenia",
94
- "uk": "Конфігурація переглянуті, переклади регульовані і перепо очищають",
95
- "zh-cn": "配置修改、翻译调整和重新整理"
96
96
  }
97
97
  },
98
98
  "titleLang": {
@@ -138,6 +138,7 @@ class Tracker {
138
138
  routeWeight: c.tracker_route_weight ?? 4,
139
139
  routeOpacity: c.tracker_route_opacity ?? 0.85,
140
140
  markerOpacity: c.tracker_marker_opacity ?? 1,
141
+ markerSize: c.tracker_marker_size ?? 1,
141
142
  },
142
143
  familyRoutesEnabled: c.tracker_family_routes_enabled ?? true,
143
144
  familyMapHeaderName: c.family_map_header_name || "",
@@ -878,6 +879,7 @@ class Tracker {
878
879
  const DARK = "${dark}";
879
880
  const SEL_DATE = "${selDate}";
880
881
  const MARKER_OPACITY = ${c.markerOpacity};
882
+ const MARKER_SIZE = ${c.markerSize};
881
883
  // Use a unique storage key per person (personId or name)
882
884
  const STORAGE_KEY = "tracker_showRoute_${personKey}";
883
885
 
@@ -905,12 +907,14 @@ class Tracker {
905
907
  }
906
908
 
907
909
  function pinIcon(color) {
910
+ const w = Math.round(28 * MARKER_SIZE);
911
+ const h = Math.round(36 * MARKER_SIZE);
908
912
  return L.divIcon({
909
913
  className: '',
910
- html: '<svg xmlns="http://www.w3.org/2000/svg" width="28" height="36" viewBox="0 0 28 36" style="opacity:' + MARKER_OPACITY + '"><path d="M14 0C6.27 0 0 6.27 0 14c0 9.33 14 22 14 22S28 23.33 28 14C28 6.27 21.73 0 14 0z" fill="' + color + '" stroke="#fff" stroke-width="2"/><circle cx="14" cy="14" r="5" fill="#fff"/></svg>',
911
- iconSize: [28, 36],
912
- iconAnchor: [14, 36],
913
- popupAnchor: [0, -36]
914
+ html: '<svg xmlns="http://www.w3.org/2000/svg" width="' + w + '" height="' + h + '" viewBox="0 0 28 36" style="opacity:' + MARKER_OPACITY + '"><path fill-rule="evenodd" d="M14 0C6.27 0 0 6.27 0 14c0 9.33 14 22 14 22S28 23.33 28 14C28 6.27 21.73 0 14 0z M8 14a6 6 0 1 0 12 0a6 6 0 1 0-12 0z" fill="' + color + '" stroke="#fff" stroke-width="1.5"/></svg>',
915
+ iconSize: [w, h],
916
+ iconAnchor: [Math.round(w / 2), h],
917
+ popupAnchor: [0, -h]
914
918
  });
915
919
  }
916
920
 
@@ -984,6 +988,7 @@ class Tracker {
984
988
  clearLayers();
985
989
  const feats = FEATURES.filter(f => f.date >= from && f.date <= to && f.coords.length > 0);
986
990
  if (feats.length === 0) return;
991
+ const maxDate = feats.reduce((max, f) => f.date > max ? f.date : max, '');
987
992
  const bounds = [];
988
993
  feats.forEach(function(feat) {
989
994
  const fc = feat.color || COLOR;
@@ -996,10 +1001,17 @@ class Tracker {
996
1001
  L.circleMarker(coords[0], { radius:7, fillColor:DARK, color:'#fff', weight:2, fillOpacity:1 })
997
1002
  .bindPopup(feat.date + '<br>▶ ' + fmt(ts[0])).addTo(map)
998
1003
  );
999
- layers.push(
1000
- L.marker(coords[coords.length-1], { icon: pinIcon(fc) })
1001
- .bindPopup(feat.date + '<br>📍 ' + fmt(ts[ts.length-1])).addTo(map)
1002
- );
1004
+ if (feat.date === maxDate) {
1005
+ layers.push(
1006
+ L.marker(coords[coords.length-1], { icon: pinIcon(fc) })
1007
+ .bindPopup(feat.date + '<br>📍 ' + fmt(ts[ts.length-1])).addTo(map)
1008
+ );
1009
+ } else {
1010
+ layers.push(
1011
+ L.circleMarker(coords[coords.length-1], { radius:8, fillColor:fc, color:'#fff', weight:2, fillOpacity:MARKER_OPACITY })
1012
+ .bindPopup(feat.date + '<br>📍 ' + fmt(ts[ts.length-1])).addTo(map)
1013
+ );
1014
+ }
1003
1015
  coords.forEach(function(coord, i) {
1004
1016
  if (i === 0 || i === coords.length - 1) return;
1005
1017
  layers.push(
@@ -1248,6 +1260,7 @@ class Tracker {
1248
1260
  const FEATURES = ${featuresJSON};
1249
1261
  const SEL_DATE = "${selDate}";
1250
1262
  const MARKER_OPACITY = ${c.markerOpacity};
1263
+ const MARKER_SIZE = ${c.markerSize};
1251
1264
  const visiblePeople = Object.fromEntries([...new Set(FEATURES.map(f => f.name))].map(name => [name, true]));
1252
1265
  // Use a unique storage key for the family map
1253
1266
  const STORAGE_KEY = "tracker_showRoute_circle";
@@ -1267,12 +1280,14 @@ class Tracker {
1267
1280
  }
1268
1281
 
1269
1282
  function pinIcon(color) {
1283
+ const w = Math.round(28 * MARKER_SIZE);
1284
+ const h = Math.round(36 * MARKER_SIZE);
1270
1285
  return L.divIcon({
1271
1286
  className: '',
1272
- html: '<svg xmlns="http://www.w3.org/2000/svg" width="28" height="36" viewBox="0 0 28 36" style="opacity:' + MARKER_OPACITY + '"><path d="M14 0C6.27 0 0 6.27 0 14c0 9.33 14 22 14 22S28 23.33 28 14C28 6.27 21.73 0 14 0z" fill="' + color + '" stroke="#fff" stroke-width="2"/><circle cx="14" cy="14" r="5" fill="#fff"/></svg>',
1273
- iconSize: [28, 36],
1274
- iconAnchor: [14, 36],
1275
- popupAnchor: [0, -36]
1287
+ html: '<svg xmlns="http://www.w3.org/2000/svg" width="' + w + '" height="' + h + '" viewBox="0 0 28 36" style="opacity:' + MARKER_OPACITY + '"><path fill-rule="evenodd" d="M14 0C6.27 0 0 6.27 0 14c0 9.33 14 22 14 22S28 23.33 28 14C28 6.27 21.73 0 14 0z M8 14a6 6 0 1 0 12 0a6 6 0 1 0-12 0z" fill="' + color + '" stroke="#fff" stroke-width="1.5"/></svg>',
1288
+ iconSize: [w, h],
1289
+ iconAnchor: [Math.round(w / 2), h],
1290
+ popupAnchor: [0, -h]
1276
1291
  });
1277
1292
  }
1278
1293
 
@@ -1302,6 +1317,11 @@ class Tracker {
1302
1317
  // Only render routes if showRoute is enabled
1303
1318
  const showRoute = document.getElementById('showRoute')?.checked;
1304
1319
  const bounds = [];
1320
+ // Most recent date per person: only that day gets a pin, all others get a larger dot
1321
+ const maxDateByPerson = {};
1322
+ feats.forEach(function(f) {
1323
+ if (!maxDateByPerson[f.name] || f.date > maxDateByPerson[f.name]) maxDateByPerson[f.name] = f.date;
1324
+ });
1305
1325
  feats.forEach(function(feat) {
1306
1326
  const color = feat.color;
1307
1327
  const dark = darken(color, 0.6);
@@ -1322,11 +1342,18 @@ class Tracker {
1322
1342
  .bindPopup(prefix + '▶ Start: ' + fmt(ts[0])).addTo(map)
1323
1343
  );
1324
1344
  }
1325
- // Always show last point
1326
- layers.push(
1327
- L.marker(coords[coords.length - 1], { icon: pinIcon(color) })
1328
- .bindPopup(prefix + '📍 ' + fmt(ts[ts.length - 1])).addTo(map)
1329
- );
1345
+ // Most recent day → pin, past days → larger dot
1346
+ if (feat.date === maxDateByPerson[feat.name]) {
1347
+ layers.push(
1348
+ L.marker(coords[coords.length - 1], { icon: pinIcon(color) })
1349
+ .bindPopup(prefix + '📍 ' + fmt(ts[ts.length - 1])).addTo(map)
1350
+ );
1351
+ } else {
1352
+ layers.push(
1353
+ L.circleMarker(coords[coords.length - 1], { radius:8, fillColor:color, color:'#fff', weight:2, fillOpacity:MARKER_OPACITY })
1354
+ .bindPopup(prefix + '📍 ' + fmt(ts[ts.length - 1])).addTo(map)
1355
+ );
1356
+ }
1330
1357
 
1331
1358
  // Only show intermediate points if route is visible
1332
1359
  if (showRoute) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iobroker.life360ng",
3
- "version": "1.2.0",
3
+ "version": "1.2.2",
4
4
  "description": "An ioBroker adapter for Life360.",
5
5
  "author": "skvarel <skvarel@inventwo.com>",
6
6
  "homepage": "https://github.com/inventwo/ioBroker.life360ng",