Marker Set

This tutorial assumes familiarity with the basic Markers tutorial in WellLog. This tutorial builds upon those basics and demonstrates how to create a CustomMarker visual with advanced layout capabilities (see ILayout1D, ILayoutElement1D and MarkerSetLayout). The WellLog widget's highly extensible properties allow creation of custom well log visuals like Composite Markers , which can clearly display overlapping markers.

# Regular Markers

If the number of markers in a track increases, regular LogMarkers may become visually indistinguishable. GeoToolkitJS provides classes like MarkerSet and MarkerSetLayout to deal with cases like the one shown below.

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { LogMarker } from "@int/geotoolkit/welllog/LogMarker.ts";
import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { createCurve } from "/src/code/WellLog/utils/curveData.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
function createScene(canvas) {
  const minDepth = 5e3, maxDepth = 1e4;
  const widget = createWellLogWidget({
    "range": new Range(minDepth, maxDepth)
  }).setAxisHeaderType(HeaderType.Simple);
  widget.addTrack(TrackType.IndexTrack);
  const cDepth = (minDepth + maxDepth) / 2;
  const depths = [], n = 7;
  for (let i = -n; i <= n; i++) {
    depths.push(cDepth + i);
  }
  const colors = ["red", "green", "blue", "violet", "orange"];
  const markers = depths.map((depth, i) => new LogMarker(depth, "Marker# " + i).setLineStyle(colors[i % colors.length]).setTextStyle({
    "color": colors[i % colors.length],
    "font": "bold 14px Arial"
  }).setNameLabelPosition(AnchorType.Center).setVisibleDepthLabel(false));
  widget.addTrack(TrackType.LinearTrack).setWidth(240).addChild(createCurve(minDepth, 10, "GR", "#7cb342")).addChild(markers);
  const plot = new Plot({
    "canvaselement": canvas,
    "root": widget
  });
  widget.setVisibleDepthLimits(minDepth, maxDepth);
  return plot;
}
export { createScene };

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

# MarkerSet

Markers in MarkerSet are visually distributed along the MD-axis by the layout of their welllog track.

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { MarkerSet } from "@int/geotoolkit/welllog/MarkerSet.ts";
import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { MarkerSetLayout } from "@int/geotoolkit/welllog/layout/MarkerSetLayout.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { CustomMarker } from "/src/code/WellLog/Visuals/MarkerSet/shapes/customMarker.ts";
import { createCurve } from "/src/code/WellLog/utils/curveData.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
function createScene(canvas) {
  const minDepth = 5e3, maxDepth = 1e4;
  const widget = createWellLogWidget({
    "range": new Range(minDepth, maxDepth)
  }).setAxisHeaderType(HeaderType.Simple);
  widget.addTrack(TrackType.IndexTrack);
  const cDepth = (minDepth + maxDepth) / 2;
  const depths = [], n = 7;
  for (let i = -n; i <= n; i++) {
    depths.push(cDepth + i);
  }
  const colors = ["red", "green", "blue", "violet", "orange"];
  const markers = depths.map((depth, i) => new CustomMarker({
    "depth": depth,
    "nameLabel": "Marker# " + i
  }).setLineStyle(colors[i % colors.length]).setTextStyle({
    "color": colors[i % colors.length],
    "font": "bold 14px Arial"
  }));
  const markerSetOptions = {
    "visiblenamelabel": true,
    "visibledepthlabel": false,
    "namelabelposition": AnchorType.Center,
    "depthlabelposition": AnchorType.Center,
    "visiblenameborder": false,
    "visibledepthborder": false,
    "layout": new MarkerSetLayout({ "overlap": "all" }),
    "showoverlappedlabels": true
  };
  const markerSet = new MarkerSet(markerSetOptions).addChild(markers);
  widget.addTrack(TrackType.LinearTrack).setWidth(240).addChild(createCurve(minDepth, 10, "GR", "#7cb342")).addChild(markerSet);
  const plot = new Plot({
    "canvaselement": canvas,
    "root": widget
  });
  widget.setVisibleDepthLimits(minDepth, maxDepth);
  return plot;
}
export { createScene };

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

Track's depth limits are the values that define maximal extent where a visual can be displayed, so if markers in a set do not fit the limits then the following layout options are available.

1. Overlap the markers evenly:

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { MarkerSet } from "@int/geotoolkit/welllog/MarkerSet.ts";
import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { MarkerSetLayout } from "@int/geotoolkit/welllog/layout/MarkerSetLayout.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { CustomMarker } from "/src/code/WellLog/Visuals/MarkerSet/shapes/customMarker.ts";
import { createCurve } from "/src/code/WellLog/utils/curveData.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
function createScene(canvas) {
  const minDepth = 5e3, maxDepth = 1e4;
  const widget = createWellLogWidget({
    "range": new Range(minDepth, maxDepth)
  }).setAxisHeaderType(HeaderType.Simple);
  widget.addTrack(TrackType.IndexTrack);
  const cDepth = (minDepth + maxDepth) / 2;
  const depths = [], n = 7;
  for (let i = -n; i <= n; i++) {
    depths.push(cDepth + i);
  }
  const colors = ["red", "green", "blue", "violet", "orange"];
  const markers = depths.map((depth, i) => new CustomMarker({
    "depth": depth,
    "nameLabel": "Marker# " + i
  }).setLineStyle(colors[i % colors.length]).setTextStyle({
    "color": colors[i % colors.length],
    "font": "bold 14px Arial"
  }));
  const markerSet = new MarkerSet({
    "visiblenamelabel": true,
    "visibledepthlabel": false,
    "namelabelposition": AnchorType.Center,
    "depthlabelposition": AnchorType.Center,
    "visiblenameborder": false,
    "visibledepthborder": false,
    "layout": new MarkerSetLayout({ "overlap": "all" }),
    "showoverlappedlabels": true
  }).addChild(markers);
  widget.addTrack(TrackType.LinearTrack).setWidth(240).addChild(createCurve(minDepth, 10, "GR", "#7cb342")).addChild(markerSet);
  const plot = new Plot({
    "canvaselement": canvas,
    "root": widget
  });
  widget.setVisibleDepthLimits(minDepth, maxDepth);
  return plot;
}
export { createScene };

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

2. Another option is display non-overlapped as many markers as possible, while drawing the rest on top of each other:

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { MarkerSet } from "@int/geotoolkit/welllog/MarkerSet.ts";
import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { MarkerSetLayout } from "@int/geotoolkit/welllog/layout/MarkerSetLayout.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { CustomMarker } from "/src/code/WellLog/Visuals/MarkerSet/shapes/customMarker.ts";
import { createCurve } from "/src/code/WellLog/utils/curveData.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
function createScene(canvas) {
  const minDepth = 5e3, maxDepth = 1e4;
  const widget = createWellLogWidget({
    "range": new Range(minDepth, maxDepth)
  }).setAxisHeaderType(HeaderType.Simple);
  widget.addTrack(TrackType.IndexTrack);
  const cDepth = (minDepth + maxDepth) / 2;
  const depths = [], n = 7;
  for (let i = -n; i <= n; i++) {
    depths.push(cDepth + i);
  }
  const colors = ["red", "green", "blue", "violet", "orange"];
  const markers = depths.map((depth, i) => new CustomMarker({
    "depth": depth,
    "nameLabel": "Marker# " + i
  }).setLineStyle(colors[i % colors.length]).setTextStyle({
    "color": colors[i % colors.length],
    "font": "bold 14px Arial"
  }));
  const markerSet = new MarkerSet({
    "visiblenamelabel": true,
    "visibledepthlabel": false,
    "namelabelposition": AnchorType.Center,
    "depthlabelposition": AnchorType.Center,
    "visiblenameborder": false,
    "visibledepthborder": false,
    "layout": new MarkerSetLayout({ "overlap": "some" }),
    "showoverlappedlabels": true
  }).addChild(markers);
  widget.addTrack(TrackType.LinearTrack).setWidth(240).addChild(createCurve(minDepth, 10, "GR", "#7cb342")).addChild(markerSet);
  const plot = new Plot({
    "canvaselement": canvas,
    "root": widget
  });
  widget.setVisibleDepthLimits(minDepth, maxDepth);
  return plot;
}
export { createScene };

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

