@genome-spy/core 0.30.0 → 0.30.3

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 (234) hide show
  1. package/dist/index.es.js +16379 -0
  2. package/dist/index.js +43 -43
  3. package/package.json +10 -7
  4. package/src/data/collector.js +0 -183
  5. package/src/data/collector.test.js +0 -84
  6. package/src/data/dataFlow.js +0 -148
  7. package/src/data/dataFlow.test.js +0 -5
  8. package/src/data/facetNode.js +0 -17
  9. package/src/data/flow.test.js +0 -72
  10. package/src/data/flowBatch.d.ts +0 -40
  11. package/src/data/flowNode.js +0 -283
  12. package/src/data/flowNode.test.js +0 -50
  13. package/src/data/flowOptimizer.js +0 -123
  14. package/src/data/flowOptimizer.test.js +0 -193
  15. package/src/data/flowTestUtils.js +0 -63
  16. package/src/data/formats/fasta.js +0 -32
  17. package/src/data/formats/fasta.test.js +0 -27
  18. package/src/data/sources/dataSource.js +0 -22
  19. package/src/data/sources/dataSourceFactory.js +0 -24
  20. package/src/data/sources/dataUtils.js +0 -78
  21. package/src/data/sources/dynamicCallbackSource.js +0 -57
  22. package/src/data/sources/dynamicSource.js +0 -37
  23. package/src/data/sources/inlineSource.js +0 -67
  24. package/src/data/sources/inlineSource.test.js +0 -56
  25. package/src/data/sources/namedSource.js +0 -79
  26. package/src/data/sources/sequenceSource.js +0 -46
  27. package/src/data/sources/sequenceSource.test.js +0 -46
  28. package/src/data/sources/urlSource.js +0 -74
  29. package/src/data/transforms/aggregate.js +0 -70
  30. package/src/data/transforms/clone.js +0 -40
  31. package/src/data/transforms/clone.test.js +0 -11
  32. package/src/data/transforms/coverage.js +0 -187
  33. package/src/data/transforms/coverage.test.js +0 -123
  34. package/src/data/transforms/filter.js +0 -37
  35. package/src/data/transforms/filter.test.js +0 -18
  36. package/src/data/transforms/filterScoredLabels.js +0 -134
  37. package/src/data/transforms/flattenCompressedExons.js +0 -57
  38. package/src/data/transforms/flattenDelimited.js +0 -74
  39. package/src/data/transforms/flattenDelimited.test.js +0 -87
  40. package/src/data/transforms/flattenSequence.js +0 -39
  41. package/src/data/transforms/flattenSequence.test.js +0 -34
  42. package/src/data/transforms/formula.js +0 -39
  43. package/src/data/transforms/formula.test.js +0 -19
  44. package/src/data/transforms/identifier.js +0 -108
  45. package/src/data/transforms/identifier.test.js +0 -83
  46. package/src/data/transforms/linearizeGenomicCoordinate.js +0 -101
  47. package/src/data/transforms/measureText.js +0 -44
  48. package/src/data/transforms/pileup.js +0 -128
  49. package/src/data/transforms/pileup.test.js +0 -70
  50. package/src/data/transforms/project.js +0 -41
  51. package/src/data/transforms/project.test.js +0 -32
  52. package/src/data/transforms/regexExtract.js +0 -61
  53. package/src/data/transforms/regexExtract.test.js +0 -67
  54. package/src/data/transforms/regexFold.js +0 -141
  55. package/src/data/transforms/regexFold.test.js +0 -160
  56. package/src/data/transforms/sample.js +0 -101
  57. package/src/data/transforms/sample.test.js +0 -38
  58. package/src/data/transforms/stack.js +0 -137
  59. package/src/data/transforms/stack.test.js +0 -91
  60. package/src/data/transforms/transformFactory.js +0 -60
  61. package/src/embedApi.d.ts +0 -67
  62. package/src/encoder/accessor.js +0 -82
  63. package/src/encoder/accessor.test.js +0 -47
  64. package/src/encoder/encoder.js +0 -394
  65. package/src/encoder/encoder.test.js +0 -98
  66. package/src/fonts/Lato-Regular.json +0 -1267
  67. package/src/fonts/Lato-Regular.png +0 -0
  68. package/src/fonts/OFL.txt +0 -93
  69. package/src/fonts/README.md +0 -3
  70. package/src/fonts/bmFont.d.ts +0 -58
  71. package/src/fonts/bmFontManager.js +0 -357
  72. package/src/fonts/bmFontMetrics.js +0 -108
  73. package/src/genome/genome.js +0 -317
  74. package/src/genome/genome.test.js +0 -188
  75. package/src/genome/genomeStore.js +0 -54
  76. package/src/genome/locusFormat.js +0 -31
  77. package/src/genome/scaleIndex.d.ts +0 -38
  78. package/src/genome/scaleIndex.js +0 -166
  79. package/src/genome/scaleIndex.test.js +0 -78
  80. package/src/genome/scaleLocus.d.ts +0 -11
  81. package/src/genome/scaleLocus.js +0 -108
  82. package/src/genome/scaleLocus.test.js +0 -4
  83. package/src/genomeSpy.js +0 -785
  84. package/src/gl/arrayBuilder.js +0 -199
  85. package/src/gl/dataToVertices.js +0 -636
  86. package/src/gl/includes/common.glsl +0 -63
  87. package/src/gl/includes/picking.fragment.glsl +0 -1
  88. package/src/gl/includes/picking.vertex.glsl +0 -27
  89. package/src/gl/includes/sampleFacet.glsl +0 -107
  90. package/src/gl/includes/scales.glsl +0 -112
  91. package/src/gl/link.fragment.glsl +0 -18
  92. package/src/gl/link.vertex.glsl +0 -111
  93. package/src/gl/point.fragment.glsl +0 -123
  94. package/src/gl/point.vertex.glsl +0 -129
  95. package/src/gl/rect.fragment.glsl +0 -51
  96. package/src/gl/rect.vertex.glsl +0 -114
  97. package/src/gl/rule.fragment.glsl +0 -52
  98. package/src/gl/rule.vertex.glsl +0 -89
  99. package/src/gl/text.fragment.glsl +0 -31
  100. package/src/gl/text.vertex.glsl +0 -246
  101. package/src/gl/webGLHelper.js +0 -504
  102. package/src/img/bowtie.svg +0 -1
  103. package/src/img/genomespy-favicon.svg +0 -34
  104. package/src/index.html +0 -11
  105. package/src/index.js +0 -128
  106. package/src/marks/link.js +0 -175
  107. package/src/marks/mark.js +0 -975
  108. package/src/marks/markUtils.js +0 -125
  109. package/src/marks/pointMark.js +0 -251
  110. package/src/marks/rectMark.js +0 -241
  111. package/src/marks/rule.js +0 -250
  112. package/src/marks/text.js +0 -278
  113. package/src/node_modules/.vitest/results.json +0 -1
  114. package/src/scale/colorUtils.js +0 -184
  115. package/src/scale/glslScaleGenerator.js +0 -502
  116. package/src/scale/scale.js +0 -451
  117. package/src/scale/scale.test.js +0 -324
  118. package/src/scale/ticks.js +0 -203
  119. package/src/scale/ticks.test.js +0 -40
  120. package/src/singlePageApp.js +0 -13
  121. package/src/spec/axis.d.ts +0 -296
  122. package/src/spec/channel.d.ts +0 -430
  123. package/src/spec/data.d.ts +0 -196
  124. package/src/spec/font.d.ts +0 -15
  125. package/src/spec/genome.d.ts +0 -35
  126. package/src/spec/mark.d.ts +0 -429
  127. package/src/spec/root.d.ts +0 -17
  128. package/src/spec/sampleView.d.ts +0 -180
  129. package/src/spec/scale.d.ts +0 -273
  130. package/src/spec/title.d.ts +0 -102
  131. package/src/spec/tooltip.d.ts +0 -9
  132. package/src/spec/transform.d.ts +0 -479
  133. package/src/spec/view.d.ts +0 -201
  134. package/src/styles/genome-spy.scss +0 -153
  135. package/src/tooltip/dataTooltipHandler.js +0 -64
  136. package/src/tooltip/refseqGeneTooltipHandler.js +0 -78
  137. package/src/tooltip/tooltipHandler.ts +0 -12
  138. package/src/types/filetypes.d.ts +0 -14
  139. package/src/types/flatqueue.d.ts +0 -53
  140. package/src/types/glsl.d.ts +0 -4
  141. package/src/types/internmap.d.ts +0 -22
  142. package/src/types/object.d.ts +0 -21
  143. package/src/types/vega-loader.d.ts +0 -1
  144. package/src/types/vega-scale.d.ts +0 -60
  145. package/src/utils/addBaseUrl.js +0 -19
  146. package/src/utils/addBaseUrl.test.js +0 -22
  147. package/src/utils/animator.js +0 -83
  148. package/src/utils/arrayUtils.js +0 -61
  149. package/src/utils/binnedIndex.js +0 -167
  150. package/src/utils/binnedIndex.test.js +0 -155
  151. package/src/utils/clamp.js +0 -8
  152. package/src/utils/cloner.js +0 -34
  153. package/src/utils/cloner.test.js +0 -24
  154. package/src/utils/coalesce.js +0 -11
  155. package/src/utils/coalesce.test.js +0 -16
  156. package/src/utils/concatIterables.js +0 -26
  157. package/src/utils/concatIterables.test.js +0 -8
  158. package/src/utils/debounce.js +0 -37
  159. package/src/utils/domainArray.js +0 -216
  160. package/src/utils/domainArray.test.js +0 -130
  161. package/src/utils/eerp.js +0 -13
  162. package/src/utils/expression.js +0 -32
  163. package/src/utils/field.js +0 -28
  164. package/src/utils/formatObject.js +0 -31
  165. package/src/utils/indexer.js +0 -43
  166. package/src/utils/indexer.test.js +0 -47
  167. package/src/utils/inertia.js +0 -124
  168. package/src/utils/interactionEvent.js +0 -33
  169. package/src/utils/iterateNestedMaps.js +0 -21
  170. package/src/utils/iterateNestedMaps.test.js +0 -33
  171. package/src/utils/kWayMerge.js +0 -42
  172. package/src/utils/kWayMerge.test.js +0 -26
  173. package/src/utils/layout/flexLayout.js +0 -368
  174. package/src/utils/layout/flexLayout.test.js +0 -311
  175. package/src/utils/layout/grid.js +0 -95
  176. package/src/utils/layout/grid.test.js +0 -71
  177. package/src/utils/layout/padding.js +0 -120
  178. package/src/utils/layout/point.js +0 -23
  179. package/src/utils/layout/rectangle.js +0 -288
  180. package/src/utils/layout/rectangle.test.js +0 -172
  181. package/src/utils/mergeObjects.js +0 -99
  182. package/src/utils/mergeObjects.test.js +0 -42
  183. package/src/utils/numberExtractor.js +0 -24
  184. package/src/utils/numberExtractor.test.js +0 -6
  185. package/src/utils/point.js +0 -14
  186. package/src/utils/propertyCacher.js +0 -70
  187. package/src/utils/propertyCacher.test.js +0 -85
  188. package/src/utils/propertyCoalescer.js +0 -42
  189. package/src/utils/propertyCoalescer.test.js +0 -22
  190. package/src/utils/reservationMap.js +0 -103
  191. package/src/utils/reservationMap.test.js +0 -20
  192. package/src/utils/scaleNull.js +0 -19
  193. package/src/utils/setOperations.js +0 -75
  194. package/src/utils/smoothstep.js +0 -10
  195. package/src/utils/throttle.js +0 -34
  196. package/src/utils/topK.js +0 -76
  197. package/src/utils/topK.test.js +0 -64
  198. package/src/utils/transition.js +0 -74
  199. package/src/utils/ui/tooltip.js +0 -189
  200. package/src/utils/url.js +0 -22
  201. package/src/utils/variableTools.js +0 -24
  202. package/src/utils/variableTools.test.js +0 -13
  203. package/src/view/axisResolution.js +0 -140
  204. package/src/view/axisResolution.test.js +0 -201
  205. package/src/view/axisView.js +0 -747
  206. package/src/view/concatView.js +0 -45
  207. package/src/view/containerView.js +0 -159
  208. package/src/view/facetView.js +0 -491
  209. package/src/view/flowBuilder.js +0 -367
  210. package/src/view/flowBuilder.test.js +0 -125
  211. package/src/view/gridView.js +0 -786
  212. package/src/view/implicitRootView.js +0 -14
  213. package/src/view/importView.js +0 -19
  214. package/src/view/layerView.js +0 -74
  215. package/src/view/rendering.d.ts +0 -44
  216. package/src/view/renderingContext/compositeViewRenderingContext.js +0 -51
  217. package/src/view/renderingContext/deferredViewRenderingContext.js +0 -176
  218. package/src/view/renderingContext/layoutRecorderViewRenderingContext.js +0 -128
  219. package/src/view/renderingContext/simpleViewRenderingContext.js +0 -64
  220. package/src/view/renderingContext/svgViewRenderingContext.js +0 -125
  221. package/src/view/renderingContext/viewRenderingContext.js +0 -41
  222. package/src/view/scaleResolution.js +0 -797
  223. package/src/view/scaleResolution.test.js +0 -572
  224. package/src/view/scaleResolutionApi.d.ts +0 -40
  225. package/src/view/testUtils.js +0 -51
  226. package/src/view/title.js +0 -165
  227. package/src/view/unitView.js +0 -382
  228. package/src/view/view.js +0 -612
  229. package/src/view/view.test.js +0 -214
  230. package/src/view/viewContext.d.ts +0 -62
  231. package/src/view/viewFactory.js +0 -181
  232. package/src/view/viewFactory.test.js +0 -17
  233. package/src/view/viewUtils.js +0 -327
  234. package/src/view/zoom.js +0 -89
