@genome-spy/core 0.43.3 → 0.44.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/bundle/index.es.js +5525 -5259
- package/dist/bundle/index.js +153 -104
- package/dist/schema.json +412 -43
- package/dist/src/data/sources/lazy/axisTickSource.d.ts +1 -1
- package/dist/src/data/sources/lazy/axisTickSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/axisTickSource.js +2 -2
- package/dist/src/data/sources/lazy/bigWigSource.d.ts +6 -0
- package/dist/src/data/sources/lazy/bigWigSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/bigWigSource.js +3 -5
- package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts +1 -1
- package/dist/src/data/sources/lazy/singleAxisLazySource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisLazySource.js +1 -1
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts +7 -12
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.d.ts.map +1 -1
- package/dist/src/data/sources/lazy/singleAxisWindowedSource.js +33 -29
- package/dist/src/data/transforms/filterScoredLabels.js +1 -1
- package/dist/src/encoder/encoder.d.ts.map +1 -1
- package/dist/src/encoder/encoder.js +16 -6
- package/dist/src/genomeSpy.d.ts +1 -0
- package/dist/src/genomeSpy.d.ts.map +1 -1
- package/dist/src/genomeSpy.js +108 -6
- package/dist/src/gl/glslScaleGenerator.d.ts +23 -3
- package/dist/src/gl/glslScaleGenerator.d.ts.map +1 -1
- package/dist/src/gl/glslScaleGenerator.js +137 -42
- package/dist/src/gl/webGLHelper.d.ts.map +1 -1
- package/dist/src/gl/webGLHelper.js +5 -7
- package/dist/src/marks/link.common.glsl.js +2 -0
- package/dist/src/marks/link.d.ts.map +1 -1
- package/dist/src/marks/link.js +19 -9
- package/dist/src/marks/link.vertex.glsl.js +1 -1
- package/dist/src/marks/mark.d.ts +19 -17
- package/dist/src/marks/mark.d.ts.map +1 -1
- package/dist/src/marks/mark.js +181 -120
- package/dist/src/marks/point.common.glsl.js +1 -1
- package/dist/src/marks/rect.common.glsl.js +2 -0
- package/dist/src/marks/rect.d.ts.map +1 -1
- package/dist/src/marks/rect.js +12 -12
- package/dist/src/marks/rect.vertex.glsl.js +1 -1
- package/dist/src/marks/rule.common.glsl.js +1 -1
- package/dist/src/marks/rule.js +2 -2
- package/dist/src/marks/text.common.glsl.js +1 -1
- package/dist/src/marks/text.js +2 -2
- package/dist/src/paramBroker.d.ts +19 -3
- package/dist/src/paramBroker.d.ts.map +1 -1
- package/dist/src/paramBroker.js +18 -2
- package/dist/src/spec/channel.d.ts +4 -3
- package/dist/src/spec/mark.d.ts +17 -25
- package/dist/src/spec/parameter.d.ts +123 -0
- package/dist/src/spec/root.d.ts +9 -0
- package/dist/src/spec/scale.d.ts +2 -1
- package/dist/src/spec/view.d.ts +1 -1
- package/dist/src/types/scaleResolutionApi.d.ts +7 -3
- package/dist/src/utils/expression.d.ts +2 -2
- package/dist/src/utils/expression.d.ts.map +1 -1
- package/dist/src/utils/expression.js +3 -3
- package/dist/src/view/axisView.js +3 -3
- package/dist/src/view/scaleResolution.d.ts +8 -18
- package/dist/src/view/scaleResolution.d.ts.map +1 -1
- package/dist/src/view/scaleResolution.js +220 -126
- package/dist/src/view/scaleResolution.test.js +7 -7
- package/dist/src/view/unitView.d.ts.map +1 -1
- package/dist/src/view/unitView.js +10 -3
- package/dist/src/view/view.js +2 -2
- package/package.json +2 -2
package/dist/src/marks/mark.js
CHANGED
|
@@ -18,15 +18,16 @@ import createEncoders, {
|
|
|
18
18
|
isValueDef,
|
|
19
19
|
} from "../encoder/encoder.js";
|
|
20
20
|
import {
|
|
21
|
-
|
|
22
|
-
generateValueGlsl,
|
|
21
|
+
generateConstantValueGlsl,
|
|
23
22
|
generateScaleGlsl,
|
|
24
23
|
RANGE_TEXTURE_PREFIX,
|
|
25
|
-
ATTRIBUTE_PREFIX,
|
|
26
24
|
isHighPrecisionScale,
|
|
27
25
|
toHighPrecisionDomainUniform,
|
|
28
|
-
splitHighPrecision,
|
|
29
26
|
dedupeEncodingFields,
|
|
27
|
+
generateDynamicValueGlslAndUniform,
|
|
28
|
+
isLargeGenome,
|
|
29
|
+
splitLargeHighPrecision,
|
|
30
|
+
getRangeForGlsl,
|
|
30
31
|
} from "../gl/glslScaleGenerator.js";
|
|
31
32
|
import GLSL_COMMON from "../gl/includes/common.glsl.js";
|
|
32
33
|
import GLSL_SCALES from "../gl/includes/scales.glsl.js";
|
|
@@ -38,7 +39,6 @@ import { createProgram } from "../gl/webGLHelper.js";
|
|
|
38
39
|
import coalesceProperties from "../utils/propertyCoalescer.js";
|
|
39
40
|
import { isScalar } from "../utils/variableTools.js";
|
|
40
41
|
import { InternMap } from "internmap";
|
|
41
|
-
import scaleNull from "../utils/scaleNull.js";
|
|
42
42
|
import ViewError from "../view/viewError.js";
|
|
43
43
|
import { isString } from "vega-util";
|
|
44
44
|
|
|
@@ -60,13 +60,20 @@ export const SAMPLE_FACET_TEXTURE = "SAMPLE_FACET_TEXTURE";
|
|
|
60
60
|
*/
|
|
61
61
|
export default class Mark {
|
|
62
62
|
/**
|
|
63
|
-
* @typedef {import("../spec/mark.js").
|
|
63
|
+
* @typedef {import("../spec/mark.js").MarkProps} MarkProps
|
|
64
64
|
* @typedef {import("../spec/channel.js").Channel} Channel
|
|
65
65
|
* @typedef {import("../spec/channel.js").Encoding} Encoding
|
|
66
66
|
* @typedef {import("../spec/channel.js").ValueDef} ValueDef
|
|
67
|
-
* @typedef {import("../spec/
|
|
67
|
+
* @typedef {import("../spec/parameter.js").ExprRef} ExprRef
|
|
68
68
|
*/
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Only needed during initialization;
|
|
72
|
+
*
|
|
73
|
+
* @type {(() => void)[]}
|
|
74
|
+
*/
|
|
75
|
+
#callAfterShaderCompilation = [];
|
|
76
|
+
|
|
70
77
|
/**
|
|
71
78
|
* @param {import("../view/unitView.js").default} unitView
|
|
72
79
|
*/
|
|
@@ -111,7 +118,7 @@ export default class Mark {
|
|
|
111
118
|
this.rangeMap = new RangeMap();
|
|
112
119
|
|
|
113
120
|
// TODO: Implement https://vega.github.io/vega-lite/docs/config.html
|
|
114
|
-
/** @type {
|
|
121
|
+
/** @type {MarkProps} */
|
|
115
122
|
this.defaultProperties = {
|
|
116
123
|
get clip() {
|
|
117
124
|
// TODO: Cache once the scales have been resolved
|
|
@@ -141,13 +148,13 @@ export default class Mark {
|
|
|
141
148
|
*
|
|
142
149
|
* TODO: Proper and comprehensive typings for mark properties
|
|
143
150
|
*
|
|
144
|
-
* @type {Partial<
|
|
151
|
+
* @type {Partial<MarkProps>}
|
|
145
152
|
* @readonly
|
|
146
153
|
*/
|
|
147
154
|
this.properties = coalesceProperties(
|
|
148
155
|
typeof this.unitView.spec.mark == "object"
|
|
149
|
-
? () => /** @type {
|
|
150
|
-
: () => /** @type {
|
|
156
|
+
? () => /** @type {MarkProps} */ (this.unitView.spec.mark)
|
|
157
|
+
: () => /** @type {MarkProps} */ ({}),
|
|
151
158
|
() => this.defaultProperties
|
|
152
159
|
);
|
|
153
160
|
}
|
|
@@ -227,20 +234,22 @@ export default class Mark {
|
|
|
227
234
|
/** @type {(property: string) => ValueDef} */
|
|
228
235
|
const propToValueDef = (property) => {
|
|
229
236
|
const value =
|
|
230
|
-
this.properties[/** @type {keyof
|
|
231
|
-
return isScalar(value)
|
|
237
|
+
this.properties[/** @type {keyof MarkProps} */ (property)];
|
|
238
|
+
return isScalar(value) || isExprRef(value)
|
|
239
|
+
? { value }
|
|
240
|
+
: undefined;
|
|
232
241
|
};
|
|
233
242
|
|
|
234
243
|
const propertyValues = Object.fromEntries(
|
|
235
244
|
this.getSupportedChannels()
|
|
236
245
|
.map(
|
|
237
246
|
(channel) =>
|
|
238
|
-
/** @type {[Channel, ValueDef]} */ ([
|
|
247
|
+
/** @type {[Channel, ValueDef] } */ ([
|
|
239
248
|
channel,
|
|
240
249
|
propToValueDef(channel),
|
|
241
250
|
])
|
|
242
251
|
)
|
|
243
|
-
.filter((entry) => entry[1]
|
|
252
|
+
.filter((entry) => isValueDef(entry[1]))
|
|
244
253
|
);
|
|
245
254
|
|
|
246
255
|
const encoding = this.fixEncoding({
|
|
@@ -326,16 +335,13 @@ export default class Mark {
|
|
|
326
335
|
* @param {string[]} [extraHeaders]
|
|
327
336
|
* @protected
|
|
328
337
|
*/
|
|
338
|
+
// eslint-disable-next-line complexity
|
|
329
339
|
createAndLinkShaders(vertexShader, fragmentShader, extraHeaders = []) {
|
|
330
340
|
const attributes = this.getAttributes();
|
|
331
341
|
|
|
332
342
|
// For debugging
|
|
333
343
|
const debugHeader = "// view: " + this.unitView.getPathString();
|
|
334
344
|
|
|
335
|
-
// TODO: This is a temporary variable, don't store it in the mark object
|
|
336
|
-
/** @type {string[]} */
|
|
337
|
-
this.domainUniforms = [];
|
|
338
|
-
|
|
339
345
|
/** @type {string[]} */
|
|
340
346
|
let scaleCode = [];
|
|
341
347
|
|
|
@@ -353,6 +359,9 @@ export default class Mark {
|
|
|
353
359
|
extraHeaders.push(`#define ${sampleFacetMode}`);
|
|
354
360
|
}
|
|
355
361
|
|
|
362
|
+
/** @type {string[]} */
|
|
363
|
+
const dynamicMarkUniforms = [];
|
|
364
|
+
|
|
356
365
|
for (const attribute of attributes) {
|
|
357
366
|
/** @type {Channel} */
|
|
358
367
|
let channel;
|
|
@@ -363,24 +372,40 @@ export default class Mark {
|
|
|
363
372
|
}
|
|
364
373
|
|
|
365
374
|
const channelDef = this.encoding[channel];
|
|
366
|
-
|
|
367
375
|
if (!channelDef) {
|
|
368
376
|
continue;
|
|
369
377
|
}
|
|
370
378
|
|
|
371
379
|
if (isValueDef(channelDef)) {
|
|
372
|
-
|
|
380
|
+
if (isExprRef(channelDef.value)) {
|
|
381
|
+
// An expression that evaluates to a value
|
|
382
|
+
const { uniformName, uniformGlsl, scaleGlsl, adjuster } =
|
|
383
|
+
generateDynamicValueGlslAndUniform(channel);
|
|
384
|
+
scaleCode.push(scaleGlsl);
|
|
385
|
+
dynamicMarkUniforms.push(uniformGlsl);
|
|
386
|
+
|
|
387
|
+
this.#callAfterShaderCompilation.push(() => {
|
|
388
|
+
this.registerMarkUniformValue(
|
|
389
|
+
uniformName,
|
|
390
|
+
channelDef.value,
|
|
391
|
+
adjuster
|
|
392
|
+
);
|
|
393
|
+
});
|
|
394
|
+
} else {
|
|
395
|
+
// A constant value
|
|
396
|
+
scaleCode.push(
|
|
397
|
+
generateConstantValueGlsl(channel, channelDef.value)
|
|
398
|
+
);
|
|
399
|
+
}
|
|
373
400
|
} else {
|
|
374
401
|
const resolutionChannel =
|
|
375
402
|
(isChannelDefWithScale(channelDef) &&
|
|
376
403
|
channelDef.resolutionChannel) ||
|
|
377
404
|
channel;
|
|
378
405
|
|
|
379
|
-
const
|
|
380
|
-
? this.unitView
|
|
381
|
-
|
|
382
|
-
.getScale()
|
|
383
|
-
: scaleNull();
|
|
406
|
+
const scaleResolution = isChannelWithScale(resolutionChannel)
|
|
407
|
+
? this.unitView.getScaleResolution(resolutionChannel)
|
|
408
|
+
: null;
|
|
384
409
|
|
|
385
410
|
// Channels that share the same quantitative field
|
|
386
411
|
// TODO: It should be ok to share a categorical field if the channels
|
|
@@ -391,7 +416,7 @@ export default class Mark {
|
|
|
391
416
|
|
|
392
417
|
const generated = generateScaleGlsl(
|
|
393
418
|
channel,
|
|
394
|
-
|
|
419
|
+
scaleResolution,
|
|
395
420
|
channelDef,
|
|
396
421
|
sharedChannels?.includes(channel)
|
|
397
422
|
? sharedChannels
|
|
@@ -399,22 +424,103 @@ export default class Mark {
|
|
|
399
424
|
);
|
|
400
425
|
|
|
401
426
|
scaleCode.push(generated.glsl);
|
|
402
|
-
|
|
403
|
-
|
|
427
|
+
dynamicMarkUniforms.push(generated.domainUniform);
|
|
428
|
+
dynamicMarkUniforms.push(generated.rangeUniform);
|
|
429
|
+
attributeCode.add(generated.attributeGlsl);
|
|
430
|
+
|
|
431
|
+
if (generated.rangeUniform) {
|
|
432
|
+
this.#callAfterShaderCompilation.push(() => {
|
|
433
|
+
const rangeSetter = this.createMarkUniformSetter(
|
|
434
|
+
generated.rangeName
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
const set = () =>
|
|
438
|
+
rangeSetter(
|
|
439
|
+
getRangeForGlsl(scaleResolution.scale, channel)
|
|
440
|
+
);
|
|
441
|
+
scaleResolution.addEventListener("range", set);
|
|
442
|
+
|
|
443
|
+
// Initial value
|
|
444
|
+
set();
|
|
445
|
+
});
|
|
404
446
|
}
|
|
405
|
-
|
|
406
|
-
|
|
447
|
+
|
|
448
|
+
if (generated.markUniformGlsl) {
|
|
449
|
+
if (!isDatumDef(channelDef)) {
|
|
450
|
+
throw new Error("Bug!");
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
const encoder = this.encoders[channel];
|
|
454
|
+
|
|
455
|
+
const indexer = encoder.indexer;
|
|
456
|
+
const hp = isHighPrecisionScale(encoder.scale.type);
|
|
457
|
+
const largeHp = hp && isLargeGenome(encoder.scale.domain());
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Discrete variables both numeric and strings must be "indexed",
|
|
461
|
+
* 64 bit floats must be converted to vec2.
|
|
462
|
+
* 32 bit continuous variables go to GPU as is.
|
|
463
|
+
*
|
|
464
|
+
* @type {function(import("../spec/channel.js").Scalar):(number | number[])}
|
|
465
|
+
*/
|
|
466
|
+
const adjuster = indexer
|
|
467
|
+
? indexer
|
|
468
|
+
: largeHp
|
|
469
|
+
? splitLargeHighPrecision
|
|
470
|
+
: (d) => +d;
|
|
471
|
+
|
|
472
|
+
dynamicMarkUniforms.push(generated.markUniformGlsl);
|
|
473
|
+
|
|
474
|
+
this.#callAfterShaderCompilation.push(() => {
|
|
475
|
+
this.registerMarkUniformValue(
|
|
476
|
+
generated.attributeName,
|
|
477
|
+
channelDef.datum,
|
|
478
|
+
adjuster
|
|
479
|
+
);
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
if (generated.domainUniform) {
|
|
484
|
+
this.#callAfterShaderCompilation.push(() => {
|
|
485
|
+
const domainSetter = this.createMarkUniformSetter(
|
|
486
|
+
generated.domainUniformName
|
|
487
|
+
);
|
|
488
|
+
const scale = scaleResolution.scale;
|
|
489
|
+
const set = () => {
|
|
490
|
+
const domain = isDiscrete(scale.type)
|
|
491
|
+
? [0, scale.domain().length]
|
|
492
|
+
: scale.domain();
|
|
493
|
+
|
|
494
|
+
domainSetter(
|
|
495
|
+
isHighPrecisionScale(scale.type)
|
|
496
|
+
? toHighPrecisionDomainUniform(domain)
|
|
497
|
+
: domain
|
|
498
|
+
);
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
scaleResolution.addEventListener("domain", set);
|
|
502
|
+
|
|
503
|
+
// Initial value
|
|
504
|
+
set();
|
|
505
|
+
});
|
|
407
506
|
}
|
|
408
507
|
}
|
|
409
508
|
}
|
|
410
509
|
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
510
|
+
const vertexPrecision = "precision highp float;\nprecision highp int;";
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* @param {string} shaderCode
|
|
514
|
+
*/
|
|
515
|
+
const addDynamicMarkUniforms = (shaderCode) =>
|
|
516
|
+
shaderCode.replace(
|
|
517
|
+
"#pragma markUniforms",
|
|
518
|
+
dynamicMarkUniforms.join("\n")
|
|
519
|
+
);
|
|
416
520
|
|
|
417
|
-
|
|
521
|
+
extraHeaders = extraHeaders.map(addDynamicMarkUniforms);
|
|
522
|
+
vertexShader = addDynamicMarkUniforms(vertexShader);
|
|
523
|
+
fragmentShader = addDynamicMarkUniforms(fragmentShader);
|
|
418
524
|
|
|
419
525
|
const vertexParts = [
|
|
420
526
|
vertexPrecision,
|
|
@@ -422,7 +528,6 @@ export default class Mark {
|
|
|
422
528
|
...extraHeaders,
|
|
423
529
|
GLSL_COMMON,
|
|
424
530
|
GLSL_SCALES,
|
|
425
|
-
domainUniformBlock,
|
|
426
531
|
[...attributeCode].join("\n"),
|
|
427
532
|
...scaleCode,
|
|
428
533
|
GLSL_SAMPLE_FACET,
|
|
@@ -431,6 +536,7 @@ export default class Mark {
|
|
|
431
536
|
];
|
|
432
537
|
|
|
433
538
|
const fragmentParts = [
|
|
539
|
+
vertexPrecision,
|
|
434
540
|
debugHeader,
|
|
435
541
|
...extraHeaders,
|
|
436
542
|
GLSL_COMMON,
|
|
@@ -453,6 +559,9 @@ export default class Mark {
|
|
|
453
559
|
/**
|
|
454
560
|
* Check WebGL shader/program compilation/linking status and finalize
|
|
455
561
|
* initialization.
|
|
562
|
+
*
|
|
563
|
+
* This is done as a separate step after all shader compilations have been
|
|
564
|
+
* initiated. The idea is to allow for parallel background compilation.
|
|
456
565
|
*/
|
|
457
566
|
finalizeGraphicsInitialization() {
|
|
458
567
|
const error = this.programStatus.getProgramErrors();
|
|
@@ -474,14 +583,6 @@ export default class Mark {
|
|
|
474
583
|
);
|
|
475
584
|
delete this.programStatus;
|
|
476
585
|
|
|
477
|
-
if (this.domainUniforms.length) {
|
|
478
|
-
this.domainUniformInfo = createUniformBlockInfo(
|
|
479
|
-
this.gl,
|
|
480
|
-
this.programInfo,
|
|
481
|
-
"Domains"
|
|
482
|
-
);
|
|
483
|
-
}
|
|
484
|
-
|
|
485
586
|
this.viewUniformInfo = createUniformBlockInfo(
|
|
486
587
|
this.gl,
|
|
487
588
|
this.programInfo,
|
|
@@ -496,14 +597,39 @@ export default class Mark {
|
|
|
496
597
|
|
|
497
598
|
this.gl.useProgram(this.programInfo.program);
|
|
498
599
|
|
|
499
|
-
this._setDatums();
|
|
500
|
-
|
|
501
600
|
setUniforms(this.programInfo, {
|
|
502
601
|
// left pos, left height, right pos, right height
|
|
503
602
|
uSampleFacet: [0, 1, 0, 1],
|
|
504
603
|
uTransitionOffset: 0.0,
|
|
505
604
|
uZero: 0.0,
|
|
506
605
|
});
|
|
606
|
+
|
|
607
|
+
for (const fn of this.#callAfterShaderCompilation) {
|
|
608
|
+
fn();
|
|
609
|
+
}
|
|
610
|
+
this.#callAfterShaderCompilation = undefined;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Sets a uniform in the Mark block. Requests a render from the animator.
|
|
615
|
+
*
|
|
616
|
+
* @protected
|
|
617
|
+
* @param {string} uniformName
|
|
618
|
+
* @returns {function(any):void}
|
|
619
|
+
*/
|
|
620
|
+
createMarkUniformSetter(uniformName) {
|
|
621
|
+
const uniformSetter = this.markUniformInfo.setters[uniformName];
|
|
622
|
+
if (!uniformSetter) {
|
|
623
|
+
throw new Error(
|
|
624
|
+
`Uniform "${uniformName}" not found int the Mark block!`
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
return (value) => {
|
|
629
|
+
uniformSetter(value);
|
|
630
|
+
this.markUniformsAltered = true;
|
|
631
|
+
this.unitView.context.animator.requestRender();
|
|
632
|
+
};
|
|
507
633
|
}
|
|
508
634
|
|
|
509
635
|
/**
|
|
@@ -517,46 +643,22 @@ export default class Mark {
|
|
|
517
643
|
* @param {T} propValue
|
|
518
644
|
* @param {(x: Exclude<T, ExprRef>) => any} adjuster
|
|
519
645
|
*/
|
|
520
|
-
|
|
521
|
-
const
|
|
646
|
+
registerMarkUniformValue(uniformName, propValue, adjuster = (x) => x) {
|
|
647
|
+
const setter = this.createMarkUniformSetter(uniformName);
|
|
522
648
|
|
|
523
649
|
if (isExprRef(propValue)) {
|
|
524
650
|
const fn = this.unitView.context.paramBroker.createExpression(
|
|
525
651
|
propValue.expr
|
|
526
652
|
);
|
|
527
653
|
|
|
528
|
-
const set = () =>
|
|
529
|
-
uniformSetter(adjuster(fn(null)));
|
|
530
|
-
this.markUniformsAltered = true;
|
|
531
|
-
};
|
|
654
|
+
const set = () => setter(adjuster(fn(null)));
|
|
532
655
|
|
|
533
656
|
// Register a listener ...
|
|
534
657
|
fn.addListener(set);
|
|
535
658
|
// ... and set the initial value
|
|
536
659
|
set();
|
|
537
660
|
} else {
|
|
538
|
-
|
|
539
|
-
adjuster(/** @type {Exclude<T, ExprRef>} */ (propValue))
|
|
540
|
-
);
|
|
541
|
-
this.markUniformsAltered = true;
|
|
542
|
-
}
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
_setDatums() {
|
|
546
|
-
for (const [channel, channelDef] of Object.entries(this.encoding)) {
|
|
547
|
-
if (isDatumDef(channelDef)) {
|
|
548
|
-
const encoder = this.encoders[channel];
|
|
549
|
-
|
|
550
|
-
const datum = encoder.indexer
|
|
551
|
-
? encoder.indexer(channelDef.datum)
|
|
552
|
-
: isHighPrecisionScale(encoder.scale.type)
|
|
553
|
-
? splitHighPrecision(+channelDef.datum)
|
|
554
|
-
: +channelDef.datum;
|
|
555
|
-
|
|
556
|
-
setUniforms(this.programInfo, {
|
|
557
|
-
[ATTRIBUTE_PREFIX + channel]: datum,
|
|
558
|
-
});
|
|
559
|
-
}
|
|
661
|
+
setter(adjuster(/** @type {Exclude<T, ExprRef>} */ (propValue)));
|
|
560
662
|
}
|
|
561
663
|
}
|
|
562
664
|
|
|
@@ -707,47 +809,6 @@ export default class Mark {
|
|
|
707
809
|
gl.useProgram(this.programInfo.program);
|
|
708
810
|
});
|
|
709
811
|
|
|
710
|
-
if (this.domainUniformInfo) {
|
|
711
|
-
// TODO: Only update the domains that have changed
|
|
712
|
-
|
|
713
|
-
for (const [uniform, setter] of Object.entries(
|
|
714
|
-
this.domainUniformInfo.setters
|
|
715
|
-
)) {
|
|
716
|
-
// TODO: isChannel()
|
|
717
|
-
const channel = /** @type {Channel} */ (
|
|
718
|
-
uniform.substring(DOMAIN_PREFIX.length)
|
|
719
|
-
);
|
|
720
|
-
|
|
721
|
-
const channelDef = this.encoding[channel];
|
|
722
|
-
const resolutionChannel =
|
|
723
|
-
(isChannelDefWithScale(channelDef) &&
|
|
724
|
-
channelDef.resolutionChannel) ||
|
|
725
|
-
channel;
|
|
726
|
-
|
|
727
|
-
if (isChannelWithScale(resolutionChannel)) {
|
|
728
|
-
const scale = this.unitView
|
|
729
|
-
.getScaleResolution(resolutionChannel)
|
|
730
|
-
.getScale();
|
|
731
|
-
|
|
732
|
-
ops.push(() => {
|
|
733
|
-
const domain = isDiscrete(scale.type)
|
|
734
|
-
? [0, scale.domain().length]
|
|
735
|
-
: scale.domain();
|
|
736
|
-
|
|
737
|
-
setter(
|
|
738
|
-
isHighPrecisionScale(scale.type)
|
|
739
|
-
? toHighPrecisionDomainUniform(domain)
|
|
740
|
-
: domain
|
|
741
|
-
);
|
|
742
|
-
});
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
ops.push(() =>
|
|
747
|
-
setUniformBlock(gl, this.programInfo, this.domainUniformInfo)
|
|
748
|
-
);
|
|
749
|
-
}
|
|
750
|
-
|
|
751
812
|
for (const [channel, channelDef] of Object.entries(this.encoding)) {
|
|
752
813
|
if (isChannelDefWithScale(channelDef)) {
|
|
753
814
|
const resolutionChannel =
|
|
@@ -888,7 +949,7 @@ export default class Mark {
|
|
|
888
949
|
/** @type {function(import("../gl/dataToVertices.js").RangeEntry):void} rangeEntry */
|
|
889
950
|
let drawWithRangeEntry;
|
|
890
951
|
|
|
891
|
-
const scale = this.unitView.getScaleResolution("x")?.
|
|
952
|
+
const scale = this.unitView.getScaleResolution("x")?.scale;
|
|
892
953
|
const continuous = scale && isContinuous(scale.type);
|
|
893
954
|
const domainStartOffset = ["index", "locus"].includes(scale?.type)
|
|
894
955
|
? -1
|
|
@@ -1119,8 +1180,8 @@ class RangeMap extends InternMap {
|
|
|
1119
1180
|
// TODO: Find a better place for this function
|
|
1120
1181
|
/**
|
|
1121
1182
|
* @param {any} x
|
|
1122
|
-
* @returns {x is import("../spec/
|
|
1183
|
+
* @returns {x is import("../spec/parameter.js").ExprRef}
|
|
1123
1184
|
*/
|
|
1124
1185
|
export function isExprRef(x) {
|
|
1125
|
-
return typeof x
|
|
1186
|
+
return typeof x == "object" && x != null && "expr" in x && isString(x.expr);
|
|
1126
1187
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const shader = "uniform Mark{/***The stroke should only grow inwards,e.g,the diameter/outline is not affected by the stroke width.*Thus,a point that has a zero size has no visible stroke. This allows strokes to be used with*geometric zoom,etc.*/uniform bool uInwardStroke;uniform lowp float uMaxRelativePointDiameter;uniform mediump float uScaleFactor;uniform mediump float uMaxPointSize;uniform mediump float uZoomLevel;uniform highp float uSemanticThreshold;uniform mediump float uGradientStrength
|
|
1
|
+
const shader = "layout(std140)uniform Mark{/***The stroke should only grow inwards,e.g,the diameter/outline is not affected by the stroke width.*Thus,a point that has a zero size has no visible stroke. This allows strokes to be used with*geometric zoom,etc.*/uniform bool uInwardStroke;uniform lowp float uMaxRelativePointDiameter;uniform mediump float uScaleFactor;uniform mediump float uMaxPointSize;uniform mediump float uZoomLevel;uniform highp float uSemanticThreshold;uniform mediump float uGradientStrength;\n#pragma markUniforms\n};";
|
|
2
2
|
export default shader;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const shader = "layout(std140)uniform Mark{uniform float uMinWidth;uniform float uMinHeight;uniform float uMinOpacity;uniform float uCornerRadiusTopRight;uniform float uCornerRadiusBottomRight;uniform float uCornerRadiusTopLeft;uniform float uCornerRadiusBottomLeft;\n#pragma markUniforms\n};";
|
|
2
|
+
export default shader;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/marks/rect.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"rect.d.ts","sourceRoot":"","sources":["../../../src/marks/rect.js"],"names":[],"mappings":"AAaA;IAyNI;;;;;;;;;;OAUG;IACH,8BALW,GAAG,KACH,OAAO,oBAAoB,EAAE,MAAM,GACjC,GAAG,CAyBf;;CACJ;iBAlQgB,WAAW"}
|
package/dist/src/marks/rect.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { drawBufferInfo, setBuffersAndAttributes } from "twgl.js";
|
|
2
2
|
import VERTEX_SHADER from "./rect.vertex.glsl.js";
|
|
3
3
|
import FRAGMENT_SHADER from "./rect.fragment.glsl.js";
|
|
4
|
+
import COMMON_SHADER from "./rect.common.glsl.js";
|
|
4
5
|
import { RectVertexBuilder } from "../gl/dataToVertices.js";
|
|
5
6
|
|
|
6
7
|
import Mark from "./mark.js";
|
|
@@ -140,11 +141,10 @@ export default class RectMark extends Mark {
|
|
|
140
141
|
defines.push("STROKED");
|
|
141
142
|
}
|
|
142
143
|
|
|
143
|
-
this.createAndLinkShaders(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
);
|
|
144
|
+
this.createAndLinkShaders(VERTEX_SHADER, FRAGMENT_SHADER, [
|
|
145
|
+
COMMON_SHADER,
|
|
146
|
+
...defines.map((d) => "#define " + d),
|
|
147
|
+
]);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
finalizeGraphicsInitialization() {
|
|
@@ -154,22 +154,22 @@ export default class RectMark extends Mark {
|
|
|
154
154
|
|
|
155
155
|
const props = this.properties;
|
|
156
156
|
|
|
157
|
-
this.
|
|
158
|
-
this.
|
|
159
|
-
this.
|
|
160
|
-
this.
|
|
157
|
+
this.registerMarkUniformValue("uMinWidth", props.minWidth);
|
|
158
|
+
this.registerMarkUniformValue("uMinHeight", props.minHeight);
|
|
159
|
+
this.registerMarkUniformValue("uMinOpacity", props.minOpacity);
|
|
160
|
+
this.registerMarkUniformValue(
|
|
161
161
|
"uCornerRadiusTopRight",
|
|
162
162
|
props.cornerRadiusTopRight ?? props.cornerRadius ?? 0
|
|
163
163
|
);
|
|
164
|
-
this.
|
|
164
|
+
this.registerMarkUniformValue(
|
|
165
165
|
"uCornerRadiusBottomRight",
|
|
166
166
|
props.cornerRadiusBottomRight ?? props.cornerRadius ?? 0
|
|
167
167
|
);
|
|
168
|
-
this.
|
|
168
|
+
this.registerMarkUniformValue(
|
|
169
169
|
"uCornerRadiusTopLeft",
|
|
170
170
|
props.cornerRadiusTopLeft ?? props.cornerRadius ?? 0
|
|
171
171
|
);
|
|
172
|
-
this.
|
|
172
|
+
this.registerMarkUniformValue(
|
|
173
173
|
"uCornerRadiusBottomLeft",
|
|
174
174
|
props.cornerRadiusBottomLeft ?? props.cornerRadius ?? 0
|
|
175
175
|
);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const shader = "
|
|
1
|
+
const shader = "out lowp vec4 vFillColor;out lowp vec4 vStrokeColor;out float vHalfStrokeWidth;out vec4 vCornerRadii;\n#if defined(ROUNDED_CORNERS) || defined(STROKED)\nout vec2 vPosInPixels;\n#endif\nout vec2 vHalfSizeInPixels;/***Clamps the minimumSize and returns an opacity that reflects the amount of clamping.*/float clampMinSize(inout float pos,float frac,float size,float minSize){if(minSize>0.0&&abs(size)<minSize){pos+=(frac-0.5)*(minSize*sign(size)-size);return abs(size)/minSize;}return 1.0;}void sort(inout float a,inout float b){if(a>b){float tmp=b;b=a;a=tmp;}}/***The vertex position wrt the rectangle specified by(x,x2,y,y2).*[0,0]=[x,y],[1,1]=[x2,y2].*The x or y component may contain fractional values if the rectangle*have been tessellated.*/vec2 getVertexPos(){int index=gl_VertexID % 6;return vec2(index==0||index==1||index==3 ? 0.0 : 1.0,index==0||index==1||index==2 ? 0.0 : 1.0);}void main(void){vec2 frac=getVertexPos();vec2 normalizedMinSize=vec2(uMinWidth,uMinHeight)/uViewportSize;vec4 cornerRadii=vec4(uCornerRadiusTopRight,uCornerRadiusBottomRight,uCornerRadiusBottomLeft,uCornerRadiusTopLeft);float x=getScaled_x();float x2=getScaled_x2();float y=getScaled_y();float y2=getScaled_y2();sort(x,x2);sort(y,y2);float clampMargin=1.0;vec2 pos1=vec2(clamp(x,0.0-clampMargin,1.0+clampMargin),y);vec2 pos2=vec2(clamp(x2,0.0-clampMargin,1.0+clampMargin),y2);vec2 size=pos2-pos1;if(size.x<=0.0||size.y<=0.0){gl_Position=vec4(0.0,0.0,0.0,1.0);return;}vec2 pos=pos1+frac*size;size.y*=getSampleFacetHeight(pos);float opaFactor=uViewOpacity*max(uMinOpacity,clampMinSize(pos.x,frac.x,size.x,normalizedMinSize.x)*clampMinSize(pos.y,frac.y,size.y,normalizedMinSize.y));pos=applySampleFacet(pos);\n#if defined(ROUNDED_CORNERS) || defined(STROKED)\nfloat aaPadding=1.0/uDevicePixelRatio;float strokeWidth=getScaled_strokeWidth();float strokeOpacity=getScaled_strokeOpacity()*opaFactor;vec2 centeredFrac=frac-0.5;vec2 expand=centeredFrac*(strokeWidth+aaPadding)/uViewportSize;pos+=expand;vec2 sizeInPixels=size*uViewportSize;vPosInPixels=(centeredFrac+expand/size)*sizeInPixels;vHalfSizeInPixels=sizeInPixels/2.0;vCornerRadii=min(cornerRadii,min(vHalfSizeInPixels.x,vHalfSizeInPixels.y));vHalfStrokeWidth=strokeWidth/2.0;vStrokeColor=vec4(getScaled_stroke()*strokeOpacity,strokeOpacity);\n#endif\ngl_Position=unitToNdc(pos);float fillOpacity=getScaled_fillOpacity()*opaFactor;vFillColor=vec4(getScaled_fill()*fillOpacity,fillOpacity);setupPicking();}";
|
|
2
2
|
export default shader;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const shader = "uniform Mark{uniform mediump float uMinLength;uniform mediump float uDashTextureSize;uniform lowp int uStrokeCap;uniform mediump float uStrokeDashOffset
|
|
1
|
+
const shader = "layout(std140)uniform Mark{uniform mediump float uMinLength;uniform mediump float uDashTextureSize;uniform lowp int uStrokeCap;uniform mediump float uStrokeDashOffset;\n#pragma markUniforms\n};";
|
|
2
2
|
export default shader;
|
package/dist/src/marks/rule.js
CHANGED
|
@@ -150,8 +150,8 @@ export default class RuleMark extends Mark {
|
|
|
150
150
|
|
|
151
151
|
const props = this.properties;
|
|
152
152
|
|
|
153
|
-
this.
|
|
154
|
-
this.
|
|
153
|
+
this.registerMarkUniformValue("uMinLength", props.minLength);
|
|
154
|
+
this.registerMarkUniformValue(
|
|
155
155
|
"uStrokeCap",
|
|
156
156
|
props.strokeCap ?? "butt",
|
|
157
157
|
(cap) => ["butt", "square", "round"].indexOf(cap)
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const shader = "uniform Mark{uniform mediump float uSdfNumerator;uniform mediump vec2 uD;uniform mediump vec4 uViewportEdgeFadeWidth;uniform mediump vec4 uViewportEdgeFadeDistance;uniform bool uSqueeze;uniform bool uLogoLetter;uniform lowp ivec2 uAlign;uniform mediump float uPaddingX;uniform bool uFlushX;uniform mediump float uPaddingY;uniform bool uFlushY
|
|
1
|
+
const shader = "layout(std140)uniform Mark{uniform mediump float uSdfNumerator;uniform mediump vec2 uD;uniform mediump vec4 uViewportEdgeFadeWidth;uniform mediump vec4 uViewportEdgeFadeDistance;uniform bool uSqueeze;uniform bool uLogoLetter;uniform lowp ivec2 uAlign;uniform mediump float uPaddingX;uniform bool uFlushX;uniform mediump float uPaddingY;uniform bool uFlushY;\n#pragma markUniforms\n};";
|
|
2
2
|
export default shader;
|
package/dist/src/marks/text.js
CHANGED
|
@@ -160,9 +160,9 @@ export default class TextMark extends Mark {
|
|
|
160
160
|
|
|
161
161
|
const props = this.properties;
|
|
162
162
|
|
|
163
|
-
this.
|
|
163
|
+
this.registerMarkUniformValue(
|
|
164
164
|
"uSdfNumerator",
|
|
165
|
-
/** @type {import("../spec/
|
|
165
|
+
/** @type {import("../spec/parameter.js").ExprRef | number} */
|
|
166
166
|
({ expr: "devicePixelRatio" }),
|
|
167
167
|
(dpr) => {
|
|
168
168
|
let q = 0.35; // TODO: Ensure that this makes sense. Now chosen by trial & error
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
* - Calling observers when a parameter changes
|
|
10
10
|
* - Somehow saving parameter "state" (in bookmarks)
|
|
11
11
|
* - Maybe something else
|
|
12
|
+
*
|
|
13
|
+
* @typedef {import("./utils/expression.js").ExpressionFunction & { addListener: (listener: () => void) => void, invalidate: () => void}} ExprRefFunction
|
|
12
14
|
*/
|
|
13
15
|
export default class ParamBroker {
|
|
14
16
|
/**
|
|
@@ -22,9 +24,23 @@ export default class ParamBroker {
|
|
|
22
24
|
*
|
|
23
25
|
* @param {string} expr
|
|
24
26
|
*/
|
|
25
|
-
createExpression(expr: string):
|
|
26
|
-
addListener: (listener: () => void) => void;
|
|
27
|
-
};
|
|
27
|
+
createExpression(expr: string): ExprRefFunction;
|
|
28
28
|
#private;
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* A class that manages parameters and expressions. Still a work in progress.
|
|
32
|
+
*
|
|
33
|
+
* TODO: Write tests for this class.
|
|
34
|
+
*
|
|
35
|
+
* This should eventually handle the following:
|
|
36
|
+
* - Parameter registration
|
|
37
|
+
* - Dependency tracking
|
|
38
|
+
* - Calling observers when a parameter changes
|
|
39
|
+
* - Somehow saving parameter "state" (in bookmarks)
|
|
40
|
+
* - Maybe something else
|
|
41
|
+
*/
|
|
42
|
+
export type ExprRefFunction = ((datum: object) => any) & import("./utils/expression.js").ExpressionProps & {
|
|
43
|
+
addListener: (listener: () => void) => void;
|
|
44
|
+
invalidate: () => void;
|
|
45
|
+
};
|
|
30
46
|
//# sourceMappingURL=paramBroker.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paramBroker.d.ts","sourceRoot":"","sources":["../../src/paramBroker.js"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"paramBroker.d.ts","sourceRoot":"","sources":["../../src/paramBroker.js"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;GAaG;AACH;IAyBI;;;;OAIG;IACH,0BAHW,MAAM,WACI,GAAG,KAAK,IAAI,CAqBhC;IAID;;;;OAIG;IACH,uBAFW,MAAM,mBA2ChB;;CACJ;;;;;;;;;;;;;;4BAtG2F,MAAM,IAAI,KAAK,IAAI;gBAAc,MAAM,IAAI"}
|