@tetacom/ng-components 1.6.29 → 1.7.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.
@@ -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,14 @@
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
+ constructor();
8
+ findIntersection(event: MouseEvent, canvas: HTMLCanvasElement, camera: THREE.Camera, wellMeshes: WellMeshData[]): IntersectionResult | null;
9
+ findClosestPointOnCurve(point: THREE.Vector3, curve: THREE.CatmullRomCurve3): THREE.Vector3;
10
+ private findClosestDataPoint;
11
+ private calculateTVD;
12
+ static ɵfac: i0.ɵɵFactoryDeclaration<Chart3dTooltipService, never>;
13
+ static ɵprov: i0.ɵɵInjectableDeclaration<Chart3dTooltipService>;
14
+ }
@@ -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,136 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
486
487
  }]
487
488
  }], ctorParameters: () => [] });
488
489
 
490
+ class Chart3dTooltipService {
491
+ constructor() {
492
+ this._raycaster = new THREE.Raycaster();
493
+ this._mouse = new THREE.Vector2();
494
+ this._raycaster.params.Line.threshold = 2;
495
+ }
496
+ findIntersection(event, canvas, camera, wellMeshes) {
497
+ // 1. Convert mouse coordinates
498
+ const rect = canvas.getBoundingClientRect();
499
+ this._mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
500
+ this._mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
501
+ // 2. Raycasting
502
+ this._raycaster.setFromCamera(this._mouse, camera);
503
+ const meshes = wellMeshes.map((_) => _.mesh);
504
+ const intersects = this._raycaster.intersectObjects(meshes, false);
505
+ if (intersects.length === 0) {
506
+ return null;
507
+ }
508
+ // 3. Find well data
509
+ const intersect = intersects[0];
510
+ const wellData = wellMeshes.find((_) => _.mesh === intersect.object);
511
+ if (!wellData) {
512
+ return null;
513
+ }
514
+ // 4. Calculate closest point on curve
515
+ const closestPoint = this.findClosestPointOnCurve(intersect.point, wellData.curve);
516
+ // 5. Find closest data point to get MD
517
+ const closestDataPoint = this.findClosestDataPoint(closestPoint, wellData.points, wellData.scale);
518
+ // 6. Calculate TVD and get MD from data point
519
+ const tvd = this.calculateTVD(closestPoint, wellData.scale.y);
520
+ const md = closestDataPoint.md ?? 0;
521
+ return {
522
+ wellData,
523
+ intersectionPoint: intersect.point,
524
+ closestCurvePoint: closestPoint,
525
+ closestDataPoint,
526
+ md,
527
+ tvd,
528
+ };
529
+ }
530
+ findClosestPointOnCurve(point, curve) {
531
+ let closestPoint = new THREE.Vector3();
532
+ let minDistance = Infinity;
533
+ const samples = 100;
534
+ for (let i = 0; i <= samples; i++) {
535
+ const t = i / samples;
536
+ const curvePoint = curve.getPoint(t);
537
+ const distance = point.distanceTo(curvePoint);
538
+ if (distance < minDistance) {
539
+ minDistance = distance;
540
+ closestPoint = curvePoint;
541
+ }
542
+ }
543
+ return closestPoint;
544
+ }
545
+ findClosestDataPoint(curvePoint, dataPoints, scale) {
546
+ let closestPoint = dataPoints[0];
547
+ let minDistance = Infinity;
548
+ let closestIndex = 0;
549
+ for (let i = 0; i < dataPoints.length; i++) {
550
+ const point = dataPoints[i];
551
+ // Convert data point to 3D space using scales
552
+ const scaledPoint = new THREE.Vector3(scale.x(point.x), scale.y(point.y), scale.z(point.z));
553
+ const distance = curvePoint.distanceTo(scaledPoint);
554
+ if (distance < minDistance) {
555
+ minDistance = distance;
556
+ closestPoint = point;
557
+ closestIndex = i;
558
+ }
559
+ }
560
+ // If MD is not available in the closest point, try to interpolate
561
+ if (closestPoint.md === undefined || closestPoint.md === null) {
562
+ // Find first point with MD
563
+ for (const point of dataPoints) {
564
+ if (point.md !== undefined && point.md !== null) {
565
+ return point;
566
+ }
567
+ }
568
+ }
569
+ // Try to interpolate MD between two closest points
570
+ if (closestIndex > 0 && closestIndex < dataPoints.length - 1) {
571
+ const prevPoint = dataPoints[closestIndex - 1];
572
+ const nextPoint = dataPoints[closestIndex + 1];
573
+ if (prevPoint.md !== undefined &&
574
+ nextPoint.md !== undefined &&
575
+ closestPoint.md === undefined) {
576
+ // Linear interpolation
577
+ const prevScaled = new THREE.Vector3(scale.x(prevPoint.x), scale.y(prevPoint.y), scale.z(prevPoint.z));
578
+ const nextScaled = new THREE.Vector3(scale.x(nextPoint.x), scale.y(nextPoint.y), scale.z(nextPoint.z));
579
+ const totalDist = prevScaled.distanceTo(nextScaled);
580
+ const distFromPrev = curvePoint.distanceTo(prevScaled);
581
+ const t = distFromPrev / totalDist;
582
+ const interpolatedMD = prevPoint.md + (nextPoint.md - prevPoint.md) * t;
583
+ return {
584
+ ...closestPoint,
585
+ md: interpolatedMD,
586
+ };
587
+ }
588
+ }
589
+ return closestPoint;
590
+ }
591
+ calculateTVD(point, yScale) {
592
+ return yScale.invert(point.y);
593
+ }
594
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: Chart3dTooltipService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
595
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: Chart3dTooltipService, providedIn: 'root' }); }
596
+ }
597
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: Chart3dTooltipService, decorators: [{
598
+ type: Injectable,
599
+ args: [{ providedIn: 'root' }]
600
+ }], ctorParameters: () => [] });
601
+
489
602
  class Chart3dComponent {
490
- constructor(_elementRef, _themeService) {
603
+ constructor(_elementRef, _themeService, _cdr, _tooltipService) {
491
604
  this._elementRef = _elementRef;
492
605
  this._themeService = _themeService;
606
+ this._cdr = _cdr;
607
+ this._tooltipService = _tooltipService;
493
608
  this.SIDE_SIZE = 100;
494
609
  this._alive = true;
610
+ // Tooltip properties
611
+ this.tooltipVisible = true;
612
+ this.tooltipX = 0;
613
+ this.tooltipY = 0;
614
+ this.tooltipWellName = '';
615
+ this.tooltipMD = '';
616
+ this.tooltipTVD = '';
617
+ this.tooltipUnit = 'm';
618
+ // Raycasting
619
+ this._wellMeshes = [];
495
620
  }
496
621
  set config(config) {
497
622
  if (config) {
@@ -518,11 +643,14 @@ class Chart3dComponent {
518
643
  this.addResizeObserver();
519
644
  this.createScene();
520
645
  this.startRenderingLoop();
646
+ this.addMouseMoveListener();
521
647
  this.init();
522
648
  }
523
649
  ngOnDestroy() {
524
650
  this._alive = false;
525
651
  this.removeResizeObserver();
652
+ this.removeMouseListeners();
653
+ this.disposeThreeResources();
526
654
  }
527
655
  init() {
528
656
  if (!this._scene) {
@@ -531,6 +659,7 @@ class Chart3dComponent {
531
659
  while (this._scene.children.length > 0) {
532
660
  this._scene.remove(this._scene.children[0]);
533
661
  }
662
+ this._wellMeshes = [];
534
663
  const { x, y, z } = this.getScales(this._config.series);
535
664
  this.config.series.forEach((data, idx) => {
536
665
  if (!data.points?.length) {
@@ -538,12 +667,21 @@ class Chart3dComponent {
538
667
  }
539
668
  const points = data.points.map((_) => new THREE.Vector3(x(_.x), y(_.y), z(_.z)));
540
669
  const color = d3.scaleOrdinal(d3.schemeTableau10);
541
- const material = new THREE.LineBasicMaterial({
670
+ const material = new THREE.MeshBasicMaterial({
542
671
  color: data?.color ?? color(idx.toString()),
543
672
  });
544
- const tubeGeometry = new THREE.TubeGeometry(new THREE.CatmullRomCurve3(points), 1024, 0.5, 20, false);
545
- let tube = new THREE.Line(tubeGeometry, material);
673
+ const curve = new THREE.CatmullRomCurve3(points);
674
+ const tubeGeometry = new THREE.TubeGeometry(curve, 1024, 0.5, 20, false);
675
+ let tube = new THREE.Mesh(tubeGeometry, material);
546
676
  this._scene.add(tube);
677
+ // Store well mesh with its data for raycasting
678
+ this._wellMeshes.push({
679
+ mesh: tube,
680
+ series: data,
681
+ scale: { x, y, z },
682
+ curve: curve,
683
+ points: data.points,
684
+ });
547
685
  });
548
686
  const circles = x.ticks(this.SIDE_SIZE / 10);
549
687
  const material = new THREE.LineBasicMaterial({ color: this.axesColor });
@@ -605,7 +743,7 @@ class Chart3dComponent {
605
743
  preserveDrawingBuffer: true,
606
744
  });
607
745
  const animate = () => {
608
- requestAnimationFrame(animate);
746
+ this._animationFrameId = requestAnimationFrame(animate);
609
747
  this._controls?.update();
610
748
  this.render();
611
749
  };
@@ -705,15 +843,162 @@ class Chart3dComponent {
705
843
  .nice();
706
844
  return { x, y, z };
707
845
  }
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 }); }
846
+ addMouseMoveListener() {
847
+ this._mouseMoveHandler = (event) => {
848
+ this.handleMouseMove(event);
849
+ };
850
+ this._mouseLeaveHandler = () => {
851
+ this.hideTooltip();
852
+ this._cdr.detectChanges();
853
+ };
854
+ this.canvas.addEventListener('mousemove', this._mouseMoveHandler);
855
+ this.canvas.addEventListener('mouseleave', this._mouseLeaveHandler);
856
+ }
857
+ handleMouseMove(event) {
858
+ const intersection = this._tooltipService.findIntersection(event, this.canvas, this._camera, this._wellMeshes);
859
+ if (intersection) {
860
+ this.showTooltip(intersection, event);
861
+ this.updateTooltipMarker(intersection.intersectionPoint, intersection.wellData.curve);
862
+ this.canvas.style.cursor = 'pointer';
863
+ }
864
+ else {
865
+ this.hideTooltip();
866
+ this.canvas.style.cursor = 'default';
867
+ }
868
+ this._cdr.detectChanges();
869
+ }
870
+ showTooltip(intersection, event) {
871
+ const rect = this.canvas.getBoundingClientRect();
872
+ this.tooltipVisible = true;
873
+ this.tooltipX = event.clientX - rect.left;
874
+ this.tooltipY = event.clientY - rect.top;
875
+ this.tooltipWellName = intersection.wellData.series.name || 'Well';
876
+ this.tooltipMD = intersection.md.toFixed(2);
877
+ this.tooltipTVD = intersection.tvd.toFixed(2);
878
+ this.tooltipUnit = this._config.unit || 'm';
879
+ if (this._tooltipMarker) {
880
+ this._tooltipMarker.visible = true;
881
+ }
882
+ }
883
+ hideTooltip() {
884
+ this.tooltipVisible = false;
885
+ if (this._tooltipMarker) {
886
+ this._tooltipMarker.visible = false;
887
+ }
888
+ }
889
+ removeMouseListeners() {
890
+ if (this.canvas && this._mouseMoveHandler) {
891
+ this.canvas.removeEventListener('mousemove', this._mouseMoveHandler);
892
+ }
893
+ if (this.canvas && this._mouseLeaveHandler) {
894
+ this.canvas.removeEventListener('mouseleave', this._mouseLeaveHandler);
895
+ }
896
+ }
897
+ disposeThreeResources() {
898
+ // Cancel animation frame
899
+ if (this._animationFrameId) {
900
+ cancelAnimationFrame(this._animationFrameId);
901
+ }
902
+ // Dispose tooltip marker
903
+ if (this._tooltipMarker) {
904
+ this._tooltipMarker.geometry.dispose();
905
+ this._tooltipMarker.material.dispose();
906
+ }
907
+ // Dispose all scene objects
908
+ if (this._scene) {
909
+ this._scene.traverse((object) => {
910
+ if (object instanceof THREE.Mesh) {
911
+ object.geometry?.dispose();
912
+ if (object.material) {
913
+ if (Array.isArray(object.material)) {
914
+ object.material.forEach((material) => material.dispose());
915
+ }
916
+ else {
917
+ object.material.dispose();
918
+ }
919
+ }
920
+ }
921
+ if (object instanceof THREE.Line || object instanceof THREE.LineSegments) {
922
+ object.geometry?.dispose();
923
+ if (object.material) {
924
+ object.material.dispose();
925
+ }
926
+ }
927
+ if (object instanceof THREE.Sprite) {
928
+ if (object.material) {
929
+ const spriteMaterial = object.material;
930
+ spriteMaterial.map?.dispose();
931
+ spriteMaterial.dispose();
932
+ }
933
+ }
934
+ });
935
+ }
936
+ // Dispose controls
937
+ if (this._controls) {
938
+ this._controls.dispose();
939
+ }
940
+ // Dispose renderer
941
+ if (this._renderer) {
942
+ this._renderer.dispose();
943
+ }
944
+ // Clear arrays
945
+ this._wellMeshes = [];
946
+ }
947
+ updateTooltipMarker(intersectionPoint, curve) {
948
+ // Remove old marker if exists
949
+ if (this._tooltipMarker) {
950
+ this._scene.remove(this._tooltipMarker);
951
+ this._tooltipMarker.geometry.dispose();
952
+ this._tooltipMarker.material.dispose();
953
+ }
954
+ // Find the closest point on the curve using service
955
+ const pointOnCurve = this._tooltipService.findClosestPointOnCurve(intersectionPoint, curve);
956
+ // Find parameter t for tangent calculation
957
+ let closestT = 0;
958
+ let minDistance = Infinity;
959
+ const samples = 100;
960
+ for (let i = 0; i <= samples; i++) {
961
+ const t = i / samples;
962
+ const curvePoint = curve.getPoint(t);
963
+ const distance = pointOnCurve.distanceTo(curvePoint);
964
+ if (distance < minDistance) {
965
+ minDistance = distance;
966
+ closestT = t;
967
+ }
968
+ }
969
+ // Get tangent at this point to orient the ring
970
+ const tangent = curve.getTangent(closestT).normalize();
971
+ const markerGeometry = new THREE.TorusGeometry(.85, 0.25, 16, 32);
972
+ const markerMaterial = new THREE.MeshBasicMaterial({
973
+ color: 0xff4444,
974
+ transparent: true,
975
+ opacity: 0.85,
976
+ depthTest: false,
977
+ side: THREE.DoubleSide,
978
+ });
979
+ this._tooltipMarker = new THREE.Mesh(markerGeometry, markerMaterial);
980
+ // Position the marker at the point on curve
981
+ this._tooltipMarker.position.copy(pointOnCurve);
982
+ // Orient the ring perpendicular to the tangent
983
+ const up = new THREE.Vector3(0, 0, 1);
984
+ const quaternion = new THREE.Quaternion().setFromUnitVectors(up, tangent);
985
+ this._tooltipMarker.setRotationFromQuaternion(quaternion);
986
+ this._tooltipMarker.renderOrder = 999;
987
+ this._tooltipMarker.visible = true;
988
+ this._scene.add(this._tooltipMarker);
989
+ }
990
+ 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 }); }
991
+ 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
992
  }
711
993
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: Chart3dComponent, decorators: [{
712
994
  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: [{
995
+ 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"] }]
996
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: ThemeSwitchService }, { type: i0.ChangeDetectorRef }, { type: Chart3dTooltipService }], propDecorators: { canvasRef: [{
715
997
  type: ViewChild,
716
998
  args: ['canvas']
999
+ }], tooltipRef: [{
1000
+ type: ViewChild,
1001
+ args: ['tooltip']
717
1002
  }], config: [{
718
1003
  type: Input
719
1004
  }] } });