@welldot/render 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +91 -14
- package/dist/chunk-ODRL222Y.js +10 -0
- package/dist/chunk-ODRL222Y.js.map +1 -0
- package/dist/index.cjs +1404 -336
- 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 +1413 -342
- 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),
|
|
@@ -540,11 +685,12 @@ function createWellTextures(cfg) {
|
|
|
540
685
|
|
|
541
686
|
// src/Renderer.ts
|
|
542
687
|
import {
|
|
543
|
-
isWellEmpty
|
|
688
|
+
isWellEmpty,
|
|
689
|
+
parseFormatVersion
|
|
544
690
|
} from "@welldot/core";
|
|
545
691
|
import {
|
|
546
|
-
formatNumber as
|
|
547
|
-
|
|
692
|
+
formatNumber as formatNumber4,
|
|
693
|
+
getCurrentPump as getCurrentPump2,
|
|
548
694
|
getProfileLastItemsDepths
|
|
549
695
|
} from "@welldot/utils";
|
|
550
696
|
|
|
@@ -608,6 +754,10 @@ var DEFAULT_COMPONENTS_CLASS_NAMES = {
|
|
|
608
754
|
group: "centralizer",
|
|
609
755
|
item: "centralizer-marker"
|
|
610
756
|
},
|
|
757
|
+
pump: {
|
|
758
|
+
group: "pump",
|
|
759
|
+
item: "pump-item"
|
|
760
|
+
},
|
|
611
761
|
reduction: {
|
|
612
762
|
group: "reduction",
|
|
613
763
|
item: "reduction-poly"
|
|
@@ -639,6 +789,26 @@ var DEFAULT_COMPONENTS_CLASS_NAMES = {
|
|
|
639
789
|
caveFill: "cave-fill",
|
|
640
790
|
constructionRect: "construction-rect"
|
|
641
791
|
},
|
|
792
|
+
overview: {
|
|
793
|
+
group: "wp-overview",
|
|
794
|
+
item: "wp-overview-item",
|
|
795
|
+
window: "wp-overview-window"
|
|
796
|
+
},
|
|
797
|
+
columnHeaders: {
|
|
798
|
+
group: "wp-column-headers",
|
|
799
|
+
text: "wp-column-header",
|
|
800
|
+
rule: "wp-column-headers-rule"
|
|
801
|
+
},
|
|
802
|
+
markers: {
|
|
803
|
+
group: "wp-markers",
|
|
804
|
+
lithology: "wp-marker-lithology",
|
|
805
|
+
fracture: "wp-marker-fracture"
|
|
806
|
+
},
|
|
807
|
+
overlap: {
|
|
808
|
+
group: "wp-overlap",
|
|
809
|
+
band: "wp-overlap-band",
|
|
810
|
+
label: "wp-overlap-label"
|
|
811
|
+
},
|
|
642
812
|
highlights: {
|
|
643
813
|
geologicGroup: "wp-highlights-geologic",
|
|
644
814
|
constructionGroup: "wp-highlights-construction",
|
|
@@ -653,6 +823,156 @@ var DEFAULT_COMPONENTS_CLASS_NAMES = {
|
|
|
653
823
|
// src/utils/render.utils.ts
|
|
654
824
|
import textures2 from "textures";
|
|
655
825
|
|
|
826
|
+
// src/utils/construction.geometry.ts
|
|
827
|
+
var JOINT_EPS = 1e-3;
|
|
828
|
+
function diameterAt(items, depth) {
|
|
829
|
+
return items.find((i) => depth >= i.from && depth <= i.to)?.diameter;
|
|
830
|
+
}
|
|
831
|
+
function getIntervalEnds(item, string, depthFrom, depthTo) {
|
|
832
|
+
return {
|
|
833
|
+
cutTop: item.from < depthFrom - JOINT_EPS,
|
|
834
|
+
cutBottom: item.to > depthTo + JOINT_EPS,
|
|
835
|
+
joinedTop: string.some(
|
|
836
|
+
(o) => o !== item && Math.abs(o.to - item.from) < JOINT_EPS
|
|
837
|
+
),
|
|
838
|
+
joinedBottom: string.some(
|
|
839
|
+
(o) => o !== item && Math.abs(o.from - item.to) < JOINT_EPS
|
|
840
|
+
)
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
function pipeWallsPath(xLeft, xRight, yTop, yBottom) {
|
|
844
|
+
return `M${xLeft},${yTop}V${yBottom}M${xRight},${yTop}V${yBottom}`;
|
|
845
|
+
}
|
|
846
|
+
function shoePath(xLeft, xRight, y, size) {
|
|
847
|
+
return `M${xLeft},${y - size}L${xLeft},${y}L${xLeft - size},${y}ZM${xRight},${y - size}L${xRight},${y}L${xRight + size},${y}Z`;
|
|
848
|
+
}
|
|
849
|
+
function screenEndPath(xLeft, xRight, y) {
|
|
850
|
+
return `M${xLeft},${y}H${xRight}`;
|
|
851
|
+
}
|
|
852
|
+
var clampDepth = (s, depth) => Math.min(Math.max(depth, s.depthFrom), s.depthTo);
|
|
853
|
+
var inPanel = (s, depth) => depth >= s.depthFrom - JOINT_EPS && depth <= s.depthTo + JOINT_EPS;
|
|
854
|
+
var shoulders = (s, a, b, y) => `M${s.left(a)},${y}H${s.left(b)}M${s.right(a)},${y}H${s.right(b)}`;
|
|
855
|
+
function boreHoleOutlinePath(item, holes, s) {
|
|
856
|
+
const yTop = s.y(clampDepth(s, item.from));
|
|
857
|
+
const yBottom = s.y(clampDepth(s, item.to));
|
|
858
|
+
let d = pipeWallsPath(
|
|
859
|
+
s.left(item.diameter),
|
|
860
|
+
s.right(item.diameter),
|
|
861
|
+
yTop,
|
|
862
|
+
yBottom
|
|
863
|
+
);
|
|
864
|
+
if (item.from > JOINT_EPS && inPanel(s, item.from)) {
|
|
865
|
+
const above = holes.find(
|
|
866
|
+
(o) => o !== item && o.from < item.from && o.to >= item.from - JOINT_EPS
|
|
867
|
+
);
|
|
868
|
+
if (above && above.diameter < item.diameter)
|
|
869
|
+
d += shoulders(s, above.diameter, item.diameter, yTop);
|
|
870
|
+
}
|
|
871
|
+
if (inPanel(s, item.to)) {
|
|
872
|
+
const below = holes.find(
|
|
873
|
+
(o) => o !== item && o.from <= item.to + JOINT_EPS && o.to > item.to
|
|
874
|
+
);
|
|
875
|
+
if (!below) {
|
|
876
|
+
d += `M${s.left(item.diameter)},${yBottom}H${s.right(item.diameter)}`;
|
|
877
|
+
} else if (below.diameter < item.diameter) {
|
|
878
|
+
d += shoulders(s, item.diameter, below.diameter, yBottom);
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
return d;
|
|
882
|
+
}
|
|
883
|
+
function holeFillOutlinePath(item, pipes, s) {
|
|
884
|
+
const yTop = s.y(clampDepth(s, item.from));
|
|
885
|
+
const yBottom = s.y(clampDepth(s, item.to));
|
|
886
|
+
const xL = s.left(item.diameter);
|
|
887
|
+
const xR = s.right(item.diameter);
|
|
888
|
+
let d = pipeWallsPath(xL, xR, yTop, yBottom);
|
|
889
|
+
const interfaces = [item.from, item.to].filter(
|
|
890
|
+
(depth) => depth > JOINT_EPS && inPanel(s, depth)
|
|
891
|
+
);
|
|
892
|
+
for (const depth of interfaces) {
|
|
893
|
+
const y = s.y(depth);
|
|
894
|
+
const pipe = diameterAt(pipes, depth);
|
|
895
|
+
if (pipe !== void 0 && pipe < item.diameter) {
|
|
896
|
+
d += `M${xL},${y}H${s.left(pipe)}M${s.right(pipe)},${y}H${xR}`;
|
|
897
|
+
} else {
|
|
898
|
+
d += `M${xL},${y}H${xR}`;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
return d;
|
|
902
|
+
}
|
|
903
|
+
function pipeSlices(pipes, from, to) {
|
|
904
|
+
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);
|
|
905
|
+
const slices = [];
|
|
906
|
+
for (let i = 1; i < cuts.length; i++) {
|
|
907
|
+
const a = cuts[i - 1];
|
|
908
|
+
const b = cuts[i];
|
|
909
|
+
const mid = (a + b) / 2;
|
|
910
|
+
const widest = Math.max(
|
|
911
|
+
0,
|
|
912
|
+
...pipes.filter((p) => p.from <= mid && p.to >= mid).map((p) => p.diameter)
|
|
913
|
+
);
|
|
914
|
+
if (widest === 0) continue;
|
|
915
|
+
const last = slices[slices.length - 1];
|
|
916
|
+
if (last && last.to === a && last.diameter === widest) last.to = b;
|
|
917
|
+
else slices.push({ from: a, to: b, diameter: widest });
|
|
918
|
+
}
|
|
919
|
+
return slices;
|
|
920
|
+
}
|
|
921
|
+
function annulusFillPath(item, pipes, s) {
|
|
922
|
+
const from = clampDepth(s, item.from);
|
|
923
|
+
const to = clampDepth(s, item.to);
|
|
924
|
+
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`;
|
|
925
|
+
const inner = pipes.filter((p) => p.diameter < item.diameter);
|
|
926
|
+
return box(item.diameter, from, to) + pipeSlices(inner, from, to).map((p) => box(p.diameter, p.from, p.to)).join("");
|
|
927
|
+
}
|
|
928
|
+
function getPadDiameters(data, surfaceCasePaddingRatio) {
|
|
929
|
+
const surfaceCase = diameterAt(data.surface_case, 0);
|
|
930
|
+
const paddedSurfaceCase = surfaceCase === void 0 ? void 0 : surfaceCase * (1 + surfaceCasePaddingRatio);
|
|
931
|
+
const casing = diameterAt([...data.well_case, ...data.well_screen], 0);
|
|
932
|
+
const hole = diameterAt(data.bore_hole, 0);
|
|
933
|
+
const opening = casing ?? paddedSurfaceCase ?? hole ?? 0;
|
|
934
|
+
const outer = Math.max(
|
|
935
|
+
opening,
|
|
936
|
+
paddedSurfaceCase ?? 0,
|
|
937
|
+
hole ?? 0,
|
|
938
|
+
diameterAt(data.hole_fill, 0) ?? 0
|
|
939
|
+
);
|
|
940
|
+
return { opening, outer };
|
|
941
|
+
}
|
|
942
|
+
function getCementPadGeometry(pocoWidth, pocoCenter, surfaceY, config, openingWidth = 0, outerWidth = openingWidth) {
|
|
943
|
+
const h = config.height;
|
|
944
|
+
const opening = Math.max(0, openingWidth);
|
|
945
|
+
const width = Math.max(
|
|
946
|
+
pocoWidth * config.widthRatio,
|
|
947
|
+
opening + 3 * h,
|
|
948
|
+
outerWidth + 2 * h
|
|
949
|
+
);
|
|
950
|
+
const xLeft = (pocoCenter - width) / 2;
|
|
951
|
+
const xRight = xLeft + width;
|
|
952
|
+
const oLeft = (pocoCenter - opening) / 2;
|
|
953
|
+
const oRight = oLeft + opening;
|
|
954
|
+
const yTop = surfaceY - h;
|
|
955
|
+
const a = h * 0.3;
|
|
956
|
+
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}`;
|
|
957
|
+
const bbox = { x: xLeft, y: yTop, width, height: h };
|
|
958
|
+
if (opening === 0) {
|
|
959
|
+
return {
|
|
960
|
+
bbox,
|
|
961
|
+
slabs: [
|
|
962
|
+
`M${xLeft},${yTop}H${xRight}${breakLine(xRight, yTop, surfaceY, 1)}H${xLeft}${breakLine(xLeft, surfaceY, yTop, -1)}Z`,
|
|
963
|
+
""
|
|
964
|
+
]
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
return {
|
|
968
|
+
bbox,
|
|
969
|
+
slabs: [
|
|
970
|
+
`M${oLeft},${yTop}H${xLeft}${breakLine(xLeft, yTop, surfaceY, -1)}H${oLeft}Z`,
|
|
971
|
+
`M${oRight},${yTop}H${xRight}${breakLine(xRight, yTop, surfaceY, 1)}H${oRight}Z`
|
|
972
|
+
]
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
|
|
656
976
|
// src/utils/d3.utils.ts
|
|
657
977
|
function mergeEnter(enter, update) {
|
|
658
978
|
return enter.merge(update);
|
|
@@ -723,6 +1043,14 @@ var makeSeededPrng = (seed, scramble = 6271) => {
|
|
|
723
1043
|
// src/utils/tooltips.utils.ts
|
|
724
1044
|
import d3tip from "d3-tip";
|
|
725
1045
|
import sanitizeHtml from "sanitize-html";
|
|
1046
|
+
import {
|
|
1047
|
+
CEMENT_PAD_TYPES,
|
|
1048
|
+
CENTRALIZER_TYPES,
|
|
1049
|
+
CONSTRUCTION_MATERIALS,
|
|
1050
|
+
SCREEN_SLOT_TYPES,
|
|
1051
|
+
getVocabLabel,
|
|
1052
|
+
powerFromCanonical
|
|
1053
|
+
} from "@welldot/core";
|
|
726
1054
|
import { formatNumber as formatNumber2 } from "@welldot/utils";
|
|
727
1055
|
var esc = (v) => sanitizeHtml(String(v ?? ""), { allowedTags: [], allowedAttributes: {} });
|
|
728
1056
|
var _tooltipCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -733,6 +1061,7 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
733
1061
|
if (cached && cached.signature === signature) {
|
|
734
1062
|
return cached.tooltips;
|
|
735
1063
|
}
|
|
1064
|
+
const material = (value) => getVocabLabel(CONSTRUCTION_MATERIALS, value, locale);
|
|
736
1065
|
const tipsText = {
|
|
737
1066
|
geology: (_, d) => `
|
|
738
1067
|
<span class="${customClasses.tooltip.title}">${labels.geology.title}</span>
|
|
@@ -765,14 +1094,15 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
765
1094
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
766
1095
|
<strong>${labels.common.diameter}</strong> ${esc(formatDiameter(d.diameter, units.diameter, locale))} ${esc(getDiameterUnit(units.diameter, locale))}
|
|
767
1096
|
</span>
|
|
768
|
-
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(d.type)}</span>
|
|
1097
|
+
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(material(d.type))}</span>
|
|
769
1098
|
`,
|
|
770
1099
|
wellScreen: (_, d) => `
|
|
771
1100
|
<span class="${customClasses.tooltip.title}">${labels.wellScreen.title}</span>
|
|
772
1101
|
<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
1102
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
774
1103
|
<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.
|
|
1104
|
+
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.wellScreen.material}</strong> ${esc(material(d.type))}</span>
|
|
1105
|
+
${d.slot_type ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.wellScreen.slotType}</strong> ${esc(getVocabLabel(SCREEN_SLOT_TYPES, d.slot_type, locale))}</span>` : ""}
|
|
776
1106
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
777
1107
|
<strong>${labels.wellScreen.slot}</strong> ${esc(formatNumber2(d.screen_slot, { maximumFractionDigits: 2, locale }))} mm
|
|
778
1108
|
</span>
|
|
@@ -783,17 +1113,29 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
783
1113
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
784
1114
|
<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
1115
|
</span>
|
|
786
|
-
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(d.type)}</span>
|
|
1116
|
+
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(material(d.type))}</span>
|
|
787
1117
|
`,
|
|
788
1118
|
centralizer: (_, d) => `
|
|
789
1119
|
<span class="${customClasses.tooltip.title}">${labels.centralizer.title}</span>
|
|
790
1120
|
<span class="${customClasses.tooltip.primaryInfo}"><strong>${labels.centralizer.depth}</strong> ${esc(formatLength(d.depth, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>
|
|
791
1121
|
${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
1122
|
${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>
|
|
1123
|
+
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(getVocabLabel(CENTRALIZER_TYPES, d.type, locale))}</span>
|
|
794
1124
|
${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
1125
|
${d.description ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.description}</strong> ${esc(d.description)}</span>` : ""}
|
|
796
1126
|
`,
|
|
1127
|
+
pump: (_, d) => {
|
|
1128
|
+
const typeLabel = labels.pump[`type_${d.type}`] ?? d.type;
|
|
1129
|
+
const model = [d.manufacturer, d.model].filter(Boolean).join(" ");
|
|
1130
|
+
return `
|
|
1131
|
+
<span class="${customClasses.tooltip.title}">${labels.pump.title}</span>
|
|
1132
|
+
<span class="${customClasses.tooltip.primaryInfo}">${esc(typeLabel)}</span>
|
|
1133
|
+
${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>` : ""}
|
|
1134
|
+
${model ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.pump.model}</strong> ${esc(model)}</span>` : ""}
|
|
1135
|
+
${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>` : ""}
|
|
1136
|
+
${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>` : ""}
|
|
1137
|
+
`;
|
|
1138
|
+
},
|
|
797
1139
|
conflict: (_, d) => `
|
|
798
1140
|
<span class="${customClasses.tooltip.title}">${labels.conflict.title}</span>
|
|
799
1141
|
<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 +1146,14 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
804
1146
|
<span class="${customClasses.tooltip.title}">${title}</span>
|
|
805
1147
|
<span class="${customClasses.tooltip.primaryInfo}"><strong>${labels.fracture.depth}</strong> ${esc(formatLength(d.depth, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>
|
|
806
1148
|
${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
|
-
|
|
1149
|
+
${typeof d.dip === "number" ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.fracture.dip}</strong> ${esc(d.dip)}\xB0</span>` : ""}
|
|
1150
|
+
${typeof d.azimuth === "number" ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.fracture.azimuth}</strong> ${esc(d.azimuth)}\xB0</span>` : ""}
|
|
809
1151
|
${d.description ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.description}</strong> ${esc(d.description)}</span>` : ""}
|
|
810
1152
|
`;
|
|
811
1153
|
},
|
|
812
1154
|
cementPad: (_, d) => `
|
|
813
1155
|
<span class="${customClasses.tooltip.title}">${labels.cementPad.title}</span>
|
|
814
|
-
<span class="${customClasses.tooltip.primaryInfo}">${esc(d.type)}</span>
|
|
1156
|
+
<span class="${customClasses.tooltip.primaryInfo}">${esc(getVocabLabel(CEMENT_PAD_TYPES, d.type, locale))}</span>
|
|
815
1157
|
<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.cementPad.thickness}</strong>
|
|
816
1158
|
${esc(formatLength(d.thickness, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>
|
|
817
1159
|
<span class="${customClasses.tooltip.secondaryInfo}">
|
|
@@ -849,6 +1191,17 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
|
|
|
849
1191
|
};
|
|
850
1192
|
|
|
851
1193
|
// src/utils/render.utils.ts
|
|
1194
|
+
var fractureDip = (dip) => typeof dip === "number" && Number.isFinite(dip) ? dip : 0;
|
|
1195
|
+
function getCementPadRect(pocoWidth, pocoCenter, surfaceY, config, openingWidth = 0, outerWidth = openingWidth) {
|
|
1196
|
+
return getCementPadGeometry(
|
|
1197
|
+
pocoWidth,
|
|
1198
|
+
pocoCenter,
|
|
1199
|
+
surfaceY,
|
|
1200
|
+
config,
|
|
1201
|
+
openingWidth,
|
|
1202
|
+
outerWidth
|
|
1203
|
+
).bbox;
|
|
1204
|
+
}
|
|
852
1205
|
var _fgdcTextures = {};
|
|
853
1206
|
var _fgdcTexturesPromise = null;
|
|
854
1207
|
var preloadFgdcTextures = () => {
|
|
@@ -957,14 +1310,23 @@ function drawAnnotationLabels(ctx, data) {
|
|
|
957
1310
|
}
|
|
958
1311
|
const items = [];
|
|
959
1312
|
if (active.has("lithology")) {
|
|
1313
|
+
const continuation = s.continuation;
|
|
960
1314
|
data.lithology.filter((d) => d.from < ctx.depthTo).forEach((d) => {
|
|
1315
|
+
const range = `${formatLength(d.from, ctx.units.length, ctx.locale)}\u2013${formatLength(d.to, ctx.units.length, ctx.locale)}${getLengthUnit(ctx.units.length)}`;
|
|
1316
|
+
const continues = continuation?.active && d.from < ctx.depthFrom;
|
|
961
1317
|
items.push({
|
|
962
1318
|
sortDepth: d.from,
|
|
963
1319
|
baseY: ctx.yScale(Math.max(d.from, ctx.depthFrom)),
|
|
964
1320
|
originX: ctx.geoXRight,
|
|
965
1321
|
originY: ctx.yScale(Math.max(d.from, ctx.depthFrom)),
|
|
966
|
-
header:
|
|
967
|
-
description: d.description || ""
|
|
1322
|
+
header: continues ? `\u2191 ${continuation.prefix} \xB7 ${range}` : range,
|
|
1323
|
+
description: continues ? "" : d.description || "",
|
|
1324
|
+
...show.has("units") ? {
|
|
1325
|
+
unit: d.geologic_unit || void 0,
|
|
1326
|
+
aquifer: continues ? void 0 : d.aquifer_unit || void 0
|
|
1327
|
+
} : {},
|
|
1328
|
+
...show.has("swatch") && !continues ? { swatch: d } : {},
|
|
1329
|
+
...show.has("rules") ? { rule: continues ? "dashed" : "solid" } : {}
|
|
968
1330
|
});
|
|
969
1331
|
});
|
|
970
1332
|
}
|
|
@@ -977,7 +1339,8 @@ function drawAnnotationLabels(ctx, data) {
|
|
|
977
1339
|
originX: ctx.pocoCenterX,
|
|
978
1340
|
originY: ctx.yScale(d.depth),
|
|
979
1341
|
header: `${formatLength(d.depth, ctx.units.length, ctx.locale)}${getLengthUnit(ctx.units.length)} \xB7 ${typeLabel}`,
|
|
980
|
-
description: d.description || ""
|
|
1342
|
+
description: d.description || "",
|
|
1343
|
+
...show.has("rules") ? { rule: "dashed" } : {}
|
|
981
1344
|
});
|
|
982
1345
|
});
|
|
983
1346
|
}
|
|
@@ -997,14 +1360,15 @@ function drawAnnotationLabels(ctx, data) {
|
|
|
997
1360
|
}
|
|
998
1361
|
items.sort((a, b) => a.sortDepth - b.sortDepth);
|
|
999
1362
|
const labelPositions = [];
|
|
1000
|
-
let currY = 0;
|
|
1363
|
+
let currY = ctx.repeatedTo != null ? s.stackingLineHeight + 2 : 0;
|
|
1001
1364
|
const charsPerLine = Math.max(
|
|
1002
1365
|
1,
|
|
1003
1366
|
Math.floor(s.descriptionMaxWidth / (st.fontSize * 0.6))
|
|
1004
1367
|
);
|
|
1005
1368
|
items.forEach((item) => {
|
|
1006
|
-
const descLines = Math.ceil((item.description.length || 1) / charsPerLine);
|
|
1007
|
-
const
|
|
1369
|
+
const descLines = show.has("units") ? item.description ? wrapText(item.description, charsPerLine).length : 0 : Math.ceil((item.description.length || 1) / charsPerLine);
|
|
1370
|
+
const extraLines = (item.unit ? 1 : 0) + (item.aquifer ? 1 : 0);
|
|
1371
|
+
const estH = (1 + descLines + extraLines) * s.stackingLineHeight + 4;
|
|
1008
1372
|
const yLabel = Math.max(item.baseY, currY + s.stackingGap);
|
|
1009
1373
|
currY = yLabel + estH;
|
|
1010
1374
|
labelPositions.push({ item, yLabel, estH });
|
|
@@ -1021,16 +1385,41 @@ function drawAnnotationLabels(ctx, data) {
|
|
|
1021
1385
|
if (show.has("description")) {
|
|
1022
1386
|
const lineH = s.stackingLineHeight;
|
|
1023
1387
|
const bgFill = st.annotationBg ?? "white";
|
|
1388
|
+
const swatchFill = labelPositions.some((p) => p.item.swatch) ? getLithologyFill(data.lithology, ctx.svg, ctx.theme.lithologyTexture) : null;
|
|
1024
1389
|
labelPositions.forEach(({ item, yLabel, estH }) => {
|
|
1025
1390
|
const labelG = ctx.groups.lithologyLabelsGroup.append("g").attr("class", ctx.classes.labels.lithology.label).attr("transform", `translate(${labelX},${yLabel})`);
|
|
1026
1391
|
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
|
-
|
|
1392
|
+
if (item.rule) {
|
|
1393
|
+
labelG.append("line").attr("x1", 0).attr("x2", s.descriptionMaxWidth).attr("y1", 0).attr("y2", 0).attr("stroke", ctx.theme.labels.color).attr(
|
|
1394
|
+
"stroke-width",
|
|
1395
|
+
item.rule === "solid" ? 0.8 : ctx.theme.labels.dividerStrokeWidth
|
|
1396
|
+
).attr(
|
|
1397
|
+
"stroke-dasharray",
|
|
1398
|
+
item.rule === "solid" ? null : ctx.theme.labels.dividerStrokeDasharray
|
|
1399
|
+
);
|
|
1400
|
+
}
|
|
1401
|
+
let headerX = 0;
|
|
1402
|
+
if (item.swatch && swatchFill) {
|
|
1403
|
+
const size = lineH * 0.75;
|
|
1404
|
+
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);
|
|
1405
|
+
headerX = size + 3;
|
|
1406
|
+
}
|
|
1407
|
+
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);
|
|
1408
|
+
let lineY = lineH * 0.85 + lineH;
|
|
1409
|
+
if (item.unit) {
|
|
1410
|
+
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);
|
|
1411
|
+
lineY += lineH;
|
|
1412
|
+
}
|
|
1028
1413
|
if (item.description) {
|
|
1029
1414
|
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",
|
|
1415
|
+
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
1416
|
lines.forEach((line, i) => {
|
|
1032
1417
|
bodyEl.append("tspan").attr("x", 0).attr("dy", i === 0 ? 0 : lineH).text(line);
|
|
1033
1418
|
});
|
|
1419
|
+
lineY += lines.length * lineH;
|
|
1420
|
+
}
|
|
1421
|
+
if (item.aquifer) {
|
|
1422
|
+
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
1423
|
}
|
|
1035
1424
|
});
|
|
1036
1425
|
}
|
|
@@ -1051,7 +1440,6 @@ var makePointKey = (type) => (d, i) => {
|
|
|
1051
1440
|
|
|
1052
1441
|
// src/renderers/caves.renderer.ts
|
|
1053
1442
|
function drawCaves(ctx, data) {
|
|
1054
|
-
if (!data.length) return;
|
|
1055
1443
|
const {
|
|
1056
1444
|
groups: { cavesGroup },
|
|
1057
1445
|
geoXLeft,
|
|
@@ -1061,7 +1449,7 @@ function drawCaves(ctx, data) {
|
|
|
1061
1449
|
yScale,
|
|
1062
1450
|
renderConfig,
|
|
1063
1451
|
theme,
|
|
1064
|
-
textures:
|
|
1452
|
+
textures: textures4,
|
|
1065
1453
|
classes,
|
|
1066
1454
|
tooltips
|
|
1067
1455
|
} = ctx;
|
|
@@ -1098,7 +1486,7 @@ function drawCaves(ctx, data) {
|
|
|
1098
1486
|
const botPath = botCut ? `M ${geoXLeft.toFixed(1)},${yBot.toFixed(1)} L ${geoXRight.toFixed(1)},${yBot.toFixed(1)}` : ptsToSmoothPath(botPts);
|
|
1099
1487
|
const botReversed = botCut ? `L ${geoXLeft.toFixed(1)},${yBot.toFixed(1)}` : ptsToSmoothPath([...botPts].reverse(), { omitMoveTo: true });
|
|
1100
1488
|
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 ?
|
|
1489
|
+
const caveTexture = cave.water_intake ? textures4.cave_wet : textures4.cave_dry;
|
|
1102
1490
|
const caveStroke = cave.water_intake ? theme.cave.wetStroke : theme.cave.dryStroke;
|
|
1103
1491
|
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
1492
|
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 +1498,6 @@ function drawCaves(ctx, data) {
|
|
|
1110
1498
|
// src/renderers/centralizers.renderer.ts
|
|
1111
1499
|
import * as d32 from "d3";
|
|
1112
1500
|
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
1501
|
function drawCentralizers(ctx, data) {
|
|
1117
1502
|
const group = ctx.groups.centralizerGroup;
|
|
1118
1503
|
const cls = ctx.classes.centralizer;
|
|
@@ -1149,8 +1534,108 @@ function drawCentralizers(ctx, data) {
|
|
|
1149
1534
|
});
|
|
1150
1535
|
}
|
|
1151
1536
|
|
|
1537
|
+
// src/utils/layout.utils.ts
|
|
1538
|
+
function getProfileTopDepth(profile) {
|
|
1539
|
+
return Math.min(
|
|
1540
|
+
0,
|
|
1541
|
+
...[
|
|
1542
|
+
...profile.surface_case ?? [],
|
|
1543
|
+
...profile.well_case ?? [],
|
|
1544
|
+
...profile.well_screen ?? []
|
|
1545
|
+
].map((i) => i.from).filter(Number.isFinite)
|
|
1546
|
+
);
|
|
1547
|
+
}
|
|
1548
|
+
function resolvePanelWindows(panels, totalDepth, topDepth = 0) {
|
|
1549
|
+
if (panels.length > 0 && panels.every((p) => p.depthRange)) {
|
|
1550
|
+
return panels.map((p) => [p.depthRange[0], p.depthRange[1]]);
|
|
1551
|
+
}
|
|
1552
|
+
if (panels.length === 1) return [[topDepth, totalDepth]];
|
|
1553
|
+
const totalHeight = panels.reduce((s, p) => s + p.height, 0) || 1;
|
|
1554
|
+
const metersPerPx = (totalDepth - topDepth) / totalHeight;
|
|
1555
|
+
let current = topDepth;
|
|
1556
|
+
return panels.map((p) => {
|
|
1557
|
+
const from = current;
|
|
1558
|
+
current = from + p.height * metersPerPx;
|
|
1559
|
+
return [from, current];
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1562
|
+
function getColumnHeaderPositions(geometry) {
|
|
1563
|
+
const { marginLeft, geoXLeft, geoXRight, pocoCenterX, descriptionX } = geometry;
|
|
1564
|
+
return {
|
|
1565
|
+
depth: marginLeft - 2,
|
|
1566
|
+
lithology: marginLeft + (geoXLeft + geoXRight) / 2,
|
|
1567
|
+
construction: marginLeft + pocoCenterX,
|
|
1568
|
+
...descriptionX != null ? { description: marginLeft + descriptionX } : {}
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
function getLithologyMarkers(lithology, depthFrom, depthTo) {
|
|
1572
|
+
const markers = [];
|
|
1573
|
+
lithology.forEach((layer, i) => {
|
|
1574
|
+
const from = Math.max(layer.from, depthFrom);
|
|
1575
|
+
const to = Math.min(layer.to, depthTo);
|
|
1576
|
+
if (to > from) markers.push({ index: i + 1, from, to });
|
|
1577
|
+
});
|
|
1578
|
+
return markers;
|
|
1579
|
+
}
|
|
1580
|
+
function getFractureMarkers(fractures, depthFrom, depthTo) {
|
|
1581
|
+
const markers = [];
|
|
1582
|
+
fractures.forEach((f, i) => {
|
|
1583
|
+
if (f.depth >= depthFrom && f.depth < depthTo) {
|
|
1584
|
+
markers.push({ label: `F${i + 1}`, depth: f.depth });
|
|
1585
|
+
}
|
|
1586
|
+
});
|
|
1587
|
+
return markers;
|
|
1588
|
+
}
|
|
1589
|
+
function getOverviewGeometry(totalDepth, height, depthFrom, depthTo) {
|
|
1590
|
+
const ratio = totalDepth > 0 ? height / totalDepth : 0;
|
|
1591
|
+
const y = (depth) => Math.min(height, Math.max(0, depth * ratio));
|
|
1592
|
+
return {
|
|
1593
|
+
y,
|
|
1594
|
+
window: { y: y(depthFrom), height: Math.max(1, y(depthTo) - y(depthFrom)) }
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
function formatOverlapLabel(template, range) {
|
|
1598
|
+
return template.replace("{range}", range);
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
// src/renderers/column-headers.renderer.ts
|
|
1602
|
+
function hasDescriptionColumn(ctx) {
|
|
1603
|
+
const { active, lithology } = ctx.renderConfig.labels;
|
|
1604
|
+
if (active === false) return false;
|
|
1605
|
+
if (Array.isArray(active) && !active.includes("lithology")) return false;
|
|
1606
|
+
if (lithology === false) return false;
|
|
1607
|
+
return !Array.isArray(lithology) || lithology.includes("description");
|
|
1608
|
+
}
|
|
1609
|
+
function drawColumnHeaders(ctx) {
|
|
1610
|
+
const group = ctx.groups.columnHeadersGroup;
|
|
1611
|
+
group.selectAll("*").remove();
|
|
1612
|
+
const cfg = ctx.renderConfig.columnHeaders;
|
|
1613
|
+
if (!cfg.active) return;
|
|
1614
|
+
const theme = ctx.theme.columnHeaders;
|
|
1615
|
+
const { margins } = ctx.state;
|
|
1616
|
+
const positions = getColumnHeaderPositions({
|
|
1617
|
+
marginLeft: margins.left,
|
|
1618
|
+
geoXLeft: ctx.geoXLeft,
|
|
1619
|
+
geoXRight: ctx.geoXRight,
|
|
1620
|
+
pocoCenterX: ctx.pocoCenterX,
|
|
1621
|
+
descriptionX: hasDescriptionColumn(ctx) ? ctx.geoXRight + ctx.renderConfig.labels.descriptionXOffset : void 0
|
|
1622
|
+
});
|
|
1623
|
+
const ruleY = margins.top - 2 - ctx.renderConfig.construction.cementPad.height;
|
|
1624
|
+
const textY = ruleY - 4;
|
|
1625
|
+
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);
|
|
1626
|
+
addText(positions.depth, cfg.labels.depth, "end");
|
|
1627
|
+
addText(positions.lithology, cfg.labels.lithology, "middle");
|
|
1628
|
+
addText(positions.construction, cfg.labels.construction, "middle");
|
|
1629
|
+
if (positions.description != null) {
|
|
1630
|
+
addText(positions.description, cfg.labels.description, "start");
|
|
1631
|
+
}
|
|
1632
|
+
const overview = ctx.renderConfig.overview;
|
|
1633
|
+
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);
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1152
1636
|
// src/renderers/construction-labels.renderer.ts
|
|
1153
1637
|
import * as d33 from "d3";
|
|
1638
|
+
import { CONSTRUCTION_MATERIALS as CONSTRUCTION_MATERIALS2, getVocabLabel as getVocabLabel2 } from "@welldot/core";
|
|
1154
1639
|
import { getProfileDiamValues as getProfileDiamValues2 } from "@welldot/utils";
|
|
1155
1640
|
function drawConstructionLabels(ctx, data) {
|
|
1156
1641
|
if (!ctx.renderConfig.constructionLabels.active) return;
|
|
@@ -1159,16 +1644,18 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1159
1644
|
const clct = ctx.theme.constructionLabels;
|
|
1160
1645
|
const fmtD = (mm) => formatDiameter(mm, ctx.units.diameter, ctx.locale);
|
|
1161
1646
|
const dUnit = getDiameterUnit(ctx.units.diameter, ctx.locale);
|
|
1647
|
+
const material = (value) => getVocabLabel2(CONSTRUCTION_MATERIALS2, value, ctx.locale);
|
|
1162
1648
|
const maxXValues = getProfileDiamValues2(ctx.constructionData);
|
|
1163
1649
|
const xScale = d33.scaleLinear().domain([0, d33.max(maxXValues) || 0]).range([0, ctx.POCO_WIDTH]);
|
|
1164
1650
|
const occupied = [];
|
|
1165
|
-
const
|
|
1651
|
+
const onRight = clc.side === "right";
|
|
1652
|
+
const continuation = ctx.renderConfig.labels.continuation;
|
|
1653
|
+
const placeLabel = (d, label) => {
|
|
1166
1654
|
const clampedFrom = Math.max(d.from, ctx.depthFrom);
|
|
1167
1655
|
const clampedTo = Math.min(d.to, ctx.depthTo);
|
|
1168
1656
|
if (clampedFrom >= clampedTo) return;
|
|
1657
|
+
const text = continuation?.active && d.from < ctx.depthFrom ? `\u2191 ${label}` : label;
|
|
1169
1658
|
const midY = ctx.yScale((clampedFrom + clampedTo) / 2);
|
|
1170
|
-
const leftEdgeX = (ctx.POCO_CENTER - xScale(d.diameter)) / 2;
|
|
1171
|
-
const labelRightX = leftEdgeX - clc.xOffset;
|
|
1172
1659
|
const charW = clct.fontSize * 0.52;
|
|
1173
1660
|
const lineH = clct.fontSize * 1.35;
|
|
1174
1661
|
const vertPad = 6;
|
|
@@ -1185,16 +1672,17 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1185
1672
|
lines = [text];
|
|
1186
1673
|
boxW = text.length * charW + 8;
|
|
1187
1674
|
}
|
|
1675
|
+
const labelRightX = onRight ? (ctx.POCO_CENTER + ctx.POCO_WIDTH) / 2 + clc.xOffset + boxW : (ctx.POCO_CENTER - xScale(d.diameter)) / 2 - clc.xOffset;
|
|
1188
1676
|
const labelH = lines.length * lineH + vertPad;
|
|
1189
|
-
let labelY = midY - labelH / 2;
|
|
1677
|
+
let labelY = onRight ? ctx.yScale(clampedFrom) + 1 : midY - labelH / 2;
|
|
1190
1678
|
for (const pos of occupied) {
|
|
1191
1679
|
if (labelY < pos.bot && labelY + labelH > pos.top) labelY = pos.bot + 2;
|
|
1192
1680
|
}
|
|
1193
1681
|
occupied.push({ top: labelY, bot: labelY + labelH });
|
|
1194
1682
|
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");
|
|
1683
|
+
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
1684
|
lines.forEach((line, i) => {
|
|
1197
|
-
textEl.append("tspan").attr("x", labelRightX - 4).attr("dy", i === 0 ? 0 : lineH).text(line);
|
|
1685
|
+
textEl.append("tspan").attr("x", onRight ? labelRightX - boxW + 4 : labelRightX - 4).attr("dy", i === 0 ? 0 : lineH).text(line);
|
|
1198
1686
|
});
|
|
1199
1687
|
};
|
|
1200
1688
|
let lastDiam = 0;
|
|
@@ -1207,7 +1695,7 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1207
1695
|
}).forEach(
|
|
1208
1696
|
(d) => placeLabel(
|
|
1209
1697
|
d,
|
|
1210
|
-
`${clc.labels.wellCasePrefix} ${fmtD(d.diameter)}${dUnit} ${d.type}`
|
|
1698
|
+
`${clc.labels.wellCasePrefix} ${fmtD(d.diameter)}${dUnit} ${material(d.type)}`
|
|
1211
1699
|
)
|
|
1212
1700
|
);
|
|
1213
1701
|
lastDiam = 0;
|
|
@@ -1220,7 +1708,7 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1220
1708
|
}).forEach(
|
|
1221
1709
|
(d) => placeLabel(
|
|
1222
1710
|
d,
|
|
1223
|
-
`${clc.labels.wellScreenPrefix} ${fmtD(d.diameter)}${dUnit} ${d.type} ${clc.labels.wellScreenSlotPrefix} ${fmtD(d.screen_slot)}${dUnit}`
|
|
1711
|
+
`${clc.labels.wellScreenPrefix} ${fmtD(d.diameter)}${dUnit} ${material(d.type)} ${clc.labels.wellScreenSlotPrefix} ${fmtD(d.screen_slot)}${dUnit}`
|
|
1224
1712
|
)
|
|
1225
1713
|
);
|
|
1226
1714
|
}
|
|
@@ -1228,110 +1716,307 @@ function drawConstructionLabels(ctx, data) {
|
|
|
1228
1716
|
// src/renderers/construction.renderer.ts
|
|
1229
1717
|
import * as d34 from "d3";
|
|
1230
1718
|
import { getProfileDiamValues as getProfileDiamValues3 } from "@welldot/utils";
|
|
1719
|
+
var entering = /* @__PURE__ */ new WeakSet();
|
|
1720
|
+
function constructionXScale(ctx) {
|
|
1721
|
+
const max6 = d34.max(getProfileDiamValues3(ctx.constructionData)) || 0;
|
|
1722
|
+
return d34.scaleLinear().domain([0, max6]).range([0, ctx.POCO_WIDTH]);
|
|
1723
|
+
}
|
|
1724
|
+
function outlineScales(ctx) {
|
|
1725
|
+
const x = constructionXScale(ctx);
|
|
1726
|
+
return {
|
|
1727
|
+
y: ctx.yScale,
|
|
1728
|
+
left: (d) => (ctx.POCO_CENTER - x(d)) / 2,
|
|
1729
|
+
right: (d) => (ctx.POCO_CENTER + x(d)) / 2,
|
|
1730
|
+
depthFrom: ctx.depthFrom,
|
|
1731
|
+
depthTo: ctx.depthTo
|
|
1732
|
+
};
|
|
1733
|
+
}
|
|
1734
|
+
var surfaceCaseDiameter = (ctx, diameter) => diameter * (1 + ctx.renderConfig.construction.surfaceCase.diameterPaddingRatio);
|
|
1735
|
+
function joinIntervalLayer(ctx, group, cls, data, key, tooltip, { shoe = false, pathFill = false, ends = false } = {}) {
|
|
1736
|
+
const sel = group.selectAll(`g.${cls}`).data(data, makeIntervalKey(key));
|
|
1737
|
+
sel.exit().transition(ctx.transition).style("opacity", 0).remove();
|
|
1738
|
+
const top = (d) => ctx.yScale(Math.max(d.from, ctx.depthFrom));
|
|
1739
|
+
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);
|
|
1740
|
+
if (pathFill)
|
|
1741
|
+
entered.append("path").attr("class", `${cls}-fill`).attr("stroke", "none").attr("fill-rule", "evenodd").attr("d", "");
|
|
1742
|
+
else
|
|
1743
|
+
entered.append("rect").attr("class", `${cls}-fill`).attr("stroke", "none").attr("y", top).attr("height", 0);
|
|
1744
|
+
entered.append("path").attr("class", `${cls}-outline`).attr("fill", "none").attr("d", "");
|
|
1745
|
+
if (shoe)
|
|
1746
|
+
entered.append("path").attr("class", `${cls}-shoe`).attr("stroke-linejoin", "round").attr("d", "");
|
|
1747
|
+
if (ends)
|
|
1748
|
+
entered.append("path").attr("class", `${cls}-ends`).attr("fill", "none").attr("d", "");
|
|
1749
|
+
return entered.merge(sel);
|
|
1750
|
+
}
|
|
1751
|
+
function drawCementPad(ctx, pad) {
|
|
1752
|
+
const cls = ctx.classes.cementPad.item;
|
|
1753
|
+
const visible = !!pad?.thickness && ctx.depthFrom <= 0 && ctx.depthTo > 0;
|
|
1754
|
+
const sel = ctx.groups.cementPadGroup.selectAll(`g.${cls}`).data(visible ? [pad] : [], () => "cement_pad");
|
|
1755
|
+
sel.exit().remove();
|
|
1756
|
+
if (!visible) return;
|
|
1757
|
+
const entered = sel.enter().append("g").attr("class", cls).on("mouseover", ctx.tooltips.cementPad.show).on("mouseout", ctx.tooltips.cementPad.hide);
|
|
1758
|
+
entered.append("path").attr("class", `${cls}-slab`);
|
|
1759
|
+
entered.append("path").attr("class", `${cls}-slab`);
|
|
1760
|
+
const x = constructionXScale(ctx);
|
|
1761
|
+
const { opening, outer } = getPadDiameters(
|
|
1762
|
+
ctx.constructionData,
|
|
1763
|
+
ctx.renderConfig.construction.surfaceCase.diameterPaddingRatio
|
|
1764
|
+
);
|
|
1765
|
+
const { slabs } = getCementPadGeometry(
|
|
1766
|
+
ctx.POCO_WIDTH,
|
|
1767
|
+
ctx.POCO_CENTER,
|
|
1768
|
+
ctx.yScale(0),
|
|
1769
|
+
ctx.renderConfig.construction.cementPad,
|
|
1770
|
+
x(opening),
|
|
1771
|
+
x(outer)
|
|
1772
|
+
);
|
|
1773
|
+
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");
|
|
1774
|
+
}
|
|
1775
|
+
function layoutConstruction(ctx, animate = false) {
|
|
1776
|
+
const c = ctx.classes;
|
|
1777
|
+
const scales = outlineScales(ctx);
|
|
1778
|
+
const data = ctx.constructionData;
|
|
1779
|
+
const motion = (sel) => animate ? withTransition(sel, ctx.transition) : sel;
|
|
1780
|
+
const yTop = (d) => ctx.yScale(Math.max(d.from, ctx.depthFrom));
|
|
1781
|
+
const yBottom = (d) => ctx.yScale(Math.min(d.to, ctx.depthTo));
|
|
1782
|
+
const collapsed = (d) => ({
|
|
1783
|
+
...scales,
|
|
1784
|
+
y: () => yTop(d)
|
|
1785
|
+
});
|
|
1786
|
+
const shapeParts = (items, part, attr, shape) => {
|
|
1787
|
+
const parts = items.select(part);
|
|
1788
|
+
if (animate)
|
|
1789
|
+
parts.filter(function() {
|
|
1790
|
+
return entering.has(this.parentNode);
|
|
1791
|
+
}).attr(attr, (d) => shape(d, collapsed(d)));
|
|
1792
|
+
motion(parts).attr(attr, (d) => shape(d, scales));
|
|
1793
|
+
};
|
|
1794
|
+
const layoutLayer = (group, cls, diameter, outline, {
|
|
1795
|
+
shoe: shoe2,
|
|
1796
|
+
ends,
|
|
1797
|
+
fill
|
|
1798
|
+
} = {}) => {
|
|
1799
|
+
const items = group.selectAll(`g.${cls}`);
|
|
1800
|
+
shapeParts(items, `.${cls}-outline`, "d", outline);
|
|
1801
|
+
if (shoe2) shapeParts(items, `.${cls}-shoe`, "d", shoe2);
|
|
1802
|
+
if (ends) shapeParts(items, `.${cls}-ends`, "d", ends);
|
|
1803
|
+
if (fill) {
|
|
1804
|
+
shapeParts(items, `.${cls}-fill`, "d", fill);
|
|
1805
|
+
return;
|
|
1806
|
+
}
|
|
1807
|
+
motion(
|
|
1808
|
+
items.select(`.${cls}-fill`).attr("x", (d) => scales.left(diameter(d))).attr(
|
|
1809
|
+
"width",
|
|
1810
|
+
(d) => scales.right(diameter(d)) - scales.left(diameter(d))
|
|
1811
|
+
)
|
|
1812
|
+
).attr("y", yTop).attr("height", (d) => Math.max(0, yBottom(d) - yTop(d)));
|
|
1813
|
+
};
|
|
1814
|
+
const walls = (d, s, dia = d.diameter) => pipeWallsPath(
|
|
1815
|
+
s.left(dia),
|
|
1816
|
+
s.right(dia),
|
|
1817
|
+
s.y(Math.max(d.from, s.depthFrom)),
|
|
1818
|
+
s.y(Math.min(d.to, s.depthTo))
|
|
1819
|
+
);
|
|
1820
|
+
layoutLayer(
|
|
1821
|
+
ctx.groups.holeGroup,
|
|
1822
|
+
c.boreHole.rect,
|
|
1823
|
+
(d) => d.diameter,
|
|
1824
|
+
(d, s) => boreHoleOutlinePath(d, data.bore_hole, s)
|
|
1825
|
+
);
|
|
1826
|
+
const pipes = [...data.well_case, ...data.well_screen];
|
|
1827
|
+
const insideSurface = [...data.bore_hole, ...data.hole_fill, ...pipes];
|
|
1828
|
+
const scDiameter = (d) => surfaceCaseDiameter(ctx, d.diameter);
|
|
1829
|
+
layoutLayer(
|
|
1830
|
+
ctx.groups.surfaceCaseGroup,
|
|
1831
|
+
c.surfaceCase.rect,
|
|
1832
|
+
scDiameter,
|
|
1833
|
+
(d, s) => walls(d, s, scDiameter(d)),
|
|
1834
|
+
// Only the ring outside the hole: the texture never shows under the casing.
|
|
1835
|
+
{
|
|
1836
|
+
fill: (d, s) => annulusFillPath({ ...d, diameter: scDiameter(d) }, insideSurface, s)
|
|
1837
|
+
}
|
|
1838
|
+
);
|
|
1839
|
+
layoutLayer(
|
|
1840
|
+
ctx.groups.holeFillGroup,
|
|
1841
|
+
c.holeFill.rect,
|
|
1842
|
+
(d) => d.diameter,
|
|
1843
|
+
(d, s) => holeFillOutlinePath(d, pipes, s),
|
|
1844
|
+
{ fill: (d, s) => annulusFillPath(d, pipes, s) }
|
|
1845
|
+
);
|
|
1846
|
+
const string = [...pipes, ...data.reduction ?? []];
|
|
1847
|
+
const shoeCfg = ctx.renderConfig.construction.casingShoe;
|
|
1848
|
+
const endsCfg = ctx.renderConfig.construction.screenEnds;
|
|
1849
|
+
const room = (d, depth, size) => {
|
|
1850
|
+
const hole = diameterAt(data.bore_hole, depth);
|
|
1851
|
+
const annulus = hole !== void 0 && hole > d.diameter ? scales.left(d.diameter) - scales.left(hole) - 1 : size;
|
|
1852
|
+
return Math.max(2, Math.min(size, annulus));
|
|
1853
|
+
};
|
|
1854
|
+
const shoe = (d, s) => {
|
|
1855
|
+
const ends = getIntervalEnds(d, string, ctx.depthFrom, ctx.depthTo);
|
|
1856
|
+
if (!shoeCfg.active || ends.cutBottom || ends.joinedBottom) return "";
|
|
1857
|
+
return shoePath(
|
|
1858
|
+
s.left(d.diameter),
|
|
1859
|
+
s.right(d.diameter),
|
|
1860
|
+
s.y(Math.min(d.to, s.depthTo)),
|
|
1861
|
+
room(d, d.to, shoeCfg.size)
|
|
1862
|
+
);
|
|
1863
|
+
};
|
|
1864
|
+
const screenEnds = (d, s) => {
|
|
1865
|
+
if (!endsCfg.active) return "";
|
|
1866
|
+
const ends = getIntervalEnds(d, string, ctx.depthFrom, ctx.depthTo);
|
|
1867
|
+
const mark = (depth) => screenEndPath(s.left(d.diameter), s.right(d.diameter), s.y(depth));
|
|
1868
|
+
return (ends.cutTop ? "" : mark(d.from)) + (ends.cutBottom ? "" : mark(d.to));
|
|
1869
|
+
};
|
|
1870
|
+
layoutLayer(
|
|
1871
|
+
ctx.groups.wellCaseGroup,
|
|
1872
|
+
c.wellCase.rect,
|
|
1873
|
+
(d) => d.diameter,
|
|
1874
|
+
walls,
|
|
1875
|
+
{ shoe }
|
|
1876
|
+
);
|
|
1877
|
+
layoutLayer(
|
|
1878
|
+
ctx.groups.wellScreenGroup,
|
|
1879
|
+
c.wellScreen.rect,
|
|
1880
|
+
(d) => d.diameter,
|
|
1881
|
+
walls,
|
|
1882
|
+
{ shoe, ends: screenEnds }
|
|
1883
|
+
);
|
|
1884
|
+
const reductions = ctx.groups.reductionGroup.selectAll(`g.${c.reduction.item}`);
|
|
1885
|
+
const corners = (d, s) => {
|
|
1886
|
+
const t = s.y(Math.max(d.from, s.depthFrom));
|
|
1887
|
+
const b = s.y(Math.min(d.to, s.depthTo));
|
|
1888
|
+
return {
|
|
1889
|
+
tl: `${s.left(d.diam_from)},${t}`,
|
|
1890
|
+
tr: `${s.right(d.diam_from)},${t}`,
|
|
1891
|
+
bl: `${s.left(d.diam_to)},${b}`,
|
|
1892
|
+
br: `${s.right(d.diam_to)},${b}`
|
|
1893
|
+
};
|
|
1894
|
+
};
|
|
1895
|
+
shapeParts(reductions, `.${c.reduction.item}-fill`, "points", (d, s) => {
|
|
1896
|
+
const p = corners(d, s);
|
|
1897
|
+
return `${p.tl} ${p.tr} ${p.br} ${p.bl}`;
|
|
1898
|
+
});
|
|
1899
|
+
shapeParts(reductions, `.${c.reduction.item}-outline`, "d", (d, s) => {
|
|
1900
|
+
const p = corners(d, s);
|
|
1901
|
+
return `M${p.tl}L${p.bl}M${p.tr}L${p.br}`;
|
|
1902
|
+
});
|
|
1903
|
+
if (animate) {
|
|
1904
|
+
for (const group of [
|
|
1905
|
+
ctx.groups.holeGroup,
|
|
1906
|
+
ctx.groups.surfaceCaseGroup,
|
|
1907
|
+
ctx.groups.holeFillGroup,
|
|
1908
|
+
ctx.groups.wellCaseGroup,
|
|
1909
|
+
ctx.groups.wellScreenGroup,
|
|
1910
|
+
ctx.groups.reductionGroup
|
|
1911
|
+
])
|
|
1912
|
+
group.selectAll("g").each(function() {
|
|
1913
|
+
entering.delete(this);
|
|
1914
|
+
});
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1231
1917
|
function drawConstructive(ctx, data) {
|
|
1232
1918
|
const { getHeight, getYPos } = getYAxisFunctions(ctx.yScale, {
|
|
1233
1919
|
from: ctx.depthFrom,
|
|
1234
1920
|
to: ctx.depthTo
|
|
1235
1921
|
});
|
|
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
|
|
1922
|
+
const c = ctx.classes;
|
|
1923
|
+
const theme = ctx.theme;
|
|
1924
|
+
drawCementPad(ctx, data.cement_pad);
|
|
1925
|
+
joinIntervalLayer(
|
|
1926
|
+
ctx,
|
|
1927
|
+
ctx.groups.holeGroup,
|
|
1928
|
+
c.boreHole.rect,
|
|
1929
|
+
data.bore_hole,
|
|
1930
|
+
"bore_hole",
|
|
1931
|
+
ctx.tooltips.hole
|
|
1932
|
+
).attr("opacity", theme.boreHole.opacity).call((g) => {
|
|
1933
|
+
g.select(`.${c.boreHole.rect}-fill`).attr("fill", theme.boreHole.fill);
|
|
1934
|
+
g.select(`.${c.boreHole.rect}-outline`).attr("stroke", theme.boreHole.stroke).attr("stroke-width", theme.boreHole.strokeWidth).attr("stroke-dasharray", theme.boreHole.strokeDasharray);
|
|
1935
|
+
});
|
|
1936
|
+
joinIntervalLayer(
|
|
1937
|
+
ctx,
|
|
1938
|
+
ctx.groups.surfaceCaseGroup,
|
|
1939
|
+
c.surfaceCase.rect,
|
|
1940
|
+
data.surface_case,
|
|
1941
|
+
"surface_case",
|
|
1942
|
+
ctx.tooltips.surfaceCase,
|
|
1943
|
+
{ pathFill: true }
|
|
1944
|
+
).call((g) => {
|
|
1945
|
+
g.select(`.${c.surfaceCase.rect}-fill`).attr(
|
|
1946
|
+
"fill",
|
|
1947
|
+
ctx.textures.surface_case.url()
|
|
1276
1948
|
);
|
|
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);
|
|
1949
|
+
g.select(`.${c.surfaceCase.rect}-outline`).attr("stroke", theme.surfaceCase.stroke).attr("stroke-width", theme.surfaceCase.strokeWidth);
|
|
1282
1950
|
});
|
|
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
|
-
|
|
1951
|
+
joinIntervalLayer(
|
|
1952
|
+
ctx,
|
|
1953
|
+
ctx.groups.holeFillGroup,
|
|
1954
|
+
c.holeFill.rect,
|
|
1955
|
+
data.hole_fill,
|
|
1956
|
+
"hole_fill",
|
|
1957
|
+
ctx.tooltips.holeFill,
|
|
1958
|
+
{ pathFill: true }
|
|
1959
|
+
).call((g) => {
|
|
1960
|
+
g.select(`.${c.holeFill.rect}-fill`).attr(
|
|
1961
|
+
"fill",
|
|
1962
|
+
(d) => ctx.textures[d.type].url()
|
|
1963
|
+
);
|
|
1964
|
+
g.select(`.${c.holeFill.rect}-outline`).attr("stroke", theme.holeFill.stroke).attr("stroke-width", theme.holeFill.strokeWidth);
|
|
1965
|
+
});
|
|
1966
|
+
for (const [group, cls, items, key, tooltip, fill, stroke] of [
|
|
1967
|
+
[
|
|
1968
|
+
ctx.groups.wellCaseGroup,
|
|
1969
|
+
c.wellCase.rect,
|
|
1970
|
+
data.well_case,
|
|
1971
|
+
"well_case",
|
|
1972
|
+
ctx.tooltips.wellCase,
|
|
1973
|
+
theme.wellCase.fill,
|
|
1974
|
+
theme.wellCase
|
|
1975
|
+
],
|
|
1976
|
+
[
|
|
1977
|
+
ctx.groups.wellScreenGroup,
|
|
1978
|
+
c.wellScreen.rect,
|
|
1979
|
+
data.well_screen,
|
|
1980
|
+
"well_screen",
|
|
1981
|
+
ctx.tooltips.wellScreen,
|
|
1982
|
+
ctx.textures.well_screen.url(),
|
|
1983
|
+
theme.wellScreen
|
|
1984
|
+
]
|
|
1985
|
+
]) {
|
|
1986
|
+
joinIntervalLayer(ctx, group, cls, items, key, tooltip, {
|
|
1987
|
+
shoe: true,
|
|
1988
|
+
ends: cls === c.wellScreen.rect
|
|
1989
|
+
}).call((g) => {
|
|
1990
|
+
g.select(`.${cls}-fill`).attr("fill", fill);
|
|
1991
|
+
g.select(`.${cls}-outline`).attr("stroke", stroke.stroke).attr("stroke-width", stroke.strokeWidth);
|
|
1992
|
+
g.select(`.${cls}-shoe`).attr("fill", stroke.stroke).attr("stroke", stroke.stroke).attr("stroke-width", 0.5);
|
|
1993
|
+
g.select(`.${cls}-ends`).attr("stroke", stroke.stroke).attr("stroke-width", theme.wellScreen.endStrokeWidth).attr("stroke-dasharray", theme.wellScreen.endDasharray);
|
|
1994
|
+
});
|
|
1995
|
+
}
|
|
1996
|
+
const reduction = ctx.groups.reductionGroup.selectAll(`g.${c.reduction.item}`).data(data.reduction ?? [], makeIntervalKey("reduction"));
|
|
1314
1997
|
reduction.exit().transition(ctx.transition).style("opacity", 0).remove();
|
|
1315
|
-
const
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1998
|
+
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);
|
|
1999
|
+
newReduction.append("polygon").attr("class", `${c.reduction.item}-fill`).attr("stroke", "none");
|
|
2000
|
+
newReduction.append("path").attr("class", `${c.reduction.item}-outline`).attr("fill", "none");
|
|
2001
|
+
newReduction.merge(reduction).call((g) => {
|
|
2002
|
+
g.select(`.${c.reduction.item}-fill`).attr("fill", theme.reduction.fill);
|
|
2003
|
+
g.select(`.${c.reduction.item}-outline`).attr("stroke", theme.reduction.stroke).attr("stroke-width", theme.reduction.strokeWidth);
|
|
2004
|
+
});
|
|
2005
|
+
const mergedConflicts = mergeConflicts(
|
|
2006
|
+
[
|
|
2007
|
+
...getConflictAreas(data.well_case, data.well_screen),
|
|
2008
|
+
...getConflictAreas(data.well_screen, data.well_case)
|
|
2009
|
+
],
|
|
2010
|
+
1
|
|
1325
2011
|
);
|
|
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"));
|
|
2012
|
+
const xScale = constructionXScale(ctx);
|
|
2013
|
+
const yPos = getYPos;
|
|
2014
|
+
const conflict = ctx.groups.conflictGroup.selectAll(`.${c.conflict.rect}`).data(mergedConflicts, makeIntervalKey("conflict"));
|
|
1331
2015
|
conflict.exit().transition(ctx.transition).attr("height", 0).remove();
|
|
1332
|
-
const newConflict = conflict.enter().append("rect").attr("class",
|
|
2016
|
+
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
2017
|
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",
|
|
2018
|
+
withTransition(mergedConflict, ctx.transition).attr("y", getYPos).attr("height", getHeight);
|
|
2019
|
+
layoutConstruction(ctx, true);
|
|
1335
2020
|
}
|
|
1336
2021
|
|
|
1337
2022
|
// src/renderers/fractures.renderer.ts
|
|
@@ -1347,7 +2032,6 @@ function wavyLine(rng, steps, baseY, jitter, startInset, endInset) {
|
|
|
1347
2032
|
return pts;
|
|
1348
2033
|
}
|
|
1349
2034
|
function drawFractures(ctx, data) {
|
|
1350
|
-
if (!data.length) return;
|
|
1351
2035
|
const {
|
|
1352
2036
|
groups: { fracturesGroup },
|
|
1353
2037
|
POCO_WIDTH,
|
|
@@ -1369,7 +2053,7 @@ function drawFractures(ctx, data) {
|
|
|
1369
2053
|
const merged = mergeEnter(entered, groups);
|
|
1370
2054
|
merged.attr(
|
|
1371
2055
|
"transform",
|
|
1372
|
-
(fracture) => `translate(0,${yScale(fracture.depth)}) rotate(${fracture.dip},${pocoCenterX},0)`
|
|
2056
|
+
(fracture) => `translate(0,${yScale(fracture.depth)}) rotate(${fractureDip(fracture.dip)},${pocoCenterX},0)`
|
|
1373
2057
|
);
|
|
1374
2058
|
merged.each(function(fracture) {
|
|
1375
2059
|
const g = d35.select(this);
|
|
@@ -1514,24 +2198,26 @@ function drawHighlights(ctx, hl) {
|
|
|
1514
2198
|
const maxXVals = getProfileDiamValues4(ctx.constructionData);
|
|
1515
2199
|
const xScaleConstr = d36.scaleLinear().domain([0, d36.max(maxXVals) || 0]).range([0, ctx.POCO_WIDTH]);
|
|
1516
2200
|
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
|
|
2201
|
+
if (hl.cement_pad && ctx.depthFrom <= 0 && ctx.depthTo > 0 && ctx.constructionData.cement_pad?.thickness) {
|
|
2202
|
+
const { opening, outer } = getPadDiameters(
|
|
2203
|
+
ctx.constructionData,
|
|
2204
|
+
constructionConfig.surfaceCase.diameterPaddingRatio
|
|
1523
2205
|
);
|
|
1524
|
-
const
|
|
1525
|
-
|
|
1526
|
-
|
|
2206
|
+
const pad = getCementPadRect(
|
|
2207
|
+
ctx.POCO_WIDTH,
|
|
2208
|
+
ctx.POCO_CENTER,
|
|
2209
|
+
ctx.yScale(0),
|
|
2210
|
+
constructionConfig.cementPad,
|
|
2211
|
+
xScaleConstr(opening),
|
|
2212
|
+
xScaleConstr(outer)
|
|
1527
2213
|
);
|
|
1528
2214
|
drawHighlightItem(
|
|
1529
2215
|
ctx,
|
|
1530
2216
|
ctx.groups.highlightsConstructionGroup,
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
2217
|
+
pad.x,
|
|
2218
|
+
pad.y,
|
|
2219
|
+
pad.width,
|
|
2220
|
+
pad.height,
|
|
1535
2221
|
hl.cement_pad.label
|
|
1536
2222
|
);
|
|
1537
2223
|
}
|
|
@@ -1607,8 +2293,12 @@ function drawHighlights(ctx, hl) {
|
|
|
1607
2293
|
// src/renderers/legend.renderer.ts
|
|
1608
2294
|
import * as d3module from "d3";
|
|
1609
2295
|
import { defu } from "defu";
|
|
2296
|
+
import { getCurrentPump } from "@welldot/utils";
|
|
1610
2297
|
var d37 = { ...d3module };
|
|
1611
|
-
|
|
2298
|
+
var SYMBOL_WIDTH = 24;
|
|
2299
|
+
var SYMBOL_HEIGHT = 12;
|
|
2300
|
+
var SYMBOL_MARGIN = 2;
|
|
2301
|
+
function getWellLegendItems(profile, labels = INTERACTIVE_RENDER_CONFIG.legend.labels) {
|
|
1612
2302
|
const fractures = profile.fractures ?? [];
|
|
1613
2303
|
const caves = profile.caves ?? [];
|
|
1614
2304
|
const boreHoles = profile.bore_hole ?? [];
|
|
@@ -1629,6 +2319,7 @@ function drawWellLegend(selector, profile, options = {}) {
|
|
|
1629
2319
|
const hasWellScreen = wellScreens.length > 0;
|
|
1630
2320
|
const hasReduction = reductions.length > 0;
|
|
1631
2321
|
const hasCentralizer = (profile.centralizers ?? []).length > 0;
|
|
2322
|
+
const hasPump = getCurrentPump(profile)?.intake_depth !== void 0;
|
|
1632
2323
|
const hasCementPad = !!profile.cement_pad?.thickness;
|
|
1633
2324
|
const hasConflict = mergeConflicts(
|
|
1634
2325
|
[
|
|
@@ -1637,222 +2328,314 @@ function drawWellLegend(selector, profile, options = {}) {
|
|
|
1637
2328
|
],
|
|
1638
2329
|
1
|
|
1639
2330
|
).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
2331
|
const items = [];
|
|
1647
2332
|
if (hasSimple)
|
|
1648
2333
|
items.push({
|
|
1649
2334
|
kind: "fracture",
|
|
1650
|
-
|
|
2335
|
+
key: "fractureSingle",
|
|
2336
|
+
label: labels.fractureSingle,
|
|
1651
2337
|
swarm: false,
|
|
1652
2338
|
water_intake: false
|
|
1653
2339
|
});
|
|
1654
2340
|
if (hasSwarm)
|
|
1655
2341
|
items.push({
|
|
1656
2342
|
kind: "fracture",
|
|
1657
|
-
|
|
2343
|
+
key: "fractureSwarm",
|
|
2344
|
+
label: labels.fractureSwarm,
|
|
1658
2345
|
swarm: true,
|
|
1659
2346
|
water_intake: false
|
|
1660
2347
|
});
|
|
1661
2348
|
if (hasWaterFx)
|
|
1662
2349
|
items.push({
|
|
1663
2350
|
kind: "fracture",
|
|
1664
|
-
|
|
2351
|
+
key: "fractureWater",
|
|
2352
|
+
label: labels.fractureWater,
|
|
1665
2353
|
swarm: false,
|
|
1666
2354
|
water_intake: true
|
|
1667
2355
|
});
|
|
1668
2356
|
if (hasCaveDry)
|
|
1669
2357
|
items.push({
|
|
1670
2358
|
kind: "cave",
|
|
1671
|
-
|
|
2359
|
+
key: "caveDry",
|
|
2360
|
+
label: labels.caveDry,
|
|
1672
2361
|
water_intake: false
|
|
1673
2362
|
});
|
|
1674
2363
|
if (hasCaveWet)
|
|
1675
|
-
items.push({
|
|
2364
|
+
items.push({
|
|
2365
|
+
kind: "cave",
|
|
2366
|
+
key: "caveWet",
|
|
2367
|
+
label: labels.caveWet,
|
|
2368
|
+
water_intake: true
|
|
2369
|
+
});
|
|
1676
2370
|
if (hasCementPad)
|
|
1677
2371
|
items.push({
|
|
1678
2372
|
kind: "construction",
|
|
1679
|
-
|
|
2373
|
+
key: "cementPad",
|
|
2374
|
+
label: labels.cementPad,
|
|
1680
2375
|
subKind: "cementPad"
|
|
1681
2376
|
});
|
|
1682
2377
|
if (hasBoreHole)
|
|
1683
2378
|
items.push({
|
|
1684
2379
|
kind: "construction",
|
|
1685
|
-
|
|
2380
|
+
key: "boreHole",
|
|
2381
|
+
label: labels.boreHole,
|
|
1686
2382
|
subKind: "boreHole"
|
|
1687
2383
|
});
|
|
1688
2384
|
if (hasSurfaceCase)
|
|
1689
2385
|
items.push({
|
|
1690
2386
|
kind: "construction",
|
|
1691
|
-
|
|
2387
|
+
key: "surfaceCase",
|
|
2388
|
+
label: labels.surfaceCase,
|
|
1692
2389
|
subKind: "surfaceCase"
|
|
1693
2390
|
});
|
|
1694
2391
|
if (hasHoleFillGravel)
|
|
1695
2392
|
items.push({
|
|
1696
2393
|
kind: "construction",
|
|
1697
|
-
|
|
2394
|
+
key: "holeFillGravel",
|
|
2395
|
+
label: labels.holeFillGravel,
|
|
1698
2396
|
subKind: "holeFillGravel"
|
|
1699
2397
|
});
|
|
1700
2398
|
if (hasHoleFillSeal)
|
|
1701
2399
|
items.push({
|
|
1702
2400
|
kind: "construction",
|
|
1703
|
-
|
|
2401
|
+
key: "holeFillSeal",
|
|
2402
|
+
label: labels.holeFillSeal,
|
|
1704
2403
|
subKind: "holeFillSeal"
|
|
1705
2404
|
});
|
|
1706
2405
|
if (hasWellCase)
|
|
1707
2406
|
items.push({
|
|
1708
2407
|
kind: "construction",
|
|
1709
|
-
|
|
2408
|
+
key: "wellCase",
|
|
2409
|
+
label: labels.wellCase,
|
|
1710
2410
|
subKind: "wellCase"
|
|
1711
2411
|
});
|
|
1712
2412
|
if (hasWellScreen)
|
|
1713
2413
|
items.push({
|
|
1714
2414
|
kind: "construction",
|
|
1715
|
-
|
|
2415
|
+
key: "wellScreen",
|
|
2416
|
+
label: labels.wellScreen,
|
|
1716
2417
|
subKind: "wellScreen"
|
|
1717
2418
|
});
|
|
1718
2419
|
if (hasReduction)
|
|
1719
2420
|
items.push({
|
|
1720
2421
|
kind: "construction",
|
|
1721
|
-
|
|
2422
|
+
key: "reduction",
|
|
2423
|
+
label: labels.reduction,
|
|
1722
2424
|
subKind: "reduction"
|
|
1723
2425
|
});
|
|
1724
2426
|
if (hasCentralizer)
|
|
1725
2427
|
items.push({
|
|
1726
2428
|
kind: "construction",
|
|
1727
|
-
|
|
2429
|
+
key: "centralizer",
|
|
2430
|
+
label: labels.centralizer,
|
|
1728
2431
|
subKind: "centralizer"
|
|
1729
2432
|
});
|
|
2433
|
+
if (hasPump)
|
|
2434
|
+
items.push({
|
|
2435
|
+
kind: "construction",
|
|
2436
|
+
key: "pump",
|
|
2437
|
+
label: labels.pump,
|
|
2438
|
+
subKind: "pump"
|
|
2439
|
+
});
|
|
1730
2440
|
if (hasConflict)
|
|
1731
2441
|
items.push({
|
|
1732
2442
|
kind: "construction",
|
|
1733
|
-
|
|
2443
|
+
key: "conflict",
|
|
2444
|
+
label: labels.conflict,
|
|
1734
2445
|
subKind: "conflict"
|
|
1735
2446
|
});
|
|
2447
|
+
return items;
|
|
2448
|
+
}
|
|
2449
|
+
function drawLegendSymbol(symG, item, cx, rowSymY, { theme, cls, textures: legendTextures }) {
|
|
2450
|
+
const RC = "round";
|
|
2451
|
+
const rw = SYMBOL_WIDTH;
|
|
2452
|
+
const rh = SYMBOL_HEIGHT;
|
|
2453
|
+
if (item.kind === "fracture") {
|
|
2454
|
+
const color = item.water_intake ? theme.fracture.wetStroke : theme.fracture.dryStroke;
|
|
2455
|
+
if (item.swarm) {
|
|
2456
|
+
[-4, 0, 4].forEach((offset) => {
|
|
2457
|
+
symG.append("polyline").attr("class", cls.fracturePoly).attr(
|
|
2458
|
+
"points",
|
|
2459
|
+
`${cx},${rowSymY + offset} ${cx + 6},${rowSymY + offset - 1} ${cx + 12},${rowSymY + offset + 1} ${cx + 18},${rowSymY + offset - 0.5} ${cx + 24},${rowSymY + offset}`
|
|
2460
|
+
).attr("stroke", color).attr(
|
|
2461
|
+
"stroke-width",
|
|
2462
|
+
offset !== 0 ? theme.legend.fractureSideStrokeWidth : theme.legend.fractureStrokeWidth
|
|
2463
|
+
).attr("fill", "none").attr("stroke-linecap", RC).attr("stroke-linejoin", RC);
|
|
2464
|
+
});
|
|
2465
|
+
} else {
|
|
2466
|
+
symG.append("polyline").attr("class", cls.fracturePoly).attr(
|
|
2467
|
+
"points",
|
|
2468
|
+
`${cx},${rowSymY} ${cx + 5},${rowSymY - 1.5} ${cx + 11},${rowSymY + 1} ${cx + 17},${rowSymY - 0.5} ${cx + 24},${rowSymY}`
|
|
2469
|
+
).attr("stroke", color).attr("stroke-width", theme.legend.fractureStrokeWidth).attr("fill", "none").attr("stroke-linecap", RC).attr("stroke-linejoin", RC);
|
|
2470
|
+
}
|
|
2471
|
+
} else if (item.kind === "cave") {
|
|
2472
|
+
const color = item.water_intake ? theme.cave.wetStroke : theme.cave.dryStroke;
|
|
2473
|
+
const texture = item.water_intake ? legendTextures.cave_wet : legendTextures.cave_dry;
|
|
2474
|
+
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);
|
|
2475
|
+
} else if (item.subKind === "surfaceCase") {
|
|
2476
|
+
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");
|
|
2477
|
+
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);
|
|
2478
|
+
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);
|
|
2479
|
+
} else if (item.subKind === "centralizer") {
|
|
2480
|
+
const pipeW = rw * 0.4;
|
|
2481
|
+
const pipeL = cx + (rw - pipeW) / 2;
|
|
2482
|
+
const pipeR = pipeL + pipeW;
|
|
2483
|
+
const y1 = rowSymY - rh / 2;
|
|
2484
|
+
const y2 = rowSymY + rh / 2;
|
|
2485
|
+
const bowH = rh * 0.3;
|
|
2486
|
+
for (const x of [pipeL, pipeR]) {
|
|
2487
|
+
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);
|
|
2488
|
+
}
|
|
2489
|
+
for (const [from, to] of [
|
|
2490
|
+
[pipeL, cx],
|
|
2491
|
+
[pipeR, cx + rw]
|
|
2492
|
+
]) {
|
|
2493
|
+
symG.append("polyline").attr("class", cls.constructionRect).attr(
|
|
2494
|
+
"points",
|
|
2495
|
+
`${from},${rowSymY - bowH} ${to},${rowSymY} ${from},${rowSymY + bowH}`
|
|
2496
|
+
).attr("fill", theme.centralizer.fill).attr("stroke", theme.centralizer.stroke).attr("stroke-width", theme.centralizer.strokeWidth);
|
|
2497
|
+
}
|
|
2498
|
+
} else if (item.subKind === "pump") {
|
|
2499
|
+
const y1 = rowSymY - rh / 2;
|
|
2500
|
+
const y2 = rowSymY + rh / 2;
|
|
2501
|
+
const midX = cx + rw / 2;
|
|
2502
|
+
const riserHalf = rw * 0.12;
|
|
2503
|
+
const bodyHalf = rw * 0.28;
|
|
2504
|
+
const bodyTop = y1 + rh * 0.4;
|
|
2505
|
+
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");
|
|
2506
|
+
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);
|
|
2507
|
+
symG.append("path").attr("class", cls.constructionRect).attr(
|
|
2508
|
+
"d",
|
|
2509
|
+
`M${midX - bodyHalf},${bodyTop}H${midX + bodyHalf}V${y2}H${midX - bodyHalf}Z`
|
|
2510
|
+
).attr("fill", theme.pump.fill).attr("stroke", theme.pump.stroke).attr("stroke-width", theme.pump.strokeWidth);
|
|
2511
|
+
} else if (item.subKind === "reduction") {
|
|
2512
|
+
const topW = rw * 0.5;
|
|
2513
|
+
const y1 = rowSymY - rh / 2;
|
|
2514
|
+
const y2 = rowSymY + rh / 2;
|
|
2515
|
+
const midX = cx + rw / 2;
|
|
2516
|
+
const tl = `${midX - topW / 2},${y1}`;
|
|
2517
|
+
const tr = `${midX + topW / 2},${y1}`;
|
|
2518
|
+
symG.append("polygon").attr("class", cls.constructionRect).attr("points", `${tl} ${tr} ${cx + rw},${y2} ${cx},${y2}`).attr("fill", theme.reduction.fill).attr("stroke", "none");
|
|
2519
|
+
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);
|
|
2520
|
+
} else if (item.subKind === "wellCase" || item.subKind === "wellScreen" || item.subKind === "boreHole") {
|
|
2521
|
+
const y1 = rowSymY - rh / 2;
|
|
2522
|
+
const y2 = rowSymY + rh / 2;
|
|
2523
|
+
const shoe = 3;
|
|
2524
|
+
const xL = cx + shoe;
|
|
2525
|
+
const xR = cx + rw - shoe;
|
|
2526
|
+
const style = {
|
|
2527
|
+
wellCase: { fill: theme.wellCase.fill, stroke: theme.wellCase.stroke },
|
|
2528
|
+
wellScreen: {
|
|
2529
|
+
fill: legendTextures.well_screen.url(),
|
|
2530
|
+
stroke: theme.wellScreen.stroke
|
|
2531
|
+
},
|
|
2532
|
+
boreHole: { fill: theme.boreHole.fill, stroke: theme.boreHole.stroke }
|
|
2533
|
+
}[item.subKind];
|
|
2534
|
+
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");
|
|
2535
|
+
const walls = symG.append("path").attr("class", cls.constructionRect).attr(
|
|
2536
|
+
"d",
|
|
2537
|
+
pipeWallsPath(xL, xR, y1, y2) + (item.subKind === "boreHole" ? `M${xL},${y2}H${xR}` : "")
|
|
2538
|
+
).attr("fill", "none").attr("stroke", style.stroke).attr("stroke-width", theme.legend.itemStrokeWidth);
|
|
2539
|
+
if (item.subKind === "boreHole")
|
|
2540
|
+
walls.attr("stroke-dasharray", theme.boreHole.strokeDasharray);
|
|
2541
|
+
if (item.subKind === "wellCase")
|
|
2542
|
+
symG.append("path").attr("class", cls.constructionRect).attr("d", shoePath(xL, xR, y2, shoe)).attr("fill", style.stroke).attr("stroke", "none");
|
|
2543
|
+
if (item.subKind === "wellScreen")
|
|
2544
|
+
symG.append("path").attr("class", cls.constructionRect).attr(
|
|
2545
|
+
"d",
|
|
2546
|
+
screenEndPath(xL, xR, y1 + 0.5) + screenEndPath(xL, xR, y2 - 0.5)
|
|
2547
|
+
).attr("fill", "none").attr("stroke", style.stroke).attr("stroke-width", theme.wellScreen.endStrokeWidth).attr("stroke-dasharray", "2, 1.5");
|
|
2548
|
+
} else if (item.subKind === "cementPad") {
|
|
2549
|
+
const h = rh * 0.6;
|
|
2550
|
+
const { slabs } = getCementPadGeometry(
|
|
2551
|
+
rw,
|
|
2552
|
+
2 * cx + rw,
|
|
2553
|
+
rowSymY + h / 2,
|
|
2554
|
+
{ widthRatio: 1, height: h },
|
|
2555
|
+
rw * 0.3
|
|
2556
|
+
);
|
|
2557
|
+
for (const d of slabs)
|
|
2558
|
+
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);
|
|
2559
|
+
} else {
|
|
2560
|
+
const symMap = {
|
|
2561
|
+
holeFillGravel: {
|
|
2562
|
+
fill: legendTextures.gravel_pack.url(),
|
|
2563
|
+
stroke: theme.holeFill.stroke
|
|
2564
|
+
},
|
|
2565
|
+
holeFillSeal: {
|
|
2566
|
+
fill: legendTextures.seal.url(),
|
|
2567
|
+
stroke: theme.holeFill.stroke
|
|
2568
|
+
},
|
|
2569
|
+
conflict: {
|
|
2570
|
+
fill: legendTextures.conflict.url(),
|
|
2571
|
+
stroke: theme.conflict.stroke
|
|
2572
|
+
}
|
|
2573
|
+
};
|
|
2574
|
+
const sym = symMap[item.subKind];
|
|
2575
|
+
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);
|
|
2576
|
+
if (sym.dasharray) symRect.attr("stroke-dasharray", sym.dasharray);
|
|
2577
|
+
}
|
|
2578
|
+
}
|
|
2579
|
+
function resolveStyle(options) {
|
|
2580
|
+
return {
|
|
2581
|
+
theme: defu(options.theme ?? {}, DEFAULT_WELL_THEME),
|
|
2582
|
+
cls: options.classNames ? { ...DEFAULT_COMPONENTS_CLASS_NAMES.legend, ...options.classNames } : DEFAULT_COMPONENTS_CLASS_NAMES.legend,
|
|
2583
|
+
textures: createWellTextures(options.textures)
|
|
2584
|
+
};
|
|
2585
|
+
}
|
|
2586
|
+
function drawWellLegendSymbol(selector, item, options = {}) {
|
|
2587
|
+
const style = resolveStyle(options);
|
|
2588
|
+
const svgEl = d37.select(selector);
|
|
2589
|
+
svgEl.selectAll("*").remove();
|
|
2590
|
+
svgEl.attr("width", SYMBOL_WIDTH + SYMBOL_MARGIN * 2).attr("height", SYMBOL_HEIGHT + SYMBOL_MARGIN * 2);
|
|
2591
|
+
Object.values(style.textures).forEach((t) => svgEl.call(t));
|
|
2592
|
+
const symG = svgEl.append("g").attr("class", style.cls.item);
|
|
2593
|
+
drawLegendSymbol(
|
|
2594
|
+
symG,
|
|
2595
|
+
item,
|
|
2596
|
+
SYMBOL_MARGIN,
|
|
2597
|
+
SYMBOL_MARGIN + SYMBOL_HEIGHT / 2,
|
|
2598
|
+
style
|
|
2599
|
+
);
|
|
2600
|
+
}
|
|
2601
|
+
function drawWellLegend(selector, profile, options = {}) {
|
|
2602
|
+
const cfg = defu(
|
|
2603
|
+
options.config ?? {},
|
|
2604
|
+
INTERACTIVE_RENDER_CONFIG.legend
|
|
2605
|
+
);
|
|
2606
|
+
const items = getWellLegendItems(profile, cfg.labels);
|
|
1736
2607
|
const svgEl = d37.select(selector);
|
|
1737
2608
|
svgEl.selectAll("*").remove();
|
|
1738
2609
|
if (items.length === 0) {
|
|
1739
2610
|
svgEl.attr("width", 0).attr("height", 0);
|
|
1740
2611
|
return;
|
|
1741
2612
|
}
|
|
1742
|
-
const
|
|
1743
|
-
|
|
2613
|
+
const style = resolveStyle(options);
|
|
2614
|
+
const { theme, cls } = style;
|
|
2615
|
+
Object.values(style.textures).forEach((t) => svgEl.call(t));
|
|
1744
2616
|
const itemsPerRow = cfg.maxWidth ? Math.max(1, Math.floor((cfg.maxWidth - cfg.padding * 2) / cfg.itemWidth)) : items.length;
|
|
1745
2617
|
const numRows = Math.ceil(items.length / itemsPerRow);
|
|
1746
2618
|
const rowWidth = Math.min(items.length, itemsPerRow) * cfg.itemWidth;
|
|
1747
2619
|
const totalWidth = cfg.padding * 2 + rowWidth;
|
|
1748
2620
|
const totalHeight = numRows * cfg.height;
|
|
1749
2621
|
svgEl.attr("width", totalWidth).attr("height", totalHeight);
|
|
1750
|
-
const RC = "round";
|
|
1751
2622
|
const g = svgEl.append("g").attr("transform", `translate(${cfg.padding}, 2)`);
|
|
1752
2623
|
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
2624
|
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
2625
|
items.forEach((item, i) => {
|
|
1757
2626
|
const col = i % itemsPerRow;
|
|
1758
2627
|
const row = Math.floor(i / itemsPerRow);
|
|
1759
2628
|
const rowSymY = row * cfg.height + (cfg.height - 4) / 2;
|
|
1760
2629
|
const cx = col * cfg.itemWidth;
|
|
1761
2630
|
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
|
-
}
|
|
2631
|
+
drawLegendSymbol(symG, item, cx, rowSymY, style);
|
|
1849
2632
|
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
2633
|
});
|
|
1851
2634
|
}
|
|
1852
2635
|
|
|
1853
2636
|
// src/renderers/lithology.renderer.ts
|
|
2637
|
+
import * as d38 from "d3";
|
|
1854
2638
|
function drawLithology(ctx, data) {
|
|
1855
|
-
if (!data.length) return;
|
|
1856
2639
|
const {
|
|
1857
2640
|
groups: { lithologyGroup },
|
|
1858
2641
|
svg,
|
|
@@ -1876,10 +2659,219 @@ function drawLithology(ctx, data) {
|
|
|
1876
2659
|
const merged = mergeEnter(newLayers, rects);
|
|
1877
2660
|
withTransition(merged, transition).attr("y", getYPos).attr("height", getHeight).attr("fill", getLithologyFill(data, svg, ctx.theme.lithologyTexture));
|
|
1878
2661
|
}
|
|
2662
|
+
function drawLithologySwatch(selector, layer, options) {
|
|
2663
|
+
const { size, theme } = options;
|
|
2664
|
+
const svg = d38.select(selector);
|
|
2665
|
+
svg.selectAll("*").remove();
|
|
2666
|
+
svg.attr("width", size).attr("height", size);
|
|
2667
|
+
const fill = getLithologyFill([layer], svg, {
|
|
2668
|
+
...theme.lithologyTexture,
|
|
2669
|
+
// Denser pattern so a few strokes show inside the small square.
|
|
2670
|
+
size: Math.max(12, size * 3)
|
|
2671
|
+
});
|
|
2672
|
+
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);
|
|
2673
|
+
}
|
|
2674
|
+
|
|
2675
|
+
// src/renderers/markers.renderer.ts
|
|
2676
|
+
function drawMarkers(ctx, data) {
|
|
2677
|
+
const group = ctx.groups.markersGroup;
|
|
2678
|
+
group.selectAll("*").remove();
|
|
2679
|
+
const cfg = ctx.renderConfig.markers;
|
|
2680
|
+
const theme = ctx.theme.markers;
|
|
2681
|
+
const r = cfg.radius;
|
|
2682
|
+
if (cfg.lithology) {
|
|
2683
|
+
const cx = (ctx.geoXLeft + ctx.geoXRight) / 2;
|
|
2684
|
+
getLithologyMarkers(data.lithology, ctx.depthFrom, ctx.depthTo).forEach(
|
|
2685
|
+
(marker) => {
|
|
2686
|
+
const top = ctx.yScale(marker.from);
|
|
2687
|
+
const bottom = ctx.yScale(marker.to);
|
|
2688
|
+
if (bottom - top < r) return;
|
|
2689
|
+
const cy = bottom - top >= 2 * r + 4 ? top + r + 2 : (top + bottom) / 2;
|
|
2690
|
+
const g = group.append("g").attr("class", ctx.classes.markers.lithology);
|
|
2691
|
+
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);
|
|
2692
|
+
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));
|
|
2693
|
+
}
|
|
2694
|
+
);
|
|
2695
|
+
}
|
|
2696
|
+
if (cfg.fractures) {
|
|
2697
|
+
const x = ctx.pocoCenterX + ctx.POCO_WIDTH * ctx.renderConfig.fractures.widthMultiplier / 2 + 3;
|
|
2698
|
+
getFractureMarkers(data.fractures, ctx.depthFrom, ctx.depthTo).forEach(
|
|
2699
|
+
(marker) => {
|
|
2700
|
+
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);
|
|
2701
|
+
}
|
|
2702
|
+
);
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
// src/renderers/overlap.renderer.ts
|
|
2707
|
+
import textures3 from "textures";
|
|
2708
|
+
import { formatNumber as formatNumber3 } from "@welldot/utils";
|
|
2709
|
+
function drawOverlap(ctx) {
|
|
2710
|
+
const group = ctx.groups.overlapGroup;
|
|
2711
|
+
group.selectAll("*").remove();
|
|
2712
|
+
const { repeatedTo, depthFrom } = ctx;
|
|
2713
|
+
if (repeatedTo == null || repeatedTo <= depthFrom) return;
|
|
2714
|
+
const theme = ctx.theme.overlap;
|
|
2715
|
+
const { margins } = ctx.state;
|
|
2716
|
+
const overview = ctx.renderConfig.overview;
|
|
2717
|
+
const showsDescription = hasDescriptionColumn(ctx);
|
|
2718
|
+
const x0 = -margins.left + (overview.active ? overview.x + overview.width + 4 : 0);
|
|
2719
|
+
const x1 = showsDescription ? ctx.geoXRight + ctx.renderConfig.labels.descriptionXOffset - 4 : ctx.svgWidth - margins.left;
|
|
2720
|
+
const y0 = ctx.yScale(depthFrom);
|
|
2721
|
+
const y1 = ctx.yScale(repeatedTo);
|
|
2722
|
+
const hatch = textures3.lines().size(theme.size).strokeWidth(theme.strokeWidth).stroke(theme.stroke);
|
|
2723
|
+
ctx.svg.call(hatch);
|
|
2724
|
+
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");
|
|
2725
|
+
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");
|
|
2726
|
+
const whole = (m) => formatNumber3(ctx.units.length === "ft" ? m * 3.28084 : m, {
|
|
2727
|
+
maximumFractionDigits: 0,
|
|
2728
|
+
locale: ctx.locale
|
|
2729
|
+
});
|
|
2730
|
+
const unit = getLengthUnit(ctx.units.length);
|
|
2731
|
+
const range = `${whole(depthFrom)}\u2013${whole(repeatedTo)} ${unit}`;
|
|
2732
|
+
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));
|
|
2733
|
+
}
|
|
2734
|
+
|
|
2735
|
+
// src/renderers/overview.renderer.ts
|
|
2736
|
+
function drawOverview(ctx, lithology) {
|
|
2737
|
+
const group = ctx.groups.overviewGroup;
|
|
2738
|
+
group.selectAll("*").remove();
|
|
2739
|
+
const cfg = ctx.renderConfig.overview;
|
|
2740
|
+
if (!cfg.active || lithology.length === 0 || ctx.totalDepth <= 0) return;
|
|
2741
|
+
const theme = ctx.theme.overview;
|
|
2742
|
+
const height = Math.min(cfg.height, ctx.state.height);
|
|
2743
|
+
const { y, window } = getOverviewGeometry(
|
|
2744
|
+
ctx.totalDepth,
|
|
2745
|
+
height,
|
|
2746
|
+
ctx.depthFrom,
|
|
2747
|
+
ctx.depthTo
|
|
2748
|
+
);
|
|
2749
|
+
lithology.forEach((layer) => {
|
|
2750
|
+
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);
|
|
2751
|
+
});
|
|
2752
|
+
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);
|
|
2753
|
+
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);
|
|
2754
|
+
}
|
|
2755
|
+
|
|
2756
|
+
// src/renderers/pump.renderer.ts
|
|
2757
|
+
import * as d39 from "d3";
|
|
2758
|
+
import { getProfileDiamValues as getProfileDiamValues5 } from "@welldot/utils";
|
|
2759
|
+
function getPumpSpans(panelTop, panelBottom, bodyTop, intakeY) {
|
|
2760
|
+
const riserBottom = Math.min(Math.max(panelTop, bodyTop), panelBottom);
|
|
2761
|
+
const top = Math.max(bodyTop, panelTop);
|
|
2762
|
+
const bottom = Math.min(intakeY, panelBottom);
|
|
2763
|
+
return {
|
|
2764
|
+
riserBottom,
|
|
2765
|
+
body: bottom > top ? { top, bottom, cutTop: top > bodyTop, cutBottom: bottom < intakeY } : null
|
|
2766
|
+
};
|
|
2767
|
+
}
|
|
2768
|
+
var riserBreakAmplitude = (width) => Math.min(2, width / 3);
|
|
2769
|
+
function getRiserTop(xLeft, xRight, y, broken) {
|
|
2770
|
+
if (!broken) return { edge: `H${xRight}`, breakLine: "" };
|
|
2771
|
+
const a = riserBreakAmplitude(xRight - xLeft);
|
|
2772
|
+
const w = xRight - xLeft;
|
|
2773
|
+
const zigzag = `L${xLeft + w / 3},${y - a}L${xLeft + 2 * w / 3},${y + a}L${xRight},${y}`;
|
|
2774
|
+
return { edge: zigzag, breakLine: `M${xLeft},${y}${zigzag}` };
|
|
2775
|
+
}
|
|
2776
|
+
var BODY_MAX_FILL = 0.85;
|
|
2777
|
+
var RISER_MAX_FILL = 0.7;
|
|
2778
|
+
function getPumpDiameters(intakeD, narrowestD, riserDiameter, cfg) {
|
|
2779
|
+
const maxBody = intakeD * BODY_MAX_FILL;
|
|
2780
|
+
const riser = Math.min(
|
|
2781
|
+
riserDiameter ?? intakeD * cfg.riserWidthRatio,
|
|
2782
|
+
narrowestD * RISER_MAX_FILL,
|
|
2783
|
+
maxBody * RISER_MAX_FILL
|
|
2784
|
+
);
|
|
2785
|
+
const body = Math.min(
|
|
2786
|
+
Math.max(intakeD * cfg.bodyWidthRatio, riser * 1.4),
|
|
2787
|
+
maxBody
|
|
2788
|
+
);
|
|
2789
|
+
return { riser, body };
|
|
2790
|
+
}
|
|
2791
|
+
function drawPump(ctx, pump) {
|
|
2792
|
+
const group = ctx.groups.pumpGroup;
|
|
2793
|
+
const cls = ctx.classes.pump;
|
|
2794
|
+
const cfg = ctx.renderConfig.construction.pump;
|
|
2795
|
+
const theme = ctx.theme.pump;
|
|
2796
|
+
const intake = pump?.intake_depth;
|
|
2797
|
+
const visible = !!pump && cfg.active && intake !== void 0 && intake > 0 && // the riser crosses this panel when the panel starts above the intake
|
|
2798
|
+
ctx.depthFrom < intake;
|
|
2799
|
+
const data = visible ? [pump] : [];
|
|
2800
|
+
const selection = group.selectAll(`g.${cls.item}`).data(data, (d) => d.id);
|
|
2801
|
+
selection.exit().remove();
|
|
2802
|
+
if (!visible) return;
|
|
2803
|
+
const maxXValue = d39.max(getProfileDiamValues5(ctx.constructionData)) || 0;
|
|
2804
|
+
const xScale = d39.scaleLinear().domain([0, maxXValue]).range([0, ctx.POCO_WIDTH]);
|
|
2805
|
+
const pipes = [
|
|
2806
|
+
...ctx.constructionData.well_case,
|
|
2807
|
+
...ctx.constructionData.well_screen
|
|
2808
|
+
];
|
|
2809
|
+
const casingD = diameterAt(pipes, intake) ?? diameterAt(ctx.constructionData.bore_hole, intake) ?? maxXValue;
|
|
2810
|
+
const narrowestD = Math.min(
|
|
2811
|
+
casingD,
|
|
2812
|
+
...[...pipes, ...ctx.constructionData.bore_hole].filter((i) => i.from < intake && i.to > 0).map((i) => i.diameter)
|
|
2813
|
+
);
|
|
2814
|
+
const { riser: riserD, body: bodyD } = getPumpDiameters(
|
|
2815
|
+
casingD,
|
|
2816
|
+
narrowestD,
|
|
2817
|
+
pump.riser_diameter,
|
|
2818
|
+
cfg
|
|
2819
|
+
);
|
|
2820
|
+
const riserLeft = (ctx.POCO_CENTER - xScale(riserD)) / 2;
|
|
2821
|
+
const riserRight = (ctx.POCO_CENTER + xScale(riserD)) / 2;
|
|
2822
|
+
const bodyLeft = (ctx.POCO_CENTER - xScale(bodyD)) / 2;
|
|
2823
|
+
const bodyRight = (ctx.POCO_CENTER + xScale(bodyD)) / 2;
|
|
2824
|
+
const yIntake = ctx.yScale(intake);
|
|
2825
|
+
const yBodyTop = yIntake - cfg.bodyHeight;
|
|
2826
|
+
const headDepth = Math.min(
|
|
2827
|
+
0,
|
|
2828
|
+
...pipes.filter((p) => p.from < 0).map((p) => p.from)
|
|
2829
|
+
);
|
|
2830
|
+
const headInPanel = ctx.depthFrom <= headDepth;
|
|
2831
|
+
const padOnHead = headDepth === 0 && !!ctx.constructionData.cement_pad?.thickness;
|
|
2832
|
+
const yRiserTop = headInPanel ? ctx.yScale(headDepth) - (padOnHead ? ctx.renderConfig.construction.cementPad.height - riserBreakAmplitude(xScale(riserD)) : 0) : ctx.yScale(ctx.depthFrom);
|
|
2833
|
+
const { riserBottom: yRiserBottom, body } = getPumpSpans(
|
|
2834
|
+
yRiserTop,
|
|
2835
|
+
ctx.yScale(ctx.depthTo),
|
|
2836
|
+
yBodyTop,
|
|
2837
|
+
yIntake
|
|
2838
|
+
);
|
|
2839
|
+
const r = Math.min(3, (bodyRight - bodyLeft) / 4);
|
|
2840
|
+
const entered = selection.enter().append("g").attr("class", cls.item).on("mouseover", ctx.tooltips.pump.show).on("mouseout", ctx.tooltips.pump.hide);
|
|
2841
|
+
entered.append("path").attr("class", `${cls.item}-riser-fill`);
|
|
2842
|
+
entered.append("path").attr("class", `${cls.item}-riser`);
|
|
2843
|
+
entered.append("path").attr("class", `${cls.item}-body`);
|
|
2844
|
+
entered.append("path").attr("class", `${cls.item}-intake`);
|
|
2845
|
+
const merged = entered.merge(selection);
|
|
2846
|
+
const top = getRiserTop(riserLeft, riserRight, yRiserTop, headInPanel);
|
|
2847
|
+
merged.select(`.${cls.item}-riser-fill`).attr(
|
|
2848
|
+
"d",
|
|
2849
|
+
yRiserBottom > yRiserTop ? `M${riserLeft},${yRiserTop}${top.edge}V${yRiserBottom}H${riserLeft}Z` : ""
|
|
2850
|
+
).attr("fill", theme.riserFill).attr("stroke", "none");
|
|
2851
|
+
merged.select(`.${cls.item}-riser`).attr(
|
|
2852
|
+
"d",
|
|
2853
|
+
yRiserBottom > yRiserTop ? `M${riserLeft},${yRiserTop}V${yRiserBottom}M${riserRight},${yRiserTop}V${yRiserBottom}${top.breakLine}` : ""
|
|
2854
|
+
).attr("stroke-linejoin", "round").attr("fill", "none").attr("stroke", theme.riserStroke).attr("stroke-width", theme.riserStrokeWidth);
|
|
2855
|
+
let bodyPath = "";
|
|
2856
|
+
if (body) {
|
|
2857
|
+
const rt = body.cutTop ? 0 : Math.min(r, (body.bottom - body.top) / 2);
|
|
2858
|
+
const rb = body.cutBottom ? 0 : Math.min(r, (body.bottom - body.top) / 2);
|
|
2859
|
+
const { top: top2, bottom } = body;
|
|
2860
|
+
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`;
|
|
2861
|
+
}
|
|
2862
|
+
merged.select(`.${cls.item}-body`).attr("d", bodyPath).attr("fill", theme.fill).attr("stroke", theme.stroke).attr("stroke-width", theme.strokeWidth);
|
|
2863
|
+
const hatchY = [
|
|
2864
|
+
yIntake - cfg.bodyHeight * 0.3,
|
|
2865
|
+
yIntake - cfg.bodyHeight * 0.15
|
|
2866
|
+
].filter((y) => body && y > body.top && y < body.bottom);
|
|
2867
|
+
merged.select(`.${cls.item}-intake`).attr(
|
|
2868
|
+
"d",
|
|
2869
|
+
hatchY.map((y) => `M${bodyLeft + 1.5},${y}H${bodyRight - 1.5}`).join("")
|
|
2870
|
+
).attr("fill", "none").attr("stroke", theme.stroke).attr("stroke-width", 0.8);
|
|
2871
|
+
}
|
|
1879
2872
|
|
|
1880
2873
|
// src/renderers/unit-labels.renderer.ts
|
|
1881
2874
|
function drawUnitLabels(ctx, data) {
|
|
1882
|
-
if (!ctx.renderConfig.unitLabels.active || !data.length) return;
|
|
1883
2875
|
const {
|
|
1884
2876
|
groups: { unitLabelsGroup },
|
|
1885
2877
|
depthFrom,
|
|
@@ -1890,6 +2882,7 @@ function drawUnitLabels(ctx, data) {
|
|
|
1890
2882
|
classes
|
|
1891
2883
|
} = ctx;
|
|
1892
2884
|
unitLabelsGroup.selectAll("*").remove();
|
|
2885
|
+
if (!renderConfig.unitLabels.active || !data.length) return;
|
|
1893
2886
|
const ru = renderConfig.unitLabels;
|
|
1894
2887
|
const rut = theme.unitLabels;
|
|
1895
2888
|
const sw = ru.stripWidth;
|
|
@@ -1970,7 +2963,7 @@ function buildSvgStyleBlock(theme) {
|
|
|
1970
2963
|
}
|
|
1971
2964
|
|
|
1972
2965
|
// src/Renderer.ts
|
|
1973
|
-
var
|
|
2966
|
+
var d310 = { ...d3module2, tip: d3tip2 };
|
|
1974
2967
|
var WellRenderer = class {
|
|
1975
2968
|
/**
|
|
1976
2969
|
* @param svgs - One entry per SVG panel; multi-entry for split-panel layouts.
|
|
@@ -2030,12 +3023,14 @@ var WellRenderer = class {
|
|
|
2030
3023
|
const { selector, height, width, margins } = inst;
|
|
2031
3024
|
const svgWidth = width + margins.left + margins.right;
|
|
2032
3025
|
const svgHeight = height + margins.top + margins.bottom;
|
|
2033
|
-
const svg =
|
|
3026
|
+
const svg = d310.select(selector);
|
|
2034
3027
|
svg.selectAll("*").remove();
|
|
2035
3028
|
svg.attr("height", svgHeight).attr("width", svgWidth);
|
|
2036
3029
|
const defs = svg.append("defs");
|
|
2037
3030
|
defs.append("style").text(buildSvgStyleBlock(this.theme));
|
|
2038
3031
|
defs.append("clipPath").attr("id", clipId).append("rect").attr("id", clipRectId).attr("x", 0).attr("y", 0).attr("width", 1e5).attr("height", 1e4);
|
|
3032
|
+
svg.append("g").attr("class", this.classes.overview.group).attr("transform", `translate(0, ${margins.top})`);
|
|
3033
|
+
svg.append("g").attr("class", this.classes.columnHeaders.group);
|
|
2039
3034
|
const poco = svg.append("g").attr("class", this.classes.wellGroup);
|
|
2040
3035
|
const geologic = poco.append("g").attr("class", this.classes.geologicGroup).attr("transform", `translate(${margins.left}, ${margins.top})`);
|
|
2041
3036
|
geologic.append("g").attr("class", this.classes.yAxis);
|
|
@@ -2050,6 +3045,7 @@ var WellRenderer = class {
|
|
|
2050
3045
|
);
|
|
2051
3046
|
const fracturesGroup = poco.append("g").attr("class", this.classes.fractures.group).attr("transform", `translate(${margins.left}, ${margins.top})`).attr("clip-path", `url(#${clipId})`);
|
|
2052
3047
|
fracturesGroup.append("g").attr("class", this.classes.highlights.fracturesGroup);
|
|
3048
|
+
poco.append("g").attr("class", this.classes.markers.group).attr("transform", `translate(${margins.left}, ${margins.top})`);
|
|
2053
3049
|
construction.append("g").attr("class", this.classes.cementPad.group);
|
|
2054
3050
|
construction.append("g").attr("class", this.classes.boreHole.group);
|
|
2055
3051
|
construction.append("g").attr("class", this.classes.surfaceCase.group);
|
|
@@ -2057,12 +3053,23 @@ var WellRenderer = class {
|
|
|
2057
3053
|
construction.append("g").attr("class", this.classes.wellCase.group);
|
|
2058
3054
|
construction.append("g").attr("class", this.classes.wellScreen.group);
|
|
2059
3055
|
construction.append("g").attr("class", this.classes.reduction.group);
|
|
3056
|
+
construction.append("g").attr("class", this.classes.pump.group);
|
|
2060
3057
|
construction.append("g").attr("class", this.classes.centralizer.group);
|
|
2061
3058
|
construction.append("g").attr("class", this.classes.conflict.group);
|
|
2062
3059
|
construction.append("g").attr("class", this.classes.constructionLabels.group);
|
|
2063
3060
|
construction.append("g").attr("class", this.classes.highlights.constructionGroup);
|
|
3061
|
+
poco.append("g").attr("class", this.classes.overlap.group).attr("transform", `translate(${margins.left}, ${margins.top})`);
|
|
2064
3062
|
Object.values(this.textures).forEach((texture) => svg.call(texture));
|
|
2065
|
-
return {
|
|
3063
|
+
return {
|
|
3064
|
+
svg,
|
|
3065
|
+
height,
|
|
3066
|
+
width,
|
|
3067
|
+
margins,
|
|
3068
|
+
clipId,
|
|
3069
|
+
clipRectId,
|
|
3070
|
+
depthRange: inst.depthRange,
|
|
3071
|
+
repeatedTo: inst.repeatedTo
|
|
3072
|
+
};
|
|
2066
3073
|
}
|
|
2067
3074
|
/** Renders a standalone legend into the element matched by `selector`. */
|
|
2068
3075
|
renderLegend(selector, profile) {
|
|
@@ -2073,6 +3080,30 @@ var WellRenderer = class {
|
|
|
2073
3080
|
textures: this.renderConfig.textures
|
|
2074
3081
|
});
|
|
2075
3082
|
}
|
|
3083
|
+
/** Lists the legend entries `profile` needs, labeled from `renderConfig.legend.labels`. */
|
|
3084
|
+
getLegendItems(profile) {
|
|
3085
|
+
return getWellLegendItems(profile, this.renderConfig.legend.labels);
|
|
3086
|
+
}
|
|
3087
|
+
/**
|
|
3088
|
+
* Renders one legend entry's symbol (see {@link getLegendItems}) into its
|
|
3089
|
+
* own SVG matched by `selector`, with the textures it needs defined inside.
|
|
3090
|
+
*/
|
|
3091
|
+
renderLegendSymbol(selector, item) {
|
|
3092
|
+
drawWellLegendSymbol(selector, item, {
|
|
3093
|
+
theme: this.theme,
|
|
3094
|
+
classNames: this.classes.legend,
|
|
3095
|
+
textures: this.renderConfig.textures
|
|
3096
|
+
});
|
|
3097
|
+
}
|
|
3098
|
+
/**
|
|
3099
|
+
* Renders one lithology layer's fill as a `size`×`size` square into its
|
|
3100
|
+
* own SVG matched by `selector`, with its texture defined inside (e.g. for
|
|
3101
|
+
* a swatch in a PDF table). Call after `prepareSvg()`, which loads the
|
|
3102
|
+
* FGDC textures.
|
|
3103
|
+
*/
|
|
3104
|
+
renderLithologySwatch(selector, layer, size = 10) {
|
|
3105
|
+
drawLithologySwatch(selector, layer, { size, theme: this.theme });
|
|
3106
|
+
}
|
|
2076
3107
|
/**
|
|
2077
3108
|
* Multiplies the current zoom scale by `factor` (e.g. `1.25` to zoom in,
|
|
2078
3109
|
* `1 / 1.25` to zoom out) on every panel. No-op if both `renderConfig.zoom`
|
|
@@ -2089,7 +3120,7 @@ var WellRenderer = class {
|
|
|
2089
3120
|
* (defaults to `1`, i.e. the initial fit-to-container view).
|
|
2090
3121
|
*/
|
|
2091
3122
|
resetZoom() {
|
|
2092
|
-
const target =
|
|
3123
|
+
const target = d310.zoomIdentity.scale(this.renderConfig.zoomLevel ?? 1);
|
|
2093
3124
|
for (const state of this.instanceStates) {
|
|
2094
3125
|
if (!state.zoomNode) continue;
|
|
2095
3126
|
asSvgElement(state.svg).transition().call(state.zoomNode.transform, target);
|
|
@@ -2101,7 +3132,46 @@ var WellRenderer = class {
|
|
|
2101
3132
|
*/
|
|
2102
3133
|
getZoomScale() {
|
|
2103
3134
|
const node = this.instanceStates[0]?.svg.node();
|
|
2104
|
-
return node ?
|
|
3135
|
+
return node ? d310.zoomTransform(node).k : 1;
|
|
3136
|
+
}
|
|
3137
|
+
/**
|
|
3138
|
+
* Removes everything drawn on every panel (layers, labels, axis,
|
|
3139
|
+
* highlights) and keeps the structure `prepareSvg()` built, so the next
|
|
3140
|
+
* `draw()` needs no new `prepareSvg()`. `draw()` calls it for an empty well.
|
|
3141
|
+
*/
|
|
3142
|
+
clear() {
|
|
3143
|
+
const c = this.classes;
|
|
3144
|
+
const layerGroups = [
|
|
3145
|
+
c.overview.group,
|
|
3146
|
+
c.columnHeaders.group,
|
|
3147
|
+
c.yAxis,
|
|
3148
|
+
c.unitLabels.group,
|
|
3149
|
+
c.lithology.group,
|
|
3150
|
+
c.caves.group,
|
|
3151
|
+
c.labels.lithology.group,
|
|
3152
|
+
c.highlights.geologicGroup,
|
|
3153
|
+
c.highlights.constructionGroup,
|
|
3154
|
+
c.highlights.fracturesGroup,
|
|
3155
|
+
c.markers.group,
|
|
3156
|
+
c.cementPad.group,
|
|
3157
|
+
c.boreHole.group,
|
|
3158
|
+
c.surfaceCase.group,
|
|
3159
|
+
c.holeFill.group,
|
|
3160
|
+
c.wellCase.group,
|
|
3161
|
+
c.wellScreen.group,
|
|
3162
|
+
c.reduction.group,
|
|
3163
|
+
c.pump.group,
|
|
3164
|
+
c.centralizer.group,
|
|
3165
|
+
c.conflict.group,
|
|
3166
|
+
c.constructionLabels.group,
|
|
3167
|
+
c.overlap.group
|
|
3168
|
+
];
|
|
3169
|
+
for (const { svg } of this.instanceStates) {
|
|
3170
|
+
for (const cls of layerGroups) {
|
|
3171
|
+
svg.select(`.${cls}`).selectAll("*").interrupt().remove();
|
|
3172
|
+
}
|
|
3173
|
+
svg.select(`.${c.fractures.group}`).selectAll(`g.${c.fractures.item}`).interrupt().remove();
|
|
3174
|
+
}
|
|
2105
3175
|
}
|
|
2106
3176
|
/**
|
|
2107
3177
|
* Initialises the SVG DOM structure and preloads FGDC textures.
|
|
@@ -2114,15 +3184,20 @@ var WellRenderer = class {
|
|
|
2114
3184
|
);
|
|
2115
3185
|
}
|
|
2116
3186
|
/**
|
|
2117
|
-
* Renders the well profile into all configured SVG panels.
|
|
3187
|
+
* Renders the well profile into all configured SVG panels. Layers the
|
|
3188
|
+
* profile no longer has are removed; an empty well (`isWellEmpty`) clears
|
|
3189
|
+
* the panels (see {@link clear}).
|
|
2118
3190
|
* @param profile - The well data to render.
|
|
2119
3191
|
* @param options.units - Override the instance-level measurement units for this render.
|
|
2120
3192
|
* @param options.locale - Override the instance-level locale for this render.
|
|
2121
3193
|
* @param options.highlights - Highlight overlays to display on top of the profile.
|
|
2122
3194
|
*/
|
|
2123
3195
|
draw(profile, options = {}) {
|
|
2124
|
-
if (isWellEmpty(profile))
|
|
2125
|
-
|
|
3196
|
+
if (isWellEmpty(profile)) {
|
|
3197
|
+
this.clear();
|
|
3198
|
+
return;
|
|
3199
|
+
}
|
|
3200
|
+
if (parseFormatVersion(profile.version)?.major !== 2) {
|
|
2126
3201
|
console.warn(
|
|
2127
3202
|
`[WellRenderer] Received a .well file with version ${profile.version ?? "unknown"}. Only v2 is supported. Normalize with deserializeWell() from @welldot/core before rendering.`
|
|
2128
3203
|
);
|
|
@@ -2133,35 +3208,18 @@ var WellRenderer = class {
|
|
|
2133
3208
|
}
|
|
2134
3209
|
const highlights = options.highlights ?? {};
|
|
2135
3210
|
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
|
-
}
|
|
3211
|
+
const maxYValues = d310.max(maxValues) || 0;
|
|
3212
|
+
const windows = resolvePanelWindows(
|
|
3213
|
+
this.instanceStates,
|
|
3214
|
+
maxYValues,
|
|
3215
|
+
getProfileTopDepth(profile)
|
|
3216
|
+
);
|
|
3217
|
+
this.instanceStates.forEach((state, i) => {
|
|
3218
|
+
const [from, to] = windows[i];
|
|
3219
|
+
this.drawLogToInstance(state, profile, from, to, maxYValues, highlights);
|
|
3220
|
+
});
|
|
2163
3221
|
}
|
|
2164
|
-
drawLogToInstance(state, profile, depthFrom, depthTo, highlights = {}) {
|
|
3222
|
+
drawLogToInstance(state, profile, depthFrom, depthTo, totalDepth, highlights = {}) {
|
|
2165
3223
|
const svg = state.svg;
|
|
2166
3224
|
const pocoGroup = svg.select(`.${this.classes.wellGroup}`);
|
|
2167
3225
|
const lithologyGroup = svg.select(`.${this.classes.lithology.group}`);
|
|
@@ -2179,6 +3237,7 @@ var WellRenderer = class {
|
|
|
2179
3237
|
const wellScreenGroup = svg.select(`.${this.classes.wellScreen.group}`);
|
|
2180
3238
|
const reductionGroup = svg.select(`.${this.classes.reduction.group}`);
|
|
2181
3239
|
const centralizerGroup = svg.select(`.${this.classes.centralizer.group}`);
|
|
3240
|
+
const pumpGroup = svg.select(`.${this.classes.pump.group}`);
|
|
2182
3241
|
const conflictGroup = svg.select(`.${this.classes.conflict.group}`);
|
|
2183
3242
|
const constructionLabelsGroup = svg.select(
|
|
2184
3243
|
`.${this.classes.constructionLabels.group}`
|
|
@@ -2193,13 +3252,19 @@ var WellRenderer = class {
|
|
|
2193
3252
|
`.${this.classes.highlights.fracturesGroup}`
|
|
2194
3253
|
);
|
|
2195
3254
|
const unitLabelsGroup = svg.select(`.${this.classes.unitLabels.group}`);
|
|
3255
|
+
const overviewGroup = svg.select(`.${this.classes.overview.group}`);
|
|
3256
|
+
const columnHeadersGroup = svg.select(
|
|
3257
|
+
`.${this.classes.columnHeaders.group}`
|
|
3258
|
+
);
|
|
3259
|
+
const markersGroup = svg.select(`.${this.classes.markers.group}`);
|
|
3260
|
+
const overlapGroup = svg.select(`.${this.classes.overlap.group}`);
|
|
2196
3261
|
const svgWidth = state.width + state.margins.left + state.margins.right;
|
|
2197
3262
|
const svgHeight = state.height + state.margins.top + state.margins.bottom;
|
|
2198
3263
|
const { pocoWidthRatio, pocoCenterRatio } = this.renderConfig.layout;
|
|
2199
3264
|
const POCO_WIDTH = svgWidth * pocoWidthRatio;
|
|
2200
3265
|
const POCO_CENTER = svgWidth * pocoCenterRatio;
|
|
2201
3266
|
const { duration, ease } = this.renderConfig.animation;
|
|
2202
|
-
const transition =
|
|
3267
|
+
const transition = d310.transition().duration(duration).ease(ease);
|
|
2203
3268
|
const tooltips = populateTooltips(
|
|
2204
3269
|
svg,
|
|
2205
3270
|
this.classes,
|
|
@@ -2228,11 +3293,11 @@ var WellRenderer = class {
|
|
|
2228
3293
|
fractures: profile.fractures
|
|
2229
3294
|
};
|
|
2230
3295
|
const contentHeight = svgHeight - state.margins.top - state.margins.bottom;
|
|
2231
|
-
const yScaleLocal =
|
|
3296
|
+
const yScaleLocal = d310.scaleLinear().domain([depthFrom, depthTo]).range([0, contentHeight]);
|
|
2232
3297
|
const depthFactor = this.units.length === "ft" ? 3.28084 : 1;
|
|
2233
|
-
const yScaleAxis =
|
|
2234
|
-
const yAxis =
|
|
2235
|
-
(d) => `${
|
|
3298
|
+
const yScaleAxis = d310.scaleLinear().domain([depthFrom * depthFactor, depthTo * depthFactor]).range([0, contentHeight]);
|
|
3299
|
+
const yAxis = d310.axisLeft(yScaleAxis).tickFormat(
|
|
3300
|
+
(d) => `${formatNumber4(Number(d), {
|
|
2236
3301
|
maximumFractionDigits: this.units.length === "ft" ? 1 : 2,
|
|
2237
3302
|
locale: this.locale
|
|
2238
3303
|
})}${getLengthUnit(this.units.length)}`
|
|
@@ -2274,10 +3339,15 @@ var WellRenderer = class {
|
|
|
2274
3339
|
wellScreenGroup,
|
|
2275
3340
|
reductionGroup,
|
|
2276
3341
|
centralizerGroup,
|
|
3342
|
+
pumpGroup,
|
|
2277
3343
|
conflictGroup,
|
|
2278
3344
|
highlightsGeologicGroup,
|
|
2279
3345
|
highlightsConstructionGroup,
|
|
2280
|
-
highlightsFracturesGroup
|
|
3346
|
+
highlightsFracturesGroup,
|
|
3347
|
+
overviewGroup,
|
|
3348
|
+
columnHeadersGroup,
|
|
3349
|
+
markersGroup,
|
|
3350
|
+
overlapGroup
|
|
2281
3351
|
};
|
|
2282
3352
|
const ctx = {
|
|
2283
3353
|
svg,
|
|
@@ -2291,6 +3361,8 @@ var WellRenderer = class {
|
|
|
2291
3361
|
geoXRight,
|
|
2292
3362
|
depthFrom,
|
|
2293
3363
|
depthTo,
|
|
3364
|
+
totalDepth,
|
|
3365
|
+
repeatedTo: state.repeatedTo,
|
|
2294
3366
|
yScale: yScaleLocal,
|
|
2295
3367
|
transition,
|
|
2296
3368
|
tooltips,
|
|
@@ -2304,6 +3376,7 @@ var WellRenderer = class {
|
|
|
2304
3376
|
groups
|
|
2305
3377
|
};
|
|
2306
3378
|
const inDepth = filterByDepth(depthFrom, depthTo);
|
|
3379
|
+
const currentPump = getCurrentPump2(profile);
|
|
2307
3380
|
const filteredConstruction = {
|
|
2308
3381
|
...constructionData,
|
|
2309
3382
|
bore_hole: constructionData.bore_hole.filter(inDepth),
|
|
@@ -2328,33 +3401,14 @@ var WellRenderer = class {
|
|
|
2328
3401
|
if (!d) return null;
|
|
2329
3402
|
return transform.k * spanH(d);
|
|
2330
3403
|
});
|
|
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
|
-
});
|
|
3404
|
+
layoutConstruction(zoomedCtx);
|
|
3405
|
+
drawCementPad(zoomedCtx, constructionData.cement_pad);
|
|
2352
3406
|
fracturesGroup.selectAll(`g.${this.classes.fractures.item}`).attr("transform", (d) => {
|
|
2353
3407
|
if (!d) return null;
|
|
2354
3408
|
const f = d;
|
|
2355
3409
|
const cx = pocoCenterX;
|
|
2356
3410
|
const cy = transform.applyY(yScaleLocal(f.depth));
|
|
2357
|
-
return `translate(0,${cy}) rotate(${f.dip},${cx},0)`;
|
|
3411
|
+
return `translate(0,${cy}) rotate(${fractureDip(f.dip)},${cx},0)`;
|
|
2358
3412
|
});
|
|
2359
3413
|
drawCaves(zoomedCtx, geologicData.caves?.filter(inDepth) ?? []);
|
|
2360
3414
|
drawUnitLabels(zoomedCtx, profile.lithology?.filter(inDepth) ?? []);
|
|
@@ -2365,11 +3419,17 @@ var WellRenderer = class {
|
|
|
2365
3419
|
) ?? [],
|
|
2366
3420
|
caves: profile.caves?.filter(inDepth) ?? []
|
|
2367
3421
|
});
|
|
3422
|
+
drawPump(zoomedCtx, currentPump);
|
|
2368
3423
|
drawCentralizers(zoomedCtx, filteredConstruction);
|
|
2369
3424
|
drawConstructionLabels(zoomedCtx, {
|
|
2370
3425
|
well_case: constructionData.well_case.filter(inDepth),
|
|
2371
3426
|
well_screen: constructionData.well_screen.filter(inDepth)
|
|
2372
3427
|
});
|
|
3428
|
+
drawMarkers(zoomedCtx, {
|
|
3429
|
+
lithology: profile.lithology ?? [],
|
|
3430
|
+
fractures: profile.fractures ?? []
|
|
3431
|
+
});
|
|
3432
|
+
drawOverlap(zoomedCtx);
|
|
2373
3433
|
drawHighlights(zoomedCtx, highlights);
|
|
2374
3434
|
this.onZoom?.(transform.k);
|
|
2375
3435
|
};
|
|
@@ -2392,11 +3452,19 @@ var WellRenderer = class {
|
|
|
2392
3452
|
) ?? []
|
|
2393
3453
|
);
|
|
2394
3454
|
drawConstructive(ctx, filteredConstruction);
|
|
3455
|
+
drawPump(ctx, currentPump);
|
|
2395
3456
|
drawCentralizers(ctx, filteredConstruction);
|
|
2396
3457
|
drawConstructionLabels(ctx, {
|
|
2397
3458
|
well_case: filteredConstruction.well_case,
|
|
2398
3459
|
well_screen: filteredConstruction.well_screen
|
|
2399
3460
|
});
|
|
3461
|
+
drawMarkers(ctx, {
|
|
3462
|
+
lithology: profile.lithology ?? [],
|
|
3463
|
+
fractures: profile.fractures ?? []
|
|
3464
|
+
});
|
|
3465
|
+
drawOverview(ctx, profile.lithology ?? []);
|
|
3466
|
+
drawColumnHeaders(ctx);
|
|
3467
|
+
drawOverlap(ctx);
|
|
2400
3468
|
svg.select(`#${state.clipRectId}`).attr("y", 0).attr("height", svgHeight);
|
|
2401
3469
|
drawHighlights(ctx, highlights);
|
|
2402
3470
|
};
|
|
@@ -2412,7 +3480,7 @@ var WellRenderer = class {
|
|
|
2412
3480
|
}
|
|
2413
3481
|
const { zoom: zoomEnabled, pan: panEnabled } = this.renderConfig;
|
|
2414
3482
|
if (zoomEnabled || panEnabled) {
|
|
2415
|
-
const zoomNode =
|
|
3483
|
+
const zoomNode = d310.zoom();
|
|
2416
3484
|
if (zoomEnabled || panEnabled) zoomNode.on("zoom", zooming);
|
|
2417
3485
|
zoomNode.scaleExtent(
|
|
2418
3486
|
zoomEnabled ? [
|
|
@@ -2428,7 +3496,7 @@ var WellRenderer = class {
|
|
|
2428
3496
|
if (initialZoom !== 1) {
|
|
2429
3497
|
asSvgElement(svg).call(
|
|
2430
3498
|
zoomNode.transform,
|
|
2431
|
-
|
|
3499
|
+
d310.zoomIdentity.scale(initialZoom)
|
|
2432
3500
|
);
|
|
2433
3501
|
}
|
|
2434
3502
|
}
|
|
@@ -2442,10 +3510,13 @@ export {
|
|
|
2442
3510
|
WellRenderer,
|
|
2443
3511
|
applyRenderLocale,
|
|
2444
3512
|
drawWellLegend,
|
|
3513
|
+
drawWellLegendSymbol,
|
|
2445
3514
|
formatDiameter,
|
|
2446
3515
|
formatLength,
|
|
2447
3516
|
getDiameterUnit,
|
|
2448
3517
|
getLengthUnit,
|
|
3518
|
+
getProfileTopDepth,
|
|
3519
|
+
getWellLegendItems,
|
|
2449
3520
|
importFgdcTextures,
|
|
2450
3521
|
resolveRenderLabel
|
|
2451
3522
|
};
|