@genome-spy/core 0.19.0 → 0.21.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 +46 -119
- package/dist/schema.json +213 -25
- package/package.json +4 -3
- package/src/data/collector.test.js +2 -0
- package/src/data/dataFlow.test.js +2 -0
- package/src/data/flow.test.js +1 -0
- package/src/data/flowNode.test.js +1 -0
- package/src/data/flowOptimizer.test.js +1 -0
- package/src/data/formats/fasta.test.js +1 -0
- package/src/data/sources/inlineSource.test.js +1 -0
- package/src/data/sources/sequenceSource.test.js +1 -0
- package/src/data/transforms/clone.test.js +1 -0
- package/src/data/transforms/coverage.test.js +1 -0
- package/src/data/transforms/filter.test.js +1 -0
- package/src/data/transforms/flattenDelimited.test.js +1 -0
- package/src/data/transforms/flattenSequence.test.js +1 -0
- package/src/data/transforms/formula.test.js +1 -0
- package/src/data/transforms/identifier.test.js +1 -0
- package/src/data/transforms/pileup.test.js +1 -0
- package/src/data/transforms/project.test.js +1 -0
- package/src/data/transforms/regexExtract.test.js +1 -0
- package/src/data/transforms/regexFold.test.js +1 -0
- package/src/data/transforms/sample.test.js +1 -0
- package/src/data/transforms/stack.test.js +1 -0
- package/src/encoder/accessor.test.js +1 -0
- package/src/encoder/encoder.test.js +1 -0
- package/src/genome/genome.test.js +1 -0
- package/src/genome/scaleIndex.js +3 -2
- package/src/genome/scaleIndex.test.js +23 -6
- package/src/genome/scaleLocus.test.js +1 -0
- package/src/genomeSpy.js +16 -11
- package/src/gl/dataToVertices.js +52 -52
- package/src/gl/includes/common.glsl +12 -12
- package/src/gl/includes/picking.fragment.glsl +0 -2
- package/src/gl/includes/picking.vertex.glsl +0 -2
- package/src/gl/includes/scales.glsl +33 -2
- package/src/gl/point.vertex.glsl +0 -2
- package/src/gl/rule.vertex.glsl +1 -1
- package/src/gl/webGLHelper.js +0 -3
- package/src/marks/link.js +32 -39
- package/src/marks/mark.js +176 -106
- package/src/marks/pointMark.js +28 -59
- package/src/marks/rectMark.js +38 -33
- package/src/marks/rule.js +31 -21
- package/src/marks/text.js +18 -14
- package/src/scale/glslScaleGenerator.js +56 -17
- package/src/scale/scale.test.js +1 -0
- package/src/scale/ticks.test.js +1 -0
- package/src/spec/mark.d.ts +0 -3
- package/src/spec/scale.d.ts +0 -9
- package/src/spec/title.d.ts +102 -0
- package/src/spec/view.d.ts +6 -4
- package/src/tooltip/dataTooltipHandler.js +3 -2
- package/src/utils/addBaseUrl.test.js +1 -0
- package/src/utils/binnedIndex.js +147 -0
- package/src/utils/binnedIndex.test.js +73 -0
- package/src/utils/cloner.test.js +1 -0
- package/src/utils/coalesce.test.js +1 -0
- package/src/utils/concatIterables.test.js +1 -0
- package/src/utils/domainArray.test.js +1 -0
- package/src/utils/indexer.test.js +1 -0
- package/src/utils/iterateNestedMaps.test.js +1 -0
- package/src/utils/kWayMerge.test.js +1 -0
- package/src/utils/layout/flexLayout.js +35 -3
- package/src/utils/layout/flexLayout.test.js +15 -0
- package/src/utils/layout/grid.js +95 -0
- package/src/utils/layout/grid.test.js +71 -0
- package/src/utils/layout/padding.js +13 -0
- package/src/utils/layout/rectangle.js +6 -0
- package/src/utils/layout/rectangle.test.js +1 -0
- package/src/utils/mergeObjects.test.js +1 -0
- package/src/utils/numberExtractor.test.js +1 -0
- package/src/utils/propertyCacher.test.js +1 -0
- package/src/utils/propertyCoalescer.test.js +1 -0
- package/src/utils/reservationMap.test.js +1 -0
- package/src/utils/topK.test.js +1 -0
- package/src/utils/variableTools.test.js +1 -0
- package/src/view/axisResolution.test.js +1 -0
- package/src/view/axisView.js +3 -5
- package/src/view/concatView.js +24 -275
- package/src/view/flowBuilder.test.js +1 -0
- package/src/view/gridView.js +774 -0
- package/src/view/implicitRootView.js +14 -0
- package/src/view/layerView.js +15 -1
- package/src/view/renderingContext/deferredViewRenderingContext.js +3 -1
- package/src/view/renderingContext/simpleViewRenderingContext.js +3 -1
- package/src/view/scaleResolution.js +5 -11
- package/src/view/scaleResolution.test.js +1 -0
- package/src/view/title.js +165 -0
- package/src/view/unitView.js +9 -5
- package/src/view/view.js +35 -14
- package/src/view/view.test.js +1 -0
- package/src/view/viewContext.d.ts +6 -1
- package/src/view/viewFactory.test.js +1 -0
- package/src/view/viewUtils.js +1 -93
- package/src/view/zoom.js +89 -0
- package/src/gl/includes/fp64-arithmetic.glsl +0 -187
- package/src/gl/includes/fp64-utils.js +0 -142
- package/src/gl/includes/scales_fp64.glsl +0 -30
- package/src/utils/binnedRangeIndex.js +0 -83
- package/src/view/decoratorView.js +0 -513
package/src/marks/mark.js
CHANGED
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
createUniformBlockInfo,
|
|
5
5
|
createVertexArrayInfo,
|
|
6
6
|
setAttribInfoBufferFromArray,
|
|
7
|
+
setBlockUniforms,
|
|
7
8
|
setUniformBlock,
|
|
8
9
|
setUniforms,
|
|
9
10
|
} from "twgl.js";
|
|
10
|
-
import { isDiscrete } from "vega-scale";
|
|
11
|
-
import { fp64ify } from "../gl/includes/fp64-utils";
|
|
11
|
+
import { isContinuous, isDiscrete } from "vega-scale";
|
|
12
12
|
import createEncoders, {
|
|
13
13
|
isChannelDefWithScale,
|
|
14
14
|
isDatumDef,
|
|
@@ -20,11 +20,12 @@ import {
|
|
|
20
20
|
generateScaleGlsl,
|
|
21
21
|
RANGE_TEXTURE_PREFIX,
|
|
22
22
|
ATTRIBUTE_PREFIX,
|
|
23
|
+
isHighPrecisionScale,
|
|
24
|
+
toHighPrecisionDomainUniform,
|
|
25
|
+
splitHighPrecision,
|
|
23
26
|
} from "../scale/glslScaleGenerator";
|
|
24
|
-
import FP64 from "../gl/includes/fp64-arithmetic.glsl";
|
|
25
27
|
import GLSL_COMMON from "../gl/includes/common.glsl";
|
|
26
28
|
import GLSL_SCALES from "../gl/includes/scales.glsl";
|
|
27
|
-
import GLSL_SCALES_FP64 from "../gl/includes/scales_fp64.glsl";
|
|
28
29
|
import GLSL_SAMPLE_FACET from "../gl/includes/sampleFacet.glsl";
|
|
29
30
|
import GLSL_PICKING_VERTEX from "../gl/includes/picking.vertex.glsl";
|
|
30
31
|
import GLSL_PICKING_FRAGMENT from "../gl/includes/picking.fragment.glsl";
|
|
@@ -32,6 +33,7 @@ import { getCachedOrCall } from "../utils/propertyCacher";
|
|
|
32
33
|
import { createProgram } from "../gl/webGLHelper";
|
|
33
34
|
import coalesceProperties from "../utils/propertyCoalescer";
|
|
34
35
|
import { isScalar } from "../utils/variableTools";
|
|
36
|
+
import { InternMap } from "internmap";
|
|
35
37
|
|
|
36
38
|
export const SAMPLE_FACET_UNIFORM = "SAMPLE_FACET_UNIFORM";
|
|
37
39
|
export const SAMPLE_FACET_TEXTURE = "SAMPLE_FACET_TEXTURE";
|
|
@@ -77,6 +79,12 @@ export default class Mark {
|
|
|
77
79
|
/** @type {import("twgl.js").UniformBlockInfo} WebGL buffers */
|
|
78
80
|
this.domainUniformInfo = undefined;
|
|
79
81
|
|
|
82
|
+
/** @type {import("twgl.js").UniformBlockInfo} WebGL buffers */
|
|
83
|
+
this.viewUniformInfo = undefined;
|
|
84
|
+
|
|
85
|
+
/** @type {RangeMap<any>} keep track of facet locations within the vertex array */
|
|
86
|
+
this.rangeMap = new RangeMap();
|
|
87
|
+
|
|
80
88
|
// TODO: Implement https://vega.github.io/vega-lite/docs/config.html
|
|
81
89
|
/** @type {MarkConfig} */
|
|
82
90
|
this.defaultProperties = {
|
|
@@ -334,7 +342,10 @@ export default class Mark {
|
|
|
334
342
|
"};\n\n"
|
|
335
343
|
: "";
|
|
336
344
|
|
|
345
|
+
const vertexPrecision = "precision highp float;\n";
|
|
346
|
+
|
|
337
347
|
const vertexParts = [
|
|
348
|
+
vertexPrecision,
|
|
338
349
|
...extraHeaders,
|
|
339
350
|
GLSL_COMMON,
|
|
340
351
|
GLSL_SCALES,
|
|
@@ -345,11 +356,6 @@ export default class Mark {
|
|
|
345
356
|
vertexShader,
|
|
346
357
|
];
|
|
347
358
|
|
|
348
|
-
if (vertexParts.some((code) => /[Ff]p64/.test(code))) {
|
|
349
|
-
vertexParts.unshift(GLSL_SCALES_FP64);
|
|
350
|
-
vertexParts.unshift(FP64);
|
|
351
|
-
}
|
|
352
|
-
|
|
353
359
|
const fragmentParts = [
|
|
354
360
|
...extraHeaders,
|
|
355
361
|
GLSL_COMMON,
|
|
@@ -401,9 +407,21 @@ export default class Mark {
|
|
|
401
407
|
);
|
|
402
408
|
}
|
|
403
409
|
|
|
410
|
+
this.viewUniformInfo = createUniformBlockInfo(
|
|
411
|
+
this.gl,
|
|
412
|
+
this.programInfo,
|
|
413
|
+
"View"
|
|
414
|
+
);
|
|
415
|
+
|
|
404
416
|
this.gl.useProgram(this.programInfo.program);
|
|
405
417
|
|
|
406
418
|
this._setDatums();
|
|
419
|
+
|
|
420
|
+
setUniforms(this.programInfo, {
|
|
421
|
+
// left pos, left height, right pos, right height
|
|
422
|
+
uSampleFacet: [0, 1, 0, 1],
|
|
423
|
+
uTransitionOffset: 0.0,
|
|
424
|
+
});
|
|
407
425
|
}
|
|
408
426
|
|
|
409
427
|
_setDatums() {
|
|
@@ -413,8 +431,8 @@ export default class Mark {
|
|
|
413
431
|
|
|
414
432
|
const datum = encoder.indexer
|
|
415
433
|
? encoder.indexer(channelDef.datum)
|
|
416
|
-
: encoder.scale.
|
|
417
|
-
?
|
|
434
|
+
: isHighPrecisionScale(encoder.scale.type)
|
|
435
|
+
? splitHighPrecision(+channelDef.datum)
|
|
418
436
|
: +channelDef.datum;
|
|
419
437
|
|
|
420
438
|
setUniforms(this.programInfo, {
|
|
@@ -537,21 +555,27 @@ export default class Mark {
|
|
|
537
555
|
* and scales) and buffers.
|
|
538
556
|
*
|
|
539
557
|
* @param {import("../view/rendering").GlobalRenderingOptions} options
|
|
558
|
+
* @returns {(() => void)[]}
|
|
540
559
|
*/
|
|
541
560
|
// eslint-disable-next-line complexity
|
|
542
561
|
prepareRender(options) {
|
|
543
562
|
const glHelper = this.glHelper;
|
|
544
563
|
const gl = this.gl;
|
|
545
564
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
this.gl,
|
|
549
|
-
this.programInfo,
|
|
550
|
-
this.bufferInfo
|
|
551
|
-
);
|
|
552
|
-
}
|
|
565
|
+
/** @type {(() => void)[]} */
|
|
566
|
+
const ops = [];
|
|
553
567
|
|
|
554
|
-
|
|
568
|
+
ops.push(() => {
|
|
569
|
+
if (!this.vertexArrayInfo) {
|
|
570
|
+
this.vertexArrayInfo = createVertexArrayInfo(
|
|
571
|
+
this.gl,
|
|
572
|
+
this.programInfo,
|
|
573
|
+
this.bufferInfo
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
gl.useProgram(this.programInfo.program);
|
|
578
|
+
});
|
|
555
579
|
|
|
556
580
|
if (this.domainUniformInfo) {
|
|
557
581
|
// TODO: Only update the domains that have changed
|
|
@@ -574,19 +598,24 @@ export default class Mark {
|
|
|
574
598
|
|
|
575
599
|
if (resolution) {
|
|
576
600
|
const scale = resolution.getScale();
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
601
|
+
|
|
602
|
+
ops.push(() => {
|
|
603
|
+
const domain = isDiscrete(scale.type)
|
|
604
|
+
? [0, scale.domain().length]
|
|
605
|
+
: scale.domain();
|
|
606
|
+
|
|
607
|
+
setter(
|
|
608
|
+
isHighPrecisionScale(scale.type)
|
|
609
|
+
? toHighPrecisionDomainUniform(domain)
|
|
610
|
+
: domain
|
|
611
|
+
);
|
|
612
|
+
});
|
|
586
613
|
}
|
|
587
614
|
}
|
|
588
615
|
|
|
589
|
-
|
|
616
|
+
ops.push(() =>
|
|
617
|
+
setUniformBlock(gl, this.programInfo, this.domainUniformInfo)
|
|
618
|
+
);
|
|
590
619
|
}
|
|
591
620
|
|
|
592
621
|
for (const [channel, channelDef] of Object.entries(this.encoding)) {
|
|
@@ -601,49 +630,56 @@ export default class Mark {
|
|
|
601
630
|
|
|
602
631
|
const texture = glHelper.rangeTextures.get(resolution);
|
|
603
632
|
if (texture) {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
633
|
+
ops.push(() =>
|
|
634
|
+
setUniforms(this.programInfo, {
|
|
635
|
+
[RANGE_TEXTURE_PREFIX + channel]: texture,
|
|
636
|
+
})
|
|
637
|
+
);
|
|
607
638
|
}
|
|
608
639
|
}
|
|
609
640
|
}
|
|
610
641
|
|
|
611
642
|
if (this.getSampleFacetMode() == SAMPLE_FACET_TEXTURE) {
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
643
|
+
ops.push(() => {
|
|
644
|
+
/** @type {WebGLTexture} */
|
|
645
|
+
let facetTexture;
|
|
646
|
+
for (const view of this.unitView.getAncestors()) {
|
|
647
|
+
facetTexture = view.getSampleFacetTexture();
|
|
648
|
+
if (facetTexture) {
|
|
649
|
+
break;
|
|
650
|
+
}
|
|
618
651
|
}
|
|
619
|
-
}
|
|
620
652
|
|
|
621
|
-
|
|
622
|
-
|
|
653
|
+
if (!facetTexture) {
|
|
654
|
+
throw new Error("No facet texture available. This is bug.");
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
setUniforms(this.programInfo, {
|
|
658
|
+
uSampleFacetTexture: facetTexture,
|
|
659
|
+
});
|
|
623
660
|
});
|
|
624
661
|
}
|
|
625
662
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
uSampleFacet: [0, 1, 0, 1],
|
|
639
|
-
uTransitionOffset: 0.0,
|
|
640
|
-
});
|
|
663
|
+
// TODO: Rendering of the mark should be completely skipped if it doesn't
|
|
664
|
+
// participate picking
|
|
665
|
+
const picking =
|
|
666
|
+
(options.picking ?? false) && this.isPickingParticipant();
|
|
667
|
+
|
|
668
|
+
// Note: the block is sent to GPU in setViewport(), which is repeated for each facet
|
|
669
|
+
ops.push(() =>
|
|
670
|
+
setBlockUniforms(this.viewUniformInfo, {
|
|
671
|
+
uViewOpacity: this.unitView.getEffectiveOpacity(),
|
|
672
|
+
uPickingEnabled: picking,
|
|
673
|
+
})
|
|
674
|
+
);
|
|
641
675
|
|
|
642
676
|
if (this.opaque || options.picking) {
|
|
643
|
-
gl.disable(gl.BLEND);
|
|
677
|
+
ops.push(() => gl.disable(gl.BLEND));
|
|
644
678
|
} else {
|
|
645
|
-
gl.enable(gl.BLEND);
|
|
679
|
+
ops.push(() => gl.enable(gl.BLEND));
|
|
646
680
|
}
|
|
681
|
+
|
|
682
|
+
return ops;
|
|
647
683
|
}
|
|
648
684
|
|
|
649
685
|
/**
|
|
@@ -705,58 +741,56 @@ export default class Mark {
|
|
|
705
741
|
/**
|
|
706
742
|
* @param {DrawFunction} draw A function that draws a range of vertices
|
|
707
743
|
* @param {import("./Mark").MarkRenderingOptions} options
|
|
708
|
-
* @param {function():Map<string, import("../gl/dataToVertices").RangeEntry>} rangeMapSource
|
|
709
744
|
*/
|
|
710
|
-
createRenderCallback(draw, options
|
|
745
|
+
createRenderCallback(draw, options) {
|
|
711
746
|
// eslint-disable-next-line consistent-this
|
|
712
747
|
const self = this;
|
|
713
748
|
|
|
714
749
|
/** @type {function(import("../gl/dataToVertices").RangeEntry):void} rangeEntry */
|
|
715
750
|
let drawWithRangeEntry;
|
|
716
751
|
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
752
|
+
const scale = this.unitView.getScaleResolution("x")?.getScale();
|
|
753
|
+
const continuous = scale && isContinuous(scale.type);
|
|
754
|
+
const domainStartOffset = ["index", "locus"].includes(scale?.type)
|
|
755
|
+
? -1
|
|
756
|
+
: 0;
|
|
757
|
+
|
|
758
|
+
/** @type {[number, number]} Recycle to ease garbage collector's work */
|
|
759
|
+
const arr = [0, 0];
|
|
760
|
+
|
|
761
|
+
drawWithRangeEntry = (rangeEntry) => {
|
|
762
|
+
if (continuous && rangeEntry.xIndex) {
|
|
763
|
+
const domain = scale.domain();
|
|
764
|
+
const vertexIndices = rangeEntry.xIndex(
|
|
765
|
+
domain[0] + domainStartOffset,
|
|
766
|
+
domain[1],
|
|
767
|
+
arr
|
|
768
|
+
);
|
|
769
|
+
const offset = vertexIndices[0];
|
|
770
|
+
const count = vertexIndices[1] - offset;
|
|
771
|
+
if (count > 0) {
|
|
772
|
+
draw(offset, count);
|
|
734
773
|
}
|
|
735
|
-
}
|
|
736
|
-
} else {
|
|
737
|
-
drawWithRangeEntry = (rangeEntry) =>
|
|
774
|
+
} else {
|
|
738
775
|
draw(rangeEntry.offset, rangeEntry.count);
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
if (this.properties.dynamicData) {
|
|
742
|
-
return function renderDynamic() {
|
|
743
|
-
const rangeEntry = rangeMapSource().get(options.facetId);
|
|
744
|
-
if (rangeEntry && rangeEntry.count) {
|
|
745
|
-
if (self.prepareSampleFacetRendering(options)) {
|
|
746
|
-
drawWithRangeEntry(rangeEntry);
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
};
|
|
750
|
-
} else {
|
|
751
|
-
const rangeEntry = rangeMapSource().get(options.facetId);
|
|
752
|
-
if (rangeEntry && rangeEntry.count) {
|
|
753
|
-
return function renderStatic() {
|
|
754
|
-
if (self.prepareSampleFacetRendering(options)) {
|
|
755
|
-
drawWithRangeEntry(rangeEntry);
|
|
756
|
-
}
|
|
757
|
-
};
|
|
758
776
|
}
|
|
759
|
-
}
|
|
777
|
+
};
|
|
778
|
+
|
|
779
|
+
const rangeEntry = this.rangeMap.get(options.facetId);
|
|
780
|
+
|
|
781
|
+
return options.sampleFacetRenderingOptions
|
|
782
|
+
? function renderSampleFacetRange() {
|
|
783
|
+
if (rangeEntry.count) {
|
|
784
|
+
if (self.prepareSampleFacetRendering(options)) {
|
|
785
|
+
drawWithRangeEntry(rangeEntry);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
: function renderRange() {
|
|
790
|
+
if (rangeEntry.count) {
|
|
791
|
+
drawWithRangeEntry(rangeEntry);
|
|
792
|
+
}
|
|
793
|
+
};
|
|
760
794
|
}
|
|
761
795
|
|
|
762
796
|
/**
|
|
@@ -838,7 +872,7 @@ export default class Mark {
|
|
|
838
872
|
uViewScale,
|
|
839
873
|
};
|
|
840
874
|
} else {
|
|
841
|
-
// Viewport comprises
|
|
875
|
+
// Viewport comprises the full canvas
|
|
842
876
|
gl.viewport(
|
|
843
877
|
0,
|
|
844
878
|
0,
|
|
@@ -861,15 +895,15 @@ export default class Mark {
|
|
|
861
895
|
};
|
|
862
896
|
}
|
|
863
897
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
setUniforms(this.programInfo, {
|
|
898
|
+
setBlockUniforms(this.viewUniformInfo, {
|
|
899
|
+
...uniforms,
|
|
868
900
|
uViewportSize: [coords.width, coords.height],
|
|
901
|
+
uDevicePixelRatio: this.glHelper.dpr,
|
|
869
902
|
});
|
|
870
903
|
|
|
871
|
-
|
|
904
|
+
setUniformBlock(this.gl, this.programInfo, this.viewUniformInfo);
|
|
872
905
|
|
|
906
|
+
// TODO: Optimize: don't set viewport and stuff if rect is outside clipRect or screen
|
|
873
907
|
return clippedCoords.height > 0 && clippedCoords.width > 0;
|
|
874
908
|
}
|
|
875
909
|
|
|
@@ -887,3 +921,39 @@ export default class Mark {
|
|
|
887
921
|
// override
|
|
888
922
|
}
|
|
889
923
|
}
|
|
924
|
+
|
|
925
|
+
/**
|
|
926
|
+
* @augments {InternMap<K, import("../gl/dataToVertices").RangeEntry>}
|
|
927
|
+
* @template K
|
|
928
|
+
*/
|
|
929
|
+
class RangeMap extends InternMap {
|
|
930
|
+
constructor() {
|
|
931
|
+
super([], JSON.stringify);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/**
|
|
935
|
+
* @param {K} key
|
|
936
|
+
*/
|
|
937
|
+
get(key) {
|
|
938
|
+
let value = super.get(key);
|
|
939
|
+
if (value === undefined) {
|
|
940
|
+
value = {
|
|
941
|
+
offset: 0,
|
|
942
|
+
count: 0,
|
|
943
|
+
xIndex: undefined,
|
|
944
|
+
};
|
|
945
|
+
super.set(key, value);
|
|
946
|
+
}
|
|
947
|
+
return value;
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
/**
|
|
951
|
+
*
|
|
952
|
+
* @param {Map<K, import("../gl/dataToVertices").RangeEntry>} anotherMap
|
|
953
|
+
*/
|
|
954
|
+
migrateEntries(anotherMap) {
|
|
955
|
+
for (const [key, value] of anotherMap.entries()) {
|
|
956
|
+
Object.assign(this.get(key), value);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
}
|
package/src/marks/pointMark.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { drawBufferInfo, setBuffersAndAttributes, setUniforms } from "twgl.js";
|
|
2
|
-
import {
|
|
3
|
-
import { zoomLinear } from "vega-util";
|
|
2
|
+
import { quantileSorted } from "d3-array";
|
|
4
3
|
import { PointVertexBuilder } from "../gl/dataToVertices";
|
|
5
4
|
import VERTEX_SHADER from "../gl/point.vertex.glsl";
|
|
6
5
|
import FRAGMENT_SHADER from "../gl/point.fragment.glsl";
|
|
@@ -156,7 +155,7 @@ export default class PointMark extends Mark {
|
|
|
156
155
|
builder.addBatches(collector.facetBatches);
|
|
157
156
|
|
|
158
157
|
const vertexData = builder.toArrays();
|
|
159
|
-
this.rangeMap
|
|
158
|
+
this.rangeMap.migrateEntries(vertexData.rangeMap);
|
|
160
159
|
this.updateBufferInfo(vertexData);
|
|
161
160
|
}
|
|
162
161
|
|
|
@@ -210,44 +209,25 @@ export default class PointMark extends Mark {
|
|
|
210
209
|
* @param {import("../view/rendering").GlobalRenderingOptions} options
|
|
211
210
|
*/
|
|
212
211
|
prepareRender(options) {
|
|
213
|
-
super.prepareRender(options);
|
|
212
|
+
const ops = super.prepareRender(options);
|
|
214
213
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
214
|
+
ops.push(() =>
|
|
215
|
+
setUniforms(this.programInfo, {
|
|
216
|
+
uMaxPointSize: this._getMaxPointSize(),
|
|
217
|
+
uScaleFactor: this._getGeometricScaleFactor(),
|
|
218
|
+
uSemanticThreshold: this.getSemanticThreshold(),
|
|
219
|
+
})
|
|
220
|
+
);
|
|
220
221
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
222
|
+
ops.push(() =>
|
|
223
|
+
setBuffersAndAttributes(
|
|
224
|
+
this.gl,
|
|
225
|
+
this.programInfo,
|
|
226
|
+
this.vertexArrayInfo
|
|
227
|
+
)
|
|
225
228
|
);
|
|
226
229
|
|
|
227
|
-
|
|
228
|
-
const xEncoder = this.encoders.x;
|
|
229
|
-
if (xEncoder && !xEncoder.constant) {
|
|
230
|
-
const bisect = bisector(xEncoder.accessor).left;
|
|
231
|
-
const visibleDomain = this.unitView
|
|
232
|
-
.getScaleResolution("x")
|
|
233
|
-
.getScale()
|
|
234
|
-
.domain();
|
|
235
|
-
|
|
236
|
-
// A hack to include points that are just beyond the borders. TODO: Compute based on maxPointSize
|
|
237
|
-
const paddedDomain = zoomLinear(visibleDomain, null, 1.01);
|
|
238
|
-
|
|
239
|
-
/** @param {any[]} facetId */
|
|
240
|
-
this._findIndices = (facetId) => {
|
|
241
|
-
const data = this.unitView
|
|
242
|
-
.getCollector()
|
|
243
|
-
.facetBatches.get(facetId);
|
|
244
|
-
|
|
245
|
-
return [
|
|
246
|
-
bisect(data, paddedDomain[0]),
|
|
247
|
-
bisect(data, paddedDomain[paddedDomain.length - 1]),
|
|
248
|
-
];
|
|
249
|
-
};
|
|
250
|
-
}
|
|
230
|
+
return ops;
|
|
251
231
|
}
|
|
252
232
|
|
|
253
233
|
/**
|
|
@@ -256,27 +236,16 @@ export default class PointMark extends Mark {
|
|
|
256
236
|
render(options) {
|
|
257
237
|
const gl = this.gl;
|
|
258
238
|
|
|
259
|
-
return this.createRenderCallback(
|
|
260
|
-
(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
gl,
|
|
271
|
-
this.vertexArrayInfo,
|
|
272
|
-
gl.POINTS,
|
|
273
|
-
length,
|
|
274
|
-
offset + lower
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
},
|
|
278
|
-
options,
|
|
279
|
-
() => this.rangeMap
|
|
280
|
-
);
|
|
239
|
+
return this.createRenderCallback((offset, count) => {
|
|
240
|
+
if (count) {
|
|
241
|
+
drawBufferInfo(
|
|
242
|
+
gl,
|
|
243
|
+
this.vertexArrayInfo,
|
|
244
|
+
gl.POINTS,
|
|
245
|
+
count,
|
|
246
|
+
offset
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}, options);
|
|
281
250
|
}
|
|
282
251
|
}
|
package/src/marks/rectMark.js
CHANGED
|
@@ -146,6 +146,25 @@ export default class RectMark extends Mark {
|
|
|
146
146
|
);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
finalizeGraphicsInitialization() {
|
|
150
|
+
super.finalizeGraphicsInitialization();
|
|
151
|
+
|
|
152
|
+
this.gl.useProgram(this.programInfo.program);
|
|
153
|
+
|
|
154
|
+
const props = this.properties;
|
|
155
|
+
|
|
156
|
+
setUniforms(this.programInfo, {
|
|
157
|
+
uMinSize: [props.minWidth, props.minHeight], // in pixels
|
|
158
|
+
uMinOpacity: props.minOpacity,
|
|
159
|
+
uCornerRadii: [
|
|
160
|
+
props.cornerRadiusTopRight ?? props.cornerRadius,
|
|
161
|
+
props.cornerRadiusBottomRight ?? props.cornerRadius,
|
|
162
|
+
props.cornerRadiusTopLeft ?? props.cornerRadius,
|
|
163
|
+
props.cornerRadiusBottomLeft ?? props.cornerRadius,
|
|
164
|
+
],
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
149
168
|
updateGraphicsData() {
|
|
150
169
|
const collector = this.unitView.getCollector();
|
|
151
170
|
const numItems = collector.getItemCount();
|
|
@@ -155,13 +174,12 @@ export default class RectMark extends Mark {
|
|
|
155
174
|
encoders: this.encoders,
|
|
156
175
|
attributes: this.getAttributes(),
|
|
157
176
|
numItems,
|
|
158
|
-
buildXIndex: this.properties.buildIndex,
|
|
159
177
|
});
|
|
160
178
|
|
|
161
179
|
builder.addBatches(collector.facetBatches);
|
|
162
180
|
|
|
163
181
|
const vertexData = builder.toArrays();
|
|
164
|
-
this.rangeMap
|
|
182
|
+
this.rangeMap.migrateEntries(vertexData.rangeMap);
|
|
165
183
|
this.updateBufferInfo(vertexData);
|
|
166
184
|
}
|
|
167
185
|
|
|
@@ -169,26 +187,17 @@ export default class RectMark extends Mark {
|
|
|
169
187
|
* @param {import("../view/rendering").GlobalRenderingOptions} options
|
|
170
188
|
*/
|
|
171
189
|
prepareRender(options) {
|
|
172
|
-
super.prepareRender(options);
|
|
190
|
+
const ops = super.prepareRender(options);
|
|
173
191
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
props.cornerRadiusTopRight ?? props.cornerRadius,
|
|
181
|
-
props.cornerRadiusBottomRight ?? props.cornerRadius,
|
|
182
|
-
props.cornerRadiusTopLeft ?? props.cornerRadius,
|
|
183
|
-
props.cornerRadiusBottomLeft ?? props.cornerRadius,
|
|
184
|
-
],
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
setBuffersAndAttributes(
|
|
188
|
-
this.gl,
|
|
189
|
-
this.programInfo,
|
|
190
|
-
this.vertexArrayInfo
|
|
192
|
+
ops.push(() =>
|
|
193
|
+
setBuffersAndAttributes(
|
|
194
|
+
this.gl,
|
|
195
|
+
this.programInfo,
|
|
196
|
+
this.vertexArrayInfo
|
|
197
|
+
)
|
|
191
198
|
);
|
|
199
|
+
|
|
200
|
+
return ops;
|
|
192
201
|
}
|
|
193
202
|
|
|
194
203
|
/**
|
|
@@ -197,19 +206,15 @@ export default class RectMark extends Mark {
|
|
|
197
206
|
render(options) {
|
|
198
207
|
const gl = this.gl;
|
|
199
208
|
|
|
200
|
-
return this.createRenderCallback(
|
|
201
|
-
(
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
},
|
|
210
|
-
options,
|
|
211
|
-
() => this.rangeMap
|
|
212
|
-
);
|
|
209
|
+
return this.createRenderCallback((offset, count) => {
|
|
210
|
+
drawBufferInfo(
|
|
211
|
+
gl,
|
|
212
|
+
this.vertexArrayInfo,
|
|
213
|
+
gl.TRIANGLE_STRIP,
|
|
214
|
+
count,
|
|
215
|
+
offset
|
|
216
|
+
);
|
|
217
|
+
}, options);
|
|
213
218
|
}
|
|
214
219
|
|
|
215
220
|
/**
|