-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathindex.bs
541 lines (422 loc) · 24.8 KB
/
index.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
<pre class="metadata">
Title: Magnetometer
Level: none
Status: ED
ED: https://w3c.github.io/magnetometer/
Shortname: magnetometer
TR: https://www.w3.org/TR/magnetometer/
Editor: Anssi Kostiainen 41974, Intel Corporation, https://intel.com/
Editor: Rijubrata Bhaumik 80407, Intel Corporation, https://intel.com/
Group: dap
Abstract:
This specification defines a concrete sensor interface to measure magnetic
field in the X, Y and Z axis.
Version History: https://github.com/w3c/magnetometer/commits/main/index.bs
Issue Tracking: Magnetometer Issues Repository https://github.com/w3c/magnetometer/issues
Indent: 2
Repository: w3c/magnetometer
Markup Shorthands: markdown on
Inline Github Issues: true
!Test Suite: <a href="https://github.com/web-platform-tests/wpt/tree/main/magnetometer">web-platform-tests on GitHub</a>
Boilerplate: omit issues-index, omit conformance, repository-issue-tracking no
Status Text:
This specification is looking for developer feedback and high value use cases. Please provide your feedback via <a href="https://github.com/w3c/magnetometer/issues/59">GitHub</a>.
This document is maintained and updated at any time. Some parts of this document are work in progress.
</pre>
<pre class="anchors">
urlPrefix: https://w3c.github.io/sensors/; spec: GENERIC-SENSOR
type: dfn
text: high-level
text: sensor
text: latest reading
text: default sensor
text: construct a sensor object; url: construct-sensor-object
text: initialize a sensor object; url: initialize-a-sensor-object
text: sensor type
text: mitigation strategies; url: mitigation-strategies
text: local coordinate system
text: keystroke monitoring; url: keystroke-monitoring
text: sensor permission name; url: sensor-permission-names
text: supported sensor options
urlPrefix: https://w3c.github.io/accelerometer/; spec: ACCELEROMETER
type: dfn
text: device coordinate system
text: screen coordinate system
urlPrefix: https://w3c.github.io/motion-sensors/; spec: MOTIONSENSORS
type: dfn
text: Absolute Orientation Sensor; url: absolute-orientation
</pre>
<pre class=biblio>
{
"MAGITACT": {
"authors": [
"Hamed Ketabdar, Kamer Ali Yüksel, Mehran Roshandel"
],
"id": "MAGITACT",
"href": "https://dl.acm.org/doi/10.1145/1719970.1720048",
"title": "Magitact",
"status": "Informational",
"publisher": "ACM"
},
"VRBUTTON": {
"authors": [
"Boris Smus"
],
"id": "VRBUTTON",
"href": "https://bugs.chromium.org/p/chromium/issues/detail?id=445926",
"title": "Magnetic input for Google cardboard",
"status": "Informational",
"publisher": "Unknown"
},
"MAGINDOORPOS": {
"authors": [
"Janne Haverinen, Anssi Kemppainen"
],
"id": "MAGINDOORPOS",
"href": "https://doi.org/10.1016%2Fj.robot.2009.07.018",
"title": "Global indoor self-localization based on the ambient magnetic field",
"status": "Informational",
"publisher": "Robotics and Autonomous Systems"
},
"MAGSPY": {
"authors": [
"Nikolay Matyunin, Yujue Wang, Tolga Arul, Kristian Kullmann, Jakub Szefer, Stefan Katzenbeisser"
],
"id": "MAGSPY",
"href": "https://dl.acm.org/doi/abs/10.1145/3338498.3358650",
"title": "MagneticSpy: Exploiting Magnetometer in Mobile Devices for Website and Application Fingerprinting",
"status": "Informational",
"publisher": "WPES'19: Proceedings of the 18th ACM Workshop on Privacy in the Electronic Society"
}
}
</pre>
<pre class="link-defaults">
spec:infra;
type:dfn;
text:list
spec:generic-sensor-1;
type:enum-value;
text:"activated"
</pre>
Introduction {#intro}
============
Magnetometer extends the Generic Sensor API [[GENERIC-SENSOR]]
to provide information about the <a>magnetic field</a>
as detected by the device's primary magnetometer sensor.
The magnetometer sensor measures the <a>magnetic field</a> for all three
physical axes (x, y, z) in μT (micro Tesla).
This specification defines two new interfaces:
- {{Magnetometer}} that reports <a>calibrated magnetic field</a> values, and
- {{UncalibratedMagnetometer}} that reports <a>uncalibrated magnetic field</a> values.
The <dfn>magnetic field</dfn> is a field that exerts magnetic force on magnetometer sensor
due to the magnetic effect generated by electric currents, magnetic materials or Earth's magnetic
force that is attributed to the combined effects of the planetary rotation and the movement of molten
iron in the Earth's core.
<dfn>Hard iron distortion</dfn> is created by objects
that produce a <a>magnetic field</a>, such as magnetized iron.
<dfn>Soft iron distortion</dfn> stretches or distorts the
<a>magnetic field</a> and is caused by metals such as
nickel and iron.
The <dfn>calibrated magnetic field</dfn> is a <a>magnetic field</a> with <a>hard iron distortion</a> and <a>soft iron distortion</a>
correction applied.
The <dfn>uncalibrated magnetic field</dfn> is the
<a>magnetic field</a> without <a>hard iron distortion</a>
correction and with <a>soft iron distortion</a> correction applied,
and as such reports changes in the <a>magnetic field</a>
caused by magnetized objects moving near the magnetometer.
Examples {#examples}
========
<div class="example">
<pre highlight="js">
let sensor = new Magnetometer();
sensor.start();
sensor.onreading = () => {
console.log("Magnetic field along the X-axis " + sensor.x);
console.log("Magnetic field along the Y-axis " + sensor.y);
console.log("Magnetic field along the Z-axis " + sensor.z);
};
sensor.onerror = event => console.log(event.error.name, event.error.message);
</pre>
</div>
Security and Privacy Considerations {#security-and-privacy}
===================================
Magnetometer provides information about magnetic field, and in theory, can expose location of a
user. For example, attack vector could be pre-magnetized surface in a particular location, or
mapping between location and constant magnetic field disturbances caused by the building. Due
to non-uniform strength of the Earth’s magnetic field, another attack vector could be exposure or
validation of the user's location. For example, if the end user is connected through VPN, magnetic
field associated with geo IP information can be compared with magnetometer readings at real
location, therefore, tell whether user is using VPN or not. Implementors should be aware of potential risk of
side-channel leaks via the correlations of magnetic field strength and other aspects such as CPU execution,
which under certain circumstances may potentially leak the information about used applications or websites visited in other tabs. [[MAGSPY]]
Uncalibrated magnetometer readings could be affected by magnetized objects nearby, such as jewelry,
thereby exposing information that might be used for [=keystroke monitoring=].
To mitigate these specific threats, user agents should
use one or both of the following mitigation strategies:
- <a>limit maximum sampling frequency</a>
- <a>reduce accuracy</a> of sensor readings
These mitigation strategies complement the [=mitigation strategies|generic mitigations=] defined in
the Generic Sensor API [[!GENERIC-SENSOR]].
Permissions Policy integration {#permissions-policy-integration}
==============================
This specification utilizes the [=policy-controlled feature=] identified by the string "<code><a permission>magnetometer</a></code>" defined in [[DEVICE-ORIENTATION]].
Model {#model}
=====
The <dfn id="magnetometer-sensor-type">Magnetometer</dfn> <a>sensor type</a> has the following associated data:
: [=Extension sensor interface=]
:: {{Magnetometer}}
: [=Sensor permission names=]
:: "<code><a permission>magnetometer</a></code>"
: [=Sensor feature names=]
:: <a permission>"magnetometer"</a>
: [=powerful feature/Permission revocation algorithm=]
:: Invoke the [=generic sensor permission revocation algorithm=] with "<code><a permission>magnetometer</a></code>".
: [=Virtual sensor type=]
:: "<code><a data-lt="magnetometer virtual sensor type">magnetometer</a></code>"
The [=latest reading=] for a {{Sensor}} whose [=sensor type=] is [=Magnetometer=] must include:
- Three [=map/entries=] whose [=map/keys=] are "x", "y", "z" and whose [=map/values=] contain <a>magnetic field</a> about the corresponding axes.
The <dfn id="uncalibrated-magnetometer-sensor-type">Uncalibrated Magnetometer</dfn> <a>sensor type</a> has the following associated data:
: [=Extension sensor interface=]
:: {{UncalibratedMagnetometer}}
: [=Sensor permission names=]
:: "<code><a permission>magnetometer</a></code>"
: [=Sensor feature names=]
:: <a permission>"magnetometer"</a>
: [=powerful feature/Permission revocation algorithm=]
:: Invoke the [=generic sensor permission revocation algorithm=] with "<code><a permission>magnetometer</a></code>".
: [=Virtual sensor type=]
:: "<code><dfn data-lt="uncalibrated-magnetometer virtual sensor type">uncalibrated-magnetometer</dfn></code>"
The [=latest reading=] for a {{Sensor}} whose [=sensor type=] is [=Uncalibrated Magnetometer=] must include:
- Three [=map/entries=] whose [=map/keys=] are "x", "y", "z" and whose [=map/values=] contain <a>uncalibrated magnetic field</a> around the 3 different axes.
- Three additional [=map/entries=] whose [=map/keys=] are "xBias", "yBias", "zBias" and whose [=map/values=] contain the <a>hard iron distortion</a> correction around the 3 different axes.
The sign of the <a>magnetic field</a> values must be according to the
right-hand convention in a [=local coordinate system=] (see figure below).
<img src="images/magnetometer_coordinate_system.svg" onerror="if (/\.svg$/.test(this.src)) this.src='images/magnetometer_coordinate_system.png'" style="display: block;margin: auto;" alt="Magnetometer coordinate system.">
Reference Frame {#reference-frame}
----------------
The [=local coordinate system=] represents the reference frame for the
{{Magnetometer}} and the {{UncalibratedMagnetometer}} [=sensor readings|readings=].
It can be either the [=device coordinate system=] or the [=screen coordinate system=].
API {#api}
===
The Magnetometer Interface {#magnetometer-interface}
--------------------------------
<pre class="idl">
[SecureContext,
Exposed=Window]
interface Magnetometer : Sensor {
constructor(optional MagnetometerSensorOptions sensorOptions = {});
readonly attribute double? x;
readonly attribute double? y;
readonly attribute double? z;
};
enum MagnetometerLocalCoordinateSystem { "device", "screen" };
dictionary MagnetometerSensorOptions : SensorOptions {
MagnetometerLocalCoordinateSystem referenceFrame = "device";
};
</pre>
<div algorithm>
The <dfn constructor for="Magnetometer" lt="Magnetometer(sensorOptions)"><code>new Magnetometer(|sensorOptions|)</code></dfn> constructor steps are to invoke the [=construct a magnetometer object=] abstract operation with [=this=] and |sensorOptions|.
</div>
[=Supported sensor options=] for {{Magnetometer}} are "frequency" and "referenceFrame".
### Magnetometer.x ### {#magnetometer-x}
The {{Magnetometer/x!!attribute}} attribute of the {{Magnetometer}}
interface represents the <a>magnetic field</a> around X-axis.
In other words, this attribute returns the result of invoking
[=get value from latest reading=] with `this` and "x" as arguments.
### Magnetometer.y ### {#magnetometer-y}
The {{Magnetometer/y!!attribute}} attribute of the {{Magnetometer}}
interface represents the <a>magnetic field</a> around Y-axis.
In other words, this attribute returns the result of invoking
[=get value from latest reading=] with `this` and "y" as arguments.
### Magnetometer.z ### {#magnetometer-z}
The {{Magnetometer/z!!attribute}} attribute of the {{Magnetometer}}
interface represents the <a>magnetic field</a> around Z-axis.
In other words, this attribute returns the result of invoking
[=get value from latest reading=] with `this` and "z" as arguments.
The UncalibratedMagnetometer Interface {#uncalibrated-magnetometer-interface}
--------------------------------
<pre class="idl">
[SecureContext,
Exposed=Window]
interface UncalibratedMagnetometer : Sensor {
constructor(optional MagnetometerSensorOptions sensorOptions = {});
readonly attribute double? x;
readonly attribute double? y;
readonly attribute double? z;
readonly attribute double? xBias;
readonly attribute double? yBias;
readonly attribute double? zBias;
};
</pre>
<div algorithm>
The <dfn constructor for="UncalibratedMagnetometer" lt="UncalibratedMagnetometer(sensorOptions)"><code>new UncalibratedMagnetometer(|sensorOptions|)</code></dfn> constructor steps are to invoke the [=construct a magnetometer object=] abstract operation with [=this=] and |sensorOptions|.
</div>
[=Supported sensor options=] for {{UncalibratedMagnetometer}} are "frequency" and "referenceFrame".
### UncalibratedMagnetometer.x ### {#uncalibrated-magnetometer-x}
The {{UncalibratedMagnetometer/x!!attribute}} attribute of the {{UncalibratedMagnetometer}}
interface represents the <a>uncalibrated magnetic field</a> around X-axis.
In other words, this attribute returns the result of invoking
[=get value from latest reading=] with `this` and "x" as arguments.
### UncalibratedMagnetometer.y ### {#uncalibrated-magnetometer-y}
The {{UncalibratedMagnetometer/y!!attribute}} attribute of the {{UncalibratedMagnetometer}}
interface represents the <a>uncalibrated magnetic field</a> around Y-axis.
In other words, this attribute returns the result of invoking
[=get value from latest reading=] with `this` and "y" as arguments.
### UncalibratedMagnetometer.z ### {#uncalibrated-magnetometer-z}
The {{UncalibratedMagnetometer/z!!attribute}} attribute of the {{UncalibratedMagnetometer}}
interface represents the <a>uncalibrated magnetic field</a> around Z-axis.
In other words, this attribute returns the result of invoking
[=get value from latest reading=] with `this` and "z" as arguments.
### UncalibratedMagnetometer.xBias ### {#uncalibrated-magnetometer-xBias}
The {{UncalibratedMagnetometer/xBias!!attribute}} attribute of the {{UncalibratedMagnetometer}}
interface represents the <a>hard iron distortion</a> correction around X-axis.
In other words, this attribute returns the result of invoking
[=get value from latest reading=] with `this` and "xBias" as arguments.
### UncalibratedMagnetometer.yBias ### {#uncalibrated-magnetometer-yBias}
The {{UncalibratedMagnetometer/yBias!!attribute}} attribute of the {{UncalibratedMagnetometer}}
interface represents the <a>hard iron distortion</a> correction around Y-axis.
In other words, this attribute returns the result of invoking
[=get value from latest reading=] with `this` and "yBias" as arguments.
### UncalibratedMagnetometer.zBias ### {#uncalibrated-magnetometer-zBias}
The {{UncalibratedMagnetometer/zBias!!attribute}} attribute of the {{UncalibratedMagnetometer}}
interface represents the <a>hard iron distortion</a> correction around Z-axis.
In other words, this attribute returns the result of invoking
[=get value from latest reading=] with `this` and "zBias" as arguments.
Abstract Operations {#abstract-opertaions}
==============
<h3 dfn>Construct a magnetometer object</h3>
<div algorithm="construct a magnetometer object">
: input
:: |object|, a {{Magnetometer}} or {{UncalibratedMagnetometer}} object
:: |options|, a {{MagnetometerSensorOptions}} object.
1. Let |allowed| be the result of invoking [=check sensor policy-controlled features=]
with |object|'s [=sensor type=].
1. If |allowed| is false, then:
1. [=Throw=] a {{SecurityError}} {{DOMException}}.
1. Invoke [=initialize a sensor object=] with |object| and |options|.
1. If |options|.{{referenceFrame!!dict-member}} is "screen", then:
1. Set |object|'s [=local coordinate system=] to the [=screen coordinate system=].
1. Otherwise, define |object|'s [=local coordinate system=] to the [=device coordinate system=].
</div>
Automation {#automation}
==========
This section extends [[GENERIC-SENSOR#automation]] by providing [=Magnetometer=]-specific virtual sensor metadata.
Magnetometer automation {#magnetometer-automation}
-----------------------
The [=per-type virtual sensor metadata=] [=map=] must have the following [=map/entry=]:
: [=map/key=]
:: "<code>[=magnetometer virtual sensor type|magnetometer=]</code>"
: [=map/value=]
:: A [=virtual sensor metadata=] whose [=virtual sensor metadata/reading parsing algorithm=] is [=parse XYZ reading=].
Uncalibrated Magnetometer automation {#uncalibrated-magnetometer-automation}
------------------------------------
The [=per-type virtual sensor metadata=] [=map=] must have the following [=map/entry=]:
: [=map/key=]
:: "<code>[=uncalibrated-magnetometer virtual sensor type|uncalibrated-magnetometer=]</code>"
: [=map/value=]
:: A [=virtual sensor metadata=] whose [=virtual sensor metadata/reading parsing algorithm=] is the [=uncalibrated magnetometer reading parsing algorithm=].
<h4 dfn>Uncalibrated Magnetometer reading parsing algorithm</h4>
<div algorithm="uncalibrated magnetometer reading parsing algorithm">
: input
:: |parameters|, a JSON {{Object}}
: output
:: A [=sensor reading=] or **undefined**
1. Let |reading| be the result of [=parse XYZ reading=] with |parameters|.
1. If |reading| is **undefined**.
1. Return **undefined**.
1. Let |keys| be the [=/list=] « "`xBias`", "`yBias`", "`zBias`" ».
1. [=list/For each=] |key| of |keys|
1. Let |value| be the result of invoking [=parse single-value number reading=] with |parameters| and |key|.
1. If |value| is **undefined**.
1. Return **undefined**.
1. [=map/Set=] |reading|[|key|] to |value|[|key|].
1. Return |reading|.
</div>
Limitations of Magnetometer Sensors {#limitations-magnetometer}
==============
<em>This section is non-normative</em>.
The direction and magnitude of the Earth’s field changes with location, latitude in particular. For example,
the magnitude is lowest near the equator and highest near the poles.
Some hard-iron interference, meaning presence of permanent magnets (e.g. magnets in the speaker of a phone) in the vicinity of the sensor
also affects the accuracy of the reading.
Presence of electronic items, laptops, batteries, etc also contribute to the soft iron interference.
Flight Mode option in mobile phones might help in decreasing the electro magnetic interference.
In addition to the above spatial variations of the <a>magnetic field</a>, time based variations,
like solar winds or magnetic storms, also distort the magnetosphere or external magnetic field of the Earth.
Use Cases and Requirements {#usecases-and-requirements}
===================
<em>This section is non-normative</em>.
Magnetometers can be used for a variety of use-cases, for example:
- Sensor fusion. A common use-case for magnetometers is sensor fusion in order to generate an <a>Absolute Orientation Sensor</a> [[MOTION-SENSORS]] which is stationary to the Earth plane, or a compass, which is basically the former with corrections to the declination depending on geolocation position, such that it points to the true north. Calculating compass heading as detailed in [[#compass]].
- Virtual Reality and Augmented Reality. Magnetometer can be used to implement input using magnetic button for VR enclosures [[VRBUTTON]]. Head-mount tracking systems for VR and AR can use magnetometer data to help in calibration of gyroscope readings and align yaw readings with the magnetic north.
- Gesture recognition. Various interactions like writing, signing and playing an instrument can also be enabled using a magnet like a rod, pen or a ring [[MAGITACT]].
The user makes coarse gestures in the 3D space around the device using the magnet. Movement of the magnet affects the magnetic field sensed by the compass sensor integrated in the device.
The temporal pattern of the gesture can be used as a basis for sending different interaction commands to the mobile device. Zooming, turning pages, accepting/rejecting calls, clicking items
are some of the use cases.
- Indoor navigation. Navigation systems can use magnetometer data on mobile devices [[MAGINDOORPOS]] to detect the magnetic field inside a building. With sufficient local variability, the anomalies can be utilized in self-localization. Use cases for indoor navigation include, for example, proximity advertising, way finding in malls or airports, and geofencing.
- Metal detection. Magnetometers can be used by utility applications to detect the presence of metal nearby, e.g. finding inclusions hidden within objects.
<div class="note">
Requirements with respect to data coarseness and sampling frequency can vary depending on the use case at hand. For example, metal detection or input using magnetic button can likely be implemented with coarser data and using lower sampling frequency compared to gesture recognition, indoor navigation, or VR and AR use cases. In sensor fusion use cases, the sampling frequency that yeilds optimal results is dependent on e.g. sensor fusion algorithm and characteristics of other motion sensors involved.
</div>
Compass Heading Using Magnetometers {#compass}
======================
<em>This section is non-normative</em>.
Compasses, instruments that align themselves with the magnetic poles of the Earth, have been used in navigation for centuries.
The Earth’s rotational axis defines the geographic north and south poles that we use for
map references. It turns out that there is a discrepancy of around 11.5 degrees (around 1000 miles) between the geographic poles and the
magnetic poles. <a>Declination angle</a> is applied to the magnetic direction to correct for this situation.
If the device is always level to the Earth’s surface, compass heading can be determined by using just the
{{Magnetometer/x!!attribute}} and {{Magnetometer/y!!attribute}} component of the Earth’s magnetic field, that
is, the directions planar with the Earth’s surface.
To determine geographic north (or true north) heading, add the appropriate <a>declination angle</a>.
<dfn>Magnetic declination</dfn> or <dfn>declination angle</dfn> is the angle on the horizontal plane between magnetic north and the true north and depends on the position on the Earth's surface, and changes over time.
By convention, declination is positive when magnetic north is east of true north, and negative when it is to the west. You can get real time value for <a>magnetic declination</a> e.g. using the <a href="https://www.ngdc.noaa.gov/geomag/calculators/magcalc.shtml">Magnetic declination calculator</a>
provided by the National Oceanic and Atmospheric Administration (NOAA).
The magnetic north is calculated as follows:
<div class="example">
<pre highlight="js">
let sensor = new Magnetometer();
sensor.start();
let heading = Math.atan2(sensor.y, sensor.x) * (180 / Math.PI);
console.log('Heading in degrees: ' + heading);
</pre>
</div>
The geographic north at a given latitude and longitude can be calculated as follows:
<div class="example">
<xmp highlight="js">
// Get the latitude and longitude, omitted for brevity here.
let latitude = 0, longitude = 0;
// Get the magnetic declination at the given latitude and longitude.
fetch('https://www.ngdc.noaa.gov/geomag-web/calculators/calculateDeclination' +
'?lat1=' + latitude + '&lon1=' + longitude + '&resultFormat=csv')
.then(response => response.text()).then(text => {
let declination = parseFloat(text.replace(/^#.*$/gm, '').trim().split(',')[4]);
// Compensate for the magnetic declination to get the geographic north.
console.log('True heading in degrees: ' + (heading + declination));
});
</xmp>
</div>
Note: If the device is not level to the Earth’s surface, a developer needs
to apply various tilt compensation techniques for which she needs a 3-axis
accelerometer. Data from the orientation sensor, which is a fusion of the
accelerometer and magnetometer sensors, is required to implement this
particular use case.
Acknowledgements {#acknowledgements}
================
Tobie Langel for the work on Generic Sensor API.
Conformance {#conformance}
===========
Conformance requirements are expressed with a combination of
descriptive assertions and RFC 2119 terminology. The key words "MUST",
"MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT",
"RECOMMENDED", "MAY", and "OPTIONAL" in the normative parts of this
document are to be interpreted as described in RFC 2119.
However, for readability, these words do not appear in all uppercase
letters in this specification.
All of the text of this specification is normative except sections
explicitly marked as non-normative, examples, and notes. [[!RFC2119]]
A <dfn>conformant user agent</dfn> must implement all the requirements
listed in this specification that are applicable to user agents.
The IDL fragments in this specification must be interpreted as required for
conforming IDL fragments, as described in the Web IDL specification. [[!WEBIDL]]