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: