@welldot/render 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -35,7 +35,7 @@ Call `prepareSvg()` once after mounting the SVG element, then call `draw(profile
35
35
  ## What it renders
36
36
 
37
37
  - **Lithology column** — geological layers with FGDC standard texture patterns and custom fill colors
38
- - **Construction** — borehole, well casings, diameter reductions, well screens, hole fills (gravel pack / cement seal), and cement pad
38
+ - **Construction** — borehole, well casings, diameter reductions, well screens, hole fills (gravel pack / cement seal), centralizers (`.well` v2.1 — bow markers in the annulus at each derived position; size via `renderConfig.construction.centralizer.markerHalfHeight`, colors via `theme.centralizer`, tooltip key `centralizer`), and cement pad
39
39
  - **Fractures** — individual and swarm fractures with dip angles and water-intake indicators
40
40
  - **Caves** — cavity zones with wavy geological contact lines
41
41
  - **Labels** — depth annotations, lithology descriptions, and geologic / aquifer unit strips
package/dist/index.cjs CHANGED
@@ -386,6 +386,7 @@ var RENDER_LABELS = {
386
386
  wellCase: { pt: "Revestimento", en: "Casing" },
387
387
  wellScreen: { pt: "Filtro", en: "Screen" },
388
388
  reduction: { pt: "Redu\xE7\xE3o", en: "Reduction" },
389
+ centralizer: { pt: "Centralizador", en: "Centralizer" },
389
390
  cementPad: { pt: "Laje de cimento", en: "Cement pad" },
390
391
  conflict: { pt: "Conflito", en: "Conflict" }
391
392
  }
@@ -412,6 +413,11 @@ var RENDER_LABELS = {
412
413
  slot: { pt: "Ranhura:", en: "Slot:" }
413
414
  },
414
415
  reduction: { title: { pt: "REDU\xC7\xC3O", en: "REDUCTION" } },
416
+ centralizer: {
417
+ title: { pt: "CENTRALIZADOR", en: "CENTRALIZER" },
418
+ depth: { pt: "Profundidade:", en: "Depth:" },
419
+ spacing: { pt: "Espa\xE7amento:", en: "Spacing:" }
420
+ },
415
421
  conflict: { title: { pt: "CONFLITO", en: "CONFLICT" } },
416
422
  fracture: {
417
423
  title: { pt: "FRATURA", en: "FRACTURE" },
@@ -457,6 +463,7 @@ function resolveTooltipLabels(locale) {
457
463
  wellCase: resolveGroup(t.wellCase, locale),
458
464
  wellScreen: resolveGroup(t.wellScreen, locale),
459
465
  reduction: resolveGroup(t.reduction, locale),
466
+ centralizer: resolveGroup(t.centralizer, locale),
460
467
  conflict: resolveGroup(t.conflict, locale),
461
468
  fracture: resolveGroup(t.fracture, locale),
462
469
  cementPad: resolveGroup(t.cementPad, locale),
@@ -517,6 +524,7 @@ var DEFAULT_WELL_THEME = {
517
524
  wellCase: { fill: "#ffffff", stroke: "#303030", strokeWidth: 2 },
518
525
  wellScreen: { stroke: "#303030", strokeWidth: 2 },
519
526
  reduction: { fill: "#ffffff", stroke: "#303030", strokeWidth: 2 },
527
+ centralizer: { fill: "none", stroke: "#303030", strokeWidth: 1.4 },
520
528
  conflict: { stroke: "#e52117", strokeWidth: 4 },
521
529
  unitLabels: {
522
530
  geologicFill: "#f0f0f0",
@@ -610,7 +618,8 @@ var STATIC_RENDER_CONFIG = {
610
618
  },
611
619
  construction: {
612
620
  cementPad: { widthMultiplier: 0.9, thicknessMultiplier: 1.3 },
613
- surfaceCase: { diameterPaddingRatio: 0.1 }
621
+ surfaceCase: { diameterPaddingRatio: 0.1 },
622
+ centralizer: { markerHalfHeight: 4 }
614
623
  },
615
624
  tooltipLabels: resolveTooltipLabels("pt"),
616
625
  labels: {
@@ -681,6 +690,7 @@ var STATIC_RENDER_CONFIG = {
681
690
  wellCase: "Revestimento",
682
691
  wellScreen: "Filtro",
683
692
  reduction: "Redu\xE7\xE3o",
693
+ centralizer: "Centralizador",
684
694
  cementPad: "Laje de cimento",
685
695
  conflict: "Conflito"
686
696
  }
@@ -721,7 +731,8 @@ var INTERACTIVE_RENDER_CONFIG = {
721
731
  },
722
732
  construction: {
723
733
  cementPad: { widthMultiplier: 0.9, thicknessMultiplier: 1.3 },
724
- surfaceCase: { diameterPaddingRatio: 0.1 }
734
+ surfaceCase: { diameterPaddingRatio: 0.1 },
735
+ centralizer: { markerHalfHeight: 4 }
725
736
  },
726
737
  tooltipLabels: resolveTooltipLabels("pt"),
727
738
  labels: {
@@ -789,6 +800,7 @@ var INTERACTIVE_RENDER_CONFIG = {
789
800
  wellCase: "Revestimento",
790
801
  wellScreen: "Filtro",
791
802
  reduction: "Redu\xE7\xE3o",
803
+ centralizer: "Centralizador",
792
804
  cementPad: "Laje de cimento",
793
805
  conflict: "Conflito"
794
806
  }
@@ -869,7 +881,7 @@ function createWellTextures(cfg) {
869
881
 
870
882
  // src/Renderer.ts
871
883
  var import_core = require("@welldot/core");
872
- var import_utils6 = require("@welldot/utils");
884
+ var import_utils7 = require("@welldot/utils");
873
885
 
874
886
  // src/configs/render.classnames.ts
875
887
  var DEFAULT_COMPONENTS_CLASS_NAMES = {
@@ -927,6 +939,10 @@ var DEFAULT_COMPONENTS_CLASS_NAMES = {
927
939
  group: "well-screen",
928
940
  rect: "well-screen-rect"
929
941
  },
942
+ centralizer: {
943
+ group: "centralizer",
944
+ item: "centralizer-marker"
945
+ },
930
946
  reduction: {
931
947
  group: "reduction",
932
948
  item: "reduction-poly"
@@ -1104,6 +1120,15 @@ var populateTooltips = (svg, customClasses, units, tooltipConfig, labels, locale
1104
1120
  </span>
1105
1121
  <span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(d.type)}</span>
1106
1122
  `,
