spacemap 0.1.3 → 0.1.5

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
@@ -1,7 +1,8 @@
1
1
  # spacemap
2
2
 
3
3
  The map of the Solar System from [spacemap.co](https://spacemap.co), on your
4
- website! There are flat maps too, and 360 panoramas from the surface.
4
+ website! There are flat maps too, 360 panoramas from the surface, and a
5
+ diagram of the whole system to pick a body from.
5
6
 
6
7
  Distances are kilometres and angles are degrees throughout. Objects are named
7
8
  by their export id — `naif-399` for Earth, `spkid-20000004` for Vesta,
@@ -43,7 +44,7 @@ your page:
43
44
  ```html
44
45
  <div id="map" style="height: 500px"></div>
45
46
  <script type="module">
46
- import { createMap } from 'https://cdn.jsdelivr.net/npm/spacemap@0.1.3/dist/spacemap.js';
47
+ import { createMap } from 'https://cdn.jsdelivr.net/npm/spacemap@0.1.5/dist/spacemap.js';
47
48
  const map = await createMap({ container: '#map' });
48
49
  </script>
49
50
  ```
@@ -140,6 +141,31 @@ map.clock.setDate(new Date('2035-06-01'));
140
141
  map.clock.now();
141
142
  ```
142
143
 
144
+ ### Measuring
145
+
146
+ Some things can be read off the scene instead of drawn on it. All take the
147
+ bodies where the last frame put them, so after `setDate` wait for a `frame`
148
+ before asking.
149
+
150
+ ```js
151
+ // Kilometres between two anchors: centres, places on a surface, or one of each.
152
+ map.distanceKm({ body: 'naif-499' }, { body: 'naif-401' });
153
+ map.distanceKm({ body: 'naif-499', latitude: 18.4, longitude: 77.5 }, { body: 'naif-401' });
154
+
155
+ // The same with its direction kept, on ecliptic axes: [x, y, z] kilometres.
156
+ map.offsetKm({ body: 'naif-499' }, { body: 'naif-401' });
157
+
158
+ // Where the Sun is overhead: the middle of the lit half.
159
+ map.getSubsolarPoint('naif-499'); // { lon, lat }
160
+ ```
161
+
162
+ Any of them is null while a body it names is not loaded, or is nowhere at the
163
+ map's date: a moon before its discovery, a craft outside its mission. The
164
+ sub-solar point is given in the frame a surface anchor is placed in, so an
165
+ anchor there is on the lit side even on a body whose spin is not measured. It
166
+ is null as well until the map has read how the body spins, which it does once
167
+ the camera is on the body or its system.
168
+
143
169
  ### Drawing on it
144
170
 
145
171
  Everything you draw is put somewhere by an **anchor**, and the anchor is what
@@ -209,6 +235,10 @@ an area drawn as a fill alone. The flat map says the same things with the same
209
235
  words — its version is `FlatShapeStyle`, named apart because a page can hold
210
236
  both maps at once — so a drawing described once can be handed to either.
211
237
 
238
+ A line, in space or on a surface, takes `dash` as the flat map's does: `'4 3'`
239
+ is four pixels drawn and three left out, counted on screen like the width, so
240
+ the dashes read the same from any distance.
241
+
212
242
  Two rules fall out of the scene rather than out of taste. Widths are pixels
213
243
  because the map spans metres to astronomical units, and a line a kilometre wide
214
244
  is a wall from low orbit and nothing at all from the next planet out. And a body
@@ -440,6 +470,22 @@ flat.isLayerVisible('clouds');
440
470
  flat.on('layerschange', (layers) => redraw(layers));
441
471
  ```
442
472
 
473
+ ### Bodies kept in sight
474
+
475
+ The map decides what to name by how far the camera is: a planet's halo and
476
+ orbit drop out once its whole orbit is a few pixels across, and a name gives way
477
+ to a bigger neighbour's. `setPinnedBodies` takes that decision for the bodies a
478
+ page is about:
479
+
480
+ ```js
481
+ map.setPinnedBodies(['naif-499', 'spkid-20000433']); // Mars and Eros, from anywhere
482
+ map.setPinnedBodies([]); // back to the map's own judgement
483
+ ```
484
+
485
+ A pinned body keeps its halo, name and orbit from however far, and through a
486
+ hidden layer. A moon is the exception: it is only drawn inside the system the
487
+ camera is in, so pin its planet to mark it from outside.
488
+
443
489
  ## The flat map
444
490
 
445
491
  One body's surface, drawn flat, with layers you can switch and drawings of your
@@ -471,14 +517,29 @@ view exists — what a page picking one for the reader needs, since `createPanor
471
517
  opens the body's first unless told which:
472
518
 
473
519
  ```js
474
- import { fetchPanoramaIndex, fetchPanoramas } from 'spacemap';
520
+ import { fetchPanoramaIndex, fetchPanoramas, isViewable } from 'spacemap';
475
521
 
476
522
  await fetchPanoramaIndex(); // every body with coverage, and the missions on it
477
- const entries = await fetchPanoramas('naif-499'); // every panorama on Mars
523
+ const entries = (await fetchPanoramas('naif-499')).filter(isViewable); // every one that opens
478
524
  const pick = entries[(Math.random() * entries.length) | 0];
479
525
  const view = await createPanorama({ container: '#panorama', body: 'naif-499', at: pick.id });
480
526
  ```
481
527
 
528
+ The list is every stop on every traverse, and not every stop has a sphere this
529
+ page may open: some are places the archive withheld the imagery of, and some
530
+ are under a licence the page has not accepted (`includeNonCommercial`).
531
+ `isViewable` says which open; the view skips the rest itself.
532
+
533
+ Both read the page's own settings, which a `create…` call applies. A page that
534
+ reads the list before it has made anything applies them itself first, or the
535
+ list comes from the published export and under the default licence:
536
+
537
+ ```js
538
+ import { configureHost } from 'spacemap';
539
+
540
+ configureHost({ textures: 'non-commercial' }); // what `includeNonCommercial` sets
541
+ ```
542
+
482
543
  ```js
483
544
  const view = await createPanorama({
484
545
  container: '#panorama',
@@ -512,6 +573,113 @@ view.setLimits({ heading: [300, 60], fov: [60, 60] }); // ±60° of north, no zo
512
573
  view.setLimits({}); // free again
513
574
  ```
514
575
 
576
+ ## The system map
577
+
578
+ The Solar System as a diagram to pick from: the Sun at the left edge, every
579
+ body along a log distance axis at its true relative size, moons stacked over
580
+ their planet, the belts as bands. It is what spacemap.co opens its Solar System
581
+ and planetary system pages with.
582
+
583
+ ```js
584
+ import { createSystemMap } from 'spacemap';
585
+
586
+ const picker = await createSystemMap({ container: '#picker' });
587
+ picker.on('select', (target) => console.log(target.kind, target.name));
588
+ ```
589
+
590
+ It is as wide as its container and three times as wide as it is tall, and it
591
+ reads at any width from a corner panel up. It draws from the export's own
592
+ figures and no imagery, so it is the one map with no credit line.
593
+
594
+ There are three views:
595
+
596
+ ```js
597
+ await picker.setView({ kind: 'solar-system' });
598
+ await picker.setView({ kind: 'system', id: 'naif-699' }); // Saturn and its moons
599
+ await picker.setView({ kind: 'zone', zone: 'inner' }); // small bodies inside Jupiter's orbit
600
+ await picker.setView({ kind: 'zone', zone: 'outer' }); // and from it outward, the trojans included
601
+ ```
602
+
603
+ A `system` is named by its primary and measured in the primary's radii. A body
604
+ with no moons has no system map, and asking for one rejects, leaving the map as
605
+ it was.
606
+
607
+ **A click reports what was picked and goes nowhere.** Walking down into a
608
+ system and back up is the page's own doing, which is what lets it keep a back
609
+ button, a breadcrumb or a URL of its own:
610
+
611
+ ```js
612
+ picker.on('select', (target) => {
613
+ if (target.kind === 'system') picker.setView({ kind: 'system', id: target.id });
614
+ else if (target.kind === 'zone') picker.setView({ kind: 'zone', zone: target.zone });
615
+ else choose(target.id); // a body
616
+ });
617
+ ```
618
+
619
+ `getView()` says which view is up and `getTargets()` lists everything a click
620
+ on it can pick, for a page that wants a list beside the picture. `viewchange`
621
+ fires once a new view is drawn, and `error` when one could not be.
622
+
623
+ Two options decide what a click on the Solar System means:
624
+
625
+ ```js
626
+ createSystemMap({ container: '#picker', grouping: 'systems', zones: 'inner-outer' });
627
+ ```
628
+
629
+ - `grouping: 'systems'` makes a primary and the moons stacked on it one target,
630
+ a `system` — one click for "somewhere round Saturn". A primary with no moons
631
+ drawn stays a `body`. The default, `'bodies'`, leaves the dot and its stack a
632
+ target each.
633
+ - `zones: 'inner-outer'` turns the two belts into the doors of the two zones of
634
+ small bodies, labelled as such. The default, `'belts'`, leaves them the
635
+ scenery they are.
636
+
637
+ A map that offers part of the catalogue names it, and everything else goes
638
+ undrawn in every view:
639
+
640
+ ```js
641
+ const picker = await createSystemMap({
642
+ container: '#picker',
643
+ bodies: ['naif-499', 'naif-401', 'naif-602', 'spkid-20101955'],
644
+ names: { 'naif-602': 'Encelade' }
645
+ });
646
+ await picker.setBodies(null); // everything again, once redrawn
647
+ ```
648
+
649
+ A primary left out is still drawn while a moon of it is in, as the thing the
650
+ moon is found by; it is then not a target itself. `names` goes over the
651
+ export's own names, and is worth filling in for a small moon: the export names
652
+ a system's twenty most notable in a system view and the rest by id.
653
+
654
+ A zone shows the dwarf planets and large asteroids the Solar System view has,
655
+ and every other small body `bodies` names — a comet, a near-Earth asteroid, a
656
+ moon of one, which rides over its parent. The map has to learn where each of
657
+ those is, and reading that from the export costs a few hundred kilobytes a
658
+ body. A page that already knows says so instead, and nothing is read:
659
+
660
+ ```js
661
+ createSystemMap({
662
+ container: '#picker',
663
+ view: { kind: 'zone', zone: 'inner' },
664
+ bodies: ['spkid-20101955', 'spkid-20065803', 'spkid-120065803'],
665
+ places: [
666
+ { id: 'spkid-20101955', name: 'Bennu', aAu: 1.126, tiltDeg: 6.03, radiusKm: 0.245 },
667
+ { id: 'spkid-20065803', name: 'Didymos', aAu: 1.643, tiltDeg: 3.41, radiusKm: 0.39 },
668
+ { id: 'spkid-120065803', name: 'Dimorphos', moon: true, parent: 'spkid-20065803' }
669
+ ]
670
+ });
671
+ ```
672
+
673
+ The colours are custom properties, set on the container or anything above it:
674
+ `--sm-system-map-background`, `--sm-system-map-ink` for the axis and the muted
675
+ band, `--sm-system-map-sky` and `--sm-system-map-amber` for the other two bands
676
+ with a `-label` of each, `--sm-system-map-tip-background` and
677
+ `--sm-system-map-tip-ink` for the hover readout, and `--sm-system-map-radius`
678
+ for the corners. The words it writes itself are in `messages`, under
679
+ `system_map_*`, `planetary_system_*`, `tab_rings` and
680
+ `unit_symbol_astronomical_unit`. Kilometres are written by the browser, in the
681
+ `locale`'s own form.
682
+
515
683
  ## Restricting the map
516
684
 
517
685
  Both maps take restrictions on what the reader may do. Each gesture is a
@@ -619,7 +787,7 @@ this document describes: `flyTo` and `jumpTo`, `getLayers` and
619
787
 
620
788
  ## Where the data comes from
621
789
 
622
- Both maps read the published export. `dataUrl` and `imagesUrl` point them
790
+ Every map reads the published export. `dataUrl` and `imagesUrl` point them
623
791
  somewhere else — your own mirror, or a local copy while you develop. They are
624
792
  page-wide: the last map created sets them, and data already fetched keeps the
625
793
  origin it came from.