@genome-spy/core 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +224 -0
- package/dist/style.css +1 -0
- package/package.json +54 -0
- package/src/data/collector.js +178 -0
- package/src/data/collector.test.js +82 -0
- package/src/data/dataFlow.js +109 -0
- package/src/data/dataFlow.test.js +3 -0
- package/src/data/facetNode.js +17 -0
- package/src/data/flow.test.js +71 -0
- package/src/data/flowBatch.d.ts +40 -0
- package/src/data/flowNode.js +283 -0
- package/src/data/flowNode.test.js +49 -0
- package/src/data/flowOptimizer.js +117 -0
- package/src/data/flowOptimizer.test.js +192 -0
- package/src/data/flowTestUtils.js +63 -0
- package/src/data/formats/fasta.js +32 -0
- package/src/data/formats/fasta.test.js +26 -0
- package/src/data/sources/dataSource.js +22 -0
- package/src/data/sources/dataSourceFactory.js +24 -0
- package/src/data/sources/dataUtils.js +31 -0
- package/src/data/sources/dynamicCallbackSource.js +56 -0
- package/src/data/sources/dynamicSource.js +36 -0
- package/src/data/sources/inlineSource.js +69 -0
- package/src/data/sources/inlineSource.test.js +55 -0
- package/src/data/sources/namedSource.js +74 -0
- package/src/data/sources/sequenceSource.js +46 -0
- package/src/data/sources/sequenceSource.test.js +45 -0
- package/src/data/sources/urlSource.js +74 -0
- package/src/data/transforms/aggregate.js +69 -0
- package/src/data/transforms/clone.js +40 -0
- package/src/data/transforms/clone.test.js +10 -0
- package/src/data/transforms/coverage.js +187 -0
- package/src/data/transforms/coverage.test.js +122 -0
- package/src/data/transforms/filter.js +37 -0
- package/src/data/transforms/filter.test.js +17 -0
- package/src/data/transforms/filterScoredLabels.js +134 -0
- package/src/data/transforms/flattenCompressedExons.js +57 -0
- package/src/data/transforms/flattenDelimited.js +68 -0
- package/src/data/transforms/flattenDelimited.test.js +86 -0
- package/src/data/transforms/flattenSequence.js +39 -0
- package/src/data/transforms/flattenSequence.test.js +33 -0
- package/src/data/transforms/formula.js +39 -0
- package/src/data/transforms/formula.test.js +18 -0
- package/src/data/transforms/identifier.js +108 -0
- package/src/data/transforms/identifier.test.js +82 -0
- package/src/data/transforms/linearizeGenomicCoordinate.js +101 -0
- package/src/data/transforms/measureText.js +44 -0
- package/src/data/transforms/pileup.js +128 -0
- package/src/data/transforms/pileup.test.js +69 -0
- package/src/data/transforms/project.js +41 -0
- package/src/data/transforms/project.test.js +31 -0
- package/src/data/transforms/regexExtract.js +61 -0
- package/src/data/transforms/regexExtract.test.js +66 -0
- package/src/data/transforms/regexFold.js +141 -0
- package/src/data/transforms/regexFold.test.js +159 -0
- package/src/data/transforms/sample.js +101 -0
- package/src/data/transforms/sample.test.js +37 -0
- package/src/data/transforms/stack.js +137 -0
- package/src/data/transforms/stack.test.js +90 -0
- package/src/data/transforms/transformFactory.js +60 -0
- package/src/encoder/accessor.js +82 -0
- package/src/encoder/accessor.test.js +46 -0
- package/src/encoder/encoder.js +369 -0
- package/src/encoder/encoder.test.js +97 -0
- package/src/fonts/Lato-Regular.json +1267 -0
- package/src/fonts/Lato-Regular.png +0 -0
- package/src/fonts/OFL.txt +93 -0
- package/src/fonts/README.md +3 -0
- package/src/fonts/bmFont.d.ts +58 -0
- package/src/fonts/bmFontManager.js +357 -0
- package/src/fonts/bmFontMetrics.js +108 -0
- package/src/genome/genome.js +305 -0
- package/src/genome/genome.test.js +152 -0
- package/src/genome/genomeStore.js +54 -0
- package/src/genome/locusFormat.js +31 -0
- package/src/genome/scaleIndex.js +199 -0
- package/src/genome/scaleIndex.test.js +61 -0
- package/src/genome/scaleLocus.js +112 -0
- package/src/genome/scaleLocus.test.js +3 -0
- package/src/genomeSpy.js +753 -0
- package/src/gl/arrayBuilder.js +199 -0
- package/src/gl/dataToVertices.js +621 -0
- package/src/gl/includes/common.glsl +63 -0
- package/src/gl/includes/fp64-arithmetic.glsl +187 -0
- package/src/gl/includes/fp64-utils.js +132 -0
- package/src/gl/includes/picking.fragment.glsl +3 -0
- package/src/gl/includes/picking.vertex.glsl +29 -0
- package/src/gl/includes/sampleFacet.glsl +107 -0
- package/src/gl/includes/scales.glsl +79 -0
- package/src/gl/includes/scales_fp64.glsl +30 -0
- package/src/gl/link.fragment.glsl +18 -0
- package/src/gl/link.vertex.glsl +111 -0
- package/src/gl/point.fragment.glsl +123 -0
- package/src/gl/point.vertex.glsl +128 -0
- package/src/gl/rect.fragment.glsl +51 -0
- package/src/gl/rect.vertex.glsl +114 -0
- package/src/gl/rule.fragment.glsl +52 -0
- package/src/gl/rule.vertex.glsl +89 -0
- package/src/gl/text.fragment.glsl +31 -0
- package/src/gl/text.vertex.glsl +246 -0
- package/src/gl/webGLHelper.js +490 -0
- package/src/img/bowtie.svg +1 -0
- package/src/img/genomespy-favicon.svg +34 -0
- package/src/index.html +11 -0
- package/src/index.js +151 -0
- package/src/marks/link.js +189 -0
- package/src/marks/mark.js +867 -0
- package/src/marks/markUtils.js +109 -0
- package/src/marks/pointMark.js +279 -0
- package/src/marks/rectMark.js +236 -0
- package/src/marks/rule.js +231 -0
- package/src/marks/text.js +274 -0
- package/src/options.d.ts +9 -0
- package/src/scale/colorUtils.js +184 -0
- package/src/scale/glslScaleGenerator.js +462 -0
- package/src/scale/scale.js +441 -0
- package/src/scale/scale.test.js +323 -0
- package/src/scale/ticks.js +198 -0
- package/src/scale/ticks.test.js +39 -0
- package/src/singlePageApp.js +13 -0
- package/src/spec/axis.d.ts +296 -0
- package/src/spec/channel.d.ts +127 -0
- package/src/spec/data.d.ts +185 -0
- package/src/spec/font.d.ts +15 -0
- package/src/spec/genome.d.ts +35 -0
- package/src/spec/mark.d.ts +432 -0
- package/src/spec/root.d.ts +22 -0
- package/src/spec/scale.d.ts +265 -0
- package/src/spec/tooltip.d.ts +9 -0
- package/src/spec/transform.d.ts +479 -0
- package/src/spec/view.d.ts +215 -0
- package/src/styles/genome-spy.scss +153 -0
- package/src/tooltip/dataTooltipHandler.js +59 -0
- package/src/tooltip/refseqGeneTooltipHandler.js +77 -0
- package/src/tooltip/tooltipHandler.ts +12 -0
- package/src/types/filetypes.d.ts +4 -0
- package/src/types/flatqueue.d.ts +53 -0
- package/src/types/glsl.d.ts +4 -0
- package/src/types/object.d.ts +21 -0
- package/src/types/vega-scale.d.ts +60 -0
- package/src/utils/animator.js +83 -0
- package/src/utils/arrayUtils.js +55 -0
- package/src/utils/binnedRangeIndex.js +83 -0
- package/src/utils/clamp.js +8 -0
- package/src/utils/cloner.js +32 -0
- package/src/utils/cloner.test.js +23 -0
- package/src/utils/coalesce.js +11 -0
- package/src/utils/coalesce.test.js +15 -0
- package/src/utils/concatIterables.js +26 -0
- package/src/utils/concatIterables.test.js +7 -0
- package/src/utils/debounce.js +37 -0
- package/src/utils/domainArray.js +224 -0
- package/src/utils/domainArray.test.js +129 -0
- package/src/utils/eerp.js +13 -0
- package/src/utils/expression.js +32 -0
- package/src/utils/field.js +28 -0
- package/src/utils/fisheye.js +60 -0
- package/src/utils/formatObject.js +31 -0
- package/src/utils/html.js +23 -0
- package/src/utils/html.test.js +13 -0
- package/src/utils/indexer.js +43 -0
- package/src/utils/indexer.test.js +46 -0
- package/src/utils/inertia.js +124 -0
- package/src/utils/interactionEvent.js +33 -0
- package/src/utils/iterateNestedMaps.js +21 -0
- package/src/utils/iterateNestedMaps.test.js +32 -0
- package/src/utils/kWayMerge.js +42 -0
- package/src/utils/kWayMerge.test.js +25 -0
- package/src/utils/layout/flexLayout.js +336 -0
- package/src/utils/layout/flexLayout.test.js +296 -0
- package/src/utils/layout/padding.js +107 -0
- package/src/utils/layout/point.js +23 -0
- package/src/utils/layout/rectangle.js +282 -0
- package/src/utils/layout/rectangle.test.js +171 -0
- package/src/utils/mergeObjects.js +99 -0
- package/src/utils/mergeObjects.test.js +41 -0
- package/src/utils/numberExtractor.js +24 -0
- package/src/utils/numberExtractor.test.js +5 -0
- package/src/utils/point.js +14 -0
- package/src/utils/propertyCacher.js +70 -0
- package/src/utils/propertyCacher.test.js +84 -0
- package/src/utils/propertyCoalescer.js +37 -0
- package/src/utils/propertyCoalescer.test.js +21 -0
- package/src/utils/reservationMap.js +103 -0
- package/src/utils/reservationMap.test.js +19 -0
- package/src/utils/scaleNull.js +19 -0
- package/src/utils/setOperations.js +75 -0
- package/src/utils/smoothstep.js +10 -0
- package/src/utils/throttle.js +34 -0
- package/src/utils/topK.js +76 -0
- package/src/utils/topK.test.js +63 -0
- package/src/utils/transition.js +74 -0
- package/src/utils/ui/tooltip.js +189 -0
- package/src/utils/url.js +22 -0
- package/src/utils/variableTools.js +24 -0
- package/src/utils/variableTools.test.js +12 -0
- package/src/view/axisResolution.js +135 -0
- package/src/view/axisResolution.test.js +200 -0
- package/src/view/axisView.js +746 -0
- package/src/view/channel.js +5 -0
- package/src/view/concatView.js +296 -0
- package/src/view/containerView.js +141 -0
- package/src/view/decoratorView.js +510 -0
- package/src/view/facetView.js +488 -0
- package/src/view/flowBuilder.js +362 -0
- package/src/view/flowBuilder.test.js +124 -0
- package/src/view/importView.js +19 -0
- package/src/view/layerView.js +60 -0
- package/src/view/rendering.d.ts +44 -0
- package/src/view/renderingContext/compositeViewRenderingContext.js +51 -0
- package/src/view/renderingContext/deferredViewRenderingContext.js +174 -0
- package/src/view/renderingContext/layoutRecorderViewRenderingContext.js +128 -0
- package/src/view/renderingContext/simpleViewRenderingContext.js +62 -0
- package/src/view/renderingContext/svgViewRenderingContext.js +121 -0
- package/src/view/renderingContext/viewRenderingContext.js +41 -0
- package/src/view/scaleResolution.js +756 -0
- package/src/view/scaleResolution.test.js +571 -0
- package/src/view/scaleResolutionApi.d.ts +40 -0
- package/src/view/testUtils.js +48 -0
- package/src/view/unitView.js +368 -0
- package/src/view/view.js +589 -0
- package/src/view/view.test.js +213 -0
- package/src/view/viewContext.d.ts +57 -0
- package/src/view/viewFactory.js +179 -0
- package/src/view/viewFactory.test.js +16 -0
- package/src/view/viewUtils.js +420 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
@use "sass:math";
|
|
2
|
+
|
|
3
|
+
$basic-spacing: 10px;
|
|
4
|
+
|
|
5
|
+
$font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif,
|
|
6
|
+
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
|
7
|
+
|
|
8
|
+
.genome-spy {
|
|
9
|
+
font-family: $font-family;
|
|
10
|
+
|
|
11
|
+
position: relative;
|
|
12
|
+
|
|
13
|
+
canvas {
|
|
14
|
+
transform: scale(1, 1);
|
|
15
|
+
opacity: 1;
|
|
16
|
+
transition: transform 0.6s, opacity 0.6s;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.loading-message {
|
|
20
|
+
position: absolute;
|
|
21
|
+
top: 0;
|
|
22
|
+
bottom: 0;
|
|
23
|
+
left: 0;
|
|
24
|
+
right: 0;
|
|
25
|
+
display: flex;
|
|
26
|
+
|
|
27
|
+
align-items: center;
|
|
28
|
+
justify-content: center;
|
|
29
|
+
|
|
30
|
+
.message {
|
|
31
|
+
color: #666;
|
|
32
|
+
opacity: 0;
|
|
33
|
+
transition: opacity 0.7s;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
&.loading {
|
|
38
|
+
canvas {
|
|
39
|
+
transform: scale(0.95, 0.95);
|
|
40
|
+
opacity: 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.loading-message .message {
|
|
44
|
+
opacity: 1;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.ellipsis {
|
|
48
|
+
animation: blinker 1s linear infinite;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@keyframes blinker {
|
|
52
|
+
50% {
|
|
53
|
+
opacity: 0;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.tooltip {
|
|
59
|
+
position: absolute;
|
|
60
|
+
|
|
61
|
+
max-width: 450px;
|
|
62
|
+
overflow: hidden;
|
|
63
|
+
|
|
64
|
+
$background-color: #f6f6f6;
|
|
65
|
+
background: $background-color;
|
|
66
|
+
padding: $basic-spacing;
|
|
67
|
+
font-size: 13px;
|
|
68
|
+
|
|
69
|
+
box-shadow: 0px 3px 15px 0px rgba(0, 0, 0, 0.21);
|
|
70
|
+
|
|
71
|
+
pointer-events: none;
|
|
72
|
+
z-index: 100;
|
|
73
|
+
|
|
74
|
+
> :last-child {
|
|
75
|
+
margin-bottom: 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
> .title {
|
|
79
|
+
padding-bottom: math.div($basic-spacing, 2);
|
|
80
|
+
margin-bottom: math.div($basic-spacing, 2);
|
|
81
|
+
border-bottom: 1px dashed darken($background-color, 25%);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.summary {
|
|
85
|
+
font-size: 12px;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
table {
|
|
89
|
+
&:first-child {
|
|
90
|
+
margin-top: 0;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
border-collapse: collapse;
|
|
94
|
+
|
|
95
|
+
th,
|
|
96
|
+
td {
|
|
97
|
+
padding: 2px 0.4em;
|
|
98
|
+
vertical-align: top;
|
|
99
|
+
|
|
100
|
+
&:first-child {
|
|
101
|
+
padding-left: 0;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
th {
|
|
106
|
+
text-align: left;
|
|
107
|
+
font-weight: bold;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.color-legend {
|
|
112
|
+
display: inline-block;
|
|
113
|
+
width: 0.8em;
|
|
114
|
+
height: 0.8em;
|
|
115
|
+
margin-left: 0.4em;
|
|
116
|
+
box-shadow: 0px 0px 3px 1px white;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.attributes {
|
|
120
|
+
.hovered {
|
|
121
|
+
background-color: #e0e0e0;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.na {
|
|
126
|
+
color: #aaa;
|
|
127
|
+
font-style: italic;
|
|
128
|
+
font-size: 80%;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.gene-track-tooltip {
|
|
133
|
+
.summary {
|
|
134
|
+
font-size: 90%;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.message-box {
|
|
139
|
+
display: flex;
|
|
140
|
+
align-items: center;
|
|
141
|
+
justify-content: center;
|
|
142
|
+
position: absolute;
|
|
143
|
+
top: 0;
|
|
144
|
+
height: 100%;
|
|
145
|
+
width: 100%;
|
|
146
|
+
|
|
147
|
+
> div {
|
|
148
|
+
border: 1px solid red;
|
|
149
|
+
padding: 10px;
|
|
150
|
+
background: #fff0f0;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { html } from "lit-html";
|
|
2
|
+
import formatObject from "../utils/formatObject";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @type {import("./tooltipHandler").TooltipHandler}
|
|
6
|
+
*/
|
|
7
|
+
export default async function dataTooltipHandler(datum, mark, params) {
|
|
8
|
+
/**
|
|
9
|
+
* @param {string} key
|
|
10
|
+
* @param {object} datum
|
|
11
|
+
*/
|
|
12
|
+
const legend = (key, datum) => {
|
|
13
|
+
for (const [channel, encoder] of Object.entries(mark.encoders)) {
|
|
14
|
+
if (encoder?.accessor?.fields.includes(key)) {
|
|
15
|
+
switch (channel) {
|
|
16
|
+
case "color":
|
|
17
|
+
case "fill":
|
|
18
|
+
case "stroke":
|
|
19
|
+
return html`
|
|
20
|
+
<span
|
|
21
|
+
class="color-legend"
|
|
22
|
+
style=${`background-color: ${encoder(datum)}`}
|
|
23
|
+
></span>
|
|
24
|
+
`;
|
|
25
|
+
default:
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return "";
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const table = html`
|
|
34
|
+
<table class="attributes">
|
|
35
|
+
${Object.entries(datum)
|
|
36
|
+
.filter(([key, value]) => !key.startsWith("_"))
|
|
37
|
+
.map(
|
|
38
|
+
([key, value]) => html`
|
|
39
|
+
<tr>
|
|
40
|
+
<th>${key}</th>
|
|
41
|
+
<td>
|
|
42
|
+
${formatObject(value)} ${legend(key, datum)}
|
|
43
|
+
</td>
|
|
44
|
+
</tr>
|
|
45
|
+
`
|
|
46
|
+
)}
|
|
47
|
+
</table>
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
const title = mark.unitView.spec.title
|
|
51
|
+
? html`
|
|
52
|
+
<div class="title">
|
|
53
|
+
<strong>${mark.unitView.spec.title}</strong>
|
|
54
|
+
</div>
|
|
55
|
+
`
|
|
56
|
+
: "";
|
|
57
|
+
|
|
58
|
+
return html`${title}${table}`;
|
|
59
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { debounce } from "../utils/debounce";
|
|
2
|
+
import { html } from "lit-html";
|
|
3
|
+
|
|
4
|
+
/*
|
|
5
|
+
* https://www.ncbi.nlm.nih.gov/books/NBK25500/
|
|
6
|
+
*
|
|
7
|
+
* TODO: Implement tool & email parameters: https://www.ncbi.nlm.nih.gov/books/NBK25497/
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// TODO: Replace with an LRU-cache
|
|
11
|
+
const symbolSummaryCache = new Map();
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @type {import("./tooltipHandler").TooltipHandler}
|
|
15
|
+
*/
|
|
16
|
+
export default async function refseqGeneTooltipHandler(datum, mark, params) {
|
|
17
|
+
const symbol = datum.symbol;
|
|
18
|
+
|
|
19
|
+
let summary =
|
|
20
|
+
symbolSummaryCache.get(symbol) ??
|
|
21
|
+
(await debouncedFetchGeneSummary(datum.symbol));
|
|
22
|
+
|
|
23
|
+
if (summary) {
|
|
24
|
+
symbolSummaryCache.set(symbol, summary);
|
|
25
|
+
return html`
|
|
26
|
+
<div class="title">
|
|
27
|
+
<strong>${summary.name}</strong>
|
|
28
|
+
${summary.description}
|
|
29
|
+
</div>
|
|
30
|
+
<p class="summary">${summary.summary}</p>
|
|
31
|
+
<p class="source">Source: NCBI RefSeq Gene</p>
|
|
32
|
+
`;
|
|
33
|
+
} else {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {string} symbol
|
|
40
|
+
*/
|
|
41
|
+
async function fetchGeneSummary(symbol) {
|
|
42
|
+
// TODO: Add more search terms to ensure that we really find genes specific to the current genome
|
|
43
|
+
|
|
44
|
+
console.log("Searching: " + symbol);
|
|
45
|
+
|
|
46
|
+
const opts = { mode: "cors" };
|
|
47
|
+
|
|
48
|
+
const searchResult = await fetch(
|
|
49
|
+
`https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=gene&term=${symbol}[GENE]&sort=relevance&retmode=json`,
|
|
50
|
+
opts
|
|
51
|
+
).then((res) => res.json());
|
|
52
|
+
|
|
53
|
+
// TODO: Handle failed searchs
|
|
54
|
+
const id = searchResult.esearchresult.idlist[0];
|
|
55
|
+
|
|
56
|
+
if (id) {
|
|
57
|
+
const summaryResult = await fetch(
|
|
58
|
+
`https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=gene&id=${id}&retmode=json`,
|
|
59
|
+
opts
|
|
60
|
+
).then((res) => res.json());
|
|
61
|
+
|
|
62
|
+
const summary = summaryResult.result[id];
|
|
63
|
+
return summary;
|
|
64
|
+
} else {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const debounced = debounce(fetchGeneSummary, 500);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
*
|
|
73
|
+
* @param {string} symbol
|
|
74
|
+
*/
|
|
75
|
+
function debouncedFetchGeneSummary(symbol) {
|
|
76
|
+
return debounced(symbol);
|
|
77
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TemplateResult } from "lit-html";
|
|
2
|
+
import Mark from "../marks/mark";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Converts a datum to tooltip (HTMLElement or lit's TemplateResult).
|
|
6
|
+
*/
|
|
7
|
+
export type TooltipHandler = (
|
|
8
|
+
datum: Record<string, any>,
|
|
9
|
+
mark: Mark,
|
|
10
|
+
/** Optional parameters from the view specification */
|
|
11
|
+
params?: Record<string, any>
|
|
12
|
+
) => Promise<string | TemplateResult | HTMLElement>;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapted from: https://github.com/mourner/flatqueue/blob/master/index.d.ts
|
|
3
|
+
*
|
|
4
|
+
* A version with typings is yet be released...
|
|
5
|
+
*/
|
|
6
|
+
declare module "flatqueue" {
|
|
7
|
+
export default class FlatQueue<T> {
|
|
8
|
+
/**
|
|
9
|
+
* Number of items in the queue.
|
|
10
|
+
*/
|
|
11
|
+
readonly length: number;
|
|
12
|
+
|
|
13
|
+
constructor();
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Removes all items from the queue.
|
|
17
|
+
*/
|
|
18
|
+
clear(): void;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Adds `item` to the queue with the specified `priority`.
|
|
22
|
+
*
|
|
23
|
+
* `priority` must be a number. Items are sorted and returned from low to
|
|
24
|
+
* high priority. Multiple items with the same priority value can be added
|
|
25
|
+
* to the queue, but there is no guaranteed order between these items.
|
|
26
|
+
*/
|
|
27
|
+
push(item: T, priority: number): void;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Removes and returns the item from the head of this queue, which is one of
|
|
31
|
+
* the items with the lowest priority. If this queue is empty, returns
|
|
32
|
+
* `undefined`.
|
|
33
|
+
*/
|
|
34
|
+
pop(): T | undefined;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Returns the item from the head of this queue without removing it. If this
|
|
38
|
+
* queue is empty, returns `undefined`.
|
|
39
|
+
*/
|
|
40
|
+
peek(): T | undefined;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Returns the priority value of the item at the head of this queue without
|
|
44
|
+
* removing it. If this queue is empty, returns `undefined`.
|
|
45
|
+
*/
|
|
46
|
+
peekValue(): number | undefined;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Shrinks the internal arrays to `this.length`.
|
|
50
|
+
*/
|
|
51
|
+
shrink(): void;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type ObjectKeys<T> = T extends object
|
|
2
|
+
? (keyof T)[]
|
|
3
|
+
: T extends number
|
|
4
|
+
? []
|
|
5
|
+
: T extends Array<any> | string
|
|
6
|
+
? string[]
|
|
7
|
+
: never;
|
|
8
|
+
|
|
9
|
+
interface ObjectConstructor {
|
|
10
|
+
// Source: https://fettblog.eu/typescript-better-object-keys/
|
|
11
|
+
keys<T>(o: T): ObjectKeys<T>;
|
|
12
|
+
|
|
13
|
+
// Source: https://github.com/microsoft/TypeScript/issues/35101
|
|
14
|
+
entries<T>(
|
|
15
|
+
o: T
|
|
16
|
+
): T extends ArrayLike<infer U>
|
|
17
|
+
? [string, U][]
|
|
18
|
+
: { [K in keyof T]: [K, T[K]] }[keyof T][];
|
|
19
|
+
|
|
20
|
+
values<T>(o: T): T extends ArrayLike<infer U> ? U[] : T[keyof T][];
|
|
21
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
type MetaDatum =
|
|
2
|
+
| "continuous"
|
|
3
|
+
| "discrete"
|
|
4
|
+
| "discretizing"
|
|
5
|
+
| "interpolating"
|
|
6
|
+
| "log"
|
|
7
|
+
| "temporal";
|
|
8
|
+
|
|
9
|
+
type Color = string;
|
|
10
|
+
type Interpolator<T> = (t: number) => T;
|
|
11
|
+
type ColorInterpolator = Interpolator<Color>;
|
|
12
|
+
|
|
13
|
+
declare module "vega-scale" {
|
|
14
|
+
// TODO: Correct return type
|
|
15
|
+
export function scale(
|
|
16
|
+
type: string,
|
|
17
|
+
scale: () => any,
|
|
18
|
+
metadata: MetaDatum | MetaDatum[]
|
|
19
|
+
): any;
|
|
20
|
+
|
|
21
|
+
export function scheme(
|
|
22
|
+
name: string,
|
|
23
|
+
scheme: string[] | ColorInterpolator
|
|
24
|
+
): void;
|
|
25
|
+
export function scheme(name: string): ColorInterpolator;
|
|
26
|
+
|
|
27
|
+
// TODO: Correct return type
|
|
28
|
+
export function interpolate(name: string, gamma?: number): any;
|
|
29
|
+
|
|
30
|
+
export function interpolateColors(
|
|
31
|
+
colors: Color[],
|
|
32
|
+
type?: string,
|
|
33
|
+
gamma?: number
|
|
34
|
+
): ColorInterpolator;
|
|
35
|
+
|
|
36
|
+
export function interpolateRange<T>(
|
|
37
|
+
interpolator: Interpolator<T>,
|
|
38
|
+
range: number[]
|
|
39
|
+
): Interpolator<T>;
|
|
40
|
+
|
|
41
|
+
export function quantizeInterpolator<T>(
|
|
42
|
+
interpolator: Interpolator<T>,
|
|
43
|
+
count: number
|
|
44
|
+
): T[];
|
|
45
|
+
|
|
46
|
+
export function isValidScaleType(type: string): boolean;
|
|
47
|
+
export function isContinuous(key: string): boolean;
|
|
48
|
+
export function isDiscrete(key: string): boolean;
|
|
49
|
+
export function isDiscretizing(key: string): boolean;
|
|
50
|
+
export function isLogarithmic(key: string): boolean;
|
|
51
|
+
export function isTemporal(key: string): boolean;
|
|
52
|
+
export function isInterpolating(key: string): boolean;
|
|
53
|
+
export function isQuantile(key: string): boolean;
|
|
54
|
+
|
|
55
|
+
export function bandSpace(
|
|
56
|
+
count: number,
|
|
57
|
+
paddingInner: number,
|
|
58
|
+
paddingOuter: number
|
|
59
|
+
): number;
|
|
60
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import doTransition from "./transition";
|
|
2
|
+
|
|
3
|
+
export default class Animator {
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {function(number):void} renderCallback
|
|
7
|
+
*/
|
|
8
|
+
constructor(renderCallback) {
|
|
9
|
+
this._renderCallback = renderCallback;
|
|
10
|
+
this._renderRequested = false;
|
|
11
|
+
this._warn = false;
|
|
12
|
+
|
|
13
|
+
/** @type {(function(number):void)[]} */
|
|
14
|
+
this.transitions = [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Schedules a "transition" to be called before the actual rendering
|
|
19
|
+
* is preformed. The transition could adjust the layout, for example.
|
|
20
|
+
* This method also requests rendering to be performed.
|
|
21
|
+
*
|
|
22
|
+
* If the callback has already been requested (compared by identity),
|
|
23
|
+
* it is removed from the queue and added to the end.
|
|
24
|
+
*
|
|
25
|
+
* @param {function(number):void} callback
|
|
26
|
+
*/
|
|
27
|
+
requestTransition(callback) {
|
|
28
|
+
this.cancelTransition(callback);
|
|
29
|
+
this.transitions.push(callback);
|
|
30
|
+
this.requestRender();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {function(number):void} callback
|
|
35
|
+
*/
|
|
36
|
+
cancelTransition(callback) {
|
|
37
|
+
const existingIndex = this.transitions.indexOf(callback);
|
|
38
|
+
if (existingIndex >= 0) {
|
|
39
|
+
this.transitions.splice(existingIndex, 1);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Requests the request transitions and rendering callback to be called
|
|
45
|
+
* during the next animation frame. Redundant calls to this method are safe,
|
|
46
|
+
* they have no effect.
|
|
47
|
+
*/
|
|
48
|
+
requestRender() {
|
|
49
|
+
if (!this._renderRequested) {
|
|
50
|
+
this._renderRequested = true;
|
|
51
|
+
window.requestAnimationFrame((timestamp) => {
|
|
52
|
+
this._renderRequested = false;
|
|
53
|
+
|
|
54
|
+
const transitions = this.transitions;
|
|
55
|
+
this.transitions = [];
|
|
56
|
+
|
|
57
|
+
/** @type {function} */
|
|
58
|
+
let transitionCallback;
|
|
59
|
+
while ((transitionCallback = transitions.shift())) {
|
|
60
|
+
transitionCallback(timestamp);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this._renderCallback(timestamp);
|
|
64
|
+
});
|
|
65
|
+
} else if (this._warn) {
|
|
66
|
+
console.warn("Render already requested!");
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Initiates a transition with a `requestAnimationFrame` that is synced
|
|
72
|
+
* with this Animator instance.
|
|
73
|
+
*
|
|
74
|
+
* @param {import("./transition").TransitionOptions} options
|
|
75
|
+
*/
|
|
76
|
+
transition(options) {
|
|
77
|
+
return doTransition({
|
|
78
|
+
requestAnimationFrame: (callback) =>
|
|
79
|
+
this.requestTransition(callback),
|
|
80
|
+
...options,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param {A[]} a
|
|
4
|
+
* @param {B[]} b
|
|
5
|
+
* @param {function(A):T} [aAccessor]
|
|
6
|
+
* @param {function(B):T} [bAccessor]
|
|
7
|
+
* @template A, B, T
|
|
8
|
+
*/
|
|
9
|
+
export function shallowArrayEquals(a, b, aAccessor, bAccessor) {
|
|
10
|
+
aAccessor = aAccessor || ((x) => x);
|
|
11
|
+
bAccessor = bAccessor || ((x) => x);
|
|
12
|
+
return (
|
|
13
|
+
a.length == b.length &&
|
|
14
|
+
a.every((s, i) => aAccessor(a[i]) === bAccessor(b[i]))
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
*
|
|
20
|
+
* @param {any[]} a
|
|
21
|
+
*/
|
|
22
|
+
export function isHomogeneous(a) {
|
|
23
|
+
if (a.length <= 1) {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const first = a[0];
|
|
28
|
+
return a.every((x) => x === first);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {T[] | T} obj
|
|
33
|
+
* @returns {T[]}
|
|
34
|
+
* @template T
|
|
35
|
+
*/
|
|
36
|
+
export function asArray(obj) {
|
|
37
|
+
if (Array.isArray(obj)) {
|
|
38
|
+
return obj;
|
|
39
|
+
} else if (typeof obj != "undefined") {
|
|
40
|
+
return [obj];
|
|
41
|
+
} else {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Returns the last element of an array.
|
|
48
|
+
* Like vega-util's peek but with stricter typings
|
|
49
|
+
*
|
|
50
|
+
* @param {T[]} arr
|
|
51
|
+
* @template T
|
|
52
|
+
*/
|
|
53
|
+
export function peek(arr) {
|
|
54
|
+
return arr[arr.length - 1];
|
|
55
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import clamp from "./clamp";
|
|
2
|
+
|
|
3
|
+
const MAX_INTEGER = 2 ** 31 - 1;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @callback Lookup
|
|
7
|
+
* @param {number} start
|
|
8
|
+
* @param {number} end
|
|
9
|
+
* @returns {[number, number]}
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A binned index for (overlapping) ranges that are sorted by their start position.
|
|
14
|
+
* Allows for indexing vertices of mark instances.
|
|
15
|
+
*
|
|
16
|
+
* @param {number} size Number of bins
|
|
17
|
+
* @param {[number, number]} domain
|
|
18
|
+
*/
|
|
19
|
+
export default function createBinningRangeIndexer(size, domain) {
|
|
20
|
+
const startIndices = new Int32Array(size);
|
|
21
|
+
startIndices.fill(MAX_INTEGER);
|
|
22
|
+
|
|
23
|
+
const endIndices = new Int32Array(size);
|
|
24
|
+
|
|
25
|
+
const start = domain[0];
|
|
26
|
+
const domainLength = domain[1] - domain[0];
|
|
27
|
+
const divisor = domainLength / size;
|
|
28
|
+
|
|
29
|
+
/** @param {number} pos */
|
|
30
|
+
const getBin = (pos) =>
|
|
31
|
+
clamp(Math.floor((pos - start) / divisor), 0, size - 1);
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
*
|
|
35
|
+
* @param {number} start
|
|
36
|
+
* @param {number} end
|
|
37
|
+
* @param {number} startIndex
|
|
38
|
+
* @param {number} endIndex
|
|
39
|
+
*/
|
|
40
|
+
const indexer = (start, end, startIndex, endIndex) => {
|
|
41
|
+
const startBin = getBin(start);
|
|
42
|
+
const endBin = getBin(end);
|
|
43
|
+
|
|
44
|
+
// TODO: This loop could probably be done as a more efficient post processing
|
|
45
|
+
// step.
|
|
46
|
+
for (let bin = startBin; bin <= endBin; bin++) {
|
|
47
|
+
if (startIndices[bin] > startIndex) {
|
|
48
|
+
startIndices[bin] = startIndex;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (endIndices[bin] < endIndex) {
|
|
52
|
+
endIndices[bin] = endIndex;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @type {Lookup}
|
|
59
|
+
*/
|
|
60
|
+
const lookup = (start, end) => [
|
|
61
|
+
startIndices[getBin(start)],
|
|
62
|
+
endIndices[getBin(end)],
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
const getIndex = () => {
|
|
66
|
+
for (let i = 1; i < endIndices.length; i++) {
|
|
67
|
+
if (endIndices[i] < endIndices[i - 1]) {
|
|
68
|
+
endIndices[i] = endIndices[i - 1];
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
for (let i = endIndices.length - 1; i > 0; i--) {
|
|
72
|
+
if (endIndices[i - 1] > endIndices[i]) {
|
|
73
|
+
endIndices[i - 1] = endIndices[i];
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return lookup;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
indexer.getIndex = getIndex;
|
|
81
|
+
|
|
82
|
+
return indexer;
|
|
83
|
+
}
|