Log Cutoff Visual

LogCutoffVisual is another type of visual supported by WellLogJS. A LogCutoffVisual needs a well log data source either passed into its constructor or set using the setData method. The visual will not render if there is no data associated with it.
Properties like LineStyle, FillStyle, Cutoff etc. can be modified. The limits are calculated automatically by default, but manual limits can be set by disabling autolimits.

# Example Log Cutoff Visuals

Here are three examples of LogCutoff: continuous (left), discrete visual (center), and categorized (right), categorized mode supports continuous and discrete mode as well. See the code below.

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { LogLinearValueGrid } from "@int/geotoolkit/welllog/LogLinearValueGrid.ts";
import { CutoffMode, DisplayMode as CutoffDisplayMode, LogCutoffVisual } from "@int/geotoolkit/welllog/LogCutoffVisual.ts";
import { LogCurve } from "@int/geotoolkit/welllog/LogCurve.ts";
import { LogData } from "@int/geotoolkit/welllog/data/LogData.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { CirclePainter } from "@int/geotoolkit/scene/shapes/painters/CirclePainter.ts";
import { InterpolationType } from "@int/geotoolkit/data/DataStepInterpolation.ts";
import { FillStyle } from "@int/geotoolkit/attributes/FillStyle.ts";
import { SymbolShape } from "@int/geotoolkit/scene/shapes/SymbolShape.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
function createSymbol(color) {
  const size = 6;
  return new SymbolShape(
    0,
    0,
    size,
    size,
    AnchorType.Center,
    false,
    CirclePainter
  ).setLineStyle({
    "color": color,
    "width": 1
  }).setFillStyle("white");
}
function createScene(canvas) {
  const widget = createWellLogWidget().setAxisHeaderType(HeaderType.Scale).setDepthLimits(100, 500);
  const logData = new LogData({
    "name": "Step curve",
    "depths": [100, 116, 132, 148, 164, 180, 196, 212, 228, 244, 260, 276, 292, 308, 324, 340, 356, 372, 388, 404, 420, 436, 452, 468, 484, 500],
    "values": [0, 0, 10, 10, 10, 20, 10, 30, 30, 10, 10, 10, 20, 20, 30, 70, 30, 30, 50, 30, 10, 60, 40, 10, 0, 0]
  });
  const min = 0;
  const max = 100;
  const logCurve = new LogCurve(logData).setInterpolationType(InterpolationType.EndStep).setLineStyle({
    "color": "blue",
    "width": 2,
    "shadow": {
      "enable": true,
      "blur": 3,
      "color": "white"
    }
  }).setDisplayMode(["line", "symbol"]).setSymbol(createSymbol("blue")).setNormalizationLimits(min, max);
  const logCuttoffVisual = new LogCutoffVisual({
    "cutoffmode": CutoffMode.Continuous,
    "data": logData,
    "linestyle": null,
    "fillstyle": "orange"
  }).setNormalizationLimits(min, max).setCutOff({
    "names": ["First Part", "Second Section", "Third Section", "Best Intervals"],
    "ranges": [0, 16, 38, 54, 100],
    "fillstyles": [
      new FillStyle("#92D050"),
      new FillStyle("#FF3232"),
      new FillStyle("#27E2FF"),
      new FillStyle("#0065B0")
    ]
  });
  widget.addTrack(TrackType.IndexTrack);
  widget.addTrack(TrackType.LinearTrack).addChild([
    logCuttoffVisual.setName("Continuous mode"),
    logCurve
  ]);
  widget.addTrack(TrackType.IndexTrack);
  widget.addTrack(TrackType.LinearTrack).addChild([
    logCuttoffVisual.clone().setName("Discrete mode").setCutoffMode(CutoffMode.Discrete),
    logCurve.clone()
  ]);
  widget.addTrack(TrackType.IndexTrack);
  widget.addTrack(TrackType.AnnotationTrack).addChild([
    new LogCutoffVisual({
      "name": "Categorized mode",
      "data": {
        "name": "Signal curve",
        "depths": [100, 116, 132, 148, 164, 180, 196, 212, 228, 244, 260, 276, 292, 308, 324, 340, 356, 372, 388, 404, 420, 436, 452, 468, 484, 500],
        "values": ["A", "B", "D", "D-1", "D-2", "D-4", "C", "B", "C", "G", "G", "G", "E", "E", "J-is-out-of-index", "K-is-out-of-range", "G", "G", "H", "F", "H", "H", "H", "G", "F", "D"]
      },
      "cutoffmode": CutoffMode.Discrete,
      "displaymode": CutoffDisplayMode.Categorized,
      "linestyle": null
    }).setName("Categorized mode").setCutOff({
      "names": [
        "Cutoff A",
        "Cutoff B",
        "Cutoff C",
        'Cutoff <b>D</b> <span style="color:#0065B0">[1..4]</span>',
        "Cutoff E",
        "Cutoff F",
        "Cutoff G",
        "Cutoff H"
      ],
      "codes": ["A", "B", "C", ["D", "D-1", "D-2", "D-4"], "E", "F", "G", "H"],
      "fillstyles": [
        new FillStyle("#92D050"),
        new FillStyle("#FF3232"),
        new FillStyle("#27E2FF"),
        new FillStyle("#0065B0"),
        new FillStyle("#E26714"),
        new FillStyle("#ABF55B"),
        new FillStyle("#AFDDFF"),
        new FillStyle("#FF7DFF")
      ]
    }),
    new LogLinearValueGrid().setSelectable(false).setLineStyle({
      "color": "gray",
      "pixelsnapmode": true
    }).setLinesCount(9)
  ]);
  widget.addTrack(TrackType.IndexTrack);
  widget.setCss({
    "css": [
      ".geotoolkit.welllog.header.LogCutoffVisualHeader {",
      "   linestyle-color: gray;",
      "   linestyle-pixelsnapmode: true;",
      "   subtitle-padding-top: 15px;",
      "   subtitle-padding-left: 5px;",
      "   subtitle-padding-right: 5px;",
      "   subtitle-padding-bottom: 5px;",
      "   subtitle-icon-margins-top: 15px;",
      "   subtitle-icon-size: 12;",
      "}",
      '.geotoolkit.welllog.LogTrack[cssclass!="INDEX_TRACK"] {',
      "   linestyle-color: gray;",
      "   linestyle-pixelsnapmode: true;",
      "   clipping : false;",
      "}"
    ].join("")
  });
  widget.getToolByName("cross-hair").setEnabled(false);
  const plot = new Plot({
    "canvaselement": canvas,
    "root": widget
  });
  widget.setHeaderHeight("auto").fitToWidth().fitToHeight();
  return plot;
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));

