@genome-spy/core 0.57.0 → 0.58.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 (50) hide show
  1. package/dist/bundle/index-BftNdA0O.js +27 -0
  2. package/dist/bundle/index-C08YCM2T.js +539 -0
  3. package/dist/bundle/{index-C159nEYc.js → index-CCJIjehY.js} +89 -83
  4. package/dist/bundle/index-CalimFw3.js +2131 -0
  5. package/dist/bundle/index-DS2hvLgl.js +3425 -0
  6. package/dist/bundle/index-DTcHjAHp.js +505 -0
  7. package/dist/bundle/{index-CfEH2hsw.js → index-Dec7VcMU.js} +25 -25
  8. package/dist/bundle/index-DnIkxb0L.js +1025 -0
  9. package/dist/bundle/{index-Bg62fPK7.js → index-DwLfOHEk.js} +435 -465
  10. package/dist/bundle/{index-DhPRJZz0.js → index-Ww3TAo6_.js} +7 -7
  11. package/dist/bundle/{index-DutovjI-.js → index-vgGDWUPz.js} +2 -2
  12. package/dist/bundle/index.es.js +3634 -4808
  13. package/dist/bundle/index.js +136 -134
  14. package/dist/bundle/long-BviWyoZx.js +2387 -0
  15. package/dist/bundle/{remoteFile-DwSeXAZ0.js → remoteFile-BuaqFGWk.js} +1 -1
  16. package/dist/schema.json +66 -0
  17. package/dist/src/data/sources/dataSourceFactory.d.ts +2 -1
  18. package/dist/src/data/sources/dataSourceFactory.d.ts.map +1 -1
  19. package/dist/src/data/sources/dataSourceFactory.js +11 -0
  20. package/dist/src/data/sources/lazy/bamSource.js +7 -7
  21. package/dist/src/data/sources/lazy/gff3Source.d.ts +3 -5
  22. package/dist/src/data/sources/lazy/gff3Source.d.ts.map +1 -1
  23. package/dist/src/data/sources/lazy/gff3Source.js +7 -13
  24. package/dist/src/data/sources/lazy/tabixSource.d.ts +5 -0
  25. package/dist/src/data/sources/lazy/tabixSource.d.ts.map +1 -1
  26. package/dist/src/data/sources/lazy/tabixSource.js +20 -7
  27. package/dist/src/data/sources/lazy/vcfSource.d.ts +9 -0
  28. package/dist/src/data/sources/lazy/vcfSource.d.ts.map +1 -0
  29. package/dist/src/data/sources/lazy/vcfSource.js +38 -0
  30. package/dist/src/data/sources/lazy/vcfTypes.d.ts +7 -0
  31. package/dist/src/encoder/accessor.js +2 -2
  32. package/dist/src/genomeSpy.d.ts.map +1 -1
  33. package/dist/src/genomeSpy.js +20 -0
  34. package/dist/src/marks/rule.js +1 -1
  35. package/dist/src/spec/data.d.ts +14 -1
  36. package/dist/src/styles/genome-spy.css.d.ts +1 -1
  37. package/dist/src/styles/genome-spy.css.js +1 -1
  38. package/dist/src/styles/genome-spy.scss +1 -1
  39. package/dist/src/tooltip/dataTooltipHandler.js +32 -12
  40. package/dist/src/types/viewContext.d.ts +8 -0
  41. package/dist/src/utils/expression.d.ts.map +1 -1
  42. package/dist/src/utils/expression.js +7 -0
  43. package/dist/src/view/scaleResolution.d.ts.map +1 -1
  44. package/dist/src/view/scaleResolution.js +13 -0
  45. package/package.json +9 -8
  46. package/dist/bundle/index-CubKalvr.js +0 -500
  47. package/dist/bundle/index-DNzxWHJt.js +0 -2136
  48. package/dist/bundle/index-DluFz_0j.js +0 -1042
  49. package/dist/bundle/index-Dpv0n-cZ.js +0 -3998
  50. package/dist/bundle/long-DM5IWGqg.js +0 -2375
@@ -1,4 +1,4 @@
1
- import { b as d } from "./index-DluFz_0j.js";
1
+ import { b as d } from "./index-BftNdA0O.js";
2
2
  function u(n) {
3
3
  return (typeof n == "object" && n !== null && "message" in n ? n.message : `${n}`).replace(/\.$/, "");
4
4
  }
package/dist/schema.json CHANGED
@@ -2905,6 +2905,13 @@
2905
2905
  "Gff3Data": {
2906
2906
  "additionalProperties": false,
2907
2907
  "properties": {
2908
+ "addChrPrefix": {
2909
+ "description": "Add a `chr` (boolean) or custom (string) prefix to the chromosome names in the Tabix file.\n\n__Default value:__ `false`",
2910
+ "type": [
2911
+ "boolean",
2912
+ "string"
2913
+ ]
2914
+ },
2908
2915
  "channel": {
2909
2916
  "$ref": "#/definitions/PrimaryPositionalChannel",
2910
2917
  "description": "Which channel's scale domain to monitor.\n\n__Default value:__ `\"x\"`"
@@ -3654,6 +3661,9 @@
3654
3661
  },
3655
3662
  {
3656
3663
  "$ref": "#/definitions/Gff3Data"
3664
+ },
3665
+ {
3666
+ "$ref": "#/definitions/VcfData"
3657
3667
  }
3658
3668
  ]
3659
3669
  },
@@ -8821,6 +8831,62 @@
8821
8831
  ],
8822
8832
  "type": "object"
8823
8833
  },
