Last updated

Real-Time Data

The WellLog widget allows simulation of real-time flow monitoring. The widget supports depth and time based data. See the WellLog Widget tutorial.
While creating the curve, auto-update is set to 'true' so the data source is constantly updated with new samples. The tutorial also shows how a user can implement a cache to hold the data. If the collected data becomes too big, the cache can release the samples that were received first. The tutorial also shows how to handle limits and scrolling of the content based on realtime data. See the Real-time Server tutorial.

For information on big data, see the Big Data tutorial.

# Depth-based Real-time

Create a widget and insert the widget in the plot and provide real-time data.

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { DepthLimitsTypes } from "@int/geotoolkit/welllog/widgets/WellLogWidget.ts";
import { LogData } from "@int/geotoolkit/welllog/data/LogData.ts";
import { LogCurve } from "@int/geotoolkit/welllog/LogCurve.ts";
import { Events as WellogWidgetsEvents } from "@int/geotoolkit/welllog/widgets/Events.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { ScrollToLocation } from "@int/geotoolkit/welllog/TrackContainer.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
import { Elements, TrackingType } from "@int/geotoolkit/welllog/header/AdaptiveLogCurveVisualHeader.ts";
import curveData from "/src/helpers/curveData.json?import";
import { defaults } from "/src/helpers/defaults.js";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
const TIME_REFRESH = 500;
const maxCachedSize = 500;
let startIndex = 0;
const startDepth = 5800;
const stepDepth = 0.5;
const DEPTH_OFFSET = "20px";
class DepthBasedWidget {
  constructor(options) {
    this.depthAutoScroll = false;
    this.timer = null;
    this.depthData = new LogData("CALI");
    this.curveData = curveData["CALI"];
    this.widget = this.createWidget();
    this.plot = new Plot({
      "canvaselement": options.canvas,
      "root": this.widget
    });
    this.runData();
  }
  dispose() {
    if (this.timer) {
      clearInterval(this.timer);
    }
    if (this.plot) {
      this.plot.dispose();
    }
  }
  onLimitsChange(type, src, args) {
    if (args["new"].getHigh() < this.depthData.getMaxDepth()) {
      this.depthAutoScroll = false;
    } else {
      this.depthAutoScroll = true;
    }
  }
  createCurve(dataSource) {
    return new LogCurve(dataSource, true).setLineStyle({
      "color": KnownColors.Blue,
      "width": 2
    }).setNormalizationLimits(7, 12);
  }
  createWidget() {
    const widget = createWellLogWidget({
      "scroll": {
        "headerverticalscroll": {
          "visible": true,
          "options": { "resizable": false }
        },
        "trackverticalscroll": {
          "visible": true,
          "options": { "resizable": false }
        }
      },
      "depthlimitsoptions": {
        "type": DepthLimitsTypes.Data,
        "offset": {
          "bottom": DEPTH_OFFSET
        }
      }
    }).setAxisHeaderType(HeaderType.Simple).scale(10);
    const header = widget.getHeaderContainer().getHeaderProvider().getHeaderProvider(LogCurve.getClassName()).clone();
    const trackingElement = header.getElements().filter((e) => e["name"] === Elements.Tracking)[0];
    if (trackingElement != null) {
      header.setElement({
        [Elements.Tracking]: {
          "options": {
            "default": TrackingType.AlwaysLastValue
          }
        }
      });
    }
    widget.getHeaderContainer().getHeaderProvider().registerHeaderProvider(LogCurve.getClassName(), header);
    const index = widget.addTrack(TrackType.IndexTrack);
    widget.setTrackOptions(index, { "autolabelrotation": false });
    widget.addTrack(TrackType.LogTrack).addChild([
      this.createCurve(this.depthData).setLineStyle(KnownColors.Green)
    ]);
    widget.addTrack(TrackType.LogTrack).addChild([
      this.createCurve(this.depthData).setLineStyle(KnownColors.Orange).setNormalizationLimits(12, 7)
    ]);
    widget.on(WellogWidgetsEvents.VisibleDepthLimitsChanged, this.onLimitsChange.bind(this));
    this.depthAutoScroll = true;
    return widget;
  }
  runData() {
    let index = 0;
    const updateData = () => {
      if (this.depthData != null) {
        if (index >= this.curveData.length) {
          this.depthData.clear();
          index = 0;
          startIndex = 0;
        }
        if (this.depthData.getSize() >= maxCachedSize) {
          startIndex = index - maxCachedSize / 2;
          this.depthData.trimValues(this.depthData.getMinDepth(), startDepth + startIndex * stepDepth);
        }
        const value = this.curveData[index];
        const depth = startDepth + index * stepDepth;
        this.depthData.addValue(depth, value);
        if (this.depthAutoScroll) {
          this.widget.scrollToIndex(this.widget.getDepthLimits().getHigh(), ScrollToLocation.BOTTOM, false);
        }
        index++;
      }
    };
    this.timer = setInterval(updateData, TIME_REFRESH);
  }
  zoomIn() {
    this.widget.scale(defaults.zoomInScale);
  }
  zoomOut() {
    this.widget.scale(defaults.zoomOutScale);
  }
  fitToHeight() {
    this.widget.fitToHeight();
  }
}
export { DepthBasedWidget };

createScene();

# Time-based Real-time

Create a widget and insert the widget in the plot and provide time-based data.

import { Plot } from "@int/geotoolkit/plot/Plot.ts";
import { DepthLimitsTypes } from "@int/geotoolkit/welllog/widgets/WellLogWidget.ts";
import { LogData } from "@int/geotoolkit/welllog/data/LogData.ts";
import { LogCurve } from "@int/geotoolkit/welllog/LogCurve.ts";
import { HeaderType } from "@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts";
import { TrackType } from "@int/geotoolkit/welllog/TrackType.ts";
import { ScrollToLocation } from "@int/geotoolkit/welllog/TrackContainer.ts";
import { KnownColors } from "@int/geotoolkit/util/ColorUtil.ts";
import { Events as WellogWidgetsEvents } from "@int/geotoolkit/welllog/widgets/Events.ts";
import { Elements, TrackingType } from "@int/geotoolkit/welllog/header/AdaptiveLogCurveVisualHeader.ts";
import curveData from "/src/helpers/curveData.json?import";
import { defaults } from "/src/helpers/defaults.js";
import { createWellLogWidget } from "/src/code/WellLog/utils/common.ts";
const TIME_REFRESH = 500;
const maxCachedSize = 500;
let startIndex = 0;
const stepTime = 1e4;
const startTime = 1598115847e3;
const TIME_OFFSET = "10%";
class TimeBasedWidget {
  constructor(options) {
    this.timeAutoScroll = false;
    this.timer = null;
    this.timeData = new LogData("CALI");
    this.curveData = curveData["CALI"];
    this.widget = this.createWidget();
    this.plot = new Plot({
      "canvaselement": options.canvas,
      "root": this.widget
    });
    this.runData();
  }
  dispose() {
    if (this.timer) {
      clearInterval(this.timer);
    }
    if (this.plot) {
      this.plot.dispose();
    }
  }
  onLimitsChange(type, src, args) {
    if (args["new"].getHigh() < this.timeData.getMaxDepth()) {
      this.timeAutoScroll = false;
    } else {
      this.timeAutoScroll = true;
    }
  }
  createCurve(dataSource) {
    return new LogCurve(dataSource, true).setLineStyle({
      "color": KnownColors.Blue,
      "width": 2
    }).setNormalizationLimits(7, 12);
  }
  createWidget() {
    const widget = createWellLogWidget({
      "indexunit": "ms",
      "indextype": "time",
      "depthlimitsoptions": {
        "type": DepthLimitsTypes.Data,
        "offset": {
          "bottom": TIME_OFFSET
        }
      }
    }).setAxisHeaderType(HeaderType.Simple).scale(1e-3);
    const header = widget.getHeaderContainer().getHeaderProvider().getHeaderProvider(LogCurve.getClassName()).clone();
    const trackingElement = header.getElements().filter((e) => e["name"] === Elements.Tracking)[0];
    if (trackingElement != null) {
      header.setElement({
        [Elements.Tracking]: {
          "options": {
            "default": TrackingType.AlwaysLastValue
          }
        }
      });
    }
    widget.getHeaderContainer().getHeaderProvider().registerHeaderProvider(LogCurve.getClassName(), header);
    widget.addTrack(TrackType.IndexTrack);
    widget.addTrack(TrackType.LogTrack).addChild([
      this.createCurve(this.timeData).setLineStyle(KnownColors.Green)
    ]);
    widget.addTrack(TrackType.LogTrack).addChild([
      this.createCurve(this.timeData).setLineStyle(KnownColors.Orange).setNormalizationLimits(12, 7)
    ]);
    widget.on(WellogWidgetsEvents.VisibleDepthLimitsChanged, this.onLimitsChange.bind(this));
    this.timeAutoScroll = true;
    this.widget = widget;
    return widget;
  }
  runData() {
    let index = 0;
    const updateWidget = () => {
      if (this.timeData != null) {
        if (index >= this.curveData.length) {
          this.timeData.clear();
          index = 0;
          startIndex = 0;
        }
        if (this.timeData.getSize() >= maxCachedSize) {
          startIndex = index - maxCachedSize / 2;
          this.timeData.trimValues(this.timeData.getMinDepth(), startTime + startIndex * stepTime);
        }
        const value = this.curveData[index];
        const depth = startTime + index * stepTime;
        this.timeData.addValue(depth, value);
        if (this.timeAutoScroll) {
          this.widget.scrollToIndex(this.widget.getDepthLimits().getHigh(), ScrollToLocation.CENTER, false);
        }
        index++;
      }
    };
    this.timer = setInterval(updateWidget, TIME_REFRESH);
  }
  zoomIn() {
    this.widget.scale(defaults.zoomInScale);
  }
  zoomOut() {
    this.widget.scale(defaults.zoomOutScale);
  }
  fitToHeight() {
    this.widget.fitToHeight();
  }
}
export { TimeBasedWidget };

createScene();