@jbrowse/wiggle-core 4.3.0 → 5.0.0-beta.10

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 (73) hide show
  1. package/README.md +76 -107
  2. package/esm/AutoscaleGroupDialog.d.ts +7 -0
  3. package/esm/AutoscaleGroupDialog.js +26 -0
  4. package/esm/ScoreAxisMixin.d.ts +134 -0
  5. package/esm/ScoreAxisMixin.js +213 -0
  6. package/esm/ScoreFieldConfigMixin.d.ts +72 -0
  7. package/esm/ScoreFieldConfigMixin.js +25 -0
  8. package/esm/ScorePlotChrome.d.ts +45 -0
  9. package/esm/ScorePlotChrome.js +47 -0
  10. package/esm/ScorePlotSvgFrame.d.ts +27 -0
  11. package/esm/ScorePlotSvgFrame.js +23 -0
  12. package/esm/ScoreScaleMixin.d.ts +113 -50
  13. package/esm/ScoreScaleMixin.js +148 -70
  14. package/esm/SetMinMaxDialog.d.ts +3 -2
  15. package/esm/SetMinMaxDialog.js +20 -6
  16. package/esm/SetScoreRulesDialog.d.ts +14 -0
  17. package/esm/SetScoreRulesDialog.js +45 -0
  18. package/esm/WiggleScoreConfigMixin.d.ts +89 -0
  19. package/esm/WiggleScoreConfigMixin.js +54 -0
  20. package/esm/autoscale.d.ts +54 -14
  21. package/esm/autoscale.js +105 -180
  22. package/esm/autoscaleGroup.d.ts +30 -0
  23. package/esm/autoscaleGroup.js +97 -0
  24. package/esm/chrome.d.ts +5 -0
  25. package/esm/chrome.js +7 -0
  26. package/esm/computeYTicks.d.ts +1 -1
  27. package/esm/computeYTicks.js +4 -3
  28. package/esm/constants.d.ts +1 -2
  29. package/esm/constants.js +1 -10
  30. package/esm/dataTypes.d.ts +4 -6
  31. package/esm/displayModel.d.ts +1 -2
  32. package/esm/gapBreak.d.ts +2 -3
  33. package/esm/gapBreak.js +2 -3
  34. package/esm/index.d.ts +24 -25
  35. package/esm/index.js +20 -18
  36. package/esm/normalize.d.ts +1 -26
  37. package/esm/normalize.js +1 -86
  38. package/esm/pointMarker.d.ts +7 -2
  39. package/esm/pointMarker.js +14 -18
  40. package/esm/pointSizeMenu.d.ts +30 -11
  41. package/esm/pointSizeMenu.js +42 -19
  42. package/esm/renderingBackendTypes.d.ts +13 -4
  43. package/esm/renderingBackendTypes.js +4 -1
  44. package/esm/rowLabelOffset.d.ts +8 -0
  45. package/esm/rowLabelOffset.js +16 -0
  46. package/esm/scale.d.ts +12 -8
  47. package/esm/scale.js +27 -14
  48. package/esm/scoreFieldConfigSchemaFields.d.ts +10 -0
  49. package/esm/scoreFieldConfigSchemaFields.js +8 -0
  50. package/esm/scoreMenuItems.d.ts +35 -16
  51. package/esm/scoreMenuItems.js +95 -62
  52. package/esm/scoreRuleMarks.d.ts +14 -39
  53. package/esm/scoreRuleMarks.js +12 -45
  54. package/esm/transferables.js +4 -9
  55. package/esm/valueScaleConfigSchema.d.ts +253 -0
  56. package/esm/valueScaleConfigSchema.js +270 -0
  57. package/esm/visibleStatsDomain.d.ts +20 -8
  58. package/esm/visibleStatsDomain.js +32 -27
  59. package/esm/wiggleRenderModes.generated.d.ts +1 -2
  60. package/esm/wiggleRenderModes.generated.js +1 -2
  61. package/package.json +14 -9
  62. package/esm/CrossHatches.d.ts +0 -11
  63. package/esm/CrossHatches.js +0 -32
  64. package/esm/ScoreRules.d.ts +0 -11
  65. package/esm/ScoreRules.js +0 -37
  66. package/esm/YScaleBar.d.ts +0 -6
  67. package/esm/YScaleBar.js +0 -46
  68. package/esm/YScaleBarOverlay.d.ts +0 -6
  69. package/esm/YScaleBarOverlay.js +0 -24
  70. package/esm/scoreAxisConfigSchemaFields.d.ts +0 -44
  71. package/esm/scoreAxisConfigSchemaFields.js +0 -54
  72. package/esm/yScaleTicks.d.ts +0 -59
  73. package/esm/yScaleTicks.js +0 -59
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@jbrowse/wiggle-core",
3
- "version": "4.3.0",
3
+ "version": "5.0.0-beta.10",
4
4
  "type": "module",
