diff --git a/frontend/src/modules/Intersection/view/components/intersection.tsx b/frontend/src/modules/Intersection/view/components/intersection.tsx
index 509e1e098..31cbabb39 100644
--- a/frontend/src/modules/Intersection/view/components/intersection.tsx
+++ b/frontend/src/modules/Intersection/view/components/intersection.tsx
@@ -2,8 +2,6 @@ import React from "react";
import { BoundingBox3d_api, WellboreCasing_api } from "@api";
import { Casing, IntersectionReferenceSystem, getSeismicInfo, getSeismicOptions } from "@equinor/esv-intersection";
-import { Button } from "@lib/components/Button";
-import { HoldPressedIntervalCallbackButton } from "@lib/components/HoldPressedIntervalCallbackButton/holdPressedIntervalCallbackButton";
import { useElementBoundingRect } from "@lib/hooks/useElementBoundingRect";
import { ColorScale, ColorScaleGradientType } from "@lib/utils/ColorScale";
import { IntersectionType, SeismicSliceImageData } from "@modules/Intersection/typesAndEnums";
@@ -14,18 +12,9 @@ import {
LayerType,
} from "@modules/_shared/components/EsvIntersection";
import { Viewport } from "@modules/_shared/components/EsvIntersection/esvIntersection";
-import {
- AdditionalInformationKey,
- HighlightItem,
- HighlightItemShape,
- ReadoutItem,
-} from "@modules/_shared/components/EsvIntersection/types";
-import { getColorFromLayerData } from "@modules/_shared/components/EsvIntersection/utils/intersectionConversion";
-import {
- getAdditionalInformationFromReadoutItem,
- getLabelFromLayerData,
-} from "@modules/_shared/components/EsvIntersection/utils/readoutItemUtils";
-import { Add, FilterCenterFocus, Remove } from "@mui/icons-material";
+import { HighlightItem, HighlightItemShape, ReadoutItem } from "@modules/_shared/components/EsvIntersection/types";
+import { ReadoutBox } from "@modules/_shared/components/EsvIntersection/utilityComponents/ReadoutBox";
+import { Toolbar } from "@modules/_shared/components/EsvIntersection/utilityComponents/Toolbar";
import { isEqual } from "lodash";
@@ -543,125 +532,3 @@ function GradientDef(props: GradientDefProps): React.ReactNode {
);
}
-
-export type ReadoutBoxProps = {
- readoutItems: ReadoutItem[];
-};
-
-function additionalInformationItemToReadableString(key: string, value: unknown): string {
- switch (key) {
- case AdditionalInformationKey.CELL_INDEX:
- return `Cell index: ${(value as number).toFixed(0)}`;
- case AdditionalInformationKey.PROP_VALUE:
- return `Property value: ${(value as number).toFixed(2)}`;
- case AdditionalInformationKey.MD:
- return `MD: ${(value as number).toFixed(2)}`;
- case AdditionalInformationKey.MAX:
- return `Max: ${(value as number).toFixed(2)}`;
- case AdditionalInformationKey.MIN:
- return `Min: ${(value as number).toFixed(2)}`;
- case AdditionalInformationKey.P10:
- return `P10: ${(value as number).toFixed(2)}`;
- case AdditionalInformationKey.P90:
- return `P90: ${(value as number).toFixed(2)}`;
- case AdditionalInformationKey.P50:
- return `P50: ${(value as number).toFixed(2)}`;
- case AdditionalInformationKey.MEAN:
- return `Mean: ${(value as number).toFixed(2)}`;
- case AdditionalInformationKey.SCHEMATIC_INFO:
- return (value as string[]).join(", ");
- case AdditionalInformationKey.X:
- return `X: ${(value as number).toFixed(2)}`;
- case AdditionalInformationKey.Y:
- return `Y: ${(value as number).toFixed(2)}`;
- default:
- return "";
- }
-}
-
-function makeAdditionalInformation(item: ReadoutItem): React.ReactNode {
- const additionalInformation = getAdditionalInformationFromReadoutItem(item);
- return Object.entries(additionalInformation).map(([key, value], index) => {
- return (
-
- {additionalInformationItemToReadableString(key, value)}
-
- );
- });
-}
-
-function ReadoutBox(props: ReadoutBoxProps): React.ReactNode {
- if (props.readoutItems.length === 0) {
- return null;
- }
-
- return (
-
- {props.readoutItems.map((item, index) => (
-
-
-
- {getLabelFromLayerData(item)}
-
- {makeAdditionalInformation(item)}
-
-
- ))}
-
- );
-}
-
-type ToolbarProps = {
- visible: boolean;
- zFactor: number;
- onFitInView: () => void;
- onVerticalScaleIncrease: () => void;
- onVerticalScaleDecrease: () => void;
-};
-
-function Toolbar(props: ToolbarProps): React.ReactNode {
- function handleFitInViewClick() {
- props.onFitInView();
- }
-
- function handleVerticalScaleIncrease() {
- props.onVerticalScaleIncrease();
- }
-
- function handleVerticalScaleDecrease() {
- props.onVerticalScaleDecrease();
- }
-
- if (!props.visible) {
- return null;
- }
-
- return (
-
-
-
-
-
-
-
{props.zFactor.toFixed(2)}
-
-
-
-
- );
-}
-
-function ToolBarDivider(): React.ReactNode {
- return ;
-}
diff --git a/frontend/src/modules/StructuralUncertaintyIntersection/components/intersectionSettings.tsx b/frontend/src/modules/StructuralUncertaintyIntersection/components/intersectionSettings.tsx
index d375563ef..1e52f6c81 100644
--- a/frontend/src/modules/StructuralUncertaintyIntersection/components/intersectionSettings.tsx
+++ b/frontend/src/modules/StructuralUncertaintyIntersection/components/intersectionSettings.tsx
@@ -17,20 +17,11 @@ export const IntersectionSettingsSelect: React.FC = (
props.onChange({ ...props.intersectionSettings, extension });
}
};
- const handleZScaleChange = (e: any) => {
- const zScale = parseInt(e.target.value, 10);
- if (zScale >= 0) {
- props.onChange({ ...props.intersectionSettings, zScale });
- }
- };
return (
<>
-
>
);
};
diff --git a/frontend/src/modules/StructuralUncertaintyIntersection/loadModule.tsx b/frontend/src/modules/StructuralUncertaintyIntersection/loadModule.tsx
index 548f3e887..d08f23798 100644
--- a/frontend/src/modules/StructuralUncertaintyIntersection/loadModule.tsx
+++ b/frontend/src/modules/StructuralUncertaintyIntersection/loadModule.tsx
@@ -2,15 +2,14 @@ import { ModuleRegistry } from "@framework/ModuleRegistry";
import { Settings } from "./settings";
import { State } from "./state";
+import { StatisticOption, VisualizationMode } from "./types";
import { View } from "./view";
-import { VisualizationMode } from "./types";
-import { StatisticFunction_api } from "@api";
const defaultState: State = {
wellboreAddress: { uwi: "55/33-A-4", uuid: "drogon_horizontal", type: "smda" },
SurfaceSetAddress: null,
visualizationMode: VisualizationMode.STATISTICAL_LINES,
- statisticFunctions: [StatisticFunction_api.MEAN],
+ statisticFunctions: [StatisticOption.MEAN, StatisticOption.MIN_MAX, StatisticOption.P10_P90, StatisticOption.P50],
stratigraphyColorMap: {},
intersectionSettings: {
extension: 1000,
diff --git a/frontend/src/modules/StructuralUncertaintyIntersection/settings.tsx b/frontend/src/modules/StructuralUncertaintyIntersection/settings.tsx
index 44cb5f544..077191624 100644
--- a/frontend/src/modules/StructuralUncertaintyIntersection/settings.tsx
+++ b/frontend/src/modules/StructuralUncertaintyIntersection/settings.tsx
@@ -1,6 +1,6 @@
import React from "react";
-import { StatisticFunction_api, SurfaceAttributeType_api } from "@api";
+import { SurfaceAttributeType_api } from "@api";
import { EnsembleIdent } from "@framework/EnsembleIdent";
import { ModuleSettingsProps } from "@framework/Module";
import { useSettingsStatusWriter } from "@framework/StatusWriter";
@@ -29,6 +29,7 @@ import { RealizationsSelect } from "./components/realizationsSelect";
import { State } from "./state";
import {
StatisticFunctionEnumToStringMapping,
+ StatisticOption,
StratigraphyColorMap,
SurfaceSetAddress,
VisualizationMode,
@@ -208,7 +209,7 @@ export function Settings({
syncHelper.publishValue(SyncSettingKey.WELLBORE, "global.syncValue.wellBore", newWellboreAddress);
}
function makeStatisticCheckboxes() {
- return Object.values(StatisticFunction_api).map((value: StatisticFunction_api) => {
+ return Object.values(StatisticOption).map((value: StatisticOption) => {
return (
, statistic: StatisticFunction_api) {
+ function handleStatisticsChange(event: React.ChangeEvent, statistic: StatisticOption) {
setStatisticFunctions((prev) => {
if (event.target.checked) {
return prev ? [...prev, statistic] : [statistic];
diff --git a/frontend/src/modules/StructuralUncertaintyIntersection/state.ts b/frontend/src/modules/StructuralUncertaintyIntersection/state.ts
index 09e059767..82c55c101 100644
--- a/frontend/src/modules/StructuralUncertaintyIntersection/state.ts
+++ b/frontend/src/modules/StructuralUncertaintyIntersection/state.ts
@@ -1,13 +1,12 @@
-import { StatisticFunction_api } from "@api";
import { Wellbore } from "@framework/types/wellbore";
-import { IntersectionSettings, SurfaceSetAddress, VisualizationMode } from "./types";
+import { IntersectionSettings, StatisticOption, SurfaceSetAddress, VisualizationMode } from "./types";
export interface State {
wellboreAddress: Wellbore | null;
SurfaceSetAddress: SurfaceSetAddress | null;
visualizationMode: VisualizationMode;
stratigraphyColorMap: { [name: string]: string };
- statisticFunctions: StatisticFunction_api[];
+ statisticFunctions: StatisticOption[];
intersectionSettings: IntersectionSettings;
}
diff --git a/frontend/src/modules/StructuralUncertaintyIntersection/types.ts b/frontend/src/modules/StructuralUncertaintyIntersection/types.ts
index c89108351..88f17798e 100644
--- a/frontend/src/modules/StructuralUncertaintyIntersection/types.ts
+++ b/frontend/src/modules/StructuralUncertaintyIntersection/types.ts
@@ -1,5 +1,3 @@
-import { StatisticFunction_api } from "@api";
-
export type SeismicAddress = {
caseUuid: string;
ensemble: string;
@@ -16,19 +14,23 @@ export type SurfaceSetAddress = {
realizationNums: number[] | null;
};
-
export type IntersectionSettings = {
extension: number;
zScale: number;
};
+export enum StatisticOption {
+ MEAN = "Mean",
+ MIN_MAX = "Min/Max",
+ P10_P90 = "P10/P90",
+ P50 = "P50",
+}
+
export const StatisticFunctionEnumToStringMapping = {
- [StatisticFunction_api.MEAN]: "Mean",
- [StatisticFunction_api.MIN]: "Min",
- [StatisticFunction_api.MAX]: "Max",
- [StatisticFunction_api.P10]: "P10",
- [StatisticFunction_api.P50]: "P50",
- [StatisticFunction_api.P90]: "P90",
+ [StatisticOption.MEAN]: "Mean",
+ [StatisticOption.MIN_MAX]: "Min/Max",
+ [StatisticOption.P10_P90]: "P10/P90",
+ [StatisticOption.P50]: "P50",
};
export enum VisualizationMode {
diff --git a/frontend/src/modules/StructuralUncertaintyIntersection/view.tsx b/frontend/src/modules/StructuralUncertaintyIntersection/view.tsx
index ffd2b8b0d..fb63705ff 100644
--- a/frontend/src/modules/StructuralUncertaintyIntersection/view.tsx
+++ b/frontend/src/modules/StructuralUncertaintyIntersection/view.tsx
@@ -1,27 +1,34 @@
import React from "react";
-import { IntersectionReferenceSystem, Trajectory } from "@equinor/esv-intersection";
+import { IntersectionReferenceSystem, SurfaceData, SurfaceLine, Trajectory } from "@equinor/esv-intersection";
import { ModuleViewProps } from "@framework/Module";
import { useViewStatusWriter } from "@framework/StatusWriter";
-import { useElementSize } from "@lib/hooks/useElementSize";
import {
makeExtendedTrajectoryFromTrajectoryXyzPoints,
makeTrajectoryXyzPointsFromWellboreTrajectory,
} from "@modules/SeismicIntersection/utils/esvIntersectionDataConversion";
import { useWellboreTrajectoriesQuery } from "@modules/_shared/WellBore/queryHooks";
import { ContentError } from "@modules/_shared/components/ContentMessage";
+import {
+ EsvIntersection,
+ EsvIntersectionReadoutEvent,
+ LayerItem,
+ LayerType,
+ Viewport,
+} from "@modules/_shared/components/EsvIntersection";
+import { SurfaceStatisticalFanchart } from "@modules/_shared/components/EsvIntersection/layers/SurfaceStatisticalFanchartCanvasLayer";
+import { ReadoutItem } from "@modules/_shared/components/EsvIntersection/types";
+import { ReadoutBox } from "@modules/_shared/components/EsvIntersection/utilityComponents/ReadoutBox";
+import { Toolbar } from "@modules/_shared/components/EsvIntersection/utilityComponents/Toolbar";
+import { makeSurfaceStatisticalFanchartFromRealizationSurface } from "@modules/_shared/components/EsvIntersection/utils/surfaceStatisticalFancharts";
import { isEqual } from "lodash";
-import Legend from "./components/Legend";
-import { EsvIntersection } from "./components/esvIntersection";
import { useSampleSurfaceInPointsQueries } from "./queryHooks";
import { State } from "./state";
+import { StatisticOption, VisualizationMode } from "./types";
export const View = ({ viewContext }: ModuleViewProps) => {
- const wrapperDivRef = React.useRef(null);
- const wrapperDivSize = useElementSize(wrapperDivRef);
-
const statusWriter = useViewStatusWriter(viewContext);
const surfaceSetAddress = viewContext.useStoreValue("SurfaceSetAddress");
@@ -31,14 +38,17 @@ export const View = ({ viewContext }: ModuleViewProps) => {
const intersectionSettings = viewContext.useStoreValue("intersectionSettings");
const stratigraphyColorMap = viewContext.useStoreValue("stratigraphyColorMap");
+ const [readoutItems, setReadoutItems] = React.useState([]);
+ const [verticalScale, setVerticalScale] = React.useState(1);
+ const [viewport, setViewport] = React.useState([1000, 1650, 6000]);
+ const [referenceSystem, setReferenceSystem] = React.useState(null);
+
// Extended wellbore trajectory for creating intersection/fence extended on both sides of wellbore
const [extendedWellboreTrajectory, setExtendedWellboreTrajectory] = React.useState(null);
const [renderWellboreTrajectoryXyzPoints, setRenderWellboreTrajectoryXyzPoints] = React.useState(
null
);
- const width = wrapperDivSize.width;
- const height = wrapperDivSize.height - 100;
// Get well trajectories query
const getWellTrajectoriesQuery = useWellboreTrajectoriesQuery(wellboreAddress ? [wellboreAddress.uuid] : undefined);
@@ -63,13 +73,16 @@ export const View = ({ viewContext }: ModuleViewProps) => {
// When new well trajectory 3D points are loaded, update the render trajectory and clear the seismic fence image
if (!isEqual(trajectoryXyzPoints, renderWellboreTrajectoryXyzPoints)) {
setRenderWellboreTrajectoryXyzPoints(trajectoryXyzPoints);
+ if (renderWellboreTrajectoryXyzPoints) {
+ setReferenceSystem(new IntersectionReferenceSystem(trajectoryXyzPoints));
+ }
}
}
- const x_points = extendedWellboreTrajectory?.points.map((coord) => coord[0]) ?? [];
- const y_points = extendedWellboreTrajectory?.points.map((coord) => coord[1]) ?? [];
+ const xPoints = extendedWellboreTrajectory?.points.map((coord) => coord[0]) ?? [];
+ const yPoints = extendedWellboreTrajectory?.points.map((coord) => coord[1]) ?? [];
- const cum_length = extendedWellboreTrajectory
+ const cumLength = extendedWellboreTrajectory
? IntersectionReferenceSystem.toDisplacement(
extendedWellboreTrajectory.points,
extendedWellboreTrajectory.offset
@@ -82,8 +95,8 @@ export const View = ({ viewContext }: ModuleViewProps) => {
surfaceSetAddress?.names ?? [],
surfaceSetAddress?.attribute ?? "",
surfaceSetAddress?.realizationNums ?? [],
- x_points,
- y_points,
+ xPoints,
+ yPoints,
true
);
@@ -98,36 +111,204 @@ export const View = ({ viewContext }: ModuleViewProps) => {
if (errorString !== "") {
statusWriter.addError(errorString);
}
- const stratigraphyColorLegendItems =
- surfaceSetAddress?.names.map((key) => {
- return { color: stratigraphyColorMap[key], label: key };
- }) ?? [];
+
+ const handleReadoutItemsChange = React.useCallback(function handleReadoutItemsChange(
+ event: EsvIntersectionReadoutEvent
+ ): void {
+ setReadoutItems(event.readoutItems);
+ },
+ []);
+
+ const handleVerticalScaleIncrease = React.useCallback(function handleVerticalScaleIncrease(): void {
+ setVerticalScale((prev) => {
+ const newVerticalScale = prev + 0.1;
+ return newVerticalScale;
+ });
+ }, []);
+
+ const handleVerticalScaleDecrease = React.useCallback(function handleVerticalScaleIncrease(): void {
+ setVerticalScale((prev) => {
+ const newVerticalScale = Math.max(0.1, prev - 0.1);
+ return newVerticalScale;
+ });
+ }, []);
+
+ const handleFitInViewClick = React.useCallback(function handleFitInViewClick(): void {
+ setViewport([1000, 1650, 6000]);
+ }, []);
+
+ const handleViewportChange = React.useCallback(function handleViewportChange(newViewport: Viewport): void {
+ setViewport(newViewport);
+ }, []);
+
+ const layers: LayerItem[] = [];
+ if (cumLength && sampleSurfaceInPointsQueries.data) {
+ if (
+ visualizationMode === VisualizationMode.STATISTICAL_LINES ||
+ visualizationMode === VisualizationMode.STATISTICS_AND_REALIZATIONS
+ ) {
+ const surfaces = sampleSurfaceInPointsQueries.data;
+ const fancharts: SurfaceStatisticalFanchart[] = [];
+ const surfaceLines: SurfaceLine[] = [];
+ for (const surface of surfaces) {
+ const fanchart = makeSurfaceStatisticalFanchartFromRealizationSurface(
+ surface.realizationPoints.map((el) => el.sampled_values),
+ cumLength,
+ surface.surfaceName,
+ stratigraphyColorMap,
+ {
+ mean: statisticFunctions.includes(StatisticOption.MEAN),
+ minMax: statisticFunctions.includes(StatisticOption.MIN_MAX),
+ p10p90: statisticFunctions.includes(StatisticOption.P10_P90),
+ p50: statisticFunctions.includes(StatisticOption.P50),
+ }
+ );
+ fancharts.push(fanchart);
+
+ const surfaceLine: SurfaceLine = {
+ id: surface.surfaceName,
+ label: surface.surfaceName,
+ color: stratigraphyColorMap[surface.surfaceName] || "black",
+ data: fanchart.data.mean,
+ };
+
+ surfaceLines.push(surfaceLine);
+ }
+
+ layers.push({
+ type: LayerType.SURFACE_STATISTICAL_FANCHARTS_CANVAS,
+ id: "surface-fancharts",
+ options: {
+ data: {
+ fancharts,
+ },
+ order: 3,
+ },
+ hoverable: true,
+ });
+ layers.push({
+ type: LayerType.GEOMODEL_LABELS,
+ id: "surface-labels",
+ options: {
+ data: {
+ lines: surfaceLines,
+ areas: [],
+ },
+ maxFontSize: 16,
+ minFontSize: 10,
+ order: 4,
+ },
+ });
+ }
+ if (
+ visualizationMode === VisualizationMode.INDIVIDUAL_REALIZATIONS ||
+ visualizationMode === VisualizationMode.STATISTICS_AND_REALIZATIONS
+ ) {
+ const surfaceValues: { surfaceName: string; name: string; realization: number; values: number[] }[] = [];
+ const surfaces = sampleSurfaceInPointsQueries.data;
+ for (const surface of surfaces) {
+ for (const realization of surface.realizationPoints) {
+ surfaceValues.push({
+ surfaceName: surface.surfaceName,
+ name: `${surface.surfaceName}, real ${realization.realization}`,
+ realization: realization.realization,
+ values: realization.sampled_values,
+ });
+ }
+ }
+
+ const surfaceLines: SurfaceLine[] = [];
+ const labelSurfaceLines: SurfaceLine[] = [];
+ for (const realizationValues of surfaceValues) {
+ const surfaceLine: SurfaceLine = {
+ id: realizationValues.name + realizationValues.realization,
+ label: realizationValues.name,
+ color: stratigraphyColorMap[realizationValues.surfaceName] || "black",
+ data: realizationValues.values.map((z: number, idx) => {
+ return [cumLength[idx], z];
+ }),
+ };
+ surfaceLines.push(surfaceLine);
+
+ if (realizationValues.realization === 0) {
+ labelSurfaceLines.push({
+ ...surfaceLine,
+ label: realizationValues.surfaceName,
+ });
+ }
+ }
+
+ layers.push({
+ type: LayerType.GEOMODEL_V2,
+ id: "surface-realizations",
+ options: {
+ data: {
+ lines: surfaceLines,
+ areas: [],
+ },
+ order: 3,
+ },
+ hoverable: true,
+ });
+
+ layers.push({
+ type: LayerType.GEOMODEL_LABELS,
+ id: "surface-labels",
+ options: {
+ data: {
+ lines: labelSurfaceLines,
+ areas: [],
+ },
+ maxFontSize: 16,
+ minFontSize: 10,
+ order: 4,
+ },
+ });
+ }
+ }
+
+ if (renderWellboreTrajectoryXyzPoints) {
+ layers.push({
+ type: LayerType.WELLBORE_PATH,
+ id: "wellbore-trajectory",
+ options: {
+ stroke: "red",
+ strokeWidth: "2",
+ order: 6,
+ },
+ hoverable: true,
+ });
+ }
return (
-
+
{errorString !== "" ? (
{errorString}
) : (
<>
+
+
-
-
-
>
)}
diff --git a/frontend/src/modules/_shared/components/EsvIntersection/esvIntersection.tsx b/frontend/src/modules/_shared/components/EsvIntersection/esvIntersection.tsx
index 6840d2d92..dc1cd53e3 100644
--- a/frontend/src/modules/_shared/components/EsvIntersection/esvIntersection.tsx
+++ b/frontend/src/modules/_shared/components/EsvIntersection/esvIntersection.tsx
@@ -197,20 +197,20 @@ function makeLayer
(
export function EsvIntersection(props: EsvIntersectionProps): React.ReactNode {
const { onReadout, onViewportChange: onViewportChange } = props;
- const [prevAxesOptions, setPrevAxesOptions] = React.useState(null);
+ const [prevAxesOptions, setPrevAxesOptions] = React.useState(undefined);
const [prevIntersectionReferenceSystem, setPrevIntersectionReferenceSystem] = React.useState<
IntersectionReferenceSystem | null | undefined
>(null);
- const [prevShowGrid, setPrevShowGrid] = React.useState(null);
- const [prevContainerSize, setPrevContainerSize] = React.useState(null);
- const [prevLayers, setPrevLayers] = React.useState(null);
- const [prevBounds, setPrevBounds] = React.useState(null);
+ const [prevShowGrid, setPrevShowGrid] = React.useState(undefined);
+ const [prevContainerSize, setPrevContainerSize] = React.useState(undefined);
+ const [prevLayers, setPrevLayers] = React.useState(undefined);
+ const [prevBounds, setPrevBounds] = React.useState(undefined);
const [currentViewport, setCurrentViewport] = React.useState(null);
- const [prevViewport, setPrevViewport] = React.useState(null);
- const [prevShowAxesLabels, setPrevShowAxesLabels] = React.useState(null);
- const [prevShowAxes, setPrevShowAxes] = React.useState(null);
- const [prevZFactor, setPrevZFactor] = React.useState(null);
- const [prevHighlightItems, setPrevHighlightItems] = React.useState(null);
+ const [prevViewport, setPrevViewport] = React.useState(undefined);
+ const [prevShowAxesLabels, setPrevShowAxesLabels] = React.useState(undefined);
+ const [prevShowAxes, setPrevShowAxes] = React.useState(undefined);
+ const [prevZFactor, setPrevZFactor] = React.useState(undefined);
+ const [prevHighlightItems, setPrevHighlightItems] = React.useState(undefined);
const [layerIds, setLayerIds] = React.useState([]);
@@ -313,12 +313,12 @@ export function EsvIntersection(props: EsvIntersectionProps): React.ReactNode {
}
if (
- !(prevViewport && props.viewport) ||
- (!prevViewport && props.viewport) ||
- (prevViewport && !props.viewport) ||
- !fuzzyCompare(prevViewport[0], props.viewport[0], 0.0001) ||
- !fuzzyCompare(prevViewport[1], props.viewport[1], 0.0001) ||
- !fuzzyCompare(prevViewport[2], props.viewport[2], 0.0001)
+ !isEqual(prevViewport, props.viewport) ||
+ (prevViewport &&
+ props.viewport &&
+ (!fuzzyCompare(prevViewport[0], props.viewport[0], 0.0001) ||
+ !fuzzyCompare(prevViewport[1], props.viewport[1], 0.0001) ||
+ !fuzzyCompare(prevViewport[2], props.viewport[2], 0.0001)))
) {
if (props.viewport) {
if (
@@ -461,14 +461,14 @@ export function EsvIntersection(props: EsvIntersectionProps): React.ReactNode {
setInteractionHandler(null);
setLayerIds([]);
setPrevLayers([]);
- setPrevAxesOptions(null);
+ setPrevAxesOptions(undefined);
setPrevIntersectionReferenceSystem(null);
- setPrevShowGrid(null);
- setPrevContainerSize(null);
- setPrevBounds(null);
- setPrevViewport(null);
- setPrevShowAxesLabels(null);
- setPrevShowAxes(null);
+ setPrevShowGrid(undefined);
+ setPrevContainerSize(undefined);
+ setPrevBounds(undefined);
+ setPrevViewport(undefined);
+ setPrevShowAxesLabels(undefined);
+ setPrevShowAxes(undefined);
newPixiRenderApplication.destroy();
newEsvController.removeAllLayers();
newEsvController.destroy();
@@ -483,7 +483,7 @@ export function EsvIntersection(props: EsvIntersectionProps): React.ReactNode {
>
);
diff --git a/frontend/src/modules/_shared/components/EsvIntersection/layers/SurfaceStatisticalFanchartCanvasLayer.ts b/frontend/src/modules/_shared/components/EsvIntersection/layers/SurfaceStatisticalFanchartCanvasLayer.ts
index a2c3243ec..2c13209be 100644
--- a/frontend/src/modules/_shared/components/EsvIntersection/layers/SurfaceStatisticalFanchartCanvasLayer.ts
+++ b/frontend/src/modules/_shared/components/EsvIntersection/layers/SurfaceStatisticalFanchartCanvasLayer.ts
@@ -102,7 +102,7 @@ export class SurfaceStatisticalFanchartsCanvasLayer {
+ return (
+
+ {additionalInformationItemToReadableString(key, value)}
+
+ );
+ });
+}
+
+export function ReadoutBox(props: ReadoutBoxProps): React.ReactNode {
+ if (props.readoutItems.length === 0) {
+ return null;
+ }
+
+ return (
+
+ {props.readoutItems.map((item, index) => {
+ if (index < (props.maxNumItems ?? 3)) {
+ return (
+
+
+
+ {getLabelFromLayerData(item)}
+
+ {makeAdditionalInformation(item)}
+
+
+ );
+ }
+ })}
+ {props.readoutItems.length > (props.maxNumItems ?? 3) && (
+
+ ...and {props.readoutItems.length - (props.maxNumItems ?? 3)} more
+
+ )}
+
+ );
+}
diff --git a/frontend/src/modules/_shared/components/EsvIntersection/utilityComponents/Toolbar.tsx b/frontend/src/modules/_shared/components/EsvIntersection/utilityComponents/Toolbar.tsx
new file mode 100644
index 000000000..e63f3d67b
--- /dev/null
+++ b/frontend/src/modules/_shared/components/EsvIntersection/utilityComponents/Toolbar.tsx
@@ -0,0 +1,55 @@
+import { Button } from "@lib/components/Button";
+import { HoldPressedIntervalCallbackButton } from "@lib/components/HoldPressedIntervalCallbackButton/holdPressedIntervalCallbackButton";
+import { Add, FilterCenterFocus, Remove } from "@mui/icons-material";
+
+export type ToolbarProps = {
+ visible: boolean;
+ zFactor: number;
+ onFitInView: () => void;
+ onVerticalScaleIncrease: () => void;
+ onVerticalScaleDecrease: () => void;
+};
+
+export function Toolbar(props: ToolbarProps): React.ReactNode {
+ function handleFitInViewClick() {
+ props.onFitInView();
+ }
+
+ function handleVerticalScaleIncrease() {
+ props.onVerticalScaleIncrease();
+ }
+
+ function handleVerticalScaleDecrease() {
+ props.onVerticalScaleDecrease();
+ }
+
+ if (!props.visible) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+
+
{props.zFactor.toFixed(2)}
+
+
+
+
+ );
+}
+
+function ToolBarDivider(): React.ReactNode {
+ return ;
+}
diff --git a/frontend/src/modules/_shared/components/EsvIntersection/utils/surfaceStatisticalFancharts.ts b/frontend/src/modules/_shared/components/EsvIntersection/utils/surfaceStatisticalFancharts.ts
index ffbcf33d0..5e8b5ea0d 100644
--- a/frontend/src/modules/_shared/components/EsvIntersection/utils/surfaceStatisticalFancharts.ts
+++ b/frontend/src/modules/_shared/components/EsvIntersection/utils/surfaceStatisticalFancharts.ts
@@ -22,7 +22,7 @@ function mergeXAndYArrays(arrayX: number[], arrayY: number[]): number[][] {
return arrayX.map((x, i) => [x, arrayY[i]]);
}
-export function makeSurfaceStatisticalFanchartFromRealizationSurfaces(
+export function makeSurfaceStatisticalFanchartFromRealizationSurface(
realizationSamplePoints: number[][],
cumulatedLength: number[],
surfaceName: string,