# Additional options available for Log Cutoff Visuals

Here is an example of additional settings you can apply to LogCutoff visual and the header. See the code below.

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { LogLinearValueGrid } from "@int/geotoolkit/welllog/LogLinearValueGrid.ts";
import { CutoffMode, DisplayMode as CutoffDisplayMode, LogCutoffVisual, StepMode } from "@int/geotoolkit/welllog/LogCutoffVisual.ts";
import { LogCurve } from "@int/geotoolkit/welllog/LogCurve.ts";
import { LogData } from "@int/geotoolkit/welllog/data/LogData.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { CirclePainter } from "@int/geotoolkit/scene/shapes/painters/CirclePainter.ts";
import { InterpolationType } from "@int/geotoolkit/data/DataStepInterpolation.ts";
import { FillStyle } from "@int/geotoolkit/attributes/FillStyle.ts";
import { SymbolShape } from "@int/geotoolkit/scene/shapes/SymbolShape.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { Orientation } from "@int/geotoolkit/util/Orientation.ts";
import { VerticalAlignment } from "@int/geotoolkit/util/VerticalAlignment.ts";
import { HorizontalAlignment } from "@int/geotoolkit/util/HorizontalAlignment.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
function createSymbol(color) {
  const size = 6;
  return new SymbolShape(
    0,
    0,
    size,
    size,
    AnchorType.Center,
    false,
    CirclePainter
  ).setLineStyle({
    "color": color,
    "width": 1
  }).setFillStyle("white");
}
function createScene(canvas) {
  const widget = createWellLogWidget().setOrientation(Orientation.Horizontal).setAxisHeaderType(HeaderType.Scale).setDepthLimits(100, 500);
  const logData = new LogData({
    "name": "Cutoff curve",
    "depths": [100, 116, 132, 148, 164, 180, 196, 212, 228, 244, 260, 276, 292, 308, 324, 340, 356, 372, 388, 404, 420, 436, 452, 468, 484, 500],
    "values": [0, 0, 10, 10, 10, 20, 10, 30, 30, 10, 10, 10, 20, 20, 30, 70, 30, 30, 50, 30, 10, 60, 40, 10, 0, 0]
  });
  const min = 0;
  const max = 100;
  const logCurve = new LogCurve(logData).setInterpolationType(InterpolationType.EndStep).setLineStyle({
    "color": "blue",
    "width": 2,
    "shadow": {
      "enable": true,
      "blur": 3,
      "color": "white"
    }
  }).setDisplayMode(["line", "symbol"]).setSymbol(createSymbol("blue")).setNormalizationLimits(min, max);
  const logCuttoffVisual = new LogCutoffVisual({
    "cutoffmode": CutoffMode.Continuous,
    "data": logData,
    "linestyle": null,
    "fillstyle": "orange"
  }).setNormalizationLimits(min, max).setCutOff({
    "names": ["First Part", "Second Section", "Third Section", "Best Intervals"],
    "ranges": [0, 16, 38, 54, 100],
    "fillstyles": [
      new FillStyle("#92D050"),
      new FillStyle("#FF3232"),
      new FillStyle("#27E2FF"),
      new FillStyle("#0065B0")
    ]
  });
  widget.addTrack(TrackType.IndexTrack);
  widget.addTrack(TrackType.LinearTrack).addChild([
    logCuttoffVisual.setName('Continuous mode<br/><i style="color:gray">End-step</i>'),
    logCurve
  ]);
  widget.getHeaderContainer().getHeaderProvider().getHeader(logCuttoffVisual).setTitleAlignment(HorizontalAlignment.Left).setSubTitleAlignment(VerticalAlignment.Top);
  widget.addTrack(TrackType.IndexTrack);
  let logCuttoffVisual2;
  widget.addTrack(TrackType.LinearTrack).addChild([
    logCuttoffVisual2 = logCuttoffVisual.clone().setName('Discrete mode<br/><i style="color:gray">Srart-step, reversed</i>').setHorizontalFlip(true).setCutoffMode(CutoffMode.Discrete).setStepMode(StepMode.StartStep),
    logCurve.clone().setInterpolationType(InterpolationType.StartStep).setHorizontalFlip(true)
  ]);
  widget.getHeaderContainer().getHeaderProvider().getHeader(logCuttoffVisual2).setTitleAlignment(HorizontalAlignment.Right).setSubTitleIconAlignment(VerticalAlignment.Top).setSubTitleAlignment(VerticalAlignment.Bottom).setSubTitleIconSize(15).setSubTitleIconRadius(8);
  widget.addTrack(TrackType.IndexTrack);
  let logCuttoffVisual3;
  widget.addTrack(TrackType.AnnotationTrack).addChild([
    logCuttoffVisual3 = new LogCutoffVisual({
      "name": "Categorized mode",
      "data": {
        "name": "Signal curve",
        "depths": [100, 116, 132, 148, 164, 180, 196, 212, 228, 244, 260, 276, 292, 308, 324, 340, 356, 372, 388, 404, 420, 436, 452, 468, 484, 500],
        "values": ["A", "B", "D", "D-1", "D-2", "D-4", "C", "B", "C", "G", "G", "G", "E", "E", "J-is-out-of-index", "K-is-out-of-range", "G", "G", "H", "F", "H", "H", "H", "G", "F", "D"]
      },
      "cutoffmode": CutoffMode.Discrete,
      "displaymode": CutoffDisplayMode.Categorized,
      "linestyle": null
    }).setName("Categorized mode").setCutOff({
      "names": [
        "Cutoff A",
        "Cutoff B",
        "Cutoff C",
        '<span style="color:white">Cutoff <b>D</b> <i>[1..4]</i></span>',
        "Cutoff E",
        "Cutoff F",
        "Cutoff G",
        "Cutoff H"
      ],
      "codes": ["A", "B", "C", ["D", "D-1", "D-2", "D-4"], "E", "F", "G", "H"],
      "fillstyles": [
        new FillStyle("#92D050"),
        new FillStyle("#FF3232"),
        new FillStyle("#27E2FF"),
        new FillStyle("#0065B0"),
        new FillStyle("#E26714"),
        new FillStyle("#ABF55B"),
        new FillStyle("#AFDDFF"),
        new FillStyle("#FF7DFF")
      ]
    }).setHorizontalFlip(true),
    new LogLinearValueGrid().setSelectable(false).setLineStyle({
      "color": "gray",
      "pixelsnapmode": true
    }).setLinesCount(9)
  ]);
  widget.getHeaderContainer().getHeaderProvider().getHeader(logCuttoffVisual3).setSubTitleIconAlignment(VerticalAlignment.Center).setSubTitleAlignment(VerticalAlignment.Center);
  widget.addTrack(TrackType.IndexTrack);
  widget.setCss({
    "css": [
      ".geotoolkit.welllog.header.LogCutoffVisualHeader {",
      "   linestyle-color: gray;",
      "   linestyle-pixelsnapmode: true;",
      "   title-size-min: 40;",
      "   subtitle-size-min: 140;",
      "   subtitle-padding: 5px;",
      "   subtitle-icon-size: 15;",
      "}",
      '.geotoolkit.welllog.LogTrack[cssclass!="INDEX_TRACK"] {',
      "   linestyle-color: gray;",
      "   linestyle-pixelsnapmode: true;",
      "   clipping : false;",
      "}"
    ].join("")
  });
  widget.getToolByName("cross-hair").setEnabled(false);
  const plot = new Plot({
    "canvaselement": canvas,
    "root": widget
  });
  widget.setHeaderHeight("auto").fitToWidth().fitToHeight();
  return plot;
}
export { createScene };

createScene(document.querySelector('[ref="plot"]'));