@jbrowse/wiggle-core 4.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.
Files changed (63) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +292 -0
  3. package/esm/CrossHatches.d.ts +11 -0
  4. package/esm/CrossHatches.js +32 -0
  5. package/esm/ResolutionStepper.d.ts +17 -0
  6. package/esm/ResolutionStepper.js +56 -0
  7. package/esm/ScoreRules.d.ts +11 -0
  8. package/esm/ScoreRules.js +37 -0
  9. package/esm/ScoreScaleMixin.d.ts +105 -0
  10. package/esm/ScoreScaleMixin.js +136 -0
  11. package/esm/SetMinMaxDialog.d.ts +11 -0
  12. package/esm/SetMinMaxDialog.js +18 -0
  13. package/esm/YScaleBar.d.ts +6 -0
  14. package/esm/YScaleBar.js +46 -0
  15. package/esm/YScaleBarOverlay.d.ts +6 -0
  16. package/esm/YScaleBarOverlay.js +24 -0
  17. package/esm/autoscale.d.ts +55 -0
  18. package/esm/autoscale.js +252 -0
  19. package/esm/computeYTicks.d.ts +15 -0
  20. package/esm/computeYTicks.js +44 -0
  21. package/esm/constants.d.ts +2 -0
  22. package/esm/constants.js +10 -0
  23. package/esm/dataTypes.d.ts +26 -0
  24. package/esm/dataTypes.js +1 -0
  25. package/esm/displayModel.d.ts +24 -0
  26. package/esm/displayModel.js +1 -0
  27. package/esm/formatNumber.d.ts +1 -0
  28. package/esm/formatNumber.js +6 -0
  29. package/esm/gapBreak.d.ts +59 -0
  30. package/esm/gapBreak.js +58 -0
  31. package/esm/index.d.ts +36 -0
  32. package/esm/index.js +26 -0
  33. package/esm/normalize.d.ts +40 -0
  34. package/esm/normalize.js +106 -0
  35. package/esm/pointMarker.d.ts +3 -0
  36. package/esm/pointMarker.js +27 -0
  37. package/esm/pointSizeMenu.d.ts +13 -0
  38. package/esm/pointSizeMenu.js +21 -0
  39. package/esm/renderingBackendTypes.d.ts +39 -0
  40. package/esm/renderingBackendTypes.js +29 -0
  41. package/esm/resolveRenderState.d.ts +1 -0
  42. package/esm/resolveRenderState.js +20 -0
  43. package/esm/scale.d.ts +60 -0
  44. package/esm/scale.js +161 -0
  45. package/esm/scoreAxisConfigSchemaFields.d.ts +44 -0
  46. package/esm/scoreAxisConfigSchemaFields.js +54 -0
  47. package/esm/scoreMenuItems.d.ts +37 -0
  48. package/esm/scoreMenuItems.js +104 -0
  49. package/esm/scoreRuleMarks.d.ts +73 -0
  50. package/esm/scoreRuleMarks.js +98 -0
  51. package/esm/symlogTicks.d.ts +17 -0
  52. package/esm/symlogTicks.js +92 -0
  53. package/esm/transferables.d.ts +2 -0
  54. package/esm/transferables.js +32 -0
  55. package/esm/vendor/d3-scale.d.ts +33 -0
  56. package/esm/vendor/d3-scale.js +249 -0
  57. package/esm/visibleStatsDomain.d.ts +59 -0
  58. package/esm/visibleStatsDomain.js +33 -0
  59. package/esm/wiggleRenderModes.generated.d.ts +9 -0
  60. package/esm/wiggleRenderModes.generated.js +11 -0
  61. package/esm/yScaleTicks.d.ts +59 -0
  62. package/esm/yScaleTicks.js +59 -0
  63. package/package.json +54 -0
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [2020] [Evolutionary Software Foundation]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,292 @@
1
+ # @jbrowse/wiggle-core
2
+
3
+ Shared scale and autoscale utilities for wiggle and coverage displays
4
+
5
+ <!-- API_DOCS_START -->
6
+
7
+ ## API
8
+
9
+ Auto-generated from `#api` JSDoc tags in this package. Do not edit by hand.
10
+
11
+ ### computeAutoscaleDomain
12
+
13
+ Computes a score domain from the visible feature arrays for the `local` /
14
+ `localsd` / `localpercentile` autoscale types.
15
+
16
+ ```js
17
+ // type signature
18
+ (autoscaleType: string, summaryScoreMode: string, numStdDev: number, visibleEntries: {…}[], numQuantile?: number) => [...] | undefined
19
+ ```
20
+
21
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/autoscale.ts)
22
+
23
+ ### DEFAULT_GAP_BREAK_MULTIPLE
24
+
25
+ Default `multiple` for the wiggle interpolated line — the `maxGapMultiple`
26
+ config slot's default. 0 means the line never breaks: one connected polyline
27
+ across every hole, which is how the interpolated line behaved before gap
28
+ breaking existed.
29
+
30
+ OFF BY DEFAULT, deliberately and after having been on. It shipped at 20 and the
31
+ calibration behind that number still holds — a hole worth breaking on runs
32
+ orders of magnitude past the mean, and bbi's reduced zoom levels emit
33
+ fixed-width bins so the series tiles (measured on volvox_microarray.bw at three
34
+ zooms: 500 bins, every gap exactly 1.0x the mean, no break at any threshold).
35
+ What changed is the call about whether a reader wants the break at all: "we
36
+ added this feature awhile back but i dont think i like it now. might consider
37
+ going back to not skipping". A broken line reads as missing data whether or not
38
+ data is missing there, and the chord across a hole is at least continuous with
39
+ what the neighbouring points say.
40
+
41
+ The mechanism stays, whole, because it is the only way to get the other behavior
42
+ back: set `maxGapMultiple` on the track, 20 being the calibrated value. Nothing
43
+ about `gapBreakLimit` itself changes — a caller passing a positive multiple gets
44
+ exactly what it always got.
45
+
46
+ ```js
47
+ // type signature
48
+ 0
49
+ ```
50
+
51
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/gapBreak.ts)
52
+
53
+ ### domainFromStats
54
+
55
+ Converts score stats into a `[min, max]` domain, applying std-dev expansion for
56
+ the `localsd` autoscale type.
57
+
58
+ ```js
59
+ // type signature
60
+ (stats: ScoreStats, autoscaleType: string, numStdDev: number) => [number, number]
61
+ ```
62
+
63
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/autoscale.ts)
64
+
65
+ ### gapBreakLimit
66
+
67
+ How far apart two consecutive points of an interpolated (point-to-point) line
68
+ may be before the span between them counts as a hole rather than a segment to
69
+ draw. Returns `Infinity` when there is nothing to decide, so a caller can always
70
+ compare against it unguarded.
71
+
72
+ The limit is a multiple of the series' own _mean_ spacing rather than an
73
+ absolute distance, which is what makes one number work across zoom levels and
74
+ data types: reduced BigWig bins get wider as you zoom out, so any fixed bp
75
+ threshold would be either useless at one end or destructive at the other. It
76
+ also lets the same rule serve a bp axis (wiggle's linecenter) and a px one — the
77
+ caller picks the space, this only cares that the units are consistent.
78
+
79
+ Mean, not median: it is O(1) from the endpoints, and it errs the safe way. A
80
+ series' holes inflate their own mean, which raises the limit and so breaks
81
+ _less_ — a line that stays connected is the status quo, whereas a spuriously
82
+ broken one destroys data the user can see nowhere else. Sorting for a true
83
+ median would cost O(n log n) per source per region on the encode path, for a
84
+ threshold this coarse.
85
+
86
+ `count < 3` returns Infinity: two points have no "typical" spacing to be unusual
87
+ against, so there is nothing to call a hole.
88
+
89
+ ```js
90
+ // type signature
91
+ ({ first, last, count, multiple, }: { first: number; last: number; count: number; multiple: number; }) => number
92
+ ```
93
+
94
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/gapBreak.ts)
95
+
96
+ ### getEffectiveScores
97
+
98
+ Per-feature scalar score array for a summary mode: the min/max summary array for
99
+ `'min'`/`'max'`, otherwise the average score.
100
+
101
+ ```js
102
+ // type signature
103
+ (data: { featureScores: Float32Array<…>; featureMinScores: Float32Array<ArrayBufferLike>; featureMaxScores: Float32Array<...>; }, summaryScoreMode: string) => Float32Array<...>
104
+ ```
105
+
106
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/autoscale.ts)
107
+
108
+ ### getNiceDomain
109
+
110
+ Rounds a domain to "nice" endpoints, clamped to the origin. An end given an
111
+ explicit `bounds` value keeps that value exactly — only an autoscaled end is
112
+ rounded. A log scale's floor still outranks a bound it cannot hold.
113
+
114
+ The result never descends: a bound that would put `min` above `max` widens the
115
+ other end instead, so no consumer has to guess what a backwards domain means.
116
+
117
+ ```js
118
+ // type signature
119
+ ({ scaleType, domain, bounds, }: { scaleType: string; domain: readonly [number, number]; bounds: readonly [number | undefined, number | undefined]; }) => [number, number]
120
+ ```
121
+
122
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scale.ts)
123
+
124
+ ### getNiceScale
125
+
126
+ Returns a niced `{min, max}` domain for a maximum score value. Uses log base-2
127
+ when `useLogScale` is true (domain is clamped to [1, max]).
128
+
129
+ ```js
130
+ // type signature
131
+ (maxScore: number, useLogScale?: boolean | undefined) => { min: number; max: number; }
132
+ ```
133
+
134
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scale.ts)
135
+
136
+ ### getScale
137
+
138
+ Builds a d3 scale (linear/log/symlog) from a `ScaleOpts`, nicing the domain
139
+ unless `nice: false` says it is already the one being drawn with.
140
+
141
+ ```js
142
+ // type signature
143
+ ({ domain, range, scaleType, symlogConstant, nice, }: ScaleOpts) => Scale
144
+ ```
145
+
146
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scale.ts)
147
+
148
+ ### makeScoreNormalizer
149
+
150
+ Returns a loop-hoistable function normalizing a score to [0,1].
151
+
152
+ `symlogConstant` is only read for `SCALE_TYPE_SYMLOG`, and is expected to be
153
+ already resolved by resolveSymlogConstant — the shader gets the same resolved
154
+ number as a uniform, so the "auto" rule lives on this side only and the two
155
+ backends compare like for like.
156
+
157
+ A range that is zero **or negative** normalizes everything to 0, which is the
158
+ rule `scoreScale.slang` spells as `range <= 0.0`. Testing `range === 0` here
159
+ instead let a descending domain through to a negative `1 / range`, so every
160
+ score saturated to 1 on this side while the shader flattened them all to 0 — one
161
+ view, opposite plots. `normalizeScoreParity.test.ts` sweeps the two.
162
+
163
+ ```js
164
+ // type signature
165
+ (min: number, max: number, scaleType: WiggleScaleType, symlogConstant?: number) => (score: number) => number
166
+ ```
167
+
168
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/normalize.ts)
169
+
170
+ ### parseScoreRules
171
+
172
+ Normalizes whatever a `scoreRules` config slot holds into `ScoreRule`s, dropping
173
+ entries that are not usable. Config is user-authored JSON, so a bare number, a
174
+ missing value or a non-numeric one all have to survive being read.
175
+
176
+ ```js
177
+ // type signature
178
+ (value: unknown) => ScoreRule[]
179
+ ```
180
+
181
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scoreRuleMarks.ts)
182
+
183
+ ### resolveSymlogConstant
184
+
185
+ The symlog constant actually used for a domain. `0` (the config default) means
186
+ "pick one from the domain": a thousandth of its largest magnitude, so the
187
+ log-ish part of the curve covers the top three decades of whatever the track
188
+ holds and the linear knee sits below the data rather than through it.
189
+
190
+ The alternative — d3's default of 1 — is `log(x + 1)`, which is fine for read
191
+ depth and useless for anything living below 1, because the entire domain then
192
+ falls in the linear part of the curve. A p-value track configured that way is
193
+ just a linear track wearing a log label, which is the reason this is resolved
194
+ rather than hard-coded.
195
+
196
+ ```js
197
+ // type signature
198
+ (min: number, max: number, configured: number) => number
199
+ ```
200
+
201
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/normalize.ts)
202
+
203
+ ### scaleTypeFromString
204
+
205
+ Maps the `'log'`/`'symlog'`/`'linear'` string to the numeric `WiggleScaleType`.
206
+
207
+ ```js
208
+ // type signature
209
+ (scaleType: string) => WiggleScaleType
210
+ ```
211
+
212
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/normalize.ts)
213
+
214
+ ### ScoreRule
215
+
216
+ One horizontal rule across a score plot, at a score the user chose.
217
+
218
+ `label` is free text and carries no meaning this package assigns. That is
219
+ deliberate: the obvious use is reading a coverage or CNV track against copy
220
+ number, and there is no ploidy JBrowse could assume on the user's behalf. A
221
+ whole-genome triplication is not diploid, plenty of genomes are not diploid to
222
+ begin with, and a cancer sample can be neither — so "2 copies" is a claim only
223
+ the person looking at the track can make.
224
+
225
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scoreRuleMarks.ts)
226
+
227
+ ### scoreRuleMarks
228
+
229
+ Screen y for each rule that falls inside the plotted domain, dropping the rest.
230
+
231
+ Out-of-domain is a real case rather than a guard: the domain is whatever
232
+ autoscale resolved for the visible data, so panning to a quiet stretch can put a
233
+ rule above everything on screen, and a rule pinned to the top edge there reads
234
+ as "the whole view is over the line".
235
+
236
+ `normalize` is the display's OWN score normalizer — the same one the renderer
237
+ draws with. It is a parameter rather than a linear interpolation of the domain
238
+ because the axis need not be linear: on a log or symlog track, placing a rule at
239
+ `(value - min) / (max - min)` puts the line somewhere the data it is meant to be
240
+ read against is not.
241
+
242
+ `box` is likewise the caller's own — hand it the same `{yTop, yBottom}` the
243
+ display's ticks were built with (a `YScaleTicks` satisfies it). Recomputing a
244
+ box here would silently disagree with any band that lays its axis out
245
+ differently, and the alignments coverage band does.
246
+
247
+ ```js
248
+ // type signature
249
+ ({…}: { rules: readonly ScoreRule[]; domain: [number, number] | undefined; box: { yTop: number; yBottom: number; }; normalize: (score: number) => number; }) => ScoreRuleMark[]
250
+ ```
251
+
252
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scoreRuleMarks.ts)
253
+
254
+ ### visibleStatsDomain
255
+
256
+ The visible score domain four displays derive identically: walk the settled
257
+ blocks, accumulate the stats of what each one shows, and nice-round the
258
+ autoscaled range inside the configured bounds. `undefined` while there is
259
+ nothing to scale against — no data, a hidden band, or a view that has not
260
+ initialized — which every caller distinguishes from a domain.
261
+
262
+ ```js
263
+ // type signature
264
+ <Payload, Item, Stats>({ active, view, payloadFor, itemsFor, accumulate, range, bounds, scaleType, }: VisibleStatsDomainSpec<Payload, Item, Stats>) => [number, number] | undefined
265
+ ```
266
+
267
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/visibleStatsDomain.ts)
268
+
269
+ ### widenRangeToRules
270
+
271
+ Widens an autoscaled range so every configured rule stays on the axis.
272
+
273
+ Without this a rule silently disappears in exactly the window that makes it
274
+ worth having. Autoscale follows the visible data, so over a homozygous deletion
275
+ a coverage domain collapses to about `[0, 1]` and a rule at the diploid depth
276
+ falls outside it — and "2 copies would be up there" is the most informative
277
+ thing that view can say. The reader has no menu to check either: `scoreRules` is
278
+ set by whoever wrote the config, so a rule that vanishes leaves nothing behind
279
+ to notice.
280
+
281
+ Applied to the raw range, before `getNiceDomain` takes the `minScore` /
282
+ `maxScore` bounds. Those still win: a rule outside an explicitly bounded axis is
283
+ one the config asked not to be shown, and it drops as before.
284
+
285
+ ```js
286
+ // type signature
287
+ (range: [number, number], ruleValues: readonly number[]) => [number, number]
288
+ ```
289
+
290
+ [Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scoreRuleMarks.ts)
291
+
292
+ <!-- API_DOCS_END -->
@@ -0,0 +1,11 @@
1
+ import type { YScaleTicks } from './yScaleTicks.ts';
2
+ export declare function CrossHatchLines({ ticks, width, offsetY, }: {
3
+ ticks: YScaleTicks;
4
+ width: number;
5
+ offsetY?: number;
6
+ }): import("react").JSX.Element;
7
+ export default function CrossHatches({ ticks, width, height, }: {
8
+ ticks: YScaleTicks;
9
+ width: number;
10
+ height: number;
11
+ }): import("react").JSX.Element;
@@ -0,0 +1,32 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { clampStrokeInsideAxis } from './yScaleTicks.js';
3
+ // Bare <line> set for the Y-scale tick guide lines, no wrapping <svg>. Shared by
4
+ // the absolutely-positioned on-screen CrossHatches overlay and the flat SVG
5
+ // export (single- and multi-wiggle), so the three can't drift. `offsetY` shifts
6
+ // every line down for per-row rendering in multi-wiggle.
7
+ export function CrossHatchLines({ ticks, width, offsetY = 0, }) {
8
+ return (_jsx(_Fragment, { children: ticks.items.map(({ value, y }) => {
9
+ // Same clamp the axis ticks take, so a guide line and the tick it
10
+ // belongs to can't disagree at the bottom edge — where, in multi-wiggle,
11
+ // "one pixel lower" is the next sample's row. Only that edge moves; the
12
+ // guide lines don't crispen to a half pixel the way the axis does.
13
+ const lineY = offsetY + clampStrokeInsideAxis(y, ticks.yBottom);
14
+ return (_jsx("line", { x1: 0, x2: width, y1: lineY, y2: lineY, stroke: "rgb(200,200,200)",
15
+ // a separate stroke-opacity attribute (not baked into an rgba()
16
+ // string) survives the SVG export, whose renderToStaticMarkup strips
17
+ // rgba() alpha
18
+ strokeOpacity: 0.8, strokeWidth: 1 }, `${value}-${y}`));
19
+ }) }));
20
+ }
21
+ // Horizontal guide lines at each Y-scale tick. Pointer-events disabled so
22
+ // the underlying canvas still receives mouse events.
23
+ export default function CrossHatches({ ticks, width, height, }) {
24
+ return (_jsx("svg", { style: {
25
+ position: 'absolute',
26
+ top: 0,
27
+ left: 0,
28
+ pointerEvents: 'none',
29
+ height,
30
+ width,
31
+ }, children: _jsx(CrossHatchLines, { ticks: ticks, width: width }) }));
32
+ }
@@ -0,0 +1,17 @@
1
+ import type { MenuItem } from '@jbrowse/core/ui';
2
+ import type React from 'react';
3
+ interface ResolutionStepperState {
4
+ label: string;
5
+ finerDisabled: boolean;
6
+ coarserDisabled: boolean;
7
+ resetDisabled: boolean;
8
+ }
9
+ export declare function makeResolutionSubMenuItem(opts: {
10
+ getState: () => ResolutionStepperState;
11
+ onFiner: () => void;
12
+ onCoarser: () => void;
13
+ onReset: () => void;
14
+ icon?: React.ElementType;
15
+ resetTitle?: string;
16
+ }): MenuItem;
17
+ export {};
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { INLINE_MENU_ROW_WIDTH, ResetToDefaultButton } from '@jbrowse/core/ui';
3
+ import { makeStyles } from '@jbrowse/core/util/tss-react';
4
+ import { Button, Typography } from '@mui/material';
5
+ import { observer } from 'mobx-react';
6
+ const useStyles = makeStyles()(theme => ({
7
+ row: {
8
+ display: 'flex',
9
+ alignItems: 'center',
10
+ gap: theme.spacing(0.5),
11
+ width: INLINE_MENU_ROW_WIDTH,
12
+ },
13
+ // subtle text buttons: no uppercase, minimal padding, inherit text color so
14
+ // "Coarser"/"Finer" read as quiet affordances rather than prominent CTAs
15
+ step: {
16
+ textTransform: 'none',
17
+ minWidth: 0,
18
+ padding: '0 4px',
19
+ },
20
+ value: {
21
+ flex: 1,
22
+ textAlign: 'center',
23
+ },
24
+ }));
25
+ // Subtle inline stepper: [−] label [+] [reset]. The −/+ icon buttons let the
26
+ // user step finer/coarser repeatedly without reopening the menu. Shared by the
27
+ // wiggle binning multiplier and the Hi-C matrix binsize, which differ only in
28
+ // how they format the label and bound the steps.
29
+ const ResolutionStepper = observer(function ResolutionStepper({ getState, onFiner, onCoarser, onReset, resetTitle, }) {
30
+ const { classes } = useStyles();
31
+ const { label, finerDisabled, coarserDisabled, resetDisabled } = getState();
32
+ return (_jsxs("div", { className: classes.row, children: [_jsx(Button, { className: classes.step, size: "small", color: "inherit", disabled: coarserDisabled, onClick: () => {
33
+ onCoarser();
34
+ }, children: "Coarser" }), _jsx(Typography, { variant: "caption", color: "textSecondary", className: classes.value, children: label }), _jsx(Button, { className: classes.step, size: "small", color: "inherit", disabled: finerDisabled, onClick: () => {
35
+ onFiner();
36
+ }, children: "Finer" }), _jsx(ResetToDefaultButton, { title: resetTitle, disabled: resetDisabled, onClick: () => {
37
+ onReset();
38
+ } })] }));
39
+ });
40
+ // A "Resolution" submenu whose single row is the inline stepper, so it sits
41
+ // alongside the other track-menu submenus but keeps the menu open while
42
+ // stepping. Callers own the label formatting, step bounds, and step actions.
43
+ export function makeResolutionSubMenuItem(opts) {
44
+ const { getState, onFiner, onCoarser, onReset, icon, resetTitle } = opts;
45
+ return {
46
+ label: 'Resolution',
47
+ icon,
48
+ subMenu: [
49
+ {
50
+ label: 'Resolution stepper',
51
+ type: 'custom',
52
+ render: () => (_jsx(ResolutionStepper, { getState: getState, onFiner: onFiner, onCoarser: onCoarser, onReset: onReset, resetTitle: resetTitle })),
53
+ },
54
+ ],
55
+ };
56
+ }
@@ -0,0 +1,11 @@
1
+ import type { ScoreRuleMark } from './scoreRuleMarks.ts';
2
+ export declare function ScoreRuleLines({ marks, width, offsetY, }: {
3
+ marks: ScoreRuleMark[];
4
+ width: number;
5
+ offsetY?: number;
6
+ }): import("react").JSX.Element;
7
+ export default function ScoreRules({ marks, width, height, }: {
8
+ marks: ScoreRuleMark[];
9
+ width: number;
10
+ height: number;
11
+ }): import("react").JSX.Element;
@@ -0,0 +1,37 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { usePalette } from '@jbrowse/core/ui/PaletteContext';
3
+ const DEFAULT_RULE_COLOR = 'rgb(120,120,120)';
4
+ // Bare marks, no wrapping <svg>, so the on-screen overlay and the SVG export
5
+ // draw the same elements from the same y. Same split as CrossHatchLines.
6
+ export function ScoreRuleLines({ marks, width, offsetY = 0, }) {
7
+ // A caption sits over the plot, not beside it, so it needs the halo the tick
8
+ // labels next to it already draw (YScaleBar) — without one a rule crossing
9
+ // filled bars captions itself in grey on the fill and cannot be read. From
10
+ // the palette rather than a hardcoded white, which inverts into a glare in
11
+ // dark mode.
12
+ const haloColor = usePalette().background.default;
13
+ return (_jsx(_Fragment, { children: marks.map(({ value, label, color, y }) => {
14
+ const lineY = offsetY + y;
15
+ const stroke = color ?? DEFAULT_RULE_COLOR;
16
+ return (_jsxs("g", { children: [_jsx("line", { x1: 0, x2: width, y1: lineY, y2: lineY, stroke: stroke,
17
+ // separate attribute rather than an rgba() string: the SVG
18
+ // export's renderToStaticMarkup strips rgba() alpha
19
+ strokeOpacity: 0.9, strokeWidth: 1, strokeDasharray: "4 3" }), label ? (_jsx("text", { x: width - 4, y: lineY - 2, textAnchor: "end", fontSize: 10,
20
+ // full alpha, unlike the line: 0.9 is there to let the rule
21
+ // recede into the plot, and a caption that has to be read wants
22
+ // the opposite
23
+ fill: stroke, stroke: haloColor, strokeWidth: 2.5, paintOrder: "stroke", children: label })) : null] }, `${value}-${y}`));
24
+ }) }));
25
+ }
26
+ // Pointer-events disabled so the canvas underneath still gets mouse events,
27
+ // matching CrossHatches.
28
+ export default function ScoreRules({ marks, width, height, }) {
29
+ return (_jsx("svg", { style: {
30
+ position: 'absolute',
31
+ top: 0,
32
+ left: 0,
33
+ pointerEvents: 'none',
34
+ height,
35
+ width,
36
+ }, children: _jsx(ScoreRuleLines, { marks: marks, width: width }) }));
37
+ }