react-msaview 9.2.0 → 9.3.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/bundle/index.js +74 -74
- package/bundle/index.js.map +4 -4
- package/dist/components/DragHandle.js +2 -1
- package/dist/components/DragHandle.js.map +1 -1
- package/dist/components/MSAViewer.d.ts +29 -19
- package/dist/components/MSAViewer.js +2 -1
- package/dist/components/MSAViewer.js.map +1 -1
- package/dist/components/Track.js +2 -5
- package/dist/components/Track.js.map +1 -1
- package/dist/components/VerticalScrollbar.js +1 -1
- package/dist/components/VerticalScrollbar.js.map +1 -1
- package/dist/components/header/Header.js +2 -1
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/minimap/Minimap.js +1 -1
- package/dist/components/minimap/Minimap.js.map +1 -1
- package/dist/components/msa/MSACanvas.js +16 -27
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/rowpanels/RowPanels.js +8 -6
- package/dist/components/rowpanels/RowPanels.js.map +1 -1
- package/dist/components/settings/SettingsPanel.js +2 -1
- package/dist/components/settings/SettingsPanel.js.map +1 -1
- package/dist/components/tree/TreeCanvas.js +8 -6
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +2 -0
- package/dist/constants.js.map +1 -1
- package/dist/element.d.ts +11 -7
- package/dist/element.js +46 -8
- package/dist/element.js.map +1 -1
- package/dist/featurePanels.d.ts +0 -7
- package/dist/featurePanels.js +1 -16
- package/dist/featurePanels.js.map +1 -1
- package/dist/ggplotPalettes.js +12 -1
- package/dist/ggplotPalettes.js.map +1 -1
- package/dist/groupKeys.d.ts +6 -0
- package/dist/groupKeys.js +52 -0
- package/dist/groupKeys.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/model.d.ts +34 -17
- package/dist/model.js +100 -54
- package/dist/model.js.map +1 -1
- package/dist/scales.d.ts +114 -13
- package/dist/scales.js +154 -19
- package/dist/scales.js.map +1 -1
- package/dist/svgTestUtil.d.ts +20 -12
- package/dist/types.d.ts +29 -27
- package/dist/useDragScroll.d.ts +4 -3
- package/dist/useDragScroll.js +9 -6
- package/dist/useDragScroll.js.map +1 -1
- package/dist/useWheelScroll.d.ts +26 -8
- package/dist/useWheelScroll.js +108 -71
- package/dist/useWheelScroll.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/viewerSnapshot.js +2 -1
- package/dist/viewerSnapshot.js.map +1 -1
- package/package.json +3 -3
- package/src/components/DragHandle.tsx +2 -1
- package/src/components/MSAViewer.tsx +11 -8
- package/src/components/Track.tsx +2 -8
- package/src/components/VerticalScrollbar.tsx +1 -1
- package/src/components/header/Header.tsx +2 -1
- package/src/components/minimap/Minimap.tsx +1 -1
- package/src/components/msa/MSACanvas.tsx +14 -35
- package/src/components/rowpanels/RowPanels.tsx +8 -10
- package/src/components/settings/SettingsPanel.tsx +2 -1
- package/src/components/tree/TreeCanvas.tsx +8 -10
- package/src/constants.ts +2 -0
- package/src/element.ts +53 -8
- package/src/featurePanels.ts +1 -25
- package/src/ggplotPalettes.ts +13 -1
- package/src/groupKeys.ts +54 -0
- package/src/index.ts +13 -2
- package/src/model.ts +149 -72
- package/src/scales.ts +268 -25
- package/src/types.ts +28 -25
- package/src/useDragScroll.ts +11 -8
- package/src/useWheelScroll.ts +124 -84
- package/src/version.ts +1 -1
- package/src/viewerSnapshot.ts +3 -1
package/dist/model.js
CHANGED
|
@@ -13,11 +13,11 @@ import { packDomainLanes } from './components/msa/packDomainLanes.js';
|
|
|
13
13
|
import { visibleColRange } from './components/msa/visibleColRange.js';
|
|
14
14
|
import { cladeGutterWidth } from './components/tree/cladeBrackets.js';
|
|
15
15
|
import { scaleBarLength } from './components/tree/scaleBar.js';
|
|
16
|
-
import { defaultAllowedGappyness, defaultColWidth, defaultColorSchemeName, defaultCurrentAlignment, defaultDrawMsaLetters, defaultHeight, defaultHideGaps, defaultRowHeight, defaultScrollX, defaultScrollY, defaultScrollZoom, defaultScrollZoomAxis, defaultShowDomainLegend, defaultShowDomains, defaultSubFeatureRows, fontSizeFor, labelFitFontSize, maxCellSize, maxFitTreeWidth, maxTreeAreaShare, maxInlineSnapshotBytes as defaultMaxInlineSnapshotBytes, maxNeighborJoiningRows, minColWidth, minLetterColWidth, minLetterRowHeight, minRowHeight, minTreeWidth, pxPerTreeDepth, rowPanelHeaderHeight, rowTintAlpha, scrollZoomAxes, segmentFeatureTypes, segmentShades, settingsPanelWidth, treeScaleBarHeight, } from './constants.js';
|
|
16
|
+
import { defaultAllowedGappyness, defaultColWidth, defaultColorSchemeName, defaultCurrentAlignment, defaultDrawMsaLetters, defaultHeight, defaultHideGaps, defaultRowHeight, defaultScrollX, defaultScrollY, defaultScrollZoom, defaultScrollZoomAxis, defaultShowDomainLegend, defaultShowDomains, defaultSubFeatureRows, fontSizeFor, labelFitFontSize, maxCellSize, maxFitTreeWidth, maxTreeAreaShare, maxInlineSnapshotBytes as defaultMaxInlineSnapshotBytes, maxNeighborJoiningRows, minColWidth, minLetterColWidth, minLetterRowHeight, minRowHeight, minTreeWidth, pxPerTreeDepth, resizeHandleWidth, rowPanelHeaderHeight, rowTintAlpha, scrollZoomAxes, segmentFeatureTypes, segmentShades, settingsPanelWidth, treeScaleBarHeight, } from './constants.js';
|
|
17
17
|
import { createPaletteMap } from './createPaletteMap.js';
|
|
18
18
|
import { exportFileName } from './exportFileName.js';
|
|
19
|
-
import { featureName } from './featureFields.js';
|
|
20
|
-
import { colorByRow, featureColorMap, featureLabelMap, featurePanelSpans,
|
|
19
|
+
import { featureField, featureName } from './featureFields.js';
|
|
20
|
+
import { colorByRow, featureColorMap, featureLabelMap, featurePanelSpans, rowPanelWidth, stringFields, } from './featurePanels.js';
|
|
21
21
|
import { featuresToAnnotations } from './featuresLayer.js';
|
|
22
22
|
import { installFilehandleLoader } from './filehandleLoader.js';
|
|
23
23
|
import { find, hierarchy, layoutTree, leaves, nodeCoveringRows, } from './hierarchy.js';
|
|
@@ -29,7 +29,7 @@ import { calculateNeighborJoiningTree } from './neighborJoining.js';
|
|
|
29
29
|
import { calculatePropertyConservation } from './propertyConservation.js';
|
|
30
30
|
import { preorder } from './rerootTree.js';
|
|
31
31
|
import { globalColToVisibleCol, seqPosOfGlobalCol, visibleColToGlobalCol, visibleColsBefore, } from './rowCoordinateCalculations.js';
|
|
32
|
-
import {
|
|
32
|
+
import { colorTable, declarationKey, readColumnTrack, readEncoding, readRowPanel, resolveShared, } from './scales.js';
|
|
33
33
|
import { buildSeqPosIndex } from './seqPosToGlobalCol.js';
|
|
34
34
|
import { maxBitsFor } from './sequenceLogo.js';
|
|
35
35
|
import { blosum62ColumnColors, identityColumnColors, } from './similarityColors.js';
|
|
@@ -391,7 +391,9 @@ function stateModelFactory({ maxInlineSnapshotBytes = defaultMaxInlineSnapshotBy
|
|
|
391
391
|
* tracks supplied as data: per-column values drawn as bars, or a
|
|
392
392
|
* per-column string drawn as a text track. See docs/layers.md
|
|
393
393
|
*/
|
|
394
|
-
columnTracks: stripDefault(types.array(types.frozen()
|
|
394
|
+
columnTracks: stripDefault(types.array(types.snapshotProcessor(types.frozen(), {
|
|
395
|
+
preProcessor: readColumnTrack,
|
|
396
|
+
})), []),
|
|
395
397
|
/**
|
|
396
398
|
* #property
|
|
397
399
|
* row-to-structure residue correspondence, computed outside the viewer
|
|
@@ -471,20 +473,25 @@ function stateModelFactory({ maxInlineSnapshotBytes = defaultMaxInlineSnapshotBy
|
|
|
471
473
|
clades: stripDefault(types.array(types.frozen()), []),
|
|
472
474
|
/**
|
|
473
475
|
* #property
|
|
474
|
-
* what the viewer's own marks read from `rowData
|
|
475
|
-
* `{channel, field,
|
|
476
|
-
* `
|
|
476
|
+
* what the viewer's own marks read from `rowData` or the feature
|
|
477
|
+
* table: `{channel, field, range?, domain?, title?}` per channel. The
|
|
478
|
+
* earlier `scale: {palette}` and `scale: {map}` read as `range` and
|
|
479
|
+
* `domain`. See docs/layers.md
|
|
477
480
|
*/
|
|
478
|
-
encodings: stripDefault(types.array(types.frozen()
|
|
481
|
+
encodings: stripDefault(types.array(types.snapshotProcessor(types.frozen(), {
|
|
482
|
+
preProcessor: readEncoding,
|
|
483
|
+
})), []),
|
|
479
484
|
/**
|
|
480
485
|
* #property
|
|
481
486
|
* panels drawn between the tree and the alignment:
|
|
482
|
-
* `{kind: "strip", field,
|
|
483
|
-
* per row from a `rowData` field, and
|
|
487
|
+
* `{kind: "strip", field, range?, domain?, title?, width?, header?}`
|
|
488
|
+
* colors one cell per row from a `rowData` field, and
|
|
484
489
|
* `{kind: "features", x, encoding?, transform?, width?, header?}`
|
|
485
490
|
* draws the spans the GFF carries. See docs/layers.md
|
|
486
491
|
*/
|
|
487
|
-
rowPanels: stripDefault(types.array(types.frozen()
|
|
492
|
+
rowPanels: stripDefault(types.array(types.snapshotProcessor(types.frozen(), {
|
|
493
|
+
preProcessor: readRowPanel,
|
|
494
|
+
})), []),
|
|
488
495
|
}))
|
|
489
496
|
.volatile(() => ({
|
|
490
497
|
/**
|
|
@@ -545,9 +552,10 @@ function stateModelFactory({ maxInlineSnapshotBytes = defaultMaxInlineSnapshotBy
|
|
|
545
552
|
volatileWidth: undefined,
|
|
546
553
|
/**
|
|
547
554
|
* #volatile
|
|
548
|
-
*
|
|
555
|
+
* thickness of the dividers, between the tree and the alignment and under
|
|
556
|
+
* the view, px
|
|
549
557
|
*/
|
|
550
|
-
resizeHandleWidth
|
|
558
|
+
resizeHandleWidth,
|
|
551
559
|
/**
|
|
552
560
|
* #volatile
|
|
553
561
|
* size of blocks of content to be drawn, px
|
|
@@ -1943,7 +1951,7 @@ function stateModelFactory({ maxInlineSnapshotBytes = defaultMaxInlineSnapshotBy
|
|
|
1943
1951
|
return [track.id, { arcs }];
|
|
1944
1952
|
}
|
|
1945
1953
|
if (track.kind === 'bar') {
|
|
1946
|
-
const max = track.
|
|
1954
|
+
const max = track.scales?.y?.domainMax ?? 1;
|
|
1947
1955
|
const values = skip(project(track, track.values ?? [], 0)).map(v => Math.min(1, Math.max(0, v / max)));
|
|
1948
1956
|
return [track.id, { values }];
|
|
1949
1957
|
}
|
|
@@ -1987,7 +1995,12 @@ function stateModelFactory({ maxInlineSnapshotBytes = defaultMaxInlineSnapshotBy
|
|
|
1987
1995
|
height: this.trackHeight(track.kind, heightKey, track.height),
|
|
1988
1996
|
barColor: track.color,
|
|
1989
1997
|
arcColor: track.color,
|
|
1990
|
-
customColorScheme: track.
|
|
1998
|
+
customColorScheme: track.encoding?.color
|
|
1999
|
+
? colorTable(track.encoding.color, [
|
|
2000
|
+
...(track.encoding.color.domain ?? []),
|
|
2001
|
+
...new Set(track.data),
|
|
2002
|
+
])
|
|
2003
|
+
: undefined,
|
|
1991
2004
|
data: content?.data,
|
|
1992
2005
|
arcs: content?.arcs,
|
|
1993
2006
|
},
|
|
@@ -2911,7 +2924,7 @@ function stateModelFactory({ maxInlineSnapshotBytes = defaultMaxInlineSnapshotBy
|
|
|
2911
2924
|
* #action
|
|
2912
2925
|
*/
|
|
2913
2926
|
setColumnTracks(tracks) {
|
|
2914
|
-
self.columnTracks.replace(tracks);
|
|
2927
|
+
self.columnTracks.replace(tracks.map(readColumnTrack));
|
|
2915
2928
|
},
|
|
2916
2929
|
/**
|
|
2917
2930
|
* #action
|
|
@@ -2926,14 +2939,14 @@ function stateModelFactory({ maxInlineSnapshotBytes = defaultMaxInlineSnapshotBy
|
|
|
2926
2939
|
* replace what the viewer's marks read from the row table
|
|
2927
2940
|
*/
|
|
2928
2941
|
setEncodings(encodings) {
|
|
2929
|
-
self.encodings.replace(encodings);
|
|
2942
|
+
self.encodings.replace(encodings.map(readEncoding));
|
|
2930
2943
|
},
|
|
2931
2944
|
/**
|
|
2932
2945
|
* #action
|
|
2933
2946
|
* replace the panels drawn between the tree and the alignment
|
|
2934
2947
|
*/
|
|
2935
2948
|
setRowPanels(panels) {
|
|
2936
|
-
self.rowPanels.replace(panels);
|
|
2949
|
+
self.rowPanels.replace(panels.map(readRowPanel));
|
|
2937
2950
|
},
|
|
2938
2951
|
/**
|
|
2939
2952
|
* #action
|
|
@@ -3116,52 +3129,47 @@ function stateModelFactory({ maxInlineSnapshotBytes = defaultMaxInlineSnapshotBy
|
|
|
3116
3129
|
* the categorical color keys drawn for this view, shared by the on-screen
|
|
3117
3130
|
* legend overlay and the SVG export's reserved column. The domain overlay
|
|
3118
3131
|
* produces the first, listing the `featureFill` scale where an encoding
|
|
3119
|
-
* names one. Every
|
|
3120
|
-
* produces one more, so two channels
|
|
3121
|
-
*
|
|
3122
|
-
*
|
|
3123
|
-
* legend between them
|
|
3132
|
+
* names one. Every scale a row-table encoding or a row panel reads
|
|
3133
|
+
* produces one more, keyed by its declaration, so two channels or two
|
|
3134
|
+
* strips declaring one scale list it once, and strips over eight fields
|
|
3135
|
+
* naming one `title` list one legend between them
|
|
3124
3136
|
*/
|
|
3125
3137
|
get legends() {
|
|
3126
3138
|
const { featureFillEncoding, fillPalette, visibleDomainTypes } = this;
|
|
3127
3139
|
const byKey = new Map();
|
|
3140
|
+
const ids = new Set();
|
|
3128
3141
|
// the accession palette keys on no field, so it takes a key of its own
|
|
3129
|
-
const add = (
|
|
3130
|
-
|
|
3142
|
+
const add = (key, title, entries, overlay = false) => {
|
|
3143
|
+
const k = key ?? 'domains';
|
|
3144
|
+
if (entries.length === 0 || byKey.has(k)) {
|
|
3131
3145
|
return;
|
|
3132
3146
|
}
|
|
3133
|
-
const
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
legend.entries.push(...entries.filter(e => !seen.has(e.id)));
|
|
3138
|
-
}
|
|
3139
|
-
else {
|
|
3140
|
-
byKey.set(key, {
|
|
3141
|
-
id: id ?? (field === undefined ? 'domains' : `rowData-${field}`),
|
|
3142
|
-
title: field ?? 'Domains',
|
|
3143
|
-
entries: [...entries],
|
|
3144
|
-
});
|
|
3147
|
+
const base = overlay || key === undefined ? 'domains' : `rowData-${title}`;
|
|
3148
|
+
let id = base;
|
|
3149
|
+
for (let n = 2; ids.has(id); n++) {
|
|
3150
|
+
id = `${base}-${n}`;
|
|
3145
3151
|
}
|
|
3152
|
+
ids.add(id);
|
|
3153
|
+
byKey.set(k, { id, title: title ?? 'Domains', entries });
|
|
3146
3154
|
};
|
|
3147
3155
|
// the overlay draws the domain key; with no columns it draws nothing,
|
|
3148
3156
|
// and a features panel taking the same colors lists them instead
|
|
3149
3157
|
if (self.actuallyShowDomains && self.numColumns > 0) {
|
|
3150
|
-
add(featureFillEncoding?.
|
|
3158
|
+
add(featureFillEncoding?.key, featureFillEncoding?.title, featureFillEncoding
|
|
3151
3159
|
? featureFillEncoding.legend
|
|
3152
3160
|
: visibleDomainTypes.map(d => ({
|
|
3153
3161
|
id: d.accession,
|
|
3154
3162
|
label: d.name,
|
|
3155
3163
|
color: d.color ?? fillPalette[d.accession],
|
|
3156
|
-
})),
|
|
3164
|
+
})), true);
|
|
3157
3165
|
}
|
|
3158
|
-
for (const { channel,
|
|
3166
|
+
for (const { channel, key, title, legend } of this.resolvedEncodings) {
|
|
3159
3167
|
if (!featureChannels.has(channel)) {
|
|
3160
|
-
add(
|
|
3168
|
+
add(key, title, legend);
|
|
3161
3169
|
}
|
|
3162
3170
|
}
|
|
3163
|
-
for (const { legendTitle, legend } of this.rowPanelScales) {
|
|
3164
|
-
add(legendTitle, legend);
|
|
3171
|
+
for (const { legendKey, legendTitle, legend } of this.rowPanelScales) {
|
|
3172
|
+
add(legendKey, legendTitle, legend);
|
|
3165
3173
|
}
|
|
3166
3174
|
return [...byKey.values()];
|
|
3167
3175
|
},
|
|
@@ -3435,14 +3443,52 @@ function stateModelFactory({ maxInlineSnapshotBytes = defaultMaxInlineSnapshotBy
|
|
|
3435
3443
|
* table or the encodings, never per row per frame.
|
|
3436
3444
|
*/
|
|
3437
3445
|
get resolvedEncodings() {
|
|
3438
|
-
const rows = Object.values(self.rowData);
|
|
3439
3446
|
return self.encodings.map(encoding => ({
|
|
3440
3447
|
...encoding,
|
|
3441
|
-
...(featureChannels.has(encoding.channel)
|
|
3442
|
-
? resolveFeatureScale(encoding.field, encoding.scale, self.allAnnotations, self.filteredAnnotations)
|
|
3443
|
-
: resolveScale(encoding.scale, rows.map(row => row?.[encoding.field]).filter(notEmpty))),
|
|
3448
|
+
...this.scaleOf(encoding, featureChannels.has(encoding.channel) ? 'features' : 'rows'),
|
|
3444
3449
|
}));
|
|
3445
3450
|
},
|
|
3451
|
+
/**
|
|
3452
|
+
* #getter
|
|
3453
|
+
* every color object the encodings and the row panels declare, keyed
|
|
3454
|
+
* by declaration (`declarationKey`) and resolved once over the union
|
|
3455
|
+
* of the values its records' fields take, so a value two strips share
|
|
3456
|
+
* takes one color in both. A feature field reads every feature loaded,
|
|
3457
|
+
* so hiding a type in the filter dialog leaves the rest in their
|
|
3458
|
+
* colors, and its legend lists the values of the drawn features.
|
|
3459
|
+
*/
|
|
3460
|
+
get resolvedScales() {
|
|
3461
|
+
const rows = Object.values(self.rowData);
|
|
3462
|
+
const featureValues = (list, field) => list.map(a => featureField(a, field)).filter(notEmpty);
|
|
3463
|
+
const use = (channel, table) => ({
|
|
3464
|
+
spec: channel,
|
|
3465
|
+
field: channel.field,
|
|
3466
|
+
table,
|
|
3467
|
+
...(table === 'rows'
|
|
3468
|
+
? {
|
|
3469
|
+
values: rows.map(row => row?.[channel.field]).filter(notEmpty),
|
|
3470
|
+
}
|
|
3471
|
+
: {
|
|
3472
|
+
values: featureValues(self.allAnnotations, channel.field),
|
|
3473
|
+
shown: featureValues(self.filteredAnnotations, channel.field),
|
|
3474
|
+
}),
|
|
3475
|
+
});
|
|
3476
|
+
return resolveShared([
|
|
3477
|
+
...self.encodings.map(encoding => use(encoding, featureChannels.has(encoding.channel) ? 'features' : 'rows')),
|
|
3478
|
+
...self.rowPanels.flatMap(panel => panel.kind === 'strip'
|
|
3479
|
+
? [use(panel, 'rows')]
|
|
3480
|
+
: panel.encoding?.color
|
|
3481
|
+
? [use(panel.encoding.color, 'features')]
|
|
3482
|
+
: []),
|
|
3483
|
+
]);
|
|
3484
|
+
},
|
|
3485
|
+
/**
|
|
3486
|
+
* #method
|
|
3487
|
+
* the shared scale a record's color object resolves to
|
|
3488
|
+
*/
|
|
3489
|
+
scaleOf(channel, table) {
|
|
3490
|
+
return this.resolvedScales.get(declarationKey({ spec: channel, field: channel.field, table }));
|
|
3491
|
+
},
|
|
3446
3492
|
/**
|
|
3447
3493
|
* #getter
|
|
3448
3494
|
* each row panel's scale resolved against the values its field takes,
|
|
@@ -3457,7 +3503,7 @@ function stateModelFactory({ maxInlineSnapshotBytes = defaultMaxInlineSnapshotBy
|
|
|
3457
3503
|
if (panel.kind === 'features') {
|
|
3458
3504
|
const color = panel.encoding?.color;
|
|
3459
3505
|
const encoding = color
|
|
3460
|
-
?
|
|
3506
|
+
? { field: color.field, ...this.scaleOf(color, 'features') }
|
|
3461
3507
|
: featureFillEncoding;
|
|
3462
3508
|
const label = panel.encoding?.label;
|
|
3463
3509
|
return {
|
|
@@ -3465,7 +3511,8 @@ function stateModelFactory({ maxInlineSnapshotBytes = defaultMaxInlineSnapshotBy
|
|
|
3465
3511
|
x: panel.x,
|
|
3466
3512
|
header: panel.header ?? '',
|
|
3467
3513
|
field: encoding?.field,
|
|
3468
|
-
|
|
3514
|
+
legendKey: encoding?.key,
|
|
3515
|
+
legendTitle: encoding?.title,
|
|
3469
3516
|
colors: color
|
|
3470
3517
|
? featureColorMap(annotations, encoding, fillPalette)
|
|
3471
3518
|
: this.featureColors,
|
|
@@ -3480,14 +3527,13 @@ function stateModelFactory({ maxInlineSnapshotBytes = defaultMaxInlineSnapshotBy
|
|
|
3480
3527
|
})),
|
|
3481
3528
|
};
|
|
3482
3529
|
}
|
|
3483
|
-
const { colorOf, legend } =
|
|
3484
|
-
.map(row => row?.[panel.field])
|
|
3485
|
-
.filter(notEmpty));
|
|
3530
|
+
const { colorOf, legend, key, title } = this.scaleOf(panel, 'rows');
|
|
3486
3531
|
return {
|
|
3487
3532
|
kind: panel.kind,
|
|
3488
3533
|
field: panel.field,
|
|
3489
3534
|
header: panel.header ?? panel.field,
|
|
3490
|
-
|
|
3535
|
+
legendKey: key,
|
|
3536
|
+
legendTitle: title,
|
|
3491
3537
|
colors: colorByRow(rowData, panel.field, colorOf),
|
|
3492
3538
|
legend,
|
|
3493
3539
|
};
|