3. This option allows displaying only the non overlapping markers and hide the overlapping markers:

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { MarkerSet } from "@int/geotoolkit/welllog/MarkerSet.ts";
import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { MarkerSetLayout } from "@int/geotoolkit/welllog/layout/MarkerSetLayout.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { CustomMarker } from "/src/code/WellLog/Visuals/MarkerSet/shapes/customMarker.ts";
import { createCurve } from "/src/code/WellLog/utils/curveData.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
function createScene(canvas) {
  const minDepth = 5e3, maxDepth = 1e4;
  const widget = createWellLogWidget({
    "range": new Range(minDepth, maxDepth)
  }).setAxisHeaderType(HeaderType.Simple);
  widget.addTrack(TrackType.IndexTrack);
  const cDepth = (minDepth + maxDepth) / 2;
  const depths = [], n = 7;
  for (let i = -n; i <= n; i++) {
    depths.push(cDepth + i);
  }
  const colors = ["red", "green", "blue", "violet", "orange"];
  const markers = depths.map((depth, i) => new CustomMarker({
    "depth": depth,
    "nameLabel": "Marker# " + i
  }).setLineStyle(colors[i % colors.length]).setTextStyle({
    "color": colors[i % colors.length],
    "font": "bold 14px Arial"
  }));
  const markerSet = new MarkerSet({
    "visiblenamelabel": true,
    "visibledepthlabel": false,
    "namelabelposition": AnchorType.Center,
    "depthlabelposition": AnchorType.Center,
    "visiblenameborder": false,
    "visibledepthborder": false,
    "layout": new MarkerSetLayout({ "overlap": "some" }),
    "showoverlappedlabels": false
  }).addChild(markers);
  widget.addTrack(TrackType.LinearTrack).setWidth(240).addChild(createCurve(minDepth, 10, "GR", "#7cb342")).addChild(markerSet);
  const plot = new Plot({
    "canvaselement": canvas,
    "root": widget
  });
  widget.setVisibleDepthLimits(minDepth, maxDepth);
  return plot;
}
export { createScene };

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

4. Beside track's depth limits, markers in a set may occupy a restricted section of an area:

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { AnchorType } from "@int/geotoolkit/util/AnchorType.ts";
import { MarkerSet } from "@int/geotoolkit/welllog/MarkerSet.ts";
import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { MarkerSetLayout } from "@int/geotoolkit/welllog/layout/MarkerSetLayout.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { CustomMarker } from "/src/code/WellLog/Visuals/MarkerSet/shapes/customMarker.ts";
import { createCurve } from "/src/code/WellLog/utils/curveData.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
function createScene(canvas) {
  const minDepth = 5e3, maxDepth = 1e4;
  const widget = createWellLogWidget({
    "range": new Range(minDepth, maxDepth)
  }).setAxisHeaderType(HeaderType.Simple);
  widget.addTrack(TrackType.IndexTrack);
  const cDepth = (minDepth + maxDepth) / 2;
  const depths = [], n = 7;
  for (let i = -n; i <= n; i++) {
    depths.push(cDepth + i);
  }
  const colors = ["red", "green", "blue", "violet", "orange"];
  const markers = depths.map((depth, i) => new CustomMarker({
    "depth": depth,
    "nameLabel": "Marker# " + i
  }).setLineStyle(colors[i % colors.length]).setTextStyle({
    "color": colors[i % colors.length],
    "font": "bold 14px Arial"
  }));
  const markerSet = new MarkerSet({
    "visiblenamelabel": true,
    "visibledepthlabel": false,
    "namelabelposition": AnchorType.Center,
    "depthlabelposition": AnchorType.Center,
    "visiblenameborder": false,
    "visibledepthborder": false,
    "layout": new MarkerSetLayout({ "overlap": "some", "maxoffset": 40 }),
    "showoverlappedlabels": false
  }).addChild(markers);
  widget.addTrack(TrackType.LinearTrack).setWidth(240).addChild(createCurve(minDepth, 10, "GR", "#7cb342")).addChild(markerSet);
  const plot = new Plot({
    "canvaselement": canvas,
    "root": widget
  });
  widget.setVisibleDepthLimits(minDepth, maxDepth);
  return plot;
}
export { createScene };

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

# Code Highlights

Besides being a LogMarker child, to be able to get layouted CustomMarker visual shall implement the ILayoutElement1D interface:

import {LogMarker} from '@int/geotoolkit/welllog/LogMarker';
import {ILayoutElement1D} from '@int/geotoolkit/layout/ILayoutElement1D';
import {implementsInterface} from '@int/geotoolkit/base';
import {obfuscate} from '@int/geotoolkit/lib';

export class CustomMarker extends LogMarker {
    constructor (options) {
        super(...);
        ...
    }

    // ILayoutElement1D implementation:
    getValue () {
        return this.getDepth();
    }
}
implementsInterface(CustomMarker, ILayoutElement1D);
obfuscate(CustomMarker);

Now it can be layouted by means of MarkerSetLayout (a ILayout1D implementation) set on MarkerSet class: