Async Rendering

# Unsing Data Loader in Async rendeing

The following example demonstrates the ability async to load data for LogCurve and Log2DVisual, when exporting, you can request only the necessary part of the data by setting limits. If data is not loaded then when attempt to export curve, loader sends request to load data and after how data is loaded, curve is exported.

import { LogData } from "@int/geotoolkit/welllog/data/LogData.ts";
import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { LogCurve } from "@int/geotoolkit/welllog/LogCurve.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { DataBindingRegistry } from "@int/geotoolkit/data/DataBindingRegistry.ts";
import { DataBinding } from "@int/geotoolkit/data/DataBinding.ts";
import { IndexType } from "@int/geotoolkit/welllog/IndexType.ts";
import { Events } from "@int/geotoolkit/util/EventDispatcher.ts";
import { DefaultColorProvider } from "@int/geotoolkit/util/DefaultColorProvider.ts";
import { Log2DVisual, PlotTypes } from "@int/geotoolkit/welllog/Log2DVisual.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorProvider.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
import { createLogCurveDataSource, initializeLogCurveDataLoader } from "/src/code/WellLog/AdditionalFunctionality/AsyncRendering/logCurveDataLoader.ts";
import { createLog2dDataSource, initializeLog2dDataLoader } from "/src/code/WellLog/AdditionalFunctionality/AsyncRendering/log2dDataLoader.ts";
import { log2DData } from "/src/code/WellLog/AdditionalFunctionality/AsyncRendering/log2DData.ts";
const DATA_RANGE = new Range(100, 5e3);
class DataLoaderBinding extends DataBinding {
  constructor(logDataLoader) {
    super();
    this._logDataLoader = logDataLoader;
  }
  dispose() {
    if (this._logDataLoader != null) {
      this._logDataLoader.dispose();
      this._logDataLoader = null;
    }
  }
  accept(node) {
    return node instanceof LogCurve;
  }
  bind(curve, dataTable) {
    if (dataTable == null || dataTable !== this._logDataLoader.getDataTable()) {
      return;
    }
    const id = curve.getName();
    const source = createLogCurveDataSource(id, this._logDataLoader);
    if (source != null) {
      curve.setData(source, true, true);
    }
  }
  unbind(curve, dataTable) {
  }
}
function create2DVisual(name, min, max, offset) {
  const delta = (max - min) / 3;
  const colors = new DefaultColorProvider().setNamedColor(KnownColors.NegativeInfinity, "blue").setNamedColor(KnownColors.PositiveInfinity, "blue").setNamedColor(KnownColors.NaN, "gray").addColor(min, "#7cb342").addColor(min + delta, "yellow").addColor(min + 2 * delta, "orange").addColor(max, "red");
  return new Log2DVisual().setData(createLog2dDataSource(initializeLog2dDataLoader())).setName(name).setColorProvider(colors).setOffsets(offset).setMicroPosition(0, 1).setPlotType(PlotTypes.Step);
}
function createWidget() {
  const wellLogWidget = createWellLogWidget({
    "indextype": IndexType.Depth,
    "indexunit": "ft",
    "range": DATA_RANGE
  }).setAxisHeaderType(HeaderType.Simple);
  wellLogWidget.addTrack(TrackType.IndexTrack);
  wellLogWidget.addTrack(TrackType.LinearTrack).addChild([
    new LogCurve(new LogData("GR")).setLineStyle("green")
  ]);
  wellLogWidget.addTrack(TrackType.LogTrack).addChild([
    new LogCurve(new LogData("RHOB")).setLineStyle("red")
  ]);
  wellLogWidget.addTrack(TrackType.LogTrack).addChild([
    create2DVisual("Log 2D", log2DData.min, log2DData.max)
  ]);
  const logDataLoader = initializeLogCurveDataLoader();
  wellLogWidget.setData(logDataLoader.getDataTable());
  const loaderBinding = new DataLoaderBinding(logDataLoader);
  const binding = new DataBindingRegistry().add(loaderBinding);
  wellLogWidget.setDataBinding(binding);
  wellLogWidget.on(Events.Disposed, () => {
    loaderBinding.dispose();
  });
  return wellLogWidget;
}
function exportToPdf(widget, settings) {
  const pdfPrintSettings = settings["printSettings"];
  const visibleDepthLimits = widget.getDepthLimits();
  let limits;
  if (pdfPrintSettings["limitsType"] === "Visible") {
    limits = {
      "start": visibleDepthLimits.getLow(),
      "end": visibleDepthLimits.getHigh()
    };
  } else if (pdfPrintSettings["limitsType"] === "Custom") {
    limits = {
      "start": pdfPrintSettings["limitsStart"],
      "end": pdfPrintSettings["limitsEnd"]
    };
  }
  const options = {
    "usedeepcopy": settings["deepcopy"],
    "output": "PDF Output",
    "printsettings": pdfPrintSettings,
    "limits": limits,
    "deviceunit": widget.getDeviceUnit(),
    "indexunit": widget.getIndexUnit(),
    "keepaspectratio": false,
    "progress": settings["progress"]
  };
  return widget.exportToPdf(options);
}
function createScene(canvas) {
  return new Plot({
    "canvaselement": canvas,
    "root": createWidget()
  });
}
function dispose(plot) {
  plot.dispose();
}
export { createScene, dispose, exportToPdf };

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

# How to add Async rendering to Custom Visual

The following example demonstrates how to create custom AsyncVisual to support async rendering.
To demonstrate this, we emulate remote rendering, to render LogTrack with data in memory to the image and then blend it to the real WellLogWidget

import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { Range } from "@int/geotoolkit/util/Range.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { IndexType } from "@int/geotoolkit/welllog/IndexType.ts";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
import { AsyncShape } from "/src/code/WellLog/AdditionalFunctionality/AsyncRendering/AsyncVisual.ts";
const DATA_RANGE = new Range(100, 2400);
function createWidget() {
  const wellLogWidget = createWellLogWidget({
    "indextype": IndexType.Depth,
    "indexunit": "ft",
    "range": DATA_RANGE
  }).setAxisHeaderType(HeaderType.Simple);
  wellLogWidget.addTrack(TrackType.IndexTrack);
  wellLogWidget.addTrack(TrackType.AnnotationTrack).setWidth(250).addChild([
    new AsyncShape()
  ]);
  return wellLogWidget;
}
function exportToPdf(widget, settings) {
  const pdfPrintSettings = settings["printSettings"];
  const visibleDepthLimits = widget.getDepthLimits();
  let limits;
  if (pdfPrintSettings["limitsType"] === "Visible") {
    limits = {
      "start": visibleDepthLimits.getLow(),
      "end": visibleDepthLimits.getHigh()
    };
  } else if (pdfPrintSettings["limitsType"] === "Custom") {
    limits = {
      "start": pdfPrintSettings["limitsStart"],
      "end": pdfPrintSettings["limitsEnd"]
    };
  }
  const options = {
    "usedeepcopy": settings["deepcopy"],
    "output": "PDF Output",
    "printsettings": pdfPrintSettings,
    "limits": limits,
    "deviceunit": widget.getDeviceUnit(),
    "indexunit": widget.getIndexUnit(),
    "keepaspectratio": false,
    "progress": settings["progress"]
  };
  return widget.exportToPdf(options);
}
function createScene(canvas) {
  return new Plot({
    "canvaselement": canvas,
    "root": createWidget()
  });
}
function dispose(plot) {
  plot.dispose();
}
export { createScene, dispose, exportToPdf };

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