8834
+ "VcfData": {
8835
+ "additionalProperties": false,
8836
+ "properties": {
8837
+ "addChrPrefix": {
8838
+ "description": "Add a `chr` (boolean) or custom (string) prefix to the chromosome names in the Tabix file.\n\n__Default value:__ `false`",
8839
+ "type": [
8840
+ "boolean",
8841
+ "string"
8842
+ ]
8843
+ },
8844
+ "channel": {
8845
+ "$ref": "#/definitions/PrimaryPositionalChannel",
8846
+ "description": "Which channel's scale domain to monitor.\n\n__Default value:__ `\"x\"`"
8847
+ },
8848
+ "debounce": {
8849
+ "anyOf": [
8850
+ {
8851
+ "type": "number"
8852
+ },
8853
+ {
8854
+ "$ref": "#/definitions/ExprRef"
8855
+ }
8856
+ ],
8857
+ "description": "Debounce time for data updates, in milliseconds. Debouncing prevents excessive data updates when the user is zooming or panning around.\n\n__Default value:__ `200`"
8858
+ },
8859
+ "debounceMode": {
8860
+ "description": "The debounce mode for data updates. If set to `\"domain\"`, domain change events (panning and zooming) will be debounced. If set to `\"window\"`, the data fetches initiated by the changes to the visible window (or tile) will be debounced. If your data is small, the `\"window\"` is better as it will start fetching data while the user is still panning around, resulting in a shorter perceived latency.\n\n__Default value:__ `\"window\"`",
8861
+ "enum": [
8862
+ "domain",
8863
+ "window"
8864
+ ],
8865
+ "type": "string"
8866
+ },
8867
+ "indexUrl": {
8868
+ "description": "Url of the tabix index file.\n\n__Default value:__ `url` + `\".tbi\"`.",
8869
+ "type": "string"
8870
+ },
8871
+ "type": {
8872
+ "const": "vcf",
8873
+ "type": "string"
8874
+ },
8875
+ "url": {
8876
+ "description": "Url of the bgzip compressed file.",
8877
+ "type": "string"
8878
+ },
8879
+ "windowSize": {
8880
+ "description": "Size of each chunk when fetching the Tabix file. Data is only fetched when the length of the visible domain smaller than the window size.\n\n__Default value:__ `30000000`",
8881
+ "type": "number"
8882
+ }
8883
+ },
8884
+ "required": [
8885
+ "type",
8886
+ "url"
8887
+ ],
8888
+ "type": "object"
8889
+ },
8824
8890
  "ViewBackground": {
8825
8891
  "additionalProperties": false,
8826
8892
  "properties": {
@@ -2,7 +2,7 @@
2
2
  * @param {Partial<import("../../spec/data.js").Data>} params
3
3
  * @param {import("../../view/view.js").default} view
4
4
  */
5
- export default function createDataSource(params: Partial<import("../../spec/data.js").Data>, view: import("../../view/view.js").default): InlineSource | UrlSource | SequenceSource | AxisTickSource | AxisGenomeSource | IndexedFastaSource | BigWigSource | BigBedSource | BamSource | Gff3Source;
5
+ export default function createDataSource(params: Partial<import("../../spec/data.js").Data>, view: import("../../view/view.js").default): InlineSource | UrlSource | SequenceSource | AxisTickSource | AxisGenomeSource | IndexedFastaSource | BigWigSource | BigBedSource | BamSource | Gff3Source | VcfSource;
6
6
  import InlineSource from "./inlineSource.js";
7
7
  import UrlSource from "./urlSource.js";
8
8
  import SequenceSource from "./sequenceSource.js";
@@ -13,4 +13,5 @@ import BigWigSource from "./lazy/bigWigSource.js";
13
13
  import BigBedSource from "./lazy/bigBedSource.js";
14
14
  import BamSource from "./lazy/bamSource.js";
15
15
  import Gff3Source from "./lazy/gff3Source.js";
16
+ import VcfSource from "./lazy/vcfSource.js";
16
17
  //# sourceMappingURL=dataSourceFactory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dataSourceFactory.d.ts","sourceRoot":"","sources":["../../../../src/data/sources/dataSourceFactory.js"],"names":[],"mappings":"AAWA;;;GAGG;AACH,iDAHW,OAAO,CAAC,OAAO,oBAAoB,EAAE,IAAI,CAAC,QAC1C,OAAO,oBAAoB,EAAE,OAAO,6JAgB9C;yBA7B0C,mBAAmB;sBACzB,gBAAgB;2BACD,qBAAqB;2BAC9C,0BAA0B;6BACxB,4BAA4B;+BAC1B,8BAA8B;yBACpC,wBAAwB;yBACxB,wBAAwB;sBAC3B,qBAAqB;uBACpB,sBAAsB"}
1
+ {"version":3,"file":"dataSourceFactory.d.ts","sourceRoot":"","sources":["../../../../src/data/sources/dataSourceFactory.js"],"names":[],"mappings":"AAYA;;;GAGG;AACH,iDAHW,OAAO,CAAC,OAAO,oBAAoB,EAAE,IAAI,CAAC,QAC1C,OAAO,oBAAoB,EAAE,OAAO,yKAgB9C;yBA9B0C,mBAAmB;sBACzB,gBAAgB;2BACD,qBAAqB;2BAC9C,0BAA0B;6BACxB,4BAA4B;+BAC1B,8BAA8B;yBACpC,wBAAwB;yBACxB,wBAAwB;sBAC3B,qBAAqB;uBACpB,sBAAsB;sBACvB,qBAAqB"}
@@ -8,6 +8,7 @@ import BigWigSource from "./lazy/bigWigSource.js";
8
8
  import BigBedSource from "./lazy/bigBedSource.js";
9
9
  import BamSource from "./lazy/bamSource.js";
10
10
  import Gff3Source from "./lazy/gff3Source.js";
11
+ import VcfSource from "./lazy/vcfSource.js";
11
12
 
12
13
  /**
13
14
  * @param {Partial<import("../../spec/data.js").Data>} params
@@ -100,6 +101,14 @@ function isGff3Source(params) {
100
101
  return params?.type == "gff3";
101
102
  }
102
103
 
104
+ /**
105
+ * @param {import("../../spec/data.js").LazyDataParams} params
106
+ * @returns {params is import("../../spec/data.js").VcfData}
107
+ */
108
+ function isVcfSource(params) {
109
+ return params?.type == "vcf";
110
+ }
111
+
103
112
  /**
104
113
  * @param {import("../../spec/data.js").LazyDataParams} params
105
114
  * @param {import("../../view/view.js").default} view
@@ -119,6 +128,8 @@ function createLazyDataSource(params, view) {
119
128
  return new BamSource(params, view);
120
129
  } else if (isGff3Source(params)) {
121
130
  return new Gff3Source(params, view);
131
+ } else if (isVcfSource(params)) {
132
+ return new VcfSource(params, view);
122
133
  }
123
134
 
124
135
  throw new Error(
@@ -92,13 +92,13 @@ export default class BamSource extends SingleAxisWindowedSource {
92
92
  .then((records) =>
93
93
  records.map((record) => ({
94
94
  chrom: d.chrom,
95
- start: record.get("start"),
96
- end: record.get("end"),
97
- name: record.get("name"),
98
- MD: record.get("MD"),
99
- cigar: record.get("cigar"),
100
- mapq: record.get("mq"),
101
- strand: record.get("strand") === 1 ? "+" : "-",
95
+ start: record.start,
96
+ end: record.end,
97
+ name: record.name,
98
+ //MD: record.get("MD"),
99
+ cigar: record.CIGAR,
100
+ mapq: record.mq,
101
+ strand: record.strand === 1 ? "+" : "-",
102
102
  }))
103
103
  )
104
104
  );
@@ -2,11 +2,9 @@
2
2
  * @extends {TabixSource<import("@gmod/gff").GFF3Feature>}
3
3
  */
4
4
  export default class Gff3Source extends TabixSource<import("@gmod/gff").GFF3Feature> {
5
- /**
6
- * @param {import("../../../spec/data.js").TabixData} params
7
- * @param {import("../../../view/view.js").default} view
8
- */
9
- constructor(params: import("../../../spec/data.js").TabixData, view: import("../../../view/view.js").default);
5
+ constructor(params: import("../../../spec/data.js").TabixData, view: import("../../../view/view.js" /**
6
+ * @param {string[]} lines
7
+ */).default);
10
8
  /**
11
9
  * @param {string[]} lines
12
10
  */
@@ -1 +1 @@
1
- {"version":3,"file":"gff3Source.d.ts","sourceRoot":"","sources":["../../../../../src/data/sources/lazy/gff3Source.js"],"names":[],"mappings":"AAEA;;GAEG;AACH;IAII;;;OAGG;IACH,oBAHW,OAAO,uBAAuB,EAAE,SAAS,QACzC,OAAO,uBAAuB,EAAE,OAAO,EASjD;IAMD;;OAEG;IACH,sBAFW,MAAM,EAAE,OAUlB;;CACJ;wBAtCuB,kBAAkB"}
1
+ {"version":3,"file":"gff3Source.d.ts","sourceRoot":"","sources":["../../../../../src/data/sources/lazy/gff3Source.js"],"names":[],"mappings":"AAEA;;GAEG;AACH;+BAWU,uBAAuB,0BACQ,uBAGzC,CAAI;;OAEG;IAFH;;OAEG;IACH,sBAFW,MAAM,EAAE,OAUlB;;CACJ;wBAhCuB,kBAAkB"}
@@ -7,23 +7,17 @@ export default class Gff3Source extends TabixSource {
7
7
  /** @type {import("@gmod/gff").default} */
8
8
  #gff;
9
9
 
10
- /**
11
- * @param {import("../../../spec/data.js").TabixData} params
12
- * @param {import("../../../view/view.js").default} view
13
- */
14
- constructor(params, view) {
15
- super(params, view);
16
-
17
- import("@gmod/gff").then((gff) => {
18
- // TODO: Fix race condition
19
- this.#gff = gff.default;
20
- });
21
- }
22
-
23
10
  get label() {
24
11
  return "gff3Source";
25
12
  }
26
13
 
14
+ /**
15
+ * @param {string} header
16
+ */
17
+ async _handleHeader(header) {
18
+ this.#gff = (await import("@gmod/gff")).default;
19
+ }
20
+
27
21
  /**
28
22
  * @param {string[]} lines
29
23
  */
@@ -10,6 +10,11 @@ export default class TabixSource<T> extends SingleAxisWindowedSource {
10
10
  constructor(params: import("../../../spec/data.js").TabixData, view: import("../../../view/view.js").default);
11
11
  params: import("../../../spec/data.js").TabixData;
12
12
  initializedPromise: Promise<any>;
13
+ /**
14
+ * @param {string} header
15
+ * @protected
16
+ */
17
+ protected _handleHeader(header: string): Promise<void>;
13
18
  /**
14
19
  * @abstract
15
20
  * @protected
@@ -1 +1 @@
1
- {"version":3,"file":"tabixSource.d.ts","sourceRoot":"","sources":["../../../../../src/data/sources/lazy/tabixSource.js"],"names":[],"mappings":"AAGA;;;GAGG;AACH,iCAHa,CAAC;IAOV;;;OAGG;IACH,oBAHW,OAAO,uBAAuB,EAAE,SAAS,QACzC,OAAO,uBAAuB,EAAE,OAAO,EA8CjD;IAhCG,kDAAgC;IAQhC,iCAuBE;IAoCN;;;;;OAKG;IACH,gCAHW,MAAM,EAAE,GACN,CAAC,EAAE,CAKf;;CACJ;qCAvGoC,+BAA+B"}
1
+ {"version":3,"file":"tabixSource.d.ts","sourceRoot":"","sources":["../../../../../src/data/sources/lazy/tabixSource.js"],"names":[],"mappings":"AAGA;;;GAGG;AACH,iCAHa,CAAC;IAOV;;;OAGG;IACH,oBAHW,OAAO,uBAAuB,EAAE,SAAS,QACzC,OAAO,uBAAuB,EAAE,OAAO,EAkDjD;IAnCG,kDAAgC;IAQhC,iCA0BE;IAqCN;;;OAGG;IACH,gCAHW,MAAM,iBAKhB;IAED;;;;;OAKG;IACH,gCAHW,MAAM,EAAE,GACN,CAAC,EAAE,CAKf;;CACJ;qCApHoC,+BAA+B"}
@@ -20,6 +20,7 @@ export default class TabixSource extends SingleAxisWindowedSource {
20
20
  windowSize: 3_000_000,
21
21
  debounce: 200,
22
22
  debounceMode: "domain",
23
+ addChrPrefix: false,
23
24
  ...params,
24
25
  };
25
26
 
@@ -35,15 +36,9 @@ export default class TabixSource extends SingleAxisWindowedSource {
35
36
 
36
37
  this.initializedPromise = new Promise((resolve) => {
37
38
  Promise.all([
38
- import("buffer"),
39
39
  import("@gmod/tabix"),
40
40
  import("generic-filehandle"),
41
- ]).then(([{ Buffer }, { TabixIndexedFile }, { RemoteFile }]) => {
42
- // Hack needed by @gmod/tabix
43
- if (typeof window !== "undefined") {
44
- window.Buffer ??= Buffer;
45
- }
46
-
41
+ ]).then(async ([{ TabixIndexedFile }, { RemoteFile }]) => {
47
42
  const withBase = (/** @type {string} */ uri) =>
48
43
  new RemoteFile(addBaseUrl(uri, this.view.getBaseUrl()));
49
44
 
@@ -52,8 +47,17 @@ export default class TabixSource extends SingleAxisWindowedSource {
52
47
  tbiFilehandle: withBase(
53
48
  this.params.indexUrl ?? this.params.url + ".tbi"
54
49
  ),
50
+ renameRefSeqs:
51
+ this.params.addChrPrefix === true
52
+ ? (refSeq) => "chr" + refSeq
53
+ : this.params.addChrPrefix
54
+ ? (refSeq) => this.params.addChrPrefix + refSeq
55
+ : undefined,
55
56
  });
56
57
 
58
+ const header = await this.#tbiIndex.getHeader();
59
+ await this._handleHeader(header);
60
+
57
61
  resolve();
58
62
  });
59
63
  });
@@ -65,6 +69,7 @@ export default class TabixSource extends SingleAxisWindowedSource {
65
69
  * @param {number[]} interval linearized domain
66
70
  */
67
71
  async loadInterval(interval) {
72
+ await this.initializedPromise;
68
73
  const featureChunks = await this.discretizeAndLoad(
69
74
  interval,
70
75
  async (discreteInterval, signal) => {
@@ -92,6 +97,14 @@ export default class TabixSource extends SingleAxisWindowedSource {
92
97
  }
93
98
  }
94
99
 
100
+ /**
101
+ * @param {string} header
102
+ * @protected
103
+ */
104
+ async _handleHeader(header) {
105
+ //
106
+ }
107
+
95
108
  /**
96
109
  * @abstract
97
110
  * @protected
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @extends {TabixSource<import("./vcfTypes.js").ParsedVariant>}
3
+ */
4
+ export default class VcfSource extends TabixSource<import("./vcfTypes.js").ParsedVariant> {
5
+ constructor(params: import("../../../spec/data.js").TabixData, view: import("../../../view/view.js").default);
6
+ #private;
7
+ }
8
+ import TabixSource from "./tabixSource.js";
9
+ //# sourceMappingURL=vcfSource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vcfSource.d.ts","sourceRoot":"","sources":["../../../../../src/data/sources/lazy/vcfSource.js"],"names":[],"mappings":"AAEA;;GAEG;AACH;+BAUK,uBACe,0BACQ,uBAAuB;;CAoBlD;wBArCuB,kBAAkB"}
@@ -0,0 +1,38 @@
1
+ import TabixSource from "./tabixSource.js";
2
+
3
+ /**
4
+ * @extends {TabixSource<import("./vcfTypes.js").ParsedVariant>}
5
+ */
6
+ export default class VcfSource extends TabixSource {
7
+ /** @type {import("@gmod/vcf").default} */
8
+ #tbiVCFParser;
9
+
10
+ get label() {
11
+ return "vcfSource";
12
+ }
13
+
14
+ /**
15
+ * @param {string} header
16
+ */
17
+ async _handleHeader(header) {
18
+ const VCFParser = (await import("@gmod/vcf")).default;
19
+ // @ts-ignore - There's something wrong with the type definition
20
+ this.#tbiVCFParser = new VCFParser({ header });
21
+ }
22
+
23
+ /**
24
+ * @param {string[]} lines
25
+ */
26
+ _parseFeatures(lines) {
27
+ return lines.map((line) => {
28
+ const parsed = this.#tbiVCFParser.parseLine(line);
29
+ delete parsed.GENOTYPES;
30
+ // @ts-ignore
31
+ parsed.SAMPLES = parsed.SAMPLES();
32
+
33
+ return /** @type {import("./vcfTypes.js").ParsedVariant} */ (
34
+ /** @type {object} */ (parsed)
35
+ );
36
+ });
37
+ }
38
+ }
@@ -0,0 +1,7 @@
1
+ import { Variant } from "@gmod/vcf";
2
+
3
+ type Samples = ReturnType<Variant["SAMPLES"]>;
4
+
5
+ export type ParsedVariant = Omit<Variant, "SAMPLES" | "GENOTYPES"> & {
6
+ SAMPLES: Samples;
7
+ };
@@ -100,9 +100,9 @@ export function createAccessor(channel, channelDef, paramMediator) {
100
100
  return potentialExprRefToAccessor(channelDef.value);
101
101
  } else {
102
102
  throw new Error(
103
- `Invalid channel definition: ${JSON.stringify(
103
+ `Invalid channel definition: "${channel}": ${JSON.stringify(
104
104
  channelDef
105
- )}. Cannot create an accessor for channel ${channel}!`
105
+ )}! The channel definition must contain one of the following properties: "field", "datum", "value" or "expr".`
106
106
  );
107
107
  }
108
108
  }
@@ -1 +1 @@
1
- {"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"genomeSpy.d.ts","sourceRoot":"","sources":["../../src/genomeSpy.js"],"names":[],"mappings":"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"}
@@ -524,6 +524,26 @@ export default class GenomeSpy {
524
524
  validator
525
525
  );
526
526
  },
527
+
528
+ highlightView: (view) => {
529
+ this.container.querySelector(".view-highlight")?.remove();
530
+ if (view) {
531
+ const coords = view.coords;
532
+ if (coords) {
533
+ const div = document.createElement("div");
534
+ div.className = "view-highlight";
535
+ div.style.position = "absolute";
536
+ div.style.left = coords.x + "px";
537
+ div.style.top = coords.y + "px";
538
+ div.style.width = coords.width + "px";
539
+ div.style.height = coords.height + "px";
540
+ div.style.border = "1px solid green";
541
+ div.style.backgroundColor = "rgba(0, 255, 0, 0.1)";
542
+ div.style.pointerEvents = "none";
543
+ this.container.appendChild(div);
544
+ }
545
+ }
546
+ },
527
547
  };
528
548
 
529
549
  /** @type {ViewSpec & RootConfig} */
@@ -114,7 +114,7 @@ export default class RuleMark extends Mark {
114
114
  }
115
115
  } else {
116
116
  throw new Error(
117
- "Invalid x and y encodings for rule mark: " +
117
+ "At a minimum, either the x or y channel must be defined in the rule mark's encoding: " +
118
118
  JSON.stringify(encoding)
119
119
  );
120
120
  }