@@ -1,394 +0,0 @@
1
- import { isDiscrete } from "vega-scale";
2
- import createIndexer from "../utils/indexer";
3
-
4
- /**
5
- * @typedef {Object} EncoderMetadata
6
- * @prop {boolean} constant True if the accessor returns the same value for all objects
7
- * @prop {boolean} constantValue True the encoder returns a "value" without a scale
8
- * @prop {(value: import("../spec/channel").Scalar) => import("../spec/channel").Scalar} invert
9
- * @prop {VegaScale} [scale]
10
- * @prop {import("./accessor").Accessor} accessor
11
- * @prop {function(any):number} [indexer] Converts ordinal values to index numbers
12
- * @prop {import("../view/viewUtils").ChannelDef} channelDef
13
- * @prop {function(function):void} applyMetadata Copies metadata to the target function
14
- *
15
- * @typedef {(function(object):(string|number)) & EncoderMetadata} Encoder
16
- * @typedef {(function(object):number) & EncoderMetadata} NumberEncoder
17
- *
18
- * @typedef {object} ScaleMetadata
19
- * @prop {string} type Scale type
20
- * @prop {boolean} [fp64] Whether to use emulated 64 bit floating point in WebGL
21
- *
22
- * @typedef {(
23
- import("d3-scale").ScaleContinuousNumeric<any, any> |
24
- import("d3-scale").ScaleLinear<any, any> |
25
- import("d3-scale").ScalePower<any, any> |
26
- import("d3-scale").ScaleLogarithmic<any, any> |
27
- import("d3-scale").ScaleSymLog<any, any> |
28
- import("d3-scale").ScaleIdentity |
29
- import("d3-scale").ScaleTime<any, any> |
30
- import("d3-scale").ScaleSequential<any> |
31
- import("d3-scale").ScaleDiverging<any> |
32
- import("d3-scale").ScaleQuantize<any> |
33
- import("d3-scale").ScaleQuantile<any> |
34
- import("d3-scale").ScaleThreshold<any, any> |
35
- import("d3-scale").ScaleOrdinal<any, any> |
36
- import("d3-scale").ScaleBand<any> |
37
- import("d3-scale").ScalePoint<any>
38
- )} D3Scale
39
- *
40
- * @typedef {(D3Scale | import("../genome/scaleIndex").ScaleIndex | import("../genome/scaleLocus").ScaleLocus) & ScaleMetadata} VegaScale
41
- *
42
- * @typedef {import("../spec/channel").Channel} Channel
43
- */
44
-
45
- /**
46
- * Creates an object that contains encoders for every channel of a mark
47
- *
48
- * TODO: This should actually receive the mark as parameter
49
- *
50
- * TODO: This method should have a test. But how to mock Mark...
51
- *
52
- * @param {import("../marks/mark").default} mark
53
- * @param {import("../spec/channel").Encoding} [encoding] Taken from the mark if not provided
54
- * @returns {Partial<Record<Channel, Encoder>>}
55
- */
56
- export default function createEncoders(mark, encoding) {
57
- /** @type {Partial<Record<Channel, Encoder>>} */
58
- const encoders = {};
59
-
60
- if (!encoding) {
61
- encoding = mark.encoding;
62
- }
63
-
64
- for (const [channel, channelDef] of Object.entries(encoding)) {
65
- if (!channelDef) {
66
- continue;
67
- }
68
-
69
- const resolution = mark.unitView.getScaleResolution(
70
- (isChannelDefWithScale(channelDef) &&
71
- channelDef.resolutionChannel) ||
72
- channel
73
- );
74
-
75
- encoders[channel] = createEncoder(
76
- encoding[channel],
77
- resolution?.getScale(),
78
- mark.unitView.getAccessor(channel),
79
- channel
80
- );
81
- }
82
-
83
- return encoders;
84
- }
85
-
86
- /**
87
- *
88
- * @param {import("../spec/channel").ChannelDef} channelDef
89
- * @param {any} scale
90
- * @param {import("./accessor").Accessor} accessor
91
- * @param {Channel} channel
92
- * @returns {Encoder}
93
- */
94
- export function createEncoder(channelDef, scale, accessor, channel) {
95
- /** @type {Encoder} */
96
- let encoder;
97
-
98
- if (isValueDef(channelDef)) {
99
- const value = channelDef.value;
100
- encoder = /** @type {Encoder} */ ((datum) => value);
101
- encoder.constant = true;
102
- encoder.constantValue = true;
103
- encoder.accessor = undefined;
104
- } else if (accessor) {
105
- if (channel == "text") {
106
- // TODO: Define somewhere channels that don't use a scale
107
- encoder = /** @type {Encoder} */ ((datum) => undefined);
108
- encoder.accessor = accessor;
109
- encoder.constant = accessor.constant;
110
- } else {
111
- if (!scale) {
112
- throw new Error(
113
- `Missing scale! "${channel}": ${JSON.stringify(channelDef)}`
114
- );
115
- }
116
-
117
- encoder = /** @type {Encoder} */ (
118
- (datum) => scale(accessor(datum))
119
- );
120
-
121
- if (isDiscrete(scale.type)) {
122
- // TODO: pass the found values back to the scale/resolution
123
- const indexer = createIndexer();
124
- indexer.addAll(scale.domain());
125
- encoder.indexer = indexer;
126
- }
127
-
128
- encoder.constant = accessor.constant;
129
- encoder.accessor = accessor;
130
- encoder.scale = scale;
131
- }
132
- } else {
133
- throw new Error(
134
- `Missing value or accessor (field, expr, datum) on channel "${channel}": ${JSON.stringify(
135
- channelDef
136
- )}`
137
- );
138
- }
139
-
140
- // TODO: Modifier should be inverted too
141
- encoder.invert = scale
142
- ? (value) => scale.invert(value)
143
- : (value) => {
144
- throw new Error(
145
- "No scale available, cannot invert: " +
146
- JSON.stringify(channelDef)
147
- );
148
- };
149
-
150
- // Just to provide a convenient access to the config
151
- encoder.channelDef = channelDef;
152
-
153
- /** @param {Encoder} target */
154
- encoder.applyMetadata = (target) => {
155
- for (const prop in encoder) {
156
- if (prop in encoder) {
157
- // @ts-ignore
158
- target[prop] = encoder[prop];
159
- }
160
- }
161
- return target;
162
- };
163
-
164
- return encoder;
165
- }
166
-
167
- /**
168
- * TODO: Move to a more generic place
169
- *
170
- * @param {import("../spec/channel").ChannelDef} channelDef
171
- * @returns {channelDef is import("../spec/channel").ValueDef}
172
- */
173
- export function isValueDef(channelDef) {
174
- return channelDef && "value" in channelDef;
175
- }
176
-
177
- /**
178
- * @param {import("../spec/channel").ChannelDef} channelDef
179
- * @returns {channelDef is import("../spec/channel").FieldDefBase<string>}
180
- */
181
- export function isFieldDef(channelDef) {
182
- return channelDef && "field" in channelDef;
183
- }
184
-
185
- /**
186
- * @param {import("../spec/channel").ChannelDef} channelDef
187
- * @returns {channelDef is import("../spec/channel").DatumDef}
188
- */
189
- export function isDatumDef(channelDef) {
190
- return channelDef && "datum" in channelDef;
191
- }
192
-
193
- /**
194
- * @param {import("../spec/channel").ChannelDef} channelDef
195
- * @returns {channelDef is import("../spec/channel").ChannelDefWithScale}
196
- */
197
- export function isChannelDefWithScale(channelDef) {
198
- // TODO: Not accurate, fix
199
- return (
200
- isFieldDef(channelDef) ||
201
- isDatumDef(channelDef) ||
202
- isExprDef(channelDef) ||
203
- isChromPosDef(channelDef)
204
- );
205
- }
206
-
207
- /**
208
- * @param {import("../view/unitView").default} view
209
- * @param {Channel} channel
210
- */
211
- export function getChannelDefWithScale(view, channel) {
212
- const channelDef = view.mark.encoding[channel];
213
- if (isChannelDefWithScale(channelDef)) {
214
- return channelDef;
215
- } else {
216
- throw new Error("Not a channel def with scale!");
217
- }
218
- }
219
-
220
- /**
221
- * @param {import("../spec/channel").ChannelDef} channelDef
222
- * @returns {channelDef is import("../spec/channel").ChromPosDef}
223
- */
224
- export function isChromPosDef(channelDef) {
225
- return channelDef && "chrom" in channelDef;
226
- }
227
-
228
- /**
229
- * @param {import("../spec/channel").ChannelDef} channelDef
230
- * @returns {channelDef is import("../spec/channel").ExprDef}
231
- */
232
- export function isExprDef(channelDef) {
233
- return channelDef && "expr" in channelDef;
234
- }
235
-
236
- /**
237
- * @type {import("../spec/channel").PrimaryPositionalChannel[]}
238
- */
239
- export const primaryPositionalChannels = ["x", "y"];
240
-
241
- /**
242
- * @type {import("../spec/channel").SecondaryPositionalChannel[]}
243
- */
244
- export const secondaryPositionalChannels = ["x2", "y2"];
245
-
246
- /**
247
- * @type {import("../spec/channel").PositionalChannel[]}
248
- */
249
- export const positionalChannels = [
250
- ...primaryPositionalChannels,
251
- ...secondaryPositionalChannels,
252
- ];
253
-
254
- /**
255
- * @param {Channel} channel
256
- * @returns {channel is import("../spec/channel").PrimaryPositionalChannel}
257
- */
258
- export function isPrimaryPositionalChannel(channel) {
259
- // @ts-expect-error
260
- return primaryPositionalChannels.includes(channel);
261
- }
262
-
263
- /**
264
- * @param {Channel} channel
265
- * @returns {channel is import("../spec/channel").PositionalChannel}
266
- */
267
- export function isPositionalChannel(channel) {
268
- // @ts-expect-error
269
- return positionalChannels.includes(channel);
270
- }
271
-
272
- /**
273
- * Map primary channels to secondarys
274
- *
275
- * @type {Partial<Record<Channel, import("../spec/channel").SecondaryPositionalChannel>>}
276
- */
277
- export const secondaryChannels = {
278
- x: "x2",
279
- y: "y2",
280
- };
281
-
282
- /**
283
- * Map secondary channels to primaries
284
- *
285
- * @type {Partial<Record<Channel, Channel>>}
286
- */
287
- export const primaryChannels = Object.fromEntries(
288
- Object.entries(secondaryChannels).map((entry) => [entry[1], entry[0]])
289
- );
290
-
291
- /**
292
- *
293
- * @param {string} channel
294
- */
295
- export function isSecondaryChannel(channel) {
296
- return channel in primaryChannels;
297
- }
298
-
299
- /**
300
- * Return the matching secondary channel or throws if one does not exist.
301
- *
302
- * @param {Channel} primaryChannel
303
- */
304
- export function getSecondaryChannel(primaryChannel) {
305
- const secondary = secondaryChannels[primaryChannel];
306
- if (secondary) {
307
- return secondary;
308
- } else {
309
- throw new Error(`${primaryChannel} has no secondary channel!`);
310
- }
311
- }
312
-
313
- /**
314
- * Finds the primary channel for the provided channel, which may be
315
- * the primary or secondary.
316
- *
317
- * @param {Channel} channel
318
- */
319
- export function getPrimaryChannel(channel) {
320
- return primaryChannels[channel] ?? channel;
321
- }
322
-
323
- /**
324
- * Returns an array that contains the given channel and its secondary channel if one exists.
325
- *
326
- * @param {Channel} channel
327
- */
328
- export function getChannelWithSecondarys(channel) {
329
- return secondaryChannels[channel]
330
- ? [channel, secondaryChannels[channel]]
331
- : [channel];
332
- }
333
-
334
- /**
335
- * @param {Channel} channel
336
- */
337
- export function isColorChannel(channel) {
338
- return ["color", "fill", "stroke"].includes(getPrimaryChannel(channel));
339
- }
340
-
341
- /**
342
- * Returns true if the channel has a discrete range.
343
- *
344
- * @param {Channel} channel
345
- */
346
- export function isDiscreteChannel(channel) {
347
- return ["shape", "squeeze"].includes(channel);
348
- }
349
-
350
- /**
351
- * Returns valid discrete values for a discrete channel.
352
- *
353
- * @param {Channel} channel
354
- * @returns {any[]}
355
- */
356
- export function getDiscreteRange(channel) {
357
- // TODO: This is not easily extendable. Figure out a more dynamic approach.
358
- switch (channel) {
359
- case "shape":
360
- return [
361
- "circle",
362
- "square",
363
- "triangle-up",
364
- "cross",
365
- "diamond",
366
- "triangle-down",
367
- "triangle-right",
368
- "triangle-left",
369
- ];
370
- default:
371
- }
372
- }
373
-
374
- /**
375
- * @param {Channel} channel
376
- * @returns {function(any):number}
377
- */
378
- export function getDiscreteRangeMapper(channel) {
379
- if (!isDiscreteChannel(channel)) {
380
- throw new Error("Not a discrete channel: " + channel);
381
- }
382
-
383
- const valueMap = new Map(
384
- getDiscreteRange(channel).map((value, i) => [value, i])
385
- );
386
-
387
- return (value) => {
388
- const mapped = valueMap.get(value);
389
- if (mapped !== undefined) {
390
- return mapped;
391
- }
392
- throw new Error(`Invalid value for "${channel}" channel: ${value}`);
393
- };
394
- }
@@ -1,98 +0,0 @@
1
- import { describe, expect, test } from "vitest";
2
- import AccessorFactory from "./accessor";
3
- import { scale as vegaScale } from "vega-scale";
4
-
5
- import { createEncoder } from "./encoder";
6
-
7
- describe("Encoder", () => {
8
- /** @type {Record<string, import("../view/viewUtils").ChannelDef>} */
9
- const encodingSpecs = {
10
- x: { value: 0 },
11
- y: { field: "a" },
12
- z: { datum: 2 },
13
- size: { value: 5 },
14
- };
15
-
16
- const scaleLinear = vegaScale("linear");
17
-
18
- /** @type {Record<string, import("./encoder").VegaScale>} */
19
- const scales = {
20
- y: scaleLinear().domain([0, 10]),
21
- z: scaleLinear().domain([0, 20]),
22
- };
23
-
24
- const accessorFactory = new AccessorFactory();
25
-
26
- /** @param {Record<string, import("../view/viewUtils").ChannelDef>} encoding */
27
- function createEncoders(encoding) {
28
- /** @type {Record<string, import("./encoder").Encoder>} */
29
- const encoders = {};
30
- for (const [channel, channelDef] of Object.entries(encoding)) {
31
- encoders[channel] = createEncoder(
32
- channelDef,
33
- scales[channel],
34
- accessorFactory.createAccessor(encodingSpecs[channel]),
35
- channel
36
- );
37
- }
38
- return encoders;
39
- }
40
-
41
- const datum = {
42
- a: 5,
43
- b: 6,
44
- c: "Pink Floyd",
45
- };
46
-
47
- test("Throws on a broken spec", () =>
48
- expect(() => createEncoders({ x: {} })).toThrow());
49
-
50
- const encoders = createEncoders(encodingSpecs);
51
-
52
- test("The encoder object contains all channels", () =>
53
- expect(
54
- ["x", "y", "z", "size"].every(
55
- (channel) => typeof encoders[channel] === "function"
56
- )
57
- ).toBeTruthy());
58
-
59
- test("Returns a value", () => expect(encoders.x(datum)).toEqual(0));
60
-
61
- test("Encodes and returns a constant using a scale", () =>
62
- expect(encoders.z(datum)).toBeCloseTo(0.1));
63
-
64
- test("Accesses a field and uses a scale", () =>
65
- expect(encoders.y(datum)).toBeCloseTo(0.5));
66
-
67
- /*
68
- test("Accesses a field on a secondary channel and uses the scale from the primary", () =>
69
- expect(encoders.y2(datum)).toBeCloseTo(0.6));
70
- */
71
-
72
- test("Constant encoder is annotated", () => {
73
- expect(encoders.y.constant).toBeFalsy();
74
- expect(encoders.z.constant).toBeTruthy();
75
- expect(encoders.size.constant).toBeTruthy();
76
- });
77
-
78
- test("Constant value encoder is annotated", () => {
79
- expect(encoders.y.constantValue).toBeFalsy();
80
- expect(encoders.z.constantValue).toBeFalsy();
81
- expect(encoders.size.constantValue).toBeTruthy();
82
- });
83
-
84
- test("Inverts a value", () => {
85
- expect(encoders.y.invert(0.5)).toBeCloseTo(5);
86
- expect(encoders.z.invert(0.5)).toBeCloseTo(10);
87
- // A value, no scale, can't invert
88
- expect(() => encoders.size.invert(123)).toThrow();
89
- });
90
-
91
- test("Accessors are provided", () => {
92
- expect(encoders.y.accessor).toBeDefined();
93
- expect(encoders.z.accessor).toBeDefined();
94
- expect(encoders.x.accessor).toBeUndefined();
95
- });
96
-
97
- // TODO: Test indexer
98
- });