@perspective-dev/viewer-charts 4.3.0 → 4.5.1
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/cdn/perspective-viewer-charts.js +2 -2
- package/dist/cdn/perspective-viewer-charts.js.map +3 -3
- package/dist/esm/axis/bar-axis.d.ts +9 -1
- package/dist/esm/axis/categorical-axis.d.ts +0 -2
- package/dist/esm/charts/cartesian/cartesian.d.ts +26 -0
- package/dist/esm/charts/common/category-axis-resolver.d.ts +43 -1
- package/dist/esm/charts/common/expand-domain.d.ts +20 -0
- package/dist/esm/charts/common/tree-chart.d.ts +7 -0
- package/dist/esm/charts/common/tree-chrome.d.ts +23 -1
- package/dist/esm/charts/common/tree-interact.d.ts +46 -0
- package/dist/esm/charts/series/glyphs/draw-lines.d.ts +11 -4
- package/dist/esm/charts/series/series-build.d.ts +38 -2
- package/dist/esm/charts/series/series-render.d.ts +1 -4
- package/dist/esm/charts/series/series-type.d.ts +19 -17
- package/dist/esm/charts/series/series.d.ts +16 -0
- package/dist/esm/charts/sunburst/sunburst-interact.d.ts +1 -1
- package/dist/esm/charts/treemap/treemap-interact.d.ts +1 -6
- package/dist/esm/interaction/host-sink-message.d.ts +10 -28
- package/dist/esm/interaction/raw-event-forwarder.d.ts +6 -7
- package/dist/esm/interaction/zoom-controller.d.ts +31 -20
- package/dist/esm/interaction/zoom-router.d.ts +3 -26
- package/dist/esm/perspective-viewer-charts.js +2 -2
- package/dist/esm/perspective-viewer-charts.js.map +3 -3
- package/dist/esm/plugin/plugin.d.ts +0 -1
- package/dist/esm/theme/palette.d.ts +0 -5
- package/dist/esm/transport/protocol.d.ts +2 -7
- package/dist/esm/worker/renderer.worker.d.ts +2 -4
- package/package.json +1 -1
- package/src/ts/axis/bar-axis.ts +74 -45
- package/src/ts/axis/categorical-axis.ts +0 -2
- package/src/ts/charts/candlestick/candlestick-render.ts +10 -7
- package/src/ts/charts/candlestick/candlestick.ts +10 -29
- package/src/ts/charts/candlestick/glyphs/draw-candlesticks.ts +36 -2
- package/src/ts/charts/candlestick/glyphs/draw-ohlc.ts +36 -2
- package/src/ts/charts/cartesian/cartesian-build.ts +143 -9
- package/src/ts/charts/cartesian/cartesian-render.ts +205 -30
- package/src/ts/charts/cartesian/cartesian.ts +43 -4
- package/src/ts/charts/cartesian/glyphs/density.ts +36 -41
- package/src/ts/charts/cartesian/glyphs/lines.ts +13 -15
- package/src/ts/charts/cartesian/glyphs/points.ts +12 -17
- package/src/ts/charts/chart-base.ts +20 -6
- package/src/ts/charts/chart.ts +1 -1
- package/src/ts/charts/common/category-axis-resolver.ts +135 -1
- package/src/ts/charts/common/expand-domain.ts +40 -0
- package/src/ts/charts/common/tree-chart.ts +16 -0
- package/src/ts/charts/common/tree-chrome.ts +86 -1
- package/src/ts/charts/common/tree-interact.ts +209 -0
- package/src/ts/charts/heatmap/heatmap-render.ts +9 -11
- package/src/ts/charts/series/glyphs/draw-areas.ts +30 -1
- package/src/ts/charts/series/glyphs/draw-lines.ts +151 -76
- package/src/ts/charts/series/series-build.ts +394 -21
- package/src/ts/charts/series/series-render.ts +159 -38
- package/src/ts/charts/series/series-type.ts +37 -17
- package/src/ts/charts/series/series.ts +63 -68
- package/src/ts/charts/sunburst/sunburst-interact.ts +18 -162
- package/src/ts/charts/sunburst/sunburst-render.ts +24 -89
- package/src/ts/charts/sunburst/sunburst.ts +1 -15
- package/src/ts/charts/treemap/treemap-interact.ts +22 -189
- package/src/ts/charts/treemap/treemap-render.ts +19 -46
- package/src/ts/charts/treemap/treemap.ts +1 -16
- package/src/ts/interaction/host-sink-message.ts +33 -22
- package/src/ts/interaction/raw-event-forwarder.ts +10 -12
- package/src/ts/interaction/zoom-controller.ts +120 -83
- package/src/ts/interaction/zoom-router.ts +3 -126
- package/src/ts/map/tile-layer.ts +13 -13
- package/src/ts/plugin/plugin.ts +100 -184
- package/src/ts/shaders/line-uniform.frag.glsl +2 -1
- package/src/ts/shaders/line-uniform.vert.glsl +19 -0
- package/src/ts/theme/palette.ts +1 -4
- package/src/ts/transport/protocol.ts +3 -8
- package/src/ts/worker/dispatch.ts +0 -1
- package/src/ts/worker/renderer.worker.ts +10 -46
|
@@ -88,7 +88,6 @@ export declare class HTMLPerspectiveViewerWebGLPluginElement extends HTMLElement
|
|
|
88
88
|
clear(): Promise<void>;
|
|
89
89
|
resize(): Promise<void>;
|
|
90
90
|
restyle(): number;
|
|
91
|
-
save(): any;
|
|
92
91
|
render(view: View): Promise<Blob>;
|
|
93
92
|
restore(config: any, columns_config?: Record<string, any>): void;
|
|
94
93
|
delete(): void;
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import { type GradientStop } from "./gradient";
|
|
2
2
|
export type Vec3 = [number, number, number];
|
|
3
|
-
/**
|
|
4
|
-
* Build a series palette of length `count` by sampling the theme gradient
|
|
5
|
-
* at evenly-spaced offsets. For count == 1 returns the 50% stop.
|
|
6
|
-
*/
|
|
7
|
-
export declare function interpolatePalette(stops: GradientStop[], count: number): Vec3[];
|
|
8
3
|
/**
|
|
9
4
|
* Resolve a series palette: use the discrete `--psp-charts--series-N--color`
|
|
10
5
|
* palette when available, otherwise fall back to evenly-spaced samples of
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { FacetConfig, PluginConfig } from "../charts/chart";
|
|
2
2
|
import type { PerspectiveClickDetail } from "../event-detail";
|
|
3
|
+
import type { ThemeSnapshot } from "../theme/theme";
|
|
3
4
|
import type { ViewConfig } from "@perspective-dev/client";
|
|
5
|
+
export type { ThemeSnapshot };
|
|
4
6
|
/**
|
|
5
7
|
* Worker-mode control-channel messages. Distinct from the perspective
|
|
6
8
|
* `ProxySession` channel that the worker's `Client` uses to talk to the
|
|
@@ -160,13 +162,6 @@ export interface FontFaceDescriptor {
|
|
|
160
162
|
featureSettings?: string;
|
|
161
163
|
display?: string;
|
|
162
164
|
}
|
|
163
|
-
/**
|
|
164
|
-
* Theme values resolved on the host via `getComputedStyle` and shipped
|
|
165
|
-
* to the renderer scope, which has no DOM. Decoded by the chart via
|
|
166
|
-
* `theme/theme.ts::resolveThemeFromVars`. Plain map for
|
|
167
|
-
* structured-clone.
|
|
168
|
-
*/
|
|
169
|
-
export type ThemeSnapshot = Record<string, string>;
|
|
170
165
|
export interface SetViewByNameMsg {
|
|
171
166
|
kind: "setViewByName";
|
|
172
167
|
name: string;
|
|
@@ -81,10 +81,8 @@ export declare class WorkerRenderer {
|
|
|
81
81
|
resetExpandedDomain(): void;
|
|
82
82
|
/**
|
|
83
83
|
* Hit-test the cursor against the chart's facet grid (in faceted
|
|
84
|
-
* mode) or its current layout (single-plot).
|
|
85
|
-
*
|
|
86
|
-
* worker owns the facet grid and controllers, so the resolution
|
|
87
|
-
* runs here.
|
|
84
|
+
* mode) or its current layout (single-plot). The worker owns the
|
|
85
|
+
* facet grid and controllers, so the resolution runs here.
|
|
88
86
|
*/
|
|
89
87
|
private _resolveTarget;
|
|
90
88
|
onInteraction(event: InteractionEvent): void;
|
package/package.json
CHANGED
package/src/ts/axis/bar-axis.ts
CHANGED
|
@@ -142,6 +142,10 @@ export type BarCategoryAxis =
|
|
|
142
142
|
| { mode: "category"; domain: CategoricalDomain }
|
|
143
143
|
| { mode: "numeric"; domain: AxisDomain; ticks: number[] };
|
|
144
144
|
|
|
145
|
+
export type BarValueAxis =
|
|
146
|
+
| { mode: "category"; domain: CategoricalDomain }
|
|
147
|
+
| { mode: "numeric"; domain: AxisDomain; ticks: number[] };
|
|
148
|
+
|
|
145
149
|
/**
|
|
146
150
|
* Render a numeric date-aware axis along the bottom of the plot. Aliases
|
|
147
151
|
* the bar-axis bottom variant so heatmap can share the implementation.
|
|
@@ -190,13 +194,11 @@ export interface BarAxesFormatters {
|
|
|
190
194
|
export function renderBarAxesChrome(
|
|
191
195
|
canvas: Canvas2D,
|
|
192
196
|
catAxis: BarCategoryAxis,
|
|
193
|
-
|
|
194
|
-
valueTicks: number[],
|
|
197
|
+
valueAxis: BarValueAxis,
|
|
195
198
|
layout: PlotLayout,
|
|
196
199
|
theme: Theme,
|
|
197
200
|
dpr: number,
|
|
198
|
-
|
|
199
|
-
altTicks?: number[],
|
|
201
|
+
altAxis: BarValueAxis | undefined,
|
|
200
202
|
isHorizontal = false,
|
|
201
203
|
formatters: BarAxesFormatters = {},
|
|
202
204
|
): void {
|
|
@@ -212,7 +214,7 @@ export function renderBarAxesChrome(
|
|
|
212
214
|
ctx.moveTo(plot.x, plot.y);
|
|
213
215
|
ctx.lineTo(plot.x, plot.y + plot.height);
|
|
214
216
|
ctx.lineTo(plot.x + plot.width, plot.y + plot.height);
|
|
215
|
-
if (
|
|
217
|
+
if (altAxis) {
|
|
216
218
|
if (isHorizontal) {
|
|
217
219
|
ctx.moveTo(plot.x, plot.y);
|
|
218
220
|
ctx.lineTo(plot.x + plot.width, plot.y);
|
|
@@ -238,31 +240,49 @@ export function renderBarAxesChrome(
|
|
|
238
240
|
);
|
|
239
241
|
}
|
|
240
242
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
layout
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
theme,
|
|
248
|
-
formatters.value,
|
|
249
|
-
);
|
|
250
|
-
if (altDomain && altTicks) {
|
|
251
|
-
const origMin = layout.paddedXMin;
|
|
252
|
-
const origMax = layout.paddedXMax;
|
|
253
|
-
layout.paddedXMin = altDomain.min;
|
|
254
|
-
layout.paddedXMax = altDomain.max;
|
|
243
|
+
if (valueAxis.mode === "category") {
|
|
244
|
+
// Categorical value axis on the bottom: reuse the X
|
|
245
|
+
// categorical painter. Slot indices on the layout's X
|
|
246
|
+
// domain already place each category at its slot pixel.
|
|
247
|
+
renderCategoricalXTicks(ctx, layout, valueAxis.domain, theme);
|
|
248
|
+
} else {
|
|
255
249
|
drawNumericXAxis(
|
|
256
250
|
ctx,
|
|
257
251
|
layout,
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
"
|
|
252
|
+
valueAxis.domain,
|
|
253
|
+
valueAxis.ticks,
|
|
254
|
+
"bottom",
|
|
261
255
|
theme,
|
|
262
|
-
formatters.
|
|
256
|
+
formatters.value,
|
|
263
257
|
);
|
|
264
|
-
|
|
265
|
-
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (altAxis) {
|
|
261
|
+
// Alt-axis painter expects the layout's X domain to match
|
|
262
|
+
// the alt domain — temporarily swap in `altDomain.min/max`
|
|
263
|
+
// for the duration of the call. Categorical alt has no
|
|
264
|
+
// top-side painter; render with the bottom-side painter
|
|
265
|
+
// (visual overlap with the primary side — documented
|
|
266
|
+
// limitation; user-pinned categorical alt is rare).
|
|
267
|
+
if (altAxis.mode === "category") {
|
|
268
|
+
renderCategoricalXTicks(ctx, layout, altAxis.domain, theme);
|
|
269
|
+
} else {
|
|
270
|
+
const origMin = layout.paddedXMin;
|
|
271
|
+
const origMax = layout.paddedXMax;
|
|
272
|
+
layout.paddedXMin = altAxis.domain.min;
|
|
273
|
+
layout.paddedXMax = altAxis.domain.max;
|
|
274
|
+
drawNumericXAxis(
|
|
275
|
+
ctx,
|
|
276
|
+
layout,
|
|
277
|
+
altAxis.domain,
|
|
278
|
+
altAxis.ticks,
|
|
279
|
+
"top",
|
|
280
|
+
theme,
|
|
281
|
+
formatters.alt,
|
|
282
|
+
);
|
|
283
|
+
layout.paddedXMin = origMin;
|
|
284
|
+
layout.paddedXMax = origMax;
|
|
285
|
+
}
|
|
266
286
|
}
|
|
267
287
|
} else {
|
|
268
288
|
if (catAxis.mode === "category") {
|
|
@@ -278,31 +298,40 @@ export function renderBarAxesChrome(
|
|
|
278
298
|
);
|
|
279
299
|
}
|
|
280
300
|
|
|
281
|
-
|
|
282
|
-
ctx,
|
|
283
|
-
|
|
284
|
-
valueDomain,
|
|
285
|
-
valueTicks,
|
|
286
|
-
"left",
|
|
287
|
-
theme,
|
|
288
|
-
formatters.value,
|
|
289
|
-
);
|
|
290
|
-
if (altDomain && altTicks) {
|
|
291
|
-
const origMin = layout.paddedYMin;
|
|
292
|
-
const origMax = layout.paddedYMax;
|
|
293
|
-
layout.paddedYMin = altDomain.min;
|
|
294
|
-
layout.paddedYMax = altDomain.max;
|
|
301
|
+
if (valueAxis.mode === "category") {
|
|
302
|
+
renderCategoricalYTicks(ctx, layout, valueAxis.domain, theme);
|
|
303
|
+
} else {
|
|
295
304
|
drawYAxis(
|
|
296
305
|
ctx,
|
|
297
306
|
layout,
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
"
|
|
307
|
+
valueAxis.domain,
|
|
308
|
+
valueAxis.ticks,
|
|
309
|
+
"left",
|
|
301
310
|
theme,
|
|
302
|
-
formatters.
|
|
311
|
+
formatters.value,
|
|
303
312
|
);
|
|
304
|
-
|
|
305
|
-
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (altAxis) {
|
|
316
|
+
if (altAxis.mode === "category") {
|
|
317
|
+
renderCategoricalYTicks(ctx, layout, altAxis.domain, theme);
|
|
318
|
+
} else {
|
|
319
|
+
const origMin = layout.paddedYMin;
|
|
320
|
+
const origMax = layout.paddedYMax;
|
|
321
|
+
layout.paddedYMin = altAxis.domain.min;
|
|
322
|
+
layout.paddedYMax = altAxis.domain.max;
|
|
323
|
+
drawYAxis(
|
|
324
|
+
ctx,
|
|
325
|
+
layout,
|
|
326
|
+
altAxis.domain,
|
|
327
|
+
altAxis.ticks,
|
|
328
|
+
"right",
|
|
329
|
+
theme,
|
|
330
|
+
formatters.alt,
|
|
331
|
+
);
|
|
332
|
+
layout.paddedYMin = origMin;
|
|
333
|
+
layout.paddedYMax = origMax;
|
|
334
|
+
}
|
|
306
335
|
}
|
|
307
336
|
}
|
|
308
337
|
}
|
|
@@ -56,8 +56,6 @@ function categoryIndexToPixelY(layout: PlotLayout, index: number): number {
|
|
|
56
56
|
return layout.dataToPixel(0, index).py;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
export const categoryIndexToPixel = categoryIndexToPixelX;
|
|
60
|
-
|
|
61
59
|
function leafLevelLayout(
|
|
62
60
|
numRows: number,
|
|
63
61
|
longestCharCount: number,
|
|
@@ -125,13 +125,14 @@ export function renderCandlestickFrame(
|
|
|
125
125
|
yMax: chart._yDomain.max,
|
|
126
126
|
};
|
|
127
127
|
|
|
128
|
-
// Auto-fit the price axis to the visible X window. Skipped
|
|
129
|
-
// default zoom (the refit equals `_yDomain` there and would
|
|
130
|
-
// churn baselines)
|
|
128
|
+
// Auto-fit the price axis to the visible X window. Skipped when X
|
|
129
|
+
// is at default zoom (the refit equals `_yDomain` there and would
|
|
130
|
+
// only churn baselines) — Y-axis pan/zoom alone shouldn't trigger
|
|
131
|
+
// an X-window refit.
|
|
131
132
|
if (
|
|
132
133
|
chart._autoFitValue &&
|
|
133
134
|
chart._zoomController &&
|
|
134
|
-
!chart._zoomController.
|
|
135
|
+
!chart._zoomController.isXDefault()
|
|
135
136
|
) {
|
|
136
137
|
const fit = computeVisibleCandleExtent(chart, vis.xMin, vis.xMax);
|
|
137
138
|
if (fit.hasFit) {
|
|
@@ -271,13 +272,15 @@ export function renderCandlestickChromeOverlay(chart: CandlestickChart): void {
|
|
|
271
272
|
renderBarAxesChrome(
|
|
272
273
|
chart._chromeCanvas,
|
|
273
274
|
catAxis,
|
|
274
|
-
|
|
275
|
-
|
|
275
|
+
{
|
|
276
|
+
mode: "numeric",
|
|
277
|
+
domain: chart._lastYDomain,
|
|
278
|
+
ticks: chart._lastYTicks,
|
|
279
|
+
},
|
|
276
280
|
chart._lastLayout,
|
|
277
281
|
theme,
|
|
278
282
|
chart._glManager?.dpr ?? 1,
|
|
279
283
|
undefined,
|
|
280
|
-
undefined,
|
|
281
284
|
false,
|
|
282
285
|
{
|
|
283
286
|
value: chart.getColumnFormatter(valueColumn, "tick"),
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from "./candlestick-interact";
|
|
34
34
|
import { BodyWickGlyph } from "./glyphs/draw-candlesticks";
|
|
35
35
|
import { OHLCGlyph } from "./glyphs/draw-ohlc";
|
|
36
|
+
import { expandDomainInPlace } from "../common/expand-domain";
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
39
|
* Per-frame memo of the auto-fit Y extent for a {@link CandlestickChart},
|
|
@@ -266,38 +267,18 @@ export class CandlestickChart extends CategoricalYChart {
|
|
|
266
267
|
scratchCandles: this._candles,
|
|
267
268
|
});
|
|
268
269
|
// `domain_mode: "expand"` post-build union — mirrors the series
|
|
269
|
-
// pipeline.
|
|
270
|
+
// pipeline. `expandDomainInPlace` mutates `result.*` so the
|
|
270
271
|
// assignments below pick up the grown extent automatically.
|
|
271
272
|
if (this._pluginConfig.domain_mode === "expand") {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
);
|
|
277
|
-
result.yDomain.max = Math.max(
|
|
278
|
-
this._expandedYDomain.max,
|
|
279
|
-
result.yDomain.max,
|
|
280
|
-
);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
this._expandedYDomain = { ...result.yDomain };
|
|
284
|
-
|
|
273
|
+
this._expandedYDomain = expandDomainInPlace(
|
|
274
|
+
this._expandedYDomain,
|
|
275
|
+
result.yDomain,
|
|
276
|
+
);
|
|
285
277
|
if (result.numericCategoryDomain) {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
);
|
|
291
|
-
result.numericCategoryDomain.max = Math.max(
|
|
292
|
-
this._expandedCategoryDomain.max,
|
|
293
|
-
result.numericCategoryDomain.max,
|
|
294
|
-
);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
this._expandedCategoryDomain = {
|
|
298
|
-
min: result.numericCategoryDomain.min,
|
|
299
|
-
max: result.numericCategoryDomain.max,
|
|
300
|
-
};
|
|
278
|
+
this._expandedCategoryDomain = expandDomainInPlace(
|
|
279
|
+
this._expandedCategoryDomain,
|
|
280
|
+
result.numericCategoryDomain,
|
|
281
|
+
);
|
|
301
282
|
}
|
|
302
283
|
} else {
|
|
303
284
|
this._expandedYDomain = null;
|
|
@@ -46,9 +46,23 @@ interface WickCache {
|
|
|
46
46
|
u_color: WebGLUniformLocation | null;
|
|
47
47
|
u_resolution: WebGLUniformLocation | null;
|
|
48
48
|
u_line_width: WebGLUniformLocation | null;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* `line-uniform` was extended to support the Y-Line `interpolate`
|
|
52
|
+
* feature with a per-segment alpha multiplier driven by
|
|
53
|
+
* `a_real_start * a_real_end` and `u_interp_alpha`. Wicks are
|
|
54
|
+
* always "real" data — every segment renders fully — so we hold
|
|
55
|
+
* these locations to neutralize them at draw time (uniform = 1.0,
|
|
56
|
+
* constant attribute values = 1.0). Without that, an unset uniform
|
|
57
|
+
* defaults to 0 and the fragment alpha collapses to 0, rendering
|
|
58
|
+
* the wicks invisible.
|
|
59
|
+
*/
|
|
60
|
+
u_interp_alpha: WebGLUniformLocation | null;
|
|
49
61
|
a_corner: number;
|
|
50
62
|
a_start: number;
|
|
51
63
|
a_end: number;
|
|
64
|
+
a_real_start: number;
|
|
65
|
+
a_real_end: number;
|
|
52
66
|
}
|
|
53
67
|
|
|
54
68
|
interface ProgramCache {
|
|
@@ -124,8 +138,14 @@ export class BodyWickGlyph {
|
|
|
124
138
|
"line-uniform",
|
|
125
139
|
lineVert,
|
|
126
140
|
lineFrag,
|
|
127
|
-
[
|
|
128
|
-
|
|
141
|
+
[
|
|
142
|
+
"u_projection",
|
|
143
|
+
"u_color",
|
|
144
|
+
"u_resolution",
|
|
145
|
+
"u_line_width",
|
|
146
|
+
"u_interp_alpha",
|
|
147
|
+
],
|
|
148
|
+
["a_corner", "a_start", "a_end", "a_real_start", "a_real_end"],
|
|
129
149
|
);
|
|
130
150
|
const wick: WickCache = {
|
|
131
151
|
...wickPartial,
|
|
@@ -375,6 +395,20 @@ function drawWicks(
|
|
|
375
395
|
gl.uniform2f(cache.u_resolution, gl.canvas.width, gl.canvas.height);
|
|
376
396
|
gl.uniform1f(cache.u_line_width, chart._pluginConfig.wick_width_px * dpr);
|
|
377
397
|
|
|
398
|
+
// `line-uniform` was extended for the Y-Line interpolate feature
|
|
399
|
+
// with a per-segment alpha multiplier; neutralize it here.
|
|
400
|
+
// Constant attribute values (used when the array is disabled) and
|
|
401
|
+
// uniform are stable for every draw, so set once after
|
|
402
|
+
// `useProgram`. Disabling the arrays first guards against a prior
|
|
403
|
+
// Y-Line draw that left them enabled at the same attribute index
|
|
404
|
+
// (locations are shared because both programs link from the same
|
|
405
|
+
// source).
|
|
406
|
+
gl.disableVertexAttribArray(cache.a_real_start);
|
|
407
|
+
gl.disableVertexAttribArray(cache.a_real_end);
|
|
408
|
+
gl.vertexAttrib1f(cache.a_real_start, 1.0);
|
|
409
|
+
gl.vertexAttrib1f(cache.a_real_end, 1.0);
|
|
410
|
+
gl.uniform1f(cache.u_interp_alpha, 1.0);
|
|
411
|
+
|
|
378
412
|
const instancing = getInstancing(glManager);
|
|
379
413
|
const { setDivisor } = instancing;
|
|
380
414
|
|
|
@@ -30,9 +30,23 @@ interface OHLCCache {
|
|
|
30
30
|
u_color: WebGLUniformLocation | null;
|
|
31
31
|
u_resolution: WebGLUniformLocation | null;
|
|
32
32
|
u_line_width: WebGLUniformLocation | null;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* `line-uniform` was extended to support the Y-Line `interpolate`
|
|
36
|
+
* feature with a per-segment alpha multiplier driven by
|
|
37
|
+
* `a_real_start * a_real_end` and `u_interp_alpha`. The OHLC glyph
|
|
38
|
+
* doesn't need that — every segment is "real" — so we hold these
|
|
39
|
+
* locations to neutralize them at draw time (uniform = 1.0,
|
|
40
|
+
* constant attribute values = 1.0). Without that, an unset uniform
|
|
41
|
+
* defaults to 0 and the fragment alpha collapses to 0, rendering
|
|
42
|
+
* the entire OHLC glyph invisible.
|
|
43
|
+
*/
|
|
44
|
+
u_interp_alpha: WebGLUniformLocation | null;
|
|
33
45
|
a_corner: number;
|
|
34
46
|
a_start: number;
|
|
35
47
|
a_end: number;
|
|
48
|
+
a_real_start: number;
|
|
49
|
+
a_real_end: number;
|
|
36
50
|
}
|
|
37
51
|
|
|
38
52
|
/**
|
|
@@ -76,8 +90,14 @@ export class OHLCGlyph {
|
|
|
76
90
|
"line-uniform",
|
|
77
91
|
lineVert,
|
|
78
92
|
lineFrag,
|
|
79
|
-
[
|
|
80
|
-
|
|
93
|
+
[
|
|
94
|
+
"u_projection",
|
|
95
|
+
"u_color",
|
|
96
|
+
"u_resolution",
|
|
97
|
+
"u_line_width",
|
|
98
|
+
"u_interp_alpha",
|
|
99
|
+
],
|
|
100
|
+
["a_corner", "a_start", "a_end", "a_real_start", "a_real_end"],
|
|
81
101
|
);
|
|
82
102
|
this._program = {
|
|
83
103
|
...partial,
|
|
@@ -229,6 +249,20 @@ export class OHLCGlyph {
|
|
|
229
249
|
chart._pluginConfig.ohlc_line_width_px * dpr,
|
|
230
250
|
);
|
|
231
251
|
|
|
252
|
+
// `line-uniform` was extended for the Y-Line interpolate
|
|
253
|
+
// feature with a per-segment alpha multiplier; neutralize it
|
|
254
|
+
// here. Constant attribute values (used when the array is
|
|
255
|
+
// disabled) and uniform are stable for every draw, so set
|
|
256
|
+
// once after `useProgram`. Disabling the arrays first guards
|
|
257
|
+
// against a prior Y-Line draw that left them enabled at the
|
|
258
|
+
// same attribute index (locations are shared because both
|
|
259
|
+
// programs link from the same source).
|
|
260
|
+
gl.disableVertexAttribArray(cache.a_real_start);
|
|
261
|
+
gl.disableVertexAttribArray(cache.a_real_end);
|
|
262
|
+
gl.vertexAttrib1f(cache.a_real_start, 1.0);
|
|
263
|
+
gl.vertexAttrib1f(cache.a_real_end, 1.0);
|
|
264
|
+
gl.uniform1f(cache.u_interp_alpha, 1.0);
|
|
265
|
+
|
|
232
266
|
const instancing = getInstancing(glManager);
|
|
233
267
|
const { setDivisor } = instancing;
|
|
234
268
|
|