@@ -201,7 +201,8 @@ export type LazyDataParams =
201
201
  | BigWigData
202
202
  | BigBedData
203
203
  | BamData
204
- | Gff3Data;
204
+ | Gff3Data
205
+ | VcfData;
205
206
 
206
207
  export interface DebouncedData {
207
208
  /**
@@ -372,6 +373,14 @@ export interface TabixData extends DebouncedData {
372
373
  */
373
374
  indexUrl?: string;
374
375
 
376
+ /**
377
+ * Add a `chr` (boolean) or custom (string) prefix to the chromosome names
378
+ * in the Tabix file.
379
+ *
380
+ * __Default value:__ `false`
381
+ */
382
+ addChrPrefix?: boolean | string;
383
+
375
384
  /**
376
385
  * Size of each chunk when fetching the Tabix file. Data is only fetched
377
386
  * when the length of the visible domain smaller than the window size.
@@ -384,3 +393,7 @@ export interface TabixData extends DebouncedData {
384
393
  export interface Gff3Data extends TabixData {
385
394
  type: "gff3";
386
395
  }
396
+
397
+ export interface VcfData extends TabixData {
398
+ type: "vcf";
399
+ }
@@ -1,3 +1,3 @@
1
1
  export default css;
2
- declare const css: "\n.genome-spy {\n font-family: system-ui, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n position: relative;\n display: flex;\n flex-direction: column;\n}\n.genome-spy .canvas-wrapper {\n position: relative;\n flex-grow: 1;\n overflow: hidden;\n}\n.genome-spy canvas {\n display: block;\n transform: scale(1, 1);\n opacity: 1;\n transition: transform 0.6s, opacity 0.6s;\n}\n.genome-spy .loading-message {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.genome-spy .loading-message .message {\n color: #666;\n opacity: 0;\n transition: opacity 0.7s;\n}\n.genome-spy .loading > canvas {\n transform: scale(0.95, 0.95);\n opacity: 0;\n}\n.genome-spy .loading > .loading-message .message {\n opacity: 1;\n}\n.genome-spy .loading > .loading-message .message .ellipsis {\n animation: blinker 1s linear infinite;\n}\n@keyframes blinker {\n 50% {\n opacity: 0;\n }\n}\n.genome-spy .loading-indicators {\n position: absolute;\n inset: 0;\n user-select: none;\n pointer-events: none;\n}\n.genome-spy .loading-indicators div {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.genome-spy .loading-indicators div > div {\n font-size: 11px;\n transition: opacity 0.2s;\n background: white;\n padding: 2px 5px;\n display: flex;\n border-radius: 3px;\n gap: 0.5em;\n opacity: 0;\n}\n.genome-spy .loading-indicators div > div.loading {\n opacity: 0.5;\n}\n.genome-spy .loading-indicators div > div.error {\n opacity: 0.8;\n color: firebrick;\n}\n.genome-spy .loading-indicators div > div > * {\n display: block;\n}\n.genome-spy .loading-indicators div > div img {\n width: 1.5em;\n height: 1.5em;\n}\n.genome-spy .tooltip {\n position: absolute;\n max-width: 450px;\n overflow: hidden;\n background: #f6f6f6;\n padding: 10px;\n font-size: 13px;\n box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.21);\n pointer-events: none;\n z-index: 100;\n}\n.genome-spy .tooltip > :last-child {\n margin-bottom: 0;\n}\n.genome-spy .tooltip > .title {\n padding-bottom: 5px;\n margin-bottom: 5px;\n border-bottom: 1px dashed #b6b6b6;\n}\n.genome-spy .tooltip .summary {\n font-size: 12px;\n}\n.genome-spy .tooltip table {\n border-collapse: collapse;\n}\n.genome-spy .tooltip table:first-child {\n margin-top: 0;\n}\n.genome-spy .tooltip table th,\n.genome-spy .tooltip table td {\n padding: 2px 0.4em;\n vertical-align: top;\n}\n.genome-spy .tooltip table th:first-child,\n.genome-spy .tooltip table td:first-child {\n padding-left: 0;\n}\n.genome-spy .tooltip table th {\n text-align: left;\n font-weight: bold;\n}\n.genome-spy .tooltip .color-legend {\n display: inline-block;\n width: 0.8em;\n height: 0.8em;\n margin-left: 0.4em;\n box-shadow: 0px 0px 3px 1px white;\n}\n.genome-spy .tooltip .attributes .hovered {\n background-color: #e0e0e0;\n}\n.genome-spy .tooltip .na {\n color: #aaa;\n font-style: italic;\n font-size: 80%;\n}\n.genome-spy .gene-track-tooltip .summary {\n font-size: 90%;\n}\n.genome-spy .message-box {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n top: 0;\n height: 100%;\n width: 100%;\n}\n.genome-spy .message-box > div {\n border: 1px solid red;\n padding: 10px;\n background: #fff0f0;\n}\n\n.gs-input-binding {\n display: grid;\n grid-template-columns: max-content max-content;\n column-gap: 1em;\n row-gap: 0.3em;\n justify-items: start;\n}\n.gs-input-binding > select,\n.gs-input-binding > input:not([type=checkbox]) {\n width: 100%;\n}\n.gs-input-binding input[type=range] + span {\n display: inline-block;\n margin-left: 0.3em;\n min-width: 2.2em;\n font-variant-numeric: tabular-nums;\n}\n.gs-input-binding input[type=range],\n.gs-input-binding input[type=radio] {\n vertical-align: text-bottom;\n}\n.gs-input-binding .radio-group {\n display: flex;\n align-items: center;\n}\n.gs-input-binding .description {\n max-width: 26em;\n grid-column: 1/-1;\n color: #777;\n font-size: 90%;\n margin-top: -0.5em;\n}\n\n.gs-input-bindings {\n flex-basis: content;\n font-size: 14px;\n padding: 10px;\n}\n";
2
+ declare const css: "\n.genome-spy {\n font-family: system-ui, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\";\n position: relative;\n display: flex;\n flex-direction: column;\n}\n.genome-spy .canvas-wrapper {\n position: relative;\n flex-grow: 1;\n overflow: hidden;\n}\n.genome-spy canvas {\n display: block;\n transform: scale(1, 1);\n opacity: 1;\n transition: transform 0.6s, opacity 0.6s;\n}\n.genome-spy .loading-message {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.genome-spy .loading-message .message {\n color: #666;\n opacity: 0;\n transition: opacity 0.7s;\n}\n.genome-spy .loading > canvas {\n transform: scale(0.95, 0.95);\n opacity: 0;\n}\n.genome-spy .loading > .loading-message .message {\n opacity: 1;\n}\n.genome-spy .loading > .loading-message .message .ellipsis {\n animation: blinker 1s linear infinite;\n}\n@keyframes blinker {\n 50% {\n opacity: 0;\n }\n}\n.genome-spy .loading-indicators {\n position: absolute;\n inset: 0;\n user-select: none;\n pointer-events: none;\n}\n.genome-spy .loading-indicators div {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.genome-spy .loading-indicators div > div {\n font-size: 11px;\n transition: opacity 0.2s;\n background: white;\n padding: 2px 5px;\n display: flex;\n border-radius: 3px;\n gap: 0.5em;\n opacity: 0;\n}\n.genome-spy .loading-indicators div > div.loading {\n opacity: 0.5;\n}\n.genome-spy .loading-indicators div > div.error {\n opacity: 0.8;\n color: firebrick;\n}\n.genome-spy .loading-indicators div > div > * {\n display: block;\n}\n.genome-spy .loading-indicators div > div img {\n width: 1.5em;\n height: 1.5em;\n}\n.genome-spy .tooltip {\n position: absolute;\n max-width: 450px;\n overflow: hidden;\n background: #f6f6f6;\n padding: 10px;\n font-size: 12px;\n box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.21);\n pointer-events: none;\n z-index: 100;\n}\n.genome-spy .tooltip > :last-child {\n margin-bottom: 0;\n}\n.genome-spy .tooltip > .title {\n padding-bottom: 5px;\n margin-bottom: 5px;\n border-bottom: 1px dashed #b6b6b6;\n}\n.genome-spy .tooltip .summary {\n font-size: 12px;\n}\n.genome-spy .tooltip table {\n border-collapse: collapse;\n}\n.genome-spy .tooltip table:first-child {\n margin-top: 0;\n}\n.genome-spy .tooltip table th,\n.genome-spy .tooltip table td {\n padding: 2px 0.4em;\n vertical-align: top;\n}\n.genome-spy .tooltip table th:first-child,\n.genome-spy .tooltip table td:first-child {\n padding-left: 0;\n}\n.genome-spy .tooltip table th {\n text-align: left;\n font-weight: bold;\n}\n.genome-spy .tooltip .color-legend {\n display: inline-block;\n width: 0.8em;\n height: 0.8em;\n margin-left: 0.4em;\n box-shadow: 0px 0px 3px 1px white;\n}\n.genome-spy .tooltip .attributes .hovered {\n background-color: #e0e0e0;\n}\n.genome-spy .tooltip .na {\n color: #aaa;\n font-style: italic;\n font-size: 80%;\n}\n.genome-spy .gene-track-tooltip .summary {\n font-size: 90%;\n}\n.genome-spy .message-box {\n display: flex;\n align-items: center;\n justify-content: center;\n position: absolute;\n top: 0;\n height: 100%;\n width: 100%;\n}\n.genome-spy .message-box > div {\n border: 1px solid red;\n padding: 10px;\n background: #fff0f0;\n}\n\n.gs-input-binding {\n display: grid;\n grid-template-columns: max-content max-content;\n column-gap: 1em;\n row-gap: 0.3em;\n justify-items: start;\n}\n.gs-input-binding > select,\n.gs-input-binding > input:not([type=checkbox]) {\n width: 100%;\n}\n.gs-input-binding input[type=range] + span {\n display: inline-block;\n margin-left: 0.3em;\n min-width: 2.2em;\n font-variant-numeric: tabular-nums;\n}\n.gs-input-binding input[type=range],\n.gs-input-binding input[type=radio] {\n vertical-align: text-bottom;\n}\n.gs-input-binding .radio-group {\n display: flex;\n align-items: center;\n}\n.gs-input-binding .description {\n max-width: 26em;\n grid-column: 1/-1;\n color: #777;\n font-size: 90%;\n margin-top: -0.5em;\n}\n\n.gs-input-bindings {\n flex-basis: content;\n font-size: 14px;\n padding: 10px;\n}\n";
3
3
  //# sourceMappingURL=genome-spy.css.d.ts.map
@@ -85,7 +85,7 @@ const css = `
85
85
  overflow: hidden;
86
86
  background: #f6f6f6;
87
87
  padding: 10px;
88
- font-size: 13px;
88
+ font-size: 12px;
89
89
  box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.21);
90
90
  pointer-events: none;
91
91
  z-index: 100;
@@ -117,7 +117,7 @@ $font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
117
117
  $background-color: #f6f6f6;
118
118
  background: $background-color;
119
119
  padding: $basic-spacing;
120
- font-size: 13px;
120
+ font-size: 12px;
121
121
 
122
122
  box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.21);
123
123
 
@@ -30,24 +30,44 @@ export default async function dataTooltipHandler(datum, mark, params) {
30
30
  return "";
31
31
  };
32
32
 
33
- const strippedEntries = Object.entries(datum).filter(
34
- ([key, _value]) => !key.startsWith("_")
35
- );
33
+ /**
34
+ *
35
+ * @param {[string, any][]} entries
36
+ * @param {string} [prefix]
37
+ * @returns {ReturnType<typeof html>[]}
38
+ */
39
+ const entriesToHtml = (entries, prefix) => {
40
+ const strippedEntries = entries.filter(
41
+ ([key, _value]) => !key.startsWith("_")
42
+ );
43
+
44
+ if (strippedEntries.length === 0) {
45
+ return;
46
+ }
47
+
48
+ return strippedEntries.map(([key, value]) =>
49
+ typeof value === "object" && !Array.isArray(value)
50
+ ? html`${entriesToHtml(
51
+ Object.entries(value),
52
+ (prefix ? prefix : "") + key + "."
53
+ )}`
54
+ : html`
55
+ <tr>
56
+ <th>${prefix}${key}</th>
57
+ <td>${formatObject(value)} ${legend(key, datum)}</td>
58
+ </tr>
59
+ `
60
+ );
61
+ };
36
62
 
37
- if (strippedEntries.length === 0) {
63
+ const tableContents = entriesToHtml(Object.entries(datum));
64
+ if (!tableContents) {
38
65
  return;
39
66
  }
40
67
 
41
68
  const table = html`
42
69
  <table class="attributes">
43
- ${strippedEntries.map(
44
- ([key, value]) => html`
45
- <tr>
46
- <th>${key}</th>
47
- <td>${formatObject(value)} ${legend(key, datum)}</td>
48
- </tr>
49
- `
50
- )}
70
+ ${tableContents}
51
71
  </table>
52
72
  `;
53
73
 
@@ -82,6 +82,14 @@ export default interface ViewContext {
82
82
  detail?: string
83
83
  ) => void;
84
84
 
85
+ /**
86
+ * Highlights a view by adding a border around it. This is useful for debugging.
87
+ *
88
+ * @param view The view to highlight. Null to remove the highlight.
89
+ * @returns
90
+ */
91
+ highlightView?: (view: View | null) => void;
92
+
85
93
  /**
86
94
  * Returns true if the view is configured to be visible.
87
95
  * N.B. This does NOT consider ancestors' visibility.
@@ -1 +1 @@
1
- {"version":3,"file":"expression.d.ts","sourceRoot":"","sources":["../../../src/utils/expression.js"],"names":[],"mappings":"AA2DA;;;;;;;;;;GAUG;AACH,6CAHW,MAAM,sBACJ,kBAAkB,CAgC9B;;YAvCU,MAAM,EAAE;aACR,MAAM,EAAE;UACR,MAAM;;iCAEH,CAAC,CAAC,KAAK,CAAC,EAAE,OAAO,qBAAqB,EAAE,KAAK,KAAK,GAAG,CAAC,GAAG,eAAe"}
1
+ {"version":3,"file":"expression.d.ts","sourceRoot":"","sources":["../../../src/utils/expression.js"],"names":[],"mappings":"AAkEA;;;;;;;;;;GAUG;AACH,6CAHW,MAAM,sBACJ,kBAAkB,CAgC9B;;YAvCU,MAAM,EAAE;aACR,MAAM,EAAE;UACR,MAAM;;iCAEH,CAAC,CAAC,KAAK,CAAC,EAAE,OAAO,qBAAqB,EAAE,KAAK,KAAK,GAAG,CAAC,GAAG,eAAe"}
@@ -33,6 +33,13 @@ const functionContext = {
33
33
  },
34
34
  lerp,
35
35
  linearstep,
36
+ replace(
37
+ /** @type {string} */ str,
38
+ /** @type {RegExp} */ pattern,
39
+ /** @type {string} */ replace
40
+ ) {
41
+ return String(str).replace(pattern, replace);
42
+ },
36
43
  smoothstep,
37
44
  selectionTest,
38
45
  };
