@tetacom/ng-components 1.6.29 → 1.7.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.
@@ -1,22 +1,38 @@
1
- import { AfterViewInit, ElementRef, OnDestroy, OnInit } from '@angular/core';
1
+ import { AfterViewInit, ChangeDetectorRef, ElementRef, OnDestroy, OnInit } from '@angular/core';
2
2
  import { Chart3dOptions } from '../model/chart-3d-options';
3
3
  import { ThemeSwitchService } from '../../theme-switch/theme-switch.service';
4
+ import { Chart3dTooltipService } from '../services/chart3d-tooltip.service';
4
5
  import * as i0 from "@angular/core";
5
6
  export declare class Chart3dComponent implements OnInit, AfterViewInit, OnDestroy {
6
7
  private _elementRef;
7
8
  private _themeService;
9
+ private _cdr;
10
+ private _tooltipService;
8
11
  canvasRef: ElementRef;
12
+ tooltipRef: ElementRef;
9
13
  private _scene;
10
14
  private _camera;
11
15
  private _renderer;
12
16
  private _controls;
13
17
  private _obs;
14
18
  private _config;
19
+ private _animationFrameId;
15
20
  private SIDE_SIZE;
16
21
  private gridColor;
17
22
  private axesColor;
18
23
  private _alive;
19
- constructor(_elementRef: ElementRef, _themeService: ThemeSwitchService);
24
+ tooltipVisible: boolean;
25
+ tooltipX: number;
26
+ tooltipY: number;
27
+ tooltipWellName: string;
28
+ tooltipMD: string;
29
+ tooltipTVD: string;
30
+ tooltipUnit: string;
31
+ private _wellMeshes;
32
+ private _tooltipMarker;
33
+ private _mouseMoveHandler;
34
+ private _mouseLeaveHandler;
35
+ constructor(_elementRef: ElementRef, _themeService: ThemeSwitchService, _cdr: ChangeDetectorRef, _tooltipService: Chart3dTooltipService);
20
36
  set config(config: Chart3dOptions);
21
37
  get config(): Chart3dOptions;
22
38
  private get canvas();
@@ -33,6 +49,13 @@ export declare class Chart3dComponent implements OnInit, AfterViewInit, OnDestro
33
49
  private makeSprite;
34
50
  private drawTicks;
35
51
  private getScales;
52
+ private addMouseMoveListener;
53
+ private handleMouseMove;
54
+ private showTooltip;
55
+ private hideTooltip;
56
+ private removeMouseListeners;
57
+ private disposeThreeResources;
58
+ private updateTooltipMarker;
36
59
  static ɵfac: i0.ɵɵFactoryDeclaration<Chart3dComponent, never>;
37
60
  static ɵcmp: i0.ɵɵComponentDeclaration<Chart3dComponent, "teta-chart3d", never, { "config": { "alias": "config"; "required": false; }; }, {}, never, never, true, never>;
38
61
  }
@@ -2,4 +2,5 @@ export interface Base3dPoint {
2
2
  x: number;
3
3
  y: number;
4
4
  z: number;
5
+ md?: number;
5
6
  }
@@ -5,6 +5,7 @@ export declare class Chart3dOptions {
5
5
  min?: number;
6
6
  max?: number;
7
7
  };
8
+ unit?: string;
8
9
  series: Series3d<Base3dPoint>[];
9
10
  constructor(options?: Chart3dOptions);
10
11
  }
@@ -0,0 +1,22 @@
1
+ import * as THREE from 'three';
2
+ import { Series3d } from './series-3d';
3
+ import { Base3dPoint } from './base-3d-point';
4
+ export interface WellMeshData {
5
+ mesh: THREE.Mesh;
6
+ series: Series3d<Base3dPoint>;
7
+ scale: {
8
+ x: any;
9
+ y: any;
10
+ z: any;
11
+ };
12
+ curve: THREE.CatmullRomCurve3;
13
+ points: Base3dPoint[];
14
+ }
15
+ export interface IntersectionResult {
16
+ wellData: WellMeshData;
17
+ intersectionPoint: THREE.Vector3;
18
+ closestCurvePoint: THREE.Vector3;
19
+ closestDataPoint: Base3dPoint;
20
+ md: number;
21
+ tvd: number;
22
+ }
@@ -1,8 +1,10 @@
1
1
  import { Base3dPoint } from './base-3d-point';
