Custom Visual

This tutorial show how to create own simple visual with sinus and circle geometry

To implement a custom visual, perform these steps:

# I. Extend base class. It can be LogAbstractVisual

# Implement rendering method

Implement .renderContent() - the method determines what to draw

# Set up model limits

Override .getModelLimits() if need. By default visual has track's model limits

# Set up serialization

Override .setProperties() and .getProperties() if serialisation is needed

# Provide data

Add data setting via .setData() or constructor. Name and type can vary, it's up to the author.

# II. Adding own tooltip

To add custom tooltip, perform these steps:

# Handle selection in visual

In .renderContent() implement selection

# Add hit test to visual

Add method .hitTest() which creates Selector

# Create new class for Tooltip

Create own tooltip extending NodeTooltip, it should call .hitTest() to get the data

# Register tooltip

Create ToolTipTool instance and register there custom tooltip

# III. Adding own header

To add custom tooltip, perform these steps:

# Create new class for header

Extend new class from LogVisualHeader, implement render() and clone() methods

# Register header

Add custom header to LogVisualHeaderProvider - existing one or new one

# Full example

import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
import { SineVisual } from "/src/code/WellLog/Visuals/CustomVisual/SineVisual.ts";
import { FillStyle } from "@int/geotoolkit/attributes/FillStyle.ts";
import { LineStyle } from "@int/geotoolkit/attributes/LineStyle.ts";
import { LogVisualHeaderProvider } from "@int/geotoolkit/welllog/header/LogVisualHeaderProvider.ts";
import { SineVisualHeader } from "/src/code/WellLog/Visuals/CustomVisual/SineVisualHeader.ts";
import { SineVisualTooltip } from "/src/code/WellLog/Visuals/CustomVisual/SineVisualTooltip.ts";
import { ToolTipTool } from "@int/geotoolkit/controls/tools/ToolTipTool.ts";
import { ToolTipRegistry } from "@int/geotoolkit/controls/tooltip/ToolTipRegistry.ts";
import { DisplayType as HeaderContainerDisplayType } from "@int/geotoolkit/welllog/HeaderContainer.ts";
const COLORS = ["darkgreen", "red", "black", "yellow"];
let i = 0;
const getNextColor = () => COLORS[i++ % COLORS.length];
const lineStyle = new LineStyle({
  "color": getNextColor(),
  "width": 3
});
const fillStyle = new FillStyle(getNextColor());
function createSinusoidVisual(data) {
  return new SineVisual(data).setLineStyle(lineStyle).setFillStyle(fillStyle);
}
let logSinusoid;
let widget;
function createScene(canvas) {
  widget = createWellLogWidget().setDepthLimits(1704, 1716);
  widget.addTrack(TrackType.IndexTrack);
  logSinusoid = createSinusoidVisual({
    depth: 1710,
    angle: Math.PI / 6
  });
  const headerProvider = LogVisualHeaderProvider.getDefaultInstance().clone();
  headerProvider.registerHeaderProvider(SineVisual.getClassName(), new SineVisualHeader(logSinusoid));
  widget.getHeaderContainer().setHeaderProvider(headerProvider);
  widget.connectTool(
    new ToolTipTool({
      "layer": widget,
      "registry": new ToolTipRegistry().register(SineVisual.getClassName(), new SineVisualTooltip("Depth: ${depth} <br/> Angle: ${angle}&#8451;"))
    })
  );
  widget.addTrack(TrackType.LinearTrack).setWidth(400).addChild(logSinusoid);
  widget.setHeaderHeight("auto");
  const plot = new Plot({
    "canvaselement": canvas,
    "root": widget
  });
  widget.fitToHeight();
  return plot;
}
function changeStyles() {
  lineStyle.setColor(getNextColor());
  fillStyle.setColor(getNextColor());
}
function changeMicropositions() {
  if (logSinusoid.getMicroPositionLeft() === 0)
    logSinusoid.setMicroPosition(0.2, 1);
  else
    logSinusoid.setMicroPosition(0, 1);
}
function addFooter() {
  widget.setProperties({
    "footer": {
      "visible": true,
      "displaytype": HeaderContainerDisplayType.Minimized,
      "margin": 2,
      "padding": 4,
      "height": 50
    }
  });
  widget.getFooterContainer().getHeaderProvider().registerHeaderProvider(SineVisual.getClassName(), new SineVisualHeader(logSinusoid));
  widget.getFooterContainer().rebuild();
}
function toggleFooter() {
  const isVisible = widget.getProperties()["footer"]["visible"];
  if (isVisible === "none")
    addFooter();
  else
    widget.setProperties({ "footer": { "visible": !isVisible } });
}
export { changeMicropositions, changeStyles, createScene, toggleFooter };

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