@tissuumaps/render 0.1.0-beta.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.
@@ -0,0 +1,2599 @@
1
+ import { Color } from '@tissuumaps/core';
2
+ import { CustomTileSource } from '@tissuumaps/core';
3
+ import { default as default_2 } from 'openseadragon';
4
+ import { Dims } from '@tissuumaps/core';
5
+ import { GroupValueMap } from '@tissuumaps/core';
6
+ import { IDArray } from '@tissuumaps/core';
7
+ import { Image as Image_2 } from '@tissuumaps/core';
8
+ import { ImageData as ImageData_2 } from '@tissuumaps/core';
9
+ import { InteractionMode } from '@tissuumaps/core';
10
+ import { Labels } from '@tissuumaps/core';
11
+ import { LabelsData } from '@tissuumaps/core';
12
+ import { Layer } from '@tissuumaps/core';
13
+ import { Marker } from '@tissuumaps/core';
14
+ import { MultiPolygon } from '@tissuumaps/core';
15
+ import { OpenSeadragonViewerOptions } from '@tissuumaps/core';
16
+ import { Points } from '@tissuumaps/core';
17
+ import { PointsData } from '@tissuumaps/core';
18
+ import { PointsGeometry } from '@tissuumaps/core';
19
+ import { Rect } from '@tissuumaps/core';
20
+ import { Shapes } from '@tissuumaps/core';
21
+ import { ShapesData } from '@tissuumaps/core';
22
+ import { Table } from '@tissuumaps/core';
23
+ import { TableData } from '@tissuumaps/core';
24
+ import { TileSourceConfig } from '@tissuumaps/core';
25
+ import { TypedArray } from '@tissuumaps/core';
26
+ import { WebGLPointsRenderOptions } from '@tissuumaps/core';
27
+ import { WebGLShapesRenderOptions } from '@tissuumaps/core';
28
+
29
+ /**
30
+ * Recolors the tiles of a tiled image whose pixels carry values rather than colors
31
+ *
32
+ * `getTileData` extracts the raw pixel values of an invalidated tile, in row-major
33
+ * order, one per raster pixel, along with the width and height of the raster.
34
+ * The raster may cover the full tile size rather than the tile's source bounds,
35
+ * as OpenSeadragon crops it when drawing. `transferValues` writes the packed RGBA
36
+ * color of each value to the pixel at the same index, as `0xAABBGGRR`, i.e.
37
+ * `(a << 24) | (b << 16) | (g << 8) | r` (see
38
+ * {@link OpenSeadragonContext.updateTiledImageDataTransfer}). It is called
39
+ * once per tile, with `pixelBuffer` as long as `values`. The buffer is reused
40
+ * across tiles and still holds the colors of the previous one, so every pixel
41
+ * has to be written.
42
+ */
43
+ declare type DataTransfer_2 = {
44
+ getTileData: (event: default_2.TileInvalidatedEvent) => Promise<{
45
+ values: TypedArray;
46
+ width: number;
47
+ height: number;
48
+ }>;
49
+ transferValues: (values: TypedArray, pixelBuffer: Uint32Array) => void;
50
+ };
51
+
52
+ /**
53
+ * A reference to either an image or labels object on a specific layer
54
+ *
55
+ * The reference of a rendered object carries the layer and object as they were
56
+ * when the reference was loaded; the properties applied to its tiled images
57
+ * come from the current model instead (see
58
+ * {@link OpenSeadragonRendererBase._updateRenderedObject}).
59
+ */
60
+ declare type ObjectRef<TObject extends Image_2 | Labels, TObjectData extends ImageData_2 | LabelsData> = {
61
+ layer: Layer;
62
+ object: TObject;
63
+ data: TObjectData;
64
+ };
65
+
66
+ /**
67
+ * A reference to a points or shapes object on a specific layer
68
+ *
69
+ * Identifies the layer, and carries the object as it was when the reference was
70
+ * loaded: everything that is resolved into a GPU resource is read from it, so
71
+ * that one synchronization sees one consistent model state, however often the
72
+ * model is set while it runs. The properties that are applied when drawing are
73
+ * not read from it - those come from the current model, which may have moved on
74
+ * since (see {@link WebGLRendererBase.getRenderPasses}).
75
+ *
76
+ * The item IDs and the item mask are cached and shared between references and
77
+ * across calls to {@link WebGLRendererBase.loadObjects}, and must not be
78
+ * modified.
79
+ */
80
+ declare type ObjectRef_2<TObject extends Points | Shapes, TObjectData extends PointsData | ShapesData> = {
81
+ layerId: string;
82
+ object: TObject;
83
+ itemIds: IDArray;
84
+ itemsMask: Uint8Array | undefined;
85
+ data: TObjectData;
86
+ };
87
+
88
+ /**
89
+ * A wrapper around an OpenSeadragon viewer
90
+ *
91
+ * In addition to creating and destroying the viewer, this class manages viewer
92
+ * options (including temporary overrides while the viewer is animating) and
93
+ * mutations of the viewer's world.
94
+ *
95
+ * Additions are split in two: tile sources are opened concurrently, but the
96
+ * world itself is mutated one operation at a time. World indices are shared
97
+ * mutable state that every addition and removal invalidates, and OpenSeadragon
98
+ * applies the `index` option only once an addition is committed - a microtask or
99
+ * more after it was requested - so an index is valid only while nothing else
100
+ * touches the world in between. Removals therefore go through the same queue as
101
+ * additions, rather than being applied right away. Reordering the world
102
+ * afterwards is not an alternative: the navigator mirrors index changes
103
+ * positionally and on a timer, and corrupts its own world if it has not caught
104
+ * up yet.
105
+ *
106
+ * Queued world mutations are ordered by request, so a caller that removes tiled
107
+ * images before requesting additions still resolves its indices against the
108
+ * world as it is once those removals have been applied.
109
+ *
110
+ * Tiled images can also be recolored: a tiled image whose pixels carry values
111
+ * rather than colors is drawn by mapping each value to an RGBA color (see
112
+ * {@link updateTiledImageDataTransfer}). As OpenSeadragon has no notion of a
113
+ * per-image color mapping, it is applied to the tiles themselves, in a
114
+ * `tile-invalidated` handler installed on the viewer. Data transfers are kept
115
+ * per tile source, rather than per tiled image, which also covers the
116
+ * navigator: it mirrors the world with tiled images of its own, but shares
117
+ * their tile sources, and OpenSeadragon raises the invalidation events of its
118
+ * tiles on this viewer. Its tiles are cached separately, though, so the
119
+ * navigator's mirror of a tiled image is invalidated alongside the original
120
+ * whenever the data transfer changes.
121
+ *
122
+ * The context also owns the world background: an opaque single-tile image at
123
+ * world index 0 that spans the bounds registered by every source via
124
+ * {@link setContentBounds} - the content of each renderer, and content rendered
125
+ * outside OpenSeadragon, such as points and shapes. It thereby fits the world,
126
+ * and with it the viewport, to all content, and it makes the drawer's canvas
127
+ * opaque wherever content is drawn, which additive compositing relies on (see
128
+ * `OpenSeadragonRendererBase.usesAdditiveBlending`). Its color is given on
129
+ * construction and is expected to match the background behind the viewer,
130
+ * which shows outside of it. Renderers insert their anchors after it, i.e. at
131
+ * world index 1 and up. See {@link _resizeBackground} for how it is resized
132
+ * without ever uncovering the canvas.
133
+ */
134
+ export declare class OpenSeadragonContext {
135
+ private static readonly _isLittleEndian;
136
+ private static readonly _emptyWorldBounds;
137
+ private static readonly _navigationKeyCodes;
138
+ readonly viewer: default_2.Viewer;
139
+ private readonly _tileSourceDataTransfers;
140
+ private readonly _tileDataTransfers;
141
+ private readonly _backgroundPixelUrl;
142
+ private readonly _contentBounds;
143
+ private _animationMemory?;
144
+ private _animationStartHandler?;
145
+ private _animationFinishHandler?;
146
+ private _worldMutationQueue;
147
+ private _pixelBuffer;
148
+ private _destroyed;
149
+ private _viewportControlledByUser;
150
+ private _background;
151
+ private _backgroundUpdateQueue;
152
+ /**
153
+ * Creates a new OpenSeadragonContext instance and initializes the OpenSeadragon viewer
154
+ *
155
+ * @param viewerElement - DOM element in which the OpenSeadragon viewer is created
156
+ * @param backgroundColor - Color of the world background (see the class
157
+ * documentation), which has to match the background of `viewerElement`
158
+ * @param viewerOptions - Options for configuring the OpenSeadragon viewer (optional)
159
+ */
160
+ constructor(viewerElement: HTMLElement, backgroundColor: Color, viewerOptions?: OpenSeadragonViewerOptions);
161
+ /**
162
+ * Installs OpenSeadragon `animation-start` and `animation-finish` handlers
163
+ *
164
+ * On animation start, the current values of all keys of the start options are
165
+ * saved (for the viewer and for each tiled image having such a property) and
166
+ * the start options are applied. On animation finish, the saved values are
167
+ * restored, overridden by the finish options.
168
+ *
169
+ * Only keys of the start options are saved and restored; keys appearing solely
170
+ * in the finish options are applied without ever being reverted. Likewise, only
171
+ * tiled images present at animation start have their values restored.
172
+ *
173
+ * Calling this method again replaces any previously installed handlers.
174
+ *
175
+ * @param viewerAnimationStartOptions - Options to apply when an animation starts
176
+ * @param viewerAnimationFinishOptions - Options to apply when an animation finishes
177
+ */
178
+ configureAnimationHandlers(viewerAnimationStartOptions: OpenSeadragonViewerOptions, viewerAnimationFinishOptions: OpenSeadragonViewerOptions): void;
179
+ /**
180
+ * Returns whether {@link destroy} has been called
181
+ *
182
+ * Turns `true` as soon as destruction starts, i.e. before pending world
183
+ * mutations have settled and before the viewer is actually destroyed. Further
184
+ * additions are rejected and further removals are ignored from that point on.
185
+ */
186
+ isDestroyed(): boolean;
187
+ /**
188
+ * Returns the currently visible viewport bounds in world coordinates
189
+ *
190
+ * Reflects the current viewport, not the target of an ongoing animation.
191
+ */
192
+ getViewport(): Rect;
193
+ /**
194
+ * Returns the size of the viewer container element, in screen-space pixels
195
+ */
196
+ getContainerSize(): Dims;
197
+ /**
198
+ * Applies viewer options to the OpenSeadragon viewer and all existing tiled images
199
+ *
200
+ * For each option key, performs a shallow merge (one level deep) of nested objects
201
+ * on both the viewer instance and every tiled image in the world.
202
+ *
203
+ * @param viewerOptions - Options to apply
204
+ */
205
+ setViewerOptions(viewerOptions: OpenSeadragonViewerOptions): void;
206
+ /**
207
+ * Resolves a tile source specifier to a ready-to-use OpenSeadragon tile source
208
+ *
209
+ * Fetches the image information if the specifier is a URL, awaits promised
210
+ * tile sources, and passes ready tile sources through. Doing this before an
211
+ * addition keeps the loading concurrent, while the additions themselves stay
212
+ * serialized (see {@link addTiledImage}).
213
+ *
214
+ * Rejects as soon as the operation is aborted, so that nothing waits for an
215
+ * abandoned open; the open itself cannot be canceled, and settles unobserved.
216
+ *
217
+ * @param tiledImageOptions - Options containing the tile source to open
218
+ * @param options - Optional abort signal
219
+ * @returns A promise that resolves with the opened tile source
220
+ */
221
+ openTileSource(tiledImageOptions: Omit<default_2.TileSourceSpecifier, "success" | "error">, options?: {
222
+ signal?: AbortSignal;
223
+ }): Promise<default_2.TileSource>;
224
+ /**
225
+ * Adds a tiled image to the OpenSeadragon viewer
226
+ *
227
+ * The tile source is opened right away, i.e. concurrently with the tile sources
228
+ * of other additions, but the tiled images are added to the world one after
229
+ * another, in the order in which they were requested. The index is resolved in
230
+ * between, when nothing else can shift the world anymore.
231
+ *
232
+ * The tile source may also be a promise of an already opened tile source,
233
+ * which is only awaited once the addition is executed. Callers can thus derive
234
+ * a tile source from another one that is still being opened, without giving up
235
+ * their place in the queue and thereby their world index.
236
+ *
237
+ * Rejects right away once the context has been destroyed.
238
+ *
239
+ * Aborting before the addition is executed skips it entirely. Later than that,
240
+ * the pending tile source load cannot be canceled anymore: the tiled image is
241
+ * added, immediately removed again, and the returned promise rejects with the
242
+ * signal's reason. Aborting a replacement (`tiledImageOptions.replace`) instead
243
+ * resolves, as the replaced tiled image is already gone by then and removing
244
+ * the new one, too, would leave a gap in the world.
245
+ *
246
+ * @param tiledImageOptions - Options for adding the tiled image, including the tile source
247
+ * @param options - Optional abort signal and index resolver. The latter takes
248
+ * precedence over `tiledImageOptions.index`, and appends the tiled image to the
249
+ * world if it returns `undefined`.
250
+ * @returns A promise that resolves with the added tiled image, or rejects if
251
+ * adding it failed or the operation was aborted
252
+ */
253
+ addTiledImage(tiledImageOptions: Omit<default_2.TileSourceSpecifier, "success" | "error">, options?: {
254
+ signal?: AbortSignal;
255
+ getIndex?: () => number | undefined;
256
+ }): Promise<default_2.TiledImage>;
257
+ /**
258
+ * Removes a tiled image from the OpenSeadragon viewer
259
+ *
260
+ * The removal is queued behind the world mutations requested before it, so
261
+ * that it cannot shift the world while an addition is waiting for
262
+ * OpenSeadragon to apply its index. Does nothing once the context has been
263
+ * destroyed, as the viewer tears down its world itself.
264
+ *
265
+ * @param tiledImage - The tiled image to remove
266
+ * @returns A promise that resolves once the tiled image has been removed.
267
+ */
268
+ removeTiledImage(tiledImage: default_2.TiledImage): Promise<void>;
269
+ /**
270
+ * Returns the index of a tiled image in the OpenSeadragon viewer's world
271
+ *
272
+ * @param tiledImage - The tiled image for which to get the index
273
+ * @returns The index of the tiled image, or -1 if it is not in the world
274
+ */
275
+ getTiledImageIndex(tiledImage: default_2.TiledImage): number;
276
+ /**
277
+ * Updates the data transfer of a tiled image
278
+ *
279
+ * The data transfer is applied per tile: the tile's pixel values are
280
+ * extracted and each is replaced by the color it maps to (see
281
+ * {@link DataTransfer}). Passing `undefined` leaves the tiles as they are. It
282
+ * is applied to every tile of the tiled image, including those loaded later.
283
+ *
284
+ * The data transfer is remembered per tile source, until the tile source is
285
+ * garbage-collected. Tiled images that share a tile source therefore also
286
+ * share a data transfer, with the last one set winning - including the tiled
287
+ * images of the navigator, which mirror those of this viewer and are
288
+ * recolored along with them. As the navigator keeps a tile cache of its own,
289
+ * which the invalidation of `tiledImage` does not reach, its tiled images
290
+ * that share the tile source are invalidated explicitly, too. Those are few
291
+ * low-resolution tiles, so this stays cheap; invalidating the whole viewer
292
+ * would re-run every data transfer on every loaded tile instead.
293
+ *
294
+ * A tiled image keeps up to the whole tile cache loaded, most of it outside
295
+ * the viewport, so only the tiles drawn in the viewport are invalidated. The
296
+ * others are recolored once they are drawn again (see
297
+ * {@link _recolorStaleTiles}), which keeps the cost of a change proportional
298
+ * to the viewport rather than to the tile cache. Removing a data transfer
299
+ * invalidates every tile of the tiled image instead, as tiles without a data
300
+ * transfer are not caught up with.
301
+ *
302
+ * Data transfers are compared by identity: the tiles are only invalidated,
303
+ * and thereby recolored from their original data, if a different data
304
+ * transfer object is passed. Callers are expected to pass the same object for
305
+ * as long as its outcome would not change, as invalidating the tiles re-runs
306
+ * the data transfer on every tile in the viewport, and on every other loaded
307
+ * tile of the tile source once it is drawn.
308
+ *
309
+ * @param tiledImage - The tiled image to update
310
+ * @param dataTransfer - The data transfer to apply, or `undefined` for none
311
+ */
312
+ updateTiledImageDataTransfer(tiledImage: default_2.TiledImage, dataTransfer: DataTransfer_2 | undefined): void;
313
+ /**
314
+ * Sets the bounds of the content that a source contributes to the world
315
+ *
316
+ * The world background (see the class documentation) is resized to the
317
+ * bounding box of the bounds of all sources, or to
318
+ * {@link _emptyWorldBounds} if there are none (see
319
+ * {@link _resizeBackground}). Renderers register the bounds of their tiled
320
+ * images under themselves; the bounds of content rendered outside
321
+ * OpenSeadragon are registered under any other stable object. Passing no
322
+ * bounds removes the source.
323
+ *
324
+ * @param source - The object under which to register the bounds
325
+ * @param bounds - The bounds contributed by the source, in world coordinates
326
+ * @param options - Optional abort signal
327
+ * @returns A promise that resolves once the background covers the bounds,
328
+ * i.e. once it has been drawn wherever they are in the viewport
329
+ */
330
+ setContentBounds(source: object, bounds: Rect[], options?: {
331
+ signal?: AbortSignal;
332
+ }): Promise<void>;
333
+ /**
334
+ * Hands viewport control back to the renderers
335
+ *
336
+ * Fits the viewport to the bounds of the world, and resumes doing so whenever
337
+ * they change, until the user pans or zooms again. Call this when the content
338
+ * of the viewer is replaced, e.g. on opening a project.
339
+ */
340
+ resetViewport(): void;
341
+ /**
342
+ * Destroys the OpenSeadragon viewer and cleans up resources
343
+ *
344
+ * The context is marked as destroyed immediately (see {@link isDestroyed}), but
345
+ * the viewer is only destroyed once no world mutation is pending anymore, as
346
+ * their callbacks would otherwise run against a destroyed viewer. Marking the
347
+ * context as destroyed also stops further world mutations from being enqueued,
348
+ * so awaiting the queue's current tail is enough to drain it.
349
+ */
350
+ destroy(): Promise<void>;
351
+ /**
352
+ * Opens a tile source, see {@link openTileSource}
353
+ *
354
+ * @param tiledImageOptions - Options containing the tile source to open
355
+ * @param options - Optional abort signal, which skips the open if the
356
+ * operation is aborted before it starts
357
+ * @returns A promise that resolves with the opened tile source
358
+ */
359
+ private _openTileSource;
360
+ /**
361
+ * Resizes the world background to the registered bounds, creating it at world index 0 if it does not exist yet
362
+ *
363
+ * The background is kept if it already has the bounds (see
364
+ * {@link OpenSeadragonUtils.hasBounds}). Otherwise, a new background is
365
+ * inserted right below it, and the old one is removed only once the new one
366
+ * has been drawn (see {@link _waitUntilDrawn}). Unlike a renderer's anchor
367
+ * (see `OpenSeadragonRendererBase._resizeAnchor`), the background is not
368
+ * replaced as part of the addition: OpenSeadragon removes the replaced tiled
369
+ * image right away, whereas the new one is drawn only once its tile has
370
+ * loaded, which would leave the canvas uncovered for a frame or more. While
371
+ * both backgrounds exist, they sit below all anchors, so the world indices
372
+ * that the renderers resolve relative to their anchors are unaffected.
373
+ *
374
+ * Resizes are run one at a time, in call order, each to the bounds
375
+ * registered by the time it runs, so intermediate ones are skipped. A
376
+ * failing resize does not prevent subsequent ones from running. Aborting
377
+ * skips the resize if the new background has not been added yet, and has no
378
+ * effect afterwards, as that would leave two backgrounds in the world. Does
379
+ * nothing once the context has been destroyed.
380
+ *
381
+ * @param options - Optional abort signal
382
+ * @returns A promise that resolves once the background has been resized
383
+ */
384
+ private _resizeBackground;
385
+ /**
386
+ * Implementation of {@link addTiledImage}, bypassing the world mutation queue
387
+ *
388
+ * Must only be called from within an enqueued world mutation, such that the
389
+ * index resolved by `options.getIndex` is still valid when OpenSeadragon
390
+ * applies it.
391
+ */
392
+ private _addTiledImage;
393
+ /**
394
+ * Waits until a tiled image has been drawn wherever it is in the viewport
395
+ *
396
+ * That is, until all tiles it needs for the current view have loaded, or
397
+ * until it is not in the viewport at all: OpenSeadragon keeps the loading
398
+ * state of a tiled image outside the viewport as it is, so the tiled image
399
+ * would otherwise be waited for until it is panned into view. OpenSeadragon
400
+ * sets the former while updating a frame, right before drawing it; the
401
+ * latter can only change along with the viewport, as the tiled image is not
402
+ * moved while waited for. Both are therefore checked right away, and again
403
+ * whenever either changes. Also resolves once its tile has failed to load
404
+ * for good, as it is never fully loaded then, and once the context has been
405
+ * destroyed, at the latest when it destroys the viewer (see {@link destroy}).
406
+ *
407
+ * @param tiledImage - The tiled image to wait for
408
+ * @returns A promise that resolves once the tiled image has been drawn
409
+ */
410
+ private _waitUntilDrawn;
411
+ /**
412
+ * Appends a world mutation to the world mutation queue
413
+ *
414
+ * Tasks are run one at a time, in call order, and a failing task does not
415
+ * prevent subsequent tasks from running. Every operation that adds to or
416
+ * removes from the world has to be enqueued here, so that the world cannot
417
+ * shift between an addition resolving its index and OpenSeadragon applying it.
418
+ *
419
+ * @param task - Task to run once all previously enqueued tasks have settled
420
+ * @returns A promise that resolves with the task's result
421
+ */
422
+ private _enqueueWorldMutation;
423
+ /**
424
+ * Recolors the drawn tiles whose data transfer is outdated
425
+ *
426
+ * A change of a data transfer only invalidates the tiles in the viewport
427
+ * (see {@link updateTiledImageDataTransfer}), which leaves the other loaded
428
+ * tiles of the tile source in the colors of an earlier data transfer. Every
429
+ * tile records the data transfer it was last recolored with (see
430
+ * {@link _applyDataTransfer}); a drawn tile that recorded a different one than
431
+ * its tile source's is invalidated, unless it is being recolored already.
432
+ * Such a tile is drawn in its earlier colors until it is recolored, which
433
+ * takes a frame or two.
434
+ *
435
+ * Tiles loaded after a change are recolored on load, and tile sources
436
+ * without a data transfer are skipped: their tiles were all restored when
437
+ * the data transfer was removed.
438
+ */
439
+ private _recolorStaleTiles;
440
+ /**
441
+ * Replaces the data of an invalidated tile with the colors of its values
442
+ *
443
+ * Does nothing unless a data transfer is set for the tile source of the tile
444
+ * (see {@link updateTiledImageDataTransfer}).
445
+ *
446
+ * OpenSeadragon raises the invalidation events of all tiles of a change at
447
+ * once, and recoloring a tile holds the thread for as long as the tile has
448
+ * pixels, so each tile first yields to the event loop: the user interface
449
+ * stays responsive while a change is recolored. A change that arrives
450
+ * meanwhile invalidates the same tiles again, which marks the runs of the
451
+ * change before it as outdated; those are abandoned, as the newer runs
452
+ * recolor the tiles. The data transfer is read only after yielding, so that
453
+ * a run that continues always applies the latest one. It is recorded as the
454
+ * tile's before the tile is recolored (see {@link _recolorStaleTiles}), so
455
+ * that a tile whose recoloring fails is not retried on every draw.
456
+ *
457
+ * The colors are written as packed 32-bit values through a `Uint32Array`
458
+ * view of an `ImageData` buffer, whose bytes are R, G, B, A. The
459
+ * `0xAABBGGRR` layout of {@link DataTransfer} lands in that order on a
460
+ * little-endian host; on a big-endian host, the bytes of every pixel are
461
+ * swapped afterwards. The buffer is shared by all tiles of the viewer and
462
+ * only ever grows, as this is a hot path: changing a data transfer
463
+ * reconverts every cached tile. Sharing is safe because nothing awaits
464
+ * between filling and copying the buffer, and `putImageData` copies the
465
+ * pixels.
466
+ *
467
+ * The pixels are copied onto a new canvas of the raster's size, which
468
+ * becomes the tile's data. The canvas cannot be shared, as OpenSeadragon
469
+ * keeps it in its tile cache by reference. Nor is the tile's own canvas
470
+ * used: obtaining that would convert the tile's original data to a canvas
471
+ * first, only for it to be overwritten. The canvas is created with
472
+ * `willReadFrequently`, which keeps it in memory rather than on the GPU: the
473
+ * WebGL drawer reads a pixel of every canvas it turns into a texture, to
474
+ * check whether it is tainted, and reading from a GPU canvas waits for the
475
+ * GPU.
476
+ *
477
+ * @param event - The tile invalidation event whose tile data is replaced
478
+ * @returns A promise that resolves once the tile data has been replaced
479
+ * @throws Error if the number of pixel values does not match the raster size
480
+ */
481
+ private _applyDataTransfer;
482
+ }
483
+
484
+ /**
485
+ * Renderer for the tiled images of {@link Image} data objects
486
+ *
487
+ * Multi-channel image data provides one tiled image per channel, whose tiles
488
+ * carry the channel's values rather than colors. Each channel is recolored by a
489
+ * data transfer (see {@link OpenSeadragonContext.updateTiledImageDataTransfer})
490
+ * that scales the values between the channel's contrast limits and multiplies
491
+ * them with the channel's color. Color and contrast limits are resolved by
492
+ * {@link ImageUtils.getChannelColor} and
493
+ * {@link ImageUtils.getChannelContrastLimits}; channels without contrast
494
+ * limits are stretched over the value range of each tile's data type. In the
495
+ * grayscale view mode, every channel is colorized white instead of its color.
496
+ * Channels whose data does not provide values are drawn as they are, as is
497
+ * image data that is not multi-channel. Channel visibility and opacity are not
498
+ * part of the transfer: like layer and image opacity, OpenSeadragon applies
499
+ * them when drawing the tiled image, which is also where the single-channel
500
+ * view modes hide all but the image's active channel (see
501
+ * {@link getTiledImageOpacity}).
502
+ *
503
+ * Channel colors, contrast limits and the view mode need no synchronization:
504
+ * like visibility and opacity, they are read from the current model whenever
505
+ * the image's tiled images are updated (see
506
+ * {@link resolveTiledImageDataTransfer}), so changing them only requires
507
+ * {@link setModel}. As data transfers are compared by identity, each channel's
508
+ * data transfer is kept until the image's data, or the channel's resolved color
509
+ * (white in grayscale) or contrast limits change, so that tiles are only
510
+ * recolored when needed.
511
+ */
512
+ export declare class OpenSeadragonImageRenderer extends OpenSeadragonRendererBase<Image_2, ImageData_2, OpenSeadragonImageSyncContext> {
513
+ private readonly _renderedMultichannelImages;
514
+ /**
515
+ * Returns the state of an image that a synchronization depends on
516
+ *
517
+ * Blanks out the channel view mode and active channel, and the name,
518
+ * visibility, opacity, color and contrast limits of every channel on top of
519
+ * what the base class blanks out: they are applied from the current model
520
+ * when updating the channel's tiled image (see {@link getTiledImageOpacity}
521
+ * and {@link resolveTiledImageDataTransfer}), except for the name, which is
522
+ * cosmetic.
523
+ *
524
+ * @param image - The image to return the state of
525
+ * @returns The image without the properties that are applied by
526
+ * {@link setModel}, and without the cosmetic ones
527
+ */
528
+ protected getObjectSyncState(image: Image_2): object;
529
+ /**
530
+ * Drops the data transfers of all images other than the given ones
531
+ *
532
+ * @param images - The images about to be displayed
533
+ */
534
+ protected retainObjects(images: Image_2[]): void;
535
+ /**
536
+ * Returns the tile sources for the given image data
537
+ *
538
+ * Multi-channel image data provides one tile source per channel, in channel
539
+ * order; all other image data provides a single tile source.
540
+ *
541
+ * @param data - The image data for which to retrieve the tile sources
542
+ * @returns The tile sources, one per channel for multi-channel image data and
543
+ * a single one otherwise
544
+ */
545
+ protected getTileSources(data: ImageData_2): (string | TileSourceConfig | CustomTileSource)[];
546
+ /**
547
+ * Returns whether the channels of the given image data are blended additively
548
+ *
549
+ * Multi-channel image data blends additively, so that its channels add up
550
+ * rather than hide one another. Image data that is not multi-channel has a
551
+ * single tile source, so there is nothing to add up, and it keeps
552
+ * OpenSeadragon's default compositing, which preserves the transparency of its
553
+ * tiles.
554
+ *
555
+ * @param data - The image data to check
556
+ * @returns Whether the image's channels are blended additively
557
+ */
558
+ protected usesAdditiveBlending(data: ImageData_2): boolean;
559
+ /**
560
+ * Computes the effective opacity for one of an image's tiled images
561
+ *
562
+ * Multiplies the layer and image opacity computed by the base class with the
563
+ * visibility and opacity of the channel that the tiled image renders. Channels
564
+ * are only applied to multi-channel image data, and channels that the image
565
+ * does not define are visible at full opacity. In the single-channel view
566
+ * modes, only the image's active channel is visible (see
567
+ * {@link ImageUtils.getActiveChannel}). Without a channel index, i.e. for the
568
+ * image's backdrop, the layer and image opacity is returned as is.
569
+ *
570
+ * @param ref - The image reference for which to compute the opacity
571
+ * @param index - The index of the tiled image (channel), or `null` for the image's backdrop
572
+ * @returns The effective opacity for the tiled image
573
+ */
574
+ protected getTiledImageOpacity(ref: ObjectRef<Image_2, ImageData_2>, index: number | null): number;
575
+ /**
576
+ * Resolves the data transfer for one of an image's tiled images, unless it is up to date
577
+ *
578
+ * Only the tiled images of the channels of multi-channel image data are
579
+ * recolored, never the backdrop. A channel's color and contrast limits are
580
+ * resolved (see {@link ImageUtils.getChannelColor} and
581
+ * {@link ImageUtils.getChannelContrastLimits}), with every channel white in
582
+ * the grayscale view mode. The channel's data transfer is kept as long as the
583
+ * image's data and the resolved values are unchanged, and is created anew
584
+ * otherwise (see {@link _createDataTransfer}). Channels are resolved
585
+ * independently, so that changing one channel only recolors the tiles of that
586
+ * channel.
587
+ *
588
+ * @param ref - The image reference for which to get the data transfer, holding
589
+ * the image as it currently is in the model
590
+ * @param index - The index of the tiled image (channel), or `null` for the image's backdrop
591
+ * @returns The channel's data transfer, or `undefined` if the channel has none
592
+ */
593
+ protected resolveTiledImageDataTransfer(ref: ObjectRef<Image_2, ImageData_2>, index: number | null): DataTransfer_2 | undefined;
594
+ /**
595
+ * Creates the data transfer of an image channel
596
+ *
597
+ * The transfer scales each value linearly between the contrast limits,
598
+ * clamped to `[0, 1]`, and multiplies the result with the channel's color,
599
+ * which {@link resolveTiledImageDataTransfer} has already resolved. Without
600
+ * contrast limits, the value range of the data type of each tile's data is
601
+ * used (see {@link ImageUtils.getDataTypeRange}); contrast limits that are not
602
+ * ascending render every value black. The resulting pixels are opaque;
603
+ * channel visibility and opacity are applied by OpenSeadragon when drawing
604
+ * the tiled image.
605
+ *
606
+ * The scaled color is not computed per pixel: the transfer packs a ramp of
607
+ * 256 colors once, with `ColorUtils.packColor` and `ColorUtils.withAlpha`,
608
+ * and maps each value to the nearest ramp entry. As no color component
609
+ * exceeds 255, the ramp holds every color the channel can take.
610
+ *
611
+ * @param data - The image data providing the channel's values
612
+ * @param channel - The resolved color and contrast limits of the channel
613
+ * @returns The data transfer, or `undefined` if the data provides no channel
614
+ * values
615
+ */
616
+ private static _createDataTransfer;
617
+ }
618
+
619
+ declare type OpenSeadragonImageSyncContext = {
620
+ loadObject: (image: Image_2, options?: {
621
+ signal?: AbortSignal;
622
+ }) => Promise<ImageData_2>;
623
+ };
624
+
625
+ /**
626
+ * Renderer for the tiled images of {@link Labels} data objects
627
+ *
628
+ * The tiles of a labels object carry label IDs rather than colors, and are
629
+ * recolored by a data transfer (see
630
+ * {@link OpenSeadragonContext.updateTiledImageDataTransfer}) that looks each
631
+ * ID up in a color lookup table, which folds the visibility and opacity into
632
+ * the alpha channel. Layer and object opacity are not part of it; OpenSeadragon
633
+ * applies them when drawing the tiled image.
634
+ *
635
+ * A label image does not enumerate its labels (see {@link LabelsData}), so the
636
+ * lookup table is resolved per object for the labels that the referenced table
637
+ * lists, in the same way as the WebGL renderers resolve the appearance of their
638
+ * items, and every other label is resolved as it is first drawn (see
639
+ * {@link _resolveDataTransfer}).
640
+ *
641
+ * As data transfers are compared by identity, each object's data transfer is
642
+ * kept (see {@link resolveObject}) until its data, one of the configurations
643
+ * it was resolved from, or one of the group-to-value maps those configurations
644
+ * reference changes, so that tiles are only recolored when needed. Maps are
645
+ * never mutated - an edit replaces the map object - so they are compared by
646
+ * identity, which is why the maps passed to a synchronization have to keep
647
+ * their identity for as long as they are unchanged.
648
+ */
649
+ export declare class OpenSeadragonLabelsRenderer extends OpenSeadragonRendererBase<Labels, LabelsData, OpenSeadragonLabelsSyncContext> {
650
+ private readonly _renderedLabels;
651
+ /**
652
+ * Drops the data transfers of all labels objects other than the given ones
653
+ *
654
+ * @param labels - The labels objects about to be displayed
655
+ */
656
+ protected retainObjects(labels: Labels[]): void;
657
+ /**
658
+ * Resolves the data transfer of a labels object, unless it is up to date
659
+ *
660
+ * An object's data transfer is kept as long as its data, its label color,
661
+ * visibility and opacity configurations, and the group-to-value maps those
662
+ * configurations resolve from (see {@link ConfigUtils.findGroupByMap}) are
663
+ * unchanged, and is resolved anew otherwise (see
664
+ * {@link _resolveDataTransfer}). Configurations are compared by value, maps
665
+ * by identity. If resolving from the referenced table fails, e.g. because the
666
+ * table failed to load, the failure is logged and the object's labels are
667
+ * resolved without table data instead, until its data, one of its
668
+ * configurations or one of its maps changes.
669
+ *
670
+ * @param labels - The labels object to resolve
671
+ * @param data - The loaded data of the labels object
672
+ * @param context - The inputs of the current synchronization
673
+ * @param options - Optional abort signal
674
+ * @returns A promise that resolves once the data transfer has been resolved
675
+ */
676
+ protected resolveObject(labels: Labels, data: LabelsData, context: OpenSeadragonLabelsSyncContext, options?: {
677
+ signal?: AbortSignal;
678
+ }): Promise<void>;
679
+ /**
680
+ * Returns the data transfer resolved for the given labels object
681
+ *
682
+ * A labels object has a single tiled image, whose tiles carry the label IDs,
683
+ * and no backdrop, so the index is not looked at.
684
+ *
685
+ * @param ref - The labels reference for which to get the data transfer
686
+ * @returns The data transfer resolved by {@link resolveObject}, or
687
+ * `undefined` if the object has not been resolved
688
+ */
689
+ protected resolveTiledImageDataTransfer(ref: ObjectRef<Labels, LabelsData>): DataTransfer_2 | undefined;
690
+ /**
691
+ * Resolves the data transfer of a labels object
692
+ *
693
+ * If a label color, visibility or opacity configuration reads from the
694
+ * referenced table, the table is loaded and the appearance of every label it
695
+ * lists is resolved up front, in the same way as the WebGL renderers resolve
696
+ * the appearance of their items, into a lookup table from label ID to packed
697
+ * pixel. Every other label - those the table does not list, and all labels
698
+ * if no configuration needs the table - is resolved as it is first drawn
699
+ * (see {@link _createDataTransfer}).
700
+ *
701
+ * If the table cannot be loaded or a configuration cannot be resolved from
702
+ * it, the failure is logged and the lookup table is left empty, so that all
703
+ * labels are resolved without table data.
704
+ *
705
+ * @param labels - The labels object to resolve
706
+ * @param data - The loaded data of the labels object
707
+ * @param context - The inputs of the current synchronization
708
+ * @param options - Optional abort signal
709
+ * @returns The resolved data transfer
710
+ */
711
+ private static _resolveDataTransfer;
712
+ /**
713
+ * Creates the data transfer of a labels object from a lookup table
714
+ *
715
+ * Label value `0` is background and maps to a fully transparent pixel. Labels
716
+ * that the lookup table does not list are resolved without table data as
717
+ * they are first drawn (see e.g. {@link ColorResolver.resolveColorWithoutTable}):
718
+ * constant values and random colors resolve exactly, whereas configurations
719
+ * that need the table fall back to the default label color, visibility and
720
+ * opacity. The result is memoized in the lookup table, so that each label is
721
+ * resolved once.
722
+ *
723
+ * @param labels - The labels object whose configurations unlisted labels are resolved from
724
+ * @param data - The loaded data of the labels object
725
+ * @param labelPixelValues - The lookup table from label ID to packed pixel,
726
+ * extended as labels are drawn
727
+ * @returns The data transfer
728
+ */
729
+ private static _createDataTransfer;
730
+ }
731
+
732
+ declare type OpenSeadragonLabelsSyncContext = {
733
+ tables: Table[];
734
+ colorMaps: GroupValueMap<Color>[];
735
+ visibilityMaps: GroupValueMap<boolean>[];
736
+ opacityMaps: GroupValueMap<number>[];
737
+ loadObject: (labels: Labels, options?: {
738
+ signal?: AbortSignal;
739
+ }) => Promise<LabelsData>;
740
+ loadTable: (table: Table, options?: {
741
+ signal?: AbortSignal;
742
+ }) => Promise<TableData>;
743
+ };
744
+
745
+ /**
746
+ * Base class for OpenSeadragon renderers that manage tiled images for objects (images or labels)
747
+ *
748
+ * Renderers share a viewer, so each renderer owns an anchor: an invisible
749
+ * single-tile image that marks where the renderer's own tiled images belong.
750
+ * They directly follow the anchor, in the order of {@link _renderedObjects},
751
+ * with one tiled image per channel of each object.
752
+ *
753
+ * Every tiled image contributes to the bounds of the world, the anchor
754
+ * included, so the anchor spans just the renderer's own tiled images, which
755
+ * keeps it from extending the world (see {@link updateBounds}). The same bounds
756
+ * are registered with the context (see
757
+ * {@link OpenSeadragonContext.setContentBounds}), whose world background fits
758
+ * the world to the content of all renderers, and covers it from below.
759
+ *
760
+ * The tiled images of an object that uses additive blending are preceded by one
761
+ * more tiled image, its backdrop (see {@link usesAdditiveBlending}).
762
+ *
763
+ * Tiled images are inserted behind the anchor when they are added, rather than
764
+ * moved there afterwards, as OpenSeadragon's navigator cannot keep up with
765
+ * reordering. {@link _cleanRenderedObjects} recreates those that are out of place.
766
+ *
767
+ * The layers and objects to render are set by {@link setModel}, which applies
768
+ * the properties that tiled images take directly - transforms, visibility and
769
+ * opacity - to the rendered objects right away. Everything else - the set and
770
+ * order of the layers and objects, data sources and whatever the subclasses
771
+ * resolve from an object (see {@link resolveObject}) - requires a
772
+ * synchronization, which {@link needsSynchronization} reports and
773
+ * {@link synchronize} performs. The properties applied directly are always read
774
+ * from the current model, never from the reference of a rendered object (see
775
+ * {@link _updateRenderedObject}), so a synchronization that is in flight while
776
+ * the model changes does not write stale values.
777
+ */
778
+ declare abstract class OpenSeadragonRendererBase<TObject extends Image_2 | Labels, TObjectData extends ImageData_2 | LabelsData, TSyncContext extends {
779
+ loadObject: (object: TObject, options?: {
780
+ signal?: AbortSignal;
781
+ }) => Promise<TObjectData>;
782
+ }> {
783
+ private static readonly _emptyAnchorBounds;
784
+ readonly context: OpenSeadragonContext;
785
+ private _anchor;
786
+ private _model?;
787
+ private _lastSyncState?;
788
+ private _renderedObjects;
789
+ private _anchorTaskPromise;
790
+ private _destroyed;
791
+ /**
792
+ * Creates a new OpenSeadragonRendererBase instance and asynchronously adds its anchor
793
+ *
794
+ * The renderer must not be used before `onInitialized` has been called;
795
+ * `onError` is called instead if adding the anchor failed or was aborted.
796
+ *
797
+ * @param context - The OpenSeadragon context that provides access to the viewer and other shared state
798
+ * @param onInitialized - Called once the anchor has been added to the world
799
+ * @param onError - Called if the anchor could not be added
800
+ * @param options - Optional abort signal and world index at which to insert
801
+ * the anchor, behind the context's world background (i.e. `1` or higher)
802
+ */
803
+ constructor(context: OpenSeadragonContext, onInitialized: () => void, onError: (error: Error) => void, options?: {
804
+ signal?: AbortSignal;
805
+ anchorIndex?: number;
806
+ });
807
+ /**
808
+ * Sets the layers and objects to render
809
+ *
810
+ * The properties that tiled images take directly - the layer and object
811
+ * transforms, visibility and opacity, and whatever else a subclass reads from
812
+ * the current model when updating a tiled image (see
813
+ * {@link getTiledImageOpacity} and {@link resolveTiledImageDataTransfer}) -
814
+ * are applied to the rendered objects right away (see
815
+ * {@link _updateRenderedObject}), and need no synchronization.
816
+ * Every other change - a different set or order of layers or objects, layer
817
+ * memberships, data sources or the configurations that subclasses resolve
818
+ * from - requires a resynchronization, which the caller is expected to
819
+ * trigger whenever {@link needsSynchronization} says so.
820
+ *
821
+ * Does not resize the anchor: a transform change moves the tiled images, so
822
+ * the caller is expected to call {@link updateBounds} afterwards.
823
+ *
824
+ * The layers and objects are cloned, so that what the renderer compares
825
+ * against later - in {@link needsSynchronization}, and in the references of
826
+ * a synchronization - is what it was given, whatever the caller does with its
827
+ * instances afterwards.
828
+ *
829
+ * @param layers - The layers to render
830
+ * @param objects - The objects (images or labels) to render
831
+ */
832
+ setModel(layers: Layer[], objects: TObject[]): void;
833
+ /**
834
+ * Returns whether the rendered objects have to be synchronized with the
835
+ * current model
836
+ *
837
+ * Compares the state that a synchronization depends on (see
838
+ * {@link getSyncState}) against the one the last synchronization was based
839
+ * on, which {@link synchronize} records before its first `await` and forgets
840
+ * again if it fails. Everything else about the model - the properties that
841
+ * tiled images take directly - is fully applied by {@link setModel}.
842
+ */
843
+ needsSynchronization(): boolean;
844
+ /**
845
+ * Synchronizes the viewer's tiled images with the current model
846
+ *
847
+ * Loads all objects assigned to the layers of the model set by
848
+ * {@link setModel}, removes the tiled images that are no longer needed, and
849
+ * creates or updates the remaining ones. Resolves once the tiled images have
850
+ * actually been added to the world, i.e. once the viewer reflects the model
851
+ * state that was read. The model may be set again while the synchronization
852
+ * runs; it reads the model once, so it sees one consistent state, while the
853
+ * properties it applies to the tiled images come from the current model (see
854
+ * {@link _updateRenderedObject}).
855
+ *
856
+ * Objects whose tiled images cannot be created, e.g. because their data
857
+ * provides no tile sources, are logged and skipped, just like objects whose
858
+ * data failed to load (see {@link _loadObjects}). A synchronization that
859
+ * fails or is aborted leaves the model unsynchronized (see
860
+ * {@link needsSynchronization}).
861
+ *
862
+ * @param context - The inputs to synchronize with: an immutable snapshot of
863
+ * the tables and maps that the objects resolve from and the loaders that the
864
+ * renderer needs. It carries inputs only; a renderer that derives state from
865
+ * an object does so in {@link resolveObject}.
866
+ * @param options - Optional abort signal
867
+ * @throws Error if no model has been set (see {@link setModel})
868
+ */
869
+ synchronize(context: TSyncContext, options?: {
870
+ signal?: AbortSignal;
871
+ }): Promise<void>;
872
+ /**
873
+ * Resizes the anchor to the bounding box of all tiled images, and registers it with the context
874
+ *
875
+ * Rendered objects whose tiled images have not been added to the world yet are
876
+ * ignored; they update the anchor themselves upon arrival (see
877
+ * {@link _createRenderedObject}). Resolves once the context's world
878
+ * background covers the bounds, too (see
879
+ * {@link OpenSeadragonContext.setContentBounds}). The bounds are registered
880
+ * after the anchor task rather than within it, so that the anchor task
881
+ * queue, and with it {@link destroy}, never waits for the background, which
882
+ * waits for being drawn. Does nothing once the renderer has been destroyed,
883
+ * as there is no anchor to resize anymore.
884
+ *
885
+ * @param options - Optional abort signal
886
+ */
887
+ updateBounds(options?: {
888
+ signal?: AbortSignal;
889
+ }): Promise<void>;
890
+ /**
891
+ * Destroys the renderer by removing the anchor tiled image and all rendered objects from the OpenSeadragon viewer, and its bounds from the context
892
+ *
893
+ * Rendered objects whose tiled images have not been added to the world yet are
894
+ * only marked for deletion, and are removed as soon as they arrive.
895
+ *
896
+ * The renderer is unusable afterwards: it has no anchor anymore, so
897
+ * {@link updateBounds} does nothing, {@link _cleanRenderedObjects} throws, and
898
+ * tiled images that still arrive are removed right away.
899
+ *
900
+ * The bounds are removed from the context without waiting for the world
901
+ * background to be resized, and a failure to resize it is only logged: the
902
+ * background waits for being drawn, which never happens while the page is
903
+ * hidden, and the teardown of the renderer, and thereby of the context, must
904
+ * not depend on it.
905
+ */
906
+ destroy(): Promise<void>;
907
+ /**
908
+ * Returns the state of the current model that a synchronization depends on
909
+ *
910
+ * Unlike the WebGL renderers, whose draw order is read from the model on
911
+ * every draw, the order of the layers and objects is part of the state: it
912
+ * is the order of the tiled images in the world, which only a
913
+ * synchronization can change (see {@link _cleanRenderedObjects}). See
914
+ * {@link getLayerSyncState} and {@link getObjectSyncState} for what else is.
915
+ *
916
+ * @returns The state, or `undefined` if no model has been set
917
+ */
918
+ protected getSyncState(): object | undefined;
919
+ /**
920
+ * Returns the state of a layer that a synchronization depends on
921
+ *
922
+ * The counterpart of {@link getObjectSyncState} for layers. The point size
923
+ * factor is blanked out as well, as nothing rendered here depends on it, and
924
+ * so is the name.
925
+ *
926
+ * @param layer - The layer to return the state of
927
+ * @returns The layer without the properties that are applied by
928
+ * {@link setModel}, and without the cosmetic ones
929
+ */
930
+ protected getLayerSyncState(layer: Layer): object;
931
+ /**
932
+ * Returns the state of an object that a synchronization depends on
933
+ *
934
+ * Everything but the properties that are applied by {@link setModel}, and
935
+ * but the cosmetic ones, which nothing rendered depends on. Those are blanked
936
+ * out rather than dropped, so that a property added to the model later is
937
+ * part of the state, and thereby requires a resynchronization, unless it is
938
+ * blanked out here as well. Subclasses override this to blank out the
939
+ * properties that they apply from the current model themselves.
940
+ *
941
+ * The result is only ever deep-compared against that of another object, hence
942
+ * the opaque return type.
943
+ *
944
+ * @param object - The object (image or labels) to return the state of
945
+ * @returns The object without the properties that are applied by
946
+ * {@link setModel}, and without the cosmetic ones
947
+ */
948
+ protected getObjectSyncState(object: TObject): object;
949
+ /**
950
+ * Retains what was resolved for the given objects, and discards the rest
951
+ *
952
+ * Called by {@link synchronize} once all objects have loaded and the rendered
953
+ * objects of all others have been deleted, with the objects that are about
954
+ * to be displayed: those assigned to a rendered layer whose data loaded
955
+ * successfully. Does nothing here; subclasses that keep
956
+ * state per object (see {@link resolveObject} and
957
+ * {@link resolveTiledImageDataTransfer}) override this to drop the state of
958
+ * every object that is not among the given ones.
959
+ *
960
+ * @param _objects - The objects (images or labels) about to be displayed
961
+ */
962
+ protected retainObjects(_objects: TObject[]): void;
963
+ /**
964
+ * Resolves what a renderer derives from an object, once its data has loaded
965
+ *
966
+ * Called by {@link _loadObjects} for every object on one of the given layers,
967
+ * concurrently, right after
968
+ * its data has loaded and before its tiled images are created or updated. An
969
+ * object that cannot be resolved is logged, but kept: its tiled images are
970
+ * still created or updated, with whatever the synchronous hooks return for
971
+ * it. Does nothing here; subclasses override this to resolve, from the
972
+ * object, its data and the inputs of the synchronization, whatever their
973
+ * synchronous hooks return later (see {@link resolveTiledImageDataTransfer}),
974
+ * and to keep it for as long as its outcome would not change.
975
+ *
976
+ * @param _object - The object (image or labels) to resolve
977
+ * @param _data - The loaded data of the object
978
+ * @param _context - The inputs of the current synchronization
979
+ * @param _options - Optional abort signal
980
+ * @returns A promise that resolves once the object has been resolved
981
+ */
982
+ protected resolveObject(_object: TObject, _data: TObjectData, _context: TSyncContext, _options?: {
983
+ signal?: AbortSignal;
984
+ }): Promise<void>;
985
+ /**
986
+ * Returns the tile sources for the given object data
987
+ *
988
+ * @param data - The object data (image or labels) for which to retrieve the tile sources
989
+ * @returns The tile sources, one per tiled image of the object. Defaults to
990
+ * the single tile source of the data; renderers of multi-channel data
991
+ * override this.
992
+ */
993
+ protected getTileSources(data: TObjectData): (string | TileSourceConfig | CustomTileSource)[];
994
+ /**
995
+ * Returns whether the channels of the given object data are blended additively
996
+ *
997
+ * The channels of an object that blends additively are composited with
998
+ * OpenSeadragon's "lighter" operation onto an opaque black backdrop below
999
+ * them, so that they add up among themselves while the backdrop hides
1000
+ * whatever is below the object, thereby compositing the object as a whole over
1001
+ * it. Objects that do not blend additively have no backdrop and keep
1002
+ * OpenSeadragon's default composite operation, i.e. each of their channels is
1003
+ * composited over the one below it.
1004
+ *
1005
+ * This only composites correctly onto an opaque canvas: "lighter" adds alpha
1006
+ * as well as color, so onto the transparent canvas that OpenSeadragon clears
1007
+ * to, an object with opacity below one would accumulate alpha from each
1008
+ * channel and fade out to the wrong color, in wrong proportions, instead of
1009
+ * fading out to the background behind the viewer. The context's world
1010
+ * background (see {@link OpenSeadragonContext.setContentBounds}) therefore makes the
1011
+ * canvas opaque wherever objects are.
1012
+ *
1013
+ * @param _data - The object data (image or labels) to check
1014
+ * @returns Whether the object's channels are blended additively. Defaults to `false`.
1015
+ */
1016
+ protected usesAdditiveBlending(_data: TObjectData): boolean;
1017
+ /**
1018
+ * Computes the effective opacity for one of an object's tiled images
1019
+ *
1020
+ * Returns `0` when either the layer or the object is invisible; otherwise
1021
+ * multiplies layer and object opacities. The channel index is ignored here,
1022
+ * i.e. all tiled images of an object share the same opacity; subclasses
1023
+ * override this to additionally apply per-channel visibility and opacity. The
1024
+ * channel index is omitted for an object's backdrop, which carries the opacity
1025
+ * of the object itself.
1026
+ *
1027
+ * @param ref - The object reference for which to compute the opacity
1028
+ * @param _index - The index of the tiled image (e.g. channel), or `null` for the object's backdrop
1029
+ * @returns The effective opacity for the tiled image
1030
+ */
1031
+ protected getTiledImageOpacity(ref: ObjectRef<TObject, TObjectData>, _index: number | null): number;
1032
+ /**
1033
+ * Resolves the data transfer for one of an object's tiled images
1034
+ *
1035
+ * Returns `undefined` here, i.e. the tiles are drawn as they are; subclasses
1036
+ * whose tiles carry values rather than colors override this to map the values
1037
+ * to colors (see {@link OpenSeadragonContext.updateTiledImageDataTransfer}).
1038
+ * As data transfers are compared by identity, the returned object has to stay
1039
+ * the same for as long as its outcome would not change. This hook is
1040
+ * synchronous and receives the object as it currently is in the model:
1041
+ * subclasses either resolve the data transfer here, from the current object
1042
+ * and its data, which needs no synchronization, or, if resolving is
1043
+ * asynchronous, once the object's data has loaded (see
1044
+ * {@link resolveObject}), and only return it here.
1045
+ *
1046
+ * @param _ref - The object reference for which to get the data transfer
1047
+ * @param _index - The index of the tiled image (e.g. channel), or `null` for the object's backdrop
1048
+ * @returns The data transfer to apply, or `undefined` for none. Defaults to
1049
+ * `undefined`.
1050
+ */
1051
+ protected resolveTiledImageDataTransfer(_ref: ObjectRef<TObject, TObjectData>, _index: number | null): DataTransfer_2 | undefined;
1052
+ /**
1053
+ * Concurrently loads and resolves all objects assigned to the layers of the current model
1054
+ *
1055
+ * Each object's data is loaded with the context's `loadObject`, and the object
1056
+ * is then resolved (see {@link resolveObject}). The returned references are
1057
+ * ordered by layer and then by object, which determines the order of the
1058
+ * corresponding tiled images in the world. Objects whose data failed to load
1059
+ * are logged and skipped; objects that could not be resolved are logged, but
1060
+ * kept. The model is read once, before the first `await`, so one
1061
+ * synchronization sees one consistent model state, however often the model
1062
+ * is set while it runs.
1063
+ *
1064
+ * @param context - The inputs of the current synchronization
1065
+ * @param options - Optional abort signal
1066
+ * @returns A promise that resolves to one object reference per successfully loaded object
1067
+ * @throws Error if no model has been set (see {@link setModel})
1068
+ */
1069
+ private _loadObjects;
1070
+ /**
1071
+ * Retains the rendered objects that can be reused for the new object references, and deletes the rest
1072
+ *
1073
+ * A rendered object is matched by the layer and object it references.
1074
+ * Unmatched rendered objects are deleted first, so that removing an object
1075
+ * does not shift the world indices of the objects behind it. A matched
1076
+ * rendered object is reusable if the data source it was loaded for is that of
1077
+ * the reference, and if its backdrop, if any, and all of its tiled images
1078
+ * already sit at the consecutive world indices expected for its position
1079
+ * among the references, counted from the anchor. A partially misplaced object
1080
+ * is not reusable. The other matched rendered objects are deleted as well,
1081
+ * and are expected to be recreated by the caller via
1082
+ * {@link _createRenderedObject}, which is also how the world is reordered.
1083
+ *
1084
+ * The expected indices account for every matched rendered object, reusable or
1085
+ * not, by the world footprint it currently has: a matched object that is
1086
+ * recreated, e.g. because its data source changed, is deleted and inserted at
1087
+ * the same position, with possibly different tiled images, so the objects
1088
+ * behind it keep their indices relative to it and stay reusable. Only the
1089
+ * backdrop and tiled images assigned to it count, i.e. none for an object
1090
+ * whose tiled images could not be added, which is thereby retried without
1091
+ * recreating the objects behind it. The tiled images that an earlier
1092
+ * synchronization is still adding are waited for first, so that each
1093
+ * rendered object is either fully in the world or not at all. This does not
1094
+ * delay the additions of this synchronization, which are queued behind them
1095
+ * anyway (see {@link OpenSeadragonContext.addTiledImage}).
1096
+ *
1097
+ * @param newRefs - The new object references, in the intended world order
1098
+ * @param options - Optional abort signal
1099
+ * @returns A map of new object references to their reusable rendered objects
1100
+ * @throws Error if the renderer has no anchor, i.e. it is not initialized or
1101
+ * already destroyed
1102
+ */
1103
+ private _cleanRenderedObjects;
1104
+ /**
1105
+ * Creates a new rendered object for the given object reference and adds one TiledImage per channel, preceded by a backdrop where required, to the world
1106
+ *
1107
+ * The TiledImages are inserted at consecutive indices, starting `offset` places
1108
+ * after the anchor, which establishes the world layout that
1109
+ * {@link _cleanRenderedObjects} expects. `offset` therefore counts TiledImages,
1110
+ * not objects, and callers have to advance it by
1111
+ * {@link RenderedObject.tileSourceCount} plus the object's backdrop, if it has
1112
+ * one. The indices are resolved once each addition is executed, as the anchor
1113
+ * may have been replaced, and world indices may have shifted, while it was
1114
+ * enqueued.
1115
+ *
1116
+ * The tile sources are opened here, rather than by the additions themselves,
1117
+ * so that the backdrop can be sized like the object's content, which is only
1118
+ * known once one of them has been opened. The additions are all requested
1119
+ * before this function returns, and in world order, so that the TiledImages of
1120
+ * the object that the caller creates next end up behind them.
1121
+ *
1122
+ * Returns before the TiledImages exist: they are added asynchronously and only
1123
+ * then assigned to the rendered object, transformed, and included in the anchor
1124
+ * bounds, which is when {@link RenderedObject.tiledImagesPromise} resolves. The
1125
+ * backdrop and TiledImages are removed again immediately after they were added
1126
+ * if the rendered object is deleted or the operation is aborted in the
1127
+ * meantime, or if any of them could not be added at all - a partially added
1128
+ * object would shift the world indices of every object after it. For the same
1129
+ * reason, a tile source that fails to open is replaced by a transparent
1130
+ * placeholder rather than skipped: the indices of the objects created after
1131
+ * this one are resolved against the full footprint of this one, so it has to
1132
+ * take up all of its indices until it is removed again. If the context
1133
+ * is destroyed, nothing is done at all, as the viewer tears down its world
1134
+ * itself.
1135
+ *
1136
+ * @param offset - The number of TiledImages between the anchor and the object's first new TiledImage
1137
+ * @param newRef - The object reference for which to create a rendered object
1138
+ * @param options - Optional abort signal
1139
+ * @returns The newly created rendered object, which does not have TiledImages yet
1140
+ * @throws Error if the object data provides no tile sources
1141
+ */
1142
+ private _createRenderedObject;
1143
+ /**
1144
+ * Stores a reference on the rendered object and applies the current model to its backdrop and TiledImages
1145
+ *
1146
+ * The reference holds the layer and object as they were when it was loaded,
1147
+ * and is what the next synchronization matches against (see
1148
+ * {@link _cleanRenderedObjects}). The transform, visibility and opacity
1149
+ * applied to the TiledImages are not read from it, but from the current
1150
+ * model, as they are the properties {@link setModel} applies without a
1151
+ * synchronization: read from the reference, a call from {@link setModel}
1152
+ * would re-apply the values of the last synchronization, and a call from a
1153
+ * synchronization that was in flight while the model changed would overwrite
1154
+ * what {@link setModel} applied.
1155
+ *
1156
+ * Nothing is applied if the layer or object has left the model, the object
1157
+ * has moved to another layer, or its data source has changed: each of these
1158
+ * requires a resynchronization, which drops or recreates the rendered object.
1159
+ * The last one also protects the reference's data, which its provider may
1160
+ * release once the data source it was loaded for is gone from the model.
1161
+ *
1162
+ * The opacity is computed per TiledImage via {@link getTiledImageOpacity}, so
1163
+ * that subclasses can vary it by channel; all other properties are shared by
1164
+ * all TiledImages of an object, and by its backdrop. The backdrop is opaque
1165
+ * where the object is, so it gets {@link getTiledImageOpacity} without a
1166
+ * channel index. A rendered object that is `pendingBackground` gets
1167
+ * everything but its opacity, which stays at zero; its tiles are loaded
1168
+ * nonetheless, unless it is invisible anyway, so that they are ready by the
1169
+ * time it is revealed.
1170
+ *
1171
+ * @param renderedObject - The rendered object to update
1172
+ * @param newRef - The reference to store, addressing the same layer, object
1173
+ * and data source as the current one; defaults to the current one
1174
+ * @throws Error if the TiledImages have not been created yet
1175
+ */
1176
+ private _updateRenderedObject;
1177
+ /**
1178
+ * Deletes the rendered object by removing its backdrop and TiledImages from the OpenSeadragon viewer, or marking it for deletion if the TiledImages have not yet been created
1179
+ *
1180
+ * The removals are queued by the context (see
1181
+ * {@link OpenSeadragonContext.removeTiledImage}) and applied before any tiled
1182
+ * image requested after them, so a caller that deletes before it creates still
1183
+ * gets the world indices it expects.
1184
+ *
1185
+ * Deleting a rendered object does not remove it from {@link _renderedObjects}.
1186
+ * An object that is `pendingBackground` is no longer, so that it is not
1187
+ * revealed once the bounds update it waits for settles (see
1188
+ * {@link _updateBoundsAndReveal}), which would update TiledImages that are
1189
+ * no longer in the world.
1190
+ *
1191
+ * @param renderedObject - The rendered object to delete
1192
+ * @returns A promise that resolves once its backdrop and all of its TiledImages have been removed
1193
+ */
1194
+ private _deleteRenderedObject;
1195
+ /**
1196
+ * Applies the transform, opacity and data transfer of an object reference to a single TiledImage
1197
+ *
1198
+ * Only properties whose value actually changed are written, as each write
1199
+ * triggers a redraw. The data transfer is applied to the TiledImage's tiles
1200
+ * (see {@link OpenSeadragonContext.updateTiledImageDataTransfer}).
1201
+ *
1202
+ * @param tiledImage - The TiledImage to update
1203
+ * @param ref - The object reference whose transform to apply
1204
+ * @param index - The index of the tiled image (e.g. channel), or `null` for the object's backdrop
1205
+ * @param options - Whether to keep the TiledImage hidden, i.e. at opacity
1206
+ * `0`, while preloading its tiles if it would be visible otherwise
1207
+ */
1208
+ private _updateTiledImage;
1209
+ /**
1210
+ * Updates the bounds (see {@link updateBounds}), and then reveals the given rendered objects that are `pendingBackground`
1211
+ *
1212
+ * The objects are revealed once the context's world background covers them,
1213
+ * and also if that failed for any other reason than an abort: an object
1214
+ * shown on an uncovered canvas, where its channels may be composited wrongly
1215
+ * (see {@link usesAdditiveBlending}), beats one that is not shown at all. An
1216
+ * aborted update leaves them hidden, for the synchronization that follows to
1217
+ * reveal them (see {@link synchronize}).
1218
+ *
1219
+ * @param renderedObjects - The rendered objects to reveal
1220
+ * @param options - Optional abort signal
1221
+ * @returns A promise that resolves once the bounds have been updated
1222
+ */
1223
+ private _updateBoundsAndReveal;
1224
+ /**
1225
+ * Resizes the anchor (see the class documentation), or creates it
1226
+ *
1227
+ * If the anchor already has `newBounds` (see
1228
+ * {@link OpenSeadragonUtils.hasBounds}), it is kept. Otherwise, a new anchor
1229
+ * is created at `anchorIndex` (defaulting to the index of the current
1230
+ * anchor, or appended if neither is specified) and the current anchor is
1231
+ * removed. Where possible, OpenSeadragon replaces the current anchor as part
1232
+ * of the addition, so that the new anchor takes its place without leaving a
1233
+ * gap. Replacing the anchor cannot be aborted once the new anchor has been
1234
+ * created, as that would leave the renderer without an anchor.
1235
+ *
1236
+ * The viewport is not fitted here: it follows the bounds of the world as a
1237
+ * whole, for as long as the renderers own it (see
1238
+ * {@link OpenSeadragonContext.resetViewport}). Reads and writes
1239
+ * {@link _anchor}, so it must only be called from within an anchor task (see
1240
+ * {@link _enqueueAnchorTask}).
1241
+ *
1242
+ * @param newBounds - The new bounds of the anchor, in world coordinates
1243
+ * @param options - Optional abort signal, and index at which to insert the
1244
+ * new anchor
1245
+ * @returns A promise that resolves once the anchor has the new bounds
1246
+ */
1247
+ private _resizeAnchor;
1248
+ /**
1249
+ * Appends a task to the anchor task queue
1250
+ *
1251
+ * Tasks are run one at a time, in call order, and a failing task does not
1252
+ * prevent subsequent tasks from running. Every task that reads or writes
1253
+ * {@link _anchor} has to be enqueued here: concurrent tasks would each replace
1254
+ * the anchor they captured, leaving the anchors created in between orphaned in
1255
+ * the world, which shifts all subsequent world indices and thereby invalidates
1256
+ * the layout expected by {@link _cleanRenderedObjects}.
1257
+ *
1258
+ * The queue is per renderer, and separate from the context's addition queue,
1259
+ * which anchor tasks enqueue onto themselves.
1260
+ *
1261
+ * @param task - Task to run once all previously enqueued tasks have settled
1262
+ * @returns A promise that resolves with the task's result
1263
+ */
1264
+ private _enqueueAnchorTask;
1265
+ }
1266
+
1267
+ /**
1268
+ * A reference to a points object, its layer, and its loaded data
1269
+ */
1270
+ declare type PointsRef = ObjectRef_2<Points, PointsData>;
1271
+
1272
+ /**
1273
+ * What a preparation of a points object uploads
1274
+ *
1275
+ * See {@link WebGLPointsRenderer.prepareRenderedObject}.
1276
+ */
1277
+ declare type PreparedPoints = {
1278
+ objectBounds: Rect;
1279
+ maskedGeometry: PointsGeometry | undefined;
1280
+ packedPointMarkers: Uint8Array | number | undefined;
1281
+ packedPointSizes: Float32Array | number | undefined;
1282
+ packedPointColors: Uint32Array | number | undefined;
1283
+ renderConfigSnapshot: RenderedPoints["renderConfigSnapshot"];
1284
+ };
1285
+
1286
+ /**
1287
+ * What a preparation of a shapes object uploads
1288
+ *
1289
+ * See {@link WebGLShapesRenderer.prepareRenderedObject}.
1290
+ */
1291
+ declare type PreparedShapes = {
1292
+ objectBounds: Rect;
1293
+ edgesPerScanline: number;
1294
+ binWidthFactor: number;
1295
+ shapePadding: number;
1296
+ numScanlines: number;
1297
+ numBins: number;
1298
+ scanlineBuffer: Uint32Array | undefined;
1299
+ packedShapeFillColors: Uint32Array | undefined;
1300
+ packedShapeStrokeColors: Uint32Array | undefined;
1301
+ renderConfigSnapshot: RenderedShapes["renderConfigSnapshot"];
1302
+ };
1303
+
1304
+ /**
1305
+ * The rendered state of one {@link ObjectRef}
1306
+ *
1307
+ * Extended by the renderers with the GPU resources they own, and with a
1308
+ * snapshot of the object properties those were built from, which their change
1309
+ * detection compares against. Rendered objects are mutated in place across
1310
+ * synchronizations:
1311
+ * {@link WebGLRendererBase.matchOrDestroyRenderedObjects} replaces the
1312
+ * reference of a matched object, and the renderers replace the bounds, the
1313
+ * snapshot and the GPU resources of an object as they are rebuilt.
1314
+ */
1315
+ declare type RenderedObjectBase<TObject extends Points | Shapes, TObjectData extends PointsData | ShapesData> = {
1316
+ /** The reference the object was last matched to, holding what its GPU resources were resolved from */
1317
+ ref: ObjectRef_2<TObject, TObjectData>;
1318
+ /** The bounds of the object's items, in data coordinates */
1319
+ objectBounds: Rect;
1320
+ };
1321
+
1322
+ /**
1323
+ * GPU state for a single points object
1324
+ *
1325
+ * Holds the vertex array, the coordinate buffers it is configured with, and
1326
+ * the per-point attributes, each backed by a buffer holding one value per
1327
+ * point or by one constant value for all points (see
1328
+ * {@link WebGLPointsRenderer._backAttribute}), plus a snapshot of the model
1329
+ * values they were loaded from, which the change predicates compare against
1330
+ * (see {@link WebGLPointsRenderer._createRenderConfigSnapshot}). Layer- and
1331
+ * object-level properties are read from the current model when drawing (see
1332
+ * {@link WebGLRendererBase.getRenderPasses}), and are not part of the snapshot.
1333
+ */
1334
+ declare type RenderedPoints = RenderedObjectBase<Points, PointsData> & {
1335
+ vao: WebGLVertexArrayObject;
1336
+ buffers: {
1337
+ x: WebGLBuffer;
1338
+ y: WebGLBuffer;
1339
+ };
1340
+ attributes: {
1341
+ marker: WebGLBuffer | number;
1342
+ size: WebGLBuffer | number;
1343
+ color: WebGLBuffer | number;
1344
+ };
1345
+ renderConfigSnapshot: Pick<Points, "pointMarker" | "pointSize" | "pointColor" | "pointVisibility" | "pointOpacity"> & {
1346
+ pointMarkerMap: GroupValueMap<Marker> | undefined;
1347
+ pointSizeMap: GroupValueMap<number> | undefined;
1348
+ pointColorMap: GroupValueMap<Color> | undefined;
1349
+ pointVisibilityMap: GroupValueMap<boolean> | undefined;
1350
+ pointOpacityMap: GroupValueMap<number> | undefined;
1351
+ };
1352
+ };
1353
+
1354
+ /**
1355
+ * GPU state for a single shapes object
1356
+ *
1357
+ * Holds the texture handles for scanline data, fill colors and stroke colors,
1358
+ * plus a snapshot of the model values they were built from, which the change
1359
+ * predicates compare against (see
1360
+ * {@link WebGLShapesRenderer._createRenderConfigSnapshot}). Layer- and
1361
+ * object-level properties are read from the current model when drawing (see
1362
+ * {@link WebGLRendererBase.getRenderPasses}), and are not part of the
1363
+ * snapshot. The grid render options are the ones the scanline data texture
1364
+ * was rasterized for (see
1365
+ * {@link WebGLShapesRenderer.getRenderOptionsSyncState}), and the numbers of
1366
+ * scanlines and bins are the ones it was rasterized into, which are also the
1367
+ * ones the object is drawn with.
1368
+ */
1369
+ declare type RenderedShapes = RenderedObjectBase<Shapes, ShapesData> & {
1370
+ edgesPerScanline: number;
1371
+ binWidthFactor: number;
1372
+ shapePadding: number;
1373
+ numScanlines: number;
1374
+ numBins: number;
1375
+ scanlineDataTexture: WebGLTexture;
1376
+ shapeFillColorsTexture: WebGLTexture;
1377
+ shapeStrokeColorsTexture: WebGLTexture;
1378
+ renderConfigSnapshot: Pick<Shapes, "shapeVisibility" | "shapeOpacity" | "shapeFillColor" | "shapeFillVisibility" | "shapeFillOpacity" | "shapeStrokeColor" | "shapeStrokeVisibility" | "shapeStrokeOpacity"> & {
1379
+ shapeVisibilityMap: GroupValueMap<boolean> | undefined;
1380
+ shapeOpacityMap: GroupValueMap<number> | undefined;
1381
+ shapeFillColorMap: GroupValueMap<Color> | undefined;
1382
+ shapeFillVisibilityMap: GroupValueMap<boolean> | undefined;
1383
+ shapeFillOpacityMap: GroupValueMap<number> | undefined;
1384
+ shapeStrokeColorMap: GroupValueMap<Color> | undefined;
1385
+ shapeStrokeVisibilityMap: GroupValueMap<boolean> | undefined;
1386
+ shapeStrokeOpacityMap: GroupValueMap<number> | undefined;
1387
+ };
1388
+ };
1389
+
1390
+ /**
1391
+ * A reference to a shapes object, its layer, and its loaded data
1392
+ */
1393
+ declare type ShapesRef = ObjectRef_2<Shapes, ShapesData>;
1394
+
1395
+ /**
1396
+ * Controller for managing the drawing of SVG shapes
1397
+ */
1398
+ export declare class SVGController {
1399
+ readonly container: SVGSVGElement;
1400
+ readonly transformNode: SVGGElement;
1401
+ readonly shapeCompleteHandler?: (shape: MultiPolygon) => void;
1402
+ private static readonly _previewFillColor;
1403
+ private static readonly _previewStrokeColor;
1404
+ private static readonly _previewStrokeWidthFactor;
1405
+ private static readonly _minShapeSizeFactor;
1406
+ private static readonly _closeShapeThresholdFactor;
1407
+ private static readonly _vertexMarkerRadiusFactor;
1408
+ private _containerSize;
1409
+ private _viewport;
1410
+ private _interactionMode?;
1411
+ private _rectangleDrawingState;
1412
+ private _polygonDrawingState;
1413
+ private _freehandDrawingState;
1414
+ /** Creates a positioned, full-size `<svg>` element for the SVG overlay */
1415
+ static createContainer(): SVGSVGElement;
1416
+ /**
1417
+ * Creates the transform node inside the given container and registers the
1418
+ * shape drawing event handlers
1419
+ *
1420
+ * The viewport starts out as the unit square; {@link setViewport} is the only
1421
+ * way to change it.
1422
+ *
1423
+ * @param container - The `<svg>` element to draw on (typically created by {@link createContainer})
1424
+ * @param options - Optional shape drawing event handlers
1425
+ */
1426
+ constructor(container: SVGSVGElement, options?: {
1427
+ onShapeComplete?: (shape: MultiPolygon) => void;
1428
+ });
1429
+ /**
1430
+ * Updates the world-space viewport rectangle
1431
+ *
1432
+ * @param viewport - New viewport bounds in world coordinates
1433
+ * @returns `true` if the viewport actually changed, `false` otherwise
1434
+ */
1435
+ setViewport(viewport: Rect): boolean;
1436
+ /**
1437
+ * Updates the interaction mode
1438
+ *
1439
+ * @param newInteractionMode - New interaction mode
1440
+ */
1441
+ setInteractionMode(newInteractionMode: InteractionMode): void;
1442
+ /**
1443
+ * Resizes the SVG container to match the given screen-space dimensions,
1444
+ * accounting for `devicePixelRatio`
1445
+ *
1446
+ * @param newContainerSize - Desired container size in screen-space pixels
1447
+ * @returns `true` if the container size actually changed, `false` otherwise
1448
+ */
1449
+ resizeContainer(newContainerSize: Dims): boolean;
1450
+ destroy(): void;
1451
+ private _registerEventHandlers;
1452
+ private _unregisterEventHandlers;
1453
+ private _handlePointerDown;
1454
+ private _handleRectanglePointerDown;
1455
+ private _handleRectanglePointerMove;
1456
+ private _handleRectanglePointerUp;
1457
+ private _handlePolygonPointerDown;
1458
+ private _handlePolygonPointerMove;
1459
+ private _handlePolygonKeyDown;
1460
+ private _handlePolygonPointerCancel;
1461
+ private _handleFreehandPointerDown;
1462
+ private _handleFreehandPointerMove;
1463
+ private _handleFreehandPointerUp;
1464
+ private _handleFreehandPointerCancel;
1465
+ private _cancelFreehand;
1466
+ private _createPreviewRect;
1467
+ private _updatePreviewRect;
1468
+ private _createRectangleMultiPolygon;
1469
+ private _hasMinimumSize;
1470
+ private _updatePolygonPreviewPolyline;
1471
+ private _updateFirstVertexMarker;
1472
+ private _completePolygon;
1473
+ private _cancelPolygon;
1474
+ private _createPreviewPolyline;
1475
+ private _createVertexMarker;
1476
+ private _setMarkerHighlighted;
1477
+ private _createMultiPolygon;
1478
+ private _isNearPoint;
1479
+ private _screenToWorld;
1480
+ /**
1481
+ * Updates the world-to-viewport transform based on the current container size
1482
+ * (in screen coordinates) and the current viewport (in world coordinates)
1483
+ */
1484
+ private _updateTransformNode;
1485
+ }
1486
+
1487
+ /**
1488
+ * A wrapper around a WebGL2RenderingContext that provides utility methods for
1489
+ * creating shaders, programs, buffers, and textures
1490
+ */
1491
+ export declare class WebGLContext {
1492
+ private static readonly _maxCanvasSize;
1493
+ readonly gl: WebGL2RenderingContext;
1494
+ /** The largest width and height of a texture that the GPU supports, in texels */
1495
+ readonly maxTextureSize: number;
1496
+ /**
1497
+ * Creates a new WebGLContext for the given canvas element
1498
+ *
1499
+ * @param canvas - The HTML canvas element to use for rendering
1500
+ * @throws Error if the browser does not support WebGL 2.0
1501
+ */
1502
+ constructor(canvas: HTMLCanvasElement);
1503
+ /**
1504
+ * Resizes the canvas to match the given screen-space dimensions,
1505
+ * accounting for `devicePixelRatio` and clamping to {@link _maxCanvasSize}
1506
+ *
1507
+ * @param canvas - The HTML canvas element to resize
1508
+ * @param newCanvasSize - Desired canvas size in screen-space pixels
1509
+ * @returns `true` if the canvas size actually changed, `false` otherwise
1510
+ */
1511
+ resizeCanvas(canvas: HTMLCanvasElement, newCanvasSize: Dims): boolean;
1512
+ /**
1513
+ * Clears the color buffer with transparent black
1514
+ */
1515
+ clear(): void;
1516
+ /**
1517
+ * Compiles vertex and fragment shaders, links them into a program, and
1518
+ * returns the linked program
1519
+ *
1520
+ * The individual shaders are flagged for deletion after linking.
1521
+ *
1522
+ * @param vertexShaderSource - GLSL source for the vertex shader
1523
+ * @param fragmentShaderSource - GLSL source for the fragment shader
1524
+ * @throws Error if shader compilation or program linking fails
1525
+ */
1526
+ createProgram(vertexShaderSource: string, fragmentShaderSource: string): WebGLProgram;
1527
+ /**
1528
+ * Returns the location of a uniform variable in a shader program
1529
+ *
1530
+ * @param program - The shader program
1531
+ * @param name - The uniform name as declared in the shader
1532
+ * @throws Error if the uniform is not found
1533
+ */
1534
+ getUniformLocation(program: WebGLProgram, name: string): WebGLUniformLocation;
1535
+ /**
1536
+ * Creates a new vertex array object (VAO)
1537
+ *
1538
+ * @throws Error if VAO creation fails
1539
+ */
1540
+ createVertexArray(): WebGLVertexArrayObject;
1541
+ /**
1542
+ * Binds a buffer to a vertex attribute as a floating-point attribute
1543
+ *
1544
+ * @param target - Buffer binding target
1545
+ * @param buffer - The buffer containing attribute data
1546
+ * @param index - Attribute location index
1547
+ * @param size - Number of components per vertex attribute
1548
+ * @param type - Data type (e.g. `gl.FLOAT`)
1549
+ * @param options - Optional normalized, stride, offset, and divisor settings
1550
+ */
1551
+ configureVertexFloatAttribute(target: GLenum, buffer: WebGLBuffer, index: number, size: number, type: GLenum, options?: {
1552
+ normalized?: boolean;
1553
+ stride?: number;
1554
+ offset?: number;
1555
+ divisor?: number;
1556
+ }): void;
1557
+ /**
1558
+ * Binds a buffer to a vertex attribute as an integer attribute
1559
+ *
1560
+ * @param target - Buffer binding target
1561
+ * @param buffer - The buffer containing attribute data
1562
+ * @param index - Attribute location index
1563
+ * @param size - Number of components per vertex attribute
1564
+ * @param type - Data type (e.g. `gl.UNSIGNED_INT`)
1565
+ * @param options - Optional stride, offset, and divisor settings
1566
+ */
1567
+ configureVertexIntAttribute(target: GLenum, buffer: WebGLBuffer, index: number, size: number, type: GLenum, options?: {
1568
+ stride?: number;
1569
+ offset?: number;
1570
+ divisor?: number;
1571
+ }): void;
1572
+ /**
1573
+ * Creates an immutable 2D data texture with nearest-neighbor filtering
1574
+ * and clamp-to-edge wrapping
1575
+ *
1576
+ * @param internalformat - Internal texture format (e.g. `gl.RGBA32F`)
1577
+ * @param width - Texture width in texels
1578
+ * @param height - Texture height in texels
1579
+ * @param format - Pixel data format (e.g. `gl.RGBA`)
1580
+ * @param type - Pixel data type (e.g. `gl.FLOAT`)
1581
+ * @param data - Optional initial pixel data
1582
+ * @throws Error if texture creation fails
1583
+ */
1584
+ createDataTexture(internalformat: GLenum, width: number, height: number, format: GLenum, type: GLenum, data?: TypedArray): WebGLTexture;
1585
+ /**
1586
+ * Uploads new pixel data into an existing immutable 2D data texture
1587
+ *
1588
+ * @param texture - The target texture
1589
+ * @param width - Texture width in texels
1590
+ * @param height - Texture height in texels
1591
+ * @param format - Pixel data format (e.g. `gl.RGBA`)
1592
+ * @param type - Pixel data type (e.g. `gl.FLOAT`)
1593
+ * @param data - The pixel data to upload
1594
+ */
1595
+ loadDataTexture(texture: WebGLTexture, width: number, height: number, format: GLenum, type: GLenum, data: TypedArray): void;
1596
+ /**
1597
+ * Loads an image from a URL and creates a WebGL texture from it
1598
+ *
1599
+ * If the image fails to load, or the operation is aborted, the pending image load is
1600
+ * cancelled and the texture is deleted again before rejecting.
1601
+ *
1602
+ * @param url - The image URL
1603
+ * @param options - Optional mipmap generation flag and abort signal
1604
+ * @throws Error if texture creation fails, the image fails to load, or the
1605
+ * operation was aborted
1606
+ */
1607
+ loadImageTextureFromUrl(url: string, options?: {
1608
+ signal?: AbortSignal;
1609
+ mipmap?: boolean;
1610
+ }): Promise<WebGLTexture>;
1611
+ /**
1612
+ * Creates a new WebGL buffer
1613
+ *
1614
+ * @throws Error if buffer creation fails
1615
+ */
1616
+ createBuffer(): WebGLBuffer;
1617
+ /**
1618
+ * Allocates (or re-allocates) storage for a buffer and fills it with the
1619
+ * given data, discarding previous contents
1620
+ *
1621
+ * @param target - Buffer binding target (e.g. `gl.ARRAY_BUFFER`)
1622
+ * @param buffer - The buffer to allocate
1623
+ * @param data - The data to fill the buffer with; sets its size
1624
+ * @param usage - Usage hint (e.g. `gl.STATIC_DRAW`)
1625
+ */
1626
+ allocateBuffer(target: GLenum, buffer: WebGLBuffer, data: Exclude<TypedArray, Float64Array>, usage: GLenum): void;
1627
+ /**
1628
+ * Uploads typed array data into a region of an existing buffer
1629
+ *
1630
+ * @param target - Buffer binding target
1631
+ * @param buffer - The target buffer
1632
+ * @param data - The data to upload
1633
+ * @param options - Optional element offset within the buffer
1634
+ */
1635
+ loadBuffer(target: GLenum, buffer: WebGLBuffer, data: Exclude<TypedArray, Float64Array>, options?: {
1636
+ offset?: number;
1637
+ }): void;
1638
+ /**
1639
+ * Enables premultiplied-alpha blending (Porter-Duff "over" operator)
1640
+ */
1641
+ enableAlphaBlending(): void;
1642
+ /**
1643
+ * Disables blending and restores the default blend state
1644
+ */
1645
+ disableAlphaBlending(): void;
1646
+ /**
1647
+ * Destroys the WebGLContext by forcing the underlying WebGL context to be
1648
+ * lost, releasing its GPU resources immediately.
1649
+ *
1650
+ * Browsers cap the number of concurrently live WebGL contexts, so a context
1651
+ * that is never released (e.g. across React StrictMode / HMR remounts)
1652
+ * eventually prevents new contexts from being created. Callers are expected
1653
+ * to have already destroyed any resources (programs, buffers, textures, VAOs)
1654
+ * they created through this context.
1655
+ */
1656
+ destroy(): void;
1657
+ }
1658
+
1659
+ /**
1660
+ * WebGL renderer for two-dimensional point clouds
1661
+ *
1662
+ * Manages a shader program, a marker atlas texture, and per-object GPU
1663
+ * buffers. Points are rendered as `gl.POINTS` using per-vertex attributes (x,
1664
+ * y, size, color, marker), one draw call per object.
1665
+ *
1666
+ * Every object owns its vertex array and attribute buffers. Synchronizing
1667
+ * compares the current model against the snapshot those buffers were loaded
1668
+ * from, and re-uploads only the attributes whose inputs changed. An attribute
1669
+ * whose configuration is a constant has no buffer at all: its value is
1670
+ * supplied as a generic vertex attribute when drawing, which saves the buffer,
1671
+ * its upload and the resolve (see {@link _backAttribute}).
1672
+ * Layer- and object-level properties (transforms, point size factors,
1673
+ * visibility and opacity) are shader uniforms, so changing them never touches
1674
+ * the buffers, and never requires a synchronization (see
1675
+ * {@link WebGLRendererBase.setModel}).
1676
+ */
1677
+ export declare class WebGLPointsRenderer extends WebGLRendererBase<Points, PointsData, WebGLPointsSyncContext, PreparedPoints, RenderedPoints> {
1678
+ private static readonly _attribLocations;
1679
+ private static readonly _textureUnits;
1680
+ renderOptions: WebGLPointsRenderOptions;
1681
+ private readonly _program;
1682
+ private readonly _uniformLocations;
1683
+ private _markerAtlasTexture;
1684
+ private _destroyed;
1685
+ /**
1686
+ * Creates the shader program and retrieves uniform locations
1687
+ *
1688
+ * The marker atlas texture is loaded asynchronously, so the renderer must not
1689
+ * be drawn before `onInitialized` has been called; `onError` is called instead
1690
+ * if loading it failed or was aborted, or if the renderer was destroyed
1691
+ * meanwhile, in which case the texture is released right away.
1692
+ *
1693
+ * @param context - The WebGL context to use for rendering
1694
+ * @param onInitialized - Called once the marker atlas texture has been loaded
1695
+ * @param onError - Called if the marker atlas texture could not be loaded
1696
+ * @param options - Optional abort signal
1697
+ */
1698
+ constructor(context: WebGLContext, onInitialized: () => void, onError: (error: Error) => void, options?: {
1699
+ signal?: AbortSignal;
1700
+ });
1701
+ /**
1702
+ * Issues the WebGL draw calls for all synchronized points
1703
+ *
1704
+ * Binds the shader program, configures the global uniforms (transform,
1705
+ * viewport, canvas size in device pixels), binds the marker atlas texture,
1706
+ * and then draws every object in its own `gl.POINTS` call with alpha
1707
+ * blending, with its data → world matrix, point size factor and opacity
1708
+ * factor as uniforms, computed from the current model (see
1709
+ * {@link getRenderPasses}), and with the constants of its per-point
1710
+ * attributes as generic vertex attributes (see {@link _backAttribute}).
1711
+ * Objects whose layer or object is invisible are skipped.
1712
+ *
1713
+ * @throws Error if the renderer has not been initialized
1714
+ */
1715
+ draw(): void;
1716
+ /**
1717
+ * Releases the shader program, the marker atlas texture, and all per-object
1718
+ * GPU resources
1719
+ *
1720
+ * A marker atlas texture that is still loading is released once it has
1721
+ * loaded (see the constructor).
1722
+ */
1723
+ destroy(): void;
1724
+ /**
1725
+ * Returns the state of a points object that a synchronization depends on
1726
+ *
1727
+ * Blanks out the object-level point size factor, and the units of the point
1728
+ * size configuration, on top of what the base class blanks out: the sizes are
1729
+ * uploaded without their unit, which is applied as part of the point size
1730
+ * factor uniform instead (see {@link _computePointSizeFactor}).
1731
+ *
1732
+ * @param points - The points object to return the state of
1733
+ * @returns The points object without the properties that are applied when drawing
1734
+ */
1735
+ protected getObjectSyncState(points: Points): object;
1736
+ /**
1737
+ * Prepares everything that has to be uploaded for an object
1738
+ *
1739
+ * Decides what the object's buffers need - the geometry for a new object,
1740
+ * and the markers, sizes and colors whose configurations or referenced maps
1741
+ * changed (see {@link _createRenderConfigSnapshot}) - requests all of it
1742
+ * before the first `await`, and then computes the bounds and folds the
1743
+ * resolved visibilities and opacities into the colors. An attribute whose
1744
+ * configuration is a constant is not resolved per point: it is prepared as
1745
+ * the one packed value all points share (see {@link _backAttribute}).
1746
+ *
1747
+ * See {@link WebGLRendererBase.prepareRenderedObject} for when this runs.
1748
+ *
1749
+ * @param newRef - The object to prepare
1750
+ * @param renderedPoints - The object's current GPU state, if it is reused
1751
+ * @param syncContext - The inputs of the current synchronization
1752
+ * @param options - Optional abort signal
1753
+ * @returns The snapshot the decisions were based on, the masked geometry
1754
+ * (new objects only), the bounds, and the attributes that have to be
1755
+ * uploaded, each resolved per point or as a constant
1756
+ */
1757
+ protected prepareRenderedObject(newRef: PointsRef, renderedPoints: RenderedPoints | undefined, syncContext: WebGLPointsSyncContext, options?: {
1758
+ signal?: AbortSignal;
1759
+ }): Promise<PreparedPoints>;
1760
+ /**
1761
+ * Creates the vertex array and attributes of a new object
1762
+ *
1763
+ * @param newRef - The object
1764
+ * @param prepared - Its preparation, which holds every attribute
1765
+ * @returns The rendered object
1766
+ */
1767
+ protected createRenderedObject(newRef: PointsRef, prepared: PreparedPoints): RenderedPoints;
1768
+ /**
1769
+ * Backs the attributes of an object that were resolved again
1770
+ *
1771
+ * The snapshot is adopted last, so that an update that throws is retried by
1772
+ * the next synchronization.
1773
+ *
1774
+ * @param renderedPoints - The rendered object to update in place
1775
+ * @param prepared - Its preparation, holding the attributes that changed
1776
+ * @returns Whether any attribute was backed again
1777
+ */
1778
+ protected updateRenderedObject(renderedPoints: RenderedPoints, prepared: PreparedPoints): boolean;
1779
+ /**
1780
+ * Deletes the vertex array and all attribute buffers owned by a single
1781
+ * rendered object
1782
+ *
1783
+ * @param renderedPoints - The rendered object whose GPU resources to delete
1784
+ */
1785
+ protected destroyRenderedObject(renderedPoints: RenderedPoints): void;
1786
+ /**
1787
+ * Creates the vertex array of an object, configured with its coordinate
1788
+ * buffers and per-point attributes
1789
+ *
1790
+ * The coordinates always go into buffers; the other attributes go into
1791
+ * buffers or are constants, see {@link _backAttribute}.
1792
+ *
1793
+ * @param geometry - X and Y coordinates of the points, in data coordinates
1794
+ * @param packedPointMarkers - The marker index of every point, or of all points
1795
+ * @param packedPointSizes - The size of every point, or of all points
1796
+ * @param packedPointColors - The packed RGBA color of every point, or of all points
1797
+ * @returns The vertex array, the coordinate buffers and the per-point
1798
+ * attributes it is configured with
1799
+ */
1800
+ private _createVertexArray;
1801
+ /**
1802
+ * Brings a per-point attribute of an object up to date with its prepared
1803
+ * values, and returns what the attribute is now backed by
1804
+ *
1805
+ * A per-point attribute is backed either by a buffer holding one value per
1806
+ * point, or, if its configuration is a constant, by nothing: the vertex
1807
+ * attribute array is disabled in the vertex array, and the constant is
1808
+ * supplied as a generic vertex attribute when drawing (see {@link draw}).
1809
+ * Per-point values refill an existing buffer in place, or allocate one and
1810
+ * enable the attribute array if the attribute was constant before; a constant
1811
+ * releases an existing buffer and disables the attribute array. The buffer is
1812
+ * released with the vertex array bound, as that is the only way a deleted
1813
+ * buffer is detached from its attribute pointer; otherwise the vertex array
1814
+ * would keep it alive.
1815
+ *
1816
+ * @param vao - The vertex array of the object
1817
+ * @param location - The attribute location, see {@link _attribLocations}
1818
+ * @param type - The data type of the attribute: `gl.FLOAT` configures a float
1819
+ * attribute, any other type an integer attribute
1820
+ * @param values - The prepared values: one per point, or one constant
1821
+ * @param current - What the attribute is currently backed by; omitted for a
1822
+ * new object
1823
+ * @returns The buffer now holding the values, or the constant
1824
+ */
1825
+ private _backAttribute;
1826
+ /**
1827
+ * Computes the factor that converts the sizes of an object to world units
1828
+ *
1829
+ * Multiplies the object- and layer-level point size factors with the
1830
+ * transform scales that the unit of the size configuration is subject to:
1831
+ * sizes in data units scale with the object and layer transforms, sizes in
1832
+ * layer units with the layer transform only, and sizes in world units with
1833
+ * neither.
1834
+ *
1835
+ * @param layer - The layer the points are drawn on, as of the current model
1836
+ * @param points - The points object being drawn, as of the current model
1837
+ */
1838
+ private static _computePointSizeFactor;
1839
+ /**
1840
+ * Copies a size configuration without its units
1841
+ *
1842
+ * The unit only affects {@link _computePointSizeFactor}, not the resolved
1843
+ * sizes, so it is left out of the snapshot that
1844
+ * {@link _checkPointSizeBufferChanged} compares.
1845
+ */
1846
+ private static _stripSizeUnit;
1847
+ /**
1848
+ * Captures what the buffers of an object are resolved from
1849
+ *
1850
+ * Every property the change predicates read has to be captured here: the
1851
+ * item-level configurations, and the maps they resolve their values from,
1852
+ * looked up now so that the predicates compare maps rather than map IDs (see
1853
+ * {@link ConfigUtils.findGroupByMap}).
1854
+ *
1855
+ * @param newRef - The object to capture the snapshot of
1856
+ * @param syncContext - The inputs of the current synchronization, holding the maps
1857
+ * @returns The snapshot
1858
+ */
1859
+ private static _createRenderConfigSnapshot;
1860
+ /**
1861
+ * Returns whether the markers of an object have to be resolved again
1862
+ *
1863
+ * Also true for an object that has not been rendered yet, like the other
1864
+ * predicates. Configurations are compared by value, maps by identity (see
1865
+ * {@link _createRenderConfigSnapshot}).
1866
+ */
1867
+ private static _checkPointMarkerBufferChanged;
1868
+ /**
1869
+ * Returns whether the sizes of an object have to be resolved again
1870
+ *
1871
+ * The point size factors, transform scales and size units are shader
1872
+ * uniforms (see {@link _computePointSizeFactor}), so only the rest of the
1873
+ * point size configuration matters here.
1874
+ */
1875
+ private static _checkPointSizeBufferChanged;
1876
+ /**
1877
+ * Returns whether the colors of an object have to be resolved again
1878
+ *
1879
+ * Colors carry the resolved point visibilities and opacities in their alpha
1880
+ * channel, so they also depend on those configurations. The layer- and
1881
+ * object-level visibility and opacity are shader uniforms (see
1882
+ * {@link WebGLRendererBase.computeOpacityFactor}) and do not matter here.
1883
+ */
1884
+ private static _checkPointColorBufferChanged;
1885
+ /**
1886
+ * Resolves the packed RGBA color all points share if the color, visibility
1887
+ * and opacity configurations are all constants, `undefined` otherwise
1888
+ *
1889
+ * The three fold into one attribute (see {@link ColorUtils.withAlpha}), so
1890
+ * it is only constant if all of them are.
1891
+ */
1892
+ private static _resolveConstantColor;
1893
+ /**
1894
+ * Computes the axis-aligned bounding box of the given points in data coordinates
1895
+ *
1896
+ * @param geometry - X and Y coordinates of the points, in data coordinates
1897
+ * @param options - Optional abort signal
1898
+ * @returns The axis-aligned bounding box of the points in data coordinates
1899
+ * @throws Error if the coordinate arrays are empty or have different lengths
1900
+ */
1901
+ private static _getObjectBounds;
1902
+ }
1903
+
1904
+ /**
1905
+ * The inputs of a synchronization of the points renderer
1906
+ *
1907
+ * The tables and group-to-value maps that the objects resolve their
1908
+ * properties from, and the loaders for points and table data (see
1909
+ * {@link WebGLRendererBase.synchronize}).
1910
+ */
1911
+ declare type WebGLPointsSyncContext = {
1912
+ tables: Table[];
1913
+ markerMaps: GroupValueMap<Marker>[];
1914
+ sizeMaps: GroupValueMap<number>[];
1915
+ colorMaps: GroupValueMap<Color>[];
1916
+ visibilityMaps: GroupValueMap<boolean>[];
1917
+ opacityMaps: GroupValueMap<number>[];
1918
+ loadObject: (points: Points, options?: {
1919
+ signal?: AbortSignal;
1920
+ }) => Promise<PointsData>;
1921
+ loadTable: (table: Table, options?: {
1922
+ signal?: AbortSignal;
1923
+ }) => Promise<TableData>;
1924
+ };
1925
+
1926
+ /**
1927
+ * Base class for WebGL renderers that draw the items of objects (points or shapes)
1928
+ *
1929
+ * {@link setModel} sets the layers and objects to render. The properties that
1930
+ * are applied when drawing (transforms, visibility, opacity, draw order) are
1931
+ * read from the current model on every draw (see {@link getRenderPasses}).
1932
+ * Everything else is built into GPU resources by {@link synchronize}, which
1933
+ * {@link needsSynchronization} tells when to call, through the
1934
+ * {@link prepareRenderedObject}, {@link createRenderedObject} and
1935
+ * {@link updateRenderedObject} hooks that the renderers implement.
1936
+ *
1937
+ * Objects are assigned to a layer either as a whole, by layer ID, or per item,
1938
+ * by a table column; {@link loadObjects} resolves both into one
1939
+ * {@link ObjectRef} per object and layer. The per-item assignment is cached by
1940
+ * the identity of the object and table data (see {@link _getLayerItemsInfos}),
1941
+ * so the loaders have to return immutable data that keeps its identity for as
1942
+ * long as its content is unchanged. Likewise, the renderers detect an edit to
1943
+ * a group-to-value map by comparing the maps that their objects' configurations
1944
+ * resolve from by identity (see `ConfigUtils.findGroupByMap`), so the maps
1945
+ * passed to a synchronization have to keep their identity for as long as they
1946
+ * are unchanged.
1947
+ */
1948
+ declare abstract class WebGLRendererBase<TObject extends Points | Shapes, TObjectData extends PointsData | ShapesData, TSyncContext extends {
1949
+ tables: Table[];
1950
+ loadObject: (object: TObject, options?: {
1951
+ signal?: AbortSignal;
1952
+ }) => Promise<TObjectData>;
1953
+ loadTable: (table: Table, options?: {
1954
+ signal?: AbortSignal;
1955
+ }) => Promise<TableData>;
1956
+ }, TPreparedObject, TRenderedObject extends RenderedObjectBase<TObject, TObjectData>> {
1957
+ readonly context: WebGLContext;
1958
+ viewport: Rect;
1959
+ private _model?;
1960
+ private _lastSyncState?;
1961
+ private _hasUnreportedChanges;
1962
+ private readonly _renderedObjects;
1963
+ private readonly _layerItemsInfosCache;
1964
+ /**
1965
+ * Creates a new WebGLRendererBase instance
1966
+ *
1967
+ * @param context - The WebGL context to use for rendering
1968
+ */
1969
+ constructor(context: WebGLContext);
1970
+ /**
1971
+ * Sets the layers and objects to render
1972
+ *
1973
+ * Layer- and object-level properties are drawn from uniforms, and the draw
1974
+ * order is the order of the model, so a change that affects nothing else
1975
+ * needs nothing done here: both are read from the new model by the next draw
1976
+ * (see {@link getRenderPasses}).
1977
+ * Every other change - a different set of layers or objects, layer
1978
+ * memberships, data sources or item-level configurations - requires a
1979
+ * resynchronization, which the caller is expected to trigger whenever
1980
+ * {@link needsSynchronization} says so.
1981
+ *
1982
+ * Does not redraw: a model that differs at all differs either in a property
1983
+ * that is applied when drawing, or in one that requires a resynchronization,
1984
+ * so the caller is expected to redraw whenever this returns `true`. A model
1985
+ * equal to the current one is ignored.
1986
+ *
1987
+ * The layers and objects are cloned, so that what the renderer compares
1988
+ * against later - in {@link needsSynchronization}, and in the references of
1989
+ * a synchronization - is what it was given, whatever the caller does with its
1990
+ * instances afterwards.
1991
+ *
1992
+ * @param layers - The layers to render
1993
+ * @param objects - The objects (points or shapes) to render
1994
+ * @returns Whether the model differs from the current one
1995
+ */
1996
+ setModel(layers: Layer[], objects: TObject[]): boolean;
1997
+ /**
1998
+ * Gets the bounding box of all drawn objects, in world coordinates
1999
+ *
2000
+ * Reads the transforms from the current model (see
2001
+ * {@link getRenderPasses}), so the bounds follow a model that requires no
2002
+ * resynchronization.
2003
+ *
2004
+ * @returns The bounds, or null if nothing is drawn
2005
+ */
2006
+ getRenderedBounds(): Rect | null;
2007
+ /**
2008
+ * Returns whether the rendered objects have to be synchronized with the
2009
+ * current model and render options
2010
+ *
2011
+ * Compares the state that a synchronization depends on (see
2012
+ * {@link getSyncState}) against the one the last synchronization was based
2013
+ * on (see {@link _recordSyncState}). Everything else about the model - the
2014
+ * properties that are applied when drawing, and the order of the layers and
2015
+ * objects - is fully applied by {@link setModel}, and everything else about
2016
+ * the render options by the next draw.
2017
+ *
2018
+ * @returns Whether {@link synchronize} has to be called
2019
+ */
2020
+ needsSynchronization(): boolean;
2021
+ /**
2022
+ * Synchronizes the rendered objects with the current model and render options
2023
+ *
2024
+ * Loads the objects of the model (see {@link loadObjects}), drops the
2025
+ * rendered objects that no longer match one (see
2026
+ * {@link matchOrDestroyRenderedObjects}), and then creates or updates the
2027
+ * rest in two passes. The first prepares every object (see
2028
+ * {@link prepareRenderedObject}), issuing all requests before the first
2029
+ * `await`: requests are shared with, and cancelled once abandoned by, a
2030
+ * superseded synchronization, unless they are reclaimed within the same
2031
+ * task. The second awaits the preparations in order and uploads each of them
2032
+ * in one synchronous block (see {@link createRenderedObject} and
2033
+ * {@link updateRenderedObject}), so a draw never sees a half-updated object.
2034
+ *
2035
+ * An object whose preparation fails, or finds nothing to render, is logged
2036
+ * and dropped. A synchronization that fails or is aborted leaves the model
2037
+ * unsynchronized (see {@link _discardSyncState}), and the changes it made
2038
+ * before it stopped are reported by the next one that completes.
2039
+ *
2040
+ * @param syncContext - The inputs to synchronize with: the tables and
2041
+ * group-to-value maps that the objects resolve their properties from, and
2042
+ * the loaders for object and table data. It carries inputs only; what an
2043
+ * object was resolved from is captured per object (see {@link ObjectRef})
2044
+ * @param options - Optional abort signal
2045
+ * @returns A promise that resolves to whether any rendered object changed
2046
+ * since the last completed synchronization
2047
+ * @throws Error if no model has been set (see {@link setModel})
2048
+ */
2049
+ synchronize(syncContext: TSyncContext, options?: {
2050
+ signal?: AbortSignal;
2051
+ }): Promise<boolean>;
2052
+ /**
2053
+ * Returns the state of the current model and render options that a
2054
+ * synchronization depends on
2055
+ *
2056
+ * The layers and objects are keyed by ID, so that their order - the draw order
2057
+ * - is not part of the state (see {@link getLayerSyncState} and
2058
+ * {@link getObjectSyncState} for what is, and
2059
+ * {@link getRenderOptionsSyncState} for the render options).
2060
+ *
2061
+ * @returns The state, or `undefined` if no model has been set
2062
+ */
2063
+ protected getSyncState(): object | undefined;
2064
+ /**
2065
+ * Returns the state of a layer that a synchronization depends on
2066
+ *
2067
+ * The counterpart of {@link getObjectSyncState} for layers. The point size
2068
+ * factor is blanked out as well: it is a uniform of the points renderer, and
2069
+ * the shapes renderer never reads it. So is the name, which nothing rendered
2070
+ * depends on.
2071
+ *
2072
+ * @param layer - The layer to return the state of
2073
+ * @returns The layer without the properties that are applied when drawing,
2074
+ * and without the cosmetic ones
2075
+ */
2076
+ protected getLayerSyncState(layer: Layer): object;
2077
+ /**
2078
+ * Returns the state of an object that a synchronization depends on
2079
+ *
2080
+ * Everything but the properties that are applied when drawing, which are read
2081
+ * from the current model on every draw (see {@link getRenderPasses}) and
2082
+ * hence need no synchronization, and but the cosmetic ones, which nothing
2083
+ * rendered depends on. Those are blanked out rather than dropped, so that a
2084
+ * property added to the model later is part of the state, and thereby
2085
+ * requires a resynchronization, unless it is blanked out here as well.
2086
+ *
2087
+ * The result is only ever deep-compared against that of another object, hence
2088
+ * the opaque return type.
2089
+ *
2090
+ * @param object - The object (points or shapes) to return the state of
2091
+ * @returns The object without the properties that are applied when drawing,
2092
+ * and without the cosmetic ones
2093
+ */
2094
+ protected getObjectSyncState(object: TObject): object;
2095
+ /**
2096
+ * Returns the state of the render options that a synchronization depends on
2097
+ *
2098
+ * Render options that are applied when drawing need no synchronization and
2099
+ * are left out. Nothing by default; a renderer whose GPU resources are built
2100
+ * for a render option overrides this to return it.
2101
+ *
2102
+ * @returns The state, or `undefined` if no render option needs a synchronization
2103
+ */
2104
+ protected getRenderOptionsSyncState(): object | undefined;
2105
+ /**
2106
+ * Concurrently loads the data of all objects to be rendered on the layers of the current model
2107
+ *
2108
+ * An object assigned to a layer by layer ID is loaded for that layer only, an
2109
+ * object assigned per item by a table column is loaded for every layer, with
2110
+ * the items on each layer resolved from the table (see
2111
+ * {@link _getLayerItemsInfos}). The data of an object, and of a table, is
2112
+ * loaded once, no matter how many references it is shared by.
2113
+ *
2114
+ * The returned references are ordered by layer and then by object. Objects
2115
+ * whose data or table failed to load are logged and skipped, and so are
2116
+ * objects whose items are assigned per item without a table to resolve the
2117
+ * assignment from. Objects without items on a layer are skipped silently,
2118
+ * which also covers empty objects and objects whose table is empty - those
2119
+ * are legitimate states, not failures.
2120
+ *
2121
+ * @param syncContext - The inputs of the current synchronization: the tables
2122
+ * that the objects resolve their item layers from, and the loaders for
2123
+ * object and table data
2124
+ * @param options - Optional abort signal
2125
+ * @returns A promise that resolves to one reference per loaded object and layer
2126
+ * @throws Error if no model has been set (see {@link setModel})
2127
+ */
2128
+ protected loadObjects(syncContext: TSyncContext, options?: {
2129
+ signal?: AbortSignal;
2130
+ }): Promise<ObjectRef_2<TObject, TObjectData>[]>;
2131
+ /**
2132
+ * Matches the rendered objects to a new set of references, and destroys the
2133
+ * ones left over
2134
+ *
2135
+ * A rendered object is matched by the layer and object it is kept under, and
2136
+ * kept if its contributed items and data source are those of the reference,
2137
+ * which it then adopts and is returned for reuse with. Every other rendered
2138
+ * object - one that no reference addresses, or one whose items or data source
2139
+ * changed - is destroyed and dropped.
2140
+ *
2141
+ * @param newRefs - The object references to match against
2142
+ * @returns One match per reference, in the order of the references, each with
2143
+ * the rendered object to reuse for it, or `undefined` if it has none yet
2144
+ */
2145
+ protected matchOrDestroyRenderedObjects(newRefs: ObjectRef_2<TObject, TObjectData>[]): {
2146
+ newRef: ObjectRef_2<TObject, TObjectData>;
2147
+ renderedObject: TRenderedObject | undefined;
2148
+ }[];
2149
+ /**
2150
+ * Adds a newly created rendered object under its layer and object
2151
+ *
2152
+ * @param renderedObject - The rendered object to add
2153
+ */
2154
+ protected addRenderedObject(renderedObject: TRenderedObject): void;
2155
+ /**
2156
+ * Drops a rendered object and releases its GPU resources
2157
+ *
2158
+ * @param renderedObject - The rendered object to remove
2159
+ */
2160
+ protected removeRenderedObject(renderedObject: TRenderedObject): void;
2161
+ /**
2162
+ * Drops all rendered objects and releases their GPU resources
2163
+ */
2164
+ protected clearRenderedObjects(): void;
2165
+ /**
2166
+ * Prepares everything that has to be uploaded for an object
2167
+ *
2168
+ * Runs in the first pass of {@link synchronize}, which calls it synchronously
2169
+ * for every object of a synchronization, one after the other: every request
2170
+ * has to be issued before the first `await`. Decides, from the object's
2171
+ * current rendered state, which of its GPU resources have to be rebuilt, and
2172
+ * resolves only those.
2173
+ *
2174
+ * @param newRef - The object to prepare
2175
+ * @param renderedObject - The object's current rendered state, if it is reused
2176
+ * @param syncContext - The inputs of the current synchronization
2177
+ * @param options - Optional abort signal
2178
+ * @returns What {@link createRenderedObject} or {@link updateRenderedObject}
2179
+ * upload, or `null` if there is nothing to render for the object, which is
2180
+ * then dropped
2181
+ */
2182
+ protected abstract prepareRenderedObject(newRef: ObjectRef_2<TObject, TObjectData>, renderedObject: TRenderedObject | undefined, syncContext: TSyncContext, options?: {
2183
+ signal?: AbortSignal;
2184
+ }): Promise<TPreparedObject | null>;
2185
+ /**
2186
+ * Creates the rendered object, with its GPU resources, of a newly prepared object
2187
+ *
2188
+ * Runs in the second pass of {@link synchronize}, synchronously.
2189
+ *
2190
+ * @param newRef - The object
2191
+ * @param prepared - Its preparation, made without a rendered object to reuse
2192
+ * @returns The rendered object, which {@link synchronize} adds
2193
+ */
2194
+ protected abstract createRenderedObject(newRef: ObjectRef_2<TObject, TObjectData>, prepared: TPreparedObject): TRenderedObject;
2195
+ /**
2196
+ * Updates the GPU resources of a rendered object from its preparation
2197
+ *
2198
+ * Runs in the second pass of {@link synchronize}, synchronously.
2199
+ *
2200
+ * @param renderedObject - The rendered object to update in place
2201
+ * @param prepared - Its preparation, made with it as the rendered object to reuse
2202
+ * @returns Whether any GPU resource was uploaded to, i.e. whether the object
2203
+ * draws differently now
2204
+ */
2205
+ protected abstract updateRenderedObject(renderedObject: TRenderedObject, prepared: TPreparedObject): boolean;
2206
+ /**
2207
+ * Releases the GPU resources owned by a single rendered object
2208
+ *
2209
+ * Does not remove the object from {@link _renderedObjects}, see
2210
+ * {@link removeRenderedObject}.
2211
+ *
2212
+ * @param renderedObject - The rendered object whose GPU resources to release
2213
+ */
2214
+ protected abstract destroyRenderedObject(renderedObject: TRenderedObject): void;
2215
+ /**
2216
+ * Returns one render pass per rendered object to draw, in draw order
2217
+ *
2218
+ * A pass carries the layer and the object of the current model, and the
2219
+ * rendered object holding the GPU resources to draw them with.
2220
+ *
2221
+ * The properties that are applied when drawing - the transforms, the
2222
+ * visibility, the opacity and the point size factors - are read from the
2223
+ * layer and the object returned here, never from the reference of a rendered
2224
+ * object: the reference holds the object as it was when it was loaded (see
2225
+ * {@link ObjectRef}), whereas these are the current ones, so that setting a
2226
+ * model that only changes them takes effect without a resynchronization.
2227
+ *
2228
+ * The model is what is iterated, the way {@link loadObjects} iterates it:
2229
+ * by layer, then by object, pairing an object with the layer it is assigned
2230
+ * to by ID, or with every layer if its items are assigned to layers by a
2231
+ * table column. That order is the draw order. Rendered objects whose layer or
2232
+ * object has been removed from the model, or whose object has moved to
2233
+ * another layer, are therefore never visited, until the resynchronization
2234
+ * that the change requires drops them. Before a model is set, there is
2235
+ * nothing to draw.
2236
+ *
2237
+ * @returns The render passes, in draw order
2238
+ */
2239
+ protected getRenderPasses(): {
2240
+ layer: Layer;
2241
+ object: TObject;
2242
+ renderedObject: TRenderedObject;
2243
+ }[];
2244
+ /**
2245
+ * Records the current model and render options as what the rendered objects
2246
+ * are being synchronized with
2247
+ *
2248
+ * {@link synchronize} calls this first, before its first `await`: the model
2249
+ * may be set again while it runs, and {@link needsSynchronization} has to
2250
+ * report such a change against the model the synchronization actually read,
2251
+ * not against the one it found when it finished. A synchronization that
2252
+ * fails hands the returned state back to {@link _discardSyncState}, so that
2253
+ * the model is synchronized again.
2254
+ *
2255
+ * @returns The recorded state
2256
+ */
2257
+ private _recordSyncState;
2258
+ /**
2259
+ * Forgets a recorded synchronization state, unless another synchronization
2260
+ * has recorded its own since
2261
+ *
2262
+ * Called by a synchronization that failed, so that
2263
+ * {@link needsSynchronization} reports the model as unsynchronized again. A
2264
+ * synchronization that was aborted because a newer one started must not
2265
+ * undo what the newer one recorded, hence the identity check.
2266
+ *
2267
+ * @param syncState - The state the failed synchronization recorded, as
2268
+ * returned by {@link _recordSyncState}
2269
+ */
2270
+ private _discardSyncState;
2271
+ /**
2272
+ * Returns the items of an object that belong to each of the given layers
2273
+ *
2274
+ * Layers that are missing from {@link _layerItemsInfosCache} are computed in a
2275
+ * single pass over the items of the object, looking each item's row up in the
2276
+ * table (see {@link TableUtils.forEachRow}), and are added to the cache.
2277
+ * Layers that are already cached for the same object data, table data and
2278
+ * layer column are re-used as they are, so that objects sharing their data,
2279
+ * but not their table or layer column, do not evict each other's layers.
2280
+ * Cached layers that are not among the given ones are dropped, as are their
2281
+ * item masks, which take one byte per item of the object. Item IDs and masks
2282
+ * are only allocated for layers that turn out to contain items, layers
2283
+ * without items are cached as `null`.
2284
+ *
2285
+ * @param data - The data of the object to compute the item masks for
2286
+ * @param tableData - The data of the table holding the item layers
2287
+ * @param tableLayersColumn - The name of the table column holding the layer IDs
2288
+ * @param tableLayers - The values of the table column, in table item order
2289
+ * @param layers - The layers to compute the item masks for
2290
+ * @param options - Optional abort signal
2291
+ * @returns A promise that resolves to the item IDs and mask of each layer, by
2292
+ * layer ID, or to `null` for layers without items
2293
+ */
2294
+ private _getLayerItemsInfos;
2295
+ /**
2296
+ * Awaits the preparation of an object, dropping the object if it fails or
2297
+ * finds nothing to render
2298
+ *
2299
+ * @param newRef - The prepared object
2300
+ * @param renderedObject - The object's current rendered state, if any, which
2301
+ * is removed if the object is dropped
2302
+ * @param preparedPromise - The preparation, see {@link prepareRenderedObject}
2303
+ * @param options - Optional abort signal
2304
+ * @returns The preparation, or `undefined` if the object was dropped (which
2305
+ * is logged)
2306
+ */
2307
+ private _settleRenderedObjectPreparation;
2308
+ /**
2309
+ * Creates the loader for the tables that an object resolves its properties
2310
+ * from
2311
+ *
2312
+ * A configuration may name a table other than the object's, in which case its
2313
+ * values are resolved by the item IDs of the object's own table.
2314
+ *
2315
+ * @param ref - The object reference
2316
+ * @param syncContext - The inputs of the current synchronization: the tables to
2317
+ * look the configured table up in, and the loader for table data
2318
+ * @returns The loader, taking the ID of a table, or `undefined` for the
2319
+ * object's own table; it rejects if the object has no table, or the table was
2320
+ * not found
2321
+ */
2322
+ protected static createTableLoader(ref: ObjectRef_2<Points | Shapes, PointsData | ShapesData>, syncContext: {
2323
+ tables: Table[];
2324
+ loadTable: (table: Table, options?: {
2325
+ signal?: AbortSignal;
2326
+ }) => Promise<TableData>;
2327
+ }): (tableId: string | undefined, options?: {
2328
+ signal?: AbortSignal;
2329
+ }) => Promise<TableData>;
2330
+ /**
2331
+ * Computes the factor that the alpha of every item of an object is
2332
+ * multiplied with when drawing
2333
+ *
2334
+ * @param layer - The layer the object is drawn on, as of the current model
2335
+ * @param object - The object being drawn, as of the current model
2336
+ * @returns The product of the layer and object opacities, or `0` if the
2337
+ * layer or the object is invisible
2338
+ */
2339
+ protected static computeOpacityFactor(layer: Layer, object: Points | Shapes): number;
2340
+ }
2341
+
2342
+ /**
2343
+ * WebGL renderer for two-dimensional shape clouds
2344
+ *
2345
+ * Shapes are rasterized on the GPU via a scanline-based algorithm. Each shapes
2346
+ * object is represented by a quad covering its bounds within the viewport,
2347
+ * whose fragment shader samples a scanline data texture to determine polygon
2348
+ * membership, fill colors, and stroke colors.
2349
+ *
2350
+ * Every object owns its textures. Synchronizing compares the current model
2351
+ * against the snapshot those textures were built from, and rebuilds only the
2352
+ * ones whose inputs changed. Layer- and object-level properties (transforms,
2353
+ * visibility and opacity) are shader uniforms, so changing them never touches
2354
+ * the textures, and never requires a synchronization (see
2355
+ * {@link WebGLRendererBase.setModel}).
2356
+ */
2357
+ export declare class WebGLShapesRenderer extends WebGLRendererBase<Shapes, ShapesData, WebGLShapesSyncContext, PreparedShapes, RenderedShapes> {
2358
+ private static readonly _scanlineDataTextureWidth;
2359
+ private static readonly _shapeColorsTextureWidth;
2360
+ private static readonly _numValuesPerScanlineDataTextureLine;
2361
+ private static readonly _numValuesPerShapeColorsTextureLine;
2362
+ private static readonly _textureUnits;
2363
+ renderOptions: WebGLShapesRenderOptions;
2364
+ private readonly _program;
2365
+ private readonly _uniformLocations;
2366
+ /**
2367
+ * Creates the shader program and retrieves uniform locations
2368
+ *
2369
+ * @param context - The WebGL context to use for rendering
2370
+ */
2371
+ constructor(context: WebGLContext);
2372
+ /**
2373
+ * Issues the WebGL draw calls for all synchronized shapes
2374
+ *
2375
+ * Renders each shapes object as a quad whose fragment shader performs
2376
+ * scanline-based polygon rasterization using the per-object scanline data
2377
+ * texture, with the viewport → world matrix as a global uniform and its
2378
+ * world → data matrix, bounds, numbers of scanlines and bins, half stroke
2379
+ * width and device pixel size in data units (for anti-aliasing) and opacity
2380
+ * factor as per-pass uniforms, computed from the current model (see
2381
+ * {@link getRenderPasses}). The quad covers the object's bounds, dilated by
2382
+ * how far the anti-aliased strokes reach beyond them, within the viewport, so
2383
+ * that fragments are only shaded where the object can be; objects outside the
2384
+ * viewport, objects whose layer or object is invisible, and objects without
2385
+ * scanlines or bins are skipped.
2386
+ */
2387
+ draw(): void;
2388
+ /**
2389
+ * Releases the shader program and all per-object GPU textures
2390
+ */
2391
+ destroy(): void;
2392
+ /**
2393
+ * Gets the bounding box of all drawn shapes, in world coordinates
2394
+ *
2395
+ * Dilates the bounds of the shapes by half the stroke width, as the strokes
2396
+ * reach beyond them, but not by the anti-aliasing margin, which depends on
2397
+ * the current zoom level (see {@link _computeQuad}).
2398
+ */
2399
+ getRenderedBounds(): Rect | null;
2400
+ /**
2401
+ * Returns the grid render options (the number of edges per scanline, the
2402
+ * bin width factor and the shape padding), which the scanline data textures
2403
+ * are rasterized for, so that changing them requires a resynchronization
2404
+ */
2405
+ protected getRenderOptionsSyncState(): object;
2406
+ /**
2407
+ * Prepares everything that has to be uploaded for an object
2408
+ *
2409
+ * Decides what the object's textures need - the geometry for a new object or
2410
+ * changed grid render options (see {@link getRenderOptionsSyncState}), and
2411
+ * the resolved fill and stroke colors whose configurations or referenced
2412
+ * maps changed (see {@link _createRenderConfigSnapshot}) -
2413
+ * requests all of it before the first `await`, and then computes the bounds,
2414
+ * the grid size and the paddings, rasterizes the scanline data and folds the
2415
+ * resolved visibilities and opacities into the colors.
2416
+ *
2417
+ * See {@link WebGLRendererBase.prepareRenderedObject} for when this runs.
2418
+ *
2419
+ * @param newRef - The object to prepare
2420
+ * @param renderedShapes - The object's current GPU state, if it is reused
2421
+ * @param syncContext - The inputs of the current synchronization
2422
+ * @param options - Optional abort signal
2423
+ * @returns The snapshot the decisions were based on, the bounds, the grid
2424
+ * render options and the numbers of scanlines and bins, the packed scanline
2425
+ * data (if the geometry was loaded) and the resolved colors that have to be
2426
+ * uploaded, or `null` if the shapes have no area
2427
+ */
2428
+ protected prepareRenderedObject(newRef: ShapesRef, renderedShapes: RenderedShapes | undefined, syncContext: WebGLShapesSyncContext, options?: {
2429
+ signal?: AbortSignal;
2430
+ }): Promise<PreparedShapes | null>;
2431
+ /**
2432
+ * Creates the textures of a new object
2433
+ *
2434
+ * @param newRef - The object
2435
+ * @param prepared - Its preparation, which holds every texture's data
2436
+ * @returns The rendered object
2437
+ */
2438
+ protected createRenderedObject(newRef: ShapesRef, prepared: PreparedShapes): RenderedShapes;
2439
+ /**
2440
+ * Reloads the textures of an object whose data was prepared again
2441
+ *
2442
+ * Refills the colors textures in place, and creates a new scanline data
2443
+ * texture before releasing the one it replaces, so that the old one survives
2444
+ * if creating the new one throws. The snapshot is adopted last, so that an
2445
+ * update that throws is retried by the next synchronization.
2446
+ *
2447
+ * @param renderedShapes - The rendered object to update in place
2448
+ * @param prepared - Its preparation, holding the texture data that changed
2449
+ * @returns Whether any texture was reloaded
2450
+ */
2451
+ protected updateRenderedObject(renderedShapes: RenderedShapes, prepared: PreparedShapes): boolean;
2452
+ /**
2453
+ * Deletes all GPU textures owned by a single rendered object
2454
+ *
2455
+ * @param renderedShapes - The rendered object whose textures to delete
2456
+ */
2457
+ protected destroyRenderedObject(renderedShapes: RenderedShapes): void;
2458
+ /**
2459
+ * Builds the scanline data of a shapes object
2460
+ *
2461
+ * Rasterizes all shapes into horizontal scanlines and their x-bins, packed
2462
+ * into a 32-bit integer buffer, aligned to the lines of the scanline data
2463
+ * texture that {@link _createScanlineDataTexture} creates from it.
2464
+ *
2465
+ * @param numScanlines - Number of scanlines to rasterize into
2466
+ * @param numBins - Number of x-bins per scanline
2467
+ * @param scanlinePadding - See {@link WebGLShapesRasterizer.rasterizeScanlines}
2468
+ * @param binPadding - See {@link WebGLShapesRasterizer.rasterizeScanlines}
2469
+ * @param geometry - Geometry for all shapes in the object
2470
+ * @param shapesMask - Per-shape inclusion mask, or `undefined` if all shapes are included
2471
+ * @param objectBounds - Axis-aligned bounding box of all shapes
2472
+ * @param options - Optional abort signal
2473
+ * @returns The packed scanline data
2474
+ */
2475
+ private static _createScanlineBuffer;
2476
+ /**
2477
+ * Throws unless a data texture of the given size fits the GPU
2478
+ *
2479
+ * Checked while an object is prepared, where a failure drops only that
2480
+ * object, with a message that says why, rather than when its textures are
2481
+ * created, where WebGL would fail with an opaque error, or render garbage.
2482
+ * The width is fixed per texture, but WebGL 2 only guarantees 2048 texels.
2483
+ *
2484
+ * @param name - What the texture holds, for the error message
2485
+ * @param width - The width of the texture, in texels
2486
+ * @param height - The number of texture lines the data needs
2487
+ * @throws Error if the width or height exceeds the maximum texture size
2488
+ */
2489
+ private _checkDataTextureSize;
2490
+ /**
2491
+ * Uploads packed scanline data as an RGBA32UI texture
2492
+ *
2493
+ * @param scanlineBuffer - The packed scanline data, see {@link _createScanlineBuffer}
2494
+ * @returns The scanline data texture
2495
+ */
2496
+ private _createScanlineDataTexture;
2497
+ /**
2498
+ * Uploads packed fill or stroke colors as a new R32UI texture
2499
+ *
2500
+ * @param packedShapeColors - The packed RGBA colors, one per shape, aligned
2501
+ * to the texture width
2502
+ * @returns The colors texture
2503
+ */
2504
+ private _createShapeColorsTexture;
2505
+ /**
2506
+ * Refills an existing colors texture with packed fill or stroke colors
2507
+ *
2508
+ * The texture has to have been created by {@link _createShapeColorsTexture}
2509
+ * for the same number of shapes: its storage is immutable, so the colors
2510
+ * have to fill it exactly.
2511
+ *
2512
+ * @param texture - The colors texture to refill
2513
+ * @param packedShapeColors - The packed RGBA colors, one per shape, aligned
2514
+ * to the texture width
2515
+ */
2516
+ private _loadShapeColorsTexture;
2517
+ /**
2518
+ * Computes the quad to draw an object with, in viewport coordinates
2519
+ *
2520
+ * The object's bounds are transformed to world coordinates, dilated by how
2521
+ * far the anti-aliased strokes reach beyond the shapes (half the stroke
2522
+ * width, which is at least half a pixel, plus half a pixel, see fragment
2523
+ * shader), and intersected with the viewport, then expressed in viewport
2524
+ * coordinates, `[0, 1]` spanning the viewport. Fragments outside the
2525
+ * object's bounds are discarded by the fragment shader anyway, so drawing
2526
+ * only this quad changes nothing but the number of fragments shaded.
2527
+ *
2528
+ * @param objectBounds - The bounds of the object's shapes, in data coordinates
2529
+ * @param dataToWorldMatrix - The data → world matrix of the object
2530
+ * @param worldDevicePixelSize - The size of a device pixel, in world coordinates
2531
+ * @returns The quad, or `null` if the object lies outside the viewport
2532
+ */
2533
+ private _computeQuad;
2534
+ /**
2535
+ * Captures what the textures of an object are resolved from
2536
+ *
2537
+ * Every property the change predicates read has to be captured here: the
2538
+ * item-level configurations, and the maps they resolve their values from,
2539
+ * looked up now so that the predicates compare maps rather than map IDs (see
2540
+ * {@link ConfigUtils.findGroupByMap}).
2541
+ *
2542
+ * @param newRef - The object to capture the snapshot of
2543
+ * @param syncContext - The inputs of the current synchronization, holding the maps
2544
+ * @returns The snapshot
2545
+ */
2546
+ private static _createRenderConfigSnapshot;
2547
+ /**
2548
+ * Returns whether the fill colors of an object have to be resolved again
2549
+ *
2550
+ * Colors carry the resolved shape and fill visibilities and opacities in
2551
+ * their alpha channel, so they also depend on those configurations. The
2552
+ * layer- and object-level visibility and opacity are shader uniforms (see
2553
+ * {@link WebGLRendererBase.computeOpacityFactor}) and do not matter here.
2554
+ * Also true for an object that has not been rendered yet, like the other
2555
+ * predicate. Configurations are compared by value, maps by identity (see
2556
+ * {@link _createRenderConfigSnapshot}).
2557
+ */
2558
+ private static _checkShapeFillColorsTextureChanged;
2559
+ /**
2560
+ * Returns whether the stroke colors of an object have to be resolved again
2561
+ *
2562
+ * See {@link _checkShapeFillColorsTextureChanged}.
2563
+ */
2564
+ private static _checkShapeStrokeColorsTextureChanged;
2565
+ /**
2566
+ * Computes the axis-aligned bounding box of all (included) shapes
2567
+ *
2568
+ * @param geometry - Geometry for all shapes in the object
2569
+ * @param shapesMask - Per-shape inclusion mask, or `undefined` if all shapes are included
2570
+ * @param options - Optional abort signal
2571
+ * @returns The bounding rectangle in data-space coordinates, or `null` if the
2572
+ * shapes have no area, including shapes without any vertices, as such an
2573
+ * object can neither be rasterized into scanlines nor drawn by the fragment
2574
+ * shader
2575
+ */
2576
+ private static _getObjectBounds;
2577
+ }
2578
+
2579
+ /**
2580
+ * The inputs of a synchronization of the shapes renderer
2581
+ *
2582
+ * The tables and group-to-value maps that the objects resolve their
2583
+ * properties from, and the loaders for shapes and table data (see
2584
+ * {@link WebGLRendererBase.synchronize}).
2585
+ */
2586
+ declare type WebGLShapesSyncContext = {
2587
+ tables: Table[];
2588
+ colorMaps: GroupValueMap<Color>[];
2589
+ visibilityMaps: GroupValueMap<boolean>[];
2590
+ opacityMaps: GroupValueMap<number>[];
2591
+ loadObject: (shapes: Shapes, options?: {
2592
+ signal?: AbortSignal;
2593
+ }) => Promise<ShapesData>;
2594
+ loadTable: (table: Table, options?: {
2595
+ signal?: AbortSignal;
2596
+ }) => Promise<TableData>;
2597
+ };
2598
+
2599
+ export { }