2
2
  export declare class Series3d<T extends Base3dPoint> {
3
+ name?: string;
3
4
  color?: string;
4
5
  points: T[];
5
6
  constructor(options?: {
7
+ name?: string;
6
8
  color?: string;
7
9
  points: T[];
8
10
  });
@@ -0,0 +1,15 @@
1
+ import * as THREE from 'three';
2
+ import { WellMeshData, IntersectionResult } from '../model/chart3d-tooltip';
3
+ import * as i0 from "@angular/core";
4
+ export declare class Chart3dTooltipService {
5
+ private _raycaster;
6
+ private _mouse;
7
+ findClosestPointOnCurveLocal(point: THREE.Vector3, curve: THREE.CatmullRomCurve3): THREE.Vector3;
8
+ constructor();
9
+ findIntersection(event: MouseEvent, canvas: HTMLCanvasElement, camera: THREE.Camera, wellMeshes: WellMeshData[]): IntersectionResult | null;
10
+ private findClosestPointOnCurveToRay;
11
+ private findClosestDataPoint;
12
+ private calculateTVD;
13
+ static ɵfac: i0.ɵɵFactoryDeclaration<Chart3dTooltipService, never>;
14
+ static ɵprov: i0.ɵɵInjectableDeclaration<Chart3dTooltipService>;
15
+ }
@@ -451,6 +451,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
451
451
  class Chart3dOptions {
452
452
  constructor(options) {
453
453
  this.axes = { ...options?.axes };
454
+ this.unit = options?.unit;
454
455
  this.series = options?.series || [];
455
456
  }
456
457
  }
@@ -486,12 +487,188 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
486
487
  }]
487
488
  }], ctorParameters: () => [] });
488
489
 