@@ -1 +1 @@
1
- {"version":3,"file":"scaleResolution.d.ts","sourceRoot":"","sources":["../../../src/view/scaleResolution.js"],"names":[],"mappings":"AAq9BA;;;;;;;;;;GAUG;AACH,6CAFW,OAAO,WAAW,EAAE,OAAO,GAAG,OAAO,WAAW,EAAE,OAAO,EAAE,QA4BrE;AA78BD,0CAA2C;AAC3C,gCAAiC;AACjC,gCAAiC;AACjC,4BAA6B;AAC7B,4BAA6B;AAE7B;;;;;;;;GAQG;AACH;;;;;;;GAOG;AACH;IAyCI;;OAEG;IACH,2DASC;IARG,8CAAsB;IACtB,yDAAyD;IACzD,SADW,qBAAqB,EAAE,CACjB;IACjB,0FAA0F;IAC1F,MADW,OAAO,oBAAoB,EAAE,IAAI,CAC5B;IAEhB,iEAAiE;IACjE,MADW,MAAM,CACI;IAWzB;;;;;;;OAOG;IACH,4KAEC;IAED;;;OAGG;IACH,+KAEC;IAcD;;;;;OAKG;IACH,qBAFW,qBAAqB,QAgC/B;IA8MD;;;;OAIG;IACH,+DAOC;IAED;;OAEG;IACH,oBAyCC;IAED;;OAEG;IACH;eAhYkC,OAAO,kBAAkB,EAAE,KAAK;MA4ajE;IAED,mBAEC;IAED;;OAEG;IACH,oBAFa,mFAA6B,CAOzC;IAED;;;;OAIG;IACH,oBAKC;IAED;;OAEG;IACH,sBAGC;IAUD;;;;;;;OAOG;IACH,kBALW,MAAM,eACN,MAAM,OACN,MAAM,GACJ,OAAO,CAwEnB;IAED;;;;;;OAMG;IACH,eAJW,mFAA6B,aAC7B,OAAO,GAAG,MAAM,iBA0D1B;IAED;;;;OAIG;IACH,qBAcC;IAED;;;;;OAKG;IACH,uBAOC;IAED;;;;;;;OAOG;IACH,wBAoBC;IA8DD;;;OAGG;IACH,aAFa,OAAO,qBAAqB,EAAE,OAAO,CAajD;IAID;;;;;OAKG;IACH,uBAFW,MAAM,yDAUhB;IAED;;OAEG;IACH,iBAFW,MAAM,yDAKhB;IAED;;;OAGG;IACH,qBAHW,MAAM,+CAAmB,GACvB,MAAM,CAQlB;IAED;;;OAGG;IACH,8BAHW,kFAA4B,GAC1B,MAAM,EAAE,CAOpB;;CACJ;kCAv0B+B,CAAC,SAApB,6CAAkB;;;;UAGrB,OAAO,eAAe,EAAE,OAAO;aAC/B,CAAC;gBACD,OAAO,oBAAoB,EAAE,mBAAmB;sBAChD,CAAC,OAAO,+CAAkB,EAAE,IAAI,EAAE,OAAO,oBAAoB,EAAE,IAAI,kDAAgB"}
1
+ {"version":3,"file":"scaleResolution.d.ts","sourceRoot":"","sources":["../../../src/view/scaleResolution.js"],"names":[],"mappings":"AAk+BA;;;;;;;;;;GAUG;AACH,6CAFW,OAAO,WAAW,EAAE,OAAO,GAAG,OAAO,WAAW,EAAE,OAAO,EAAE,QA4BrE;AA19BD,0CAA2C;AAC3C,gCAAiC;AACjC,gCAAiC;AACjC,4BAA6B;AAC7B,4BAA6B;AAE7B;;;;;;;;GAQG;AACH;;;;;;;GAOG;AACH;IAyCI;;OAEG;IACH,2DASC;IARG,8CAAsB;IACtB,yDAAyD;IACzD,SADW,qBAAqB,EAAE,CACjB;IACjB,0FAA0F;IAC1F,MADW,OAAO,oBAAoB,EAAE,IAAI,CAC5B;IAEhB,iEAAiE;IACjE,MADW,MAAM,CACI;IAWzB;;;;;;;OAOG;IACH,4KAEC;IAED;;;OAGG;IACH,+KAEC;IAcD;;;;;OAKG;IACH,qBAFW,qBAAqB,QA6C/B;IA8MD;;;;OAIG;IACH,+DAOC;IAED;;OAEG;IACH,oBAyCC;IAED;;OAEG;IACH;eA7YkC,OAAO,kBAAkB,EAAE,KAAK;MAybjE;IAED,mBAEC;IAED;;OAEG;IACH,oBAFa,mFAA6B,CAOzC;IAED;;;;OAIG;IACH,oBAKC;IAED;;OAEG;IACH,sBAGC;IAUD;;;;;;;OAOG;IACH,kBALW,MAAM,eACN,MAAM,OACN,MAAM,GACJ,OAAO,CAwEnB;IAED;;;;;;OAMG;IACH,eAJW,mFAA6B,aAC7B,OAAO,GAAG,MAAM,iBA0D1B;IAED;;;;OAIG;IACH,qBAcC;IAED;;;;;OAKG;IACH,uBAOC;IAED;;;;;;;OAOG;IACH,wBAoBC;IA8DD;;;OAGG;IACH,aAFa,OAAO,qBAAqB,EAAE,OAAO,CAajD;IAID;;;;;OAKG;IACH,uBAFW,MAAM,yDAUhB;IAED;;OAEG;IACH,iBAFW,MAAM,yDAKhB;IAED;;;OAGG;IACH,qBAHW,MAAM,+CAAmB,GACvB,MAAM,CAQlB;IAED;;;OAGG;IACH,8BAHW,kFAA4B,GAC1B,MAAM,EAAE,CAOpB;;CACJ;kCAp1B+B,CAAC,SAApB,6CAAkB;;;;UAGrB,OAAO,eAAe,EAAE,OAAO;aAC/B,CAAC;gBACD,OAAO,oBAAoB,EAAE,mBAAmB;sBAChD,CAAC,OAAO,+CAAkB,EAAE,IAAI,EAAE,OAAO,oBAAoB,EAAE,IAAI,kDAAgB"}
@@ -170,6 +170,19 @@ export default class ScaleResolution {
170
170
  addMember(newMember) {
171
171
  const { channel, channelDef } = newMember;
172
172
 
173
+ if (
174
+ // @ts-expect-error "sample" is not really a channel with scale
175
+ channel != "sample" &&
176
+ !channelDef.type &&
177
+ !isSecondaryChannel(channel)
178
+ ) {
179
+ throw new Error(
180
+ `The "type" property must be defined in channel definition: "${channel}": ${JSON.stringify(
181
+ channelDef
182
+ )}. Must be one of: "quantitative", "ordinal", "nominal", "locus", "index"`
183
+ );
184
+ }
185
+
173
186
  // A hack for sample channel, which really doesn't have a scale but the
174
187
  // domain is needed when samples are not specified explicitly.
175
188
  // @ts-expect-error "sample" is not really a channel with scale