@furkot/garmin-data 1.0.1 → 2.0.0
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/index.js +1 -1
- package/lib/garmin.js +114 -12
- package/lib/index.js +233 -0
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
module.exports = require('./lib
|
|
1
|
+
module.exports = require('./lib');
|
package/lib/garmin.js
CHANGED
|
@@ -7,7 +7,7 @@ module.exports = {
|
|
|
7
7
|
4: 'Trail Head', // snowshoeing
|
|
8
8
|
5: 'Library', // book
|
|
9
9
|
6: 'Bank', // deal
|
|
10
|
-
|
|
10
|
+
7: 'Pin, Blue', // pin
|
|
11
11
|
8: 'Bike Trail', // biking
|
|
12
12
|
9: 'Picnic Area', // picnic
|
|
13
13
|
10: 'Gas Station', // charging
|
|
@@ -26,7 +26,7 @@ module.exports = {
|
|
|
26
26
|
23: 'Airport', // airplane
|
|
27
27
|
24: 'Restaurant', // restaurant
|
|
28
28
|
25: 'Gas Station', // fillingstation
|
|
29
|
-
|
|
29
|
+
26: 'Bike Trail', // motorcycle
|
|
30
30
|
27: 'Food Source', // farmstand
|
|
31
31
|
28: 'Bar', // brewery
|
|
32
32
|
29: 'Amusement Park', // amusementpark
|
|
@@ -43,7 +43,7 @@ module.exports = {
|
|
|
43
43
|
40: 'Building', // worldheritagesite
|
|
44
44
|
41: 'City Hall', // officebuilding
|
|
45
45
|
42: 'Church', // shrine
|
|
46
|
-
43: 'Tower',
|
|
46
|
+
43: 'Tall Tower', // tower
|
|
47
47
|
44: 'Church', // temple
|
|
48
48
|
45: 'Museum', // sciencemuseum
|
|
49
49
|
46: 'Building', // landmark
|
|
@@ -69,13 +69,13 @@ module.exports = {
|
|
|
69
69
|
66: 'Library', // library
|
|
70
70
|
67: 'Zoo', // zoo
|
|
71
71
|
68: 'Stadium', // stadium
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
69: 'Short Tower', // windmill
|
|
73
|
+
70: 'Square, Green', // square
|
|
74
74
|
71: 'City (Medium)', // town
|
|
75
|
-
|
|
75
|
+
72: 'Buoy, White', // statue
|
|
76
76
|
73: 'Information', // information
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
74: 'Diamond, Green', // amphitheater
|
|
78
|
+
75: 'Scenic Area', // observatory
|
|
79
79
|
//76: '', // passthru
|
|
80
80
|
77: 'Drinking Water', // tap
|
|
81
81
|
78: 'Convenience Store', // minimarket
|
|
@@ -86,27 +86,129 @@ module.exports = {
|
|
|
86
86
|
83: 'Truck Stop', // truck
|
|
87
87
|
84: 'RV Park', // rvpark
|
|
88
88
|
85: 'Bridge', // bridge
|
|
89
|
-
86: '
|
|
89
|
+
86: 'Favorite', // star
|
|
90
90
|
87: 'Geocache', // treasure
|
|
91
|
-
|
|
91
|
+
88: 'Parachute Area', // teleport
|
|
92
92
|
89: 'Crossing', // railroadcrossing
|
|
93
93
|
90: 'Restaurant', // coffee
|
|
94
94
|
91: 'ATV', // atv
|
|
95
95
|
92: 'Dog, sitting', // pets
|
|
96
|
-
|
|
96
|
+
93: 'Triangle, Red', // fire
|
|
97
97
|
94: 'Fishing Area', // pier
|
|
98
98
|
95: 'Ferry', // ferry
|
|
99
99
|
96: 'Live Theater', // theater
|
|
100
100
|
97: 'Railway', // train
|
|
101
101
|
98: 'Parking Area', // parking
|
|
102
102
|
99: 'Shopping Center', // cart
|
|
103
|
-
100: 'Boat Ramp'
|
|
103
|
+
100: 'Boat Ramp', // boatramp
|
|
104
|
+
101: 'Covey', // bird
|
|
105
|
+
102: 'Mile Marker', // clock
|
|
106
|
+
103: 'Movie Theater', // film
|
|
107
|
+
104: 'Horn', // music
|
|
108
|
+
105: 'Contact, clown', // entertain
|
|
109
|
+
106: 'Ground Transportation', // bus
|
|
110
|
+
107: 'Ground Transportation', // taxi
|
|
111
|
+
108: 'ATV', // off-road
|
|
112
|
+
109: 'Dam', // dam
|
|
113
|
+
110: 'Skull and Crossbones', // danger
|
|
114
|
+
111: 'Exit', // enter
|
|
115
|
+
112: 'Geocache', // gift
|
|
116
|
+
113: 'Contact, Blonde', // hairdresser
|
|
117
|
+
114: 'Favorite', // heart
|
|
118
|
+
115: 'Oil Field', // industry
|
|
119
|
+
116: 'Happy Face', // laundry
|
|
120
|
+
117: 'Beacon', // lighthouse
|
|
121
|
+
118: 'Controlled Area', // one-way
|
|
122
|
+
119: 'Fitness Center', // playground
|
|
123
|
+
120: 'Police Station', // police
|
|
124
|
+
121: 'Police Station', // prison
|
|
125
|
+
122: 'Laydown', // roadblock
|
|
126
|
+
123: 'Contact, Alien', // rocket
|
|
127
|
+
124: 'School', // school
|
|
128
|
+
125: 'Fishing Hot Spot Facility',// shelter
|
|
129
|
+
126: 'Shipwreck', // suitcase
|
|
130
|
+
127: 'Dog, running', // veterinary
|
|
131
|
+
128: 'Sad Face', // remove
|
|
132
|
+
129: 'Underwater Grass', // wetland
|
|
133
|
+
130: 'Circle with X', // wheelchair
|
|
134
|
+
131: 'Golf Course', // golf
|
|
135
|
+
132: 'Post Office', // envelope
|
|
136
|
+
133: 'Funicular', // aerialway
|
|
137
|
+
134: 'Ultralight Area', // airfield
|
|
138
|
+
135: 'Bar', // alcohol_shop
|
|
139
|
+
136: 'Stadium', // american_football
|
|
140
|
+
137: 'Fishing Area', // aquarium
|
|
141
|
+
138: 'Scenic Area', // attraction
|
|
142
|
+
139: 'Pizza', // bakery
|
|
143
|
+
140: 'Ball Park', // baseball
|
|
144
|
+
141: 'Stadium', // basketball
|
|
145
|
+
142: 'Building', // building
|
|
146
|
+
143: 'Contact, Pig', // butcher
|
|
147
|
+
144: 'Building', // castle
|
|
148
|
+
145: 'Navaid, White', // radio-unchecked
|
|
149
|
+
146: 'Circle, Blue', // circle
|
|
150
|
+
147: 'Department Store', // clothing_store
|
|
151
|
+
148: 'School', // college
|
|
152
|
+
149: 'Scales', // commercial
|
|
153
|
+
150: 'Stadium', // cricket
|
|
154
|
+
151: 'Crossing', // cross
|
|
155
|
+
152: 'Hospital', // dentist
|
|
156
|
+
153: 'Hospital', // doctor
|
|
157
|
+
154: 'City Hall', // embassy
|
|
158
|
+
155: 'Exit', // entrance
|
|
159
|
+
156: 'Fast Food', // fast_food
|
|
160
|
+
157: 'Heliport', // heliport
|
|
161
|
+
158: 'Fast Food', // ice_cream
|
|
162
|
+
159: 'Pin, Green', // marker
|
|
163
|
+
160: 'Summit', // mountain
|
|
164
|
+
161: 'Parking, Pay', // parking_garage
|
|
165
|
+
162: 'Pharmacy', // pharmacy
|
|
166
|
+
163: 'Telephone', // phone
|
|
167
|
+
164: 'Stadium', // pitch
|
|
168
|
+
165: 'Church', // place_of_worship
|
|
169
|
+
166: 'Railway', // rail_light
|
|
170
|
+
167: 'Railway', // rail_metro
|
|
171
|
+
168: 'Stadium', // soccer
|
|
172
|
+
169: 'Square, Yellow', // square-stroke
|
|
173
|
+
170: 'Square, Blue', // square-fill
|
|
174
|
+
171: 'City (Capitol)', // star-stroke
|
|
175
|
+
172: 'Restaurant', // sushi
|
|
176
|
+
173: 'Stadium', // tennis
|
|
177
|
+
174: 'Triangle, Blue', // triangle
|
|
178
|
+
175: 'Triangle, Yellow', // triangle_stroked
|
|
179
|
+
176: 'Multi-Cache', // warehouse
|
|
180
|
+
177: 'Weed Bed', // garden
|
|
181
|
+
178: 'Gas Station', // diesel
|
|
182
|
+
179: 'Gas Station', // ethanol-free
|
|
183
|
+
180: 'Swimming Area', // swimming
|
|
184
|
+
181: 'Puzzle Cache' // question
|
|
104
185
|
},
|
|
105
186
|
toFurkot: {
|
|
187
|
+
'ATV': 91, // atv
|
|
188
|
+
'Bar': 31, // bar
|
|
189
|
+
'Bike Trail': 8, // biking
|
|
190
|
+
'Building': 51, // structure
|
|
106
191
|
'Church': 34, // church
|
|
192
|
+
'City Hall': 41, // officebuilding
|
|
193
|
+
'Crossing': 89, // railroadcrossing
|
|
194
|
+
'Exit': 155, // entrance
|
|
195
|
+
'Fast Food': 156, // fast_food
|
|
196
|
+
'Favorite': 86, // star
|
|
197
|
+
'Fishing Area': 137, // aquarium
|
|
198
|
+
'Gas Station': 25, // fillingstation
|
|
199
|
+
'Geocache': 87, // treasure
|
|
200
|
+
'Ground Transportation': 106, // bus'
|
|
201
|
+
'Hospital': 81, // hospital
|
|
107
202
|
'Lodging': 0, // hotel
|
|
108
203
|
'Museum': 33, // museum
|
|
109
204
|
'Park': 50, // park
|
|
205
|
+
'Police Station': 120, // police
|
|
206
|
+
'Railway': 97, // train
|
|
207
|
+
'Residence': 12, // house
|
|
208
|
+
'Restaurant': 24, // restaurant
|
|
209
|
+
'Scenic Area': 61, // lookout
|
|
210
|
+
'School': 124, // school
|
|
211
|
+
'Stadium': 68, // stadium
|
|
110
212
|
'Summit': 59, // mountains
|
|
111
213
|
'Swimming Area': 54, // watersport
|
|
112
214
|
'Trail Head': 3 // guide
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
const {
|
|
2
|
+
toGarmin,
|
|
3
|
+
toFurkot,
|
|
4
|
+
colors
|
|
5
|
+
} = require('./garmin');
|
|
6
|
+
|
|
7
|
+
const schema = [
|
|
8
|
+
[
|
|
9
|
+
'xmlns:gpxx', 'http://www.garmin.com/xmlschemas/GpxExtensions/v3',
|
|
10
|
+
'http://www8.garmin.com/xmlschemas/GpxExtensionsv3.xsd'
|
|
11
|
+
],
|
|
12
|
+
[
|
|
13
|
+
'xmlns:trp', 'http://www.garmin.com/xmlschemas/TripExtensions/v1',
|
|
14
|
+
'http://www.garmin.com/xmlschemas/TripExtensionsv1.xsd'
|
|
15
|
+
],
|
|
16
|
+
[
|
|
17
|
+
'xmlns:tmd', 'http://www.garmin.com/xmlschemas/TripMetaDataExtensions/v1',
|
|
18
|
+
'http://www.garmin.com/xmlschemas/TripMetaDataExtensionsv1.xsd'
|
|
19
|
+
],
|
|
20
|
+
[
|
|
21
|
+
'xmlns:vptm', 'http://www.garmin.com/xmlschemas/ViaPointTransportationModeExtensions/v1',
|
|
22
|
+
'http://www.garmin.com/xmlschemas/ViaPointTransportationModeExtensionsv1.xsd'
|
|
23
|
+
]
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const modeMap = [
|
|
27
|
+
'Motorcycling',
|
|
28
|
+
'Automotive',
|
|
29
|
+
'Bicycling',
|
|
30
|
+
'Walking',
|
|
31
|
+
'Direct',
|
|
32
|
+
'Direct',
|
|
33
|
+
'RV',
|
|
34
|
+
'Direct'
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
function getMode(rMode, mMode) {
|
|
38
|
+
if (rMode !== undefined) {
|
|
39
|
+
return modeMap[rMode + 1] || 'Unknown';
|
|
40
|
+
}
|
|
41
|
+
return modeMap[(mMode || 0) + 1] || 'Unknown';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const millisInMinute = 60 * 1000;
|
|
45
|
+
const millisInHour = 60 * millisInMinute;
|
|
46
|
+
|
|
47
|
+
function formatDuration(step) {
|
|
48
|
+
const duration = ['P'];
|
|
49
|
+
if (step.nights) {
|
|
50
|
+
duration.push(step.nights, 'D');
|
|
51
|
+
}
|
|
52
|
+
if (step.visit_duration) {
|
|
53
|
+
duration.push('T');
|
|
54
|
+
let dur = Math.floor(step.visit_duration / millisInHour);
|
|
55
|
+
if (dur) {
|
|
56
|
+
duration.push(dur, 'H');
|
|
57
|
+
}
|
|
58
|
+
dur = Math.floor((step.visit_duration % millisInHour) / millisInMinute);
|
|
59
|
+
if (dur) {
|
|
60
|
+
duration.push(dur, 'M');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (duration.length > 2) {
|
|
64
|
+
return duration.join('');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function getWptExt({ start, end, el, elIfText, each }) {
|
|
69
|
+
return function* (st) {
|
|
70
|
+
yield* start('gpxx:WaypointExtension');
|
|
71
|
+
if (st.tags && st.tags.length) {
|
|
72
|
+
yield* start('gpxx:Categories');
|
|
73
|
+
yield* each(st.tags, function* (cat) {
|
|
74
|
+
yield* el('gpxx:Category', null, cat);
|
|
75
|
+
});
|
|
76
|
+
yield* end();
|
|
77
|
+
}
|
|
78
|
+
if (st.address) {
|
|
79
|
+
yield* start('gpxx:Address');
|
|
80
|
+
yield* elIfText('gpxx:StreetAddress', st.stopStreetAddress);
|
|
81
|
+
if (st.locality) {
|
|
82
|
+
yield* elIfText('gpxx:City', st.locality.town);
|
|
83
|
+
yield* elIfText('gpxx:State', st.locality.province);
|
|
84
|
+
yield* elIfText('gpxx:Country', st.locality.country_long);
|
|
85
|
+
}
|
|
86
|
+
yield* end();
|
|
87
|
+
}
|
|
88
|
+
yield* elIfText('gpxx:PhoneNumber', st.phone);
|
|
89
|
+
yield* end();
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function getRteExt({ ctx, start, end, el, elIfText }) {
|
|
94
|
+
return function* (rt) {
|
|
95
|
+
yield* start('gpxx:RouteExtension');
|
|
96
|
+
yield* elIfText('gpxx:IsAutoNamed', 'false');
|
|
97
|
+
yield* elIfText('gpxx:DisplayColor', colors[rt.color] || 'Blue');
|
|
98
|
+
yield* end();
|
|
99
|
+
|
|
100
|
+
const { mode, name } = ctx?.metadata || {};
|
|
101
|
+
|
|
102
|
+
if (rt.mode !== undefined || mode !== undefined) {
|
|
103
|
+
yield* start('trp:Trip');
|
|
104
|
+
//- The <trp:TransportationMode> extension tells the devices Trip Planner algorithm what calculation type to use:
|
|
105
|
+
//- Automotive, Motorcycling, Walking, Bicycling, Direct.
|
|
106
|
+
yield* elIfText('trp:TransportationMode', getMode(rt.mode, mode));
|
|
107
|
+
yield* end();
|
|
108
|
+
|
|
109
|
+
if (name || rt.routeTimestamp || rt.day) {
|
|
110
|
+
yield* start('tmd:TripMetaData');
|
|
111
|
+
yield* el('tmd:TripName', null, name || '');
|
|
112
|
+
if (rt.routeTimestamp) {
|
|
113
|
+
yield* elIfText('tmd:Date', rt.routeTimestamp);
|
|
114
|
+
}
|
|
115
|
+
yield* elIfText('tmd:DayNumber', rt.day);
|
|
116
|
+
yield* end();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function getRtePtExt({ ctx, precision, start, end, each, el, elIfText }) {
|
|
123
|
+
|
|
124
|
+
function* $gpxxRpt(p, subclass) {
|
|
125
|
+
const attribs = {
|
|
126
|
+
lat: p[1].toFixed(precision),
|
|
127
|
+
lon: p[0].toFixed(precision)
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
if (subclass) {
|
|
131
|
+
yield* start('gpxx:rpt', attribs);
|
|
132
|
+
yield* el('gpxx:Subclass', null, subclass);
|
|
133
|
+
yield* end();
|
|
134
|
+
} else {
|
|
135
|
+
yield* el('gpxx:rpt', attribs);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return function* (rt, st, index, next) {
|
|
140
|
+
let shapingPoint;
|
|
141
|
+
|
|
142
|
+
if (st.stopIsActualStop || index % 124 === 0 || !next) {
|
|
143
|
+
//- The <trp:ViaPoint> is equivalent to a Furkot Stop.
|
|
144
|
+
yield* start('trp:ViaPoint');
|
|
145
|
+
if (st.stopDeparture && next) {
|
|
146
|
+
yield* elIfText('trp:DepartureTime', st.stopDeparture);
|
|
147
|
+
}
|
|
148
|
+
if (index && next) {
|
|
149
|
+
yield* elIfText('trp:StopDuration', formatDuration(st));
|
|
150
|
+
}
|
|
151
|
+
if (st.stopTimestamp && index > 0) {
|
|
152
|
+
yield* elIfText('trp:ArrivalTime', st.stopTimestamp);
|
|
153
|
+
}
|
|
154
|
+
yield* elIfText('trp:CalculationMode', 'FasterTime');
|
|
155
|
+
yield* elIfText('trp:ElevationMode', 'Standard');
|
|
156
|
+
yield* end();
|
|
157
|
+
} else {
|
|
158
|
+
shapingPoint = true;
|
|
159
|
+
//- The <trp:ShapingPoint> is equivalent to Furkot Pass-through Points.
|
|
160
|
+
//- These points are displayed in the Route point list on the GPS but are not announced during navigation.
|
|
161
|
+
//- There can be up to 124 ShapingPoints between each ViaPoint.
|
|
162
|
+
yield* el('trp:ShapingPoint');
|
|
163
|
+
}
|
|
164
|
+
if (next && next.mode !== undefined) {
|
|
165
|
+
|
|
166
|
+
//- The <vptm:ViaPointTransportationMode> extension tells the devices Trip Planner algorithm
|
|
167
|
+
//- what calculation type to use between this and next point:
|
|
168
|
+
//- Automotive, Motorcycling, Walking, Bicycling, Direct.
|
|
169
|
+
yield* start('vptm:ViaPointTransportationMode');
|
|
170
|
+
yield* elIfText('vptm:TransportationMode', getMode(next.mode));
|
|
171
|
+
yield* end();
|
|
172
|
+
}
|
|
173
|
+
if (ctx.RoutePointExtension) {
|
|
174
|
+
yield* start('gpxx:RoutePointExtension');
|
|
175
|
+
|
|
176
|
+
//- The <gpxx:Subclass> is a special Garmin code for older Garmin devices that do not use
|
|
177
|
+
//- the Trip Planner algorithm. This specific code says to use the above RoutePoint as a waypoint.
|
|
178
|
+
//- Older Garmin devices don't use the Trip Planner algorithm.
|
|
179
|
+
yield* el('gpxx:Subclass', null, '000000000000FFFFFFFFFFFFFFFFFFFFFFFF');
|
|
180
|
+
const expanded = next && next.track;
|
|
181
|
+
|
|
182
|
+
if (expanded) {
|
|
183
|
+
yield* each(expanded, function* (p) {
|
|
184
|
+
let subclass;
|
|
185
|
+
|
|
186
|
+
//- All of the <gpxx:rpt> are equivalent to Furkot Track Points generated between Stops.
|
|
187
|
+
//- These points are not displayed on the GPS or announced during navigation.
|
|
188
|
+
if (next.custom || next.mode === 3) {
|
|
189
|
+
//- This Subclass code denotes a route point that is not on a mapped road (off-road).
|
|
190
|
+
//- There are usually many of these in succession to define the route path
|
|
191
|
+
//- and each off-road point needs to have this Subclass.
|
|
192
|
+
subclass = 'FFFF00000000FFFFFFFF2117000000000000';
|
|
193
|
+
} else if (shapingPoint) {
|
|
194
|
+
shapingPoint = false;
|
|
195
|
+
//- A Subclass other than 000000000000FFFFFFFFFFFFFFFFFFFFFFFF must be added after a ShapingPoint.
|
|
196
|
+
//- Any other ‘valid’ Subclass code works.
|
|
197
|
+
subclass = '0300F2F7C403DD6E00002116000025490404';
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
yield* $gpxxRpt(p, subclass);
|
|
201
|
+
});
|
|
202
|
+
yield* $gpxxRpt(expanded[expanded.length - 1], '000000000000FFFFFFFFFFFFFFFFFFFFFFFF');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
yield* end();
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function getTrkExt({ start, end, elIfText }) {
|
|
211
|
+
return function* (tr) {
|
|
212
|
+
yield* start('gpxx:TrackExtension');
|
|
213
|
+
yield* elIfText('gpxx:DisplayColor', colors[tr.color]);
|
|
214
|
+
yield* end();
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
module.exports = {
|
|
219
|
+
getWptCmt: st => st.notes,
|
|
220
|
+
getWptSym: st => toGarmin[st.sym],
|
|
221
|
+
hasWptExt: st => st.address || st.phone || st.tags?.length,
|
|
222
|
+
getWptExt,
|
|
223
|
+
hasRteExt: () => true,
|
|
224
|
+
getRteExt,
|
|
225
|
+
hasRtePtExt: () => true,
|
|
226
|
+
getRtePtExt,
|
|
227
|
+
hasTrkExt: tr => tr.color,
|
|
228
|
+
getTrkExt,
|
|
229
|
+
schema,
|
|
230
|
+
toGarmin,
|
|
231
|
+
toFurkot,
|
|
232
|
+
colors
|
|
233
|
+
};
|