5
- "description": "Shared scale and autoscale utilities for wiggle and coverage displays",
5
+ "description": "Score-axis scale, autoscale, config mixins and plot chrome shared by wiggle, Manhattan, mark and coverage displays",
6
6
  "keywords": [
7
7
  "jbrowse",
8
8
  "jbrowse2",
@@ -21,20 +21,25 @@
21
21
  "main": "esm/index.js",
22
22
  "exports": {
23
23
  ".": "./esm/index.js",
24
+ "./ScorePlotChrome": "./esm/ScorePlotChrome.js",
25
+ "./ScorePlotSvgFrame": "./esm/ScorePlotSvgFrame.js",
26
+ "./chrome": "./esm/chrome.js",
24
27
  "./constants": "./esm/constants.js",
25
- "./normalize": "./esm/normalize.js"
28
+ "./normalize": "./esm/normalize.js",
29
+ "./renderingBackendTypes": "./esm/renderingBackendTypes.js"
26
30
  },
27
31
  "files": [
28
32
  "esm"
29
33
  ],
30
34
  "dependencies": {
31
- "@jbrowse/mobx-state-tree": "^6.5.1",
32
- "@mui/icons-material": "^9.3.1",
33
- "@mui/material": "^9.3.1",
35
+ "@jbrowse/mobx-state-tree": "^6.6.1",
36
+ "@mui/icons-material": "^9.4.0",
37
+ "@mui/material": "^9.4.0",
34
38
  "mobx-react": "^10.0.2",
35
- "@jbrowse/core": "^4.3.0",
36
- "@jbrowse/display-kit": "^4.3.0",
37
- "@jbrowse/render-core": "^4.3.0"
39
+ "@jbrowse/core": "^5.0.0-beta.10",
40
+ "@jbrowse/display-kit": "^5.0.0-beta.10",
41
+ "@jbrowse/display-ui": "^5.0.0-beta.10",
42
+ "@jbrowse/render-core": "^5.0.0-beta.10"
38
43
  },
39
44
  "peerDependencies": {
40
45
  "react": ">=19.0.0"
@@ -1,11 +0,0 @@
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;
@@ -1,32 +0,0 @@
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
- }
@@ -1,11 +0,0 @@
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;
package/esm/ScoreRules.js DELETED
@@ -1,37 +0,0 @@
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
- }
@@ -1,6 +0,0 @@
1
- import type { YScaleTicks } from './yScaleTicks.ts';
2
- export default function YScaleBar({ ticks, orientation, insetLabels, }: {
3
- ticks: YScaleTicks | undefined;
4
- orientation?: 'left' | 'right';
5
- insetLabels?: boolean;
6
- }): import("react").JSX.Element | null;
package/esm/YScaleBar.js DELETED
@@ -1,46 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { usePalette } from '@jbrowse/core/ui/PaletteContext';
3
- import { clampStrokeInsideAxis } from './yScaleTicks.js';
4
- // Not an `observer`, and deliberately: there is nothing here to observe. Every
5
- // caller already reads `model.ticks` inside its own observer and hands the
6
- // resolved plain object down, and `usePalette` is a React context, not MobX.
7
- // Wrapping it anyway allocated a Reaction per instance — multi-wiggle renders
8
- // one per sample row, on screen as well as in export — and, per CLAUDE.md, put
9
- // the component out of `babel-plugin-react-compiler`'s reach, so it got neither
10
- // the MobX tracking it doesn't need nor the memoization it does. Its sibling
11
- // `CrossHatchLines`, consuming the same ticks, is already plain.
12
- // Half the vertical space a 10px label needs, halo included: digits reach about
13
- // 3.6px above the centered baseline and the 2.5px-wide background stroke another
14
- // 1.25px past that.
15
- const LABEL_HALF_HEIGHT_PX = 5;
16
- export default function YScaleBar({ ticks, orientation, insetLabels, }) {
17
- const palette = usePalette();
18
- if (!ticks) {
19
- return null;
20
- }
21
- const { items, yTop, yBottom } = ticks;
22
- const bg = palette.background.default;
23
- const fg = palette.text.primary;
24
- const isLeft = orientation !== 'right';
25
- const k = isLeft ? -1 : 1;
26
- const tickLength = 6;
27
- // Crispen to `y + 0.5` so each 1px stroke fills one pixel instead of
28
- // straddling two, then clamp, which only bites at the bottom edge: there the
29
- // stroke goes on the last pixel inside the box rather than the first one
30
- // below it.
31
- const strokeY = (y) => clampStrokeInsideAxis(y + 0.5, yBottom);
32
- // The tick keeps the group transform; only the text moves off it, and only
33
- // under `insetLabels` within half a label of an end. A tick is where the data
34
- // is, so it never moves — the label is then drawn against the tick rather than
35
- // across it, which is what any axis does at the edge of its own frame.
36
- // `undefined` rather than 0 for the labels that don't move, so the markup this
37
- // emits is unchanged wherever the inset doesn't apply.
38
- const labelDy = (sy) => {
39
- if (!insetLabels) {
40
- return undefined;
41
- }
42
- const inset = Math.min(Math.max(sy, yTop + LABEL_HALF_HEIGHT_PX), yBottom - LABEL_HALF_HEIGHT_PX);
43
- return inset === sy ? undefined : inset - sy;
44
- };
45
- return (_jsxs("g", { fontSize: 10, textAnchor: isLeft ? 'end' : 'start', stroke: fg, strokeWidth: 1, children: [_jsx("path", { fill: "none", d: `M${k * tickLength} ${strokeY(yTop)}H0.5V${strokeY(yBottom)}H${k * tickLength}` }), items.map(({ value, y, label }) => (_jsxs("g", { transform: `translate(0,${strokeY(y)})`, children: [_jsx("line", { x2: k * tickLength }), _jsx("text", { stroke: bg, strokeWidth: 2.5, paintOrder: "stroke", fill: fg, y: labelDy(strokeY(y)), dy: "0.32em", x: k * 9, children: label ?? value })] }, `${value}-${y}`)))] }));
46
- }
@@ -1,6 +0,0 @@
1
- import type { YScaleTicks } from './yScaleTicks.ts';
2
- export default function YScaleBarOverlay({ ticks, height, width, }: {
3
- ticks: YScaleTicks;
4
- height: number;
5
- width: number;
6
- }): import("react").JSX.Element;
@@ -1,24 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import YScaleBar from './YScaleBar.js';
3
- import { ONSCREEN_AXIS_LEFT_PX } from './constants.js';
4
- // Y-axis tick labels positioned absolutely, indented from the track's left edge
5
- // so a right-oriented axis reads inside the plot. The SVG export instead anchors
6
- // a left-oriented axis at the content edge, putting the labels in the export
7
- // margin — see WiggleFamilySvgFrame.
8
- //
9
- // `width` is the track's, not a fixed strip: an <svg> clips to its own box, and
10
- // the hardcoded 70px this used to carry silently truncated any label past ~11
11
- // characters. Not hypothetical on a log axis — a domain under 1 nices to
12
- // negative powers of two, so `0.0009765625` is an ordinary tick on a
13
- // mappability track and the labels grow exactly where the numbers get small.
14
- // The track's own right edge is the real boundary.
15
- export default function YScaleBarOverlay({ ticks, height, width, }) {
16
- return (_jsx("svg", { style: {
17
- position: 'absolute',
18
- top: 0,
19
- left: ONSCREEN_AXIS_LEFT_PX,
20
- pointerEvents: 'none',
21
- height,
22
- width: Math.max(0, width - ONSCREEN_AXIS_LEFT_PX),
23
- }, children: _jsx(YScaleBar, { ticks: ticks, orientation: "right" }) }));
24
- }
@@ -1,44 +0,0 @@
1
- import type { ConfigModelForFields } from '@jbrowse/core/configuration';
2
- export declare const scoreAxisConfigSchemaFields: {
3
- readonly minScore: {
4
- readonly type: 'number';
5
- readonly defaultValue: number;
6
- readonly description: 'Fixed minimum score bound. The default (Number.MIN_VALUE) is a sentinel meaning "unset, use autoscale"';
7
- readonly advanced: true;
8
- };
9
- readonly maxScore: {
10
- readonly type: 'number';
11
- readonly defaultValue: number;
12
- readonly description: 'Fixed maximum score bound. The default (Number.MAX_VALUE) is a sentinel meaning "unset, use autoscale"';
13
- readonly advanced: true;
14
- };
15
- readonly scaleType: {
16
- readonly type: 'stringEnum';
17
- readonly model: import("@jbrowse/mobx-state-tree").ISimpleType<"linear" | "log">;
18
- readonly defaultValue: 'linear';
19
- readonly description: 'Scale type (linear or log)';
20
- };
21
- readonly autoscale: {
22
- readonly type: 'stringEnum';
23
- readonly model: import("@jbrowse/mobx-state-tree").ISimpleType<"local" | "localpercentile" | "localsd">;
24
- readonly defaultValue: 'localpercentile';
25
- readonly description: 'Autoscale type: "local" uses the min/max in the visible region, "localsd" uses mean ± numStdDev standard deviations, "localpercentile" uses the numQuantile-th percentile score as the max (robust to skewed/peaky data)';
26
- };
27
- readonly numStdDev: {
28
- readonly type: 'number';
29
- readonly defaultValue: 3;
30
- readonly description: 'Number of standard deviations to use for the localsd autoscale type';
31
- readonly advanced: true;
32
- };
33
- readonly displayCrossHatches: {
34
- readonly type: 'boolean';
35
- readonly defaultValue: false;
36
- readonly description: 'Rule the score axis with horizontal cross hatches at the tick positions — the config form of the score menu\'s "Show cross hatches". Ignored by the density rendering types, which spend color rather than height on the score and so have no axis to rule';
37
- };
38
- };
39
- /**
40
- * What `ScoreScaleMixin` asks a composing display's `configuration` to be — the
41
- * slots above and nothing else, which is all the mixin touches. Narrow so
42
- * `getConf`/`setConf` still check the slot name; see `ConfigModelForFields`.
43
- */
44
- export type ScoreAxisConfigModel = ConfigModelForFields<typeof scoreAxisConfigSchemaFields>;
@@ -1,54 +0,0 @@
1
- import { types } from '@jbrowse/mobx-state-tree';
2
- // The score AXIS alone: exactly the slots `ScoreScaleMixin` reads, and nothing
3
- // else. Split out of `wiggleConfigSchemaFields` below so a display with a score
4
- // axis but none of wiggle's palette/rendering vocabulary can declare the axis
5
- // without inheriting the rest — LinearManhattanDisplay used to extend the whole
6
- // wiggle display schema and advertised twelve slots that did nothing on a GWAS
7
- // track.
8
- //
9
- // `numQuantile` is deliberately NOT here even though `autoscale` names
10
- // `localpercentile`: it is read by the autoscale *computation*
11
- // (`WiggleCommonMixin`), which only the wiggle displays run.
12
- export const scoreAxisConfigSchemaFields = {
13
- minScore: {
14
- type: 'number',
15
- defaultValue: Number.MIN_VALUE,
16
- description: 'Fixed minimum score bound. The default (Number.MIN_VALUE) is a sentinel meaning "unset, use autoscale"',
17
- advanced: true,
18
- },
19
- maxScore: {
20
- type: 'number',
21
- defaultValue: Number.MAX_VALUE,
22
- description: 'Fixed maximum score bound. The default (Number.MAX_VALUE) is a sentinel meaning "unset, use autoscale"',
23
- advanced: true,
24
- },
25
- // #region stringEnumSlot
26
- scaleType: {
27
- type: 'stringEnum',
28
- model: types.enumeration('Scale type', ['linear', 'log']),
29
- defaultValue: 'linear',
30
- description: 'Scale type (linear or log)',
31
- },
32
- // #endregion
33
- autoscale: {
34
- type: 'stringEnum',
35
- model: types.enumeration('Autoscale type', [
36
- 'local',
37
- 'localsd',
38
- 'localpercentile',
39
- ]),
40
- defaultValue: 'localpercentile',
41
- description: 'Autoscale type: "local" uses the min/max in the visible region, "localsd" uses mean ± numStdDev standard deviations, "localpercentile" uses the numQuantile-th percentile score as the max (robust to skewed/peaky data)',
42
- },
43
- numStdDev: {
44
- type: 'number',
45
- defaultValue: 3,
46
- description: 'Number of standard deviations to use for the localsd autoscale type',
47
- advanced: true,
48
- },
49
- displayCrossHatches: {
50
- type: 'boolean',
51
- defaultValue: false,
52
- description: 'Rule the score axis with horizontal cross hatches at the tick positions — the config form of the score menu\'s "Show cross hatches". Ignored by the density rendering types, which spend color rather than height on the score and so have no axis to rule',
53
- },
54
- };
@@ -1,59 +0,0 @@
1
- export interface YScaleTicks {
2
- items: {
3
- value: number;
4
- y: number;
5
- label?: string;
6
- }[];
7
- yTop: number;
8
- yBottom: number;
9
- }
10
- /**
11
- * The plot box a wiggle-family display insets inside its own height, for both
12
- * sides of the contract above: the renderer positions its canvas at `yTop` and
13
- * draws `plotHeight` tall, and the axis puts domain-max at `yTop` and
14
- * domain-min at `yBottom`.
15
- *
16
- * One function because the two have to agree exactly, and `height - 2 * offset`
17
- * spelled out at each end is how they stopped: `computeYTicks` derived its own
18
- * bottom as `height - offset - 1`, and every tick above it inherited a fraction
19
- * of that pixel.
20
- */
21
- export declare function axisPlotBox(height: number, offset?: number): {
22
- yTop: number;
23
- yBottom: number;
24
- plotHeight: number;
25
- };
26
- /**
27
- * Screen y for an already-normalized ([0,1], 0 at domain-min) score. The
28
- * composition of {@link axisPlotBox} with a `makeScoreNormalizer` result, which
29
- * is what a tick at that score must land on.
30
- */
31
- export declare function scoreToAxisY(normalized: number, box: ReturnType<typeof axisPlotBox>): number;
32
- /**
33
- * Width of the gutter a left-oriented {@link YScaleBar} is drawn in, and the x
34
- * inside that gutter its spine goes at.
35
- *
36
- * `YScaleBar` grows its ticks and numbers *away* from the spine, so a
37
- * left-oriented axis has to inset its spine by the label width or the labels
38
- * land at negative x — which is what once put an exported coverage axis off the
39
- * image entirely. Both numbers live here, beside the component whose own
40
- * geometry (`x = ±9`, `fontSize 10`, `textAnchor: end`) is what makes them the
41
- * right ones: the alignments coverage axis and the MAF band axes had each
42
- * arrived at this same 50/45 pair independently, so a change to the labels moved
43
- * neither.
44
- *
45
- * An axis drawn over its own plot rather than in reserved space may narrow the
46
- * gutter — every px of it is a px of data hidden. Such an axis still places its
47
- * spine at `width - 1`, the same rule stated against its own width.
48
- */
49
- export declare const AXIS_GUTTER_WIDTH_PX = 50;
50
- export declare function leftAxisSpineX(gutterLeft?: number): number;
51
- /**
52
- * Keep a 1px stroke's center inside the axis box. At `yBottom` — the box's own
53
- * bottom edge — the stroke has to cover the pixel *above* the boundary, since
54
- * the one below belongs to whatever is drawn next; in multi-wiggle, where rows
55
- * stack edge to edge, that is literally the next sample's first row of pixels.
56
- * Callers pass whatever stroke center their own convention gives (the axis
57
- * crispens to `y + 0.5`, the guide lines don't); only the bottom edge moves.
58
- */
59
- export declare function clampStrokeInsideAxis(strokeY: number, yBottom: number): number;
@@ -1,59 +0,0 @@
1
- import { YSCALEBAR_LABEL_OFFSET } from './constants.js';
2
- /**
3
- * The plot box a wiggle-family display insets inside its own height, for both
4
- * sides of the contract above: the renderer positions its canvas at `yTop` and
5
- * draws `plotHeight` tall, and the axis puts domain-max at `yTop` and
6
- * domain-min at `yBottom`.
7
- *
8
- * One function because the two have to agree exactly, and `height - 2 * offset`
9
- * spelled out at each end is how they stopped: `computeYTicks` derived its own
10
- * bottom as `height - offset - 1`, and every tick above it inherited a fraction
11
- * of that pixel.
12
- */
13
- export function axisPlotBox(height, offset = YSCALEBAR_LABEL_OFFSET) {
14
- return {
15
- yTop: offset,
16
- yBottom: height - offset,
17
- plotHeight: height - 2 * offset,
18
- };
19
- }
20
- /**
21
- * Screen y for an already-normalized ([0,1], 0 at domain-min) score. The
22
- * composition of {@link axisPlotBox} with a `makeScoreNormalizer` result, which
23
- * is what a tick at that score must land on.
24
- */
25
- export function scoreToAxisY(normalized, box) {
26
- return box.yTop + (1 - normalized) * box.plotHeight;
27
- }
28
- /**
29
- * Width of the gutter a left-oriented {@link YScaleBar} is drawn in, and the x
30
- * inside that gutter its spine goes at.
31
- *
32
- * `YScaleBar` grows its ticks and numbers *away* from the spine, so a
33
- * left-oriented axis has to inset its spine by the label width or the labels
34
- * land at negative x — which is what once put an exported coverage axis off the
35
- * image entirely. Both numbers live here, beside the component whose own
36
- * geometry (`x = ±9`, `fontSize 10`, `textAnchor: end`) is what makes them the
37
- * right ones: the alignments coverage axis and the MAF band axes had each
38
- * arrived at this same 50/45 pair independently, so a change to the labels moved
39
- * neither.
40
- *
41
- * An axis drawn over its own plot rather than in reserved space may narrow the
42
- * gutter — every px of it is a px of data hidden. Such an axis still places its
43
- * spine at `width - 1`, the same rule stated against its own width.
44
- */
45
- export const AXIS_GUTTER_WIDTH_PX = 50;
46
- export function leftAxisSpineX(gutterLeft = 0) {
47
- return gutterLeft + AXIS_GUTTER_WIDTH_PX - YSCALEBAR_LABEL_OFFSET;
48
- }
49
- /**
50
- * Keep a 1px stroke's center inside the axis box. At `yBottom` — the box's own
51
- * bottom edge — the stroke has to cover the pixel *above* the boundary, since
52
- * the one below belongs to whatever is drawn next; in multi-wiggle, where rows
53
- * stack edge to edge, that is literally the next sample's first row of pixels.
54
- * Callers pass whatever stroke center their own convention gives (the axis
55
- * crispens to `y + 0.5`, the guide lines don't); only the bottom edge moves.
56
- */
57
- export function clampStrokeInsideAxis(strokeY, yBottom) {
58
- return Math.min(strokeY, yBottom - 0.5);
59
- }