Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions typescript/packages/subsurface-viewer/src/SubsurfaceViewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,26 @@ import { TGrid3DColoringMode } from "./layers/grid3d/grid3dLayer";

import Map, { createLayers } from "./components/Map";

// Type extracted from Deck.gl.
export type DeckMetrics = {
/* eslint-disable*/
fps: number; // fps - average number of frames rendered per second
setPropsTime: number; // setPropsTime - time spent setting deck properties
updateAttributesTime: number; // updateAttributesTime - time spent updating layer attributes
framesRedrawn: number; // framesRedrawn - number of times the scene was rendered
pickTime: number; // pickTime - total time spent on picking operations
pickCount: number; // pickCount - number of times a pick operation was performed
gpuTime: number; // gpuTime - total time spent on GPU processing
gpuTimePerFrame: number; // gpuTimePerFrame - average time spent on GPU processing per frame
cpuTime: number; // cpuTime - total time spent on CPU processing
cpuTimePerFrame: number; // cpuTimePerFrame - average time spent on CPU processing per frame
bufferMemory: number; // bufferMemory - total GPU memory allocated for buffers
textureMemory: number; // textureMemory - total GPU memory allocated for textures
renderbufferMemory: number; // renderbufferMemory - total GPU memory allocated for renderbuffers
gpuMemory: number; // gpuMemory - total allocated GPU memory
/* eslint-enable*/
};

export type {
BoundsAccessor,
colorTablesArray,
Expand Down Expand Up @@ -80,6 +100,11 @@ export interface SubsurfaceViewerProps
* instead.
*/
setProps?: (data: Record<string, unknown>) => void;

/**
* Callback called from deck.gl whith metrics data.
*/
onMetrics?: ((m: DeckMetrics) => void) | null;
Comment on lines +103 to +107
Copy link
Collaborator

@hkfb hkfb May 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed, since MapProps is already included in the type definition.

}

