@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.
- package/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/README.md +25 -0
- package/dist/index.d.ts +2599 -0
- package/dist/index.js +6015 -0
- package/package.json +46 -0
package/dist/index.d.ts
ADDED
|
@@ -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 { }
|