@welldot/render 0.2.3 → 0.3.0-next.20261015.d7c7365
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/README.md +71 -14
- package/dist/chunk-ODRL222Y.js +10 -0
- package/dist/chunk-ODRL222Y.js.map +1 -0
- package/dist/index.cjs +1493 -325
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +332 -33
- package/dist/index.d.ts +332 -33
- package/dist/index.js +1501 -331
- package/dist/index.js.map +1 -1
- package/dist/textures.cjs +339 -0
- package/dist/textures.cjs.map +1 -0
- package/dist/textures.d.cts +9 -0
- package/dist/textures.d.ts +9 -0
- package/dist/textures.js +7 -0
- package/dist/textures.js.map +1 -0
- package/package.json +11 -4
package/dist/index.js
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
importFgdcTextures
|
|
3
|
+
} from "./chunk-ODRL222Y.js";
|
|
4
|
+
|
|
1
5
|
// src/configs/render.configs.ts
|
|
2
6
|
import { easeCubic } from "d3";
|
|
3
7
|
|
|
4
8
|
// src/utils/format.utils.ts
|
|
9
|
+
import { resolveLanguageText } from "@welldot/core";
|
|
5
10
|
import { formatNumber } from "@welldot/utils";
|
|
6
11
|
var MM_TO_INCHES = 0.0393701;
|
|
7
12
|
var M_TO_FT = 3.28084;
|
|
@@ -19,8 +24,7 @@ function getDiameterUnit(units, locale) {
|
|
|
19
24
|
return locale === "en" ? "in." : '"';
|
|
20
25
|
}
|
|
21
26
|
function resolveRenderLabel(value, locale) {
|
|
22
|
-
|
|
23
|
-
return locale === "en" && value.en ? value.en : value.pt;
|
|
27
|
+
return resolveLanguageText(value, locale, "pt");
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
// src/configs/render.configs.ts
|
|
@@ -45,6 +49,8 @@ var RENDER_LABELS = {
|
|
|
45
49
|
wellCase: { pt: "Revestimento", en: "Casing" },
|
|
46
50
|
wellScreen: { pt: "Filtro", en: "Screen" },
|
|
47
51
|
reduction: { pt: "Redu\xE7\xE3o", en: "Reduction" },
|
|
52
|
+
centralizer: { pt: "Centralizador", en: "Centralizer" },
|
|
53
|
+
pump: { pt: "Bomba e edutor", en: "Pump and riser" },
|
|
48
54
|
cementPad: { pt: "Laje de cimento", en: "Cement pad" },
|
|
49
55
|
conflict: { pt: "Conflito", en: "Conflict" }
|
|
50
56
|
}
|
|
@@ -68,9 +74,38 @@ var RENDER_LABELS = {
|
|
|
68
74
|
wellCase: { title: { pt: "REVESTIMENTO", en: "CASING" } },
|
|
69
75
|
wellScreen: {
|
|
70
76
|
title: { pt: "FILTROS", en: "SCREENS" },
|
|
71
|
-
slot: { pt: "Ranhura:", en: "Slot:" }
|
|
77
|
+
slot: { pt: "Ranhura:", en: "Slot:" },
|
|
78
|
+
material: { pt: "Material:", en: "Material:" },
|
|
79
|
+
slotType: { pt: "Tipo:", en: "Type:" }
|
|
72
80
|
},
|
|
73
81
|
reduction: { title: { pt: "REDU\xC7\xC3O", en: "REDUCTION" } },
|
|
82
|
+
centralizer: {
|
|
83
|
+
title: { pt: "CENTRALIZADOR", en: "CENTRALIZER" },
|
|
84
|
+
depth: { pt: "Profundidade:", en: "Depth:" },
|
|
85
|
+
spacing: { pt: "Espa\xE7amento:", en: "Spacing:" }
|
|
86
|
+
},
|
|
87
|
+
pump: {
|
|
88
|
+
title: { pt: "BOMBA", en: "PUMP" },
|
|
89
|
+
intakeDepth: { pt: "Profundidade do crivo:", en: "Intake depth:" },
|
|
90
|
+
model: { pt: "Modelo:", en: "Model:" },
|
|
91
|
+
power: { pt: "Pot\xEAncia:", en: "Power:" },
|
|
92
|
+
riser: { pt: "Edutor:", en: "Riser:" },
|
|
93
|
+
type_submersible: { pt: "Bomba submersa", en: "Submersible pump" },
|
|
94
|
+
type_vertical_turbine: {
|
|
95
|
+
pt: "Bomba de eixo vertical",
|
|
96
|
+
en: "Vertical turbine pump"
|
|
97
|
+
},
|
|
98
|
+
type_jet: { pt: "Bomba injetora", en: "Jet pump" },
|
|
99
|
+
type_progressive_cavity: {
|
|
100
|
+
pt: "Bomba helicoidal",
|
|
101
|
+
en: "Progressive cavity pump"
|
|
102
|
+
},
|
|
103
|
+
type_hand_pump: { pt: "Bomba manual", en: "Hand pump" },
|
|
104
|
+
type_compressor_airlift: {
|
|
105
|
+
pt: "Compressor (air-lift)",
|
|
106
|
+
en: "Compressor (air-lift)"
|
|
107
|
+
}
|
|
108
|
+
},
|
|
74
109
|
conflict: { title: { pt: "CONFLITO", en: "CONFLICT" } },
|
|
75
110
|
fracture: {
|
|
76
111
|
title: { pt: "FRATURA", en: "FRACTURE" },
|
|
@@ -96,6 +131,19 @@ var RENDER_LABELS = {
|
|
|
96
131
|
fractureWater: { pt: "fratura aberta", en: "open fracture" },
|
|
97
132
|
cave: { pt: "caverna", en: "cave" },
|
|
98
133
|
caveWater: { pt: "caverna \xFAmida", en: "wet cave" }
|
|
134
|
+
},
|
|
135
|
+
columnHeaders: {
|
|
136
|
+
depth: { pt: "PROF.", en: "DEPTH" },
|
|
137
|
+
lithology: { pt: "LIT.", en: "LITH." },
|
|
138
|
+
construction: { pt: "CONSTRU\xC7\xC3O", en: "CONSTRUCTION" },
|
|
139
|
+
description: { pt: "DESCRI\xC7\xC3O GEOL\xD3GICA", en: "GEOLOGICAL DESCRIPTION" }
|
|
140
|
+
},
|
|
141
|
+
continuation: { prefix: { pt: "continua\xE7\xE3o", en: "continued" } },
|
|
142
|
+
overlap: {
|
|
143
|
+
label: {
|
|
144
|
+
pt: "{range} repetido da p\xE1g. anterior",
|
|
145
|
+
en: "{range} repeated from previous page"
|
|
146
|
+
}
|
|
99
147
|
}
|
|
100
148
|
};
|
|
101
149
|
function resolveGroup(group, locale) {
|
|
@@ -116,6 +164,8 @@ function resolveTooltipLabels(locale) {
|
|
|
116
164
|
wellCase: resolveGroup(t.wellCase, locale),
|
|
117
165
|
wellScreen: resolveGroup(t.wellScreen, locale),
|
|
118
166
|
reduction: resolveGroup(t.reduction, locale),
|
|
167
|
+
centralizer: resolveGroup(t.centralizer, locale),
|
|
168
|
+
pump: resolveGroup(t.pump, locale),
|
|
119
169
|
conflict: resolveGroup(t.conflict, locale),
|
|
120
170
|
fracture: resolveGroup(t.fracture, locale),
|
|
121
171
|
cementPad: resolveGroup(t.cementPad, locale),
|
|
@@ -137,7 +187,19 @@ function applyRenderLocale(config, locale) {
|
|
|
137
187
|
tooltipLabels: resolveTooltipLabels(locale),
|
|
138
188
|
labels: {
|
|
139
189
|
...config.labels,
|
|
140
|
-
typeLabels: resolveGroup(RENDER_LABELS.typeLabels, locale)
|
|
190
|
+
typeLabels: resolveGroup(RENDER_LABELS.typeLabels, locale),
|
|
191
|
+
continuation: {
|
|
192
|
+
...config.labels.continuation,
|
|
193
|
+
prefix: resolveRenderLabel(RENDER_LABELS.continuation.prefix, locale)
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
columnHeaders: {
|
|
197
|
+
...config.columnHeaders,
|
|
198
|
+
labels: resolveGroup(RENDER_LABELS.columnHeaders, locale)
|
|
199
|
+
},
|
|
200
|
+
overlap: {
|
|
201
|
+
...config.overlap,
|
|
202
|
+
label: resolveRenderLabel(RENDER_LABELS.overlap.label, locale)
|
|
141
203
|
}
|
|
142
204
|
};
|
|
143
205
|
}
|
|
@@ -163,7 +225,7 @@ var DEFAULT_WELL_THEME = {
|
|
|
163
225
|
crackStrokeWidth: 0.7
|
|
164
226
|
}
|
|
165
227
|
},
|
|
166
|
-
cementPad: { stroke: "#303030", strokeWidth:
|
|
228
|
+
cementPad: { stroke: "#303030", strokeWidth: 1 },
|
|
167
229
|
boreHole: {
|
|
168
230
|
fill: "#ffffff",
|
|
169
231
|
stroke: "#191919",
|
|
@@ -172,10 +234,24 @@ var DEFAULT_WELL_THEME = {
|
|
|
172
234
|
strokeWidth: 1.2
|
|
173
235
|
},
|
|
174
236
|
surfaceCase: { stroke: "#000000", strokeWidth: 4 },
|
|
175
|
-
holeFill: { stroke: "#303030", strokeWidth: 2 },
|
|
237
|
+
holeFill: { stroke: "#303030", strokeWidth: 1.2 },
|
|
176
238
|
wellCase: { fill: "#ffffff", stroke: "#303030", strokeWidth: 2 },
|
|
177
|
-
wellScreen: {
|
|
239
|
+
wellScreen: {
|
|
240
|
+
stroke: "#303030",
|
|
241
|
+
strokeWidth: 2,
|
|
242
|
+
endStrokeWidth: 0.75,
|
|
243
|
+
endDasharray: "3, 2"
|
|
244
|
+
},
|
|
178
245
|
reduction: { fill: "#ffffff", stroke: "#303030", strokeWidth: 2 },
|
|
246
|
+
centralizer: { fill: "none", stroke: "#303030", strokeWidth: 1.4 },
|
|
247
|
+
pump: {
|
|
248
|
+
fill: "#5b6b7a",
|
|
249
|
+
stroke: "#202020",
|
|
250
|
+
strokeWidth: 1.2,
|
|
251
|
+
riserFill: "#a3adb7",
|
|
252
|
+
riserStroke: "#2f3a44",
|
|
253
|
+
riserStrokeWidth: 1
|
|
254
|
+
},
|
|
179
255
|
conflict: { stroke: "#e52117", strokeWidth: 4 },
|
|
180
256
|
unitLabels: {
|
|
181
257
|
geologicFill: "#f0f0f0",
|
|
@@ -211,6 +287,39 @@ var DEFAULT_WELL_THEME = {
|
|
|
211
287
|
headerFontWeight: 600,
|
|
212
288
|
bodyFontWeight: 400
|
|
213
289
|
},
|
|
290
|
+
overview: {
|
|
291
|
+
stroke: "#303030",
|
|
292
|
+
strokeWidth: 0.5,
|
|
293
|
+
emptyFill: "#d9d9d9",
|
|
294
|
+
windowStroke: "#c0392b",
|
|
295
|
+
windowStrokeWidth: 1.2
|
|
296
|
+
},
|
|
297
|
+
columnHeaders: {
|
|
298
|
+
fontSize: 6.5,
|
|
299
|
+
color: "#303030",
|
|
300
|
+
fontFamily: "sans-serif",
|
|
301
|
+
fontWeight: 600,
|
|
302
|
+
ruleStroke: "#101010",
|
|
303
|
+
ruleStrokeWidth: 1
|
|
304
|
+
},
|
|
305
|
+
markers: {
|
|
306
|
+
fill: "#ffffff",
|
|
307
|
+
stroke: "#101010",
|
|
308
|
+
strokeWidth: 0.6,
|
|
309
|
+
color: "#101010",
|
|
310
|
+
fontSize: 6,
|
|
311
|
+
fontFamily: "sans-serif",
|
|
312
|
+
fontWeight: 600
|
|
313
|
+
},
|
|
314
|
+
overlap: {
|
|
315
|
+
stroke: "#9a9a9a",
|
|
316
|
+
strokeWidth: 0.6,
|
|
317
|
+
size: 6,
|
|
318
|
+
ruleStroke: "#9a9a9a",
|
|
319
|
+
labelColor: "#555555",
|
|
320
|
+
fontSize: 6.5,
|
|
321
|
+
fontFamily: "monospace"
|
|
322
|
+
},
|
|
214
323
|
legend: {
|
|
215
324
|
borderStrokeWidth: 0.8,
|
|
216
325
|
fractureStrokeWidth: 1.5,
|
|
@@ -268,8 +377,17 @@ var STATIC_RENDER_CONFIG = {
|
|
|
268
377
|
}
|
|
269
378
|
},
|
|
270
379
|
construction: {
|
|
271
|
-
cementPad: {
|
|
272
|
-
|
|
380
|
+
cementPad: { widthRatio: 1.4, height: 6 },
|
|
381
|
+
casingShoe: { active: true, size: 4 },
|
|
382
|
+
screenEnds: { active: true },
|
|
383
|
+
surfaceCase: { diameterPaddingRatio: 0.1 },
|
|
384
|
+
centralizer: { markerHalfHeight: 4 },
|
|
385
|
+
pump: {
|
|
386
|
+
active: true,
|
|
387
|
+
bodyHeight: 22,
|
|
388
|
+
bodyWidthRatio: 0.6,
|
|
389
|
+
riserWidthRatio: 0.3
|
|
390
|
+
}
|
|
273
391
|
},
|
|
274
392
|
tooltipLabels: resolveTooltipLabels("pt"),
|
|
275
393
|
labels: {
|
|
@@ -282,7 +400,11 @@ var STATIC_RENDER_CONFIG = {
|
|
|
282
400
|
stackingLineHeight: 10,
|
|
283
401
|
stackingGap: 0,
|
|
284
402
|
fractureLabelLeaderGap: 5,
|
|
285
|
-
lithology: true
|
|
403
|
+
lithology: true,
|
|
404
|
+
continuation: {
|
|
405
|
+
active: false,
|
|
406
|
+
prefix: resolveRenderLabel(RENDER_LABELS.continuation.prefix, "pt")
|
|
407
|
+
}
|
|
286
408
|
},
|
|
287
409
|
unitLabels: {
|
|
288
410
|
active: true,
|
|
@@ -340,10 +462,22 @@ var STATIC_RENDER_CONFIG = {
|
|
|
340
462
|
wellCase: "Revestimento",
|
|
341
463
|
wellScreen: "Filtro",
|
|
342
464
|
reduction: "Redu\xE7\xE3o",
|
|
465
|
+
centralizer: "Centralizador",
|
|
466
|
+
pump: "Bomba e edutor",
|
|
343
467
|
cementPad: "Laje de cimento",
|
|
344
468
|
conflict: "Conflito"
|
|
345
469
|
}
|
|
346
470
|
},
|
|
471
|
+
overview: { active: false, x: 4, width: 8, height: 200 },
|
|
472
|
+
columnHeaders: {
|
|
473
|
+
active: false,
|
|
474
|
+
height: 14,
|
|
475
|
+
labels: resolveGroup(RENDER_LABELS.columnHeaders, "pt")
|
|
476
|
+
},
|
|
477
|
+
markers: { lithology: false, fractures: false, radius: 4.5 },
|
|
478
|
+
overlap: {
|
|
479
|
+
label: resolveRenderLabel(RENDER_LABELS.overlap.label, "pt")
|
|
480
|
+
},
|
|
347
481
|
highlights: DEFAULT_HIGHLIGHT_CONFIG
|
|
348
482
|
};
|
|
349
483
|
var INTERACTIVE_RENDER_CONFIG = {
|
|
@@ -379,8 +513,17 @@ var INTERACTIVE_RENDER_CONFIG = {
|
|
|
379
513
|
}
|
|
380
514
|
},
|
|
381
515
|
construction: {
|
|
382
|
-
cementPad: {
|
|
383
|
-
|
|
516
|
+
cementPad: { widthRatio: 1.4, height: 6 },
|
|
517
|
+
casingShoe: { active: true, size: 4 },
|
|
518
|
+
screenEnds: { active: true },
|
|
519
|
+
surfaceCase: { diameterPaddingRatio: 0.1 },
|
|
520
|
+
centralizer: { markerHalfHeight: 4 },
|
|
521
|
+
pump: {
|
|
522
|
+
active: true,
|
|
523
|
+
bodyHeight: 22,
|
|
524
|
+
bodyWidthRatio: 0.6,
|
|
525
|
+
riserWidthRatio: 0.3
|
|
526
|
+
}
|
|
384
527
|
},
|
|
385
528
|
tooltipLabels: resolveTooltipLabels("pt"),
|
|
386
529
|
labels: {
|
|
@@ -391,7 +534,11 @@ var INTERACTIVE_RENDER_CONFIG = {
|
|
|
391
534
|
descriptionXOffset: 78,
|
|
392
535
|
descriptionMaxWidth: 226,
|
|
393
536
|
stackingLineHeight: 11,
|
|
394
|
-
stackingGap: 0
|
|
537
|
+
stackingGap: 0,
|
|
538
|
+
continuation: {
|
|
539
|
+
active: false,
|
|
540
|
+
prefix: resolveRenderLabel(RENDER_LABELS.continuation.prefix, "pt")
|
|
541
|
+
}
|
|
395
542
|
},
|
|
396
543
|
unitLabels: {
|
|
397
544
|
active: false,
|
|
@@ -448,19 +595,25 @@ var INTERACTIVE_RENDER_CONFIG = {
|
|
|
448
595
|
wellCase: "Revestimento",
|
|
449
596
|
wellScreen: "Filtro",
|
|
450
597
|
reduction: "Redu\xE7\xE3o",
|
|
598
|
+
centralizer: "Centralizador",
|
|
599
|
+
pump: "Bomba e edutor",
|
|
451
600
|
cementPad: "Laje de cimento",
|
|
452
601
|
conflict: "Conflito"
|
|
453
602
|
}
|
|
454
603
|
},
|
|
604
|
+
overview: { active: false, x: 4, width: 8, height: 200 },
|
|
605
|
+
columnHeaders: {
|
|
606
|
+
active: false,
|
|
607
|
+
height: 14,
|
|
608
|
+
labels: resolveGroup(RENDER_LABELS.columnHeaders, "pt")
|
|
609
|
+
},
|
|
610
|
+
markers: { lithology: false, fractures: false, radius: 4.5 },
|
|
611
|
+
overlap: {
|
|
612
|
+
label: resolveRenderLabel(RENDER_LABELS.overlap.label, "pt")
|
|
613
|
+
},
|
|
455
614
|
highlights: DEFAULT_HIGHLIGHT_CONFIG
|
|
456
615
|
};
|
|
457
616
|
|
|
458
|
-
// src/utils/fgdcTextures.ts
|
|
459
|
-
async function importFgdcTextures() {
|
|
460
|
-
const fgdcTextures = await import("./fgdcTextures-P5DTFNPT.js");
|
|
461
|
-
return fgdcTextures.default;
|
|
462
|
-
}
|
|
463
|
-
|
|
464
617
|
// src/Renderer.ts
|
|
465
618
|
import * as d3module2 from "d3";
|
|
466
619
|
import d3tip2 from "d3-tip";
|
|
@@ -468,6 +621,8 @@ import { defu as defu2 } from "defu";
|
|
|
468
621
|
|
|
469
622
|
// src/configs/render.textures.ts
|
|
470
623
|
import textures from "textures";
|
|
624
|
+
var dot = (x, y, r) => `M${x - r},${y}a${r},${r} 0 1,0 ${2 * r},0a${r},${r} 0 1,0 ${-2 * r},0Z`;
|
|
625
|
+
var concreteAggregate = (s) => `M${s * 0.08},${s * 0.42}l${s * 0.3},0l${-s * 0.12},${-s * 0.26}ZM${s * 0.55},${s * 0.92}l${s * 0.26},${-s * 0.06}l${-s * 0.16},${-s * 0.2}Z${dot(s * 0.72, s * 0.24, s * 0.06)}${dot(s * 0.22, s * 0.78, s * 0.05)}`;
|
|
471
626
|
function createWellTextures(cfg) {
|
|
472
627
|
const pad = {
|
|
473
628
|
background: "#ffffff",
|
|
@@ -515,7 +670,9 @@ function createWellTextures(cfg) {
|
|
|
515
670
|
...cfg?.surface_case
|
|
516
671
|
};
|
|
517
672
|
return {
|
|
518
|
-
|
|
673
|
+
// Concrete: aggregate (small triangles and dots) on a light ground, so it
|
|
674
|
+
// reads apart from the seal's diagonals and the gravel pack's circles.
|
|
675
|
+
pad: textures.paths().d(concreteAggregate).size(6).strokeWidth(0.4).stroke(pad.stroke).fill(pad.stroke).background(pad.background),
|
|
519
676
|
conflict: textures.lines().heavier().stroke(conflict.stroke),
|
|
520
677
|
cave_dry: textures.lines().size(cave_dry.size).orientation("6/8").heavier(0.3).thinner(0.8).background(cave_dry.background).stroke(cave_dry.stroke),
|
|
521
678
|
cave_wet: textures.lines().size(cave_wet.size).orientation("6/8").heavier(0.3).thinner(0.8).background(cave_wet.background).stroke(cave_wet.stroke),
|
|
@@ -531,8 +688,8 @@ import {
|
|
|
531
688
|
isWellEmpty
|
|
532
689
|
} from "@welldot/core";
|
|
533
690
|
import {
|
|
534
|
-
formatNumber as
|
|
535
|
-
|
|
691
|
+
formatNumber as formatNumber4,
|
|
692
|
+
getCurrentPump as getCurrentPump2,
|
|
536
693
|
getProfileLastItemsDepths
|
|
537
694
|
} from "@welldot/utils";
|
|
538
695
|
|
|
@@ -592,6 +749,14 @@ var DEFAULT_COMPONENTS_CLASS_NAMES = {
|
|
|
592
749
|
group: "well-screen",
|
|
593
750
|
rect: "well-screen-rect"
|
|
594
751
|
},
|
|
752
|
+
centralizer: {
|
|
753
|
+
group: "centralizer",
|
|
754
|
+
item: "centralizer-marker"
|
|
755
|
+
},
|
|
756
|
+
pump: {
|
|
757
|
+
group: "pump",
|
|
758
|
+
item: "pump-item"
|
|
759
|
+
},
|
|
595
760
|
reduction: {
|
|
596
761
|
group: "reduction",
|
|
597
762
|
item: "reduction-poly"
|
|
@@ -623,6 +788,26 @@ var DEFAULT_COMPONENTS_CLASS_NAMES = {
|
|
|
623
788
|
caveFill: "cave-fill",
|
|
624
789
|
constructionRect: "construction-rect"
|
|
625
790
|
},
|
|
791
|
+
overview: {
|
|
792
|
+
group: "wp-overview",
|
|
793
|
+
item: "wp-overview-item",
|
|
794
|
+
window: "wp-overview-window"
|
|
795
|
+
},
|
|
796
|
+
columnHeaders: {
|
|
797
|
+
group: "wp-column-headers",
|
|
798
|
+
text: "wp-column-header",
|
|
799
|
+
rule: "wp-column-headers-rule"
|
|
800
|
+
},
|
|
801
|
+
markers: {
|
|
802
|
+
group: "wp-markers",
|
|
803
|
+
lithology: "wp-marker-lithology",
|
|
804
|
+
fracture: "wp-marker-fracture"
|
|
805
|
+
},
|
|
806
|
+
overlap: {
|
|
807
|
+
group: "wp-overlap",
|
|
808
|
+
band: "wp-overlap-band",
|
|
809
|
+
label: "wp-overlap-label"
|
|
810
|
+
},
|
|
626
811
|
highlights: {
|
|
627
812
|
geologicGroup: "wp-highlights-geologic",
|
|
628
813
|
constructionGroup: "wp-highlights-construction",
|
|
@@ -637,6 +822,156 @@ var DEFAULT_COMPONENTS_CLASS_NAMES = {
|
|
|
637
822
|
// src/utils/render.utils.ts
|
|
638
823
|
import textures2 from "textures";
|
|
639
824
|
|
|
825
|
+
// src/utils/construction.geometry.ts
|
|
826
|
+
var JOINT_EPS = 1e-3;
|
|
827
|
+
function diameterAt(items, depth) {
|
|
828
|
+
return items.find((i) => depth >= i.from && depth <= i.to)?.diameter;
|
|
829
|
+
}
|
|
830
|
+
function getIntervalEnds(item, string, depthFrom, depthTo) {
|
|
831
|
+
return {
|
|
832
|
+
cutTop: item.from < depthFrom - JOINT_EPS,
|
|
833
|
+
cutBottom: item.to > depthTo + JOINT_EPS,
|
|
834
|
+
joinedTop: string.some(
|
|
835
|
+
(o) => o !== item && Math.abs(o.to - item.from) < JOINT_EPS
|
|
836
|
+
),
|
|
837
|
+
joinedBottom: string.some(
|
|
838
|
+
(o) => o !== item && Math.abs(o.from - item.to) < JOINT_EPS
|
|
839
|
+
)
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
function pipeWallsPath(xLeft, xRight, yTop, yBottom) {
|
|
843
|
+
return `M${xLeft},${yTop}V${yBottom}M${xRight},${yTop}V${yBottom}`;
|
|
844
|
+
}
|
|
845
|
+
function shoePath(xLeft, xRight, y, size) {
|
|
846
|
+
return `M${xLeft},${y - size}L${xLeft},${y}L${xLeft - size},${y}ZM${xRight},${y - size}L${xRight},${y}L${xRight + size},${y}Z`;
|
|
847
|
+
}
|
|
848
|
+
function screenEndPath(xLeft, xRight, y) {
|
|
849
|
+
return `M${xLeft},${y}H${xRight}`;
|
|
850
|
+
}
|
|
851
|
+
var clampDepth = (s, depth) => Math.min(Math.max(depth, s.depthFrom), s.depthTo);
|
|
852
|
+
var inPanel = (s, depth) => depth >= s.depthFrom - JOINT_EPS && depth <= s.depthTo + JOINT_EPS;
|
|
853
|
+
var shoulders = (s, a, b, y) => `M${s.left(a)},${y}H${s.left(b)}M${s.right(a)},${y}H${s.right(b)}`;
|
|
854
|
+
function boreHoleOutlinePath(item, holes, s) {
|
|
855
|
+
const yTop = s.y(clampDepth(s, item.from));
|
|
856
|
+
const yBottom = s.y(clampDepth(s, item.to));
|
|
857
|
+
let d = pipeWallsPath(
|
|
858
|
+
s.left(item.diameter),
|
|
859
|
+
s.right(item.diameter),
|
|
860
|
+
yTop,
|
|
861
|
+
yBottom
|
|
862
|
+
);
|
|
863
|
+
if (item.from > JOINT_EPS && inPanel(s, item.from)) {
|
|
864
|
+
const above = holes.find(
|
|
865
|
+
(o) => o !== item && o.from < item.from && o.to >= item.from - JOINT_EPS
|
|
866
|
+
);
|
|
867
|
+
if (above && above.diameter < item.diameter)
|
|
868
|
+
d += shoulders(s, above.diameter, item.diameter, yTop);
|
|
869
|
+
}
|
|
870
|
+
if (inPanel(s, item.to)) {
|
|
871
|
+
const below = holes.find(
|
|
872
|
+
(o) => o !== item && o.from <= item.to + JOINT_EPS && o.to > item.to
|
|
873
|
+
);
|
|
874
|
+
if (!below) {
|
|
875
|
+
d += `M${s.left(item.diameter)},${yBottom}H${s.right(item.diameter)}`;
|
|
876
|
+
} else if (below.diameter < item.diameter) {
|
|
877
|
+
d += shoulders(s, item.diameter, below.diameter, yBottom);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
return d;
|
|
881
|
+
}
|
|
882
|
+
function holeFillOutlinePath(item, pipes, s) {
|
|
883
|
+
const yTop = s.y(clampDepth(s, item.from));
|
|
884
|
+
const yBottom = s.y(clampDepth(s, item.to));
|
|
885
|
+
const xL = s.left(item.diameter);
|
|
886
|
+
const xR = s.right(item.diameter);
|
|
887
|
+
let d = pipeWallsPath(xL, xR, yTop, yBottom);
|
|
888
|
+
const interfaces = [item.from, item.to].filter(
|
|
889
|
+
(depth) => depth > JOINT_EPS && inPanel(s, depth)
|
|
890
|
+
);
|
|
891
|
+
for (const depth of interfaces) {
|
|
892
|
+
const y = s.y(depth);
|
|
893
|
+
const pipe = diameterAt(pipes, depth);
|
|
894
|
+
if (pipe !== void 0 && pipe < item.diameter) {
|
|
895
|
+
d += `M${xL},${y}H${s.left(pipe)}M${s.right(pipe)},${y}H${xR}`;
|
|
896
|
+
} else {
|
|
897
|
+
d += `M${xL},${y}H${xR}`;
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
return d;
|
|
901
|
+
}
|
|
902
|
+
function pipeSlices(pipes, from, to) {
|
|
903
|
+
const cuts = [.../* @__PURE__ */ new Set([from, to, ...pipes.flatMap((p) => [p.from, p.to])])].filter((d) => d >= from && d <= to).sort((a, b) => a - b);
|
|
904
|
+
const slices = [];
|
|
905
|
+
for (let i = 1; i < cuts.length; i++) {
|
|
906
|
+
const a = cuts[i - 1];
|
|
907
|
+
const b = cuts[i];
|
|
908
|
+
const mid = (a + b) / 2;
|
|
909
|
+
const widest = Math.max(
|
|
910
|
+
0,
|
|
911
|
+
...pipes.filter((p) => p.from <= mid && p.to >= mid).map((p) => p.diameter)
|
|
912
|
+
);
|
|
913
|
+
if (widest === 0) continue;
|
|
914
|
+
const last = slices[slices.length - 1];
|
|
915
|
+
if (last && last.to === a && last.diameter === widest) last.to = b;
|
|
916
|
+
else slices.push({ from: a, to: b, diameter: widest });
|
|
917
|
+
}
|
|
918
|
+
return slices;
|
|
919
|
+
}
|
|
920
|
+
function annulusFillPath(item, pipes, s) {
|
|
921
|
+
const from = clampDepth(s, item.from);
|
|
922
|
+
const to = clampDepth(s, item.to);
|
|
923
|
+
const box = (dia, a, b) => `M${s.left(dia)},${s.y(a)}H${s.right(dia)}V${s.y(b)}H${s.left(dia)}Z`;
|
|
924
|
+
const inner = pipes.filter((p) => p.diameter < item.diameter);
|
|
925
|
+
return box(item.diameter, from, to) + pipeSlices(inner, from, to).map((p) => box(p.diameter, p.from, p.to)).join("");
|
|
926
|
+
}
|
|
927
|
+
function getPadDiameters(data, surfaceCasePaddingRatio) {
|
|
928
|
+
const surfaceCase = diameterAt(data.surface_case, 0);
|
|
929
|
+
const paddedSurfaceCase = surfaceCase === void 0 ? void 0 : surfaceCase * (1 + surfaceCasePaddingRatio);
|
|
930
|
+
const casing = diameterAt([...data.well_case, ...data.well_screen], 0);
|
|
931
|
+
const hole = diameterAt(data.bore_hole, 0);
|
|
932
|
+
const opening = casing ?? paddedSurfaceCase ?? hole ?? 0;
|
|
933
|
+
const outer = Math.max(
|
|
934
|
+
opening,
|
|
935
|
+
paddedSurfaceCase ?? 0,
|
|
936
|
+
hole ?? 0,
|
|
937
|
+
diameterAt(data.hole_fill, 0) ?? 0
|
|
938
|
+
);
|
|
939
|
+
return { opening, outer };
|
|
940
|
+
}
|
|
941
|
+
function getCementPadGeometry(pocoWidth, pocoCenter, surfaceY, config, openingWidth = 0, outerWidth = openingWidth) {
|
|
942
|
+
const h = config.height;
|
|
943
|
+
const opening = Math.max(0, openingWidth);
|
|
944
|
+
const width = Math.max(
|
|
945
|
+
pocoWidth * config.widthRatio,
|
|
946
|
+
opening + 3 * h,
|
|
947
|
+
outerWidth + 2 * h
|
|
948
|
+
);
|
|
949
|
+
const xLeft = (pocoCenter - width) / 2;
|
|
950
|
+
const xRight = xLeft + width;
|
|
951
|
+
const oLeft = (pocoCenter - opening) / 2;
|
|
952
|
+
const oRight = oLeft + opening;
|
|
953
|
+
const yTop = surfaceY - h;
|
|
954
|
+
const a = h * 0.3;
|
|
955
|
+
const breakLine = (x, y0, y1, dir) => `L${x + dir * a},${y0 + (y1 - y0) * 0.4}L${x - dir * a},${y0 + (y1 - y0) * 0.6}L${x},${y1}`;
|
|
956
|
+
const bbox = { x: xLeft, y: yTop, width, height: h };
|
|
957
|
+
if (opening === 0) {
|
|
958
|
+
return {
|
|
959
|
+
bbox,
|
|
960
|
+
slabs: [
|
|
961
|
+
`M${xLeft},${yTop}H${xRight}${breakLine(xRight, yTop, surfaceY, 1)}H${xLeft}${breakLine(xLeft, surfaceY, yTop, -1)}Z`,
|
|
962
|
+
""
|
|
963
|
+
]
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
return {
|
|
967
|
+
bbox,
|
|
968
|
+
slabs: [
|
|
969
|
+
`M${oLeft},${yTop}H${xLeft}${breakLine(xLeft, yTop, surfaceY, -1)}H${oLeft}Z`,
|
|
970
|
+
`M${oRight},${yTop}H${xRight}${breakLine(xRight, yTop, surfaceY, 1)}H${oRight}Z`
|
|
971
|
+
]
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
|
|
640
975
|
// src/utils/d3.utils.ts
|
|
641
976
|
function mergeEnter(enter, update) {
|
|
642
977
|
return enter.merge(update);
|
|
@@ -707,6 +1042,14 @@ var makeSeededPrng = (seed, scramble = 6271) => {
|
|
|
707
1042
|
// src/utils/tooltips.utils.ts
|
|
708
1043
|
import d3tip from "d3-tip";
|
|
709
1044
|
import sanitizeHtml from "sanitize-html";
|
|
1045
|
+
import {
|
|
1046
|
+
CEMENT_PAD_TYPES,
|
|
1047
|
+
CENTRALIZER_TYPES,
|
|
1048
|
+
CONSTRUCTION_MATERIALS,
|
|
1049
|
+
SCREEN_SLOT_TYPES,
|
|
1050
|
+
getVocabLabel,
|
|
1051
|
+
powerFromCanonical
|
|
1052
|
+
} from "@welldot/core";
|
|
710
1053
|
import { formatNumber as formatNumber2 } from "@welldot/utils";
|
|
711
1054
|
var esc = (v) => sanitizeHtml(String(v ?? ""), { allowedTags: [], allowedAttributes: {} });
|
|
712
1055
|
var _tooltipCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -717,6 +1060,7 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
717
1060
|
if (cached && cached.signature === signature) {
|
|
718
1061
|
return cached.tooltips;
|
|
719
1062
|
}
|
|
1063
|
+
const material = (value) => getVocabLabel(CONSTRUCTION_MATERIALS, value, locale);
|
|
720
1064
|
const tipsText = {
|
|
721
1065
|
geology: (_, d) => `
|
|
722
1066
|
<span class="${customClasses.tooltip.title}">${labels.geology.title}</span>
|
|
@@ -749,14 +1093,15 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
749
1093
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
750
1094
|
<strong>${labels.common.diameter}</strong> ${esc(formatDiameter(d.diameter, units.diameter, locale))} ${esc(getDiameterUnit(units.diameter, locale))}
|
|
751
1095
|
</span>
|
|
752
|
-
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(d.type)}</span>
|
|
1096
|
+
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(material(d.type))}</span>
|
|
753
1097
|
`,
|
|
754
1098
|
wellScreen: (_, d) => `
|
|
755
1099
|
<span class="${customClasses.tooltip.title}">${labels.wellScreen.title}</span>
|
|
756
1100
|
<span class="${customClasses.tooltip.primaryInfo}">${labels.common.from} ${esc(formatLength(d.from, units.length, locale))} ${esc(getLengthUnit(units.length))} ${labels.common.to} ${esc(formatLength(d.to, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>
|
|
757
1101
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
758
1102
|
<strong>${labels.common.diameter}</strong> ${esc(formatDiameter(d.diameter, units.diameter, locale))} ${esc(getDiameterUnit(units.diameter, locale))}</span>
|
|
759
|
-
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.
|
|
1103
|
+
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.wellScreen.material}</strong> ${esc(material(d.type))}</span>
|
|
1104
|
+
${d.slot_type ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.wellScreen.slotType}</strong> ${esc(getVocabLabel(SCREEN_SLOT_TYPES, d.slot_type, locale))}</span>` : ""}
|
|
760
1105
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
761
1106
|
<strong>${labels.wellScreen.slot}</strong> ${esc(formatNumber2(d.screen_slot, { maximumFractionDigits: 2, locale }))} mm
|
|
762
1107
|
</span>
|
|
@@ -767,8 +1112,29 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
767
1112
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
768
1113
|
<strong>${labels.common.diameter}</strong> ${esc(formatDiameter(d.diam_from, units.diameter, locale))} \u2192 ${esc(formatDiameter(d.diam_to, units.diameter, locale))} ${esc(getDiameterUnit(units.diameter, locale))}
|
|
769
1114
|
</span>
|
|
770
|
-
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(d.type)}</span>
|
|
1115
|
+
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(material(d.type))}</span>
|
|
771
1116
|
`,
|
|
1117
|
+
centralizer: (_, d) => `
|
|
1118
|
+
<span class="${customClasses.tooltip.title}">${labels.centralizer.title}</span>
|
|
1119
|
+
<span class="${customClasses.tooltip.primaryInfo}"><strong>${labels.centralizer.depth}</strong> ${esc(formatLength(d.depth, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>
|
|
1120
|
+
${d.from !== d.to ? `<span class="${customClasses.tooltip.secondaryInfo}">${labels.common.from} ${esc(formatLength(d.from, units.length, locale))} ${esc(getLengthUnit(units.length))} ${labels.common.to} ${esc(formatLength(d.to, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>` : ""}
|
|
1121
|
+
${d.spacing ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.centralizer.spacing}</strong> ${esc(formatLength(d.spacing, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>` : ""}
|
|
1122
|
+
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(getVocabLabel(CENTRALIZER_TYPES, d.type, locale))}</span>
|
|
1123
|
+
${d.diameter ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.diameter}</strong> ${esc(formatDiameter(d.diameter, units.diameter, locale))} ${esc(getDiameterUnit(units.diameter, locale))}</span>` : ""}
|
|
1124
|
+
${d.description ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.description}</strong> ${esc(d.description)}</span>` : ""}
|
|
1125
|
+
`,
|
|
1126
|
+
pump: (_, d) => {
|
|
1127
|
+
const typeLabel = labels.pump[`type_${d.type}`] ?? d.type;
|
|
1128
|
+
const model = [d.manufacturer, d.model].filter(Boolean).join(" ");
|
|
1129
|
+
return `
|
|
1130
|
+
<span class="${customClasses.tooltip.title}">${labels.pump.title}</span>
|
|
1131
|
+
<span class="${customClasses.tooltip.primaryInfo}">${esc(typeLabel)}</span>
|
|
1132
|
+
${d.intake_depth !== void 0 ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.pump.intakeDepth}</strong> ${esc(formatLength(d.intake_depth, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>` : ""}
|
|
1133
|
+
${model ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.pump.model}</strong> ${esc(model)}</span>` : ""}
|
|
1134
|
+
${d.rated_power !== void 0 ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.pump.power}</strong> ${esc(formatNumber2(powerFromCanonical(d.rated_power, units.power ?? "kW"), { maximumFractionDigits: 2, locale }))} ${esc(units.power ?? "kW")}</span>` : ""}
|
|
1135
|
+
${d.riser_diameter !== void 0 ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.pump.riser}</strong> ${esc(formatDiameter(d.riser_diameter, units.diameter, locale))} ${esc(getDiameterUnit(units.diameter, locale))}${d.riser_material ? ` \xB7 ${esc(material(d.riser_material))}` : ""}</span>` : ""}
|
|
1136
|
+
`;
|
|
1137
|
+
},
|
|
772
1138
|
conflict: (_, d) => `
|
|
773
1139
|
<span class="${customClasses.tooltip.title}">${labels.conflict.title}</span>
|
|
774
1140
|
<span class="${customClasses.tooltip.primaryInfo}">${labels.common.from} ${esc(formatLength(d.from, units.length, locale))} ${esc(getLengthUnit(units.length))} ${labels.common.to} ${esc(formatLength(d.to, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>
|
|
@@ -779,14 +1145,14 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
779
1145
|
<span class="${customClasses.tooltip.title}">${title}</span>
|
|
780
1146
|
<span class="${customClasses.tooltip.primaryInfo}"><strong>${labels.fracture.depth}</strong> ${esc(formatLength(d.depth, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>
|
|
781
1147
|
${d.water_intake ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.fracture.waterIntake}</strong> ${esc(formatLength(d.depth, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>` : ""}
|
|
782
|
-
|
|
783
|
-
|
|
1148
|
+
${typeof d.dip === "number" ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.fracture.dip}</strong> ${esc(d.dip)}\xB0</span>` : ""}
|
|
1149
|
+
${typeof d.azimuth === "number" ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.fracture.azimuth}</strong> ${esc(d.azimuth)}\xB0</span>` : ""}
|
|
784
1150
|
${d.description ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.description}</strong> ${esc(d.description)}</span>` : ""}
|
|
785
1151
|
`;
|
|
786
1152
|
},
|
|
787
1153
|
cementPad: (_, d) => `
|
|
788
1154
|
<span class="${customClasses.tooltip.title}">${labels.cementPad.title}</span>
|
|
789
|
-
<span class="${customClasses.tooltip.primaryInfo}">${esc(d.type)}</span>
|
|
1155
|
+
<span class="${customClasses.tooltip.primaryInfo}">${esc(getVocabLabel(CEMENT_PAD_TYPES, d.type, locale))}</span>
|
|
790
1156
|
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.cementPad.thickness}</strong>
|
|
791
1157
|
${esc(formatLength(d.thickness, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>
|
|
792
1158
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
@@ -824,6 +1190,17 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
824
1190
|
};
|
|
825
1191
|
|
|
826
1192
|
// src/utils/render.utils.ts
|
|
1193
|
+
var fractureDip = (dip) => typeof dip === "number" && Number.isFinite(dip) ? dip : 0;
|
|
1194
|
+
function getCementPadRect(pocoWidth, pocoCenter, surfaceY, config, openingWidth = 0, outerWidth = openingWidth) {
|
|
1195
|
+
return getCementPadGeometry(
|
|
1196
|
+
pocoWidth,
|
|
1197
|
+
pocoCenter,
|
|
1198
|
+
surfaceY,
|
|
1199
|
+
config,
|
|
1200
|
+
openingWidth,
|
|
1201
|
+
outerWidth
|
|
1202
|
+
).bbox;
|
|
1203
|
+
}
|
|
827
1204
|
var _fgdcTextures = {};
|
|
828
1205
|
var _fgdcTexturesPromise = null;
|
|
829
1206
|
var preloadFgdcTextures = () => {
|
|
@@ -932,14 +1309,23 @@ function drawAnnotationLabels(ctx, data) {
|
|
|
932
1309
|
}
|
|
933
1310
|
const items = [];
|
|
934
1311
|
if (active.has("lithology")) {
|
|
1312
|
+
const continuation = s.continuation;
|
|
935
1313
|
data.lithology.filter((d) => d.from < ctx.depthTo).forEach((d) => {
|
|
1314
|
+
const range = `${formatLength(d.from, ctx.units.length, ctx.locale)}\u2013${formatLength(d.to, ctx.units.length, ctx.locale)}${getLengthUnit(ctx.units.length)}`;
|
|
1315
|
+
const continues = continuation?.active && d.from < ctx.depthFrom;
|
|
936
1316
|
items.push({
|
|
937
1317
|
sortDepth: d.from,
|
|
938
1318
|
baseY: ctx.yScale(Math.max(d.from, ctx.depthFrom)),
|
|
939
1319
|
originX: ctx.geoXRight,
|
|
940
1320
|
originY: ctx.yScale(Math.max(d.from, ctx.depthFrom)),
|
|
941
|
-
header:
|
|
942
|
-
description: d.description || ""
|
|
1321
|
+
header: continues ? `\u2191 ${continuation.prefix} \xB7 ${range}` : range,
|
|
1322
|
+
description: continues ? "" : d.description || "",
|
|
1323
|
+
...show.has("units") ? {
|
|
1324
|
+
unit: d.geologic_unit || void 0,
|
|
1325
|
+
aquifer: continues ? void 0 : d.aquifer_unit || void 0
|
|
1326
|
+
} : {},
|
|
1327
|
+
...show.has("swatch") && !continues ? { swatch: d } : {},
|
|
1328
|
+
...show.has("rules") ? { rule: continues ? "dashed" : "solid" } : {}
|
|
943
1329
|
});
|
|
944
1330
|
});
|
|
945
1331
|
}
|
|
@@ -952,7 +1338,8 @@ function drawAnnotationLabels(ctx, data) {
|
|
|
952
1338
|
originX: ctx.pocoCenterX,
|
|
953
1339
|
originY: ctx.yScale(d.depth),
|
|
954
1340
|
header: `${formatLength(d.depth, ctx.units.length, ctx.locale)}${getLengthUnit(ctx.units.length)} \xB7 ${typeLabel}`,
|
|
955
|
-
description: d.description || ""
|
|
1341
|
+
description: d.description || "",
|
|
1342
|
+
...show.has("rules") ? { rule: "dashed" } : {}
|
|
956
1343
|
});
|
|
957
1344
|
});
|
|
958
1345
|
}
|
|
@@ -972,14 +1359,15 @@ function drawAnnotationLabels(ctx, data) {
|
|
|
972
1359
|
}
|
|
973
1360
|
items.sort((a, b) => a.sortDepth - b.sortDepth);
|
|
974
1361
|
const labelPositions = [];
|
|
975
|
-
let currY = 0;
|
|
1362
|
+
let currY = ctx.repeatedTo != null ? s.stackingLineHeight + 2 : 0;
|
|
976
1363
|
const charsPerLine = Math.max(
|
|
977
1364
|
1,
|
|
978
1365
|
Math.floor(s.descriptionMaxWidth / (st.fontSize * 0.6))
|
|
979
1366
|
);
|
|
980
1367
|
items.forEach((item) => {
|
|
981
|
-
const descLines = Math.ceil((item.description.length || 1) / charsPerLine);
|
|
982
|
-
const
|
|
1368
|
+
const descLines = show.has("units") ? item.description ? wrapText(item.description, charsPerLine).length : 0 : Math.ceil((item.description.length || 1) / charsPerLine);
|
|
1369
|
+
const extraLines = (item.unit ? 1 : 0) + (item.aquifer ? 1 : 0);
|
|
1370
|
+
const estH = (1 + descLines + extraLines) * s.stackingLineHeight + 4;
|
|
983
1371
|
const yLabel = Math.max(item.baseY, currY + s.stackingGap);
|
|
984
1372
|
currY = yLabel + estH;
|
|
985
1373
|
labelPositions.push({ item, yLabel, estH });
|
|
@@ -996,16 +1384,41 @@ function drawAnnotationLabels(ctx, data) {
|
|
|
996
1384
|
if (show.has("description")) {
|
|
997
1385
|
const lineH = s.stackingLineHeight;
|
|
998
1386
|
const bgFill = st.annotationBg ?? "white";
|
|
1387
|
+
const swatchFill = labelPositions.some((p) => p.item.swatch) ? getLithologyFill(data.lithology, ctx.svg, ctx.theme.lithologyTexture) : null;
|
|
999
1388
|
labelPositions.forEach(({ item, yLabel, estH }) => {
|
|
1000
1389
|
const labelG = ctx.groups.lithologyLabelsGroup.append("g").attr("class", ctx.classes.labels.lithology.label).attr("transform", `translate(${labelX},${yLabel})`);
|
|
1001
1390
|
labelG.append("rect").attr("x", 0).attr("y", 0).attr("width", s.descriptionMaxWidth).attr("height", estH).attr("rx", st.annotationRadius ?? 2).attr("fill", bgFill).attr("fill-opacity", st.annotationBgOpacity ?? 0.85).attr("stroke", st.annotationBorderColor ?? "none");
|
|
1002
|
-
|
|
1391
|
+
if (item.rule) {
|
|
1392
|
+
labelG.append("line").attr("x1", 0).attr("x2", s.descriptionMaxWidth).attr("y1", 0).attr("y2", 0).attr("stroke", ctx.theme.labels.color).attr(
|
|
1393
|
+
"stroke-width",
|
|
1394
|
+
item.rule === "solid" ? 0.8 : ctx.theme.labels.dividerStrokeWidth
|
|
1395
|
+
).attr(
|
|
1396
|
+
"stroke-dasharray",
|
|
1397
|
+
item.rule === "solid" ? null : ctx.theme.labels.dividerStrokeDasharray
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1400
|
+
let headerX = 0;
|
|
1401
|
+
if (item.swatch && swatchFill) {
|
|
1402
|
+
const size = lineH * 0.75;
|
|
1403
|
+
labelG.append("rect").attr("x", 0).attr("y", lineH * 0.85 - size + 1).attr("width", size).attr("height", size).attr("fill", swatchFill(item.swatch)).attr("stroke", ctx.theme.lithology.stroke).attr("stroke-width", 0.5);
|
|
1404
|
+
headerX = size + 3;
|
|
1405
|
+
}
|
|
1406
|
+
labelG.append("text").attr("class", "wp-annotation-header").attr("fill", ctx.theme.labels.color).attr("font-weight", st.headerFontWeight ?? 600).attr("font-family", ctx.theme.labels.headerFont).attr("x", headerX).attr("y", lineH * 0.85).attr("font-size", st.fontSize).text(item.header);
|
|
1407
|
+
let lineY = lineH * 0.85 + lineH;
|
|
1408
|
+
if (item.unit) {
|
|
1409
|
+
labelG.append("text").attr("class", "wp-annotation-unit").attr("fill", ctx.theme.labels.color).attr("font-weight", st.headerFontWeight ?? 600).attr("font-family", ctx.theme.labels.bodyFont ?? "sans-serif").attr("x", 0).attr("y", lineY).attr("font-size", st.fontSize).text(item.unit);
|
|
1410
|
+
lineY += lineH;
|
|
1411
|
+
}
|
|
1003
1412
|
if (item.description) {
|
|
1004
1413
|
const lines = wrapText(item.description, charsPerLine);
|
|
1005
|
-
const bodyEl = labelG.append("text").attr("class", "wp-annotation-body").attr("fill", ctx.theme.labels.bodyColor).attr("font-weight", st.bodyFontWeight ?? 400).attr("font-family", ctx.theme.labels.bodyFont ?? "sans-serif").attr("x", 0).attr("y",
|
|
1414
|
+
const bodyEl = labelG.append("text").attr("class", "wp-annotation-body").attr("fill", ctx.theme.labels.bodyColor).attr("font-weight", st.bodyFontWeight ?? 400).attr("font-family", ctx.theme.labels.bodyFont ?? "sans-serif").attr("x", 0).attr("y", lineY).attr("font-size", st.fontSize);
|
|
1006
1415
|
lines.forEach((line, i) => {
|
|
1007
1416
|
bodyEl.append("tspan").attr("x", 0).attr("dy", i === 0 ? 0 : lineH).text(line);
|
|
1008
1417
|
});
|
|
1418
|
+
lineY += lines.length * lineH;
|
|
1419
|
+
}
|
|
1420
|
+
if (item.aquifer) {
|
|
1421
|
+
labelG.append("text").attr("class", "wp-annotation-aquifer").attr("fill", ctx.theme.labels.bodyColor).attr("font-style", "italic").attr("font-family", ctx.theme.labels.bodyFont ?? "sans-serif").attr("x", 0).attr("y", lineY).attr("font-size", st.fontSize).text(item.aquifer);
|
|
1009
1422
|
}
|
|
1010
1423
|
});
|
|
1011
1424
|
}
|
|
@@ -1026,7 +1439,6 @@ var makePointKey = (type) => (d, i) => {
|
|
|
1026
1439
|
|
|
1027
1440
|
// src/renderers/caves.renderer.ts
|
|
1028
1441
|
function drawCaves(ctx, data) {
|
|
1029
|
-
if (!data.length) return;
|
|
1030
1442
|
const {
|
|
1031
1443
|
groups: { cavesGroup },
|
|
1032
1444
|
geoXLeft,
|
|
@@ -1036,7 +1448,7 @@ function drawCaves(ctx, data) {
|
|
|
1036
1448
|
yScale,
|
|
1037
1449
|
renderConfig,
|
|
1038
1450
|
theme,
|
|
1039
|
-
textures:
|
|
1451
|
+
textures: textures4,
|
|
1040
1452
|
classes,
|
|
1041
1453
|
tooltips
|
|
1042
1454
|
} = ctx;
|
|
@@ -1073,7 +1485,7 @@ function drawCaves(ctx, data) {
|
|
|
1073
1485
|
const botPath = botCut ? `M ${geoXLeft.toFixed(1)},${yBot.toFixed(1)} L ${geoXRight.toFixed(1)},${yBot.toFixed(1)}` : ptsToSmoothPath(botPts);
|
|
1074
1486
|
const botReversed = botCut ? `L ${geoXLeft.toFixed(1)},${yBot.toFixed(1)}` : ptsToSmoothPath([...botPts].reverse(), { omitMoveTo: true });
|
|
1075
1487
|
const closedPath = `${topPath} L ${geoXRight.toFixed(1)},${yBot.toFixed(1)}${botReversed} L ${geoXLeft.toFixed(1)},${yTop.toFixed(1)} Z`;
|
|
1076
|
-
const caveTexture = cave.water_intake ?
|
|
1488
|
+
const caveTexture = cave.water_intake ? textures4.cave_wet : textures4.cave_dry;
|
|
1077
1489
|
const caveStroke = cave.water_intake ? theme.cave.wetStroke : theme.cave.dryStroke;
|
|
1078
1490
|
g.append("path").attr("class", classes.caves.fill).attr("d", closedPath).attr("fill", caveTexture.url()).attr("fill-opacity", theme.cave.fillOpacity).attr("stroke", "none");
|
|
1079
1491
|
g.append("path").attr("class", classes.caves.contact).attr("d", topPath).attr("fill", "none").attr("stroke", caveStroke).attr("stroke-width", theme.cave.contactStrokeWidth).attr("stroke-linecap", "round").attr("stroke-linejoin", "round");
|
|
@@ -1082,9 +1494,148 @@ function drawCaves(ctx, data) {
|
|
|
1082
1494
|
merged.transition(ctx.transition).style("opacity", 1);
|
|
1083
1495
|
}
|
|
1084
1496
|
|
|
1085
|
-
// src/renderers/
|
|
1497
|
+
// src/renderers/centralizers.renderer.ts
|
|
1086
1498
|
import * as d32 from "d3";
|
|
1087
|
-
import { getProfileDiamValues } from "@welldot/utils";
|
|
1499
|
+
import { getCentralizerDepths, getProfileDiamValues } from "@welldot/utils";
|
|
1500
|
+
function drawCentralizers(ctx, data) {
|
|
1501
|
+
const group = ctx.groups.centralizerGroup;
|
|
1502
|
+
const cls = ctx.classes.centralizer;
|
|
1503
|
+
const maxXValue = d32.max(getProfileDiamValues(ctx.constructionData)) || 0;
|
|
1504
|
+
const xScale = d32.scaleLinear().domain([0, maxXValue]).range([0, ctx.POCO_WIDTH]);
|
|
1505
|
+
const pipes = [
|
|
1506
|
+
...ctx.constructionData.well_case,
|
|
1507
|
+
...ctx.constructionData.well_screen
|
|
1508
|
+
];
|
|
1509
|
+
const holes = ctx.constructionData.bore_hole;
|
|
1510
|
+
const markers = (data.centralizers ?? []).flatMap(
|
|
1511
|
+
(c) => getCentralizerDepths(c).filter((depth) => depth >= ctx.depthFrom && depth < ctx.depthTo).map((depth) => ({ ...c, depth }))
|
|
1512
|
+
);
|
|
1513
|
+
const halfH = ctx.renderConfig.construction.centralizer.markerHalfHeight;
|
|
1514
|
+
const bowPoints = (m, side) => {
|
|
1515
|
+
const outerD = m.diameter ?? diameterAt(holes, m.depth) ?? maxXValue;
|
|
1516
|
+
const pipeD = diameterAt(pipes, m.depth) ?? outerD * 0.75;
|
|
1517
|
+
const pipeX = (ctx.POCO_CENTER + side * xScale(pipeD)) / 2;
|
|
1518
|
+
const outerX = (ctx.POCO_CENTER + side * xScale(outerD)) / 2;
|
|
1519
|
+
const y = ctx.yScale(m.depth);
|
|
1520
|
+
return `${pipeX},${y - halfH} ${outerX},${y} ${pipeX},${y + halfH}`;
|
|
1521
|
+
};
|
|
1522
|
+
const selection = group.selectAll(`g.${cls.item}`).data(markers, (d) => `${d.from}:${d.to}:${d.depth}`);
|
|
1523
|
+
selection.exit().remove();
|
|
1524
|
+
const entered = selection.enter().append("g").attr("class", cls.item).on("mouseover", ctx.tooltips.centralizer.show).on("mouseout", ctx.tooltips.centralizer.hide);
|
|
1525
|
+
entered.append("polyline").attr("class", `${cls.item}-left`);
|
|
1526
|
+
entered.append("polyline").attr("class", `${cls.item}-right`);
|
|
1527
|
+
const merged = entered.merge(selection);
|
|
1528
|
+
merged.selectAll("polyline").attr("fill", ctx.theme.centralizer.fill).attr("stroke", ctx.theme.centralizer.stroke).attr("stroke-width", ctx.theme.centralizer.strokeWidth).attr("stroke-linejoin", "round");
|
|
1529
|
+
merged.each((d, i, nodes) => {
|
|
1530
|
+
const g = d32.select(nodes[i]);
|
|
1531
|
+
g.select(`.${cls.item}-left`).attr("points", bowPoints(d, -1));
|
|
1532
|
+
g.select(`.${cls.item}-right`).attr("points", bowPoints(d, 1));
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
// src/utils/layout.utils.ts
|
|
1537
|
+
function getProfileTopDepth(profile) {
|
|
1538
|
+
return Math.min(
|
|
1539
|
+
0,
|
|
1540
|
+
...[
|
|
1541
|
+
...profile.surface_case ?? [],
|
|
1542
|
+
...profile.well_case ?? [],
|
|
1543
|
+
...profile.well_screen ?? []
|
|
1544
|
+
].map((i) => i.from).filter(Number.isFinite)
|
|
1545
|
+
);
|
|
1546
|
+
}
|
|
1547
|
+
function resolvePanelWindows(panels, totalDepth, topDepth = 0) {
|
|
1548
|
+
if (panels.length > 0 && panels.every((p) => p.depthRange)) {
|
|
1549
|
+
return panels.map((p) => [p.depthRange[0], p.depthRange[1]]);
|
|
1550
|
+
}
|
|
1551
|
+
if (panels.length === 1) return [[topDepth, totalDepth]];
|
|
1552
|
+
const totalHeight = panels.reduce((s, p) => s + p.height, 0) || 1;
|
|
1553
|
+
const metersPerPx = (totalDepth - topDepth) / totalHeight;
|
|
1554
|
+
let current = topDepth;
|
|
1555
|
+
return panels.map((p) => {
|
|
1556
|
+
const from = current;
|
|
1557
|
+
current = from + p.height * metersPerPx;
|
|
1558
|
+
return [from, current];
|
|
1559
|
+
});
|
|
1560
|
+
}
|
|
1561
|
+
function getColumnHeaderPositions(geometry) {
|
|
1562
|
+
const { marginLeft, geoXLeft, geoXRight, pocoCenterX, descriptionX } = geometry;
|
|
1563
|
+
return {
|
|
1564
|
+
depth: marginLeft - 2,
|
|
1565
|
+
lithology: marginLeft + (geoXLeft + geoXRight) / 2,
|
|
1566
|
+
construction: marginLeft + pocoCenterX,
|
|
1567
|
+
...descriptionX != null ? { description: marginLeft + descriptionX } : {}
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
function getLithologyMarkers(lithology, depthFrom, depthTo) {
|
|
1571
|
+
const markers = [];
|
|
1572
|
+
lithology.forEach((layer, i) => {
|
|
1573
|
+
const from = Math.max(layer.from, depthFrom);
|
|
1574
|
+
const to = Math.min(layer.to, depthTo);
|
|
1575
|
+
if (to > from) markers.push({ index: i + 1, from, to });
|
|
1576
|
+
});
|
|
1577
|
+
return markers;
|
|
1578
|
+
}
|
|
1579
|
+
function getFractureMarkers(fractures, depthFrom, depthTo) {
|
|
1580
|
+
const markers = [];
|
|
1581
|
+
fractures.forEach((f, i) => {
|
|
1582
|
+
if (f.depth >= depthFrom && f.depth < depthTo) {
|
|
1583
|
+
markers.push({ label: `F${i + 1}`, depth: f.depth });
|
|
1584
|
+
}
|
|
1585
|
+
});
|
|
1586
|
+
return markers;
|
|
1587
|
+
}
|
|
1588
|
+
function getOverviewGeometry(totalDepth, height, depthFrom, depthTo) {
|
|
1589
|
+
const ratio = totalDepth > 0 ? height / totalDepth : 0;
|
|
1590
|
+
const y = (depth) => Math.min(height, Math.max(0, depth * ratio));
|
|
1591
|
+
return {
|
|
1592
|
+
y,
|
|
1593
|
+
window: { y: y(depthFrom), height: Math.max(1, y(depthTo) - y(depthFrom)) }
|
|
1594
|
+
};
|
|
1595
|
+
}
|
|
1596
|
+
function formatOverlapLabel(template, range) {
|
|
1597
|
+
return template.replace("{range}", range);
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
// src/renderers/column-headers.renderer.ts
|
|
1601
|
+
function hasDescriptionColumn(ctx) {
|
|
1602
|
+
const { active, lithology } = ctx.renderConfig.labels;
|
|
1603
|
+
if (active === false) return false;
|
|
1604
|
+
if (Array.isArray(active) && !active.includes("lithology")) return false;
|
|
1605
|
+
if (lithology === false) return false;
|
|
1606
|
+
return !Array.isArray(lithology) || lithology.includes("description");
|
|
1607
|
+
}
|
|
1608
|
+
function drawColumnHeaders(ctx) {
|
|
1609
|
+
const group = ctx.groups.columnHeadersGroup;
|
|
1610
|
+
group.selectAll("*").remove();
|
|
1611
|
+
const cfg = ctx.renderConfig.columnHeaders;
|
|
1612
|
+
if (!cfg.active) return;
|
|
1613
|
+
const theme = ctx.theme.columnHeaders;
|
|
1614
|
+
const { margins } = ctx.state;
|
|
1615
|
+
const positions = getColumnHeaderPositions({
|
|
1616
|
+
marginLeft: margins.left,
|
|
1617
|
+
geoXLeft: ctx.geoXLeft,
|
|
1618
|
+
geoXRight: ctx.geoXRight,
|
|
1619
|
+
pocoCenterX: ctx.pocoCenterX,
|
|
1620
|
+
descriptionX: hasDescriptionColumn(ctx) ? ctx.geoXRight + ctx.renderConfig.labels.descriptionXOffset : void 0
|
|
1621
|
+
});
|
|
1622
|
+
const ruleY = margins.top - 2 - ctx.renderConfig.construction.cementPad.height;
|
|
1623
|
+
const textY = ruleY - 4;
|
|
1624
|
+
const addText = (x, text, anchor) => group.append("text").attr("class", ctx.classes.columnHeaders.text).attr("x", x).attr("y", textY).attr("text-anchor", anchor).attr("font-size", theme.fontSize).attr("font-family", theme.fontFamily ?? "sans-serif").attr("font-weight", theme.fontWeight ?? 600).attr("fill", theme.color).text(text);
|
|
1625
|
+
addText(positions.depth, cfg.labels.depth, "end");
|
|
1626
|
+
addText(positions.lithology, cfg.labels.lithology, "middle");
|
|
1627
|
+
addText(positions.construction, cfg.labels.construction, "middle");
|
|
1628
|
+
if (positions.description != null) {
|
|
1629
|
+
addText(positions.description, cfg.labels.description, "start");
|
|
1630
|
+
}
|
|
1631
|
+
const overview = ctx.renderConfig.overview;
|
|
1632
|
+
group.append("line").attr("class", ctx.classes.columnHeaders.rule).attr("x1", overview.active ? overview.x : 0).attr("x2", ctx.svgWidth).attr("y1", ruleY).attr("y2", ruleY).attr("stroke", theme.ruleStroke).attr("stroke-width", theme.ruleStrokeWidth);
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
// src/renderers/construction-labels.renderer.ts
|
|
1636
|
+
import * as d33 from "d3";
|
|
1637
|
+
import { CONSTRUCTION_MATERIALS as CONSTRUCTION_MATERIALS2, getVocabLabel as getVocabLabel2 } from "@welldot/core";
|
|
1638
|
+
import { getProfileDiamValues as getProfileDiamValues2 } from "@welldot/utils";
|
|
1088
1639
|
function drawConstructionLabels(ctx, data) {
|
|
1089
1640
|
if (!ctx.renderConfig.constructionLabels.active) return;
|
|
1090
1641
|
ctx.groups.constructionLabelsGroup.selectAll("*").remove();
|
|
@@ -1092,16 +1643,18 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1092
1643
|
const clct = ctx.theme.constructionLabels;
|
|
1093
1644
|
const fmtD = (mm) => formatDiameter(mm, ctx.units.diameter, ctx.locale);
|
|
1094
1645
|
const dUnit = getDiameterUnit(ctx.units.diameter, ctx.locale);
|
|
1095
|
-
const
|
|
1096
|
-
const
|
|
1646
|
+
const material = (value) => getVocabLabel2(CONSTRUCTION_MATERIALS2, value, ctx.locale);
|
|
1647
|
+
const maxXValues = getProfileDiamValues2(ctx.constructionData);
|
|
1648
|
+
const xScale = d33.scaleLinear().domain([0, d33.max(maxXValues) || 0]).range([0, ctx.POCO_WIDTH]);
|
|
1097
1649
|
const occupied = [];
|
|
1098
|
-
const
|
|
1650
|
+
const onRight = clc.side === "right";
|
|
1651
|
+
const continuation = ctx.renderConfig.labels.continuation;
|
|
1652
|
+
const placeLabel = (d, label) => {
|
|
1099
1653
|
const clampedFrom = Math.max(d.from, ctx.depthFrom);
|
|
1100
1654
|
const clampedTo = Math.min(d.to, ctx.depthTo);
|
|
1101
1655
|
if (clampedFrom >= clampedTo) return;
|
|
1656
|
+
const text = continuation?.active && d.from < ctx.depthFrom ? `\u2191 ${label}` : label;
|
|
1102
1657
|
const midY = ctx.yScale((clampedFrom + clampedTo) / 2);
|
|
1103
|
-
const leftEdgeX = (ctx.POCO_CENTER - xScale(d.diameter)) / 2;
|
|
1104
|
-
const labelRightX = leftEdgeX - clc.xOffset;
|
|
1105
1658
|
const charW = clct.fontSize * 0.52;
|
|
1106
1659
|
const lineH = clct.fontSize * 1.35;
|
|
1107
1660
|
const vertPad = 6;
|
|
@@ -1118,16 +1671,17 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1118
1671
|
lines = [text];
|
|
1119
1672
|
boxW = text.length * charW + 8;
|
|
1120
1673
|
}
|
|
1674
|
+
const labelRightX = onRight ? (ctx.POCO_CENTER + ctx.POCO_WIDTH) / 2 + clc.xOffset + boxW : (ctx.POCO_CENTER - xScale(d.diameter)) / 2 - clc.xOffset;
|
|
1121
1675
|
const labelH = lines.length * lineH + vertPad;
|
|
1122
|
-
let labelY = midY - labelH / 2;
|
|
1676
|
+
let labelY = onRight ? ctx.yScale(clampedFrom) + 1 : midY - labelH / 2;
|
|
1123
1677
|
for (const pos of occupied) {
|
|
1124
1678
|
if (labelY < pos.bot && labelY + labelH > pos.top) labelY = pos.bot + 2;
|
|
1125
1679
|
}
|
|
1126
1680
|
occupied.push({ top: labelY, bot: labelY + labelH });
|
|
1127
1681
|
ctx.groups.constructionLabelsGroup.append("rect").attr("x", labelRightX - boxW).attr("y", labelY).attr("width", boxW).attr("height", labelH).attr("rx", clc.labelRadius).attr("fill", clct.labelFill ?? "white").attr("stroke", clct.labelColor ?? "#303030").attr("stroke-width", 0.5);
|
|
1128
|
-
const textEl = ctx.groups.constructionLabelsGroup.append("text").attr("x", labelRightX - 4).attr("y", labelY + lineH * 0.85).attr("font-size", clct.fontSize).attr("font-family", clct.fontFamily ?? "sans-serif").attr("font-weight", clct.fontWeight ?? 400).attr("text-anchor", "end").attr("fill", clct.labelColor ?? "#303030");
|
|
1682
|
+
const textEl = ctx.groups.constructionLabelsGroup.append("text").attr("x", onRight ? labelRightX - boxW + 4 : labelRightX - 4).attr("y", labelY + lineH * 0.85).attr("font-size", clct.fontSize).attr("font-family", clct.fontFamily ?? "sans-serif").attr("font-weight", clct.fontWeight ?? 400).attr("text-anchor", onRight ? "start" : "end").attr("fill", clct.labelColor ?? "#303030");
|
|
1129
1683
|
lines.forEach((line, i) => {
|
|
1130
|
-
textEl.append("tspan").attr("x", labelRightX - 4).attr("dy", i === 0 ? 0 : lineH).text(line);
|
|
1684
|
+
textEl.append("tspan").attr("x", onRight ? labelRightX - boxW + 4 : labelRightX - 4).attr("dy", i === 0 ? 0 : lineH).text(line);
|
|
1131
1685
|
});
|
|
1132
1686
|
};
|
|
1133
1687
|
let lastDiam = 0;
|
|
@@ -1140,7 +1694,7 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1140
1694
|
}).forEach(
|
|
1141
1695
|
(d) => placeLabel(
|
|
1142
1696
|
d,
|
|
1143
|
-
`${clc.labels.wellCasePrefix} ${fmtD(d.diameter)}${dUnit} ${d.type}`
|
|
1697
|
+
`${clc.labels.wellCasePrefix} ${fmtD(d.diameter)}${dUnit} ${material(d.type)}`
|
|
1144
1698
|
)
|
|
1145
1699
|
);
|
|
1146
1700
|
lastDiam = 0;
|
|
@@ -1153,122 +1707,319 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1153
1707
|
}).forEach(
|
|
1154
1708
|
(d) => placeLabel(
|
|
1155
1709
|
d,
|
|
1156
|
-
`${clc.labels.wellScreenPrefix} ${fmtD(d.diameter)}${dUnit} ${d.type} ${clc.labels.wellScreenSlotPrefix} ${fmtD(d.screen_slot)}${dUnit}`
|
|
1710
|
+
`${clc.labels.wellScreenPrefix} ${fmtD(d.diameter)}${dUnit} ${material(d.type)} ${clc.labels.wellScreenSlotPrefix} ${fmtD(d.screen_slot)}${dUnit}`
|
|
1157
1711
|
)
|
|
1158
1712
|
);
|
|
1159
1713
|
}
|
|
1160
1714
|
|
|
1161
1715
|
// src/renderers/construction.renderer.ts
|
|
1162
|
-
import * as
|
|
1163
|
-
import { getProfileDiamValues as
|
|
1716
|
+
import * as d34 from "d3";
|
|
1717
|
+
import { getProfileDiamValues as getProfileDiamValues3 } from "@welldot/utils";
|
|
1718
|
+
var entering = /* @__PURE__ */ new WeakSet();
|
|
1719
|
+
function constructionXScale(ctx) {
|
|
1720
|
+
const max6 = d34.max(getProfileDiamValues3(ctx.constructionData)) || 0;
|
|
1721
|
+
return d34.scaleLinear().domain([0, max6]).range([0, ctx.POCO_WIDTH]);
|
|
1722
|
+
}
|
|
1723
|
+
function outlineScales(ctx) {
|
|
1724
|
+
const x = constructionXScale(ctx);
|
|
1725
|
+
return {
|
|
1726
|
+
y: ctx.yScale,
|
|
1727
|
+
left: (d) => (ctx.POCO_CENTER - x(d)) / 2,
|
|
1728
|
+
right: (d) => (ctx.POCO_CENTER + x(d)) / 2,
|
|
1729
|
+
depthFrom: ctx.depthFrom,
|
|
1730
|
+
depthTo: ctx.depthTo
|
|
1731
|
+
};
|
|
1732
|
+
}
|
|
1733
|
+
var surfaceCaseDiameter = (ctx, diameter) => diameter * (1 + ctx.renderConfig.construction.surfaceCase.diameterPaddingRatio);
|
|
1734
|
+
function joinIntervalLayer(ctx, group, cls, data, key, tooltip, { shoe = false, pathFill = false, ends = false } = {}) {
|
|
1735
|
+
const sel = group.selectAll(`g.${cls}`).data(data, makeIntervalKey(key));
|
|
1736
|
+
sel.exit().transition(ctx.transition).style("opacity", 0).remove();
|
|
1737
|
+
const top = (d) => ctx.yScale(Math.max(d.from, ctx.depthFrom));
|
|
1738
|
+
const entered = sel.enter().append("g").attr("class", cls).each((_d, i, nodes) => entering.add(nodes[i])).on("mouseover", tooltip.show).on("mouseout", tooltip.hide);
|
|
1739
|
+
if (pathFill)
|
|
1740
|
+
entered.append("path").attr("class", `${cls}-fill`).attr("stroke", "none").attr("fill-rule", "evenodd").attr("d", "");
|
|
1741
|
+
else
|
|
1742
|
+
entered.append("rect").attr("class", `${cls}-fill`).attr("stroke", "none").attr("y", top).attr("height", 0);
|
|
1743
|
+
entered.append("path").attr("class", `${cls}-outline`).attr("fill", "none").attr("d", "");
|
|
1744
|
+
if (shoe)
|
|
1745
|
+
entered.append("path").attr("class", `${cls}-shoe`).attr("stroke-linejoin", "round").attr("d", "");
|
|
1746
|
+
if (ends)
|
|
1747
|
+
entered.append("path").attr("class", `${cls}-ends`).attr("fill", "none").attr("d", "");
|
|
1748
|
+
return entered.merge(sel);
|
|
1749
|
+
}
|
|
1750
|
+
function drawCementPad(ctx, pad) {
|
|
1751
|
+
const cls = ctx.classes.cementPad.item;
|
|
1752
|
+
const visible = !!pad?.thickness && ctx.depthFrom <= 0 && ctx.depthTo > 0;
|
|
1753
|
+
const sel = ctx.groups.cementPadGroup.selectAll(`g.${cls}`).data(visible ? [pad] : [], () => "cement_pad");
|
|
1754
|
+
sel.exit().remove();
|
|
1755
|
+
if (!visible) return;
|
|
1756
|
+
const entered = sel.enter().append("g").attr("class", cls).on("mouseover", ctx.tooltips.cementPad.show).on("mouseout", ctx.tooltips.cementPad.hide);
|
|
1757
|
+
entered.append("path").attr("class", `${cls}-slab`);
|
|
1758
|
+
entered.append("path").attr("class", `${cls}-slab`);
|
|
1759
|
+
const x = constructionXScale(ctx);
|
|
1760
|
+
const { opening, outer } = getPadDiameters(
|
|
1761
|
+
ctx.constructionData,
|
|
1762
|
+
ctx.renderConfig.construction.surfaceCase.diameterPaddingRatio
|
|
1763
|
+
);
|
|
1764
|
+
const { slabs } = getCementPadGeometry(
|
|
1765
|
+
ctx.POCO_WIDTH,
|
|
1766
|
+
ctx.POCO_CENTER,
|
|
1767
|
+
ctx.yScale(0),
|
|
1768
|
+
ctx.renderConfig.construction.cementPad,
|
|
1769
|
+
x(opening),
|
|
1770
|
+
x(outer)
|
|
1771
|
+
);
|
|
1772
|
+
entered.merge(sel).selectAll("path").attr("d", (_d, i) => slabs[i] ?? "").attr("fill", ctx.textures.pad.url()).attr("stroke", ctx.theme.cementPad.stroke).attr("stroke-width", ctx.theme.cementPad.strokeWidth).attr("stroke-linejoin", "round");
|
|
1773
|
+
}
|
|
1774
|
+
function layoutConstruction(ctx, animate = false) {
|
|
1775
|
+
const c = ctx.classes;
|
|
1776
|
+
const scales = outlineScales(ctx);
|
|
1777
|
+
const data = ctx.constructionData;
|
|
1778
|
+
const motion = (sel) => animate ? withTransition(sel, ctx.transition) : sel;
|
|
1779
|
+
const yTop = (d) => ctx.yScale(Math.max(d.from, ctx.depthFrom));
|
|
1780
|
+
const yBottom = (d) => ctx.yScale(Math.min(d.to, ctx.depthTo));
|
|
1781
|
+
const collapsed = (d) => ({
|
|
1782
|
+
...scales,
|
|
1783
|
+
y: () => yTop(d)
|
|
1784
|
+
});
|
|
1785
|
+
const shapeParts = (items, part, attr, shape) => {
|
|
1786
|
+
const parts = items.select(part);
|
|
1787
|
+
if (animate)
|
|
1788
|
+
parts.filter(function() {
|
|
1789
|
+
return entering.has(this.parentNode);
|
|
1790
|
+
}).attr(attr, (d) => shape(d, collapsed(d)));
|
|
1791
|
+
motion(parts).attr(attr, (d) => shape(d, scales));
|
|
1792
|
+
};
|
|
1793
|
+
const layoutLayer = (group, cls, diameter, outline, {
|
|
1794
|
+
shoe: shoe2,
|
|
1795
|
+
ends,
|
|
1796
|
+
fill
|
|
1797
|
+
} = {}) => {
|
|
1798
|
+
const items = group.selectAll(`g.${cls}`);
|
|
1799
|
+
shapeParts(items, `.${cls}-outline`, "d", outline);
|
|
1800
|
+
if (shoe2) shapeParts(items, `.${cls}-shoe`, "d", shoe2);
|
|
1801
|
+
if (ends) shapeParts(items, `.${cls}-ends`, "d", ends);
|
|
1802
|
+
if (fill) {
|
|
1803
|
+
shapeParts(items, `.${cls}-fill`, "d", fill);
|
|
1804
|
+
return;
|
|
1805
|
+
}
|
|
1806
|
+
motion(
|
|
1807
|
+
items.select(`.${cls}-fill`).attr("x", (d) => scales.left(diameter(d))).attr(
|
|
1808
|
+
"width",
|
|
1809
|
+
(d) => scales.right(diameter(d)) - scales.left(diameter(d))
|
|
1810
|
+
)
|
|
1811
|
+
).attr("y", yTop).attr("height", (d) => Math.max(0, yBottom(d) - yTop(d)));
|
|
1812
|
+
};
|
|
1813
|
+
const walls = (d, s, dia = d.diameter) => pipeWallsPath(
|
|
1814
|
+
s.left(dia),
|
|
1815
|
+
s.right(dia),
|
|
1816
|
+
s.y(Math.max(d.from, s.depthFrom)),
|
|
1817
|
+
s.y(Math.min(d.to, s.depthTo))
|
|
1818
|
+
);
|
|
1819
|
+
layoutLayer(
|
|
1820
|
+
ctx.groups.holeGroup,
|
|
1821
|
+
c.boreHole.rect,
|
|
1822
|
+
(d) => d.diameter,
|
|
1823
|
+
(d, s) => boreHoleOutlinePath(d, data.bore_hole, s)
|
|
1824
|
+
);
|
|
1825
|
+
const pipes = [...data.well_case, ...data.well_screen];
|
|
1826
|
+
const insideSurface = [...data.bore_hole, ...data.hole_fill, ...pipes];
|
|
1827
|
+
const scDiameter = (d) => surfaceCaseDiameter(ctx, d.diameter);
|
|
1828
|
+
layoutLayer(
|
|
1829
|
+
ctx.groups.surfaceCaseGroup,
|
|
1830
|
+
c.surfaceCase.rect,
|
|
1831
|
+
scDiameter,
|
|
1832
|
+
(d, s) => walls(d, s, scDiameter(d)),
|
|
1833
|
+
// Only the ring outside the hole: the texture never shows under the casing.
|
|
1834
|
+
{
|
|
1835
|
+
fill: (d, s) => annulusFillPath({ ...d, diameter: scDiameter(d) }, insideSurface, s)
|
|
1836
|
+
}
|
|
1837
|
+
);
|
|
1838
|
+
layoutLayer(
|
|
1839
|
+
ctx.groups.holeFillGroup,
|
|
1840
|
+
c.holeFill.rect,
|
|
1841
|
+
(d) => d.diameter,
|
|
1842
|
+
(d, s) => holeFillOutlinePath(d, pipes, s),
|
|
1843
|
+
{ fill: (d, s) => annulusFillPath(d, pipes, s) }
|
|
1844
|
+
);
|
|
1845
|
+
const string = [...pipes, ...data.reduction ?? []];
|
|
1846
|
+
const shoeCfg = ctx.renderConfig.construction.casingShoe;
|
|
1847
|
+
const endsCfg = ctx.renderConfig.construction.screenEnds;
|
|
1848
|
+
const room = (d, depth, size) => {
|
|
1849
|
+
const hole = diameterAt(data.bore_hole, depth);
|
|
1850
|
+
const annulus = hole !== void 0 && hole > d.diameter ? scales.left(d.diameter) - scales.left(hole) - 1 : size;
|
|
1851
|
+
return Math.max(2, Math.min(size, annulus));
|
|
1852
|
+
};
|
|
1853
|
+
const shoe = (d, s) => {
|
|
1854
|
+
const ends = getIntervalEnds(d, string, ctx.depthFrom, ctx.depthTo);
|
|
1855
|
+
if (!shoeCfg.active || ends.cutBottom || ends.joinedBottom) return "";
|
|
1856
|
+
return shoePath(
|
|
1857
|
+
s.left(d.diameter),
|
|
1858
|
+
s.right(d.diameter),
|
|
1859
|
+
s.y(Math.min(d.to, s.depthTo)),
|
|
1860
|
+
room(d, d.to, shoeCfg.size)
|
|
1861
|
+
);
|
|
1862
|
+
};
|
|
1863
|
+
const screenEnds = (d, s) => {
|
|
1864
|
+
if (!endsCfg.active) return "";
|
|
1865
|
+
const ends = getIntervalEnds(d, string, ctx.depthFrom, ctx.depthTo);
|
|
1866
|
+
const mark = (depth) => screenEndPath(s.left(d.diameter), s.right(d.diameter), s.y(depth));
|
|
1867
|
+
return (ends.cutTop ? "" : mark(d.from)) + (ends.cutBottom ? "" : mark(d.to));
|
|
1868
|
+
};
|
|
1869
|
+
layoutLayer(
|
|
1870
|
+
ctx.groups.wellCaseGroup,
|
|
1871
|
+
c.wellCase.rect,
|
|
1872
|
+
(d) => d.diameter,
|
|
1873
|
+
walls,
|
|
1874
|
+
{ shoe }
|
|
1875
|
+
);
|
|
1876
|
+
layoutLayer(
|
|
1877
|
+
ctx.groups.wellScreenGroup,
|
|
1878
|
+
c.wellScreen.rect,
|
|
1879
|
+
(d) => d.diameter,
|
|
1880
|
+
walls,
|
|
1881
|
+
{ shoe, ends: screenEnds }
|
|
1882
|
+
);
|
|
1883
|
+
const reductions = ctx.groups.reductionGroup.selectAll(`g.${c.reduction.item}`);
|
|
1884
|
+
const corners = (d, s) => {
|
|
1885
|
+
const t = s.y(Math.max(d.from, s.depthFrom));
|
|
1886
|
+
const b = s.y(Math.min(d.to, s.depthTo));
|
|
1887
|
+
return {
|
|
1888
|
+
tl: `${s.left(d.diam_from)},${t}`,
|
|
1889
|
+
tr: `${s.right(d.diam_from)},${t}`,
|
|
1890
|
+
bl: `${s.left(d.diam_to)},${b}`,
|
|
1891
|
+
br: `${s.right(d.diam_to)},${b}`
|
|
1892
|
+
};
|
|
1893
|
+
};
|
|
1894
|
+
shapeParts(reductions, `.${c.reduction.item}-fill`, "points", (d, s) => {
|
|
1895
|
+
const p = corners(d, s);
|
|
1896
|
+
return `${p.tl} ${p.tr} ${p.br} ${p.bl}`;
|
|
1897
|
+
});
|
|
1898
|
+
shapeParts(reductions, `.${c.reduction.item}-outline`, "d", (d, s) => {
|
|
1899
|
+
const p = corners(d, s);
|
|
1900
|
+
return `M${p.tl}L${p.bl}M${p.tr}L${p.br}`;
|
|
1901
|
+
});
|
|
1902
|
+
if (animate) {
|
|
1903
|
+
for (const group of [
|
|
1904
|
+
ctx.groups.holeGroup,
|
|
1905
|
+
ctx.groups.surfaceCaseGroup,
|
|
1906
|
+
ctx.groups.holeFillGroup,
|
|
1907
|
+
ctx.groups.wellCaseGroup,
|
|
1908
|
+
ctx.groups.wellScreenGroup,
|
|
1909
|
+
ctx.groups.reductionGroup
|
|
1910
|
+
])
|
|
1911
|
+
group.selectAll("g").each(function() {
|
|
1912
|
+
entering.delete(this);
|
|
1913
|
+
});
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1164
1916
|
function drawConstructive(ctx, data) {
|
|
1165
1917
|
const { getHeight, getYPos } = getYAxisFunctions(ctx.yScale, {
|
|
1166
1918
|
from: ctx.depthFrom,
|
|
1167
1919
|
to: ctx.depthTo
|
|
1168
1920
|
});
|
|
1169
|
-
const
|
|
1170
|
-
const
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
).attr("
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
withTransition(mergedHole, ctx.transition).attr("y", getYPos).attr("height", getHeight);
|
|
1196
|
-
const surfaceCaseGs = ctx.groups.surfaceCaseGroup.selectAll(`g.${ctx.classes.surfaceCase.rect}`).data(data.surface_case, makeIntervalKey("surface_case"));
|
|
1197
|
-
surfaceCaseGs.exit().transition(ctx.transition).style("opacity", 0).remove();
|
|
1198
|
-
const newSC = surfaceCaseGs.enter().append("g").attr("class", ctx.classes.surfaceCase.rect).on("mouseover", ctx.tooltips.surfaceCase.show).on("mouseout", ctx.tooltips.surfaceCase.hide);
|
|
1199
|
-
newSC.append("rect").attr("class", "surface-case-fill").attr("stroke", "none").attr("y", yPos).attr("height", 0);
|
|
1200
|
-
newSC.append("line").attr("class", "surface-case-side").attr("stroke", ctx.theme.surfaceCase.stroke).attr("stroke-width", ctx.theme.surfaceCase.strokeWidth);
|
|
1201
|
-
newSC.append("line").attr("class", "surface-case-side").attr("stroke", ctx.theme.surfaceCase.stroke).attr("stroke-width", ctx.theme.surfaceCase.strokeWidth);
|
|
1202
|
-
const mergedSC = mergeEnter(newSC, surfaceCaseGs);
|
|
1203
|
-
mergedSC.each((d, i, nodes) => {
|
|
1204
|
-
const x = (ctx.POCO_CENTER - xScale(
|
|
1205
|
-
d.diameter + d.diameter * rcc.surfaceCase.diameterPaddingRatio
|
|
1206
|
-
)) / 2;
|
|
1207
|
-
const w = xScale(
|
|
1208
|
-
d.diameter + d.diameter * rcc.surfaceCase.diameterPaddingRatio
|
|
1921
|
+
const c = ctx.classes;
|
|
1922
|
+
const theme = ctx.theme;
|
|
1923
|
+
drawCementPad(ctx, data.cement_pad);
|
|
1924
|
+
joinIntervalLayer(
|
|
1925
|
+
ctx,
|
|
1926
|
+
ctx.groups.holeGroup,
|
|
1927
|
+
c.boreHole.rect,
|
|
1928
|
+
data.bore_hole,
|
|
1929
|
+
"bore_hole",
|
|
1930
|
+
ctx.tooltips.hole
|
|
1931
|
+
).attr("opacity", theme.boreHole.opacity).call((g) => {
|
|
1932
|
+
g.select(`.${c.boreHole.rect}-fill`).attr("fill", theme.boreHole.fill);
|
|
1933
|
+
g.select(`.${c.boreHole.rect}-outline`).attr("stroke", theme.boreHole.stroke).attr("stroke-width", theme.boreHole.strokeWidth).attr("stroke-dasharray", theme.boreHole.strokeDasharray);
|
|
1934
|
+
});
|
|
1935
|
+
joinIntervalLayer(
|
|
1936
|
+
ctx,
|
|
1937
|
+
ctx.groups.surfaceCaseGroup,
|
|
1938
|
+
c.surfaceCase.rect,
|
|
1939
|
+
data.surface_case,
|
|
1940
|
+
"surface_case",
|
|
1941
|
+
ctx.tooltips.surfaceCase,
|
|
1942
|
+
{ pathFill: true }
|
|
1943
|
+
).call((g) => {
|
|
1944
|
+
g.select(`.${c.surfaceCase.rect}-fill`).attr(
|
|
1945
|
+
"fill",
|
|
1946
|
+
ctx.textures.surface_case.url()
|
|
1209
1947
|
);
|
|
1210
|
-
|
|
1211
|
-
g.select(".surface-case-fill").attr("x", x).attr("width", w).attr("fill", ctx.textures.surface_case.url());
|
|
1212
|
-
const sideNodes = g.selectAll(".surface-case-side").nodes();
|
|
1213
|
-
d33.select(sideNodes[0]).attr("x1", x).attr("x2", x);
|
|
1214
|
-
d33.select(sideNodes[1]).attr("x1", x + w).attr("x2", x + w);
|
|
1948
|
+
g.select(`.${c.surfaceCase.rect}-outline`).attr("stroke", theme.surfaceCase.stroke).attr("stroke-width", theme.surfaceCase.strokeWidth);
|
|
1215
1949
|
});
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
ctx.
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
"
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1950
|
+
joinIntervalLayer(
|
|
1951
|
+
ctx,
|
|
1952
|
+
ctx.groups.holeFillGroup,
|
|
1953
|
+
c.holeFill.rect,
|
|
1954
|
+
data.hole_fill,
|
|
1955
|
+
"hole_fill",
|
|
1956
|
+
ctx.tooltips.holeFill,
|
|
1957
|
+
{ pathFill: true }
|
|
1958
|
+
).call((g) => {
|
|
1959
|
+
g.select(`.${c.holeFill.rect}-fill`).attr(
|
|
1960
|
+
"fill",
|
|
1961
|
+
(d) => ctx.textures[d.type].url()
|
|
1962
|
+
);
|
|
1963
|
+
g.select(`.${c.holeFill.rect}-outline`).attr("stroke", theme.holeFill.stroke).attr("stroke-width", theme.holeFill.strokeWidth);
|
|
1964
|
+
});
|
|
1965
|
+
for (const [group, cls, items, key, tooltip, fill, stroke] of [
|
|
1966
|
+
[
|
|
1967
|
+
ctx.groups.wellCaseGroup,
|
|
1968
|
+
c.wellCase.rect,
|
|
1969
|
+
data.well_case,
|
|
1970
|
+
"well_case",
|
|
1971
|
+
ctx.tooltips.wellCase,
|
|
1972
|
+
theme.wellCase.fill,
|
|
1973
|
+
theme.wellCase
|
|
1974
|
+
],
|
|
1975
|
+
[
|
|
1976
|
+
ctx.groups.wellScreenGroup,
|
|
1977
|
+
c.wellScreen.rect,
|
|
1978
|
+
data.well_screen,
|
|
1979
|
+
"well_screen",
|
|
1980
|
+
ctx.tooltips.wellScreen,
|
|
1981
|
+
ctx.textures.well_screen.url(),
|
|
1982
|
+
theme.wellScreen
|
|
1983
|
+
]
|
|
1984
|
+
]) {
|
|
1985
|
+
joinIntervalLayer(ctx, group, cls, items, key, tooltip, {
|
|
1986
|
+
shoe: true,
|
|
1987
|
+
ends: cls === c.wellScreen.rect
|
|
1988
|
+
}).call((g) => {
|
|
1989
|
+
g.select(`.${cls}-fill`).attr("fill", fill);
|
|
1990
|
+
g.select(`.${cls}-outline`).attr("stroke", stroke.stroke).attr("stroke-width", stroke.strokeWidth);
|
|
1991
|
+
g.select(`.${cls}-shoe`).attr("fill", stroke.stroke).attr("stroke", stroke.stroke).attr("stroke-width", 0.5);
|
|
1992
|
+
g.select(`.${cls}-ends`).attr("stroke", stroke.stroke).attr("stroke-width", theme.wellScreen.endStrokeWidth).attr("stroke-dasharray", theme.wellScreen.endDasharray);
|
|
1993
|
+
});
|
|
1994
|
+
}
|
|
1995
|
+
const reduction = ctx.groups.reductionGroup.selectAll(`g.${c.reduction.item}`).data(data.reduction ?? [], makeIntervalKey("reduction"));
|
|
1247
1996
|
reduction.exit().transition(ctx.transition).style("opacity", 0).remove();
|
|
1248
|
-
const
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1997
|
+
const newReduction = reduction.enter().append("g").attr("class", c.reduction.item).each((_d, i, nodes) => entering.add(nodes[i])).on("mouseover", ctx.tooltips.reduction.show).on("mouseout", ctx.tooltips.reduction.hide);
|
|
1998
|
+
newReduction.append("polygon").attr("class", `${c.reduction.item}-fill`).attr("stroke", "none");
|
|
1999
|
+
newReduction.append("path").attr("class", `${c.reduction.item}-outline`).attr("fill", "none");
|
|
2000
|
+
newReduction.merge(reduction).call((g) => {
|
|
2001
|
+
g.select(`.${c.reduction.item}-fill`).attr("fill", theme.reduction.fill);
|
|
2002
|
+
g.select(`.${c.reduction.item}-outline`).attr("stroke", theme.reduction.stroke).attr("stroke-width", theme.reduction.strokeWidth);
|
|
2003
|
+
});
|
|
2004
|
+
const mergedConflicts = mergeConflicts(
|
|
2005
|
+
[
|
|
2006
|
+
...getConflictAreas(data.well_case, data.well_screen),
|
|
2007
|
+
...getConflictAreas(data.well_screen, data.well_case)
|
|
2008
|
+
],
|
|
2009
|
+
1
|
|
1258
2010
|
);
|
|
1259
|
-
const
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
const mergedConflicts = mergeConflicts(conflictAreas, 1);
|
|
1263
|
-
const conflict = ctx.groups.conflictGroup.selectAll(`.${ctx.classes.conflict.rect}`).data(mergedConflicts, makeIntervalKey("conflict"));
|
|
2011
|
+
const xScale = constructionXScale(ctx);
|
|
2012
|
+
const yPos = getYPos;
|
|
2013
|
+
const conflict = ctx.groups.conflictGroup.selectAll(`.${c.conflict.rect}`).data(mergedConflicts, makeIntervalKey("conflict"));
|
|
1264
2014
|
conflict.exit().transition(ctx.transition).attr("height", 0).remove();
|
|
1265
|
-
const newConflict = conflict.enter().append("rect").attr("class",
|
|
2015
|
+
const newConflict = conflict.enter().append("rect").attr("class", c.conflict.rect).attr("fill", ctx.textures.conflict.url()).attr("stroke", theme.conflict.stroke).attr("stroke-width", theme.conflict.strokeWidth).on("mouseover", ctx.tooltips.conflict.show).on("mouseout", ctx.tooltips.conflict.hide).attr("y", yPos).attr("height", 0);
|
|
1266
2016
|
const mergedConflict = mergeEnter(newConflict, conflict).attr("x", (d) => (ctx.POCO_CENTER - xScale(d.diameter)) / 2).attr("width", (d) => xScale(d.diameter));
|
|
1267
|
-
withTransition(mergedConflict, ctx.transition).attr("y",
|
|
2017
|
+
withTransition(mergedConflict, ctx.transition).attr("y", getYPos).attr("height", getHeight);
|
|
2018
|
+
layoutConstruction(ctx, true);
|
|
1268
2019
|
}
|
|
1269
2020
|
|
|
1270
2021
|
// src/renderers/fractures.renderer.ts
|
|
1271
|
-
import * as
|
|
2022
|
+
import * as d35 from "d3";
|
|
1272
2023
|
function wavyLine(rng, steps, baseY, jitter, startInset, endInset) {
|
|
1273
2024
|
const pts = [];
|
|
1274
2025
|
for (let i = 0; i < steps; i++) {
|
|
@@ -1280,7 +2031,6 @@ function wavyLine(rng, steps, baseY, jitter, startInset, endInset) {
|
|
|
1280
2031
|
return pts;
|
|
1281
2032
|
}
|
|
1282
2033
|
function drawFractures(ctx, data) {
|
|
1283
|
-
if (!data.length) return;
|
|
1284
2034
|
const {
|
|
1285
2035
|
groups: { fracturesGroup },
|
|
1286
2036
|
POCO_WIDTH,
|
|
@@ -1302,10 +2052,10 @@ function drawFractures(ctx, data) {
|
|
|
1302
2052
|
const merged = mergeEnter(entered, groups);
|
|
1303
2053
|
merged.attr(
|
|
1304
2054
|
"transform",
|
|
1305
|
-
(fracture) => `translate(0,${yScale(fracture.depth)}) rotate(${fracture.dip},${pocoCenterX},0)`
|
|
2055
|
+
(fracture) => `translate(0,${yScale(fracture.depth)}) rotate(${fractureDip(fracture.dip)},${pocoCenterX},0)`
|
|
1306
2056
|
);
|
|
1307
2057
|
merged.each(function(fracture) {
|
|
1308
|
-
const g =
|
|
2058
|
+
const g = d35.select(this);
|
|
1309
2059
|
g.selectAll("*").remove();
|
|
1310
2060
|
const rng = makeSeededPrng(fracture.depth, 7919);
|
|
1311
2061
|
const hitBuffer = fracture.swarm ? rf.hitBuffer.swarm : rf.hitBuffer.single;
|
|
@@ -1384,8 +2134,8 @@ function drawFractures(ctx, data) {
|
|
|
1384
2134
|
}
|
|
1385
2135
|
|
|
1386
2136
|
// src/renderers/highlights.renderer.ts
|
|
1387
|
-
import * as
|
|
1388
|
-
import { getProfileDiamValues as
|
|
2137
|
+
import * as d36 from "d3";
|
|
2138
|
+
import { getProfileDiamValues as getProfileDiamValues4 } from "@welldot/utils";
|
|
1389
2139
|
function drawHighlightItem(ctx, group, x, y, w, h, label) {
|
|
1390
2140
|
if (h <= 0 || w <= 0) return;
|
|
1391
2141
|
const hlConfig = ctx.renderConfig.highlights;
|
|
@@ -1444,27 +2194,29 @@ function drawHighlights(ctx, hl) {
|
|
|
1444
2194
|
h.label
|
|
1445
2195
|
);
|
|
1446
2196
|
});
|
|
1447
|
-
const maxXVals =
|
|
1448
|
-
const xScaleConstr =
|
|
2197
|
+
const maxXVals = getProfileDiamValues4(ctx.constructionData);
|
|
2198
|
+
const xScaleConstr = d36.scaleLinear().domain([0, d36.max(maxXVals) || 0]).range([0, ctx.POCO_WIDTH]);
|
|
1449
2199
|
const constructionConfig = ctx.renderConfig.construction;
|
|
1450
|
-
if (hl.cement_pad && ctx.depthFrom
|
|
1451
|
-
const
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
const cpY = ctx.yScale(0) - ctx.yScale(
|
|
1455
|
-
cp.thickness * constructionConfig.cementPad.thicknessMultiplier
|
|
2200
|
+
if (hl.cement_pad && ctx.depthFrom <= 0 && ctx.depthTo > 0 && ctx.constructionData.cement_pad?.thickness) {
|
|
2201
|
+
const { opening, outer } = getPadDiameters(
|
|
2202
|
+
ctx.constructionData,
|
|
2203
|
+
constructionConfig.surfaceCase.diameterPaddingRatio
|
|
1456
2204
|
);
|
|
1457
|
-
const
|
|
1458
|
-
|
|
1459
|
-
|
|
2205
|
+
const pad = getCementPadRect(
|
|
2206
|
+
ctx.POCO_WIDTH,
|
|
2207
|
+
ctx.POCO_CENTER,
|
|
2208
|
+
ctx.yScale(0),
|
|
2209
|
+
constructionConfig.cementPad,
|
|
2210
|
+
xScaleConstr(opening),
|
|
2211
|
+
xScaleConstr(outer)
|
|
1460
2212
|
);
|
|
1461
2213
|
drawHighlightItem(
|
|
1462
2214
|
ctx,
|
|
1463
2215
|
ctx.groups.highlightsConstructionGroup,
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
2216
|
+
pad.x,
|
|
2217
|
+
pad.y,
|
|
2218
|
+
pad.width,
|
|
2219
|
+
pad.height,
|
|
1468
2220
|
hl.cement_pad.label
|
|
1469
2221
|
);
|
|
1470
2222
|
}
|
|
@@ -1540,8 +2292,12 @@ function drawHighlights(ctx, hl) {
|
|
|
1540
2292
|
// src/renderers/legend.renderer.ts
|
|
1541
2293
|
import * as d3module from "d3";
|
|
1542
2294
|
import { defu } from "defu";
|
|
1543
|
-
|
|
1544
|
-
|
|
2295
|
+
import { getCurrentPump } from "@welldot/utils";
|
|
2296
|
+
var d37 = { ...d3module };
|
|
2297
|
+
var SYMBOL_WIDTH = 24;
|
|
2298
|
+
var SYMBOL_HEIGHT = 12;
|
|
2299
|
+
var SYMBOL_MARGIN = 2;
|
|
2300
|
+
function getWellLegendItems(profile, labels = INTERACTIVE_RENDER_CONFIG.legend.labels) {
|
|
1545
2301
|
const fractures = profile.fractures ?? [];
|
|
1546
2302
|
const caves = profile.caves ?? [];
|
|
1547
2303
|
const boreHoles = profile.bore_hole ?? [];
|
|
@@ -1561,6 +2317,8 @@ function drawWellLegend(selector, profile, options = {}) {
|
|
|
1561
2317
|
const hasWellCase = wellCases.length > 0;
|
|
1562
2318
|
const hasWellScreen = wellScreens.length > 0;
|
|
1563
2319
|
const hasReduction = reductions.length > 0;
|
|
2320
|
+
const hasCentralizer = (profile.centralizers ?? []).length > 0;
|
|
2321
|
+
const hasPump = getCurrentPump(profile)?.intake_depth !== void 0;
|
|
1564
2322
|
const hasCementPad = !!profile.cement_pad?.thickness;
|
|
1565
2323
|
const hasConflict = mergeConflicts(
|
|
1566
2324
|
[
|
|
@@ -1569,197 +2327,314 @@ function drawWellLegend(selector, profile, options = {}) {
|
|
|
1569
2327
|
],
|
|
1570
2328
|
1
|
|
1571
2329
|
).length > 0;
|
|
1572
|
-
const cfg = defu(
|
|
1573
|
-
options.config ?? {},
|
|
1574
|
-
INTERACTIVE_RENDER_CONFIG.legend
|
|
1575
|
-
);
|
|
1576
|
-
const theme = defu(options.theme ?? {}, DEFAULT_WELL_THEME);
|
|
1577
|
-
const cls = options.classNames ? { ...DEFAULT_COMPONENTS_CLASS_NAMES.legend, ...options.classNames } : DEFAULT_COMPONENTS_CLASS_NAMES.legend;
|
|
1578
2330
|
const items = [];
|
|
1579
2331
|
if (hasSimple)
|
|
1580
2332
|
items.push({
|
|
1581
2333
|
kind: "fracture",
|
|
1582
|
-
|
|
2334
|
+
key: "fractureSingle",
|
|
2335
|
+
label: labels.fractureSingle,
|
|
1583
2336
|
swarm: false,
|
|
1584
2337
|
water_intake: false
|
|
1585
2338
|
});
|
|
1586
2339
|
if (hasSwarm)
|
|
1587
2340
|
items.push({
|
|
1588
2341
|
kind: "fracture",
|
|
1589
|
-
|
|
2342
|
+
key: "fractureSwarm",
|
|
2343
|
+
label: labels.fractureSwarm,
|
|
1590
2344
|
swarm: true,
|
|
1591
2345
|
water_intake: false
|
|
1592
2346
|
});
|
|
1593
2347
|
if (hasWaterFx)
|
|
1594
2348
|
items.push({
|
|
1595
2349
|
kind: "fracture",
|
|
1596
|
-
|
|
2350
|
+
key: "fractureWater",
|
|
2351
|
+
label: labels.fractureWater,
|
|
1597
2352
|
swarm: false,
|
|
1598
2353
|
water_intake: true
|
|
1599
2354
|
});
|
|
1600
2355
|
if (hasCaveDry)
|
|
1601
2356
|
items.push({
|
|
1602
2357
|
kind: "cave",
|
|
1603
|
-
|
|
2358
|
+
key: "caveDry",
|
|
2359
|
+
label: labels.caveDry,
|
|
1604
2360
|
water_intake: false
|
|
1605
2361
|
});
|
|
1606
2362
|
if (hasCaveWet)
|
|
1607
|
-
items.push({
|
|
2363
|
+
items.push({
|
|
2364
|
+
kind: "cave",
|
|
2365
|
+
key: "caveWet",
|
|
2366
|
+
label: labels.caveWet,
|
|
2367
|
+
water_intake: true
|
|
2368
|
+
});
|
|
1608
2369
|
if (hasCementPad)
|
|
1609
2370
|
items.push({
|
|
1610
2371
|
kind: "construction",
|
|
1611
|
-
|
|
2372
|
+
key: "cementPad",
|
|
2373
|
+
label: labels.cementPad,
|
|
1612
2374
|
subKind: "cementPad"
|
|
1613
2375
|
});
|
|
1614
2376
|
if (hasBoreHole)
|
|
1615
2377
|
items.push({
|
|
1616
2378
|
kind: "construction",
|
|
1617
|
-
|
|
2379
|
+
key: "boreHole",
|
|
2380
|
+
label: labels.boreHole,
|
|
1618
2381
|
subKind: "boreHole"
|
|
1619
2382
|
});
|
|
1620
2383
|
if (hasSurfaceCase)
|
|
1621
2384
|
items.push({
|
|
1622
2385
|
kind: "construction",
|
|
1623
|
-
|
|
2386
|
+
key: "surfaceCase",
|
|
2387
|
+
label: labels.surfaceCase,
|
|
1624
2388
|
subKind: "surfaceCase"
|
|
1625
2389
|
});
|
|
1626
2390
|
if (hasHoleFillGravel)
|
|
1627
2391
|
items.push({
|
|
1628
2392
|
kind: "construction",
|
|
1629
|
-
|
|
2393
|
+
key: "holeFillGravel",
|
|
2394
|
+
label: labels.holeFillGravel,
|
|
1630
2395
|
subKind: "holeFillGravel"
|
|
1631
2396
|
});
|
|
1632
2397
|
if (hasHoleFillSeal)
|
|
1633
2398
|
items.push({
|
|
1634
2399
|
kind: "construction",
|
|
1635
|
-
|
|
2400
|
+
key: "holeFillSeal",
|
|
2401
|
+
label: labels.holeFillSeal,
|
|
1636
2402
|
subKind: "holeFillSeal"
|
|
1637
2403
|
});
|
|
1638
2404
|
if (hasWellCase)
|
|
1639
2405
|
items.push({
|
|
1640
2406
|
kind: "construction",
|
|
1641
|
-
|
|
2407
|
+
key: "wellCase",
|
|
2408
|
+
label: labels.wellCase,
|
|
1642
2409
|
subKind: "wellCase"
|
|
1643
2410
|
});
|
|
1644
2411
|
if (hasWellScreen)
|
|
1645
2412
|
items.push({
|
|
1646
2413
|
kind: "construction",
|
|
1647
|
-
|
|
2414
|
+
key: "wellScreen",
|
|
2415
|
+
label: labels.wellScreen,
|
|
1648
2416
|
subKind: "wellScreen"
|
|
1649
2417
|
});
|
|
1650
2418
|
if (hasReduction)
|
|
1651
2419
|
items.push({
|
|
1652
2420
|
kind: "construction",
|
|
1653
|
-
|
|
2421
|
+
key: "reduction",
|
|
2422
|
+
label: labels.reduction,
|
|
1654
2423
|
subKind: "reduction"
|
|
1655
2424
|
});
|
|
2425
|
+
if (hasCentralizer)
|
|
2426
|
+
items.push({
|
|
2427
|
+
kind: "construction",
|
|
2428
|
+
key: "centralizer",
|
|
2429
|
+
label: labels.centralizer,
|
|
2430
|
+
subKind: "centralizer"
|
|
2431
|
+
});
|
|
2432
|
+
if (hasPump)
|
|
2433
|
+
items.push({
|
|
2434
|
+
kind: "construction",
|
|
2435
|
+
key: "pump",
|
|
2436
|
+
label: labels.pump,
|
|
2437
|
+
subKind: "pump"
|
|
2438
|
+
});
|
|
1656
2439
|
if (hasConflict)
|
|
1657
2440
|
items.push({
|
|
1658
2441
|
kind: "construction",
|
|
1659
|
-
|
|
2442
|
+
key: "conflict",
|
|
2443
|
+
label: labels.conflict,
|
|
1660
2444
|
subKind: "conflict"
|
|
1661
2445
|
});
|
|
1662
|
-
|
|
2446
|
+
return items;
|
|
2447
|
+
}
|
|
2448
|
+
function drawLegendSymbol(symG, item, cx, rowSymY, { theme, cls, textures: legendTextures }) {
|
|
2449
|
+
const RC = "round";
|
|
2450
|
+
const rw = SYMBOL_WIDTH;
|
|
2451
|
+
const rh = SYMBOL_HEIGHT;
|
|
2452
|
+
if (item.kind === "fracture") {
|
|
2453
|
+
const color = item.water_intake ? theme.fracture.wetStroke : theme.fracture.dryStroke;
|
|
2454
|
+
if (item.swarm) {
|
|
2455
|
+
[-4, 0, 4].forEach((offset) => {
|
|
2456
|
+
symG.append("polyline").attr("class", cls.fracturePoly).attr(
|
|
2457
|
+
"points",
|
|
2458
|
+
`${cx},${rowSymY + offset} ${cx + 6},${rowSymY + offset - 1} ${cx + 12},${rowSymY + offset + 1} ${cx + 18},${rowSymY + offset - 0.5} ${cx + 24},${rowSymY + offset}`
|
|
2459
|
+
).attr("stroke", color).attr(
|
|
2460
|
+
"stroke-width",
|
|
2461
|
+
offset !== 0 ? theme.legend.fractureSideStrokeWidth : theme.legend.fractureStrokeWidth
|
|
2462
|
+
).attr("fill", "none").attr("stroke-linecap", RC).attr("stroke-linejoin", RC);
|
|
2463
|
+
});
|
|
2464
|
+
} else {
|
|
2465
|
+
symG.append("polyline").attr("class", cls.fracturePoly).attr(
|
|
2466
|
+
"points",
|
|
2467
|
+
`${cx},${rowSymY} ${cx + 5},${rowSymY - 1.5} ${cx + 11},${rowSymY + 1} ${cx + 17},${rowSymY - 0.5} ${cx + 24},${rowSymY}`
|
|
2468
|
+
).attr("stroke", color).attr("stroke-width", theme.legend.fractureStrokeWidth).attr("fill", "none").attr("stroke-linecap", RC).attr("stroke-linejoin", RC);
|
|
2469
|
+
}
|
|
2470
|
+
} else if (item.kind === "cave") {
|
|
2471
|
+
const color = item.water_intake ? theme.cave.wetStroke : theme.cave.dryStroke;
|
|
2472
|
+
const texture = item.water_intake ? legendTextures.cave_wet : legendTextures.cave_dry;
|
|
2473
|
+
symG.append("rect").attr("class", cls.caveFill).attr("x", cx).attr("y", rowSymY - rh / 2).attr("width", rw).attr("height", rh).attr("fill", texture.url()).attr("stroke", color).attr("stroke-width", theme.legend.itemStrokeWidth);
|
|
2474
|
+
} else if (item.subKind === "surfaceCase") {
|
|
2475
|
+
symG.append("rect").attr("class", cls.constructionRect).attr("x", cx).attr("y", rowSymY - rh / 2).attr("width", rw).attr("height", rh).attr("fill", legendTextures.surface_case.url()).attr("stroke", "none");
|
|
2476
|
+
symG.append("line").attr("class", cls.constructionRect).attr("x1", cx).attr("x2", cx).attr("y1", rowSymY - rh / 2).attr("y2", rowSymY + rh / 2).attr("stroke", theme.surfaceCase.stroke).attr("stroke-width", 2);
|
|
2477
|
+
symG.append("line").attr("class", cls.constructionRect).attr("x1", cx + rw).attr("x2", cx + rw).attr("y1", rowSymY - rh / 2).attr("y2", rowSymY + rh / 2).attr("stroke", theme.surfaceCase.stroke).attr("stroke-width", 2);
|
|
2478
|
+
} else if (item.subKind === "centralizer") {
|
|
2479
|
+
const pipeW = rw * 0.4;
|
|
2480
|
+
const pipeL = cx + (rw - pipeW) / 2;
|
|
2481
|
+
const pipeR = pipeL + pipeW;
|
|
2482
|
+
const y1 = rowSymY - rh / 2;
|
|
2483
|
+
const y2 = rowSymY + rh / 2;
|
|
2484
|
+
const bowH = rh * 0.3;
|
|
2485
|
+
for (const x of [pipeL, pipeR]) {
|
|
2486
|
+
symG.append("line").attr("class", cls.constructionRect).attr("x1", x).attr("x2", x).attr("y1", y1).attr("y2", y2).attr("stroke", theme.wellCase.stroke).attr("stroke-width", theme.legend.itemStrokeWidth);
|
|
2487
|
+
}
|
|
2488
|
+
for (const [from, to] of [
|
|
2489
|
+
[pipeL, cx],
|
|
2490
|
+
[pipeR, cx + rw]
|
|
2491
|
+
]) {
|
|
2492
|
+
symG.append("polyline").attr("class", cls.constructionRect).attr(
|
|
2493
|
+
"points",
|
|
2494
|
+
`${from},${rowSymY - bowH} ${to},${rowSymY} ${from},${rowSymY + bowH}`
|
|
2495
|
+
).attr("fill", theme.centralizer.fill).attr("stroke", theme.centralizer.stroke).attr("stroke-width", theme.centralizer.strokeWidth);
|
|
2496
|
+
}
|
|
2497
|
+
} else if (item.subKind === "pump") {
|
|
2498
|
+
const y1 = rowSymY - rh / 2;
|
|
2499
|
+
const y2 = rowSymY + rh / 2;
|
|
2500
|
+
const midX = cx + rw / 2;
|
|
2501
|
+
const riserHalf = rw * 0.12;
|
|
2502
|
+
const bodyHalf = rw * 0.28;
|
|
2503
|
+
const bodyTop = y1 + rh * 0.4;
|
|
2504
|
+
symG.append("rect").attr("class", cls.constructionRect).attr("x", midX - riserHalf).attr("y", y1).attr("width", 2 * riserHalf).attr("height", bodyTop - y1).attr("fill", theme.pump.riserFill).attr("stroke", "none");
|
|
2505
|
+
symG.append("path").attr("class", cls.constructionRect).attr("d", pipeWallsPath(midX - riserHalf, midX + riserHalf, y1, bodyTop)).attr("fill", "none").attr("stroke", theme.pump.riserStroke).attr("stroke-width", theme.pump.riserStrokeWidth);
|
|
2506
|
+
symG.append("path").attr("class", cls.constructionRect).attr(
|
|
2507
|
+
"d",
|
|
2508
|
+
`M${midX - bodyHalf},${bodyTop}H${midX + bodyHalf}V${y2}H${midX - bodyHalf}Z`
|
|
2509
|
+
).attr("fill", theme.pump.fill).attr("stroke", theme.pump.stroke).attr("stroke-width", theme.pump.strokeWidth);
|
|
2510
|
+
} else if (item.subKind === "reduction") {
|
|
2511
|
+
const topW = rw * 0.5;
|
|
2512
|
+
const y1 = rowSymY - rh / 2;
|
|
2513
|
+
const y2 = rowSymY + rh / 2;
|
|
2514
|
+
const midX = cx + rw / 2;
|
|
2515
|
+
const tl = `${midX - topW / 2},${y1}`;
|
|
2516
|
+
const tr = `${midX + topW / 2},${y1}`;
|
|
2517
|
+
symG.append("polygon").attr("class", cls.constructionRect).attr("points", `${tl} ${tr} ${cx + rw},${y2} ${cx},${y2}`).attr("fill", theme.reduction.fill).attr("stroke", "none");
|
|
2518
|
+
symG.append("path").attr("class", cls.constructionRect).attr("d", `M${tl}L${cx},${y2}M${tr}L${cx + rw},${y2}`).attr("fill", "none").attr("stroke", theme.reduction.stroke).attr("stroke-width", theme.legend.itemStrokeWidth);
|
|
2519
|
+
} else if (item.subKind === "wellCase" || item.subKind === "wellScreen" || item.subKind === "boreHole") {
|
|
2520
|
+
const y1 = rowSymY - rh / 2;
|
|
2521
|
+
const y2 = rowSymY + rh / 2;
|
|
2522
|
+
const shoe = 3;
|
|
2523
|
+
const xL = cx + shoe;
|
|
2524
|
+
const xR = cx + rw - shoe;
|
|
2525
|
+
const style = {
|
|
2526
|
+
wellCase: { fill: theme.wellCase.fill, stroke: theme.wellCase.stroke },
|
|
2527
|
+
wellScreen: {
|
|
2528
|
+
fill: legendTextures.well_screen.url(),
|
|
2529
|
+
stroke: theme.wellScreen.stroke
|
|
2530
|
+
},
|
|
2531
|
+
boreHole: { fill: theme.boreHole.fill, stroke: theme.boreHole.stroke }
|
|
2532
|
+
}[item.subKind];
|
|
2533
|
+
symG.append("rect").attr("class", cls.constructionRect).attr("x", xL).attr("y", y1).attr("width", xR - xL).attr("height", rh).attr("fill", style.fill).attr("stroke", "none");
|
|
2534
|
+
const walls = symG.append("path").attr("class", cls.constructionRect).attr(
|
|
2535
|
+
"d",
|
|
2536
|
+
pipeWallsPath(xL, xR, y1, y2) + (item.subKind === "boreHole" ? `M${xL},${y2}H${xR}` : "")
|
|
2537
|
+
).attr("fill", "none").attr("stroke", style.stroke).attr("stroke-width", theme.legend.itemStrokeWidth);
|
|
2538
|
+
if (item.subKind === "boreHole")
|
|
2539
|
+
walls.attr("stroke-dasharray", theme.boreHole.strokeDasharray);
|
|
2540
|
+
if (item.subKind === "wellCase")
|
|
2541
|
+
symG.append("path").attr("class", cls.constructionRect).attr("d", shoePath(xL, xR, y2, shoe)).attr("fill", style.stroke).attr("stroke", "none");
|
|
2542
|
+
if (item.subKind === "wellScreen")
|
|
2543
|
+
symG.append("path").attr("class", cls.constructionRect).attr(
|
|
2544
|
+
"d",
|
|
2545
|
+
screenEndPath(xL, xR, y1 + 0.5) + screenEndPath(xL, xR, y2 - 0.5)
|
|
2546
|
+
).attr("fill", "none").attr("stroke", style.stroke).attr("stroke-width", theme.wellScreen.endStrokeWidth).attr("stroke-dasharray", "2, 1.5");
|
|
2547
|
+
} else if (item.subKind === "cementPad") {
|
|
2548
|
+
const h = rh * 0.6;
|
|
2549
|
+
const { slabs } = getCementPadGeometry(
|
|
2550
|
+
rw,
|
|
2551
|
+
2 * cx + rw,
|
|
2552
|
+
rowSymY + h / 2,
|
|
2553
|
+
{ widthRatio: 1, height: h },
|
|
2554
|
+
rw * 0.3
|
|
2555
|
+
);
|
|
2556
|
+
for (const d of slabs)
|
|
2557
|
+
symG.append("path").attr("class", cls.constructionRect).attr("d", d).attr("fill", legendTextures.pad.url()).attr("stroke", theme.cementPad.stroke).attr("stroke-width", theme.legend.itemStrokeWidth).attr("stroke-linejoin", RC);
|
|
2558
|
+
} else {
|
|
2559
|
+
const symMap = {
|
|
2560
|
+
holeFillGravel: {
|
|
2561
|
+
fill: legendTextures.gravel_pack.url(),
|
|
2562
|
+
stroke: theme.holeFill.stroke
|
|
2563
|
+
},
|
|
2564
|
+
holeFillSeal: {
|
|
2565
|
+
fill: legendTextures.seal.url(),
|
|
2566
|
+
stroke: theme.holeFill.stroke
|
|
2567
|
+
},
|
|
2568
|
+
conflict: {
|
|
2569
|
+
fill: legendTextures.conflict.url(),
|
|
2570
|
+
stroke: theme.conflict.stroke
|
|
2571
|
+
}
|
|
2572
|
+
};
|
|
2573
|
+
const sym = symMap[item.subKind];
|
|
2574
|
+
const symRect = symG.append("rect").attr("class", cls.constructionRect).attr("x", cx).attr("y", rowSymY - rh / 2).attr("width", rw).attr("height", rh).attr("fill", sym.fill).attr("stroke", sym.stroke).attr("stroke-width", theme.legend.itemStrokeWidth);
|
|
2575
|
+
if (sym.dasharray) symRect.attr("stroke-dasharray", sym.dasharray);
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
function resolveStyle(options) {
|
|
2579
|
+
return {
|
|
2580
|
+
theme: defu(options.theme ?? {}, DEFAULT_WELL_THEME),
|
|
2581
|
+
cls: options.classNames ? { ...DEFAULT_COMPONENTS_CLASS_NAMES.legend, ...options.classNames } : DEFAULT_COMPONENTS_CLASS_NAMES.legend,
|
|
2582
|
+
textures: createWellTextures(options.textures)
|
|
2583
|
+
};
|
|
2584
|
+
}
|
|
2585
|
+
function drawWellLegendSymbol(selector, item, options = {}) {
|
|
2586
|
+
const style = resolveStyle(options);
|
|
2587
|
+
const svgEl = d37.select(selector);
|
|
2588
|
+
svgEl.selectAll("*").remove();
|
|
2589
|
+
svgEl.attr("width", SYMBOL_WIDTH + SYMBOL_MARGIN * 2).attr("height", SYMBOL_HEIGHT + SYMBOL_MARGIN * 2);
|
|
2590
|
+
Object.values(style.textures).forEach((t) => svgEl.call(t));
|
|
2591
|
+
const symG = svgEl.append("g").attr("class", style.cls.item);
|
|
2592
|
+
drawLegendSymbol(
|
|
2593
|
+
symG,
|
|
2594
|
+
item,
|
|
2595
|
+
SYMBOL_MARGIN,
|
|
2596
|
+
SYMBOL_MARGIN + SYMBOL_HEIGHT / 2,
|
|
2597
|
+
style
|
|
2598
|
+
);
|
|
2599
|
+
}
|
|
2600
|
+
function drawWellLegend(selector, profile, options = {}) {
|
|
2601
|
+
const cfg = defu(
|
|
2602
|
+
options.config ?? {},
|
|
2603
|
+
INTERACTIVE_RENDER_CONFIG.legend
|
|
2604
|
+
);
|
|
2605
|
+
const items = getWellLegendItems(profile, cfg.labels);
|
|
2606
|
+
const svgEl = d37.select(selector);
|
|
1663
2607
|
svgEl.selectAll("*").remove();
|
|
1664
2608
|
if (items.length === 0) {
|
|
1665
2609
|
svgEl.attr("width", 0).attr("height", 0);
|
|
1666
2610
|
return;
|
|
1667
2611
|
}
|
|
1668
|
-
const
|
|
1669
|
-
|
|
2612
|
+
const style = resolveStyle(options);
|
|
2613
|
+
const { theme, cls } = style;
|
|
2614
|
+
Object.values(style.textures).forEach((t) => svgEl.call(t));
|
|
1670
2615
|
const itemsPerRow = cfg.maxWidth ? Math.max(1, Math.floor((cfg.maxWidth - cfg.padding * 2) / cfg.itemWidth)) : items.length;
|
|
1671
2616
|
const numRows = Math.ceil(items.length / itemsPerRow);
|
|
1672
2617
|
const rowWidth = Math.min(items.length, itemsPerRow) * cfg.itemWidth;
|
|
1673
2618
|
const totalWidth = cfg.padding * 2 + rowWidth;
|
|
1674
2619
|
const totalHeight = numRows * cfg.height;
|
|
1675
2620
|
svgEl.attr("width", totalWidth).attr("height", totalHeight);
|
|
1676
|
-
const RC = "round";
|
|
1677
2621
|
const g = svgEl.append("g").attr("transform", `translate(${cfg.padding}, 2)`);
|
|
1678
2622
|
g.append("rect").attr("class", cls.border).attr("x", 0).attr("y", 0).attr("width", totalWidth - cfg.padding).attr("height", totalHeight - 4).attr("fill", "white").attr("rx", cfg.borderRadius).attr("stroke-width", theme.legend.borderStrokeWidth);
|
|
1679
2623
|
g.append("text").attr("class", cls.title).attr("x", 4).attr("y", 11).attr("font-size", theme.legend.fontSize).attr("font-family", theme.legend.fontFamily ?? "sans-serif").attr("font-weight", theme.legend.titleFontWeight ?? "bold").text(`${cfg.title}:`);
|
|
1680
|
-
const rw = 24;
|
|
1681
|
-
const rh = 12;
|
|
1682
2624
|
items.forEach((item, i) => {
|
|
1683
2625
|
const col = i % itemsPerRow;
|
|
1684
2626
|
const row = Math.floor(i / itemsPerRow);
|
|
1685
2627
|
const rowSymY = row * cfg.height + (cfg.height - 4) / 2;
|
|
1686
2628
|
const cx = col * cfg.itemWidth;
|
|
1687
2629
|
const symG = g.append("g").attr("class", cls.item);
|
|
1688
|
-
|
|
1689
|
-
const color = item.water_intake ? theme.fracture.wetStroke : theme.fracture.dryStroke;
|
|
1690
|
-
if (item.swarm) {
|
|
1691
|
-
[-4, 0, 4].forEach((offset) => {
|
|
1692
|
-
symG.append("polyline").attr("class", cls.fracturePoly).attr(
|
|
1693
|
-
"points",
|
|
1694
|
-
`${cx},${rowSymY + offset} ${cx + 6},${rowSymY + offset - 1} ${cx + 12},${rowSymY + offset + 1} ${cx + 18},${rowSymY + offset - 0.5} ${cx + 24},${rowSymY + offset}`
|
|
1695
|
-
).attr("stroke", color).attr(
|
|
1696
|
-
"stroke-width",
|
|
1697
|
-
offset !== 0 ? theme.legend.fractureSideStrokeWidth : theme.legend.fractureStrokeWidth
|
|
1698
|
-
).attr("fill", "none").attr("stroke-linecap", RC).attr("stroke-linejoin", RC);
|
|
1699
|
-
});
|
|
1700
|
-
} else {
|
|
1701
|
-
symG.append("polyline").attr("class", cls.fracturePoly).attr(
|
|
1702
|
-
"points",
|
|
1703
|
-
`${cx},${rowSymY} ${cx + 5},${rowSymY - 1.5} ${cx + 11},${rowSymY + 1} ${cx + 17},${rowSymY - 0.5} ${cx + 24},${rowSymY}`
|
|
1704
|
-
).attr("stroke", color).attr("stroke-width", theme.legend.fractureStrokeWidth).attr("fill", "none").attr("stroke-linecap", RC).attr("stroke-linejoin", RC);
|
|
1705
|
-
}
|
|
1706
|
-
} else if (item.kind === "cave") {
|
|
1707
|
-
const color = item.water_intake ? theme.cave.wetStroke : theme.cave.dryStroke;
|
|
1708
|
-
const texture = item.water_intake ? legendTextures.cave_wet : legendTextures.cave_dry;
|
|
1709
|
-
symG.append("rect").attr("class", cls.caveFill).attr("x", cx).attr("y", rowSymY - rh / 2).attr("width", rw).attr("height", rh).attr("fill", texture.url()).attr("stroke", color).attr("stroke-width", theme.legend.itemStrokeWidth);
|
|
1710
|
-
} else if (item.subKind === "surfaceCase") {
|
|
1711
|
-
symG.append("rect").attr("class", cls.constructionRect).attr("x", cx).attr("y", rowSymY - rh / 2).attr("width", rw).attr("height", rh).attr("fill", legendTextures.surface_case.url()).attr("stroke", "none");
|
|
1712
|
-
symG.append("line").attr("class", cls.constructionRect).attr("x1", cx).attr("x2", cx).attr("y1", rowSymY - rh / 2).attr("y2", rowSymY + rh / 2).attr("stroke", theme.surfaceCase.stroke).attr("stroke-width", 2);
|
|
1713
|
-
symG.append("line").attr("class", cls.constructionRect).attr("x1", cx + rw).attr("x2", cx + rw).attr("y1", rowSymY - rh / 2).attr("y2", rowSymY + rh / 2).attr("stroke", theme.surfaceCase.stroke).attr("stroke-width", 2);
|
|
1714
|
-
} else if (item.subKind === "reduction") {
|
|
1715
|
-
const topW = rw * 0.5;
|
|
1716
|
-
const y1 = rowSymY - rh / 2;
|
|
1717
|
-
const y2 = rowSymY + rh / 2;
|
|
1718
|
-
const midX = cx + rw / 2;
|
|
1719
|
-
symG.append("polygon").attr("class", cls.constructionRect).attr(
|
|
1720
|
-
"points",
|
|
1721
|
-
`${midX - topW / 2},${y1} ${midX + topW / 2},${y1} ${cx + rw},${y2} ${cx},${y2}`
|
|
1722
|
-
).attr("fill", theme.reduction.fill).attr("stroke", theme.reduction.stroke).attr("stroke-width", theme.legend.itemStrokeWidth);
|
|
1723
|
-
} else {
|
|
1724
|
-
const symMap = {
|
|
1725
|
-
boreHole: {
|
|
1726
|
-
fill: theme.boreHole.fill,
|
|
1727
|
-
stroke: theme.boreHole.stroke,
|
|
1728
|
-
dasharray: theme.boreHole.strokeDasharray
|
|
1729
|
-
},
|
|
1730
|
-
holeFillGravel: {
|
|
1731
|
-
fill: legendTextures.gravel_pack.url(),
|
|
1732
|
-
stroke: theme.holeFill.stroke
|
|
1733
|
-
},
|
|
1734
|
-
holeFillSeal: {
|
|
1735
|
-
fill: legendTextures.seal.url(),
|
|
1736
|
-
stroke: theme.holeFill.stroke
|
|
1737
|
-
},
|
|
1738
|
-
wellCase: { fill: theme.wellCase.fill, stroke: theme.wellCase.stroke },
|
|
1739
|
-
wellScreen: {
|
|
1740
|
-
fill: legendTextures.well_screen.url(),
|
|
1741
|
-
stroke: theme.wellScreen.stroke
|
|
1742
|
-
},
|
|
1743
|
-
cementPad: {
|
|
1744
|
-
fill: legendTextures.pad.url(),
|
|
1745
|
-
stroke: theme.cementPad.stroke
|
|
1746
|
-
},
|
|
1747
|
-
conflict: {
|
|
1748
|
-
fill: legendTextures.conflict.url(),
|
|
1749
|
-
stroke: theme.conflict.stroke
|
|
1750
|
-
}
|
|
1751
|
-
};
|
|
1752
|
-
const sym = symMap[item.subKind];
|
|
1753
|
-
const symRect = symG.append("rect").attr("class", cls.constructionRect).attr("x", cx).attr("y", rowSymY - rh / 2).attr("width", rw).attr("height", rh).attr("fill", sym.fill).attr("stroke", sym.stroke).attr("stroke-width", theme.legend.itemStrokeWidth);
|
|
1754
|
-
if (sym.dasharray) symRect.attr("stroke-dasharray", sym.dasharray);
|
|
1755
|
-
}
|
|
2630
|
+
drawLegendSymbol(symG, item, cx, rowSymY, style);
|
|
1756
2631
|
g.append("text").attr("class", cls.label).attr("x", cx + 28).attr("y", rowSymY + 3).attr("font-size", theme.legend.fontSize).attr("font-family", theme.legend.fontFamily ?? "sans-serif").attr("font-weight", theme.legend.labelFontWeight ?? 400).text(item.label);
|
|
1757
2632
|
});
|
|
1758
2633
|
}
|
|
1759
2634
|
|
|
1760
2635
|
// src/renderers/lithology.renderer.ts
|
|
2636
|
+
import * as d38 from "d3";
|
|
1761
2637
|
function drawLithology(ctx, data) {
|
|
1762
|
-
if (!data.length) return;
|
|
1763
2638
|
const {
|
|
1764
2639
|
groups: { lithologyGroup },
|
|
1765
2640
|
svg,
|
|
@@ -1783,10 +2658,219 @@ function drawLithology(ctx, data) {
|
|
|
1783
2658
|
const merged = mergeEnter(newLayers, rects);
|
|
1784
2659
|
withTransition(merged, transition).attr("y", getYPos).attr("height", getHeight).attr("fill", getLithologyFill(data, svg, ctx.theme.lithologyTexture));
|
|
1785
2660
|
}
|
|
2661
|
+
function drawLithologySwatch(selector, layer, options) {
|
|
2662
|
+
const { size, theme } = options;
|
|
2663
|
+
const svg = d38.select(selector);
|
|
2664
|
+
svg.selectAll("*").remove();
|
|
2665
|
+
svg.attr("width", size).attr("height", size);
|
|
2666
|
+
const fill = getLithologyFill([layer], svg, {
|
|
2667
|
+
...theme.lithologyTexture,
|
|
2668
|
+
// Denser pattern so a few strokes show inside the small square.
|
|
2669
|
+
size: Math.max(12, size * 3)
|
|
2670
|
+
});
|
|
2671
|
+
svg.append("rect").attr("x", 0.5).attr("y", 0.5).attr("width", size - 1).attr("height", size - 1).attr("fill", fill(layer)).attr("stroke", theme.lithology.stroke).attr("stroke-width", 0.5);
|
|
2672
|
+
}
|
|
2673
|
+
|
|
2674
|
+
// src/renderers/markers.renderer.ts
|
|
2675
|
+
function drawMarkers(ctx, data) {
|
|
2676
|
+
const group = ctx.groups.markersGroup;
|
|
2677
|
+
group.selectAll("*").remove();
|
|
2678
|
+
const cfg = ctx.renderConfig.markers;
|
|
2679
|
+
const theme = ctx.theme.markers;
|
|
2680
|
+
const r = cfg.radius;
|
|
2681
|
+
if (cfg.lithology) {
|
|
2682
|
+
const cx = (ctx.geoXLeft + ctx.geoXRight) / 2;
|
|
2683
|
+
getLithologyMarkers(data.lithology, ctx.depthFrom, ctx.depthTo).forEach(
|
|
2684
|
+
(marker) => {
|
|
2685
|
+
const top = ctx.yScale(marker.from);
|
|
2686
|
+
const bottom = ctx.yScale(marker.to);
|
|
2687
|
+
if (bottom - top < r) return;
|
|
2688
|
+
const cy = bottom - top >= 2 * r + 4 ? top + r + 2 : (top + bottom) / 2;
|
|
2689
|
+
const g = group.append("g").attr("class", ctx.classes.markers.lithology);
|
|
2690
|
+
g.append("circle").attr("cx", cx).attr("cy", cy).attr("r", r).attr("fill", theme.fill).attr("stroke", theme.stroke).attr("stroke-width", theme.strokeWidth);
|
|
2691
|
+
g.append("text").attr("x", cx).attr("y", cy).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("font-size", theme.fontSize).attr("font-family", theme.fontFamily ?? "sans-serif").attr("font-weight", theme.fontWeight ?? 600).attr("fill", theme.color).text(String(marker.index));
|
|
2692
|
+
}
|
|
2693
|
+
);
|
|
2694
|
+
}
|
|
2695
|
+
if (cfg.fractures) {
|
|
2696
|
+
const x = ctx.pocoCenterX + ctx.POCO_WIDTH * ctx.renderConfig.fractures.widthMultiplier / 2 + 3;
|
|
2697
|
+
getFractureMarkers(data.fractures, ctx.depthFrom, ctx.depthTo).forEach(
|
|
2698
|
+
(marker) => {
|
|
2699
|
+
group.append("text").attr("class", ctx.classes.markers.fracture).attr("x", x).attr("y", ctx.yScale(marker.depth)).attr("dominant-baseline", "central").attr("font-size", theme.fontSize).attr("font-family", theme.fontFamily ?? "sans-serif").attr("font-weight", theme.fontWeight ?? 600).attr("fill", theme.color).text(marker.label);
|
|
2700
|
+
}
|
|
2701
|
+
);
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
|
|
2705
|
+
// src/renderers/overlap.renderer.ts
|
|
2706
|
+
import textures3 from "textures";
|
|
2707
|
+
import { formatNumber as formatNumber3 } from "@welldot/utils";
|
|
2708
|
+
function drawOverlap(ctx) {
|
|
2709
|
+
const group = ctx.groups.overlapGroup;
|
|
2710
|
+
group.selectAll("*").remove();
|
|
2711
|
+
const { repeatedTo, depthFrom } = ctx;
|
|
2712
|
+
if (repeatedTo == null || repeatedTo <= depthFrom) return;
|
|
2713
|
+
const theme = ctx.theme.overlap;
|
|
2714
|
+
const { margins } = ctx.state;
|
|
2715
|
+
const overview = ctx.renderConfig.overview;
|
|
2716
|
+
const showsDescription = hasDescriptionColumn(ctx);
|
|
2717
|
+
const x0 = -margins.left + (overview.active ? overview.x + overview.width + 4 : 0);
|
|
2718
|
+
const x1 = showsDescription ? ctx.geoXRight + ctx.renderConfig.labels.descriptionXOffset - 4 : ctx.svgWidth - margins.left;
|
|
2719
|
+
const y0 = ctx.yScale(depthFrom);
|
|
2720
|
+
const y1 = ctx.yScale(repeatedTo);
|
|
2721
|
+
const hatch = textures3.lines().size(theme.size).strokeWidth(theme.strokeWidth).stroke(theme.stroke);
|
|
2722
|
+
ctx.svg.call(hatch);
|
|
2723
|
+
group.append("rect").attr("class", ctx.classes.overlap.band).attr("x", x0).attr("y", y0).attr("width", Math.max(0, x1 - x0)).attr("height", Math.max(0, y1 - y0)).attr("fill", hatch.url()).style("pointer-events", "none");
|
|
2724
|
+
group.append("line").attr("x1", x0).attr("x2", ctx.svgWidth - margins.left).attr("y1", y1).attr("y2", y1).attr("stroke", theme.ruleStroke).attr("stroke-width", 0.6).attr("stroke-dasharray", "3, 2");
|
|
2725
|
+
const whole = (m) => formatNumber3(ctx.units.length === "ft" ? m * 3.28084 : m, {
|
|
2726
|
+
maximumFractionDigits: 0,
|
|
2727
|
+
locale: ctx.locale
|
|
2728
|
+
});
|
|
2729
|
+
const unit = getLengthUnit(ctx.units.length);
|
|
2730
|
+
const range = `${whole(depthFrom)}\u2013${whole(repeatedTo)} ${unit}`;
|
|
2731
|
+
group.append("text").attr("class", ctx.classes.overlap.label).attr("x", ctx.svgWidth - margins.left - 2).attr("y", y0 + theme.fontSize + 1).attr("text-anchor", "end").attr("font-size", theme.fontSize).attr("font-family", theme.fontFamily ?? "monospace").attr("fill", theme.labelColor).text(formatOverlapLabel(ctx.renderConfig.overlap.label, range));
|
|
2732
|
+
}
|
|
2733
|
+
|
|
2734
|
+
// src/renderers/overview.renderer.ts
|
|
2735
|
+
function drawOverview(ctx, lithology) {
|
|
2736
|
+
const group = ctx.groups.overviewGroup;
|
|
2737
|
+
group.selectAll("*").remove();
|
|
2738
|
+
const cfg = ctx.renderConfig.overview;
|
|
2739
|
+
if (!cfg.active || lithology.length === 0 || ctx.totalDepth <= 0) return;
|
|
2740
|
+
const theme = ctx.theme.overview;
|
|
2741
|
+
const height = Math.min(cfg.height, ctx.state.height);
|
|
2742
|
+
const { y, window } = getOverviewGeometry(
|
|
2743
|
+
ctx.totalDepth,
|
|
2744
|
+
height,
|
|
2745
|
+
ctx.depthFrom,
|
|
2746
|
+
ctx.depthTo
|
|
2747
|
+
);
|
|
2748
|
+
lithology.forEach((layer) => {
|
|
2749
|
+
group.append("rect").attr("class", ctx.classes.overview.item).attr("x", cfg.x).attr("y", y(layer.from)).attr("width", cfg.width).attr("height", Math.max(0, y(layer.to) - y(layer.from))).attr("fill", layer.color || theme.emptyFill);
|
|
2750
|
+
});
|
|
2751
|
+
group.append("rect").attr("x", cfg.x).attr("y", 0).attr("width", cfg.width).attr("height", y(ctx.totalDepth)).attr("fill", "none").attr("stroke", theme.stroke).attr("stroke-width", theme.strokeWidth);
|
|
2752
|
+
group.append("rect").attr("class", ctx.classes.overview.window).attr("x", cfg.x - 2).attr("y", window.y).attr("width", cfg.width + 4).attr("height", window.height).attr("fill", "none").attr("stroke", theme.windowStroke).attr("stroke-width", theme.windowStrokeWidth);
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
// src/renderers/pump.renderer.ts
|
|
2756
|
+
import * as d39 from "d3";
|
|
2757
|
+
import { getProfileDiamValues as getProfileDiamValues5 } from "@welldot/utils";
|
|
2758
|
+
function getPumpSpans(panelTop, panelBottom, bodyTop, intakeY) {
|
|
2759
|
+
const riserBottom = Math.min(Math.max(panelTop, bodyTop), panelBottom);
|
|
2760
|
+
const top = Math.max(bodyTop, panelTop);
|
|
2761
|
+
const bottom = Math.min(intakeY, panelBottom);
|
|
2762
|
+
return {
|
|
2763
|
+
riserBottom,
|
|
2764
|
+
body: bottom > top ? { top, bottom, cutTop: top > bodyTop, cutBottom: bottom < intakeY } : null
|
|
2765
|
+
};
|
|
2766
|
+
}
|
|
2767
|
+
var riserBreakAmplitude = (width) => Math.min(2, width / 3);
|
|
2768
|
+
function getRiserTop(xLeft, xRight, y, broken) {
|
|
2769
|
+
if (!broken) return { edge: `H${xRight}`, breakLine: "" };
|
|
2770
|
+
const a = riserBreakAmplitude(xRight - xLeft);
|
|
2771
|
+
const w = xRight - xLeft;
|
|
2772
|
+
const zigzag = `L${xLeft + w / 3},${y - a}L${xLeft + 2 * w / 3},${y + a}L${xRight},${y}`;
|
|
2773
|
+
return { edge: zigzag, breakLine: `M${xLeft},${y}${zigzag}` };
|
|
2774
|
+
}
|
|
2775
|
+
var BODY_MAX_FILL = 0.85;
|
|
2776
|
+
var RISER_MAX_FILL = 0.7;
|
|
2777
|
+
function getPumpDiameters(intakeD, narrowestD, riserDiameter, cfg) {
|
|
2778
|
+
const maxBody = intakeD * BODY_MAX_FILL;
|
|
2779
|
+
const riser = Math.min(
|
|
2780
|
+
riserDiameter ?? intakeD * cfg.riserWidthRatio,
|
|
2781
|
+
narrowestD * RISER_MAX_FILL,
|
|
2782
|
+
maxBody * RISER_MAX_FILL
|
|
2783
|
+
);
|
|
2784
|
+
const body = Math.min(
|
|
2785
|
+
Math.max(intakeD * cfg.bodyWidthRatio, riser * 1.4),
|
|
2786
|
+
maxBody
|
|
2787
|
+
);
|
|
2788
|
+
return { riser, body };
|
|
2789
|
+
}
|
|
2790
|
+
function drawPump(ctx, pump) {
|
|
2791
|
+
const group = ctx.groups.pumpGroup;
|
|
2792
|
+
const cls = ctx.classes.pump;
|
|
2793
|
+
const cfg = ctx.renderConfig.construction.pump;
|
|
2794
|
+
const theme = ctx.theme.pump;
|
|
2795
|
+
const intake = pump?.intake_depth;
|
|
2796
|
+
const visible = !!pump && cfg.active && intake !== void 0 && intake > 0 && // the riser crosses this panel when the panel starts above the intake
|
|
2797
|
+
ctx.depthFrom < intake;
|
|
2798
|
+
const data = visible ? [pump] : [];
|
|
2799
|
+
const selection = group.selectAll(`g.${cls.item}`).data(data, (d) => d.id);
|
|
2800
|
+
selection.exit().remove();
|
|
2801
|
+
if (!visible) return;
|
|
2802
|
+
const maxXValue = d39.max(getProfileDiamValues5(ctx.constructionData)) || 0;
|
|
2803
|
+
const xScale = d39.scaleLinear().domain([0, maxXValue]).range([0, ctx.POCO_WIDTH]);
|
|
2804
|
+
const pipes = [
|
|
2805
|
+
...ctx.constructionData.well_case,
|
|
2806
|
+
...ctx.constructionData.well_screen
|
|
2807
|
+
];
|
|
2808
|
+
const casingD = diameterAt(pipes, intake) ?? diameterAt(ctx.constructionData.bore_hole, intake) ?? maxXValue;
|
|
2809
|
+
const narrowestD = Math.min(
|
|
2810
|
+
casingD,
|
|
2811
|
+
...[...pipes, ...ctx.constructionData.bore_hole].filter((i) => i.from < intake && i.to > 0).map((i) => i.diameter)
|
|
2812
|
+
);
|
|
2813
|
+
const { riser: riserD, body: bodyD } = getPumpDiameters(
|
|
2814
|
+
casingD,
|
|
2815
|
+
narrowestD,
|
|
2816
|
+
pump.riser_diameter,
|
|
2817
|
+
cfg
|
|
2818
|
+
);
|
|
2819
|
+
const riserLeft = (ctx.POCO_CENTER - xScale(riserD)) / 2;
|
|
2820
|
+
const riserRight = (ctx.POCO_CENTER + xScale(riserD)) / 2;
|
|
2821
|
+
const bodyLeft = (ctx.POCO_CENTER - xScale(bodyD)) / 2;
|
|
2822
|
+
const bodyRight = (ctx.POCO_CENTER + xScale(bodyD)) / 2;
|
|
2823
|
+
const yIntake = ctx.yScale(intake);
|
|
2824
|
+
const yBodyTop = yIntake - cfg.bodyHeight;
|
|
2825
|
+
const headDepth = Math.min(
|
|
2826
|
+
0,
|
|
2827
|
+
...pipes.filter((p) => p.from < 0).map((p) => p.from)
|
|
2828
|
+
);
|
|
2829
|
+
const headInPanel = ctx.depthFrom <= headDepth;
|
|
2830
|
+
const padOnHead = headDepth === 0 && !!ctx.constructionData.cement_pad?.thickness;
|
|
2831
|
+
const yRiserTop = headInPanel ? ctx.yScale(headDepth) - (padOnHead ? ctx.renderConfig.construction.cementPad.height - riserBreakAmplitude(xScale(riserD)) : 0) : ctx.yScale(ctx.depthFrom);
|
|
2832
|
+
const { riserBottom: yRiserBottom, body } = getPumpSpans(
|
|
2833
|
+
yRiserTop,
|
|
2834
|
+
ctx.yScale(ctx.depthTo),
|
|
2835
|
+
yBodyTop,
|
|
2836
|
+
yIntake
|
|
2837
|
+
);
|
|
2838
|
+
const r = Math.min(3, (bodyRight - bodyLeft) / 4);
|
|
2839
|
+
const entered = selection.enter().append("g").attr("class", cls.item).on("mouseover", ctx.tooltips.pump.show).on("mouseout", ctx.tooltips.pump.hide);
|
|
2840
|
+
entered.append("path").attr("class", `${cls.item}-riser-fill`);
|
|
2841
|
+
entered.append("path").attr("class", `${cls.item}-riser`);
|
|
2842
|
+
entered.append("path").attr("class", `${cls.item}-body`);
|
|
2843
|
+
entered.append("path").attr("class", `${cls.item}-intake`);
|
|
2844
|
+
const merged = entered.merge(selection);
|
|
2845
|
+
const top = getRiserTop(riserLeft, riserRight, yRiserTop, headInPanel);
|
|
2846
|
+
merged.select(`.${cls.item}-riser-fill`).attr(
|
|
2847
|
+
"d",
|
|
2848
|
+
yRiserBottom > yRiserTop ? `M${riserLeft},${yRiserTop}${top.edge}V${yRiserBottom}H${riserLeft}Z` : ""
|
|
2849
|
+
).attr("fill", theme.riserFill).attr("stroke", "none");
|
|
2850
|
+
merged.select(`.${cls.item}-riser`).attr(
|
|
2851
|
+
"d",
|
|
2852
|
+
yRiserBottom > yRiserTop ? `M${riserLeft},${yRiserTop}V${yRiserBottom}M${riserRight},${yRiserTop}V${yRiserBottom}${top.breakLine}` : ""
|
|
2853
|
+
).attr("stroke-linejoin", "round").attr("fill", "none").attr("stroke", theme.riserStroke).attr("stroke-width", theme.riserStrokeWidth);
|
|
2854
|
+
let bodyPath = "";
|
|
2855
|
+
if (body) {
|
|
2856
|
+
const rt = body.cutTop ? 0 : Math.min(r, (body.bottom - body.top) / 2);
|
|
2857
|
+
const rb = body.cutBottom ? 0 : Math.min(r, (body.bottom - body.top) / 2);
|
|
2858
|
+
const { top: top2, bottom } = body;
|
|
2859
|
+
bodyPath = `M${bodyLeft + rt},${top2}H${bodyRight - rt}Q${bodyRight},${top2} ${bodyRight},${top2 + rt}V${bottom - rb}Q${bodyRight},${bottom} ${bodyRight - rb},${bottom}H${bodyLeft + rb}Q${bodyLeft},${bottom} ${bodyLeft},${bottom - rb}V${top2 + rt}Q${bodyLeft},${top2} ${bodyLeft + rt},${top2}Z`;
|
|
2860
|
+
}
|
|
2861
|
+
merged.select(`.${cls.item}-body`).attr("d", bodyPath).attr("fill", theme.fill).attr("stroke", theme.stroke).attr("stroke-width", theme.strokeWidth);
|
|
2862
|
+
const hatchY = [
|
|
2863
|
+
yIntake - cfg.bodyHeight * 0.3,
|
|
2864
|
+
yIntake - cfg.bodyHeight * 0.15
|
|
2865
|
+
].filter((y) => body && y > body.top && y < body.bottom);
|
|
2866
|
+
merged.select(`.${cls.item}-intake`).attr(
|
|
2867
|
+
"d",
|
|
2868
|
+
hatchY.map((y) => `M${bodyLeft + 1.5},${y}H${bodyRight - 1.5}`).join("")
|
|
2869
|
+
).attr("fill", "none").attr("stroke", theme.stroke).attr("stroke-width", 0.8);
|
|
2870
|
+
}
|
|
1786
2871
|
|
|
1787
2872
|
// src/renderers/unit-labels.renderer.ts
|
|
1788
2873
|
function drawUnitLabels(ctx, data) {
|
|
1789
|
-
if (!ctx.renderConfig.unitLabels.active || !data.length) return;
|
|
1790
2874
|
const {
|
|
1791
2875
|
groups: { unitLabelsGroup },
|
|
1792
2876
|
depthFrom,
|
|
@@ -1797,6 +2881,7 @@ function drawUnitLabels(ctx, data) {
|
|
|
1797
2881
|
classes
|
|
1798
2882
|
} = ctx;
|
|
1799
2883
|
unitLabelsGroup.selectAll("*").remove();
|
|
2884
|
+
if (!renderConfig.unitLabels.active || !data.length) return;
|
|
1800
2885
|
const ru = renderConfig.unitLabels;
|
|
1801
2886
|
const rut = theme.unitLabels;
|
|
1802
2887
|
const sw = ru.stripWidth;
|
|
@@ -1877,7 +2962,7 @@ function buildSvgStyleBlock(theme) {
|
|
|
1877
2962
|
}
|
|
1878
2963
|
|
|
1879
2964
|
// src/Renderer.ts
|
|
1880
|
-
var
|
|
2965
|
+
var d310 = { ...d3module2, tip: d3tip2 };
|
|
1881
2966
|
var WellRenderer = class {
|
|
1882
2967
|
/**
|
|
1883
2968
|
* @param svgs - One entry per SVG panel; multi-entry for split-panel layouts.
|
|
@@ -1937,12 +3022,14 @@ var WellRenderer = class {
|
|
|
1937
3022
|
const { selector, height, width, margins } = inst;
|
|
1938
3023
|
const svgWidth = width + margins.left + margins.right;
|
|
1939
3024
|
const svgHeight = height + margins.top + margins.bottom;
|
|
1940
|
-
const svg =
|
|
3025
|
+
const svg = d310.select(selector);
|
|
1941
3026
|
svg.selectAll("*").remove();
|
|
1942
3027
|
svg.attr("height", svgHeight).attr("width", svgWidth);
|
|
1943
3028
|
const defs = svg.append("defs");
|
|
1944
3029
|
defs.append("style").text(buildSvgStyleBlock(this.theme));
|
|
1945
3030
|
defs.append("clipPath").attr("id", clipId).append("rect").attr("id", clipRectId).attr("x", 0).attr("y", 0).attr("width", 1e5).attr("height", 1e4);
|
|
3031
|
+
svg.append("g").attr("class", this.classes.overview.group).attr("transform", `translate(0, ${margins.top})`);
|
|
3032
|
+
svg.append("g").attr("class", this.classes.columnHeaders.group);
|
|
1946
3033
|
const poco = svg.append("g").attr("class", this.classes.wellGroup);
|
|
1947
3034
|
const geologic = poco.append("g").attr("class", this.classes.geologicGroup).attr("transform", `translate(${margins.left}, ${margins.top})`);
|
|
1948
3035
|
geologic.append("g").attr("class", this.classes.yAxis);
|
|
@@ -1957,6 +3044,7 @@ var WellRenderer = class {
|
|
|
1957
3044
|
);
|
|
1958
3045
|
const fracturesGroup = poco.append("g").attr("class", this.classes.fractures.group).attr("transform", `translate(${margins.left}, ${margins.top})`).attr("clip-path", `url(#${clipId})`);
|
|
1959
3046
|
fracturesGroup.append("g").attr("class", this.classes.highlights.fracturesGroup);
|
|
3047
|
+
poco.append("g").attr("class", this.classes.markers.group).attr("transform", `translate(${margins.left}, ${margins.top})`);
|
|
1960
3048
|
construction.append("g").attr("class", this.classes.cementPad.group);
|
|
1961
3049
|
construction.append("g").attr("class", this.classes.boreHole.group);
|
|
1962
3050
|
construction.append("g").attr("class", this.classes.surfaceCase.group);
|
|
@@ -1964,11 +3052,23 @@ var WellRenderer = class {
|
|
|
1964
3052
|
construction.append("g").attr("class", this.classes.wellCase.group);
|
|
1965
3053
|
construction.append("g").attr("class", this.classes.wellScreen.group);
|
|
1966
3054
|
construction.append("g").attr("class", this.classes.reduction.group);
|
|
3055
|
+
construction.append("g").attr("class", this.classes.pump.group);
|
|
3056
|
+
construction.append("g").attr("class", this.classes.centralizer.group);
|
|
1967
3057
|
construction.append("g").attr("class", this.classes.conflict.group);
|
|
1968
3058
|
construction.append("g").attr("class", this.classes.constructionLabels.group);
|
|
1969
3059
|
construction.append("g").attr("class", this.classes.highlights.constructionGroup);
|
|
3060
|
+
poco.append("g").attr("class", this.classes.overlap.group).attr("transform", `translate(${margins.left}, ${margins.top})`);
|
|
1970
3061
|
Object.values(this.textures).forEach((texture) => svg.call(texture));
|
|
1971
|
-
return {
|
|
3062
|
+
return {
|
|
3063
|
+
svg,
|
|
3064
|
+
height,
|
|
3065
|
+
width,
|
|
3066
|
+
margins,
|
|
3067
|
+
clipId,
|
|
3068
|
+
clipRectId,
|
|
3069
|
+
depthRange: inst.depthRange,
|
|
3070
|
+
repeatedTo: inst.repeatedTo
|
|
3071
|
+
};
|
|
1972
3072
|
}
|
|
1973
3073
|
/** Renders a standalone legend into the element matched by `selector`. */
|
|
1974
3074
|
renderLegend(selector, profile) {
|
|
@@ -1979,6 +3079,30 @@ var WellRenderer = class {
|
|
|
1979
3079
|
textures: this.renderConfig.textures
|
|
1980
3080
|
});
|
|
1981
3081
|
}
|
|
3082
|
+
/** Lists the legend entries `profile` needs, labeled from `renderConfig.legend.labels`. */
|
|
3083
|
+
getLegendItems(profile) {
|
|
3084
|
+
return getWellLegendItems(profile, this.renderConfig.legend.labels);
|
|
3085
|
+
}
|
|
3086
|
+
/**
|
|
3087
|
+
* Renders one legend entry's symbol (see {@link getLegendItems}) into its
|
|
3088
|
+
* own SVG matched by `selector`, with the textures it needs defined inside.
|
|
3089
|
+
*/
|
|
3090
|
+
renderLegendSymbol(selector, item) {
|
|
3091
|
+
drawWellLegendSymbol(selector, item, {
|
|
3092
|
+
theme: this.theme,
|
|
3093
|
+
classNames: this.classes.legend,
|
|
3094
|
+
textures: this.renderConfig.textures
|
|
3095
|
+
});
|
|
3096
|
+
}
|
|
3097
|
+
/**
|
|
3098
|
+
* Renders one lithology layer's fill as a `size`×`size` square into its
|
|
3099
|
+
* own SVG matched by `selector`, with its texture defined inside (e.g. for
|
|
3100
|
+
* a swatch in a PDF table). Call after `prepareSvg()`, which loads the
|
|
3101
|
+
* FGDC textures.
|
|
3102
|
+
*/
|
|
3103
|
+
renderLithologySwatch(selector, layer, size = 10) {
|
|
3104
|
+
drawLithologySwatch(selector, layer, { size, theme: this.theme });
|
|
3105
|
+
}
|
|
1982
3106
|
/**
|
|
1983
3107
|
* Multiplies the current zoom scale by `factor` (e.g. `1.25` to zoom in,
|
|
1984
3108
|
* `1 / 1.25` to zoom out) on every panel. No-op if both `renderConfig.zoom`
|
|
@@ -1995,7 +3119,7 @@ var WellRenderer = class {
|
|
|
1995
3119
|
* (defaults to `1`, i.e. the initial fit-to-container view).
|
|
1996
3120
|
*/
|
|
1997
3121
|
resetZoom() {
|
|
1998
|
-
const target =
|
|
3122
|
+
const target = d310.zoomIdentity.scale(this.renderConfig.zoomLevel ?? 1);
|
|
1999
3123
|
for (const state of this.instanceStates) {
|
|
2000
3124
|
if (!state.zoomNode) continue;
|
|
2001
3125
|
asSvgElement(state.svg).transition().call(state.zoomNode.transform, target);
|
|
@@ -2007,7 +3131,46 @@ var WellRenderer = class {
|
|
|
2007
3131
|
*/
|
|
2008
3132
|
getZoomScale() {
|
|
2009
3133
|
const node = this.instanceStates[0]?.svg.node();
|
|
2010
|
-
return node ?
|
|
3134
|
+
return node ? d310.zoomTransform(node).k : 1;
|
|
3135
|
+
}
|
|
3136
|
+
/**
|
|
3137
|
+
* Removes everything drawn on every panel (layers, labels, axis,
|
|
3138
|
+
* highlights) and keeps the structure `prepareSvg()` built, so the next
|
|
3139
|
+
* `draw()` needs no new `prepareSvg()`. `draw()` calls it for an empty well.
|
|
3140
|
+
*/
|
|
3141
|
+
clear() {
|
|
3142
|
+
const c = this.classes;
|
|
3143
|
+
const layerGroups = [
|
|
3144
|
+
c.overview.group,
|
|
3145
|
+
c.columnHeaders.group,
|
|
3146
|
+
c.yAxis,
|
|
3147
|
+
c.unitLabels.group,
|
|
3148
|
+
c.lithology.group,
|
|
3149
|
+
c.caves.group,
|
|
3150
|
+
c.labels.lithology.group,
|
|
3151
|
+
c.highlights.geologicGroup,
|
|
3152
|
+
c.highlights.constructionGroup,
|
|
3153
|
+
c.highlights.fracturesGroup,
|
|
3154
|
+
c.markers.group,
|
|
3155
|
+
c.cementPad.group,
|
|
3156
|
+
c.boreHole.group,
|
|
3157
|
+
c.surfaceCase.group,
|
|
3158
|
+
c.holeFill.group,
|
|
3159
|
+
c.wellCase.group,
|
|
3160
|
+
c.wellScreen.group,
|
|
3161
|
+
c.reduction.group,
|
|
3162
|
+
c.pump.group,
|
|
3163
|
+
c.centralizer.group,
|
|
3164
|
+
c.conflict.group,
|
|
3165
|
+
c.constructionLabels.group,
|
|
3166
|
+
c.overlap.group
|
|
3167
|
+
];
|
|
3168
|
+
for (const { svg } of this.instanceStates) {
|
|
3169
|
+
for (const cls of layerGroups) {
|
|
3170
|
+
svg.select(`.${cls}`).selectAll("*").interrupt().remove();
|
|
3171
|
+
}
|
|
3172
|
+
svg.select(`.${c.fractures.group}`).selectAll(`g.${c.fractures.item}`).interrupt().remove();
|
|
3173
|
+
}
|
|
2011
3174
|
}
|
|
2012
3175
|
/**
|
|
2013
3176
|
* Initialises the SVG DOM structure and preloads FGDC textures.
|
|
@@ -2020,14 +3183,19 @@ var WellRenderer = class {
|
|
|
2020
3183
|
);
|
|
2021
3184
|
}
|
|
2022
3185
|
/**
|
|
2023
|
-
* Renders the well profile into all configured SVG panels.
|
|
3186
|
+
* Renders the well profile into all configured SVG panels. Layers the
|
|
3187
|
+
* profile no longer has are removed; an empty well (`isWellEmpty`) clears
|
|
3188
|
+
* the panels (see {@link clear}).
|
|
2024
3189
|
* @param profile - The well data to render.
|
|
2025
3190
|
* @param options.units - Override the instance-level measurement units for this render.
|
|
2026
3191
|
* @param options.locale - Override the instance-level locale for this render.
|
|
2027
3192
|
* @param options.highlights - Highlight overlays to display on top of the profile.
|
|
2028
3193
|
*/
|
|
2029
3194
|
draw(profile, options = {}) {
|
|
2030
|
-
if (isWellEmpty(profile))
|
|
3195
|
+
if (isWellEmpty(profile)) {
|
|
3196
|
+
this.clear();
|
|
3197
|
+
return;
|
|
3198
|
+
}
|
|
2031
3199
|
if (profile.version !== 2) {
|
|
2032
3200
|
console.warn(
|
|
2033
3201
|
`[WellRenderer] Received a .well file with version ${profile.version ?? "unknown"}. Only v2 is supported. Normalize with deserializeWell() from @welldot/core before rendering.`
|
|
@@ -2039,35 +3207,18 @@ var WellRenderer = class {
|
|
|
2039
3207
|
}
|
|
2040
3208
|
const highlights = options.highlights ?? {};
|
|
2041
3209
|
const maxValues = getProfileLastItemsDepths(profile);
|
|
2042
|
-
const maxYValues =
|
|
2043
|
-
|
|
2044
|
-
this.
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
);
|
|
2051
|
-
|
|
2052
|
-
}
|
|
2053
|
-
const totalHeight = this.instanceStates.reduce((s, st) => s + st.height, 0) || 1;
|
|
2054
|
-
const yScaleGlobal = d37.scaleLinear().domain([0, maxYValues]).range([0, totalHeight]);
|
|
2055
|
-
let currentDepth = 0;
|
|
2056
|
-
for (const state of this.instanceStates) {
|
|
2057
|
-
const maxSvgDepth = yScaleGlobal.invert(
|
|
2058
|
-
yScaleGlobal(currentDepth) + state.height
|
|
2059
|
-
);
|
|
2060
|
-
this.drawLogToInstance(
|
|
2061
|
-
state,
|
|
2062
|
-
profile,
|
|
2063
|
-
currentDepth,
|
|
2064
|
-
maxSvgDepth,
|
|
2065
|
-
highlights
|
|
2066
|
-
);
|
|
2067
|
-
currentDepth = maxSvgDepth;
|
|
2068
|
-
}
|
|
3210
|
+
const maxYValues = d310.max(maxValues) || 0;
|
|
3211
|
+
const windows = resolvePanelWindows(
|
|
3212
|
+
this.instanceStates,
|
|
3213
|
+
maxYValues,
|
|
3214
|
+
getProfileTopDepth(profile)
|
|
3215
|
+
);
|
|
3216
|
+
this.instanceStates.forEach((state, i) => {
|
|
3217
|
+
const [from, to] = windows[i];
|
|
3218
|
+
this.drawLogToInstance(state, profile, from, to, maxYValues, highlights);
|
|
3219
|
+
});
|
|
2069
3220
|
}
|
|
2070
|
-
drawLogToInstance(state, profile, depthFrom, depthTo, highlights = {}) {
|
|
3221
|
+
drawLogToInstance(state, profile, depthFrom, depthTo, totalDepth, highlights = {}) {
|
|
2071
3222
|
const svg = state.svg;
|
|
2072
3223
|
const pocoGroup = svg.select(`.${this.classes.wellGroup}`);
|
|
2073
3224
|
const lithologyGroup = svg.select(`.${this.classes.lithology.group}`);
|
|
@@ -2084,6 +3235,8 @@ var WellRenderer = class {
|
|
|
2084
3235
|
const wellCaseGroup = svg.select(`.${this.classes.wellCase.group}`);
|
|
2085
3236
|
const wellScreenGroup = svg.select(`.${this.classes.wellScreen.group}`);
|
|
2086
3237
|
const reductionGroup = svg.select(`.${this.classes.reduction.group}`);
|
|
3238
|
+
const centralizerGroup = svg.select(`.${this.classes.centralizer.group}`);
|
|
3239
|
+
const pumpGroup = svg.select(`.${this.classes.pump.group}`);
|
|
2087
3240
|
const conflictGroup = svg.select(`.${this.classes.conflict.group}`);
|
|
2088
3241
|
const constructionLabelsGroup = svg.select(
|
|
2089
3242
|
`.${this.classes.constructionLabels.group}`
|
|
@@ -2098,13 +3251,19 @@ var WellRenderer = class {
|
|
|
2098
3251
|
`.${this.classes.highlights.fracturesGroup}`
|
|
2099
3252
|
);
|
|
2100
3253
|
const unitLabelsGroup = svg.select(`.${this.classes.unitLabels.group}`);
|
|
3254
|
+
const overviewGroup = svg.select(`.${this.classes.overview.group}`);
|
|
3255
|
+
const columnHeadersGroup = svg.select(
|
|
3256
|
+
`.${this.classes.columnHeaders.group}`
|
|
3257
|
+
);
|
|
3258
|
+
const markersGroup = svg.select(`.${this.classes.markers.group}`);
|
|
3259
|
+
const overlapGroup = svg.select(`.${this.classes.overlap.group}`);
|
|
2101
3260
|
const svgWidth = state.width + state.margins.left + state.margins.right;
|
|
2102
3261
|
const svgHeight = state.height + state.margins.top + state.margins.bottom;
|
|
2103
3262
|
const { pocoWidthRatio, pocoCenterRatio } = this.renderConfig.layout;
|
|
2104
3263
|
const POCO_WIDTH = svgWidth * pocoWidthRatio;
|
|
2105
3264
|
const POCO_CENTER = svgWidth * pocoCenterRatio;
|
|
2106
3265
|
const { duration, ease } = this.renderConfig.animation;
|
|
2107
|
-
const transition =
|
|
3266
|
+
const transition = d310.transition().duration(duration).ease(ease);
|
|
2108
3267
|
const tooltips = populateTooltips(
|
|
2109
3268
|
svg,
|
|
2110
3269
|
this.classes,
|
|
@@ -2129,14 +3288,15 @@ var WellRenderer = class {
|
|
|
2129
3288
|
well_case: profile.well_case,
|
|
2130
3289
|
well_screen: profile.well_screen,
|
|
2131
3290
|
reduction: profile.reduction,
|
|
3291
|
+
centralizers: profile.centralizers ?? [],
|
|
2132
3292
|
fractures: profile.fractures
|
|
2133
3293
|
};
|
|
2134
3294
|
const contentHeight = svgHeight - state.margins.top - state.margins.bottom;
|
|
2135
|
-
const yScaleLocal =
|
|
3295
|
+
const yScaleLocal = d310.scaleLinear().domain([depthFrom, depthTo]).range([0, contentHeight]);
|
|
2136
3296
|
const depthFactor = this.units.length === "ft" ? 3.28084 : 1;
|
|
2137
|
-
const yScaleAxis =
|
|
2138
|
-
const yAxis =
|
|
2139
|
-
(d) => `${
|
|
3297
|
+
const yScaleAxis = d310.scaleLinear().domain([depthFrom * depthFactor, depthTo * depthFactor]).range([0, contentHeight]);
|
|
3298
|
+
const yAxis = d310.axisLeft(yScaleAxis).tickFormat(
|
|
3299
|
+
(d) => `${formatNumber4(Number(d), {
|
|
2140
3300
|
maximumFractionDigits: this.units.length === "ft" ? 1 : 2,
|
|
2141
3301
|
locale: this.locale
|
|
2142
3302
|
})}${getLengthUnit(this.units.length)}`
|
|
@@ -2177,10 +3337,16 @@ var WellRenderer = class {
|
|
|
2177
3337
|
wellCaseGroup,
|
|
2178
3338
|
wellScreenGroup,
|
|
2179
3339
|
reductionGroup,
|
|
3340
|
+
centralizerGroup,
|
|
3341
|
+
pumpGroup,
|
|
2180
3342
|
conflictGroup,
|
|
2181
3343
|
highlightsGeologicGroup,
|
|
2182
3344
|
highlightsConstructionGroup,
|
|
2183
|
-
highlightsFracturesGroup
|
|
3345
|
+
highlightsFracturesGroup,
|
|
3346
|
+
overviewGroup,
|
|
3347
|
+
columnHeadersGroup,
|
|
3348
|
+
markersGroup,
|
|
3349
|
+
overlapGroup
|
|
2184
3350
|
};
|
|
2185
3351
|
const ctx = {
|
|
2186
3352
|
svg,
|
|
@@ -2194,6 +3360,8 @@ var WellRenderer = class {
|
|
|
2194
3360
|
geoXRight,
|
|
2195
3361
|
depthFrom,
|
|
2196
3362
|
depthTo,
|
|
3363
|
+
totalDepth,
|
|
3364
|
+
repeatedTo: state.repeatedTo,
|
|
2197
3365
|
yScale: yScaleLocal,
|
|
2198
3366
|
transition,
|
|
2199
3367
|
tooltips,
|
|
@@ -2207,6 +3375,7 @@ var WellRenderer = class {
|
|
|
2207
3375
|
groups
|
|
2208
3376
|
};
|
|
2209
3377
|
const inDepth = filterByDepth(depthFrom, depthTo);
|
|
3378
|
+
const currentPump = getCurrentPump2(profile);
|
|
2210
3379
|
const filteredConstruction = {
|
|
2211
3380
|
...constructionData,
|
|
2212
3381
|
bore_hole: constructionData.bore_hole.filter(inDepth),
|
|
@@ -2214,7 +3383,8 @@ var WellRenderer = class {
|
|
|
2214
3383
|
surface_case: constructionData.surface_case.filter(inDepth),
|
|
2215
3384
|
well_case: constructionData.well_case.filter(inDepth),
|
|
2216
3385
|
well_screen: constructionData.well_screen.filter(inDepth),
|
|
2217
|
-
reduction: constructionData.reduction?.filter(inDepth) ?? []
|
|
3386
|
+
reduction: constructionData.reduction?.filter(inDepth) ?? [],
|
|
3387
|
+
centralizers: constructionData.centralizers?.filter(inDepth) ?? []
|
|
2218
3388
|
};
|
|
2219
3389
|
const zooming = (e) => {
|
|
2220
3390
|
const transform = e.transform;
|
|
@@ -2230,33 +3400,14 @@ var WellRenderer = class {
|
|
|
2230
3400
|
if (!d) return null;
|
|
2231
3401
|
return transform.k * spanH(d);
|
|
2232
3402
|
});
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
const sc = d;
|
|
2236
|
-
const g = d37.select(nodes[i]);
|
|
2237
|
-
const y = transform.applyY(spanY(sc));
|
|
2238
|
-
const h = transform.k * spanH(sc);
|
|
2239
|
-
g.select(".surface-case-fill").attr("y", y).attr("height", h);
|
|
2240
|
-
g.selectAll(".surface-case-side").attr("y1", y).attr("y2", y + h);
|
|
2241
|
-
});
|
|
2242
|
-
const maxXValsReduction = getProfileDiamValues4(constructionData);
|
|
2243
|
-
const xScaleReduction = d37.scaleLinear().domain([0, d37.max(maxXValsReduction) || 0]).range([0, POCO_WIDTH]);
|
|
2244
|
-
reductionGroup.selectAll(`polygon.${this.classes.reduction.item}`).attr("points", (d) => {
|
|
2245
|
-
const r = d;
|
|
2246
|
-
const yTop = transform.applyY(spanY(r));
|
|
2247
|
-
const yBot = yTop + transform.k * spanH(r);
|
|
2248
|
-
const xTopLeft = (POCO_CENTER - xScaleReduction(r.diam_from)) / 2;
|
|
2249
|
-
const xTopRight = (POCO_CENTER + xScaleReduction(r.diam_from)) / 2;
|
|
2250
|
-
const xBotLeft = (POCO_CENTER - xScaleReduction(r.diam_to)) / 2;
|
|
2251
|
-
const xBotRight = (POCO_CENTER + xScaleReduction(r.diam_to)) / 2;
|
|
2252
|
-
return `${xTopLeft},${yTop} ${xTopRight},${yTop} ${xBotRight},${yBot} ${xBotLeft},${yBot}`;
|
|
2253
|
-
});
|
|
3403
|
+
layoutConstruction(zoomedCtx);
|
|
3404
|
+
drawCementPad(zoomedCtx, constructionData.cement_pad);
|
|
2254
3405
|
fracturesGroup.selectAll(`g.${this.classes.fractures.item}`).attr("transform", (d) => {
|
|
2255
3406
|
if (!d) return null;
|
|
2256
3407
|
const f = d;
|
|
2257
3408
|
const cx = pocoCenterX;
|
|
2258
3409
|
const cy = transform.applyY(yScaleLocal(f.depth));
|
|
2259
|
-
return `translate(0,${cy}) rotate(${f.dip},${cx},0)`;
|
|
3410
|
+
return `translate(0,${cy}) rotate(${fractureDip(f.dip)},${cx},0)`;
|
|
2260
3411
|
});
|
|
2261
3412
|
drawCaves(zoomedCtx, geologicData.caves?.filter(inDepth) ?? []);
|
|
2262
3413
|
drawUnitLabels(zoomedCtx, profile.lithology?.filter(inDepth) ?? []);
|
|
@@ -2267,10 +3418,17 @@ var WellRenderer = class {
|
|
|
2267
3418
|
) ?? [],
|
|
2268
3419
|
caves: profile.caves?.filter(inDepth) ?? []
|
|
2269
3420
|
});
|
|
3421
|
+
drawPump(zoomedCtx, currentPump);
|
|
3422
|
+
drawCentralizers(zoomedCtx, filteredConstruction);
|
|
2270
3423
|
drawConstructionLabels(zoomedCtx, {
|
|
2271
3424
|
well_case: constructionData.well_case.filter(inDepth),
|
|
2272
3425
|
well_screen: constructionData.well_screen.filter(inDepth)
|
|
2273
3426
|
});
|
|
3427
|
+
drawMarkers(zoomedCtx, {
|
|
3428
|
+
lithology: profile.lithology ?? [],
|
|
3429
|
+
fractures: profile.fractures ?? []
|
|
3430
|
+
});
|
|
3431
|
+
drawOverlap(zoomedCtx);
|
|
2274
3432
|
drawHighlights(zoomedCtx, highlights);
|
|
2275
3433
|
this.onZoom?.(transform.k);
|
|
2276
3434
|
};
|
|
@@ -2293,10 +3451,19 @@ var WellRenderer = class {
|
|
|
2293
3451
|
) ?? []
|
|
2294
3452
|
);
|
|
2295
3453
|
drawConstructive(ctx, filteredConstruction);
|
|
3454
|
+
drawPump(ctx, currentPump);
|
|
3455
|
+
drawCentralizers(ctx, filteredConstruction);
|
|
2296
3456
|
drawConstructionLabels(ctx, {
|
|
2297
3457
|
well_case: filteredConstruction.well_case,
|
|
2298
3458
|
well_screen: filteredConstruction.well_screen
|
|
2299
3459
|
});
|
|
3460
|
+
drawMarkers(ctx, {
|
|
3461
|
+
lithology: profile.lithology ?? [],
|
|
3462
|
+
fractures: profile.fractures ?? []
|
|
3463
|
+
});
|
|
3464
|
+
drawOverview(ctx, profile.lithology ?? []);
|
|
3465
|
+
drawColumnHeaders(ctx);
|
|
3466
|
+
drawOverlap(ctx);
|
|
2300
3467
|
svg.select(`#${state.clipRectId}`).attr("y", 0).attr("height", svgHeight);
|
|
2301
3468
|
drawHighlights(ctx, highlights);
|
|
2302
3469
|
};
|
|
@@ -2312,7 +3479,7 @@ var WellRenderer = class {
|
|
|
2312
3479
|
}
|
|
2313
3480
|
const { zoom: zoomEnabled, pan: panEnabled } = this.renderConfig;
|
|
2314
3481
|
if (zoomEnabled || panEnabled) {
|
|
2315
|
-
const zoomNode =
|
|
3482
|
+
const zoomNode = d310.zoom();
|
|
2316
3483
|
if (zoomEnabled || panEnabled) zoomNode.on("zoom", zooming);
|
|
2317
3484
|
zoomNode.scaleExtent(
|
|
2318
3485
|
zoomEnabled ? [
|
|
@@ -2328,7 +3495,7 @@ var WellRenderer = class {
|
|
|
2328
3495
|
if (initialZoom !== 1) {
|
|
2329
3496
|
asSvgElement(svg).call(
|
|
2330
3497
|
zoomNode.transform,
|
|
2331
|
-
|
|
3498
|
+
d310.zoomIdentity.scale(initialZoom)
|
|
2332
3499
|
);
|
|
2333
3500
|
}
|
|
2334
3501
|
}
|
|
@@ -2342,10 +3509,13 @@ export {
|
|
|
2342
3509
|
WellRenderer,
|
|
2343
3510
|
applyRenderLocale,
|
|
2344
3511
|
drawWellLegend,
|
|
3512
|
+
drawWellLegendSymbol,
|
|
2345
3513
|
formatDiameter,
|
|
2346
3514
|
formatLength,
|
|
2347
3515
|
getDiameterUnit,
|
|
2348
3516
|
getLengthUnit,
|
|
3517
|
+
getProfileTopDepth,
|
|
3518
|
+
getWellLegendItems,
|
|
2349
3519
|
importFgdcTextures,
|
|
2350
3520
|
resolveRenderLabel
|
|
2351
3521
|
};
|