const SubsurfaceViewer: React.FC<SubsurfaceViewerProps> = ({
Expand Down Expand Up @@ -108,6 +133,7 @@ const SubsurfaceViewer: React.FC<SubsurfaceViewerProps> = ({
lights,
children,
verticalScale,
onMetrics,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not needed, should be included in ...args

...args
}: SubsurfaceViewerProps) => {
// Contains layers data received from map layers by user interaction
Expand Down Expand Up @@ -188,6 +214,7 @@ const SubsurfaceViewer: React.FC<SubsurfaceViewerProps> = ({
triggerResetMultipleWells={triggerResetMultipleWells}
lights={lights}
verticalScale={verticalScale}
onMetrics={onMetrics ?? undefined}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not needed, should be included in ...args

{...args}
>
{children}
Expand Down
13 changes: 12 additions & 1 deletion typescript/packages/subsurface-viewer/src/components/Map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,11 @@ import StatusIndicator from "./StatusIndicator";
import type { Unit } from "convert-units";
import IntersectionView from "../views/intersectionView";

import type { LightsType, TLayerDefinition } from "../SubsurfaceViewer";
import type {
LightsType,
TLayerDefinition,
DeckMetrics,
} from "../SubsurfaceViewer";
import { getZoom, useLateralZoom } from "../utils/camera";
import { useScaleFactor, useShiftHeld } from "../utils/event";

Expand Down Expand Up @@ -399,6 +403,11 @@ export interface MapProps {
* The reference to the deck.gl instance.
*/
deckGlRef?: React.ForwardedRef<DeckGLRef>;

/**
* Callback called from deck.gl whith metrics data.
*/
onMetrics?: ((m: DeckMetrics) => void) | null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest using something like DeckGL["_onMetrics"], so that we don't need to duplicate the type

}

function defaultTooltip(info: PickingInfo) {
Expand Down Expand Up @@ -446,6 +455,7 @@ const Map: React.FC<MapProps> = ({
innerRef,
pickingRadius,
deckGlRef,
onMetrics,
}: MapProps) => {
// From react doc, ref should not be read nor modified during rendering.
const deckRef = React.useRef<DeckGLRef>(null);
Expand Down Expand Up @@ -884,6 +894,7 @@ const Map: React.FC<MapProps> = ({
onDrag={onDrag}
onResize={onResize}
pickingRadius={pickingRadius}
_onMetrics={onMetrics}
>
{children}
</DeckGL>
Expand Down
60 changes: 60 additions & 0 deletions typescript/packages/subsurface-viewer/src/components/Metrics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, { useState } from "react";
import { forwardRef, useImperativeHandle } from "react";
import type { DeckMetrics } from "../SubsurfaceViewer";

export const Metrics = forwardRef((_props, ref) => {
const [metrics, setMetrics] = useState<DeckMetrics>();

const publicRef = {
updateMetrics: (m: DeckMetrics) => {
setMetrics({ ...m });
},
};

useImperativeHandle(ref, () => publicRef);

const isDefined = typeof metrics === "object";
if (!isDefined) {
return null;
}

const tableRows = [];
for (const key in metrics) {
if (Object.prototype.hasOwnProperty.call(metrics, key)) {
const typedKey = key as keyof DeckMetrics;
tableRows.push(
<tr key={typedKey}>
<td> {typedKey} </td>
<td> {metrics[typedKey]?.toFixed(1)} </td>
</tr>
);
}
}

return (
<div
style={{
display: "flex",
alignItems: "flex-end",
justifyContent: "right",
position: "absolute",
top: "10px",
right: "30px",
zIndex: 200,
backgroundColor: "rgba(255, 255, 255, 0.8)",
}}
>
<table>
<tbody>
<tr>
<th align="left"> {"Metrics"} </th>
</tr>
{tableRows}
</tbody>
</table>
</div>
);
});

Metrics.displayName = "MetricsComponent";
export default Metrics;
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@ import { ClipExtension } from "@deck.gl/extensions";
import type { SubsurfaceViewerProps } from "../../SubsurfaceViewer";
import SubsurfaceViewer from "../../SubsurfaceViewer";
import InfoCard from "../../components/InfoCard";
import Metrics from "../../components/Metrics";
import type { DeckMetrics } from "../../SubsurfaceViewer";
import type {
BoundingBox2D,
BoundingBox3D,
BoundsAccessor,
ViewsType,
} from "../../components/Map";
import { useHoverInfo } from "../../components/Map";
Expand Down Expand Up @@ -315,9 +318,47 @@ export const BigMap: StoryObj<typeof SubsurfaceViewer> = {
},
};

export const BigMap3d: StoryObj<typeof SubsurfaceViewer> = {
interface BigMapComponentProps {
showMetrics: boolean;
layers: Array<Record<string, unknown>>; // Array of layer objects
bounds: BoundingBox2D | BoundsAccessor | undefined; // Can be 2D or 3D bounding box
views: ViewsType; // Type for views
}

const BigMapComponent: React.FC<BigMapComponentProps> = (
props: BigMapComponentProps
) => {
const metricsComponentRef = React.useRef<{
updateMetrics?: (m: DeckMetrics) => void;
} | null>(null);
const updateMetrics = (m: DeckMetrics) => {
if (!metricsComponentRef.current) {
return;
}
if ("updateMetrics" in metricsComponentRef.current) {
metricsComponentRef.current.updateMetrics?.(m);
}
};

const onMetrics = (m: DeckMetrics) => {
updateMetrics(m);
};
Comment on lines +331 to +345
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest creating an exported custom React hook that returns

  1. a state that contains the metrics
  2. a callback that updates the state, used as the onMetrics argument

I think it will be a more versatile and easier to use approach. I agree with @w1nklr that the ref shouldn't be necessary. I think it's at least worth a try.


return (
<div>
<SubsurfaceViewer
id={"test"}
onMetrics={onMetrics}
{...props}
></SubsurfaceViewer>
{props.showMetrics ? <Metrics ref={metricsComponentRef} /> : null}
</div>
);
};

export const BigMap3d: StoryObj<typeof BigMapComponent> = {
args: {
id: "map",
showMetrics: false,
layers: [huginAxes3DLayer, hugin5mKhNetmapMapLayer, northArrowLayer],
bounds: hugin2DBounds,
views: default3DViews,
Expand All @@ -330,6 +371,7 @@ export const BigMap3d: StoryObj<typeof SubsurfaceViewer> = {
},
},
},
render: (args) => <BigMapComponent {...args} />,
};

const axes_small = {
Expand Down
Loading