1123
+ centralizer: (_, d) => `
1124
+ <span class="${customClasses.tooltip.title}">${labels.centralizer.title}</span>
1125
+ <span class="${customClasses.tooltip.primaryInfo}"><strong>${labels.centralizer.depth}</strong> ${esc(formatLength(d.depth, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>
1126
+ ${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>` : ""}
1127
+ ${d.spacing ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.centralizer.spacing}</strong> ${esc(formatLength(d.spacing, units.length, locale))} ${esc(getLengthUnit(units.length))}</span>` : ""}
1128
+ <span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.type}</strong> ${esc(d.type)}</span>
1129
+ ${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>` : ""}
1130
+ ${d.description ? `<span class="${customClasses.tooltip.secondaryInfo}"><strong>${labels.common.description}</strong> ${esc(d.description)}</span>` : ""}
1131
+ `,
1107
1132
  conflict: (_, d) => `
1108
1133
  <span class="${customClasses.tooltip.title}">${labels.conflict.title}</span>
1109
1134
  <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>
@@ -1417,9 +1442,51 @@ function drawCaves(ctx, data) {
1417
1442
  merged.transition(ctx.transition).style("opacity", 1);
1418
1443
  }
1419
1444
 
1420
- // src/renderers/construction-labels.renderer.ts
1445
+ // src/renderers/centralizers.renderer.ts
1421
1446
  var d32 = __toESM(require("d3"), 1);
1422
1447
  var import_utils3 = require("@welldot/utils");
