archaeopteryx 3.24.0 → 3.25.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/README.md +46 -22
- package/archaeopteryx.d.ts +12 -4
- package/archaeopteryx.js +96 -136
- package/forester.js +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -64,23 +64,32 @@ Archaeopteryx.js has the following dependencies:
|
|
|
64
64
|
* d3.js (version 7): https://www.npmjs.com/package/d3
|
|
65
65
|
* sax.js (1.6.1): https://www.npmjs.com/package/sax/v/1.6.1
|
|
66
66
|
|
|
67
|
-
For **raster PNG export** (optional — the PNG entry
|
|
68
|
-
|
|
69
|
-
* canvg (4.x): https://www.npmjs.com/package/canvg
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
67
|
+
For **raster PNG export** (optional — the PNG entry, the Copy PNG button and
|
|
68
|
+
the PNG-scale row appear only when `window.Canvg` is present):
|
|
69
|
+
* canvg (4.x): https://www.npmjs.com/package/canvg. **Load it before
|
|
70
|
+
`launch()` is called:** the Download menu looks for it at click time, but
|
|
71
|
+
the Copy PNG button and the PNG-scale row are built with the control
|
|
72
|
+
panel at launch, so a page that provides it later gets a PNG entry and
|
|
73
|
+
nothing else. canvg publishes ES modules only (no classic-script global
|
|
74
|
+
build); this repository ships two ready-made files:
|
|
75
|
+
* `docs/lib/canvg.global.js` — a classic-script build for a plain
|
|
76
|
+
`<script src="canvg.global.js"></script>`, or for one more file in a
|
|
77
|
+
site's concatenated bundle; it defines `window.Canvg` itself. This is
|
|
78
|
+
what the demo pages use. (Generated from `canvg.js` by
|
|
79
|
+
`test/make_canvg_global.js`; a unit test keeps the two in step.)
|
|
80
|
+
* `docs/lib/canvg.js` — the self-contained ES module build (npm's
|
|
81
|
+
`canvg@4.0.3` bundled into one file via `esm.sh/canvg@4?bundle`, with
|
|
82
|
+
its one unnecessary Node-environment shim import removed — see the
|
|
83
|
+
file's own header), for a page that prefers a module bridge of its own:
|
|
84
|
+
```html
|
|
85
|
+
<script type="module">
|
|
86
|
+
import {Canvg} from 'http://path/to/canvg.js';
|
|
87
|
+
window.Canvg = Canvg;
|
|
88
|
+
</script>
|
|
89
|
+
```
|
|
90
|
+
A module script runs after the document is parsed, so a page that calls
|
|
91
|
+
`launch()` from an inline script during parsing must use the classic
|
|
92
|
+
build instead.
|
|
84
93
|
|
|
85
94
|
For **vector PDF export** (optional — the PDF entry appears in the Download
|
|
86
95
|
menu only when both are loaded before archaeopteryx.js):
|
|
@@ -1056,8 +1065,8 @@ Both entry points take **exactly** the arguments shown — a call with the old
|
|
|
1056
1065
|
trailing arguments (the separate settings bag, `nodeVisualizations`,
|
|
1057
1066
|
`nodeLabels`, `specialVisualizations`, or the positional Newick parse
|
|
1058
1067
|
options) **throws** with a message saying where each one went: everything now
|
|
1059
|
-
lives in the **one config object** (`
|
|
1060
|
-
`
|
|
1068
|
+
lives in the **one config object** (`internalNumericLabels` is a config key;
|
|
1069
|
+
`nodeLabels` is retired, see the deprecated keys below). `config` itself is optional — `archaeopteryx.launch('#phylogram1',
|
|
1061
1070
|
tree)` works.
|
|
1062
1071
|
|
|
1063
1072
|
`container` is a **CSS selector or the DOM element itself** (frameworks hand
|
|
@@ -1551,14 +1560,13 @@ copy-pastable JSON.
|
|
|
1551
1560
|
| `onViewChange` | `null` | `function (state, encoded)`, called once per settled redraw when the view changed: `state` as `getViewState()` returns it, `encoded` its hash-ready string. The demo pages write it into the URL. |
|
|
1552
1561
|
| `searchBinitialValue` | `null` | Prefill search box B. |
|
|
1553
1562
|
| `enableVisualizations` | `true` | Offer the Color / Shape visualizations (which fields they cover is decided from the tree). |
|
|
1554
|
-
| `initialVisualization` | `null` | The visualization to open with, by its Color-menu name (e.g. `'Host'`; case-insensitive). A name the tree cannot honour logs a console warning and falls back to the automatic choice, so a site-wide value is safe on trees without that field. Default: Archaeopteryx.js picks the most informative field itself. |
|
|
1563
|
+
| `initialVisualization` | `null` | The visualization to open with, by its Color-menu name (e.g. `'Host'`; case-insensitive). A name the tree cannot honour logs a console warning and falls back to the automatic choice, so a site-wide value is safe on trees without that field. A name the tree *can* honour is always honoured, but when it is a field the automatic choice would not have opened with -- more than 20 values, or a value on fewer than two thirds of the tips -- a console warning says so and names the field the viewer would have chosen. Default: Archaeopteryx.js picks the most informative field itself. |
|
|
1555
1564
|
| `visualizationsLegendXpos` | `254` | Legend position, x. |
|
|
1556
1565
|
| `visualizationsLegendYpos` | `30` | Legend position, y. |
|
|
1557
1566
|
| `enableDownloads` | `true` | Offer the download buttons. |
|
|
1558
1567
|
| `pngExportScale` | `4` | The PNG resolution the Download section starts on: 2, 4 or 8 (any other value is snapped to the nearest, with a console warning). |
|
|
1559
1568
|
| `nhExportWriteConfidences` | `true` | Write confidences into exported Newick. |
|
|
1560
1569
|
| `internalNumericLabels` | `'auto'` | Newick / Nexus parsing: how a bare numeric internal label (`)100:0.05`) is read. `'auto'` reads them as confidence values only when *every* internal label looks like support; `'confidence'` reads every numeric label as one, whatever its value; `'label'` keeps them as names. Replaces `nhConfidenceValuesAsInternalNames` (still accepted, with a warning; its `true` maps to `'confidence'`). |
|
|
1561
|
-
| `nodeLabels` | `null` | Custom label-field checkboxes: `{key: {label, description, propertyRef, showButton, selected}}` — each adds a panel checkbox labelling nodes with the named property's value. (Was `launch()`'s sixth positional argument.) |
|
|
1562
1570
|
| `enableSubtreeDeletion` | `true` | Offer node / subtree deletion in the node menu. |
|
|
1563
1571
|
| `enableAccessToDatabases` | `true` | Offer the “Access DB” link in the node menu. |
|
|
1564
1572
|
| `enableManualNodeSelection` | `false` | Add the Select/Deselect entries to the node menu. |
|
|
@@ -1581,7 +1589,7 @@ whatever it names.
|
|
|
1581
1589
|
|
|
1582
1590
|
### Accepted, with a warning
|
|
1583
1591
|
|
|
1584
|
-
|
|
1592
|
+
Five keys are neither current nor removed: they are accepted so an existing
|
|
1585
1593
|
embed keeps working, and warn on the console.
|
|
1586
1594
|
|
|
1587
1595
|
| Key | What happens |
|
|
@@ -1590,6 +1598,7 @@ embed keeps working, and warn on the console.
|
|
|
1590
1598
|
| `nhConfidenceValuesInBrackets` | Retired: ignored. It gated whether `[95]` is read as a confidence, but setting it `false` never reinterpreted the bracket — it *discarded* it, so the option's only effect was to throw support values away. A bracket that is not a number is a Newick comment and was ignored either way, and NHX / BEAST blobs go through a different path. Bracketed values are now always read as confidences. |
|
|
1591
1599
|
| `showTimeAxis` | Translated to `showScaleAxis`, value unchanged: the switch now also draws a distance axis on a tree that is not in time. An explicit `showScaleAxis` always wins. |
|
|
1592
1600
|
| `timeAxisGrid` | Translated to `showScaleGrid`, value unchanged. |
|
|
1601
|
+
| `nodeLabels` | Retired in 3.25.0: ignored, with a warning. The custom label checkboxes it declared predate the Metadata checkbox and its "Metadata fields…" chooser, which offer exactly the fields the tree carries; a fixed site-wide list put checkboxes for absent fields on every tree. `labelProperties` sets the starting fields where the automatic choice is not wanted. Removed in a later release. |
|
|
1593
1602
|
|
|
1594
1603
|
### What replaced the rest
|
|
1595
1604
|
|
|
@@ -1734,6 +1743,21 @@ All 118 of them, alphabetically:
|
|
|
1734
1743
|
| `visualizationsLegendXposOrig` | Internal bookkeeping; set visualizationsLegendXpos. |
|
|
1735
1744
|
| `visualizationsLegendYposOrig` | Internal bookkeeping; set visualizationsLegendYpos. |
|
|
1736
1745
|
|
|
1746
|
+
### Removed from `forester` — calling these throws `TypeError`
|
|
1747
|
+
|
|
1748
|
+
3.0.0 also dropped twelve exports of `forester.js` that the viewer no longer
|
|
1749
|
+
used. They are gone, not stubbed, so a 2.x embedding that calls one fails with
|
|
1750
|
+
`TypeError: forester.<name> is not a function` — inside its own parse step, if
|
|
1751
|
+
that is where it called it.
|
|
1752
|
+
|
|
1753
|
+
| Function | Why, and what to do instead |
|
|
1754
|
+
| --- | --- |
|
|
1755
|
+
| `collectPropertyRefs` | Nothing to call. The viewer derives the Color-by candidates (`forester.visualizationCandidates(tree)`, below) and the label-field chooser's list from the tree itself, and substitutes a readable name property (`genome_name`) for identifier-like tip names on its own. A 2.x embedding that built `nodeLabels` from this function's result should delete that block together with the `nodeLabels` key; `labelProperties` sets the starting label fields where the automatic choice is not wanted. |
|
|
1756
|
+
| `collapse`, `unCollapse` | The subtree-collapse feature was removed; they were its only writers. |
|
|
1757
|
+
| `getChildren` | Only meant something while collapse existed; read `node.children`. |
|
|
1758
|
+
| `findByTaxonomyCode`, `findByTaxonomyScientificName` | Superseded by the search (the panel's search fields). |
|
|
1759
|
+
| `calcAverageTreeHeight`, `calcMaxDepth`, `calcBranchLengthSimpleStatistics`, `removeMaxBranchLength`, `isHasNodeData`, `getOneDistinctTaxonomy` | Never used by the viewer; nothing replaces them. |
|
|
1760
|
+
|
|
1737
1761
|
## The automatic visualization system (developer spec)
|
|
1738
1762
|
|
|
1739
1763
|
This section, together with **Value grouping** below, is written to be
|
package/archaeopteryx.d.ts
CHANGED
|
@@ -29,9 +29,13 @@ export interface Phylogeny extends PhylogenyNode {
|
|
|
29
29
|
|
|
30
30
|
export type Layout = 'rectangular' | 'circular' | 'unrooted';
|
|
31
31
|
|
|
32
|
-
/**
|
|
32
|
+
/** @deprecated Retired in 3.25.0 with `nodeLabels`: accepted with a console
|
|
33
|
+
* warning, no effect; removed in a later release. The Metadata checkbox and
|
|
34
|
+
* its "Metadata fields…" chooser offer the tree's own fields.
|
|
33
35
|
*
|
|
34
|
-
*
|
|
36
|
+
* One custom label-field entry (the config's nodeLabels values).
|
|
37
|
+
*
|
|
38
|
+
* Two modes (3.0.0 to 3.24.0):
|
|
35
39
|
* - a PANEL CHECKBOX needs label, description AND propertyRef set, plus
|
|
36
40
|
* showButton: true -- omit showButton (or any of the three) and no
|
|
37
41
|
* checkbox appears;
|
|
@@ -85,6 +89,10 @@ export interface ArchaeopteryxConfig {
|
|
|
85
89
|
nhConfidenceValuesAsInternalNames?: boolean;
|
|
86
90
|
nhConfidenceValuesInBrackets?: boolean;
|
|
87
91
|
nhExportWriteConfidences?: boolean;
|
|
92
|
+
/** @deprecated Retired in 3.25.0: accepted with a console warning, no
|
|
93
|
+
* effect; removed in a later release. The Metadata checkbox and its
|
|
94
|
+
* "Metadata fields…" chooser offer the tree's own fields; labelProperties
|
|
95
|
+
* sets the starting fields. */
|
|
88
96
|
nodeLabels?: Record<string, NodeLabelSpec> | null;
|
|
89
97
|
/** Called once per settled redraw when the view changed: the state as
|
|
90
98
|
* getViewState() returns it, and its hash-ready string. */
|
|
@@ -176,8 +184,8 @@ export interface ViewState {
|
|
|
176
184
|
shapeBy?: string;
|
|
177
185
|
/** The panel's checked boxes: name, taxonomy, sequence, confidence,
|
|
178
186
|
* madValues, branchLength, external, internal, nodeEvents, branchEvents,
|
|
179
|
-
* supportDots, shortNames, autoHide, visualizations, visualStyles
|
|
180
|
-
* custom:<key>
|
|
187
|
+
* supportDots, shortNames, autoHide, visualizations, visualStyles. (A
|
|
188
|
+
* custom:<key> flag from a 3.24.0 hash is read and ignored.) */
|
|
181
189
|
show?: string[];
|
|
182
190
|
font?: number;
|
|
183
191
|
node?: number;
|
package/archaeopteryx.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
|
-
// v 3.
|
|
23
|
+
// v 3.25.0
|
|
24
24
|
// 2026-09-17
|
|
25
25
|
//
|
|
26
26
|
// Archaeopteryx.js is a software tool for the visualization and
|
|
@@ -103,7 +103,7 @@ function (root, d3, forester, phyloXml) {
|
|
|
103
103
|
// IIFE's own function name -- a plain object says what it is.)
|
|
104
104
|
let archaeopteryx = {};
|
|
105
105
|
|
|
106
|
-
const VERSION = '3.
|
|
106
|
+
const VERSION = '3.25.0';
|
|
107
107
|
const WEBSITE = 'https://cmzmasek.github.io/archaeopteryx-js/';
|
|
108
108
|
const DESKTOP_WEBSITE = 'https://cmzmasek.github.io/archaeopteryx/';
|
|
109
109
|
const SOURCE_WEBSITE = 'https://github.com/cmzmasek/archaeopteryx-js';
|
|
@@ -539,7 +539,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
539
539
|
let _container = null; // the resolved container ELEMENT (never a selector string)
|
|
540
540
|
let _intervalId = 0;
|
|
541
541
|
let _maxLabelLength = 0;
|
|
542
|
-
let _nodeLabels = null;
|
|
543
542
|
let _state = null; // live display state: what the control panel writes to
|
|
544
543
|
let _root = null;
|
|
545
544
|
let _root_const = null;
|
|
@@ -606,6 +605,7 @@ function (root, d3, forester, phyloXml) {
|
|
|
606
605
|
const DOMAIN_SCALE_HEADROOM = 0.9; // drawn length over reserved length
|
|
607
606
|
const DOMAIN_BOX_MIN_H = 6;
|
|
608
607
|
const DOMAIN_BOX_MAX_H = 16;
|
|
608
|
+
const LEGEND_MAX_ROWS = 20; // value rows a legend lists before "n more"; the rest fold
|
|
609
609
|
const DOMAIN_BACKBONE_COLOR = 'rgb(100,100,100)'; // the same in both themes and in exports
|
|
610
610
|
const DOMAIN_SHADOW_COLOR = 'rgb(8,18,21)';
|
|
611
611
|
const DOMAIN_SHADOWS = [[0.4, 0.7, 40], [0.9, 1.5, 28], [1.6, 2.5, 17]]; // dx, dy, alpha of 255, in drawing order
|
|
@@ -1948,7 +1948,32 @@ function (root, d3, forester, phyloXml) {
|
|
|
1948
1948
|
// an explicit request is honoured even for a wide field (21+
|
|
1949
1949
|
// values) the automatic path would only offer, never impose;
|
|
1950
1950
|
// autoColorId too, so it survives subtree views like the
|
|
1951
|
-
// automatic pick does
|
|
1951
|
+
// automatic pick does.
|
|
1952
|
+
//
|
|
1953
|
+
// Honoured, but not in silence. A request for a field the
|
|
1954
|
+
// automatic choice would not open with -- wide, or sparse (on
|
|
1955
|
+
// fewer than 2/3 of the tips; it opens only when nothing denser
|
|
1956
|
+
// exists) -- says so in the console and names the field the
|
|
1957
|
+
// viewer would have chosen. BV-BRC's virus trees carried a
|
|
1958
|
+
// site-wide 'Host' from the influenza days: family trees opened
|
|
1959
|
+
// coloured by 39 to 168 hosts while Genus (4 to 15 values) sat
|
|
1960
|
+
// in the file, and nothing anywhere said the viewer had been
|
|
1961
|
+
// overruled (Christian, 2026-10-08: a console warning when a
|
|
1962
|
+
// sub-optimal visualization is forced is needed). A request for
|
|
1963
|
+
// a clean field that merely ranks below the automatic pick is a
|
|
1964
|
+
// site's taste and warns nothing; nor does a sparse field that
|
|
1965
|
+
// is the automatic pick itself.
|
|
1966
|
+
let auto = forester.openingVisualization(_vis.candidates);
|
|
1967
|
+
if ((requested.wide || requested.sparse) && !(auto && auto.id === requested.id)) {
|
|
1968
|
+
let why = requested.wide
|
|
1969
|
+
? requested.values.length + ' distinct values on this tree, more than the '
|
|
1970
|
+
+ LEGEND_MAX_ROWS + ' the legend lists'
|
|
1971
|
+
: 'a value on ' + requested.coverage + ' of the tree\'s ' + requested.total + ' tips';
|
|
1972
|
+
console.warn(WARNING + ': initialVisualization "' + _settings.initialVisualization
|
|
1973
|
+
+ '" names a field with ' + why + '; left to itself the viewer would '
|
|
1974
|
+
+ (auto ? 'open with "' + auto.label + '" (' + auto.values.length + ' values)'
|
|
1975
|
+
: 'open uncoloured'));
|
|
1976
|
+
}
|
|
1952
1977
|
_vis.autoColorId = requested.id;
|
|
1953
1978
|
_vis.colorId = requested.id;
|
|
1954
1979
|
_state.showVisualizations = true;
|
|
@@ -2144,6 +2169,7 @@ function (root, d3, forester, phyloXml) {
|
|
|
2144
2169
|
}
|
|
2145
2170
|
dialog.addEventListener('close', close);
|
|
2146
2171
|
|
|
2172
|
+
let placed = false; // set by place() once the picker has been put somewhere
|
|
2147
2173
|
render(false);
|
|
2148
2174
|
dialog.show();
|
|
2149
2175
|
place();
|
|
@@ -2151,40 +2177,67 @@ function (root, d3, forester, phyloXml) {
|
|
|
2151
2177
|
// Beside the legend it edits, never on top of it -- a picker that hides
|
|
2152
2178
|
// the swatch it is changing defeats the live preview.
|
|
2153
2179
|
//
|
|
2154
|
-
//
|
|
2155
|
-
//
|
|
2156
|
-
//
|
|
2157
|
-
//
|
|
2158
|
-
//
|
|
2159
|
-
//
|
|
2160
|
-
//
|
|
2180
|
+
// Placed OUTRIGHT the first time, viewport-fixed. A non-modal <dialog>
|
|
2181
|
+
// appended to the body sits at its static position, the end of the
|
|
2182
|
+
// document: on the demo page that is the top of the window (the
|
|
2183
|
+
// container is out of flow), on a page that flows, such as BV-BRC's,
|
|
2184
|
+
// it is below everything on it. Until 2026-10-08 the picker moved
|
|
2185
|
+
// only when that spot overlapped the card, so on BV-BRC it opened
|
|
2186
|
+
// under the site's own bars, off the bottom of the window
|
|
2187
|
+
// (Christian's screenshot). Fixed positioning also keeps a scrolling
|
|
2188
|
+
// page from carrying it away.
|
|
2189
|
+
//
|
|
2190
|
+
// Re-measured rather than remembered afterwards, for two reasons:
|
|
2191
|
+
// every redraw DESTROYS and rebuilds the legend group, so a held
|
|
2192
|
+
// reference goes stale and measures zero; and the card grows when the
|
|
2193
|
+
// [reset colors] chip appears on the first pick, which would leave a
|
|
2194
|
+
// positioned-once picker sitting over the counts. Once placed it only
|
|
2195
|
+
// MOVES when it would otherwise overlap, so the dialog does not chase
|
|
2196
|
+
// the legend around while the user drags.
|
|
2161
2197
|
function place() {
|
|
2162
2198
|
let el = anchorClass ? document.querySelector('g.' + anchorClass) : null;
|
|
2163
2199
|
let box = el ? el.getBoundingClientRect() : null;
|
|
2164
|
-
if (
|
|
2165
|
-
|
|
2200
|
+
if (box && !box.width) {
|
|
2201
|
+
box = null;
|
|
2166
2202
|
}
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2203
|
+
if (placed) {
|
|
2204
|
+
if (!box) {
|
|
2205
|
+
return;
|
|
2206
|
+
}
|
|
2207
|
+
let now = dialog.getBoundingClientRect();
|
|
2208
|
+
let overlaps = now.width > 0
|
|
2209
|
+
&& !(now.left >= box.right || now.right <= box.left
|
|
2210
|
+
|| now.top >= box.bottom || now.bottom <= box.top);
|
|
2211
|
+
if (!overlaps) {
|
|
2212
|
+
return;
|
|
2213
|
+
}
|
|
2173
2214
|
}
|
|
2174
2215
|
let w = dialog.offsetWidth;
|
|
2175
2216
|
let h = dialog.offsetHeight;
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2217
|
+
let left;
|
|
2218
|
+
let top;
|
|
2219
|
+
if (box) {
|
|
2220
|
+
// to the right of the card, or to its left when that would
|
|
2221
|
+
// leave the viewport
|
|
2222
|
+
left = box.right + 10;
|
|
2223
|
+
if (left + w > window.innerWidth - 6) {
|
|
2224
|
+
left = box.left - w - 10;
|
|
2225
|
+
}
|
|
2226
|
+
top = box.top;
|
|
2227
|
+
} else {
|
|
2228
|
+
// no card to sit beside (the view has no swatch for the value):
|
|
2229
|
+
// the tree area's top left corner, inside the window
|
|
2230
|
+
let area = _container ? _container.getBoundingClientRect() : null;
|
|
2231
|
+
left = area ? area.left + 14 : 10;
|
|
2232
|
+
top = area ? Math.max(area.top, 0) + 14 : 10;
|
|
2181
2233
|
}
|
|
2182
2234
|
setStyles(dialog, {
|
|
2183
2235
|
'position': 'fixed',
|
|
2184
2236
|
'margin': '0',
|
|
2185
2237
|
'left': Math.max(6, Math.min(window.innerWidth - w - 6, left)) + 'px',
|
|
2186
|
-
'top': Math.max(6, Math.min(window.innerHeight - h - 6,
|
|
2238
|
+
'top': Math.max(6, Math.min(window.innerHeight - h - 6, top)) + 'px'
|
|
2187
2239
|
});
|
|
2240
|
+
placed = true;
|
|
2188
2241
|
}
|
|
2189
2242
|
setTimeout(function () {
|
|
2190
2243
|
document.addEventListener('pointerdown', onOutside, true);
|
|
@@ -2521,7 +2574,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
2521
2574
|
// is then just its "no value" row
|
|
2522
2575
|
const isRange = kind === 'color' && colorModeOf(vis) === 'range' && vis.values.length > 0;
|
|
2523
2576
|
|
|
2524
|
-
const LEGEND_MAX_ROWS = 20;
|
|
2525
2577
|
let rows = [];
|
|
2526
2578
|
let hidden = 0;
|
|
2527
2579
|
if (!isRange) {
|
|
@@ -4725,25 +4777,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
4725
4777
|
l = append(l, labelPropertiesOf(phynode));
|
|
4726
4778
|
}
|
|
4727
4779
|
|
|
4728
|
-
if (_nodeLabels && phynode.properties) {
|
|
4729
|
-
const props_length = phynode.properties.length;
|
|
4730
|
-
if (props_length > 0) {
|
|
4731
|
-
for (const value of Object.values(_nodeLabels)) {
|
|
4732
|
-
if (value.selected === true && value.propertyRef) {
|
|
4733
|
-
let prop_text = '';
|
|
4734
|
-
for (let pm = 0; pm < props_length; ++pm) {
|
|
4735
|
-
if (phynode.properties[pm].ref === value.propertyRef && phynode.properties[pm].datatype === 'xsd:string' && forester.isNodeScopedProperty(phynode.properties[pm])) {
|
|
4736
|
-
if (prop_text.length > 0) {
|
|
4737
|
-
prop_text += ', '
|
|
4738
|
-
}
|
|
4739
|
-
prop_text += phynode.properties[pm].value;
|
|
4740
|
-
}
|
|
4741
|
-
}
|
|
4742
|
-
l = append(l, prop_text);
|
|
4743
|
-
}
|
|
4744
|
-
}
|
|
4745
|
-
}
|
|
4746
|
-
}
|
|
4747
4780
|
|
|
4748
4781
|
|
|
4749
4782
|
if (_state.showDistributions && phynode.distributions && phynode.distributions.length > 0) {
|
|
@@ -5522,6 +5555,21 @@ function (root, d3, forester, phyloXml) {
|
|
|
5522
5555
|
return v;
|
|
5523
5556
|
},
|
|
5524
5557
|
note: 'the grid follows the scale axis, time or distance'
|
|
5558
|
+
},
|
|
5559
|
+
// Retired in 3.25.0 (Christian, 2026-10-08: "go with the deprecation").
|
|
5560
|
+
// The custom label checkboxes it declared -- a site's fixed list of
|
|
5561
|
+
// property refs, one panel checkbox each, labelling nodes with the
|
|
5562
|
+
// property's value -- predate the Metadata checkbox and its
|
|
5563
|
+
// "Metadata fields…" chooser, which offer exactly the fields the tree
|
|
5564
|
+
// carries and replace identifier-like tip names with a name property
|
|
5565
|
+
// on their own. On BV-BRC the list, written for influenza, put eight
|
|
5566
|
+
// checkboxes on every virus tree, six of them for fields the tree
|
|
5567
|
+
// did not have. The checkbox code went with the key (the label
|
|
5568
|
+
// text, the panel rows, the view state's custom:<key> flags, which
|
|
5569
|
+
// an old hash may still carry and the reader now ignores). Accepted
|
|
5570
|
+
// with this warning for one release cycle, then REMOVED_CONFIG.
|
|
5571
|
+
nodeLabels: {
|
|
5572
|
+
note: 'the Metadata checkbox and its "Metadata fields…" chooser offer the tree\'s own fields; labelProperties sets the starting fields'
|
|
5525
5573
|
}
|
|
5526
5574
|
};
|
|
5527
5575
|
|
|
@@ -5721,7 +5769,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
5721
5769
|
'internalNumericLabels',
|
|
5722
5770
|
'ladderizeTree',
|
|
5723
5771
|
'nhExportWriteConfidences',
|
|
5724
|
-
'nodeLabels',
|
|
5725
5772
|
'onViewChange',
|
|
5726
5773
|
'panelDensity',
|
|
5727
5774
|
'pngExportScale',
|
|
@@ -6321,19 +6368,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
6321
6368
|
} else if (typeof _settings.onViewChange !== 'function') {
|
|
6322
6369
|
throw new Error(ERROR + '"onViewChange" must be a function (state, encoded) or null');
|
|
6323
6370
|
}
|
|
6324
|
-
if (_settings.nodeLabels === undefined) {
|
|
6325
|
-
_settings.nodeLabels = null;
|
|
6326
|
-
} else if (_settings.nodeLabels !== null && typeof _settings.nodeLabels !== 'object') {
|
|
6327
|
-
throw new Error('nodeLabels must be an object (see the README) or null');
|
|
6328
|
-
}
|
|
6329
|
-
if (_settings.nodeLabels) {
|
|
6330
|
-
// a DEEP copy: the viewer writes runtime state into these specs
|
|
6331
|
-
// (the checkbox element id, the live checked state), and the
|
|
6332
|
-
// caller's config object must stay declarative -- an embedder
|
|
6333
|
-
// reusing one nodeLabels constant across launches must not
|
|
6334
|
-
// inherit the previous session's checkbox state
|
|
6335
|
-
_settings.nodeLabels = JSON.parse(JSON.stringify(_settings.nodeLabels));
|
|
6336
|
-
}
|
|
6337
6371
|
if (_settings.pngExportScale === undefined) {
|
|
6338
6372
|
_settings.pngExportScale = 4;
|
|
6339
6373
|
} else if (typeof _settings.pngExportScale !== 'number'
|
|
@@ -6593,7 +6627,7 @@ function (root, d3, forester, phyloXml) {
|
|
|
6593
6627
|
+ ' trailing arguments were removed. The separate settings bag merged into the one'
|
|
6594
6628
|
+ ' config object; "nodeVisualizations" and "specialVisualizations" are gone for good'
|
|
6595
6629
|
+ ' (visualizations are derived automatically from the tree itself); "nodeLabels"'
|
|
6596
|
-
+ '
|
|
6630
|
+
+ ' is retired (the Metadata checkbox offers the tree\'s own fields).');
|
|
6597
6631
|
}
|
|
6598
6632
|
if (phylo === undefined || phylo === null) {
|
|
6599
6633
|
throw new Error(ERROR + 'input tree is undefined or null');
|
|
@@ -6684,9 +6718,8 @@ function (root, d3, forester, phyloXml) {
|
|
|
6684
6718
|
.on('zoom', zoom);
|
|
6685
6719
|
_basicTreeProperties = forester.collectBasicTreeProperties(_treeData);
|
|
6686
6720
|
|
|
6687
|
-
// Every launch starts from a clean slate: _vis is rebuilt below
|
|
6688
|
-
//
|
|
6689
|
-
// the same page.
|
|
6721
|
+
// Every launch starts from a clean slate: _vis is rebuilt below, never
|
|
6722
|
+
// inherited from a previous launch in the same page.
|
|
6690
6723
|
_radialRotation = 0;
|
|
6691
6724
|
_radialLabelsHorizontal = false;
|
|
6692
6725
|
_msaColOffset = 0;
|
|
@@ -6704,7 +6737,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
6704
6737
|
// candidate ranking over 13k tips before the card could even paint.
|
|
6705
6738
|
checkLayoutValue(cfg.state ? cfg.state.layout : undefined);
|
|
6706
6739
|
initializeSettings(cfg.settings);
|
|
6707
|
-
_nodeLabels = _settings.nodeLabels || null;
|
|
6708
6740
|
|
|
6709
6741
|
// whatever a previous launch left in this container (or in the
|
|
6710
6742
|
// container before it) goes now, so the old tree does not sit under
|
|
@@ -9896,20 +9928,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
9896
9928
|
return found;
|
|
9897
9929
|
}
|
|
9898
9930
|
|
|
9899
|
-
// The config's custom label checkboxes (nodeLabels) that are offered
|
|
9900
|
-
function customLabelEntries() {
|
|
9901
|
-
let out = [];
|
|
9902
|
-
if (_nodeLabels) {
|
|
9903
|
-
Object.keys(_nodeLabels).forEach(function (key) {
|
|
9904
|
-
let v = _nodeLabels[key];
|
|
9905
|
-
if (v && v.label && v.showButton === true && v.propertyRef && v.description) {
|
|
9906
|
-
out.push({key: key, entry: v});
|
|
9907
|
-
}
|
|
9908
|
-
});
|
|
9909
|
-
}
|
|
9910
|
-
return out;
|
|
9911
|
-
}
|
|
9912
|
-
|
|
9913
9931
|
function searchStateOf(idx) {
|
|
9914
9932
|
let spec = currentSearchSpec(idx);
|
|
9915
9933
|
let value = (spec.value === null || spec.value === undefined) ? '' : String(spec.value);
|
|
@@ -9957,11 +9975,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
9957
9975
|
}).map(function (f) {
|
|
9958
9976
|
return f[0];
|
|
9959
9977
|
});
|
|
9960
|
-
customLabelEntries().forEach(function (c) {
|
|
9961
|
-
if (c.entry.selected === true) {
|
|
9962
|
-
s.show.push('custom:' + c.key);
|
|
9963
|
-
}
|
|
9964
|
-
});
|
|
9965
9978
|
s.font = _state.externalNodeFontSize;
|
|
9966
9979
|
s.node = _state.nodeSizeDefault;
|
|
9967
9980
|
s.branch = _state.branchWidthDefault;
|
|
@@ -10107,9 +10120,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
10107
10120
|
VIEW_SHOW_FLAGS.forEach(function (f) {
|
|
10108
10121
|
_state[f[2]] = on.has(f[0]);
|
|
10109
10122
|
});
|
|
10110
|
-
customLabelEntries().forEach(function (c) {
|
|
10111
|
-
c.entry.selected = on.has('custom:' + c.key);
|
|
10112
|
-
});
|
|
10113
10123
|
}
|
|
10114
10124
|
if (isFinite(s.font)) {
|
|
10115
10125
|
setFontSizes(Number(s.font));
|
|
@@ -10259,11 +10269,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
10259
10269
|
VIEW_SHOW_FLAGS.forEach(function (f) {
|
|
10260
10270
|
setCheckboxValue(f[1], _state[f[2]] === true);
|
|
10261
10271
|
});
|
|
10262
|
-
customLabelEntries().forEach(function (c) {
|
|
10263
|
-
if (c.entry.cb_id) {
|
|
10264
|
-
setCheckboxValue(c.entry.cb_id, c.entry.selected === true);
|
|
10265
|
-
}
|
|
10266
|
-
});
|
|
10267
10272
|
setCheckboxValue(MSA_CB, _state.showMsa === true);
|
|
10268
10273
|
setCheckboxValue(MSA_LOGO_CB, _state.showMsaLogo === true);
|
|
10269
10274
|
setCheckboxValue(HEATMAP_CB, _state.showHeatmap === true);
|
|
@@ -15380,22 +15385,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
15380
15385
|
}
|
|
15381
15386
|
|
|
15382
15387
|
|
|
15383
|
-
function customCbClicked(cb_id) {
|
|
15384
|
-
if (_nodeLabels) {
|
|
15385
|
-
const cb_value = getCheckboxValue(cb_id);
|
|
15386
|
-
for (const value of Object.values(_nodeLabels)) {
|
|
15387
|
-
if (value.label && value.showButton === true && value.propertyRef && value.description) {
|
|
15388
|
-
if (value.cb_id === cb_id) {
|
|
15389
|
-
value.selected = cb_value;
|
|
15390
|
-
}
|
|
15391
|
-
}
|
|
15392
|
-
}
|
|
15393
|
-
search0();
|
|
15394
|
-
search1();
|
|
15395
|
-
update();
|
|
15396
|
-
}
|
|
15397
|
-
}
|
|
15398
|
-
|
|
15399
15388
|
function taxonomyCbClicked() {
|
|
15400
15389
|
_state.showTaxonomy = getCheckboxValue(TAXONOMY_CB);
|
|
15401
15390
|
if (_state.showTaxonomy) {
|
|
@@ -18431,20 +18420,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
18431
18420
|
|
|
18432
18421
|
on(SHORTEN_NODE_NAME_CB, 'click', shortenCbClicked);
|
|
18433
18422
|
|
|
18434
|
-
if (_nodeLabels) {
|
|
18435
|
-
for (const [key, value] of Object.entries(_nodeLabels)) {
|
|
18436
|
-
if (value.label && value.showButton === true && value.propertyRef && value.description) {
|
|
18437
|
-
const cb_id = makeIdForCustomCheckboxButton(key);
|
|
18438
|
-
on(cb_id, 'click', function () {
|
|
18439
|
-
customCbClicked(cb_id);
|
|
18440
|
-
});
|
|
18441
|
-
if (value.selected === true) {
|
|
18442
|
-
setCheckboxValue(cb_id, true);
|
|
18443
|
-
}
|
|
18444
|
-
}
|
|
18445
|
-
}
|
|
18446
|
-
}
|
|
18447
|
-
|
|
18448
18423
|
on(LABEL_COLOR_SELECT_MENU, 'change', function () {
|
|
18449
18424
|
let v = this.value;
|
|
18450
18425
|
if (v && v !== DEFAULT && _vis && _vis.byId[v]) {
|
|
@@ -18885,10 +18860,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
18885
18860
|
return '<label class="aptx-seg" title="' + tooltip + '"><input type="radio" name="' + radioGroup + '" id="' + id + '">' + content + '</label>';
|
|
18886
18861
|
}
|
|
18887
18862
|
|
|
18888
|
-
function makeIdForCustomCheckboxButton(key) {
|
|
18889
|
-
return key + '__cb';
|
|
18890
|
-
}
|
|
18891
|
-
|
|
18892
18863
|
function makeDisplayControl() {
|
|
18893
18864
|
let labels = [];
|
|
18894
18865
|
let nodes = [];
|
|
@@ -18910,17 +18881,6 @@ function (root, d3, forester, phyloXml) {
|
|
|
18910
18881
|
labels.push(makeCheckboxItem('Metadata', PROPERTIES_CB, 'to show/hide the nodes\' metadata (phyloXML'
|
|
18911
18882
|
+ ' properties: species, host, …) in their labels; Metadata fields… chooses which, and in what order'));
|
|
18912
18883
|
}
|
|
18913
|
-
if (_nodeLabels) {
|
|
18914
|
-
for (const [key, value] of Object.entries(_nodeLabels)) {
|
|
18915
|
-
if (value.label && value.propertyRef && value.description) {
|
|
18916
|
-
const cb_id = makeIdForCustomCheckboxButton(key);
|
|
18917
|
-
if (value.showButton === true) {
|
|
18918
|
-
labels.push(makeCheckboxItem(value.label, cb_id, value.description));
|
|
18919
|
-
}
|
|
18920
|
-
value.cb_id = cb_id;
|
|
18921
|
-
}
|
|
18922
|
-
}
|
|
18923
|
-
}
|
|
18924
18884
|
if (_basicTreeProperties.confidences) {
|
|
18925
18885
|
labels.push(makeCheckboxItem('Confidence', CONFIDENCE_VALUES_CB, 'to show/hide confidence values'));
|
|
18926
18886
|
}
|
package/forester.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "archaeopteryx",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.25.0",
|
|
4
4
|
"description": "Archaeopteryx.js is a software tool for the visualization and analysis of highly annotated phylogenetic trees.",
|
|
5
5
|
"main": "archaeopteryx.js",
|
|
6
6
|
"types": "archaeopteryx.d.ts",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"LICENSE"
|
|
21
21
|
],
|
|
22
22
|
"scripts": {
|
|
23
|
-
"test": "node test/forester_test.js && node test/search_test.js && node test/visualization_test.js && node test/domain_test.js && node test/gene_test.js && node test/clock_test.js && node test/metadata_test.js && node test/heatmap_test.js && node test/clustering_test.js",
|
|
23
|
+
"test": "node test/forester_test.js && node test/search_test.js && node test/visualization_test.js && node test/domain_test.js && node test/gene_test.js && node test/clock_test.js && node test/metadata_test.js && node test/heatmap_test.js && node test/clustering_test.js && node test/canvg_global_test.js",
|
|
24
24
|
"lint": "eslint .",
|
|
25
25
|
"lint:fix": "eslint . --fix",
|
|
26
26
|
"format": "prettier --write .",
|