@welldot/render 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -14
- package/dist/chunk-ODRL222Y.js +10 -0
- package/dist/chunk-ODRL222Y.js.map +1 -0
- package/dist/index.cjs +1403 -335
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +313 -33
- package/dist/index.d.ts +313 -33
- package/dist/index.js +1410 -340
- 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
|
|
@@ -46,6 +50,7 @@ var RENDER_LABELS = {
|
|
|
46
50
|
wellScreen: { pt: "Filtro", en: "Screen" },
|
|
47
51
|
reduction: { pt: "Redu\xE7\xE3o", en: "Reduction" },
|
|
48
52
|
centralizer: { pt: "Centralizador", en: "Centralizer" },
|
|
53
|
+
pump: { pt: "Bomba e edutor", en: "Pump and riser" },
|
|
49
54
|
cementPad: { pt: "Laje de cimento", en: "Cement pad" },
|
|
50
55
|
conflict: { pt: "Conflito", en: "Conflict" }
|
|
51
56
|
}
|
|
@@ -69,7 +74,9 @@ var RENDER_LABELS = {
|
|
|
69
74
|
wellCase: { title: { pt: "REVESTIMENTO", en: "CASING" } },
|
|
70
75
|
wellScreen: {
|
|
71
76
|
title: { pt: "FILTROS", en: "SCREENS" },
|
|
72
|
-
slot: { pt: "Ranhura:", en: "Slot:" }
|
|
77
|
+
slot: { pt: "Ranhura:", en: "Slot:" },
|
|
78
|
+
material: { pt: "Material:", en: "Material:" },
|
|
79
|
+
slotType: { pt: "Tipo:", en: "Type:" }
|
|
73
80
|
},
|
|
74
81
|
reduction: { title: { pt: "REDU\xC7\xC3O", en: "REDUCTION" } },
|
|
75
82
|
centralizer: {
|
|
@@ -77,6 +84,28 @@ var RENDER_LABELS = {
|
|
|
77
84
|
depth: { pt: "Profundidade:", en: "Depth:" },
|
|
78
85
|
spacing: { pt: "Espa\xE7amento:", en: "Spacing:" }
|
|
79
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
|
+
},
|
|
80
109
|
conflict: { title: { pt: "CONFLITO", en: "CONFLICT" } },
|
|
81
110
|
fracture: {
|
|
82
111
|
title: { pt: "FRATURA", en: "FRACTURE" },
|
|
@@ -102,6 +131,19 @@ var RENDER_LABELS = {
|
|
|
102
131
|
fractureWater: { pt: "fratura aberta", en: "open fracture" },
|
|
103
132
|
cave: { pt: "caverna", en: "cave" },
|
|
104
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
|
+
}
|
|
105
147
|
}
|
|
106
148
|
};
|
|
107
149
|
function resolveGroup(group, locale) {
|
|
@@ -123,6 +165,7 @@ function resolveTooltipLabels(locale) {
|
|
|
123
165
|
wellScreen: resolveGroup(t.wellScreen, locale),
|
|
124
166
|
reduction: resolveGroup(t.reduction, locale),
|
|
125
167
|
centralizer: resolveGroup(t.centralizer, locale),
|
|
168
|
+
pump: resolveGroup(t.pump, locale),
|
|
126
169
|
conflict: resolveGroup(t.conflict, locale),
|
|
127
170
|
fracture: resolveGroup(t.fracture, locale),
|
|
128
171
|
cementPad: resolveGroup(t.cementPad, locale),
|
|
@@ -144,7 +187,19 @@ function applyRenderLocale(config, locale) {
|
|
|
144
187
|
tooltipLabels: resolveTooltipLabels(locale),
|
|
145
188
|
labels: {
|
|
146
189
|
...config.labels,
|
|
147
|
-
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)
|
|
148
203
|
}
|
|
149
204
|
};
|
|
150
205
|
}
|
|
@@ -170,7 +225,7 @@ var DEFAULT_WELL_THEME = {
|
|
|
170
225
|
crackStrokeWidth: 0.7
|
|
171
226
|
}
|
|
172
227
|
},
|
|
173
|
-
cementPad: { stroke: "#303030", strokeWidth:
|
|
228
|
+
cementPad: { stroke: "#303030", strokeWidth: 1 },
|
|
174
229
|
boreHole: {
|
|
175
230
|
fill: "#ffffff",
|
|
176
231
|
stroke: "#191919",
|
|
@@ -179,11 +234,24 @@ var DEFAULT_WELL_THEME = {
|
|
|
179
234
|
strokeWidth: 1.2
|
|
180
235
|
},
|
|
181
236
|
surfaceCase: { stroke: "#000000", strokeWidth: 4 },
|
|
182
|
-
holeFill: { stroke: "#303030", strokeWidth: 2 },
|
|
237
|
+
holeFill: { stroke: "#303030", strokeWidth: 1.2 },
|
|
183
238
|
wellCase: { fill: "#ffffff", stroke: "#303030", strokeWidth: 2 },
|
|
184
|
-
wellScreen: {
|
|
239
|
+
wellScreen: {
|
|
240
|
+
stroke: "#303030",
|
|
241
|
+
strokeWidth: 2,
|
|
242
|
+
endStrokeWidth: 0.75,
|
|
243
|
+
endDasharray: "3, 2"
|
|
244
|
+
},
|
|
185
245
|
reduction: { fill: "#ffffff", stroke: "#303030", strokeWidth: 2 },
|
|
186
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
|
+
},
|
|
187
255
|
conflict: { stroke: "#e52117", strokeWidth: 4 },
|
|
188
256
|
unitLabels: {
|
|
189
257
|
geologicFill: "#f0f0f0",
|
|
@@ -219,6 +287,39 @@ var DEFAULT_WELL_THEME = {
|
|
|
219
287
|
headerFontWeight: 600,
|
|
220
288
|
bodyFontWeight: 400
|
|
221
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
|
+
},
|
|
222
323
|
legend: {
|
|
223
324
|
borderStrokeWidth: 0.8,
|
|
224
325
|
fractureStrokeWidth: 1.5,
|
|
@@ -276,9 +377,17 @@ var STATIC_RENDER_CONFIG = {
|
|
|
276
377
|
}
|
|
277
378
|
},
|
|
278
379
|
construction: {
|
|
279
|
-
cementPad: {
|
|
380
|
+
cementPad: { widthRatio: 1.4, height: 6 },
|
|
381
|
+
casingShoe: { active: true, size: 4 },
|
|
382
|
+
screenEnds: { active: true },
|
|
280
383
|
surfaceCase: { diameterPaddingRatio: 0.1 },
|
|
281
|
-
centralizer: { markerHalfHeight: 4 }
|
|
384
|
+
centralizer: { markerHalfHeight: 4 },
|
|
385
|
+
pump: {
|
|
386
|
+
active: true,
|
|
387
|
+
bodyHeight: 22,
|
|
388
|
+
bodyWidthRatio: 0.6,
|
|
389
|
+
riserWidthRatio: 0.3
|
|
390
|
+
}
|
|
282
391
|
},
|
|
283
392
|
tooltipLabels: resolveTooltipLabels("pt"),
|
|
284
393
|
labels: {
|
|
@@ -291,7 +400,11 @@ var STATIC_RENDER_CONFIG = {
|
|
|
291
400
|
stackingLineHeight: 10,
|
|
292
401
|
stackingGap: 0,
|
|
293
402
|
fractureLabelLeaderGap: 5,
|
|
294
|
-
lithology: true
|
|
403
|
+
lithology: true,
|
|
404
|
+
continuation: {
|
|
405
|
+
active: false,
|
|
406
|
+
prefix: resolveRenderLabel(RENDER_LABELS.continuation.prefix, "pt")
|
|
407
|
+
}
|
|
295
408
|
},
|
|
296
409
|
unitLabels: {
|
|
297
410
|
active: true,
|
|
@@ -350,10 +463,21 @@ var STATIC_RENDER_CONFIG = {
|
|
|
350
463
|
wellScreen: "Filtro",
|
|
351
464
|
reduction: "Redu\xE7\xE3o",
|
|
352
465
|
centralizer: "Centralizador",
|
|
466
|
+
pump: "Bomba e edutor",
|
|
353
467
|
cementPad: "Laje de cimento",
|
|
354
468
|
conflict: "Conflito"
|
|
355
469
|
}
|
|
356
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
|
+
},
|
|
357
481
|
highlights: DEFAULT_HIGHLIGHT_CONFIG
|
|
358
482
|
};
|
|
359
483
|
var INTERACTIVE_RENDER_CONFIG = {
|
|
@@ -389,9 +513,17 @@ var INTERACTIVE_RENDER_CONFIG = {
|
|
|
389
513
|
}
|
|
390
514
|
},
|
|
391
515
|
construction: {
|
|
392
|
-
cementPad: {
|
|
516
|
+
cementPad: { widthRatio: 1.4, height: 6 },
|
|
517
|
+
casingShoe: { active: true, size: 4 },
|
|
518
|
+
screenEnds: { active: true },
|
|
393
519
|
surfaceCase: { diameterPaddingRatio: 0.1 },
|
|
394
|
-
centralizer: { markerHalfHeight: 4 }
|
|
520
|
+
centralizer: { markerHalfHeight: 4 },
|
|
521
|
+
pump: {
|
|
522
|
+
active: true,
|
|
523
|
+
bodyHeight: 22,
|
|
524
|
+
bodyWidthRatio: 0.6,
|
|
525
|
+
riserWidthRatio: 0.3
|
|
526
|
+
}
|
|
395
527
|
},
|
|
396
528
|
tooltipLabels: resolveTooltipLabels("pt"),
|
|
397
529
|
labels: {
|
|
@@ -402,7 +534,11 @@ var INTERACTIVE_RENDER_CONFIG = {
|
|
|
402
534
|
descriptionXOffset: 78,
|
|
403
535
|
descriptionMaxWidth: 226,
|
|
404
536
|
stackingLineHeight: 11,
|
|
405
|
-
stackingGap: 0
|
|
537
|
+
stackingGap: 0,
|
|
538
|
+
continuation: {
|
|
539
|
+
active: false,
|
|
540
|
+
prefix: resolveRenderLabel(RENDER_LABELS.continuation.prefix, "pt")
|
|
541
|
+
}
|
|
406
542
|
},
|
|
407
543
|
unitLabels: {
|
|
408
544
|
active: false,
|
|
@@ -460,19 +596,24 @@ var INTERACTIVE_RENDER_CONFIG = {
|
|
|
460
596
|
wellScreen: "Filtro",
|
|
461
597
|
reduction: "Redu\xE7\xE3o",
|
|
462
598
|
centralizer: "Centralizador",
|
|
599
|
+
pump: "Bomba e edutor",
|
|
463
600
|
cementPad: "Laje de cimento",
|
|
464
601
|
conflict: "Conflito"
|
|
465
602
|
}
|
|
466
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
|
+
},
|
|
467
614
|
highlights: DEFAULT_HIGHLIGHT_CONFIG
|
|
468
615
|
};
|
|
469
616
|
|
|
470
|
-
// src/utils/fgdcTextures.ts
|
|
471
|
-
async function importFgdcTextures() {
|
|
472
|
-
const fgdcTextures = await import("./fgdcTextures-P5DTFNPT.js");
|
|
473
|
-
return fgdcTextures.default;
|
|
474
|
-
}
|
|
475
|
-
|
|
476
617
|
// src/Renderer.ts
|
|
477
618
|
import * as d3module2 from "d3";
|
|
478
619
|
import d3tip2 from "d3-tip";
|
|
@@ -480,6 +621,8 @@ import { defu as defu2 } from "defu";
|
|
|
480
621
|
|
|
481
622
|
// src/configs/render.textures.ts
|
|
482
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)}`;
|
|
483
626
|
function createWellTextures(cfg) {
|
|
484
627
|
const pad = {
|
|
485
628
|
background: "#ffffff",
|
|
@@ -527,7 +670,9 @@ function createWellTextures(cfg) {
|
|
|
527
670
|
...cfg?.surface_case
|
|
528
671
|
};
|
|
529
672
|
return {
|
|
530
|
-
|
|
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),
|
|
531
676
|
conflict: textures.lines().heavier().stroke(conflict.stroke),
|
|
532
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),
|
|
533
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),
|
|
@@ -543,8 +688,8 @@ import {
|
|
|
543
688
|
isWellEmpty
|
|
544
689
|
} from "@welldot/core";
|
|
545
690
|
import {
|
|
546
|
-
formatNumber as
|
|
547
|
-
|
|
691
|
+
formatNumber as formatNumber4,
|
|
692
|
+
getCurrentPump as getCurrentPump2,
|
|
548
693
|
getProfileLastItemsDepths
|
|
549
694
|
} from "@welldot/utils";
|
|
550
695
|
|
|
@@ -608,6 +753,10 @@ var DEFAULT_COMPONENTS_CLASS_NAMES = {
|
|
|
608
753
|
group: "centralizer",
|
|
609
754
|
item: "centralizer-marker"
|
|
610
755
|
},
|
|
756
|
+
pump: {
|
|
757
|
+
group: "pump",
|
|
758
|
+
item: "pump-item"
|
|
759
|
+
},
|
|
611
760
|
reduction: {
|
|
612
761
|
group: "reduction",
|
|
613
762
|
item: "reduction-poly"
|
|
@@ -639,6 +788,26 @@ var DEFAULT_COMPONENTS_CLASS_NAMES = {
|
|
|
639
788
|
caveFill: "cave-fill",
|
|
640
789
|
constructionRect: "construction-rect"
|
|
641
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
|
+
},
|
|
642
811
|
highlights: {
|
|
643
812
|
geologicGroup: "wp-highlights-geologic",
|
|
644
813
|
constructionGroup: "wp-highlights-construction",
|
|
@@ -653,6 +822,156 @@ var DEFAULT_COMPONENTS_CLASS_NAMES = {
|
|
|
653
822
|
// src/utils/render.utils.ts
|
|
654
823
|
import textures2 from "textures";
|
|
655
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
|
+
|
|
656
975
|
// src/utils/d3.utils.ts
|
|
657
976
|
function mergeEnter(enter, update) {
|
|
658
977
|
return enter.merge(update);
|
|
@@ -723,6 +1042,14 @@ var makeSeededPrng = (seed, scramble = 6271) => {
|
|
|
723
1042
|
// src/utils/tooltips.utils.ts
|
|
724
1043
|
import d3tip from "d3-tip";
|
|
725
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";
|
|
726
1053
|
import { formatNumber as formatNumber2 } from "@welldot/utils";
|
|
727
1054
|
var esc = (v) => sanitizeHtml(String(v ?? ""), { allowedTags: [], allowedAttributes: {} });
|
|
728
1055
|
var _tooltipCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -733,6 +1060,7 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
733
1060
|
if (cached && cached.signature === signature) {
|
|
734
1061
|
return cached.tooltips;
|
|
735
1062
|
}
|
|
1063
|
+
const material = (value) => getVocabLabel(CONSTRUCTION_MATERIALS, value, locale);
|
|
736
1064
|
const tipsText = {
|
|
737
1065
|
geology: (_, d) => `
|
|
738
1066
|
<span class="${customClasses.tooltip.title}">${labels.geology.title}</span>
|
|
@@ -765,14 +1093,15 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
765
1093
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
766
1094
|
<strong>${labels.common.diameter}</strong> ${esc(formatDiameter(d.diameter, units.diameter, locale))} ${esc(getDiameterUnit(units.diameter, locale))}
|
|
767
1095
|
</span>
|
|
768
|
-
<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>
|
|
769
1097
|
`,
|
|
770
1098
|
wellScreen: (_, d) => `
|
|
771
1099
|
<span class="${customClasses.tooltip.title}">${labels.wellScreen.title}</span>
|
|
772
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>
|
|
773
1101
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
774
1102
|
<strong>${labels.common.diameter}</strong> ${esc(formatDiameter(d.diameter, units.diameter, locale))} ${esc(getDiameterUnit(units.diameter, locale))}</span>
|
|
775
|
-
<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>` : ""}
|
|
776
1105
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
777
1106
|
<strong>${labels.wellScreen.slot}</strong> ${esc(formatNumber2(d.screen_slot, { maximumFractionDigits: 2, locale }))} mm
|
|
778
1107
|
</span>
|
|
@@ -783,17 +1112,29 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
783
1112
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
784
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))}
|
|
785
1114
|
</span>
|
|
786
|
-
<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>
|
|
787
1116
|
`,
|
|
788
1117
|
centralizer: (_, d) => `
|
|
789
1118
|
<span class="${customClasses.tooltip.title}">${labels.centralizer.title}</span>
|
|
790
1119
|
<span class="${customClasses.tooltip.primaryInfo}"><strong>${labels.centralizer.depth}</strong> ${esc(formatLength(d.depth, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>
|
|
791
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>` : ""}
|
|
792
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>` : ""}
|
|
793
|
-
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(d.type)}</span>
|
|
1122
|
+
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(getVocabLabel(CENTRALIZER_TYPES, d.type, locale))}</span>
|
|
794
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>` : ""}
|
|
795
1124
|
${d.description ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.description}</strong> ${esc(d.description)}</span>` : ""}
|
|
796
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
|
+
},
|
|
797
1138
|
conflict: (_, d) => `
|
|
798
1139
|
<span class="${customClasses.tooltip.title}">${labels.conflict.title}</span>
|
|
799
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>
|
|
@@ -804,14 +1145,14 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
804
1145
|
<span class="${customClasses.tooltip.title}">${title}</span>
|
|
805
1146
|
<span class="${customClasses.tooltip.primaryInfo}"><strong>${labels.fracture.depth}</strong> ${esc(formatLength(d.depth, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>
|
|
806
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>` : ""}
|
|
807
|
-
|
|
808
|
-
|
|
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>` : ""}
|
|
809
1150
|
${d.description ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.description}</strong> ${esc(d.description)}</span>` : ""}
|
|
810
1151
|
`;
|
|
811
1152
|
},
|
|
812
1153
|
cementPad: (_, d) => `
|
|
813
1154
|
<span class="${customClasses.tooltip.title}">${labels.cementPad.title}</span>
|
|
814
|
-
<span class="${customClasses.tooltip.primaryInfo}">${esc(d.type)}</span>
|
|
1155
|
+
<span class="${customClasses.tooltip.primaryInfo}">${esc(getVocabLabel(CEMENT_PAD_TYPES, d.type, locale))}</span>
|
|
815
1156
|
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.cementPad.thickness}</strong>
|
|
816
1157
|
${esc(formatLength(d.thickness, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>
|
|
817
1158
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
@@ -849,6 +1190,17 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
849
1190
|
};
|
|
850
1191
|
|
|
851
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
|
+
}
|
|
852
1204
|
var _fgdcTextures = {};
|
|
853
1205
|
var _fgdcTexturesPromise = null;
|
|
854
1206
|
var preloadFgdcTextures = () => {
|
|
@@ -957,14 +1309,23 @@ function drawAnnotationLabels(ctx, data) {
|
|
|
957
1309
|
}
|
|
958
1310
|
const items = [];
|
|
959
1311
|
if (active.has("lithology")) {
|
|
1312
|
+
const continuation = s.continuation;
|
|
960
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;
|
|
961
1316
|
items.push({
|
|
962
1317
|
sortDepth: d.from,
|
|
963
1318
|
baseY: ctx.yScale(Math.max(d.from, ctx.depthFrom)),
|
|
964
1319
|
originX: ctx.geoXRight,
|
|
965
1320
|
originY: ctx.yScale(Math.max(d.from, ctx.depthFrom)),
|
|
966
|
-
header:
|
|
967
|
-
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" } : {}
|
|
968
1329
|
});
|
|
969
1330
|
});
|
|
970
1331
|
}
|
|
@@ -977,7 +1338,8 @@ function drawAnnotationLabels(ctx, data) {
|
|
|
977
1338
|
originX: ctx.pocoCenterX,
|
|
978
1339
|
originY: ctx.yScale(d.depth),
|
|
979
1340
|
header: `${formatLength(d.depth, ctx.units.length, ctx.locale)}${getLengthUnit(ctx.units.length)} \xB7 ${typeLabel}`,
|
|
980
|
-
description: d.description || ""
|
|
1341
|
+
description: d.description || "",
|
|
1342
|
+
...show.has("rules") ? { rule: "dashed" } : {}
|
|
981
1343
|
});
|
|
982
1344
|
});
|
|
983
1345
|
}
|
|
@@ -997,14 +1359,15 @@ function drawAnnotationLabels(ctx, data) {
|
|
|
997
1359
|
}
|
|
998
1360
|
items.sort((a, b) => a.sortDepth - b.sortDepth);
|
|
999
1361
|
const labelPositions = [];
|
|
1000
|
-
let currY = 0;
|
|
1362
|
+
let currY = ctx.repeatedTo != null ? s.stackingLineHeight + 2 : 0;
|
|
1001
1363
|
const charsPerLine = Math.max(
|
|
1002
1364
|
1,
|
|
1003
1365
|
Math.floor(s.descriptionMaxWidth / (st.fontSize * 0.6))
|
|
1004
1366
|
);
|
|
1005
1367
|
items.forEach((item) => {
|
|
1006
|
-
const descLines = Math.ceil((item.description.length || 1) / charsPerLine);
|
|
1007
|
-
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;
|
|
1008
1371
|
const yLabel = Math.max(item.baseY, currY + s.stackingGap);
|
|
1009
1372
|
currY = yLabel + estH;
|
|
1010
1373
|
labelPositions.push({ item, yLabel, estH });
|
|
@@ -1021,16 +1384,41 @@ function drawAnnotationLabels(ctx, data) {
|
|
|
1021
1384
|
if (show.has("description")) {
|
|
1022
1385
|
const lineH = s.stackingLineHeight;
|
|
1023
1386
|
const bgFill = st.annotationBg ?? "white";
|
|
1387
|
+
const swatchFill = labelPositions.some((p) => p.item.swatch) ? getLithologyFill(data.lithology, ctx.svg, ctx.theme.lithologyTexture) : null;
|
|
1024
1388
|
labelPositions.forEach(({ item, yLabel, estH }) => {
|
|
1025
1389
|
const labelG = ctx.groups.lithologyLabelsGroup.append("g").attr("class", ctx.classes.labels.lithology.label).attr("transform", `translate(${labelX},${yLabel})`);
|
|
1026
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");
|
|
1027
|
-
|
|
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
|
+
}
|
|
1028
1412
|
if (item.description) {
|
|
1029
1413
|
const lines = wrapText(item.description, charsPerLine);
|
|
1030
|
-
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);
|
|
1031
1415
|
lines.forEach((line, i) => {
|
|
1032
1416
|
bodyEl.append("tspan").attr("x", 0).attr("dy", i === 0 ? 0 : lineH).text(line);
|
|
1033
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);
|
|
1034
1422
|
}
|
|
1035
1423
|
});
|
|
1036
1424
|
}
|
|
@@ -1051,7 +1439,6 @@ var makePointKey = (type) => (d, i) => {
|
|
|
1051
1439
|
|
|
1052
1440
|
// src/renderers/caves.renderer.ts
|
|
1053
1441
|
function drawCaves(ctx, data) {
|
|
1054
|
-
if (!data.length) return;
|
|
1055
1442
|
const {
|
|
1056
1443
|
groups: { cavesGroup },
|
|
1057
1444
|
geoXLeft,
|
|
@@ -1061,7 +1448,7 @@ function drawCaves(ctx, data) {
|
|
|
1061
1448
|
yScale,
|
|
1062
1449
|
renderConfig,
|
|
1063
1450
|
theme,
|
|
1064
|
-
textures:
|
|
1451
|
+
textures: textures4,
|
|
1065
1452
|
classes,
|
|
1066
1453
|
tooltips
|
|
1067
1454
|
} = ctx;
|
|
@@ -1098,7 +1485,7 @@ function drawCaves(ctx, data) {
|
|
|
1098
1485
|
const botPath = botCut ? `M ${geoXLeft.toFixed(1)},${yBot.toFixed(1)} L ${geoXRight.toFixed(1)},${yBot.toFixed(1)}` : ptsToSmoothPath(botPts);
|
|
1099
1486
|
const botReversed = botCut ? `L ${geoXLeft.toFixed(1)},${yBot.toFixed(1)}` : ptsToSmoothPath([...botPts].reverse(), { omitMoveTo: true });
|
|
1100
1487
|
const closedPath = `${topPath} L ${geoXRight.toFixed(1)},${yBot.toFixed(1)}${botReversed} L ${geoXLeft.toFixed(1)},${yTop.toFixed(1)} Z`;
|
|
1101
|
-
const caveTexture = cave.water_intake ?
|
|
1488
|
+
const caveTexture = cave.water_intake ? textures4.cave_wet : textures4.cave_dry;
|
|
1102
1489
|
const caveStroke = cave.water_intake ? theme.cave.wetStroke : theme.cave.dryStroke;
|
|
1103
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");
|
|
1104
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");
|
|
@@ -1110,9 +1497,6 @@ function drawCaves(ctx, data) {
|
|
|
1110
1497
|
// src/renderers/centralizers.renderer.ts
|
|
1111
1498
|
import * as d32 from "d3";
|
|
1112
1499
|
import { getCentralizerDepths, getProfileDiamValues } from "@welldot/utils";
|
|
1113
|
-
function diameterAt(items, depth) {
|
|
1114
|
-
return items.find((i) => depth >= i.from && depth <= i.to)?.diameter;
|
|
1115
|
-
}
|
|
1116
1500
|
function drawCentralizers(ctx, data) {
|
|
1117
1501
|
const group = ctx.groups.centralizerGroup;
|
|
1118
1502
|
const cls = ctx.classes.centralizer;
|
|
@@ -1149,8 +1533,108 @@ function drawCentralizers(ctx, data) {
|
|
|
1149
1533
|
});
|
|
1150
1534
|
}
|
|
1151
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
|
+
|
|
1152
1635
|
// src/renderers/construction-labels.renderer.ts
|
|
1153
1636
|
import * as d33 from "d3";
|
|
1637
|
+
import { CONSTRUCTION_MATERIALS as CONSTRUCTION_MATERIALS2, getVocabLabel as getVocabLabel2 } from "@welldot/core";
|
|
1154
1638
|
import { getProfileDiamValues as getProfileDiamValues2 } from "@welldot/utils";
|
|
1155
1639
|
function drawConstructionLabels(ctx, data) {
|
|
1156
1640
|
if (!ctx.renderConfig.constructionLabels.active) return;
|
|
@@ -1159,16 +1643,18 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1159
1643
|
const clct = ctx.theme.constructionLabels;
|
|
1160
1644
|
const fmtD = (mm) => formatDiameter(mm, ctx.units.diameter, ctx.locale);
|
|
1161
1645
|
const dUnit = getDiameterUnit(ctx.units.diameter, ctx.locale);
|
|
1646
|
+
const material = (value) => getVocabLabel2(CONSTRUCTION_MATERIALS2, value, ctx.locale);
|
|
1162
1647
|
const maxXValues = getProfileDiamValues2(ctx.constructionData);
|
|
1163
1648
|
const xScale = d33.scaleLinear().domain([0, d33.max(maxXValues) || 0]).range([0, ctx.POCO_WIDTH]);
|
|
1164
1649
|
const occupied = [];
|
|
1165
|
-
const
|
|
1650
|
+
const onRight = clc.side === "right";
|
|
1651
|
+
const continuation = ctx.renderConfig.labels.continuation;
|
|
1652
|
+
const placeLabel = (d, label) => {
|
|
1166
1653
|
const clampedFrom = Math.max(d.from, ctx.depthFrom);
|
|
1167
1654
|
const clampedTo = Math.min(d.to, ctx.depthTo);
|
|
1168
1655
|
if (clampedFrom >= clampedTo) return;
|
|
1656
|
+
const text = continuation?.active && d.from < ctx.depthFrom ? `\u2191 ${label}` : label;
|
|
1169
1657
|
const midY = ctx.yScale((clampedFrom + clampedTo) / 2);
|
|
1170
|
-
const leftEdgeX = (ctx.POCO_CENTER - xScale(d.diameter)) / 2;
|
|
1171
|
-
const labelRightX = leftEdgeX - clc.xOffset;
|
|
1172
1658
|
const charW = clct.fontSize * 0.52;
|
|
1173
1659
|
const lineH = clct.fontSize * 1.35;
|
|
1174
1660
|
const vertPad = 6;
|
|
@@ -1185,16 +1671,17 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1185
1671
|
lines = [text];
|
|
1186
1672
|
boxW = text.length * charW + 8;
|
|
1187
1673
|
}
|
|
1674
|
+
const labelRightX = onRight ? (ctx.POCO_CENTER + ctx.POCO_WIDTH) / 2 + clc.xOffset + boxW : (ctx.POCO_CENTER - xScale(d.diameter)) / 2 - clc.xOffset;
|
|
1188
1675
|
const labelH = lines.length * lineH + vertPad;
|
|
1189
|
-
let labelY = midY - labelH / 2;
|
|
1676
|
+
let labelY = onRight ? ctx.yScale(clampedFrom) + 1 : midY - labelH / 2;
|
|
1190
1677
|
for (const pos of occupied) {
|
|
1191
1678
|
if (labelY < pos.bot && labelY + labelH > pos.top) labelY = pos.bot + 2;
|
|
1192
1679
|
}
|
|
1193
1680
|
occupied.push({ top: labelY, bot: labelY + labelH });
|
|
1194
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);
|
|
1195
|
-
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");
|
|
1196
1683
|
lines.forEach((line, i) => {
|
|
1197
|
-
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);
|
|
1198
1685
|
});
|
|
1199
1686
|
};
|
|
1200
1687
|
let lastDiam = 0;
|
|
@@ -1207,7 +1694,7 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1207
1694
|
}).forEach(
|
|
1208
1695
|
(d) => placeLabel(
|
|
1209
1696
|
d,
|
|
1210
|
-
`${clc.labels.wellCasePrefix} ${fmtD(d.diameter)}${dUnit} ${d.type}`
|
|
1697
|
+
`${clc.labels.wellCasePrefix} ${fmtD(d.diameter)}${dUnit} ${material(d.type)}`
|
|
1211
1698
|
)
|
|
1212
1699
|
);
|
|
1213
1700
|
lastDiam = 0;
|
|
@@ -1220,7 +1707,7 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1220
1707
|
}).forEach(
|
|
1221
1708
|
(d) => placeLabel(
|
|
1222
1709
|
d,
|
|
1223
|
-
`${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}`
|
|
1224
1711
|
)
|
|
1225
1712
|
);
|
|
1226
1713
|
}
|
|
@@ -1228,110 +1715,307 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1228
1715
|
// src/renderers/construction.renderer.ts
|
|
1229
1716
|
import * as d34 from "d3";
|
|
1230
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
|
+
}
|
|
1231
1916
|
function drawConstructive(ctx, data) {
|
|
1232
1917
|
const { getHeight, getYPos } = getYAxisFunctions(ctx.yScale, {
|
|
1233
1918
|
from: ctx.depthFrom,
|
|
1234
1919
|
to: ctx.depthTo
|
|
1235
1920
|
});
|
|
1236
|
-
const
|
|
1237
|
-
const
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
).attr("
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
withTransition(mergedHole, ctx.transition).attr("y", getYPos).attr("height", getHeight);
|
|
1263
|
-
const surfaceCaseGs = ctx.groups.surfaceCaseGroup.selectAll(`g.${ctx.classes.surfaceCase.rect}`).data(data.surface_case, makeIntervalKey("surface_case"));
|
|
1264
|
-
surfaceCaseGs.exit().transition(ctx.transition).style("opacity", 0).remove();
|
|
1265
|
-
const newSC = surfaceCaseGs.enter().append("g").attr("class", ctx.classes.surfaceCase.rect).on("mouseover", ctx.tooltips.surfaceCase.show).on("mouseout", ctx.tooltips.surfaceCase.hide);
|
|
1266
|
-
newSC.append("rect").attr("class", "surface-case-fill").attr("stroke", "none").attr("y", yPos).attr("height", 0);
|
|
1267
|
-
newSC.append("line").attr("class", "surface-case-side").attr("stroke", ctx.theme.surfaceCase.stroke).attr("stroke-width", ctx.theme.surfaceCase.strokeWidth);
|
|
1268
|
-
newSC.append("line").attr("class", "surface-case-side").attr("stroke", ctx.theme.surfaceCase.stroke).attr("stroke-width", ctx.theme.surfaceCase.strokeWidth);
|
|
1269
|
-
const mergedSC = mergeEnter(newSC, surfaceCaseGs);
|
|
1270
|
-
mergedSC.each((d, i, nodes) => {
|
|
1271
|
-
const x = (ctx.POCO_CENTER - xScale(
|
|
1272
|
-
d.diameter + d.diameter * rcc.surfaceCase.diameterPaddingRatio
|
|
1273
|
-
)) / 2;
|
|
1274
|
-
const w = xScale(
|
|
1275
|
-
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()
|
|
1276
1947
|
);
|
|
1277
|
-
|
|
1278
|
-
g.select(".surface-case-fill").attr("x", x).attr("width", w).attr("fill", ctx.textures.surface_case.url());
|
|
1279
|
-
const sideNodes = g.selectAll(".surface-case-side").nodes();
|
|
1280
|
-
d34.select(sideNodes[0]).attr("x1", x).attr("x2", x);
|
|
1281
|
-
d34.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);
|
|
1282
1949
|
});
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
ctx.
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
"
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
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"));
|
|
1314
1996
|
reduction.exit().transition(ctx.transition).style("opacity", 0).remove();
|
|
1315
|
-
const
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
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
|
|
1325
2010
|
);
|
|
1326
|
-
const
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
const mergedConflicts = mergeConflicts(conflictAreas, 1);
|
|
1330
|
-
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"));
|
|
1331
2014
|
conflict.exit().transition(ctx.transition).attr("height", 0).remove();
|
|
1332
|
-
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);
|
|
1333
2016
|
const mergedConflict = mergeEnter(newConflict, conflict).attr("x", (d) => (ctx.POCO_CENTER - xScale(d.diameter)) / 2).attr("width", (d) => xScale(d.diameter));
|
|
1334
|
-
withTransition(mergedConflict, ctx.transition).attr("y",
|
|
2017
|
+
withTransition(mergedConflict, ctx.transition).attr("y", getYPos).attr("height", getHeight);
|
|
2018
|
+
layoutConstruction(ctx, true);
|
|
1335
2019
|
}
|
|
1336
2020
|
|
|
1337
2021
|
// src/renderers/fractures.renderer.ts
|
|
@@ -1347,7 +2031,6 @@ function wavyLine(rng, steps, baseY, jitter, startInset, endInset) {
|
|
|
1347
2031
|
return pts;
|
|
1348
2032
|
}
|
|
1349
2033
|
function drawFractures(ctx, data) {
|
|
1350
|
-
if (!data.length) return;
|
|
1351
2034
|
const {
|
|
1352
2035
|
groups: { fracturesGroup },
|
|
1353
2036
|
POCO_WIDTH,
|
|
@@ -1369,7 +2052,7 @@ function drawFractures(ctx, data) {
|
|
|
1369
2052
|
const merged = mergeEnter(entered, groups);
|
|
1370
2053
|
merged.attr(
|
|
1371
2054
|
"transform",
|
|
1372
|
-
(fracture) => `translate(0,${yScale(fracture.depth)}) rotate(${fracture.dip},${pocoCenterX},0)`
|
|
2055
|
+
(fracture) => `translate(0,${yScale(fracture.depth)}) rotate(${fractureDip(fracture.dip)},${pocoCenterX},0)`
|
|
1373
2056
|
);
|
|
1374
2057
|
merged.each(function(fracture) {
|
|
1375
2058
|
const g = d35.select(this);
|
|
@@ -1514,24 +2197,26 @@ function drawHighlights(ctx, hl) {
|
|
|
1514
2197
|
const maxXVals = getProfileDiamValues4(ctx.constructionData);
|
|
1515
2198
|
const xScaleConstr = d36.scaleLinear().domain([0, d36.max(maxXVals) || 0]).range([0, ctx.POCO_WIDTH]);
|
|
1516
2199
|
const constructionConfig = ctx.renderConfig.construction;
|
|
1517
|
-
if (hl.cement_pad && ctx.depthFrom
|
|
1518
|
-
const
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
const cpY = ctx.yScale(0) - ctx.yScale(
|
|
1522
|
-
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
|
|
1523
2204
|
);
|
|
1524
|
-
const
|
|
1525
|
-
|
|
1526
|
-
|
|
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)
|
|
1527
2212
|
);
|
|
1528
2213
|
drawHighlightItem(
|
|
1529
2214
|
ctx,
|
|
1530
2215
|
ctx.groups.highlightsConstructionGroup,
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
2216
|
+
pad.x,
|
|
2217
|
+
pad.y,
|
|
2218
|
+
pad.width,
|
|
2219
|
+
pad.height,
|
|
1535
2220
|
hl.cement_pad.label
|
|
1536
2221
|
);
|
|
1537
2222
|
}
|
|
@@ -1607,8 +2292,12 @@ function drawHighlights(ctx, hl) {
|
|
|
1607
2292
|
// src/renderers/legend.renderer.ts
|
|
1608
2293
|
import * as d3module from "d3";
|
|
1609
2294
|
import { defu } from "defu";
|
|
2295
|
+
import { getCurrentPump } from "@welldot/utils";
|
|
1610
2296
|
var d37 = { ...d3module };
|
|
1611
|
-
|
|
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) {
|
|
1612
2301
|
const fractures = profile.fractures ?? [];
|
|
1613
2302
|
const caves = profile.caves ?? [];
|
|
1614
2303
|
const boreHoles = profile.bore_hole ?? [];
|
|
@@ -1629,6 +2318,7 @@ function drawWellLegend(selector, profile, options = {}) {
|
|
|
1629
2318
|
const hasWellScreen = wellScreens.length > 0;
|
|
1630
2319
|
const hasReduction = reductions.length > 0;
|
|
1631
2320
|
const hasCentralizer = (profile.centralizers ?? []).length > 0;
|
|
2321
|
+
const hasPump = getCurrentPump(profile)?.intake_depth !== void 0;
|
|
1632
2322
|
const hasCementPad = !!profile.cement_pad?.thickness;
|
|
1633
2323
|
const hasConflict = mergeConflicts(
|
|
1634
2324
|
[
|
|
@@ -1637,222 +2327,314 @@ function drawWellLegend(selector, profile, options = {}) {
|
|
|
1637
2327
|
],
|
|
1638
2328
|
1
|
|
1639
2329
|
).length > 0;
|
|
1640
|
-
const cfg = defu(
|
|
1641
|
-
options.config ?? {},
|
|
1642
|
-
INTERACTIVE_RENDER_CONFIG.legend
|
|
1643
|
-
);
|
|
1644
|
-
const theme = defu(options.theme ?? {}, DEFAULT_WELL_THEME);
|
|
1645
|
-
const cls = options.classNames ? { ...DEFAULT_COMPONENTS_CLASS_NAMES.legend, ...options.classNames } : DEFAULT_COMPONENTS_CLASS_NAMES.legend;
|
|
1646
2330
|
const items = [];
|
|
1647
2331
|
if (hasSimple)
|
|
1648
2332
|
items.push({
|
|
1649
2333
|
kind: "fracture",
|
|
1650
|
-
|
|
2334
|
+
key: "fractureSingle",
|
|
2335
|
+
label: labels.fractureSingle,
|
|
1651
2336
|
swarm: false,
|
|
1652
2337
|
water_intake: false
|
|
1653
2338
|
});
|
|
1654
2339
|
if (hasSwarm)
|
|
1655
2340
|
items.push({
|
|
1656
2341
|
kind: "fracture",
|
|
1657
|
-
|
|
2342
|
+
key: "fractureSwarm",
|
|
2343
|
+
label: labels.fractureSwarm,
|
|
1658
2344
|
swarm: true,
|
|
1659
2345
|
water_intake: false
|
|
1660
2346
|
});
|
|
1661
2347
|
if (hasWaterFx)
|
|
1662
2348
|
items.push({
|
|
1663
2349
|
kind: "fracture",
|
|
1664
|
-
|
|
2350
|
+
key: "fractureWater",
|
|
2351
|
+
label: labels.fractureWater,
|
|
1665
2352
|
swarm: false,
|
|
1666
2353
|
water_intake: true
|
|
1667
2354
|
});
|
|
1668
2355
|
if (hasCaveDry)
|
|
1669
2356
|
items.push({
|
|
1670
2357
|
kind: "cave",
|
|
1671
|
-
|
|
2358
|
+
key: "caveDry",
|
|
2359
|
+
label: labels.caveDry,
|
|
1672
2360
|
water_intake: false
|
|
1673
2361
|
});
|
|
1674
2362
|
if (hasCaveWet)
|
|
1675
|
-
items.push({
|
|
2363
|
+
items.push({
|
|
2364
|
+
kind: "cave",
|
|
2365
|
+
key: "caveWet",
|
|
2366
|
+
label: labels.caveWet,
|
|
2367
|
+
water_intake: true
|
|
2368
|
+
});
|
|
1676
2369
|
if (hasCementPad)
|
|
1677
2370
|
items.push({
|
|
1678
2371
|
kind: "construction",
|
|
1679
|
-
|
|
2372
|
+
key: "cementPad",
|
|
2373
|
+
label: labels.cementPad,
|
|
1680
2374
|
subKind: "cementPad"
|
|
1681
2375
|
});
|
|
1682
2376
|
if (hasBoreHole)
|
|
1683
2377
|
items.push({
|
|
1684
2378
|
kind: "construction",
|
|
1685
|
-
|
|
2379
|
+
key: "boreHole",
|
|
2380
|
+
label: labels.boreHole,
|
|
1686
2381
|
subKind: "boreHole"
|
|
1687
2382
|
});
|
|
1688
2383
|
if (hasSurfaceCase)
|
|
1689
2384
|
items.push({
|
|
1690
2385
|
kind: "construction",
|
|
1691
|
-
|
|
2386
|
+
key: "surfaceCase",
|
|
2387
|
+
label: labels.surfaceCase,
|
|
1692
2388
|
subKind: "surfaceCase"
|
|
1693
2389
|
});
|
|
1694
2390
|
if (hasHoleFillGravel)
|
|
1695
2391
|
items.push({
|
|
1696
2392
|
kind: "construction",
|
|
1697
|
-
|
|
2393
|
+
key: "holeFillGravel",
|
|
2394
|
+
label: labels.holeFillGravel,
|
|
1698
2395
|
subKind: "holeFillGravel"
|
|
1699
2396
|
});
|
|
1700
2397
|
if (hasHoleFillSeal)
|
|
1701
2398
|
items.push({
|
|
1702
2399
|
kind: "construction",
|
|
1703
|
-
|
|
2400
|
+
key: "holeFillSeal",
|
|
2401
|
+
label: labels.holeFillSeal,
|
|
1704
2402
|
subKind: "holeFillSeal"
|
|
1705
2403
|
});
|
|
1706
2404
|
if (hasWellCase)
|
|
1707
2405
|
items.push({
|
|
1708
2406
|
kind: "construction",
|
|
1709
|
-
|
|
2407
|
+
key: "wellCase",
|
|
2408
|
+
label: labels.wellCase,
|
|
1710
2409
|
subKind: "wellCase"
|
|
1711
2410
|
});
|
|
1712
2411
|
if (hasWellScreen)
|
|
1713
2412
|
items.push({
|
|
1714
2413
|
kind: "construction",
|
|
1715
|
-
|
|
2414
|
+
key: "wellScreen",
|
|
2415
|
+
label: labels.wellScreen,
|
|
1716
2416
|
subKind: "wellScreen"
|
|
1717
2417
|
});
|
|
1718
2418
|
if (hasReduction)
|
|
1719
2419
|
items.push({
|
|
1720
2420
|
kind: "construction",
|
|
1721
|
-
|
|
2421
|
+
key: "reduction",
|
|
2422
|
+
label: labels.reduction,
|
|
1722
2423
|
subKind: "reduction"
|
|
1723
2424
|
});
|
|
1724
2425
|
if (hasCentralizer)
|
|
1725
2426
|
items.push({
|
|
1726
2427
|
kind: "construction",
|
|
1727
|
-
|
|
2428
|
+
key: "centralizer",
|
|
2429
|
+
label: labels.centralizer,
|
|
1728
2430
|
subKind: "centralizer"
|
|
1729
2431
|
});
|
|
2432
|
+
if (hasPump)
|
|
2433
|
+
items.push({
|
|
2434
|
+
kind: "construction",
|
|
2435
|
+
key: "pump",
|
|
2436
|
+
label: labels.pump,
|
|
2437
|
+
subKind: "pump"
|
|
2438
|
+
});
|
|
1730
2439
|
if (hasConflict)
|
|
1731
2440
|
items.push({
|
|
1732
2441
|
kind: "construction",
|
|
1733
|
-
|
|
2442
|
+
key: "conflict",
|
|
2443
|
+
label: labels.conflict,
|
|
1734
2444
|
subKind: "conflict"
|
|
1735
2445
|
});
|
|
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);
|
|
1736
2606
|
const svgEl = d37.select(selector);
|
|
1737
2607
|
svgEl.selectAll("*").remove();
|
|
1738
2608
|
if (items.length === 0) {
|
|
1739
2609
|
svgEl.attr("width", 0).attr("height", 0);
|
|
1740
2610
|
return;
|
|
1741
2611
|
}
|
|
1742
|
-
const
|
|
1743
|
-
|
|
2612
|
+
const style = resolveStyle(options);
|
|
2613
|
+
const { theme, cls } = style;
|
|
2614
|
+
Object.values(style.textures).forEach((t) => svgEl.call(t));
|
|
1744
2615
|
const itemsPerRow = cfg.maxWidth ? Math.max(1, Math.floor((cfg.maxWidth - cfg.padding * 2) / cfg.itemWidth)) : items.length;
|
|
1745
2616
|
const numRows = Math.ceil(items.length / itemsPerRow);
|
|
1746
2617
|
const rowWidth = Math.min(items.length, itemsPerRow) * cfg.itemWidth;
|
|
1747
2618
|
const totalWidth = cfg.padding * 2 + rowWidth;
|
|
1748
2619
|
const totalHeight = numRows * cfg.height;
|
|
1749
2620
|
svgEl.attr("width", totalWidth).attr("height", totalHeight);
|
|
1750
|
-
const RC = "round";
|
|
1751
2621
|
const g = svgEl.append("g").attr("transform", `translate(${cfg.padding}, 2)`);
|
|
1752
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);
|
|
1753
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}:`);
|
|
1754
|
-
const rw = 24;
|
|
1755
|
-
const rh = 12;
|
|
1756
2624
|
items.forEach((item, i) => {
|
|
1757
2625
|
const col = i % itemsPerRow;
|
|
1758
2626
|
const row = Math.floor(i / itemsPerRow);
|
|
1759
2627
|
const rowSymY = row * cfg.height + (cfg.height - 4) / 2;
|
|
1760
2628
|
const cx = col * cfg.itemWidth;
|
|
1761
2629
|
const symG = g.append("g").attr("class", cls.item);
|
|
1762
|
-
|
|
1763
|
-
const color = item.water_intake ? theme.fracture.wetStroke : theme.fracture.dryStroke;
|
|
1764
|
-
if (item.swarm) {
|
|
1765
|
-
[-4, 0, 4].forEach((offset) => {
|
|
1766
|
-
symG.append("polyline").attr("class", cls.fracturePoly).attr(
|
|
1767
|
-
"points",
|
|
1768
|
-
`${cx},${rowSymY + offset} ${cx + 6},${rowSymY + offset - 1} ${cx + 12},${rowSymY + offset + 1} ${cx + 18},${rowSymY + offset - 0.5} ${cx + 24},${rowSymY + offset}`
|
|
1769
|
-
).attr("stroke", color).attr(
|
|
1770
|
-
"stroke-width",
|
|
1771
|
-
offset !== 0 ? theme.legend.fractureSideStrokeWidth : theme.legend.fractureStrokeWidth
|
|
1772
|
-
).attr("fill", "none").attr("stroke-linecap", RC).attr("stroke-linejoin", RC);
|
|
1773
|
-
});
|
|
1774
|
-
} else {
|
|
1775
|
-
symG.append("polyline").attr("class", cls.fracturePoly).attr(
|
|
1776
|
-
"points",
|
|
1777
|
-
`${cx},${rowSymY} ${cx + 5},${rowSymY - 1.5} ${cx + 11},${rowSymY + 1} ${cx + 17},${rowSymY - 0.5} ${cx + 24},${rowSymY}`
|
|
1778
|
-
).attr("stroke", color).attr("stroke-width", theme.legend.fractureStrokeWidth).attr("fill", "none").attr("stroke-linecap", RC).attr("stroke-linejoin", RC);
|
|
1779
|
-
}
|
|
1780
|
-
} else if (item.kind === "cave") {
|
|
1781
|
-
const color = item.water_intake ? theme.cave.wetStroke : theme.cave.dryStroke;
|
|
1782
|
-
const texture = item.water_intake ? legendTextures.cave_wet : legendTextures.cave_dry;
|
|
1783
|
-
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);
|
|
1784
|
-
} else if (item.subKind === "surfaceCase") {
|
|
1785
|
-
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");
|
|
1786
|
-
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);
|
|
1787
|
-
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);
|
|
1788
|
-
} else if (item.subKind === "centralizer") {
|
|
1789
|
-
const pipeW = rw * 0.4;
|
|
1790
|
-
const pipeL = cx + (rw - pipeW) / 2;
|
|
1791
|
-
const pipeR = pipeL + pipeW;
|
|
1792
|
-
const y1 = rowSymY - rh / 2;
|
|
1793
|
-
const y2 = rowSymY + rh / 2;
|
|
1794
|
-
const bowH = rh * 0.3;
|
|
1795
|
-
for (const x of [pipeL, pipeR]) {
|
|
1796
|
-
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);
|
|
1797
|
-
}
|
|
1798
|
-
for (const [from, to] of [
|
|
1799
|
-
[pipeL, cx],
|
|
1800
|
-
[pipeR, cx + rw]
|
|
1801
|
-
]) {
|
|
1802
|
-
symG.append("polyline").attr("class", cls.constructionRect).attr(
|
|
1803
|
-
"points",
|
|
1804
|
-
`${from},${rowSymY - bowH} ${to},${rowSymY} ${from},${rowSymY + bowH}`
|
|
1805
|
-
).attr("fill", theme.centralizer.fill).attr("stroke", theme.centralizer.stroke).attr("stroke-width", theme.centralizer.strokeWidth);
|
|
1806
|
-
}
|
|
1807
|
-
} else if (item.subKind === "reduction") {
|
|
1808
|
-
const topW = rw * 0.5;
|
|
1809
|
-
const y1 = rowSymY - rh / 2;
|
|
1810
|
-
const y2 = rowSymY + rh / 2;
|
|
1811
|
-
const midX = cx + rw / 2;
|
|
1812
|
-
symG.append("polygon").attr("class", cls.constructionRect).attr(
|
|
1813
|
-
"points",
|
|
1814
|
-
`${midX - topW / 2},${y1} ${midX + topW / 2},${y1} ${cx + rw},${y2} ${cx},${y2}`
|
|
1815
|
-
).attr("fill", theme.reduction.fill).attr("stroke", theme.reduction.stroke).attr("stroke-width", theme.legend.itemStrokeWidth);
|
|
1816
|
-
} else {
|
|
1817
|
-
const symMap = {
|
|
1818
|
-
boreHole: {
|
|
1819
|
-
fill: theme.boreHole.fill,
|
|
1820
|
-
stroke: theme.boreHole.stroke,
|
|
1821
|
-
dasharray: theme.boreHole.strokeDasharray
|
|
1822
|
-
},
|
|
1823
|
-
holeFillGravel: {
|
|
1824
|
-
fill: legendTextures.gravel_pack.url(),
|
|
1825
|
-
stroke: theme.holeFill.stroke
|
|
1826
|
-
},
|
|
1827
|
-
holeFillSeal: {
|
|
1828
|
-
fill: legendTextures.seal.url(),
|
|
1829
|
-
stroke: theme.holeFill.stroke
|
|
1830
|
-
},
|
|
1831
|
-
wellCase: { fill: theme.wellCase.fill, stroke: theme.wellCase.stroke },
|
|
1832
|
-
wellScreen: {
|
|
1833
|
-
fill: legendTextures.well_screen.url(),
|
|
1834
|
-
stroke: theme.wellScreen.stroke
|
|
1835
|
-
},
|
|
1836
|
-
cementPad: {
|
|
1837
|
-
fill: legendTextures.pad.url(),
|
|
1838
|
-
stroke: theme.cementPad.stroke
|
|
1839
|
-
},
|
|
1840
|
-
conflict: {
|
|
1841
|
-
fill: legendTextures.conflict.url(),
|
|
1842
|
-
stroke: theme.conflict.stroke
|
|
1843
|
-
}
|
|
1844
|
-
};
|
|
1845
|
-
const sym = symMap[item.subKind];
|
|
1846
|
-
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);
|
|
1847
|
-
if (sym.dasharray) symRect.attr("stroke-dasharray", sym.dasharray);
|
|
1848
|
-
}
|
|
2630
|
+
drawLegendSymbol(symG, item, cx, rowSymY, style);
|
|
1849
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);
|
|
1850
2632
|
});
|
|
1851
2633
|
}
|
|
1852
2634
|
|
|
1853
2635
|
// src/renderers/lithology.renderer.ts
|
|
2636
|
+
import * as d38 from "d3";
|
|
1854
2637
|
function drawLithology(ctx, data) {
|
|
1855
|
-
if (!data.length) return;
|
|
1856
2638
|
const {
|
|
1857
2639
|
groups: { lithologyGroup },
|
|
1858
2640
|
svg,
|
|
@@ -1876,10 +2658,219 @@ function drawLithology(ctx, data) {
|
|
|
1876
2658
|
const merged = mergeEnter(newLayers, rects);
|
|
1877
2659
|
withTransition(merged, transition).attr("y", getYPos).attr("height", getHeight).attr("fill", getLithologyFill(data, svg, ctx.theme.lithologyTexture));
|
|
1878
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
|
+
}
|
|
1879
2871
|
|
|
1880
2872
|
// src/renderers/unit-labels.renderer.ts
|
|
1881
2873
|
function drawUnitLabels(ctx, data) {
|
|
1882
|
-
if (!ctx.renderConfig.unitLabels.active || !data.length) return;
|
|
1883
2874
|
const {
|
|
1884
2875
|
groups: { unitLabelsGroup },
|
|
1885
2876
|
depthFrom,
|
|
@@ -1890,6 +2881,7 @@ function drawUnitLabels(ctx, data) {
|
|
|
1890
2881
|
classes
|
|
1891
2882
|
} = ctx;
|
|
1892
2883
|
unitLabelsGroup.selectAll("*").remove();
|
|
2884
|
+
if (!renderConfig.unitLabels.active || !data.length) return;
|
|
1893
2885
|
const ru = renderConfig.unitLabels;
|
|
1894
2886
|
const rut = theme.unitLabels;
|
|
1895
2887
|
const sw = ru.stripWidth;
|
|
@@ -1970,7 +2962,7 @@ function buildSvgStyleBlock(theme) {
|
|
|
1970
2962
|
}
|
|
1971
2963
|
|
|
1972
2964
|
// src/Renderer.ts
|
|
1973
|
-
var
|
|
2965
|
+
var d310 = { ...d3module2, tip: d3tip2 };
|
|
1974
2966
|
var WellRenderer = class {
|
|
1975
2967
|
/**
|
|
1976
2968
|
* @param svgs - One entry per SVG panel; multi-entry for split-panel layouts.
|
|
@@ -2030,12 +3022,14 @@ var WellRenderer = class {
|
|
|
2030
3022
|
const { selector, height, width, margins } = inst;
|
|
2031
3023
|
const svgWidth = width + margins.left + margins.right;
|
|
2032
3024
|
const svgHeight = height + margins.top + margins.bottom;
|
|
2033
|
-
const svg =
|
|
3025
|
+
const svg = d310.select(selector);
|
|
2034
3026
|
svg.selectAll("*").remove();
|
|
2035
3027
|
svg.attr("height", svgHeight).attr("width", svgWidth);
|
|
2036
3028
|
const defs = svg.append("defs");
|
|
2037
3029
|
defs.append("style").text(buildSvgStyleBlock(this.theme));
|
|
2038
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);
|
|
2039
3033
|
const poco = svg.append("g").attr("class", this.classes.wellGroup);
|
|
2040
3034
|
const geologic = poco.append("g").attr("class", this.classes.geologicGroup).attr("transform", `translate(${margins.left}, ${margins.top})`);
|
|
2041
3035
|
geologic.append("g").attr("class", this.classes.yAxis);
|
|
@@ -2050,6 +3044,7 @@ var WellRenderer = class {
|
|
|
2050
3044
|
);
|
|
2051
3045
|
const fracturesGroup = poco.append("g").attr("class", this.classes.fractures.group).attr("transform", `translate(${margins.left}, ${margins.top})`).attr("clip-path", `url(#${clipId})`);
|
|
2052
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})`);
|
|
2053
3048
|
construction.append("g").attr("class", this.classes.cementPad.group);
|
|
2054
3049
|
construction.append("g").attr("class", this.classes.boreHole.group);
|
|
2055
3050
|
construction.append("g").attr("class", this.classes.surfaceCase.group);
|
|
@@ -2057,12 +3052,23 @@ var WellRenderer = class {
|
|
|
2057
3052
|
construction.append("g").attr("class", this.classes.wellCase.group);
|
|
2058
3053
|
construction.append("g").attr("class", this.classes.wellScreen.group);
|
|
2059
3054
|
construction.append("g").attr("class", this.classes.reduction.group);
|
|
3055
|
+
construction.append("g").attr("class", this.classes.pump.group);
|
|
2060
3056
|
construction.append("g").attr("class", this.classes.centralizer.group);
|
|
2061
3057
|
construction.append("g").attr("class", this.classes.conflict.group);
|
|
2062
3058
|
construction.append("g").attr("class", this.classes.constructionLabels.group);
|
|
2063
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})`);
|
|
2064
3061
|
Object.values(this.textures).forEach((texture) => svg.call(texture));
|
|
2065
|
-
return {
|
|
3062
|
+
return {
|
|
3063
|
+
svg,
|
|
3064
|
+
height,
|
|
3065
|
+
width,
|
|
3066
|
+
margins,
|
|
3067
|
+
clipId,
|
|
3068
|
+
clipRectId,
|
|
3069
|
+
depthRange: inst.depthRange,
|
|
3070
|
+
repeatedTo: inst.repeatedTo
|
|
3071
|
+
};
|
|
2066
3072
|
}
|
|
2067
3073
|
/** Renders a standalone legend into the element matched by `selector`. */
|
|
2068
3074
|
renderLegend(selector, profile) {
|
|
@@ -2073,6 +3079,30 @@ var WellRenderer = class {
|
|
|
2073
3079
|
textures: this.renderConfig.textures
|
|
2074
3080
|
});
|
|
2075
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
|
+
}
|
|
2076
3106
|
/**
|
|
2077
3107
|
* Multiplies the current zoom scale by `factor` (e.g. `1.25` to zoom in,
|
|
2078
3108
|
* `1 / 1.25` to zoom out) on every panel. No-op if both `renderConfig.zoom`
|
|
@@ -2089,7 +3119,7 @@ var WellRenderer = class {
|
|
|
2089
3119
|
* (defaults to `1`, i.e. the initial fit-to-container view).
|
|
2090
3120
|
*/
|
|
2091
3121
|
resetZoom() {
|
|
2092
|
-
const target =
|
|
3122
|
+
const target = d310.zoomIdentity.scale(this.renderConfig.zoomLevel ?? 1);
|
|
2093
3123
|
for (const state of this.instanceStates) {
|
|
2094
3124
|
if (!state.zoomNode) continue;
|
|
2095
3125
|
asSvgElement(state.svg).transition().call(state.zoomNode.transform, target);
|
|
@@ -2101,7 +3131,46 @@ var WellRenderer = class {
|
|
|
2101
3131
|
*/
|
|
2102
3132
|
getZoomScale() {
|
|
2103
3133
|
const node = this.instanceStates[0]?.svg.node();
|
|
2104
|
-
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
|
+
}
|
|
2105
3174
|
}
|
|
2106
3175
|
/**
|
|
2107
3176
|
* Initialises the SVG DOM structure and preloads FGDC textures.
|
|
@@ -2114,14 +3183,19 @@ var WellRenderer = class {
|
|
|
2114
3183
|
);
|
|
2115
3184
|
}
|
|
2116
3185
|
/**
|
|
2117
|
-
* 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}).
|
|
2118
3189
|
* @param profile - The well data to render.
|
|
2119
3190
|
* @param options.units - Override the instance-level measurement units for this render.
|
|
2120
3191
|
* @param options.locale - Override the instance-level locale for this render.
|
|
2121
3192
|
* @param options.highlights - Highlight overlays to display on top of the profile.
|
|
2122
3193
|
*/
|
|
2123
3194
|
draw(profile, options = {}) {
|
|
2124
|
-
if (isWellEmpty(profile))
|
|
3195
|
+
if (isWellEmpty(profile)) {
|
|
3196
|
+
this.clear();
|
|
3197
|
+
return;
|
|
3198
|
+
}
|
|
2125
3199
|
if (profile.version !== 2) {
|
|
2126
3200
|
console.warn(
|
|
2127
3201
|
`[WellRenderer] Received a .well file with version ${profile.version ?? "unknown"}. Only v2 is supported. Normalize with deserializeWell() from @welldot/core before rendering.`
|
|
@@ -2133,35 +3207,18 @@ var WellRenderer = class {
|
|
|
2133
3207
|
}
|
|
2134
3208
|
const highlights = options.highlights ?? {};
|
|
2135
3209
|
const maxValues = getProfileLastItemsDepths(profile);
|
|
2136
|
-
const maxYValues =
|
|
2137
|
-
|
|
2138
|
-
this.
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
);
|
|
2145
|
-
|
|
2146
|
-
}
|
|
2147
|
-
const totalHeight = this.instanceStates.reduce((s, st) => s + st.height, 0) || 1;
|
|
2148
|
-
const yScaleGlobal = d38.scaleLinear().domain([0, maxYValues]).range([0, totalHeight]);
|
|
2149
|
-
let currentDepth = 0;
|
|
2150
|
-
for (const state of this.instanceStates) {
|
|
2151
|
-
const maxSvgDepth = yScaleGlobal.invert(
|
|
2152
|
-
yScaleGlobal(currentDepth) + state.height
|
|
2153
|
-
);
|
|
2154
|
-
this.drawLogToInstance(
|
|
2155
|
-
state,
|
|
2156
|
-
profile,
|
|
2157
|
-
currentDepth,
|
|
2158
|
-
maxSvgDepth,
|
|
2159
|
-
highlights
|
|
2160
|
-
);
|
|
2161
|
-
currentDepth = maxSvgDepth;
|
|
2162
|
-
}
|
|
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
|
+
});
|
|
2163
3220
|
}
|
|
2164
|
-
drawLogToInstance(state, profile, depthFrom, depthTo, highlights = {}) {
|
|
3221
|
+
drawLogToInstance(state, profile, depthFrom, depthTo, totalDepth, highlights = {}) {
|
|
2165
3222
|
const svg = state.svg;
|
|
2166
3223
|
const pocoGroup = svg.select(`.${this.classes.wellGroup}`);
|
|
2167
3224
|
const lithologyGroup = svg.select(`.${this.classes.lithology.group}`);
|
|
@@ -2179,6 +3236,7 @@ var WellRenderer = class {
|
|
|
2179
3236
|
const wellScreenGroup = svg.select(`.${this.classes.wellScreen.group}`);
|
|
2180
3237
|
const reductionGroup = svg.select(`.${this.classes.reduction.group}`);
|
|
2181
3238
|
const centralizerGroup = svg.select(`.${this.classes.centralizer.group}`);
|
|
3239
|
+
const pumpGroup = svg.select(`.${this.classes.pump.group}`);
|
|
2182
3240
|
const conflictGroup = svg.select(`.${this.classes.conflict.group}`);
|
|
2183
3241
|
const constructionLabelsGroup = svg.select(
|
|
2184
3242
|
`.${this.classes.constructionLabels.group}`
|
|
@@ -2193,13 +3251,19 @@ var WellRenderer = class {
|
|
|
2193
3251
|
`.${this.classes.highlights.fracturesGroup}`
|
|
2194
3252
|
);
|
|
2195
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}`);
|
|
2196
3260
|
const svgWidth = state.width + state.margins.left + state.margins.right;
|
|
2197
3261
|
const svgHeight = state.height + state.margins.top + state.margins.bottom;
|
|
2198
3262
|
const { pocoWidthRatio, pocoCenterRatio } = this.renderConfig.layout;
|
|
2199
3263
|
const POCO_WIDTH = svgWidth * pocoWidthRatio;
|
|
2200
3264
|
const POCO_CENTER = svgWidth * pocoCenterRatio;
|
|
2201
3265
|
const { duration, ease } = this.renderConfig.animation;
|
|
2202
|
-
const transition =
|
|
3266
|
+
const transition = d310.transition().duration(duration).ease(ease);
|
|
2203
3267
|
const tooltips = populateTooltips(
|
|
2204
3268
|
svg,
|
|
2205
3269
|
this.classes,
|
|
@@ -2228,11 +3292,11 @@ var WellRenderer = class {
|
|
|
2228
3292
|
fractures: profile.fractures
|
|
2229
3293
|
};
|
|
2230
3294
|
const contentHeight = svgHeight - state.margins.top - state.margins.bottom;
|
|
2231
|
-
const yScaleLocal =
|
|
3295
|
+
const yScaleLocal = d310.scaleLinear().domain([depthFrom, depthTo]).range([0, contentHeight]);
|
|
2232
3296
|
const depthFactor = this.units.length === "ft" ? 3.28084 : 1;
|
|
2233
|
-
const yScaleAxis =
|
|
2234
|
-
const yAxis =
|
|
2235
|
-
(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), {
|
|
2236
3300
|
maximumFractionDigits: this.units.length === "ft" ? 1 : 2,
|
|
2237
3301
|
locale: this.locale
|
|
2238
3302
|
})}${getLengthUnit(this.units.length)}`
|
|
@@ -2274,10 +3338,15 @@ var WellRenderer = class {
|
|
|
2274
3338
|
wellScreenGroup,
|
|
2275
3339
|
reductionGroup,
|
|
2276
3340
|
centralizerGroup,
|
|
3341
|
+
pumpGroup,
|
|
2277
3342
|
conflictGroup,
|
|
2278
3343
|
highlightsGeologicGroup,
|
|
2279
3344
|
highlightsConstructionGroup,
|
|
2280
|
-
highlightsFracturesGroup
|
|
3345
|
+
highlightsFracturesGroup,
|
|
3346
|
+
overviewGroup,
|
|
3347
|
+
columnHeadersGroup,
|
|
3348
|
+
markersGroup,
|
|
3349
|
+
overlapGroup
|
|
2281
3350
|
};
|
|
2282
3351
|
const ctx = {
|
|
2283
3352
|
svg,
|
|
@@ -2291,6 +3360,8 @@ var WellRenderer = class {
|
|
|
2291
3360
|
geoXRight,
|
|
2292
3361
|
depthFrom,
|
|
2293
3362
|
depthTo,
|
|
3363
|
+
totalDepth,
|
|
3364
|
+
repeatedTo: state.repeatedTo,
|
|
2294
3365
|
yScale: yScaleLocal,
|
|
2295
3366
|
transition,
|
|
2296
3367
|
tooltips,
|
|
@@ -2304,6 +3375,7 @@ var WellRenderer = class {
|
|
|
2304
3375
|
groups
|
|
2305
3376
|
};
|
|
2306
3377
|
const inDepth = filterByDepth(depthFrom, depthTo);
|
|
3378
|
+
const currentPump = getCurrentPump2(profile);
|
|
2307
3379
|
const filteredConstruction = {
|
|
2308
3380
|
...constructionData,
|
|
2309
3381
|
bore_hole: constructionData.bore_hole.filter(inDepth),
|
|
@@ -2328,33 +3400,14 @@ var WellRenderer = class {
|
|
|
2328
3400
|
if (!d) return null;
|
|
2329
3401
|
return transform.k * spanH(d);
|
|
2330
3402
|
});
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
const sc = d;
|
|
2334
|
-
const g = d38.select(nodes[i]);
|
|
2335
|
-
const y = transform.applyY(spanY(sc));
|
|
2336
|
-
const h = transform.k * spanH(sc);
|
|
2337
|
-
g.select(".surface-case-fill").attr("y", y).attr("height", h);
|
|
2338
|
-
g.selectAll(".surface-case-side").attr("y1", y).attr("y2", y + h);
|
|
2339
|
-
});
|
|
2340
|
-
const maxXValsReduction = getProfileDiamValues5(constructionData);
|
|
2341
|
-
const xScaleReduction = d38.scaleLinear().domain([0, d38.max(maxXValsReduction) || 0]).range([0, POCO_WIDTH]);
|
|
2342
|
-
reductionGroup.selectAll(`polygon.${this.classes.reduction.item}`).attr("points", (d) => {
|
|
2343
|
-
const r = d;
|
|
2344
|
-
const yTop = transform.applyY(spanY(r));
|
|
2345
|
-
const yBot = yTop + transform.k * spanH(r);
|
|
2346
|
-
const xTopLeft = (POCO_CENTER - xScaleReduction(r.diam_from)) / 2;
|
|
2347
|
-
const xTopRight = (POCO_CENTER + xScaleReduction(r.diam_from)) / 2;
|
|
2348
|
-
const xBotLeft = (POCO_CENTER - xScaleReduction(r.diam_to)) / 2;
|
|
2349
|
-
const xBotRight = (POCO_CENTER + xScaleReduction(r.diam_to)) / 2;
|
|
2350
|
-
return `${xTopLeft},${yTop} ${xTopRight},${yTop} ${xBotRight},${yBot} ${xBotLeft},${yBot}`;
|
|
2351
|
-
});
|
|
3403
|
+
layoutConstruction(zoomedCtx);
|
|
3404
|
+
drawCementPad(zoomedCtx, constructionData.cement_pad);
|
|
2352
3405
|
fracturesGroup.selectAll(`g.${this.classes.fractures.item}`).attr("transform", (d) => {
|
|
2353
3406
|
if (!d) return null;
|
|
2354
3407
|
const f = d;
|
|
2355
3408
|
const cx = pocoCenterX;
|
|
2356
3409
|
const cy = transform.applyY(yScaleLocal(f.depth));
|
|
2357
|
-
return `translate(0,${cy}) rotate(${f.dip},${cx},0)`;
|
|
3410
|
+
return `translate(0,${cy}) rotate(${fractureDip(f.dip)},${cx},0)`;
|
|
2358
3411
|
});
|
|
2359
3412
|
drawCaves(zoomedCtx, geologicData.caves?.filter(inDepth) ?? []);
|
|
2360
3413
|
drawUnitLabels(zoomedCtx, profile.lithology?.filter(inDepth) ?? []);
|
|
@@ -2365,11 +3418,17 @@ var WellRenderer = class {
|
|
|
2365
3418
|
) ?? [],
|
|
2366
3419
|
caves: profile.caves?.filter(inDepth) ?? []
|
|
2367
3420
|
});
|
|
3421
|
+
drawPump(zoomedCtx, currentPump);
|
|
2368
3422
|
drawCentralizers(zoomedCtx, filteredConstruction);
|
|
2369
3423
|
drawConstructionLabels(zoomedCtx, {
|
|
2370
3424
|
well_case: constructionData.well_case.filter(inDepth),
|
|
2371
3425
|
well_screen: constructionData.well_screen.filter(inDepth)
|
|
2372
3426
|
});
|
|
3427
|
+
drawMarkers(zoomedCtx, {
|
|
3428
|
+
lithology: profile.lithology ?? [],
|
|
3429
|
+
fractures: profile.fractures ?? []
|
|
3430
|
+
});
|
|
3431
|
+
drawOverlap(zoomedCtx);
|
|
2373
3432
|
drawHighlights(zoomedCtx, highlights);
|
|
2374
3433
|
this.onZoom?.(transform.k);
|
|
2375
3434
|
};
|
|
@@ -2392,11 +3451,19 @@ var WellRenderer = class {
|
|
|
2392
3451
|
) ?? []
|
|
2393
3452
|
);
|
|
2394
3453
|
drawConstructive(ctx, filteredConstruction);
|
|
3454
|
+
drawPump(ctx, currentPump);
|
|
2395
3455
|
drawCentralizers(ctx, filteredConstruction);
|
|
2396
3456
|
drawConstructionLabels(ctx, {
|
|
2397
3457
|
well_case: filteredConstruction.well_case,
|
|
2398
3458
|
well_screen: filteredConstruction.well_screen
|
|
2399
3459
|
});
|
|
3460
|
+
drawMarkers(ctx, {
|
|
3461
|
+
lithology: profile.lithology ?? [],
|
|
3462
|
+
fractures: profile.fractures ?? []
|
|
3463
|
+
});
|
|
3464
|
+
drawOverview(ctx, profile.lithology ?? []);
|
|
3465
|
+
drawColumnHeaders(ctx);
|
|
3466
|
+
drawOverlap(ctx);
|
|
2400
3467
|
svg.select(`#${state.clipRectId}`).attr("y", 0).attr("height", svgHeight);
|
|
2401
3468
|
drawHighlights(ctx, highlights);
|
|
2402
3469
|
};
|
|
@@ -2412,7 +3479,7 @@ var WellRenderer = class {
|
|
|
2412
3479
|
}
|
|
2413
3480
|
const { zoom: zoomEnabled, pan: panEnabled } = this.renderConfig;
|
|
2414
3481
|
if (zoomEnabled || panEnabled) {
|
|
2415
|
-
const zoomNode =
|
|
3482
|
+
const zoomNode = d310.zoom();
|
|
2416
3483
|
if (zoomEnabled || panEnabled) zoomNode.on("zoom", zooming);
|
|
2417
3484
|
zoomNode.scaleExtent(
|
|
2418
3485
|
zoomEnabled ? [
|
|
@@ -2428,7 +3495,7 @@ var WellRenderer = class {
|
|
|
2428
3495
|
if (initialZoom !== 1) {
|
|
2429
3496
|
asSvgElement(svg).call(
|
|
2430
3497
|
zoomNode.transform,
|
|
2431
|
-
|
|
3498
|
+
d310.zoomIdentity.scale(initialZoom)
|
|
2432
3499
|
);
|
|
2433
3500
|
}
|
|
2434
3501
|
}
|
|
@@ -2442,10 +3509,13 @@ export {
|
|
|
2442
3509
|
WellRenderer,
|
|
2443
3510
|
applyRenderLocale,
|
|
2444
3511
|
drawWellLegend,
|
|
3512
|
+
drawWellLegendSymbol,
|
|
2445
3513
|
formatDiameter,
|
|
2446
3514
|
formatLength,
|
|
2447
3515
|
getDiameterUnit,
|
|
2448
3516
|
getLengthUnit,
|
|
3517
|
+
getProfileTopDepth,
|
|
3518
|
+
getWellLegendItems,
|
|
2449
3519
|
importFgdcTextures,
|
|
2450
3520
|
resolveRenderLabel
|
|
2451
3521
|
};
|