490
+ class Chart3dTooltipService {
491
+ // Kept for marker/orientation logic in the component (not used for MD now)
492
+ findClosestPointOnCurveLocal(point, curve) {
493
+ let closestPoint = new THREE.Vector3();
494
+ let minDistance = Infinity;
495
+ const samples = 200;
496
+ for (let i = 0; i <= samples; i++) {
497
+ const t = i / samples;
498
+ const curvePoint = curve.getPoint(t);
499
+ const distance = point.distanceTo(curvePoint);
500
+ if (distance < minDistance) {
501
+ minDistance = distance;
502
+ closestPoint = curvePoint;
503
+ }
504
+ }
505
+ return closestPoint;
506
+ }
507
+ constructor() {
508
+ this._raycaster = new THREE.Raycaster();
509
+ this._mouse = new THREE.Vector2();
510
+ this._raycaster.params.Line.threshold = 2;
511
+ }
512
+ findIntersection(event, canvas, camera, wellMeshes) {
513
+ // 1. Convert mouse coordinates
514
+ const rect = canvas.getBoundingClientRect();
515
+ this._mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
516
+ this._mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
517
+ // 2. Raycasting
518
+ this._raycaster.setFromCamera(this._mouse, camera);
519
+ const meshes = wellMeshes.map((_) => _.mesh);
520
+ const intersects = this._raycaster.intersectObjects(meshes, false);
521
+ if (intersects.length === 0) {
522
+ return null;
523
+ }
524
+ // Prefer the closest intersection by distance (Three usually returns sorted,
525
+ // but keeping it explicit avoids surprises across versions)
526
+ intersects.sort((a, b) => a.distance - b.distance);
527
+ // 3. Find well data
528
+ const intersect = intersects[0];
529
+ const wellData = wellMeshes.find((_) => _.mesh === intersect.object);
530
+ if (!wellData) {
531
+ return null;
532
+ }
533
+ // 4. Calculate closest point on the trajectory curve using the mouse ray.
534
+ // Using the curve parameter t makes the tooltip smooth even for very low-point trajectories (e.g. 3 points).
535
+ const hit = this.findClosestPointOnCurveToRay(this._raycaster.ray, wellData.curve, wellData.points);
536
+ const closestPoint = hit.point;
537
+ const intersectPoint = hit.hitPoint ?? intersect.point;
538
+ const intersectDistance = hit.hitDistance ?? intersect.distance;
539
+ // Override intersection with a stable point derived from ray→trajectory projection
540
+ intersect.point = intersectPoint;
541
+ intersect.distance = intersectDistance;
542
+ // 5. Find closest data point (useful for other fields)
543
+ const closestDataPoint = this.findClosestDataPoint(closestPoint, wellData.points, wellData.scale);
544
+ // 6. Calculate TVD and MD
545
+ const tvd = this.calculateTVD(closestPoint, wellData.scale.y);
546
+ const md = hit.md; // smoothly interpolated along curve parameter t
547
+ return {
548
+ wellData,
549
+ intersectionPoint: intersect.point,
550
+ closestCurvePoint: closestPoint,
551
+ closestDataPoint,
552
+ md,
553
+ tvd,
554
+ };
555
+ }
556
+ findClosestPointOnCurveToRay(ray, curve, orderedDataPoints) {
557
+ // Compute closest point on the rendered curve to the mouse ray.
558
+ // We sample t densely (fast enough) and then refine with a few iterations.
559
+ // MD is interpolated along the dataPoints md range using the same t.
560
+ if (!orderedDataPoints.length) {
561
+ return { point: new THREE.Vector3(), md: 0 };
562
+ }
563
+ if (orderedDataPoints.length === 1) {
564
+ // Degenerate curve
565
+ const p = curve.getPoint(0);
566
+ const s = Math.max(0, ray.direction.dot(new THREE.Vector3().subVectors(p, ray.origin)));
567
+ const hitPoint = ray.at(s, new THREE.Vector3());
568
+ return {
569
+ point: p,
570
+ md: orderedDataPoints[0].md ?? 0,
571
+ hitPoint,
572
+ hitDistance: s,
573
+ };
574
+ }
575
+ const mdMin = orderedDataPoints[0].md ?? 0;
576
+ const mdMax = orderedDataPoints[orderedDataPoints.length - 1].md ?? mdMin;
577
+ const d = ray.direction.clone().normalize();
578
+ // IMPORTANT: use getPointAt(u) (u = arc-length parameter), not getPoint(t).
579
+ // CatmullRomCurve3 "t" is not proportional to arc length and causes MD to change non-uniformly,
580
+ // especially noticeable when there are very few control points.
581
+ const distSqAt = (u) => {
582
+ const p = curve.getPointAt(u);
583
+ const s = Math.max(0, d.dot(new THREE.Vector3().subVectors(p, ray.origin)));
584
+ const r = ray.at(s, new THREE.Vector3());
585
+ return { distSq: r.distanceToSquared(p), p, s, r };
586
+ };
587
+ // 1) coarse scan over arc-length parameter u
588
+ const samples = 400;
589
+ let bestU = 0;
590
+ let best = distSqAt(0);
591
+ for (let i = 1; i <= samples; i++) {
592
+ const u = i / samples;
593
+ const cur = distSqAt(u);
594
+ if (cur.distSq < best.distSq) {
595
+ best = cur;
596
+ bestU = u;
597
+ }
598
+ }
599
+ // 2) refine around bestU
600
+ let left = Math.max(0, bestU - 1 / samples);
601
+ let right = Math.min(1, bestU + 1 / samples);
602
+ for (let iter = 0; iter < 10; iter++) {
603
+ const u1 = left + (right - left) / 3;
604
+ const u2 = right - (right - left) / 3;
605
+ const f1 = distSqAt(u1);
606
+ const f2 = distSqAt(u2);
607
+ if (f1.distSq < f2.distSq) {
608
+ right = u2;
609
+ best = f1;
610
+ bestU = u1;
611
+ }
612
+ else {
613
+ left = u1;
614
+ best = f2;
615
+ bestU = u2;
616
+ }
617
+ }
618
+ // Final eval at bestU
619
+ const final = distSqAt(bestU);
620
+ const md = mdMin + (mdMax - mdMin) * bestU;
621
+ return {
622
+ point: final.p,
623
+ md,
624
+ hitPoint: final.r,
625
+ hitDistance: final.s,
626
+ };
627
+ }
628
+ findClosestDataPoint(curvePoint, dataPoints, scale) {
629
+ let closestPoint = dataPoints[0];
630
+ let minDistance = Infinity;
631
+ for (let i = 0; i < dataPoints.length; i++) {
632
+ const point = dataPoints[i];
633
+ // Convert data point to 3D space using scales
634
+ const scaledPoint = new THREE.Vector3(scale.x(point.x), scale.y(point.y), scale.z(point.z));
635
+ const distance = curvePoint.distanceTo(scaledPoint);
636
+ if (distance < minDistance) {
637
+ minDistance = distance;
638
+ closestPoint = point;
639
+ }
640
+ }
641
+ return closestPoint;
642
+ }
643
+ calculateTVD(point, yScale) {
644
+ return yScale.invert(point.y);
645
+ }
646
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: Chart3dTooltipService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
647
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: Chart3dTooltipService, providedIn: 'root' }); }
648
+ }
649
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: Chart3dTooltipService, decorators: [{
650
+ type: Injectable,
651
+ args: [{ providedIn: 'root' }]
652
+ }], ctorParameters: () => [] });
653
+
489
654
  class Chart3dComponent {
490
- constructor(_elementRef, _themeService) {
655
+ constructor(_elementRef, _themeService, _cdr, _tooltipService) {
491
656
  this._elementRef = _elementRef;
492
657
  this._themeService = _themeService;
658
+ this._cdr = _cdr;
659
+ this._tooltipService = _tooltipService;
493
660
  this.SIDE_SIZE = 100;
494
661
  this._alive = true;
662
+ // Tooltip properties
663
+ this.tooltipVisible = true;
664
+ this.tooltipX = 0;
665
+ this.tooltipY = 0;
666
+ this.tooltipWellName = '';
667
+ this.tooltipMD = '';
668
+ this.tooltipTVD = '';
669
+ this.tooltipUnit = 'm';
670
+ // Raycasting
671
+ this._wellMeshes = [];
495
672
  }
496
673
  set config(config) {
497
674
  if (config) {
@@ -518,11 +695,14 @@ class Chart3dComponent {
518
695
  this.addResizeObserver();
519
696
  this.createScene();
520
697
  this.startRenderingLoop();
698
+ this.addMouseMoveListener();
521
699
  this.init();
522
700
  }
523
701
  ngOnDestroy() {
524
702
  this._alive = false;
525
703
  this.removeResizeObserver();
704
+ this.removeMouseListeners();
705
+ this.disposeThreeResources();
526
706
  }
527
707
  init() {
528
708
  if (!this._scene) {
@@ -531,19 +711,30 @@ class Chart3dComponent {
531
711
  while (this._scene.children.length > 0) {
532
712
  this._scene.remove(this._scene.children[0]);
533
713
  }
714
+ this._wellMeshes = [];
534
715
  const { x, y, z } = this.getScales(this._config.series);
535
716
  this.config.series.forEach((data, idx) => {
536
717
  if (!data.points?.length) {
537
718
  return;
538
719
  }
539
- const points = data.points.map((_) => new THREE.Vector3(x(_.x), y(_.y), z(_.z)));
720
+ const orderedDataPoints = [...data.points].sort((a, b) => (a.md ?? 0) - (b.md ?? 0));
721
+ const points = orderedDataPoints.map((_) => new THREE.Vector3(x(_.x), y(_.y), z(_.z)));
540
722
  const color = d3.scaleOrdinal(d3.schemeTableau10);
541
- const material = new THREE.LineBasicMaterial({
723
+ const material = new THREE.MeshBasicMaterial({
542
724
  color: data?.color ?? color(idx.toString()),
543
725
  });
544
- const tubeGeometry = new THREE.TubeGeometry(new THREE.CatmullRomCurve3(points), 1024, 0.5, 20, false);
545
- let tube = new THREE.Line(tubeGeometry, material);
726
+ const curve = new THREE.CatmullRomCurve3(points);
727
+ const tubeGeometry = new THREE.TubeGeometry(curve, 1024, 0.5, 20, false);
728
+ let tube = new THREE.Mesh(tubeGeometry, material);
546
729
  this._scene.add(tube);
730
+ // Store well mesh with its data for raycasting
731
+ this._wellMeshes.push({
732
+ mesh: tube,
733
+ series: data,
734
+ scale: { x, y, z },
735
+ curve: curve,
736
+ points: orderedDataPoints,
737
+ });
547
738
  });
548
739
  const circles = x.ticks(this.SIDE_SIZE / 10);
549
740
  const material = new THREE.LineBasicMaterial({ color: this.axesColor });
@@ -605,7 +796,7 @@ class Chart3dComponent {
605
796
  preserveDrawingBuffer: true,
606
797
  });
607
798
  const animate = () => {
608
- requestAnimationFrame(animate);
799
+ this._animationFrameId = requestAnimationFrame(animate);
609
800
  this._controls?.update();
610
801
  this.render();
611
802
  };
@@ -705,15 +896,162 @@ class Chart3dComponent {
705
896
  .nice();
706
897
  return { x, y, z };
707
898
  }
708
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: Chart3dComponent, deps: [{ token: i0.ElementRef }, { token: ThemeSwitchService }], target: i0.ɵɵFactoryTarget.Component }); }
709
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: Chart3dComponent, isStandalone: true, selector: "teta-chart3d", inputs: { config: "config" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true }], ngImport: i0, template: "<canvas #canvas></canvas>\n", styles: [":host{display:flex;width:100%;height:100%}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
899
+ addMouseMoveListener() {
900
+ this._mouseMoveHandler = (event) => {
901
+ this.handleMouseMove(event);
902
+ };
903
+ this._mouseLeaveHandler = () => {
904
+ this.hideTooltip();
905
+ this._cdr.detectChanges();
906
+ };
907
+ this.canvas.addEventListener('mousemove', this._mouseMoveHandler);
908
+ this.canvas.addEventListener('mouseleave', this._mouseLeaveHandler);
909
+ }
910
+ handleMouseMove(event) {
911
+ const intersection = this._tooltipService.findIntersection(event, this.canvas, this._camera, this._wellMeshes);
912
+ if (intersection) {
913
+ this.showTooltip(intersection, event);
914
+ this.updateTooltipMarker(intersection.intersectionPoint, intersection.wellData.curve);
915
+ this.canvas.style.cursor = 'pointer';
916
+ }
917
+ else {
918
+ this.hideTooltip();
919
+ this.canvas.style.cursor = 'default';
920
+ }
921
+ this._cdr.detectChanges();
922
+ }
923
+ showTooltip(intersection, event) {
924
+ const rect = this.canvas.getBoundingClientRect();
925
+ this.tooltipVisible = true;
926
+ this.tooltipX = event.clientX - rect.left;
927
+ this.tooltipY = event.clientY - rect.top;
928
+ this.tooltipWellName = intersection.wellData.series.name || 'Well';
929
+ this.tooltipMD = intersection.md.toFixed(2);
930
+ this.tooltipTVD = intersection.tvd.toFixed(2);
931
+ this.tooltipUnit = this._config.unit || 'm';
932
+ if (this._tooltipMarker) {
933
+ this._tooltipMarker.visible = true;
934
+ }
935
+ }
936
+ hideTooltip() {
937
+ this.tooltipVisible = false;
938
+ if (this._tooltipMarker) {
939
+ this._tooltipMarker.visible = false;
940
+ }
941
+ }
942
+ removeMouseListeners() {
943
+ if (this.canvas && this._mouseMoveHandler) {
944
+ this.canvas.removeEventListener('mousemove', this._mouseMoveHandler);
945
+ }
946
+ if (this.canvas && this._mouseLeaveHandler) {
947
+ this.canvas.removeEventListener('mouseleave', this._mouseLeaveHandler);
948
+ }
949
+ }
950
+ disposeThreeResources() {
951
+ // Cancel animation frame
952
+ if (this._animationFrameId) {
953
+ cancelAnimationFrame(this._animationFrameId);
954
+ }
955
+ // Dispose tooltip marker
956
+ if (this._tooltipMarker) {
957
+ this._tooltipMarker.geometry.dispose();
958
+ this._tooltipMarker.material.dispose();
959
+ }
960
+ // Dispose all scene objects
961
+ if (this._scene) {
962
+ this._scene.traverse((object) => {
963
+ if (object instanceof THREE.Mesh) {
964
+ object.geometry?.dispose();
965
+ if (object.material) {
966
+ if (Array.isArray(object.material)) {
967
+ object.material.forEach((material) => material.dispose());
968
+ }
969
+ else {
970
+ object.material.dispose();
971
+ }
972
+ }
973
+ }
974
+ if (object instanceof THREE.Line || object instanceof THREE.LineSegments) {
975
+ object.geometry?.dispose();
976
+ if (object.material) {
977
+ object.material.dispose();
978
+ }
979
+ }
980
+ if (object instanceof THREE.Sprite) {
981
+ if (object.material) {
982
+ const spriteMaterial = object.material;
983
+ spriteMaterial.map?.dispose();
984
+ spriteMaterial.dispose();
985
+ }
986
+ }
987
+ });
988
+ }
989
+ // Dispose controls
990
+ if (this._controls) {
991
+ this._controls.dispose();
992
+ }
993
+ // Dispose renderer
994
+ if (this._renderer) {
995
+ this._renderer.dispose();
996
+ }
997
+ // Clear arrays
998
+ this._wellMeshes = [];
999
+ }
1000
+ updateTooltipMarker(intersectionPoint, curve) {
1001
+ // Remove old marker if exists
1002
+ if (this._tooltipMarker) {
1003
+ this._scene.remove(this._tooltipMarker);
1004
+ this._tooltipMarker.geometry.dispose();
1005
+ this._tooltipMarker.material.dispose();
1006
+ }
1007
+ // Closest point on curve (local helper, keep marker purely visual)
1008
+ const pointOnCurve = this._tooltipService.findClosestPointOnCurveLocal(intersectionPoint, curve);
1009
+ // Find parameter t for tangent calculation
1010
+ let closestT = 0;
1011
+ let minDistance = Infinity;
1012
+ const samples = 100;
1013
+ for (let i = 0; i <= samples; i++) {
1014
+ const t = i / samples;
1015
+ const curvePoint = curve.getPoint(t);
1016
+ const distance = pointOnCurve.distanceTo(curvePoint);
1017
+ if (distance < minDistance) {
1018
+ minDistance = distance;
1019
+ closestT = t;
1020
+ }
1021
+ }
1022
+ // Get tangent at this point to orient the ring
1023
+ const tangent = curve.getTangent(closestT).normalize();
1024
+ const markerGeometry = new THREE.TorusGeometry(.85, 0.25, 16, 32);
1025
+ const markerMaterial = new THREE.MeshBasicMaterial({
1026
+ color: 0xff4444,
1027
+ transparent: true,
1028
+ opacity: 0.85,
1029
+ depthTest: false,
1030
+ side: THREE.DoubleSide,
1031
+ });
1032
+ this._tooltipMarker = new THREE.Mesh(markerGeometry, markerMaterial);
1033
+ // Position the marker at the point on curve
1034
+ this._tooltipMarker.position.copy(pointOnCurve);
1035
+ // Orient the ring perpendicular to the tangent
1036
+ const up = new THREE.Vector3(0, 0, 1);
1037
+ const quaternion = new THREE.Quaternion().setFromUnitVectors(up, tangent);
1038
+ this._tooltipMarker.setRotationFromQuaternion(quaternion);
1039
+ this._tooltipMarker.renderOrder = 999;
1040
+ this._tooltipMarker.visible = true;
1041
+ this._scene.add(this._tooltipMarker);
1042
+ }
1043
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: Chart3dComponent, deps: [{ token: i0.ElementRef }, { token: ThemeSwitchService }, { token: i0.ChangeDetectorRef }, { token: Chart3dTooltipService }], target: i0.ɵɵFactoryTarget.Component }); }
1044
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.5", type: Chart3dComponent, isStandalone: true, selector: "teta-chart3d", inputs: { config: "config" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true }, { propertyName: "tooltipRef", first: true, predicate: ["tooltip"], descendants: true }], ngImport: i0, template: "<canvas #canvas></canvas>\n<div #tooltip class=\"bg-global-bgcard tooltip color-text-90\" [style.display]=\"tooltipVisible ? 'block' : 'none'\" [style.left.px]=\"tooltipX\" [style.top.px]=\"tooltipY\">\n <div class=\"tooltip-content\">\n <div class=\"tooltip-header\">\n <strong>{{ tooltipWellName }}</strong>\n </div>\n <div class=\"tooltip-row\">\n <span class=\"label\">MD:</span>\n <span class=\"value\">{{ tooltipMD }} {{ tooltipUnit }}</span>\n </div>\n <div class=\"tooltip-row\">\n <span class=\"label\">TVD:</span>\n <span class=\"value\">{{ tooltipTVD }} {{ tooltipUnit }}</span>\n </div>\n </div>\n</div>\n", styles: [":host{display:flex;width:100%;height:100%;position:relative}.tooltip{position:absolute;pointer-events:none;z-index:1000;min-width:80px;font-size:12px;white-space:nowrap;transform:translate(-50%,-100%);margin-top:-8px;background-color:var(--color-global-bgcard)}.tooltip .tooltip-content .tooltip-header{font-weight:600;margin-bottom:6px;padding-bottom:4px;border-bottom:1px solid rgba(255,255,255,.2)}.tooltip .tooltip-content .tooltip-row{display:flex;justify-content:space-between;gap:12px;margin-bottom:2px}.tooltip .tooltip-content .tooltip-row .label{opacity:.8}.tooltip .tooltip-content .tooltip-row .value{font-weight:500}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
710
1045
  }
711
1046
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: Chart3dComponent, decorators: [{
712
1047
  type: Component,
713
- args: [{ selector: 'teta-chart3d', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "<canvas #canvas></canvas>\n", styles: [":host{display:flex;width:100%;height:100%}\n"] }]
714
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: ThemeSwitchService }], propDecorators: { canvasRef: [{
1048
+ args: [{ selector: 'teta-chart3d', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, template: "<canvas #canvas></canvas>\n<div #tooltip class=\"bg-global-bgcard tooltip color-text-90\" [style.display]=\"tooltipVisible ? 'block' : 'none'\" [style.left.px]=\"tooltipX\" [style.top.px]=\"tooltipY\">\n <div class=\"tooltip-content\">\n <div class=\"tooltip-header\">\n <strong>{{ tooltipWellName }}</strong>\n </div>\n <div class=\"tooltip-row\">\n <span class=\"label\">MD:</span>\n <span class=\"value\">{{ tooltipMD }} {{ tooltipUnit }}</span>\n </div>\n <div class=\"tooltip-row\">\n <span class=\"label\">TVD:</span>\n <span class=\"value\">{{ tooltipTVD }} {{ tooltipUnit }}</span>\n </div>\n </div>\n</div>\n", styles: [":host{display:flex;width:100%;height:100%;position:relative}.tooltip{position:absolute;pointer-events:none;z-index:1000;min-width:80px;font-size:12px;white-space:nowrap;transform:translate(-50%,-100%);margin-top:-8px;background-color:var(--color-global-bgcard)}.tooltip .tooltip-content .tooltip-header{font-weight:600;margin-bottom:6px;padding-bottom:4px;border-bottom:1px solid rgba(255,255,255,.2)}.tooltip .tooltip-content .tooltip-row{display:flex;justify-content:space-between;gap:12px;margin-bottom:2px}.tooltip .tooltip-content .tooltip-row .label{opacity:.8}.tooltip .tooltip-content .tooltip-row .value{font-weight:500}\n"] }]
1049
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: ThemeSwitchService }, { type: i0.ChangeDetectorRef }, { type: Chart3dTooltipService }], propDecorators: { canvasRef: [{
715
1050
  type: ViewChild,
716
1051
  args: ['canvas']
1052
+ }], tooltipRef: [{
1053
+ type: ViewChild,
1054
+ args: ['tooltip']
717
1055
  }], config: [{
718
1056
  type: Input
719
1057
  }] } });