@welldot/render 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,531 @@
1
+ import { Units, Well, DiameterUnits, LengthUnits } from '@welldot/core';
2
+
3
+ type PadTextureConfig = {
4
+ background: string;
5
+ stroke: string;
6
+ };
7
+ type ConflictTextureConfig = {
8
+ stroke: string;
9
+ };
10
+ type CaveDryTextureConfig = {
11
+ size: number;
12
+ stroke: string;
13
+ background: string;
14
+ };
15
+ type CaveWetTextureConfig = {
16
+ size: number;
17
+ stroke: string;
18
+ background: string;
19
+ };
20
+ type SealTextureConfig = {
21
+ background: string;
22
+ };
23
+ type GravelPackTextureConfig = {
24
+ size: number;
25
+ background: string;
26
+ };
27
+ type WellScreenTextureConfig = {
28
+ size: number;
29
+ strokeWidth: number;
30
+ background: string;
31
+ };
32
+ type SurfaceCaseTextureConfig = {
33
+ orientation: string[];
34
+ size: number;
35
+ strokeWidth: number;
36
+ shapeRendering: string;
37
+ stroke: string;
38
+ background: string;
39
+ };
40
+ type TexturesConfig = {
41
+ pad?: Partial<PadTextureConfig>;
42
+ conflict?: Partial<ConflictTextureConfig>;
43
+ cave_dry?: Partial<CaveDryTextureConfig>;
44
+ cave_wet?: Partial<CaveWetTextureConfig>;
45
+ seal?: Partial<SealTextureConfig>;
46
+ gravel_pack?: Partial<GravelPackTextureConfig>;
47
+ well_screen?: Partial<WellScreenTextureConfig>;
48
+ surface_case?: Partial<SurfaceCaseTextureConfig>;
49
+ };
50
+
51
+ /** Recursively makes all properties of T optional — used for deep-mergeable option objects. */
52
+ type DeepPartial<T> = T extends object ? {
53
+ [K in keyof T]?: DeepPartial<T[K]>;
54
+ } : T;
55
+ /** A single highlight overlay item. Use `from`+`to` for depth-range highlights, `depth` for point highlights. */
56
+ type HighlightItem = {
57
+ label?: string;
58
+ from?: number;
59
+ to?: number;
60
+ depth?: number;
61
+ diameter?: number;
62
+ };
63
+ /** Highlight overlay configuration passed to `draw()`. Each key targets a specific well component. */
64
+ type Highlights = {
65
+ lithology?: HighlightItem[];
66
+ caves?: HighlightItem[];
67
+ fractures?: HighlightItem[];
68
+ cement_pad?: HighlightItem;
69
+ bore_hole?: HighlightItem[];
70
+ surface_case?: HighlightItem[];
71
+ hole_fill?: HighlightItem[];
72
+ well_case?: HighlightItem[];
73
+ well_screen?: HighlightItem[];
74
+ };
75
+ type LithologyTheme = {
76
+ stroke: string;
77
+ strokeWidth: number;
78
+ };
79
+ type LithologyTextureTheme = {
80
+ size: number;
81
+ strokeWidth: number;
82
+ stroke: string;
83
+ };
84
+ type CaveTheme = {
85
+ dryStroke: string;
86
+ wetStroke: string;
87
+ fillOpacity: number;
88
+ contactStrokeWidth: number;
89
+ };
90
+ type FractureTheme = {
91
+ dryStroke: string;
92
+ wetStroke: string;
93
+ swarm: {
94
+ centralStrokeWidth: number;
95
+ sideStrokeWidthBase: number;
96
+ sideStrokeWidthVariance: number;
97
+ };
98
+ single: {
99
+ mainStrokeWidth: number;
100
+ crackStrokeWidth: number;
101
+ };
102
+ };
103
+ type ConstructionTheme = {
104
+ cementPad: {
105
+ stroke: string;
106
+ strokeWidth: number;
107
+ };
108
+ boreHole: {
109
+ fill: string;
110
+ stroke: string;
111
+ strokeDasharray: string;
112
+ opacity: number;
113
+ strokeWidth: number;
114
+ };
115
+ surfaceCase: {
116
+ stroke: string;
117
+ strokeWidth: number;
118
+ };
119
+ holeFill: {
120
+ stroke: string;
121
+ strokeWidth: number;
122
+ };
123
+ wellCase: {
124
+ fill: string;
125
+ stroke: string;
126
+ strokeWidth: number;
127
+ };
128
+ wellScreen: {
129
+ stroke: string;
130
+ strokeWidth: number;
131
+ };
132
+ conflict: {
133
+ stroke: string;
134
+ strokeWidth: number;
135
+ };
136
+ };
137
+ type LabelsTheme = {
138
+ unitLabels: {
139
+ geologicFill: string;
140
+ aquiferFill: string;
141
+ stroke: string;
142
+ strokeWidth: number;
143
+ fontSize: number;
144
+ fontFamily?: string;
145
+ fontWeight?: string | number;
146
+ };
147
+ constructionLabels: {
148
+ fontSize: number;
149
+ labelFill: string;
150
+ labelColor: string;
151
+ fontFamily?: string;
152
+ fontWeight?: string | number;
153
+ };
154
+ labels: {
155
+ dividerStroke: string;
156
+ dividerStrokeWidth: number;
157
+ dividerStrokeDasharray: string;
158
+ fontSize: number;
159
+ scaleFontSize?: number;
160
+ color: string;
161
+ headerFont: string;
162
+ bodyColor: string;
163
+ bodyFont?: string;
164
+ scaleFont?: string;
165
+ depthTipFill?: string;
166
+ depthTipRadius?: number;
167
+ annotationBg?: string;
168
+ annotationBgOpacity?: number;
169
+ annotationBorderColor?: string;
170
+ annotationRadius?: number;
171
+ headerFontWeight?: string | number;
172
+ bodyFontWeight?: string | number;
173
+ fractureLabelFontSize?: number;
174
+ caveLabelFontSize?: number;
175
+ };
176
+ };
177
+ type LegendTheme = {
178
+ borderStrokeWidth: number;
179
+ fractureStrokeWidth: number;
180
+ fractureSideStrokeWidth: number;
181
+ itemStrokeWidth: number;
182
+ fontSize: number;
183
+ fontFamily?: string;
184
+ titleFontWeight?: string | number;
185
+ labelFontWeight?: string | number;
186
+ };
187
+ /** Visual styling theme for all well components. Use `DEFAULT_WELL_THEME` as a base and pass `DeepPartial<WellTheme>` overrides. */
188
+ type WellTheme = {
189
+ lithology: LithologyTheme;
190
+ lithologyTexture: LithologyTextureTheme;
191
+ cave: CaveTheme;
192
+ fracture: FractureTheme;
193
+ } & ConstructionTheme & LabelsTheme & {
194
+ legend: LegendTheme;
195
+ };
196
+ type ComponentsClassNames = {
197
+ tooltip: {
198
+ root: string;
199
+ title: string;
200
+ primaryInfo: string;
201
+ secondaryInfo: string;
202
+ };
203
+ yAxis: string;
204
+ wellGroup: string;
205
+ geologicGroup: string;
206
+ lithology: {
207
+ group: string;
208
+ rect: string;
209
+ };
210
+ labels: {
211
+ lithology: {
212
+ group: string;
213
+ depth: string;
214
+ label: string;
215
+ divider: string;
216
+ };
217
+ };
218
+ fractures: {
219
+ group: string;
220
+ item: string;
221
+ hitArea: string;
222
+ line: string;
223
+ polyline: string;
224
+ };
225
+ caves: {
226
+ group: string;
227
+ item: string;
228
+ fill: string;
229
+ contact: string;
230
+ };
231
+ constructionGroup: string;
232
+ constructionLabels: {
233
+ group: string;
234
+ };
235
+ cementPad: {
236
+ group: string;
237
+ item: string;
238
+ };
239
+ boreHole: {
240
+ group: string;
241
+ rect: string;
242
+ };
243
+ surfaceCase: {
244
+ group: string;
245
+ rect: string;
246
+ };
247
+ holeFill: {
248
+ group: string;
249
+ rect: string;
250
+ };
251
+ wellCase: {
252
+ group: string;
253
+ rect: string;
254
+ };
255
+ wellScreen: {
256
+ group: string;
257
+ rect: string;
258
+ };
259
+ conflict: {
260
+ group: string;
261
+ rect: string;
262
+ };
263
+ unitLabels: {
264
+ group: string;
265
+ geoRect: string;
266
+ aqRect: string;
267
+ text: string;
268
+ };
269
+ legend: {
270
+ border: string;
271
+ title: string;
272
+ item: string;
273
+ label: string;
274
+ fracturePoly: string;
275
+ caveFill: string;
276
+ constructionRect: string;
277
+ };
278
+ highlights: {
279
+ geologicGroup: string;
280
+ constructionGroup: string;
281
+ fracturesGroup: string;
282
+ item: string;
283
+ rect: string;
284
+ label: string;
285
+ labelBg: string;
286
+ };
287
+ };
288
+ /** Keys identifying which tooltip types are active. Pass to `RenderConfig.tooltips` to control visibility. */
289
+ type TooltipKey = 'geology' | 'hole' | 'surfaceCase' | 'holeFill' | 'wellCase' | 'wellScreen' | 'conflict' | 'fracture' | 'cementPad' | 'cave';
290
+ /** Full rendering behaviour configuration. Use `INTERACTIVE_RENDER_CONFIG` or `STATIC_RENDER_CONFIG` as a starting point. */
291
+ type RenderConfig = {
292
+ zoom: boolean;
293
+ pan: boolean;
294
+ /** Initial zoom scale applied on first render (1 = fit all, 2 = start 2× zoomed in). */
295
+ zoomLevel?: number;
296
+ /** undefined = show all; false or [] = show none; array = show only listed keys */
297
+ tooltips?: TooltipKey[] | false;
298
+ animation: {
299
+ duration: number;
300
+ ease: (t: number) => number;
301
+ };
302
+ geologic: {
303
+ xLeft: number;
304
+ xRightInset: number;
305
+ };
306
+ layout: {
307
+ pocoWidthRatio: number;
308
+ pocoCenterRatio: number;
309
+ };
310
+ caves: {
311
+ pathSteps: number;
312
+ amplitude: {
313
+ ratio: number;
314
+ min: number;
315
+ max: number;
316
+ };
317
+ };
318
+ fractures: {
319
+ widthMultiplier: number;
320
+ hitBuffer: {
321
+ single: number;
322
+ swarm: number;
323
+ };
324
+ swarm: {
325
+ lineCountBase: number;
326
+ lineCountVariance: number;
327
+ spread: number;
328
+ };
329
+ };
330
+ construction: {
331
+ cementPad: {
332
+ widthMultiplier: number;
333
+ thicknessMultiplier: number;
334
+ };
335
+ surfaceCase: {
336
+ diameterPaddingRatio: number;
337
+ };
338
+ };
339
+ textures?: TexturesConfig;
340
+ constructionLabels: {
341
+ active: boolean;
342
+ xOffset: number;
343
+ labelRadius: number;
344
+ labelMaxWidth?: number;
345
+ labels: {
346
+ wellCasePrefix: string;
347
+ wellScreenPrefix: string;
348
+ wellScreenSlotPrefix: string;
349
+ };
350
+ };
351
+ labels: {
352
+ /** false = hide all; true = show all; array = show only listed types */
353
+ active: boolean | ('lithology' | 'fractures' | 'caves')[];
354
+ /** Fine-grained lithology sub-item control; defaults to true when lithology is active */
355
+ lithology?: boolean | ('depth' | 'description' | 'dividers')[];
356
+ typeLabels?: {
357
+ fracture?: string;
358
+ cave?: string;
359
+ };
360
+ depthTipHeight: number;
361
+ depthTipPadX: number;
362
+ descriptionXOffset: number;
363
+ descriptionMaxWidth: number;
364
+ stackingLineHeight: number;
365
+ stackingGap: number;
366
+ fractureLabelLeaderGap?: number;
367
+ fractureLabelPadX?: number;
368
+ fractureLabelPadY?: number;
369
+ caveLabelHeight?: number;
370
+ caveLabelPadX?: number;
371
+ };
372
+ unitLabels: {
373
+ /** Show geologic_unit and aquifer_unit strips to the left of the lithology column */
374
+ active: boolean;
375
+ /** X position of the first (leftmost) strip in geologic group coordinates */
376
+ xOffset: number;
377
+ stripWidth: number;
378
+ minHeightForText: number;
379
+ /** Stroke width of divider lines between adjacent segments of different units */
380
+ innerDividerWidth: number;
381
+ /** Stroke width of the top/bottom boundary (and page-clip edges in multi-SVG rendering) */
382
+ outerEdgeWidth: number;
383
+ };
384
+ legend: LegendRenderConfig;
385
+ highlights: {
386
+ stroke: string;
387
+ strokeWidth: number;
388
+ fill: string;
389
+ fillOpacity: number;
390
+ padding: number;
391
+ strokeDasharray?: string;
392
+ labelFontSize: number;
393
+ labelPadding: number;
394
+ labelBackground: string;
395
+ labelColor: string;
396
+ labelRadius: number;
397
+ };
398
+ };
399
+ type LegendRenderConfig = {
400
+ title: string;
401
+ itemWidth: number;
402
+ height: number;
403
+ padding: number;
404
+ maxWidth?: number;
405
+ borderRadius: number;
406
+ labels: {
407
+ fractureSingle: string;
408
+ fractureSwarm: string;
409
+ fractureWater: string;
410
+ caveDry: string;
411
+ caveWet: string;
412
+ boreHole: string;
413
+ surfaceCase: string;
414
+ holeFillGravel: string;
415
+ holeFillSeal: string;
416
+ wellCase: string;
417
+ wellScreen: string;
418
+ cementPad: string;
419
+ conflict: string;
420
+ };
421
+ };
422
+ /**
423
+ * Descriptor for a single SVG panel managed by `WellRenderer`.
424
+ * @param selector - CSS selector for the `<svg>` element (e.g. `"#well-panel-1"`).
425
+ * @param height - Inner drawing height in pixels (excludes margins).
426
+ * @param width - Inner drawing width in pixels (excludes margins).
427
+ * @param margins - Space reserved around the drawing area for axes and labels.
428
+ */
429
+ type SvgInstance = {
430
+ selector: string;
431
+ height: number;
432
+ width: number;
433
+ margins: {
434
+ left: number;
435
+ right: number;
436
+ top: number;
437
+ bottom: number;
438
+ };
439
+ };
440
+
441
+ declare const DEFAULT_WELL_THEME: WellTheme;
442
+ declare const STATIC_RENDER_CONFIG: RenderConfig;
443
+ declare const INTERACTIVE_RENDER_CONFIG: RenderConfig;
444
+
445
+ /**
446
+ * Dynamically imports the FGDC texture registry (SVG path data keyed by texture code).
447
+ * Useful for external UIs that need to display texture thumbnails in selection controls.
448
+ */
449
+ declare function importFgdcTextures(): Promise<{
450
+ [code: TextureCode]: string;
451
+ }>;
452
+
453
+ /**
454
+ * SVG-based renderer for geological well profiles.
455
+ *
456
+ * One instance manages one or more SVG panels (multi-panel layouts for long wells).
457
+ * Call `prepareSvg()` once to initialise the DOM and preload textures, then call
458
+ * `draw(profile)` whenever the profile data changes.
459
+ *
460
+ * @example
461
+ * ```ts
462
+ * const renderer = new WellRenderer(
463
+ * [{ selector: '#well-svg', height: 600, width: 300, margins: { top: 20, right: 10, bottom: 20, left: 40 } }],
464
+ * { renderConfig: INTERACTIVE_RENDER_CONFIG },
465
+ * );
466
+ * await renderer.prepareSvg();
467
+ * renderer.draw(profile);
468
+ * ```
469
+ */
470
+ declare class WellRenderer {
471
+ private svgInstances;
472
+ private instanceStates;
473
+ private textures;
474
+ private onError?;
475
+ classes: ComponentsClassNames;
476
+ private renderConfig;
477
+ private theme;
478
+ private units;
479
+ /**
480
+ * @param svgs - One entry per SVG panel; multi-entry for split-panel layouts.
481
+ * @param options.classNames - Override default BEM CSS class names.
482
+ * @param options.units - Active measurement units (`length` and `diameter`).
483
+ * @param options.renderConfig - Rendering behaviour (zoom, pan, animation, layout). Defaults to `INTERACTIVE_RENDER_CONFIG`.
484
+ * @param options.theme - Visual theme overrides. Merged on top of `DEFAULT_WELL_THEME`.
485
+ * @param options.onError - Called when a draw error occurs (e.g., a renderer throws). Falls back to `console.error` if omitted.
486
+ */
487
+ constructor(svgs: SvgInstance[], options?: {
488
+ classNames?: DeepPartial<ComponentsClassNames>;
489
+ units?: Units;
490
+ renderConfig?: DeepPartial<RenderConfig>;
491
+ theme?: DeepPartial<WellTheme>;
492
+ onError?: (err: Error) => void;
493
+ });
494
+ private initInstanceSvg;
495
+ /** Renders a standalone legend into the element matched by `selector`. */
496
+ renderLegend(selector: string, profile: Well): void;
497
+ /**
498
+ * Initialises the SVG DOM structure and preloads FGDC textures.
499
+ * Must be called once before the first `draw()`.
500
+ */
501
+ prepareSvg(): Promise<void>;
502
+ /**
503
+ * Renders the well profile into all configured SVG panels.
504
+ * @param profile - The well data to render.
505
+ * @param options.units - Override the instance-level measurement units for this render.
506
+ * @param options.highlights - Highlight overlays to display on top of the profile.
507
+ */
508
+ draw(profile: Well, options?: {
509
+ units?: Units;
510
+ highlights?: Highlights;
511
+ }): void;
512
+ private drawLogToInstance;
513
+ }
514
+
515
+ declare function drawWellLegend(selector: string, profile: Well, options?: {
516
+ config?: Partial<LegendRenderConfig>;
517
+ theme?: Partial<WellTheme>;
518
+ classNames?: ComponentsClassNames['legend'];
519
+ textures?: TexturesConfig;
520
+ }): void;
521
+
522
+ /** Formats a depth value in metres to the active length unit string. */
523
+ declare function formatLength(m: number, units: LengthUnits): string;
524
+ /** Formats a diameter value in millimetres to the active diameter unit string. */
525
+ declare function formatDiameter(mm: number, units: DiameterUnits): string;
526
+ /** Returns the display label for the active length unit (e.g. `"m"` or `"ft"`). */
527
+ declare function getLengthUnit(units: LengthUnits): string;
528
+ /** Returns the display label for the active diameter unit (e.g. `"mm"` or `'"'`). */
529
+ declare function getDiameterUnit(units: DiameterUnits): string;
530
+
531
+ export { type CaveTheme, type ComponentsClassNames, type ConstructionTheme, DEFAULT_WELL_THEME, type DeepPartial, type FractureTheme, type HighlightItem, type Highlights, INTERACTIVE_RENDER_CONFIG, type LabelsTheme, type LegendRenderConfig, type LegendTheme, type LithologyTextureTheme, type LithologyTheme, type RenderConfig, STATIC_RENDER_CONFIG, type SvgInstance, type TooltipKey, WellRenderer, type WellTheme, drawWellLegend, formatDiameter, formatLength, getDiameterUnit, getLengthUnit, importFgdcTextures };