{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["tabs","tab"]},"type":"markdown"},"seo":{"title":"TableView Interaction","description":"Accelerate E&P application development and protect your innovation by consuming our Data and Domain APIs / Platform APIs.","lang":"en-US","meta":[{"name":"robots","content":"noindex"}],"llmstxt":{"hide":true,"excludeFiles":[]}},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"tableview-interaction","__idx":0},"children":["TableView Interaction"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This Table View Interaction tutorial demonstrates how the WellLog widget can interact with the TableView widget. Both these widgets are created separately and added to the canvas. Multiple layers in one canvas can be synchronized automatically because they are located in the same plot, correlating the depths of points in the WellLog with the corresponding values of the TableView. If the widgets are located in different plots, then the scale can be synchronized similar to plot synchronization."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"tableview-interaction-1","__idx":1},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/AdditionalFunctionality/TableViewInteraction/tableViewInteraction#tableViewInteraction"},"children":["#"]}," TableView Interaction"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In the TableView below the depth range and curve values are calculated basing on the visible limits and current scale of the WellLog widget. Highlighting depth and the curves are synchronized for both widgets."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"main","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"ts","header":{"controls":{"copy":{}}},"source":"import { from } from \"@int/geotoolkit/selection/from.ts\";\nimport { KnownColors } from \"@int/geotoolkit/util/ColorUtil.ts\";\nimport { MathUtil } from \"@int/geotoolkit/util/MathUtil.ts\";\nimport { LogData } from \"@int/geotoolkit/welllog/data/LogData.ts\";\nimport { LogCurve } from \"@int/geotoolkit/welllog/LogCurve.ts\";\nimport { AdaptiveLogCurveVisualHeader, Elements } from \"@int/geotoolkit/welllog/header/AdaptiveLogCurveVisualHeader.ts\";\nimport { TrackType as WellLogTrackType } from \"@int/geotoolkit/welllog/TrackType.ts\";\nimport { Events as SplitterEvents } from \"@int/geotoolkit/welllog/widgets/tools/Splitter.ts\";\nimport { Point } from \"@int/geotoolkit/util/Point.ts\";\nimport { Events as CrossHairEvents } from \"@int/geotoolkit/controls/tools/CrossHair.ts\";\nimport { Events as WellLogEvents } from \"@int/geotoolkit/welllog/widgets/Events.ts\";\nimport { Plot } from \"@int/geotoolkit/plot/Plot.ts\";\nimport { Group } from \"@int/geotoolkit/scene/Group.ts\";\nimport { CssLayout } from \"@int/geotoolkit/layout/CssLayout.ts\";\nimport { Rect } from \"@int/geotoolkit/util/Rect.ts\";\nimport { Events as SelectionEvents } from \"@int/geotoolkit/controls/tools/Selection.ts\";\nimport { Events as AbstractToolEvents } from \"@int/geotoolkit/controls/tools/AbstractTool.ts\";\nimport { Events as HighlightEvents } from \"@int/geotoolkit/controls/tools/tableview/Highlight.ts\";\nimport { TableView } from \"@int/geotoolkit/widgets/TableView.ts\";\nimport { Events as ScrollEvents } from \"@int/geotoolkit/controls/tools/scroll/AbstractScroll.ts\";\nimport { Events as PanningEvents } from \"@int/geotoolkit/controls/tools/Panning.ts\";\nimport { FontSubType } from \"@int/geotoolkit/pdf/FontSubType.ts\";\nimport { HttpClient } from \"@int/geotoolkit/http/HttpClient.ts\";\nimport { TableElement } from \"@int/geotoolkit/report/dom/elements/TableElement.ts\";\nimport { DataTable } from \"@int/geotoolkit/data/DataTable.ts\";\nimport { DataTableView } from \"@int/geotoolkit/data/DataTableView.ts\";\nimport { DOMParser } from \"@int/geotoolkit/report/dom/DOMParser.ts\";\nimport { Parser } from \"@int/geotoolkit/report/Parser.ts\";\nimport { ReportML } from \"/src/code/WellLog/AdditionalFunctionality/TableViewInteraction/reports/ReportML.ts\";\nimport intLogoPng from \"/src/code/WellLog/AdditionalFunctionality/TableViewInteraction/reports/templates/int-logo.png?import\";\nimport { ImageMap } from \"@int/geotoolkit/report/resources/ImageMap.ts\";\nimport xmlDocumentTemplate from \"/src/code/WellLog/AdditionalFunctionality/TableViewInteraction/reports/templates/composite-template.xml?import\";\nimport { Registry } from \"@int/geotoolkit/report/dom/elements/Registry.ts\";\nimport { obfuscate } from \"@int/geotoolkit/lib.js\";\nimport { DataProvider } from \"@int/geotoolkit/controls/shapes/tableview/DataProvider.ts\";\nimport { curveData } from \"/src/code/WellLog/utils/curveData.ts\";\nimport { createWellLogWidget } from \"/src/code/WellLog/utils/common.ts\";\nimport { Sections } from \"@int/geotoolkit/welllog/header/AdaptiveLogVisualHeader.ts\";\nfunction reInitializeDomRegistry() {\n  Registry.getDefaultInstance().register(\"well-log\", ReportML.Nodes.WellLog);\n}\nconst COLS = [\"GR\", \"CALI\", \"SP\"];\nfunction createTestData(from2, step, curveMnemonic) {\n  const depths = [];\n  const values = [];\n  const curveDat = curveData[curveMnemonic];\n  const amountOfPoints = curveDat.length;\n  for (let i = 0; i < amountOfPoints; i++) {\n    depths.push(i * step + from2);\n    values.push(curveDat[i]);\n  }\n  return new LogData({\n    \"name\": curveMnemonic,\n    \"depths\": depths,\n    \"values\": values\n  });\n}\nclass TableViewInteraction {\n  constructor(setZoomButton) {\n    reInitializeDomRegistry();\n    this._wellLogWidget = null;\n    this._tableWidget = null;\n    this.setZoomButton = setZoomButton;\n    this._dataSources = {};\n    this._longestLogDataSource = null;\n    let curveMnemonic;\n    for (curveMnemonic in curveData) {\n      if (curveData.hasOwnProperty(curveMnemonic) === false) {\n        continue;\n      }\n      const logDataSource = createTestData(4500, 10, curveMnemonic);\n      this._dataSources[curveMnemonic] = logDataSource;\n      if (this._longestLogDataSource == null) {\n        this._longestLogDataSource = logDataSource;\n      } else if (logDataSource.getMaxDepth() > this._longestLogDataSource.getMaxDepth()) {\n        this._longestLogDataSource = logDataSource;\n      }\n    }\n    this._depths = this._longestLogDataSource.getDepths();\n    this._curves = {};\n  }\n  synchronizeTableData() {\n    const depthLimits = this._wellLogWidget.getDepthLimits();\n    const visibleDepthLimits = this._wellLogWidget.getVisibleDepthLimits();\n    const step = Math.ceil(visibleDepthLimits.getSize() / 10) / 2;\n    let low = Math.floor(depthLimits.getLow() / step);\n    const high = Math.ceil(depthLimits.getHigh() / step);\n    if (low * step <= depthLimits.getLow()) {\n      low++;\n    }\n    this._depths = [];\n    for (let i = low; i <= high; i++) {\n      this._depths.push(i * step);\n    }\n    const self = this;\n    this._tableWidget.setData({\n      \"dataprovider\": new (obfuscate(class extends DataProvider {\n        getContentData(col, row) {\n          const src = self._dataSources[COLS[col]];\n          const value = src.getValueAt(self._depths[row]);\n          return isNaN(value) ? \"-\" : value.toFixed(2);\n        }\n        getIndexData(row) {\n          return self._depths[row].toFixed();\n        }\n        getHeaderData(id) {\n          return COLS[id];\n        }\n      }))(),\n      \"rows\": this._depths.length\n    });\n    const position = this._wellLogWidget.getToolByName(\"cross-hair\").getPosition();\n    if (!isNaN(position.getY()) && !isNaN(position.getX())) {\n      const depth = position.getY();\n      const closest = this._depths.reduce((acc, val, id) => val <= depth ? id : acc, 0);\n      this._tableWidget.highlightRow(closest);\n    }\n  }\n  initializeWellLog() {\n    const widget = createWellLogWidget().setDepthLimits(this._longestLogDataSource.getMinDepth(), this._longestLogDataSource.getMaxDepth());\n    widget.getHeaderContainer().getHeaderProvider().registerHeaderProvider(LogCurve.getClassName(), new AdaptiveLogCurveVisualHeader().setElement([Elements.ScaleFrom, Elements.ScaleTo], {\n      \"section\": Sections.Top\n    }).setElement(Elements.Tracking, {\n      \"section\": Sections.Top\n    }));\n    widget.getToolByName(\"splitter\").setEnabled(true).on(SplitterEvents.onCanResize, (evt, sender, event) => {\n      event.reject();\n    });\n    widget.getToolByName(\"cross-hair\").on(CrossHairEvents.onPositionChanged, (evt, sender, event) => {\n      const position = event.getPosition();\n      if (isNaN(position.getY()) || isNaN(position.getX())) {\n        return;\n      }\n      const depth = position.getY();\n      const closest = this._depths.reduce((acc, val, id) => val <= depth ? id : acc, 0);\n      this._tableWidget.highlightRow(closest);\n    });\n    widget.getToolByName(\"TrackPlotVerticalScroll\").on(ScrollEvents.onScroll, () => {\n      const limits = widget.getVisibleDepthLimits();\n      const step = this._depths[1] - this._depths[0];\n      const top = (limits.getLow() - this._depths[0]) / step;\n      const bottom = top + this._tableWidget.getVisibleTableLimits().getHeight();\n      this._tableWidget.setVisibleTableLimits(Math.ceil(top));\n      this._tableWidget.setVisibleTableLimits(Math.floor(bottom));\n    });\n    widget.getToolByName(\"pick\").on(SelectionEvents.onSelectionChanged, () => {\n      const selection = this._wellLogWidget.getSelectedVisuals();\n      const ids = selection.map((visual) => COLS.indexOf(visual.getName()));\n      this._tableWidget.highlightColumn(ids.length > 0 ? ids[0] : -1);\n    });\n    widget.getToolByName(\"rubberband\").setAutoDisabled(true).on(AbstractToolEvents.onEnabledStateChanged, (evt, sender) => {\n      this.setZoomButton(sender.isEnabled());\n    });\n    widget.on(WellLogEvents.VisibleDepthLimitsChanged, (event, sender, eventArgs) => {\n      if (Math.abs(eventArgs[\"old\"].getSize() - eventArgs[\"new\"].getSize()) < 1e-3)\n        return;\n      this.synchronizeTableData();\n    });\n    widget.addTrack(WellLogTrackType.IndexTrack).setWidth(80);\n    widget.addTrack(WellLogTrackType.LinearTrack).addChild([\n      this.createCurve(\"GR\", KnownColors.Green),\n      this.createCurve(\"CALI\", KnownColors.Orange),\n      this.createCurve(\"SP\", KnownColors.Blue)\n    ]);\n    return widget;\n  }\n  initializeTableWidget() {\n    const tableWidget = new TableView({\n      \"horizontalscroll\": \"floating\",\n      \"verticalscroll\": \"floating\",\n      \"indexwidth\": 50,\n      \"cols\": COLS.length,\n      \"bounds\": new Rect(300, 0, 665, 400)\n    });\n    const crosshair = this._wellLogWidget.getToolByName(\"cross-hair\");\n    tableWidget.getToolByName(\"TableViewHighlight\").on(HighlightEvents.onHover, (evt, sender, eventArgs) => {\n      const depth = this._depths[eventArgs.getRowNumber()] || NaN;\n      crosshair.setPosition(new Point(0, depth));\n    }).on(AbstractToolEvents.onLeave, () => {\n      crosshair.setPosition(new Point(0, NaN));\n    });\n    const pick = this._wellLogWidget.getToolByName(\"pick\");\n    tableWidget.getToolByName(\"TableViewSelection\").on(SelectionEvents.onPick, () => {\n      const col = tableWidget.getHighlightedColumn();\n      pick.setSelection(col >= 0 ? [this._curves[COLS[col]]] : []);\n    });\n    const synchronizeLimits = () => {\n      const limits = tableWidget.getVisibleTableLimits();\n      const top = Math.floor(limits.getTop());\n      const low = (top + 1 - limits.getTop()) * this._depths[top] + (limits.getTop() - top) * this._depths[top + 1];\n      const high = low + this._wellLogWidget.getVisibleDepthLimits().getSize();\n      this._wellLogWidget.setVisibleDepthLimits(low, high);\n    };\n    tableWidget.getToolByName(\"VerticalScroll\").on(ScrollEvents.onScroll, synchronizeLimits);\n    tableWidget.getToolByName(\"TableViewPanning\").on(PanningEvents.onPanning, synchronizeLimits);\n    return tableWidget;\n  }\n  disableRubberBand() {\n    this._wellLogWidget.getToolByName(\"rubberband\").setEnabled(false);\n  }\n  zoomIn() {\n    this._wellLogWidget.scale(5 / 4);\n    this.disableRubberBand();\n  }\n  zoomOut() {\n    this._wellLogWidget.scale(4 / 5);\n    this.disableRubberBand();\n  }\n  fitToHeight() {\n    this._wellLogWidget.fitToHeight();\n    this.disableRubberBand();\n  }\n  rubberBandZoom() {\n    this._wellLogWidget.getToolByName(\"rubberband\").setEnabled(true);\n  }\n  createCurve(name, color) {\n    const dataSource = this._dataSources[name];\n    const limits = MathUtil.calculateNeatLimits(dataSource.getMinValue(), dataSource.getMaxValue(), false, false);\n    this._curves[name] = new LogCurve(dataSource).setLineStyle(color).setNormalizationLimits(limits.getLow(), limits.getHigh());\n    return this._curves[name];\n  }\n  initialize(canvas) {\n    this._plot = new Plot({\n      \"canvaselement\": canvas,\n      \"root\": new Group().setAutoModelLimitsMode(true).setLayout(new CssLayout()).addChild([\n        this._wellLogWidget = this.initializeWellLog().setLayoutStyle({\n          \"left\": 0,\n          \"top\": 0,\n          \"width\": 300,\n          \"bottom\": 0\n        }),\n        this._tableWidget = this.initializeTableWidget()\n      ])\n    });\n    this._wellLogWidget.setHeaderHeight(\"auto\").fitToHeight();\n    this.synchronizeTableData();\n  }\n  loadFonts(exportOptions) {\n    return Promise.all([{\n      \"fontUrl\": \"./src/assets/fonts/roboto.ttf\",\n      \"fontName\": \"Roboto\"\n    }, {\n      \"fontUrl\": \"./src/assets/fonts/Roboto-Bold.ttf\",\n      \"fontName\": \"Roboto\",\n      \"fontWeight\": \"bold\"\n    }].map(\n      (font) => HttpClient.getInstance().getHttp().get(font[\"fontUrl\"], {\n        \"responsetype\": \"blob\"\n      }).then((response) => {\n        const fileReader = new FileReader();\n        fileReader.onloadend = () => {\n          exportOptions[\"embededFonts\"] = exportOptions[\"embededFonts\"] || [];\n          exportOptions[\"embededFonts\"].push({\n            \"subType\": FontSubType.TrueType,\n            \"fontName\": font[\"fontName\"],\n            \"fontWeight\": font[\"fontWeight\"] || \"normal\",\n            \"fontStyle\": \"normal\",\n            \"fontBase64EncodedFile\": fileReader.result,\n            \"encoding\": \"Identity-H\"\n          });\n        };\n        return fileReader.readAsDataURL(response.data);\n      })\n    ));\n  }\n  exportToPDF(options, printDecimatedDepths) {\n    const exportOptions = {\n      \"output\": \"Widget\",\n      \"printsettings\": options != null ? options[\"printSettings\"] : null,\n      \"progress\": options != null ? options[\"progress\"] : null\n    };\n    return this.loadFonts(exportOptions).then(\n      () => this.processTemplate(xmlDocumentTemplate, printDecimatedDepths).then((geoDocument) => geoDocument.exportToPdf(exportOptions))\n    );\n  }\n  processTemplate(xml, printDecimatedDepths) {\n    return DOMParser.parse(xml).then((cgDomDocument) => {\n      this.preProcessDomDocument(cgDomDocument, printDecimatedDepths);\n      const imageMap = new ImageMap().registerImage(\"int-logo.png\", intLogoPng);\n      return new Parser(cgDomDocument).setResourceManager(imageMap).parse();\n    }, (exception) => {\n      let message = \"ERROR cannot load the template\";\n      if (typeof exception === \"string\") {\n        message = exception;\n      } else if (typeof exception.toString === \"function\") {\n        message = exception.toString();\n      }\n      global.console.log(message);\n    });\n  }\n  preProcessTableDomElement(tableNode, printDecimatedDepths) {\n    const paramColumns = [];\n    const header = tableNode.rows.item(0);\n    const depthLimits = this._wellLogWidget.getDepthLimits();\n    const visibleDepthLimits = this._wellLogWidget.getVisibleDepthLimits();\n    const step = Math.ceil(visibleDepthLimits.getSize() / 10) / 2;\n    let low = Math.floor(depthLimits.getLow() / step);\n    const high = Math.ceil(depthLimits.getHigh() / step);\n    if (low * step <= depthLimits.getLow()) {\n      low++;\n    }\n    for (let i = 0; i < header.cells.length; i++) {\n      const name = header.cells.item(i).getAttribute(\"name\");\n      let data = null;\n      let dataSource = null;\n      if (name != null) {\n        if (name.toLowerCase() === \"depth\") {\n          data = this._longestLogDataSource.getDepths();\n          dataSource = new LogData({\n            \"depths\": data,\n            \"values\": data\n          });\n        } else if (this._dataSources[name] != null) {\n          dataSource = this._dataSources[name];\n          data = this._dataSources[name].getValues();\n        }\n      }\n      if (data == null) {\n        continue;\n      }\n      if (printDecimatedDepths) {\n        data = [];\n        for (let i2 = low; i2 <= high; i2++) {\n          let value = dataSource.getValueAt(i2 * step);\n          if (Number.isNaN(value)) {\n            continue;\n          }\n          value = value.toFixed(2);\n          data.push(value);\n        }\n      }\n      paramColumns.push({\n        name: name ? name.toLowerCase() : \"\",\n        type: \"number\",\n        data\n      });\n    }\n    const paramsDataTable = new DataTable({\n      \"cols\": paramColumns\n    });\n    const paramsDataTableView = new DataTableView(paramsDataTable);\n    tableNode.setDataTable(paramsDataTableView, true);\n  }\n  preProcessDomDocument(cgDomDocument, printDecimatedDepths) {\n    const wellLogNode = from(cgDomDocument).where((node) => node instanceof ReportML.Nodes.WellLog).selectFirst();\n    if (wellLogNode != null) {\n      const template = this._wellLogWidget.saveTemplate();\n      const templateJSON = JSON.parse(template);\n      wellLogNode.setDataSources(this._dataSources).setDepthLimits(this._wellLogWidget.getDepthLimits()).setVisibleDepthLimits(this._wellLogWidget.getDepthLimits()).setTemplate(templateJSON);\n    }\n    const tableNode = from(cgDomDocument).where((node) => node instanceof TableElement && node.getAttribute(\"type\") === \"datatable\").selectFirst();\n    if (tableNode != null) {\n      this.preProcessTableDomElement(tableNode, printDecimatedDepths);\n    }\n    return cgDomDocument;\n  }\n  getPlot() {\n    return this._plot;\n  }\n}\nexport function createScene(canvas, setZoomButton) {\n  const app = new TableViewInteraction(setZoomButton);\n  app.initialize(canvas);\n  return app;\n}\n\ncreateScene(document.querySelector('[ref=\"plot\"]'), this.setRubberBandSelectionButton, this.setZoomButton);\n\n","lang":"ts"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"css","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"css","header":{"controls":{"copy":{}}},"source":"\n.cg-tooltip-holder {\n  position: relative;\n}\n\n.cg-tooltip {\n  position: absolute;\n  display: block;\n  padding: 2px 12px 3px 7px;\n  overflow: visible !important;\n  font-family: Roboto, Helvetica, Arial, sans-serif;\n  font-size: 13px;\n  background: white !important;\n  opacity: 0.9;\n  color: #333333;\n  border: solid 1px gray;\n  border-radius: 5px;\n  text-align: left;\n  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);\n  border-radius: 5px;\n  margin: 0 !important;\n  z-index: 10000;\n  max-width: 400px;\n  text-wrap: normal !important;\n  white-space: normal !important;\n}\n/* Default setting for tooltip */\n.cg-tooltip-container {\n  position: absolute;\n  display: block;\n  overflow: visible !important;\n  font-family: Roboto, Helvetica, Arial, sans-serif;\n  font-size: 12px;\n  padding: 3px 7px;\n  background: #f7f7f7;\n  color: #333333;\n  border: 1px solid #938e8e;\n  opacity: 0.8;\n  text-align: left;\n  box-shadow: 3px 3px 10px #888;\n  margin: 0 !important;\n  z-index: 10000;\n  max-width: 400px;\n  text-wrap: normal !important;\n  white-space: normal !important;\n  user-select: none;\n}\n@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {\n  .cg-tooltip-container {\n    border-radius: 0;\n  }\n}\n/* Default left arrow for tooltip */\n.cg-tooltip-arrow-left::before {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  left: 0;\n  top: 50%;\n  border: 5px solid transparent;\n  border-left: 0;\n  border-right: 5px solid  #938e8e;\n  transform: translate(calc(-100%), -50%);\n}\n.cg-tooltip-arrow-left::after {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  left: 0;\n  top: 50%;\n  border: 4px solid transparent;\n  border-left: 0;\n  border-right: 4px solid #f7f7f7;\n  transform: translate(calc(-100%), -50%);\n}\n/* Default top arrow for tooltip */\n.cg-tooltip-arrow-top::before {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  left: 50%;\n  top: 0;\n  border: 5px solid transparent;\n  border-top: 0;\n  border-bottom: 5px solid #938e8e;\n  transform: translate(-50%, -100%);\n}\n.cg-tooltip-arrow-top::after {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  left: 50%;\n  top: 0;\n  border: 4px solid transparent;\n  border-top: 0;\n  border-bottom: 4px solid #f7f7f7;\n  transform: translate(-50%, -100%);\n}\n/* Default right arrow for tooltip */\n.cg-tooltip-arrow-right::before {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  right: 0;\n  top: 50%;\n  border: 5px solid transparent;\n  border-right: 0;\n  border-left: 5px solid #938e8e;\n  transform: translate(100%, -50%);\n}\n.cg-tooltip-arrow-right::after {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  right: 0;\n  top: 50%;\n  border: 4px solid transparent;\n  border-right: 0;\n  border-left: 4px solid #f7f7f7;\n  transform: translate(100%, -50%);\n}\n/* Default bottom arrow for tooltip */\n.cg-tooltip-arrow-bottom::before {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  left: 50%;\n  bottom: 0px;\n  border: 5px solid transparent;\n  border-bottom: 0;\n  border-top: 5px solid #938e8e;\n  transform: translate(-50%, 100%);\n  z-index: 10000;\n}\n.cg-tooltip-arrow-bottom::after {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  left: 50%;\n  bottom: 0;\n  border: 4px solid transparent;\n  border-bottom: 0;\n  border-top: 4px solid #f7f7f7;\n  transform: translate(-50%, 100%);\n  z-index: 10000;\n}\n/* Tooltip item name */\n/* Tooltip item value */\n/* .cg-tooltip-item-value */\n/* Tooltip item value */\n.cg-tooltip-item-unit {\n  text-transform: none;\n}\n\n.cg-tooltip-item-name {\n    text-transform: capitalize;\n    white-space: nowrap;\n    vertical-align: middle;\n    font-size: 13px;\n}\n.cg-tooltip-row {\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n  white-space: pre-wrap;\n  font-size: 12px;\n  line-height: 100%;\n  margin: 1px 0;\n}\n.cg-tooltip-title {\n  font-size: 13px;\n  height: 14px;\n  text-transform: capitalize;\n}\n.cg-tooltip-title .cg-tooltip-symbol {\n  margin-right: 0 !important;\n}\n.cg-tooltip-title-name {\n  vertical-align: middle;\n}\n.cg-tooltip-row + .cg-tooltip-row {\n  margin-top: 4px;\n}\n.cg-tooltip-row.cg-tooltip-title + .cg-tooltip-row {\n  margin-top: 5px;\n}\n.cg-tooltip-item-value + .cg-tooltip-item-unit {\n    margin-left: 1px;\n}\n/* Tooltip symbol */\n.cg-tooltip-symbol-cell {\n  display: inline-flex;\n  min-width: 13px; /* 10px size + 3px margin */\n}\n.cg-tooltip-symbol {\n  margin-right: 3px;\n  background-color: transparent;\n  display: block;\n}\n.cg-tooltip-symbol > img {\n  display: block;\n}\n.cg-tooltip-list-cell {\n  display: inline-flex;\n}\n.cg-tooltip-list-symbol {\n  display: block;\n  margin-right: 3px;\n  width: 6px;\n  height: 6px;\n  vertical-align: middle;\n  border-radius: 50%;\n  border: 1px solid rgba(0,0,0,.4);\n}\n.cg-tooltip-symbol-legacy {\n  border-radius: 4px;\n  margin-right: 5px;\n  height: 8px;\n  width: 8px;\n  display: inline-block;\n}\n.cg-tooltip-title-legacy {\n  font-weight: 900;\n}\n\n/* Tooltip symbol circle */\n.cg-tooltip-symbol.circle {\n  height: 10px;\n  width: 10px;\n  display: inline-block;\n  border-radius: 50%;\n  border: 1px solid rgba(0,0,0,.4);\n}\n/* Tooltip symbol line */\n.cg-tooltip-symbol.line {\n    height: 10px;\n    width: 10px;\n    display: inline-block;\n    transform: scale(1.2, 0.2);\n}\n/* Tooltip symbol diamond */\n.cg-tooltip-symbol.diamond {\n    height: 10px;\n    width: 10px;\n    display: inline-block;\n    transform: rotate(45deg);\n    border-radius: 0px;\n}\n/* Tooltip symbol square */\n.cg-tooltip-symbol.square {\n    height: 10px;\n    width: 10px;\n    display: inline-block;\n    border-radius: 0px;\n    border: 1px solid rgba(0,0,0,.4);\n}\n\n","lang":"css"},"children":[]}]}]},{"$$mdtype":"Tag","name":"iframe","attributes":{"src":"https://dc2-documentation.s3.amazonaws.com/documentation/slb-docs-test/5.0/examples/vue/tutorials/index.html#/WellLog/AdditionalFunctionality/TableViewInteraction/tableViewInteraction?section=tableViewInteraction&extract=true","width":"100%","height":"554.5px","style":{"border":"none"}},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"welllog-widget-initialization","__idx":2},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/AdditionalFunctionality/TableViewInteraction/tableViewInteraction#wellLogWidgetInitialization"},"children":["#"]}," WellLog Widget Initialization"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following code shows how to initialize WellLog Widget tools for interaction with TableView."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"tableview-widget-initialization","__idx":3},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/AdditionalFunctionality/TableViewInteraction/tableViewInteraction#tableViewWidgetInitialization"},"children":["#"]}," TableView Widget Initialization"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following code shows how to initialize TableView tools for interaction with WellLog."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"export-to-pdf","__idx":4},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/AdditionalFunctionality/TableViewInteraction/tableViewInteraction#exportToPDF"},"children":["#"]}," Export To PDF"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following code shows how to export to PDF entire scene."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"real-time-interaction","__idx":5},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/AdditionalFunctionality/TableViewInteraction/tableViewInteraction#realTimeInteraction"},"children":["#"]}," Real-Time Interaction"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Here's the example of real-time depth based WellLog Widget and TableView with autoscroll and synchronized data."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"main","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"ts","header":{"controls":{"copy":{}}},"source":"import { KnownColors } from \"@int/geotoolkit/util/ColorUtil.ts\";\nimport { LogData } from \"@int/geotoolkit/welllog/data/LogData.ts\";\nimport { LogCurve } from \"@int/geotoolkit/welllog/LogCurve.ts\";\nimport { TrackType as WellLogTrackType } from \"@int/geotoolkit/welllog/TrackType.ts\";\nimport { Events as SplitterEvents } from \"@int/geotoolkit/welllog/widgets/tools/Splitter.ts\";\nimport { Point } from \"@int/geotoolkit/util/Point.ts\";\nimport { Events as CrossHairEvents } from \"@int/geotoolkit/controls/tools/CrossHair.ts\";\nimport { Events as WellLogEvents } from \"@int/geotoolkit/welllog/widgets/Events.ts\";\nimport { Plot } from \"@int/geotoolkit/plot/Plot.ts\";\nimport { Group } from \"@int/geotoolkit/scene/Group.ts\";\nimport { CssLayout } from \"@int/geotoolkit/layout/CssLayout.ts\";\nimport { Rect } from \"@int/geotoolkit/util/Rect.ts\";\nimport { TableView } from \"@int/geotoolkit/widgets/TableView.ts\";\nimport { Events as HighlightEvents } from \"@int/geotoolkit/controls/tools/tableview/Highlight.ts\";\nimport { Events as ScrollEvents } from \"@int/geotoolkit/controls/tools/scroll/AbstractScroll.ts\";\nimport { Events as PanningEvents } from \"@int/geotoolkit/controls/tools/Panning.ts\";\nimport { Events as AbstractToolEvents } from \"@int/geotoolkit/controls/tools/AbstractTool.ts\";\nimport { ScrollToLocation } from \"@int/geotoolkit/welllog/TrackContainer.ts\";\nimport { HeaderType } from \"@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts\";\nimport { obfuscate } from \"@int/geotoolkit/lib.js\";\nimport { DataProvider } from \"@int/geotoolkit/controls/shapes/tableview/DataProvider.ts\";\nimport { curveData } from \"/src/code/WellLog/utils/curveData.ts\";\nimport { createWellLogWidget } from \"/src/code/WellLog/utils/common.ts\";\nconst COLS = [\"GR\", \"CALI\", \"SP\"];\nlet startIndex = 0;\nconst maxCachedSize = 500;\nconst startDepth = 5800;\nconst stepDepth = 1;\nconst TIME_REFRESH = 500;\nclass RealTimeInteraction {\n  constructor() {\n    this._wellLogWidget = null;\n    this._tableWidget = null;\n    this.timer = null;\n    this.caliData = new LogData(\"CALI\");\n    this.grData = new LogData(\"GR\");\n    this.spData = new LogData(\"SP\");\n    this.curveData = curveData[\"CALI\"];\n    this.depthAutoScroll = true;\n    this.runData();\n  }\n  synchronizeTableData() {\n    const depth = this.caliData.getDepths() || [];\n    this._tableWidget.setData({\n      \"dataprovider\": new (obfuscate(class extends DataProvider {\n        getContentData(col, row) {\n          return curveData[COLS[col]][row].toFixed(2);\n        }\n        getIndexData(row) {\n          return (startDepth + row * stepDepth).toString();\n        }\n        getHeaderData(id) {\n          return COLS[id];\n        }\n      }))(),\n      \"rows\": depth.length\n    });\n    if (this.depthAutoScroll) {\n      this._tableWidget.highlightRow(depth.length - 1);\n    }\n  }\n  initializeWellLog() {\n    const widget = createWellLogWidget().setAxisHeaderType(HeaderType.Simple).setDepthLimits(startDepth, startDepth + stepDepth);\n    widget.addTrack(WellLogTrackType.IndexTrack).setWidth(80);\n    widget.addTrack(WellLogTrackType.LinearTrack).addChild([\n      this.createCurve(this.grData, KnownColors.Orange).setNormalizationLimits(0, 200),\n      this.createCurve(this.caliData, KnownColors.Green).setNormalizationLimits(6, 12),\n      this.createCurve(this.spData, KnownColors.Blue).setNormalizationLimits(-90, -10)\n    ]);\n    widget.on(WellLogEvents.VisibleDepthLimitsChanged, this.onLimitsChange.bind(this));\n    widget.on(WellLogEvents.VisibleDepthLimitsChanged, () => {\n      this.synchronizeTableData();\n    });\n    widget.getToolByName(\"cross-hair\").on(CrossHairEvents.onPositionChanged, (evt, sender, event) => {\n      const position = event.getPosition();\n      if (isNaN(position.getY()) || isNaN(position.getX())) {\n        return;\n      }\n      const depth = position.getY();\n      const closest = Math.floor((depth - startDepth) / stepDepth);\n      this._tableWidget.highlightRow(closest);\n    });\n    widget.getToolByName(\"TrackPlotVerticalScroll\").on(ScrollEvents.onScroll, () => {\n      const limits = widget.getVisibleDepthLimits();\n      const top = (limits.getLow() - startDepth) / stepDepth;\n      const bottom = top + this._tableWidget.getVisibleTableLimits().getHeight();\n      this._tableWidget.setVisibleTableLimits(Math.ceil(top));\n      this._tableWidget.setVisibleTableLimits(Math.floor(bottom));\n    });\n    widget.getToolByName(\"splitter\").setEnabled(true).on(SplitterEvents.onCanResize, (evt, sender, event) => {\n      event.reject();\n    });\n    return widget;\n  }\n  initializeTableWidget() {\n    const tableWidget = new TableView({\n      \"horizontalscroll\": \"floating\",\n      \"verticalscroll\": \"floating\",\n      \"indexwidth\": 50,\n      \"cols\": COLS.length,\n      \"bounds\": new Rect(300, 0, 665, 400)\n    });\n    const crosshair = this._wellLogWidget.getToolByName(\"cross-hair\");\n    tableWidget.getToolByName(\"TableViewHighlight\").on(HighlightEvents.onHover, (evt, sender, eventArgs) => {\n      const depth = startDepth + stepDepth * eventArgs.getRowNumber();\n      crosshair.setPosition(new Point(0, depth));\n    }).on(AbstractToolEvents.onLeave, () => {\n      crosshair.setPosition(new Point(0, NaN));\n    });\n    const synchronizeLimits = () => {\n      const limits = tableWidget.getVisibleTableLimits();\n      const top = Math.floor(limits.getTop());\n      const low = startDepth + stepDepth * top + stepDepth * (limits.getTop() - top);\n      const high = low + this._wellLogWidget.getVisibleDepthLimits().getSize();\n      this._wellLogWidget.setVisibleDepthLimits(low, high);\n    };\n    tableWidget.getToolByName(\"VerticalScroll\").on(ScrollEvents.onScroll, synchronizeLimits);\n    tableWidget.getToolByName(\"TableViewPanning\").on(PanningEvents.onPanning, synchronizeLimits);\n    return tableWidget;\n  }\n  onLimitsChange(type, src, args) {\n    if (args[\"new\"].getHigh() < this.caliData.getMaxDepth()) {\n      this.depthAutoScroll = false;\n    } else {\n      this.depthAutoScroll = true;\n    }\n  }\n  disableRubberBand() {\n    this._wellLogWidget.getToolByName(\"rubberband\").setEnabled(false);\n  }\n  zoomIn() {\n    this._wellLogWidget.scale(5 / 4);\n    this.disableRubberBand();\n  }\n  zoomOut() {\n    this._wellLogWidget.scale(4 / 5);\n    this.disableRubberBand();\n  }\n  fitToHeight() {\n    this._wellLogWidget.fitToHeight();\n    this.disableRubberBand();\n  }\n  rubberBandZoom() {\n    this._wellLogWidget.getToolByName(\"rubberband\").setEnabled(true);\n  }\n  createCurve(dataSource, color) {\n    return new LogCurve(dataSource).setLineStyle({\n      \"color\": color,\n      \"width\": 2\n    });\n  }\n  initialize(canvas) {\n    this._plot = new Plot({\n      \"canvaselement\": canvas,\n      \"root\": new Group().setAutoModelLimitsMode(true).setLayout(new CssLayout()).addChild([\n        this._wellLogWidget = this.initializeWellLog().setLayoutStyle({\n          \"left\": 0,\n          \"top\": 0,\n          \"width\": 300,\n          \"bottom\": 0\n        }),\n        this._tableWidget = this.initializeTableWidget()\n      ])\n    });\n    this._wellLogWidget.setHeaderHeight(\"auto\").setDepthScale(5);\n    this.synchronizeTableData();\n  }\n  runData() {\n    let index = 0;\n    const updateData = () => {\n      if (this.caliData != null) {\n        if (index >= this.curveData.length) {\n          this.caliData.clear();\n          index = 0;\n          startIndex = 0;\n        }\n        if (this.caliData.getSize() >= maxCachedSize) {\n          startIndex = index - maxCachedSize / 2;\n          this.caliData.trimValues(this.caliData.getMinDepth(), startDepth + startIndex * stepDepth);\n        }\n        const start = startDepth + startIndex * stepDepth;\n        const depth = startDepth + index * stepDepth;\n        const depthOffset = 5;\n        this.caliData.addValue(depth, curveData[\"CALI\"][index]);\n        this.grData.addValue(depth, curveData[\"GR\"][index]);\n        this.spData.addValue(depth, curveData[\"SP\"][index]);\n        this._wellLogWidget.setDepthLimits(start, depth + depthOffset);\n        if (this.depthAutoScroll) {\n          this._wellLogWidget.scrollToIndex(depth + depthOffset, ScrollToLocation.BOTTOM, false);\n        }\n        this.synchronizeTableData();\n        index++;\n      }\n    };\n    this.timer = window.setInterval(updateData, TIME_REFRESH);\n  }\n  getPlot() {\n    return this._plot;\n  }\n  dispose() {\n    if (this.timer) {\n      clearInterval(this.timer);\n    }\n    if (this._plot) {\n      this._plot.dispose();\n    }\n  }\n}\nfunction createScene(canvas) {\n  const app = new RealTimeInteraction();\n  app.initialize(canvas);\n  return app;\n}\nexport { createScene };\n\ncreateScene(document.querySelector('[ref=\"plot\"]'));\n\n","lang":"ts"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"css","disable":false},"children":[{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"css","header":{"controls":{"copy":{}}},"source":"\n.cg-tooltip-holder {\n  position: relative;\n}\n\n.cg-tooltip {\n  position: absolute;\n  display: block;\n  padding: 2px 12px 3px 7px;\n  overflow: visible !important;\n  font-family: Roboto, Helvetica, Arial, sans-serif;\n  font-size: 13px;\n  background: white !important;\n  opacity: 0.9;\n  color: #333333;\n  border: solid 1px gray;\n  border-radius: 5px;\n  text-align: left;\n  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);\n  border-radius: 5px;\n  margin: 0 !important;\n  z-index: 10000;\n  max-width: 400px;\n  text-wrap: normal !important;\n  white-space: normal !important;\n}\n/* Default setting for tooltip */\n.cg-tooltip-container {\n  position: absolute;\n  display: block;\n  overflow: visible !important;\n  font-family: Roboto, Helvetica, Arial, sans-serif;\n  font-size: 12px;\n  padding: 3px 7px;\n  background: #f7f7f7;\n  color: #333333;\n  border: 1px solid #938e8e;\n  opacity: 0.8;\n  text-align: left;\n  box-shadow: 3px 3px 10px #888;\n  margin: 0 !important;\n  z-index: 10000;\n  max-width: 400px;\n  text-wrap: normal !important;\n  white-space: normal !important;\n  user-select: none;\n}\n@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {\n  .cg-tooltip-container {\n    border-radius: 0;\n  }\n}\n/* Default left arrow for tooltip */\n.cg-tooltip-arrow-left::before {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  left: 0;\n  top: 50%;\n  border: 5px solid transparent;\n  border-left: 0;\n  border-right: 5px solid  #938e8e;\n  transform: translate(calc(-100%), -50%);\n}\n.cg-tooltip-arrow-left::after {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  left: 0;\n  top: 50%;\n  border: 4px solid transparent;\n  border-left: 0;\n  border-right: 4px solid #f7f7f7;\n  transform: translate(calc(-100%), -50%);\n}\n/* Default top arrow for tooltip */\n.cg-tooltip-arrow-top::before {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  left: 50%;\n  top: 0;\n  border: 5px solid transparent;\n  border-top: 0;\n  border-bottom: 5px solid #938e8e;\n  transform: translate(-50%, -100%);\n}\n.cg-tooltip-arrow-top::after {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  left: 50%;\n  top: 0;\n  border: 4px solid transparent;\n  border-top: 0;\n  border-bottom: 4px solid #f7f7f7;\n  transform: translate(-50%, -100%);\n}\n/* Default right arrow for tooltip */\n.cg-tooltip-arrow-right::before {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  right: 0;\n  top: 50%;\n  border: 5px solid transparent;\n  border-right: 0;\n  border-left: 5px solid #938e8e;\n  transform: translate(100%, -50%);\n}\n.cg-tooltip-arrow-right::after {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  right: 0;\n  top: 50%;\n  border: 4px solid transparent;\n  border-right: 0;\n  border-left: 4px solid #f7f7f7;\n  transform: translate(100%, -50%);\n}\n/* Default bottom arrow for tooltip */\n.cg-tooltip-arrow-bottom::before {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  left: 50%;\n  bottom: 0px;\n  border: 5px solid transparent;\n  border-bottom: 0;\n  border-top: 5px solid #938e8e;\n  transform: translate(-50%, 100%);\n  z-index: 10000;\n}\n.cg-tooltip-arrow-bottom::after {\n  content: '';\n  position: absolute;\n  display: block;\n  width: 0px;\n  left: 50%;\n  bottom: 0;\n  border: 4px solid transparent;\n  border-bottom: 0;\n  border-top: 4px solid #f7f7f7;\n  transform: translate(-50%, 100%);\n  z-index: 10000;\n}\n/* Tooltip item name */\n/* Tooltip item value */\n/* .cg-tooltip-item-value */\n/* Tooltip item value */\n.cg-tooltip-item-unit {\n  text-transform: none;\n}\n\n.cg-tooltip-item-name {\n    text-transform: capitalize;\n    white-space: nowrap;\n    vertical-align: middle;\n    font-size: 13px;\n}\n.cg-tooltip-row {\n  display: flex;\n  flex-direction: row;\n  align-items: center;\n  white-space: pre-wrap;\n  font-size: 12px;\n  line-height: 100%;\n  margin: 1px 0;\n}\n.cg-tooltip-title {\n  font-size: 13px;\n  height: 14px;\n  text-transform: capitalize;\n}\n.cg-tooltip-title .cg-tooltip-symbol {\n  margin-right: 0 !important;\n}\n.cg-tooltip-title-name {\n  vertical-align: middle;\n}\n.cg-tooltip-row + .cg-tooltip-row {\n  margin-top: 4px;\n}\n.cg-tooltip-row.cg-tooltip-title + .cg-tooltip-row {\n  margin-top: 5px;\n}\n.cg-tooltip-item-value + .cg-tooltip-item-unit {\n    margin-left: 1px;\n}\n/* Tooltip symbol */\n.cg-tooltip-symbol-cell {\n  display: inline-flex;\n  min-width: 13px; /* 10px size + 3px margin */\n}\n.cg-tooltip-symbol {\n  margin-right: 3px;\n  background-color: transparent;\n  display: block;\n}\n.cg-tooltip-symbol > img {\n  display: block;\n}\n.cg-tooltip-list-cell {\n  display: inline-flex;\n}\n.cg-tooltip-list-symbol {\n  display: block;\n  margin-right: 3px;\n  width: 6px;\n  height: 6px;\n  vertical-align: middle;\n  border-radius: 50%;\n  border: 1px solid rgba(0,0,0,.4);\n}\n.cg-tooltip-symbol-legacy {\n  border-radius: 4px;\n  margin-right: 5px;\n  height: 8px;\n  width: 8px;\n  display: inline-block;\n}\n.cg-tooltip-title-legacy {\n  font-weight: 900;\n}\n\n/* Tooltip symbol circle */\n.cg-tooltip-symbol.circle {\n  height: 10px;\n  width: 10px;\n  display: inline-block;\n  border-radius: 50%;\n  border: 1px solid rgba(0,0,0,.4);\n}\n/* Tooltip symbol line */\n.cg-tooltip-symbol.line {\n    height: 10px;\n    width: 10px;\n    display: inline-block;\n    transform: scale(1.2, 0.2);\n}\n/* Tooltip symbol diamond */\n.cg-tooltip-symbol.diamond {\n    height: 10px;\n    width: 10px;\n    display: inline-block;\n    transform: rotate(45deg);\n    border-radius: 0px;\n}\n/* Tooltip symbol square */\n.cg-tooltip-symbol.square {\n    height: 10px;\n    width: 10px;\n    display: inline-block;\n    border-radius: 0px;\n    border: 1px solid rgba(0,0,0,.4);\n}\n\n","lang":"css"},"children":[]}]}]},{"$$mdtype":"Tag","name":"iframe","attributes":{"src":"https://dc2-documentation.s3.amazonaws.com/documentation/slb-docs-test/5.0/examples/vue/tutorials/index.html#/WellLog/AdditionalFunctionality/TableViewInteraction/tableViewInteraction?section=realTimeInteraction&extract=true","width":"100%","height":"482.5px","style":{"border":"none"}},"children":[]}]},"headings":[{"value":"TableView Interaction","id":"tableview-interaction","depth":1},{"value":"TableView Interaction","id":"tableview-interaction-1","depth":3},{"value":"WellLog Widget Initialization","id":"welllog-widget-initialization","depth":3},{"value":"TableView Widget Initialization","id":"tableview-widget-initialization","depth":3},{"value":"Export To PDF","id":"export-to-pdf","depth":3},{"value":"Real-Time Interaction","id":"real-time-interaction","depth":3}],"frontmatter":{"title":"TableView Interaction","seo":{"title":"TableView Interaction"}},"lastModified":"2026-02-11T19:54:32.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/solutions/geotoolkit/tutorials/well-log/additional-functionality/table-view-interaction","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}