1448
+ function diameterAt(items, depth) {
1449
+ return items.find((i) => depth >= i.from && depth <= i.to)?.diameter;
1450
+ }
1451
+ function drawCentralizers(ctx, data) {
1452
+ const group = ctx.groups.centralizerGroup;
1453
+ const cls = ctx.classes.centralizer;
1454
+ const maxXValue = d32.max((0, import_utils3.getProfileDiamValues)(ctx.constructionData)) || 0;
1455
+ const xScale = d32.scaleLinear().domain([0, maxXValue]).range([0, ctx.POCO_WIDTH]);
1456
+ const pipes = [
1457
+ ...ctx.constructionData.well_case,
1458
+ ...ctx.constructionData.well_screen
1459
+ ];
1460
+ const holes = ctx.constructionData.bore_hole;
1461
+ const markers = (data.centralizers ?? []).flatMap(
1462
+ (c) => (0, import_utils3.getCentralizerDepths)(c).filter((depth) => depth >= ctx.depthFrom && depth < ctx.depthTo).map((depth) => ({ ...c, depth }))
1463
+ );
1464
+ const halfH = ctx.renderConfig.construction.centralizer.markerHalfHeight;
1465
+ const bowPoints = (m, side) => {
1466
+ const outerD = m.diameter ?? diameterAt(holes, m.depth) ?? maxXValue;
1467
+ const pipeD = diameterAt(pipes, m.depth) ?? outerD * 0.75;
1468
+ const pipeX = (ctx.POCO_CENTER + side * xScale(pipeD)) / 2;
1469
+ const outerX = (ctx.POCO_CENTER + side * xScale(outerD)) / 2;
1470
+ const y = ctx.yScale(m.depth);
1471
+ return `${pipeX},${y - halfH} ${outerX},${y} ${pipeX},${y + halfH}`;
1472
+ };
1473
+ const selection = group.selectAll(`g.${cls.item}`).data(markers, (d) => `${d.from}:${d.to}:${d.depth}`);
1474
+ selection.exit().remove();
1475
+ const entered = selection.enter().append("g").attr("class", cls.item).on("mouseover", ctx.tooltips.centralizer.show).on("mouseout", ctx.tooltips.centralizer.hide);
1476
+ entered.append("polyline").attr("class", `${cls.item}-left`);
1477
+ entered.append("polyline").attr("class", `${cls.item}-right`);
1478
+ const merged = entered.merge(selection);
1479
+ merged.selectAll("polyline").attr("fill", ctx.theme.centralizer.fill).attr("stroke", ctx.theme.centralizer.stroke).attr("stroke-width", ctx.theme.centralizer.strokeWidth).attr("stroke-linejoin", "round");
1480
+ merged.each((d, i, nodes) => {
1481
+ const g = d32.select(nodes[i]);
1482
+ g.select(`.${cls.item}-left`).attr("points", bowPoints(d, -1));
1483
+ g.select(`.${cls.item}-right`).attr("points", bowPoints(d, 1));
1484
+ });
1485
+ }
1486
+
1487
+ // src/renderers/construction-labels.renderer.ts
1488
+ var d33 = __toESM(require("d3"), 1);
1489
+ var import_utils4 = require("@welldot/utils");
1423
1490
  function drawConstructionLabels(ctx, data) {
1424
1491
  if (!ctx.renderConfig.constructionLabels.active) return;
1425
1492
  ctx.groups.constructionLabelsGroup.selectAll("*").remove();
@@ -1427,8 +1494,8 @@ function drawConstructionLabels(ctx, data) {
1427
1494
  const clct = ctx.theme.constructionLabels;
1428
1495
  const fmtD = (mm) => formatDiameter(mm, ctx.units.diameter, ctx.locale);
1429
1496
  const dUnit = getDiameterUnit(ctx.units.diameter, ctx.locale);
1430
- const maxXValues = (0, import_utils3.getProfileDiamValues)(ctx.constructionData);
1431
- const xScale = d32.scaleLinear().domain([0, d32.max(maxXValues) || 0]).range([0, ctx.POCO_WIDTH]);
1497
+ const maxXValues = (0, import_utils4.getProfileDiamValues)(ctx.constructionData);
1498
+ const xScale = d33.scaleLinear().domain([0, d33.max(maxXValues) || 0]).range([0, ctx.POCO_WIDTH]);
1432
1499
  const occupied = [];
1433
1500
  const placeLabel = (d, text) => {
1434
1501
  const clampedFrom = Math.max(d.from, ctx.depthFrom);
@@ -1494,16 +1561,16 @@ function drawConstructionLabels(ctx, data) {
1494
1561
  }
1495
1562
 
1496
1563
  // src/renderers/construction.renderer.ts
1497
- var d33 = __toESM(require("d3"), 1);
1498
- var import_utils4 = require("@welldot/utils");
1564
+ var d34 = __toESM(require("d3"), 1);
1565
+ var import_utils5 = require("@welldot/utils");
1499
1566
  function drawConstructive(ctx, data) {
1500
1567
  const { getHeight, getYPos } = getYAxisFunctions(ctx.yScale, {
1501
1568
  from: ctx.depthFrom,
1502
1569
  to: ctx.depthTo
1503
1570
  });
1504
- const maxXValues = (0, import_utils4.getProfileDiamValues)(ctx.constructionData);
1505
- const maxXValueConstruction = d33.max(maxXValues) || 0;
1506
- const xScale = d33.scaleLinear().domain([0, maxXValueConstruction]).range([0, ctx.POCO_WIDTH]);
1571
+ const maxXValues = (0, import_utils5.getProfileDiamValues)(ctx.constructionData);
1572
+ const maxXValueConstruction = d34.max(maxXValues) || 0;
1573
+ const xScale = d34.scaleLinear().domain([0, maxXValueConstruction]).range([0, ctx.POCO_WIDTH]);
1507
1574
  const rcc = ctx.renderConfig.construction;
1508
1575
  const yPos = getYPos;
1509
1576
  ctx.groups.constructionGroup.selectAll(`.${ctx.classes.cementPad.item}`).remove();
@@ -1542,11 +1609,11 @@ function drawConstructive(ctx, data) {
1542
1609
  const w = xScale(
1543
1610
  d.diameter + d.diameter * rcc.surfaceCase.diameterPaddingRatio
1544
1611
  );
1545
- const g = d33.select(nodes[i]);
1612
+ const g = d34.select(nodes[i]);
1546
1613
  g.select(".surface-case-fill").attr("x", x).attr("width", w).attr("fill", ctx.textures.surface_case.url());
1547
1614
  const sideNodes = g.selectAll(".surface-case-side").nodes();
1548
- d33.select(sideNodes[0]).attr("x1", x).attr("x2", x);
1549
- d33.select(sideNodes[1]).attr("x1", x + w).attr("x2", x + w);
1615
+ d34.select(sideNodes[0]).attr("x1", x).attr("x2", x);
1616
+ d34.select(sideNodes[1]).attr("x1", x + w).attr("x2", x + w);
1550
1617
  });
1551
1618
  withTransition(
1552
1619
  mergedSC.select(".surface-case-fill"),
@@ -1603,7 +1670,7 @@ function drawConstructive(ctx, data) {
1603
1670
  }
1604
1671
 
1605
1672
  // src/renderers/fractures.renderer.ts
1606
- var d34 = __toESM(require("d3"), 1);
1673
+ var d35 = __toESM(require("d3"), 1);
1607
1674
  function wavyLine(rng, steps, baseY, jitter, startInset, endInset) {
1608
1675
  const pts = [];
1609
1676
  for (let i = 0; i < steps; i++) {
@@ -1640,7 +1707,7 @@ function drawFractures(ctx, data) {
1640
1707
  (fracture) => `translate(0,${yScale(fracture.depth)}) rotate(${fracture.dip},${pocoCenterX},0)`
1641
1708
  );
1642
1709
  merged.each(function(fracture) {
1643
- const g = d34.select(this);
1710
+ const g = d35.select(this);
1644
1711
  g.selectAll("*").remove();
1645
1712
  const rng = makeSeededPrng(fracture.depth, 7919);
1646
1713
  const hitBuffer = fracture.swarm ? rf.hitBuffer.swarm : rf.hitBuffer.single;
@@ -1719,8 +1786,8 @@ function drawFractures(ctx, data) {
1719
1786
  }
1720
1787
 
1721
1788
  // src/renderers/highlights.renderer.ts
1722
- var d35 = __toESM(require("d3"), 1);
1723
- var import_utils5 = require("@welldot/utils");
1789
+ var d36 = __toESM(require("d3"), 1);
1790
+ var import_utils6 = require("@welldot/utils");
1724
1791
  function drawHighlightItem(ctx, group, x, y, w, h, label) {
1725
1792
  if (h <= 0 || w <= 0) return;
1726
1793
  const hlConfig = ctx.renderConfig.highlights;
@@ -1779,8 +1846,8 @@ function drawHighlights(ctx, hl) {
1779
1846
  h.label
1780
1847
  );
1781
1848
  });
1782
- const maxXVals = (0, import_utils5.getProfileDiamValues)(ctx.constructionData);
1783
- const xScaleConstr = d35.scaleLinear().domain([0, d35.max(maxXVals) || 0]).range([0, ctx.POCO_WIDTH]);
1849
+ const maxXVals = (0, import_utils6.getProfileDiamValues)(ctx.constructionData);
1850
+ const xScaleConstr = d36.scaleLinear().domain([0, d36.max(maxXVals) || 0]).range([0, ctx.POCO_WIDTH]);
1784
1851
  const constructionConfig = ctx.renderConfig.construction;
1785
1852
  if (hl.cement_pad && ctx.depthFrom === 0 && ctx.constructionData.cement_pad?.thickness) {
1786
1853
  const cp = ctx.constructionData.cement_pad;
@@ -1875,7 +1942,7 @@ function drawHighlights(ctx, hl) {
1875
1942
  // src/renderers/legend.renderer.ts
1876
1943
  var d3module = __toESM(require("d3"), 1);
1877
1944
  var import_defu = require("defu");
1878
- var d36 = { ...d3module };
1945
+ var d37 = { ...d3module };
1879
1946
  function drawWellLegend(selector, profile, options = {}) {
1880
1947
  const fractures = profile.fractures ?? [];
1881
1948
  const caves = profile.caves ?? [];
@@ -1896,6 +1963,7 @@ function drawWellLegend(selector, profile, options = {}) {
1896
1963
  const hasWellCase = wellCases.length > 0;
1897
1964
  const hasWellScreen = wellScreens.length > 0;
1898
1965
  const hasReduction = reductions.length > 0;
1966
+ const hasCentralizer = (profile.centralizers ?? []).length > 0;
1899
1967
  const hasCementPad = !!profile.cement_pad?.thickness;
1900
1968
  const hasConflict = mergeConflicts(
1901
1969
  [
@@ -1988,13 +2056,19 @@ function drawWellLegend(selector, profile, options = {}) {
1988
2056
  label: cfg.labels.reduction,
1989
2057
  subKind: "reduction"
1990
2058
  });
2059
+ if (hasCentralizer)
2060
+ items.push({
2061
+ kind: "construction",
2062
+ label: cfg.labels.centralizer,
2063
+ subKind: "centralizer"
2064
+ });
1991
2065
  if (hasConflict)
1992
2066
  items.push({
1993
2067
  kind: "construction",
1994
2068
  label: cfg.labels.conflict,
1995
2069
  subKind: "conflict"
1996
2070
  });
1997
- const svgEl = d36.select(selector);
2071
+ const svgEl = d37.select(selector);
1998
2072
  svgEl.selectAll("*").remove();
1999
2073
  if (items.length === 0) {
2000
2074
  svgEl.attr("width", 0).attr("height", 0);
@@ -2046,6 +2120,25 @@ function drawWellLegend(selector, profile, options = {}) {
2046
2120
  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");
2047
2121
  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);
2048
2122
  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);
2123
+ } else if (item.subKind === "centralizer") {
2124
+ const pipeW = rw * 0.4;
2125
+ const pipeL = cx + (rw - pipeW) / 2;
2126
+ const pipeR = pipeL + pipeW;
2127
+ const y1 = rowSymY - rh / 2;
2128
+ const y2 = rowSymY + rh / 2;
2129
+ const bowH = rh * 0.3;
2130
+ for (const x of [pipeL, pipeR]) {
2131
+ 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);
2132
+ }
2133
+ for (const [from, to] of [
2134
+ [pipeL, cx],
2135
+ [pipeR, cx + rw]
2136
+ ]) {
2137
+ symG.append("polyline").attr("class", cls.constructionRect).attr(
2138
+ "points",
2139
+ `${from},${rowSymY - bowH} ${to},${rowSymY} ${from},${rowSymY + bowH}`
2140
+ ).attr("fill", theme.centralizer.fill).attr("stroke", theme.centralizer.stroke).attr("stroke-width", theme.centralizer.strokeWidth);
2141
+ }
2049
2142
  } else if (item.subKind === "reduction") {
2050
2143
  const topW = rw * 0.5;
2051
2144
  const y1 = rowSymY - rh / 2;
@@ -2212,7 +2305,7 @@ function buildSvgStyleBlock(theme) {
2212
2305
  }
2213
2306
 
2214
2307
  // src/Renderer.ts
2215
- var d37 = { ...d3module2, tip: import_d3_tip2.default };
2308
+ var d38 = { ...d3module2, tip: import_d3_tip2.default };
2216
2309
  var WellRenderer = class {
2217
2310
  /**
2218
2311
  * @param svgs - One entry per SVG panel; multi-entry for split-panel layouts.
@@ -2272,7 +2365,7 @@ var WellRenderer = class {
2272
2365
  const { selector, height, width, margins } = inst;
2273
2366
  const svgWidth = width + margins.left + margins.right;
2274
2367
  const svgHeight = height + margins.top + margins.bottom;
2275
- const svg = d37.select(selector);
2368
+ const svg = d38.select(selector);
2276
2369
  svg.selectAll("*").remove();
2277
2370
  svg.attr("height", svgHeight).attr("width", svgWidth);
2278
2371
  const defs = svg.append("defs");
@@ -2299,6 +2392,7 @@ var WellRenderer = class {
2299
2392
  construction.append("g").attr("class", this.classes.wellCase.group);
2300
2393
  construction.append("g").attr("class", this.classes.wellScreen.group);
2301
2394
  construction.append("g").attr("class", this.classes.reduction.group);
2395
+ construction.append("g").attr("class", this.classes.centralizer.group);
2302
2396
  construction.append("g").attr("class", this.classes.conflict.group);
2303
2397
  construction.append("g").attr("class", this.classes.constructionLabels.group);
2304
2398
  construction.append("g").attr("class", this.classes.highlights.constructionGroup);
@@ -2330,7 +2424,7 @@ var WellRenderer = class {
2330
2424
  * (defaults to `1`, i.e. the initial fit-to-container view).
2331
2425
  */
2332
2426
  resetZoom() {
2333
- const target = d37.zoomIdentity.scale(this.renderConfig.zoomLevel ?? 1);
2427
+ const target = d38.zoomIdentity.scale(this.renderConfig.zoomLevel ?? 1);
2334
2428
  for (const state of this.instanceStates) {
2335
2429
  if (!state.zoomNode) continue;
2336
2430
  asSvgElement(state.svg).transition().call(state.zoomNode.transform, target);
@@ -2342,7 +2436,7 @@ var WellRenderer = class {
2342
2436
  */
2343
2437
  getZoomScale() {
2344
2438
  const node = this.instanceStates[0]?.svg.node();
2345
- return node ? d37.zoomTransform(node).k : 1;
2439
+ return node ? d38.zoomTransform(node).k : 1;
2346
2440
  }
2347
2441
  /**
2348
2442
  * Initialises the SVG DOM structure and preloads FGDC textures.
@@ -2373,8 +2467,8 @@ var WellRenderer = class {
2373
2467
  this.locale = options.locale;
2374
2468
  }
2375
2469
  const highlights = options.highlights ?? {};
2376
- const maxValues = (0, import_utils6.getProfileLastItemsDepths)(profile);
2377
- const maxYValues = d37.max(maxValues) || 0;
2470
+ const maxValues = (0, import_utils7.getProfileLastItemsDepths)(profile);
2471
+ const maxYValues = d38.max(maxValues) || 0;
2378
2472
  if (this.instanceStates.length === 1) {
2379
2473
  this.drawLogToInstance(
2380
2474
  this.instanceStates[0],
@@ -2386,7 +2480,7 @@ var WellRenderer = class {
2386
2480
  return;
2387
2481
  }
2388
2482
  const totalHeight = this.instanceStates.reduce((s, st) => s + st.height, 0) || 1;
2389
- const yScaleGlobal = d37.scaleLinear().domain([0, maxYValues]).range([0, totalHeight]);
2483
+ const yScaleGlobal = d38.scaleLinear().domain([0, maxYValues]).range([0, totalHeight]);
2390
2484
  let currentDepth = 0;
2391
2485
  for (const state of this.instanceStates) {
2392
2486
  const maxSvgDepth = yScaleGlobal.invert(
@@ -2419,6 +2513,7 @@ var WellRenderer = class {
2419
2513
  const wellCaseGroup = svg.select(`.${this.classes.wellCase.group}`);
2420
2514
  const wellScreenGroup = svg.select(`.${this.classes.wellScreen.group}`);
2421
2515
  const reductionGroup = svg.select(`.${this.classes.reduction.group}`);
2516
+ const centralizerGroup = svg.select(`.${this.classes.centralizer.group}`);
2422
2517
  const conflictGroup = svg.select(`.${this.classes.conflict.group}`);
2423
2518
  const constructionLabelsGroup = svg.select(
2424
2519
  `.${this.classes.constructionLabels.group}`
@@ -2439,7 +2534,7 @@ var WellRenderer = class {
2439
2534
  const POCO_WIDTH = svgWidth * pocoWidthRatio;
2440
2535
  const POCO_CENTER = svgWidth * pocoCenterRatio;
2441
2536
  const { duration, ease } = this.renderConfig.animation;
2442
- const transition = d37.transition().duration(duration).ease(ease);
2537
+ const transition = d38.transition().duration(duration).ease(ease);
2443
2538
  const tooltips = populateTooltips(
2444
2539
  svg,
2445
2540
  this.classes,
@@ -2464,14 +2559,15 @@ var WellRenderer = class {
2464
2559
  well_case: profile.well_case,
2465
2560
  well_screen: profile.well_screen,
2466
2561
  reduction: profile.reduction,
2562
+ centralizers: profile.centralizers ?? [],
2467
2563
  fractures: profile.fractures
2468
2564
  };
2469
2565
  const contentHeight = svgHeight - state.margins.top - state.margins.bottom;
2470
- const yScaleLocal = d37.scaleLinear().domain([depthFrom, depthTo]).range([0, contentHeight]);
2566
+ const yScaleLocal = d38.scaleLinear().domain([depthFrom, depthTo]).range([0, contentHeight]);
2471
2567
  const depthFactor = this.units.length === "ft" ? 3.28084 : 1;
2472
- const yScaleAxis = d37.scaleLinear().domain([depthFrom * depthFactor, depthTo * depthFactor]).range([0, contentHeight]);
2473
- const yAxis = d37.axisLeft(yScaleAxis).tickFormat(
2474
- (d) => `${(0, import_utils6.formatNumber)(Number(d), {
2568
+ const yScaleAxis = d38.scaleLinear().domain([depthFrom * depthFactor, depthTo * depthFactor]).range([0, contentHeight]);
2569
+ const yAxis = d38.axisLeft(yScaleAxis).tickFormat(
2570
+ (d) => `${(0, import_utils7.formatNumber)(Number(d), {
2475
2571
  maximumFractionDigits: this.units.length === "ft" ? 1 : 2,
2476
2572
  locale: this.locale
2477
2573
  })}${getLengthUnit(this.units.length)}`
@@ -2512,6 +2608,7 @@ var WellRenderer = class {
2512
2608
  wellCaseGroup,
2513
2609
  wellScreenGroup,
2514
2610
  reductionGroup,
2611
+ centralizerGroup,
2515
2612
  conflictGroup,
2516
2613
  highlightsGeologicGroup,
2517
2614
  highlightsConstructionGroup,
@@ -2549,7 +2646,8 @@ var WellRenderer = class {
2549
2646
  surface_case: constructionData.surface_case.filter(inDepth),
2550
2647
  well_case: constructionData.well_case.filter(inDepth),
2551
2648
  well_screen: constructionData.well_screen.filter(inDepth),
2552
- reduction: constructionData.reduction?.filter(inDepth) ?? []
2649
+ reduction: constructionData.reduction?.filter(inDepth) ?? [],
2650
+ centralizers: constructionData.centralizers?.filter(inDepth) ?? []
2553
2651
  };
2554
2652
  const zooming = (e) => {
2555
2653
  const transform = e.transform;
@@ -2568,14 +2666,14 @@ var WellRenderer = class {
2568
2666
  surfaceCaseGroup.selectAll(`g.${this.classes.surfaceCase.rect}`).each((d, i, nodes) => {
2569
2667
  if (!d) return;
2570
2668
  const sc = d;
2571
- const g = d37.select(nodes[i]);
2669
+ const g = d38.select(nodes[i]);
2572
2670
  const y = transform.applyY(spanY(sc));
2573
2671
  const h = transform.k * spanH(sc);
2574
2672
  g.select(".surface-case-fill").attr("y", y).attr("height", h);
2575
2673
  g.selectAll(".surface-case-side").attr("y1", y).attr("y2", y + h);
2576
2674
  });
2577
- const maxXValsReduction = (0, import_utils6.getProfileDiamValues)(constructionData);
2578
- const xScaleReduction = d37.scaleLinear().domain([0, d37.max(maxXValsReduction) || 0]).range([0, POCO_WIDTH]);
2675
+ const maxXValsReduction = (0, import_utils7.getProfileDiamValues)(constructionData);
2676
+ const xScaleReduction = d38.scaleLinear().domain([0, d38.max(maxXValsReduction) || 0]).range([0, POCO_WIDTH]);
2579
2677
  reductionGroup.selectAll(`polygon.${this.classes.reduction.item}`).attr("points", (d) => {
2580
2678
  const r = d;
2581
2679
  const yTop = transform.applyY(spanY(r));
@@ -2602,6 +2700,7 @@ var WellRenderer = class {
2602
2700
  ) ?? [],
2603
2701
  caves: profile.caves?.filter(inDepth) ?? []
2604
2702
  });
2703
+ drawCentralizers(zoomedCtx, filteredConstruction);
2605
2704
  drawConstructionLabels(zoomedCtx, {
2606
2705
  well_case: constructionData.well_case.filter(inDepth),
2607
2706
  well_screen: constructionData.well_screen.filter(inDepth)
@@ -2628,6 +2727,7 @@ var WellRenderer = class {
2628
2727
  ) ?? []
2629
2728
  );
2630
2729
  drawConstructive(ctx, filteredConstruction);
2730
+ drawCentralizers(ctx, filteredConstruction);
2631
2731
  drawConstructionLabels(ctx, {
2632
2732
  well_case: filteredConstruction.well_case,
2633
2733
  well_screen: filteredConstruction.well_screen
@@ -2647,7 +2747,7 @@ var WellRenderer = class {
2647
2747
  }
2648
2748
  const { zoom: zoomEnabled, pan: panEnabled } = this.renderConfig;
2649
2749
  if (zoomEnabled || panEnabled) {
2650
- const zoomNode = d37.zoom();
2750
+ const zoomNode = d38.zoom();
2651
2751
  if (zoomEnabled || panEnabled) zoomNode.on("zoom", zooming);
2652
2752
  zoomNode.scaleExtent(
2653
2753
  zoomEnabled ? [
@@ -2663,7 +2763,7 @@ var WellRenderer = class {
2663
2763
  if (initialZoom !== 1) {
2664
2764
  asSvgElement(svg).call(
2665
2765
  zoomNode.transform,
2666
- d37.zoomIdentity.scale(initialZoom)
2766
+ d38.zoomIdentity.scale(initialZoom)
2667
2767
  );
2668
2768
  }
2669
2769
  }