{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["tabs","tab"]},"type":"markdown"},"seo":{"title":"Stacked Track","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":"stacked-track","__idx":0},"children":["Stacked Track"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A stacked track serves as a container for all kinds of geotoolkit tracks and visuals. It can be added to the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["geotoolkit/welllog/widgets/WellLogWidget"]}," like any other track using ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["addTrack()"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This example shows how to create a ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["geotoolkit/welllog/StackedTrack"]},". An instance of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["geotoolkit/welllog/TrackFactory"]}," is used to create tracks. Curves are added to these tracks and then inserted into the Stacked Track. The header is automatically generated for all the curves in the track. The orientation can also be changed as shown in the example below."]},{"$$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 { Plot } from \"@int/geotoolkit/plot/Plot.ts\";\nimport { Node } from \"@int/geotoolkit/scene/Node.ts\";\nimport { LogTrack } from \"@int/geotoolkit/welllog/LogTrack.ts\";\nimport { LogAbstractVisual } from \"@int/geotoolkit/welllog/LogAbstractVisual.ts\";\nimport { Orientation } from \"@int/geotoolkit/util/Orientation.ts\";\nimport { LogAxis } from \"@int/geotoolkit/welllog/LogAxis.ts\";\nimport { TrackFactory } from \"@int/geotoolkit/welllog/TrackFactory.ts\";\nimport { StackedTrack } from \"@int/geotoolkit/welllog/StackedTrack.ts\";\nimport { TrackType } from \"@int/geotoolkit/welllog/TrackType.ts\";\nimport { HeaderType } from \"@int/geotoolkit/welllog/header/LogAxisVisualHeader.ts\";\nimport { createCurve } from \"/src/code/WellLog/utils/curveData.ts\";\nimport { createWellLogWidget } from \"/src/code/WellLog/utils/common.ts\";\nfunction createScene(canvas) {\n  const widget = createWellLogWidget().setAxisHeaderType(HeaderType.Simple);\n  const headerProvider = widget.getHeaderContainer().getHeaderProvider();\n  const axisHeader = headerProvider.getHeaderProvider(LogAxis.getClassName()).clone();\n  axisHeader.setFormatHeaderHandler((sender, axis) => {\n    const track = axis.getTrack();\n    const visibleHeight = Math.round(track.getVisibleModelLimits().getHeight() * 100) / 100;\n    const unitInfo = track.getUnitInfo();\n    return \"Depth<br><br>Visible<br>\" + visibleHeight + (unitInfo ? \"<br>(\" + unitInfo.getIndexUnit().getSymbol() + \")\" : \"\");\n  });\n  headerProvider.registerHeaderProvider(LogAxis.getClassName(), axisHeader);\n  widget.addTrack(TrackType.IndexTrack);\n  const factory = TrackFactory.getInstance();\n  const stackedTrack = factory.createTrack(TrackType.StackedTrack, {\n    \"width\": 450\n  }).addChild([\n    createCurve(4500, 4, \"CALI\", \"#2196f3\"),\n    createCurve(4500, 4, \"RILM\", \"#fdd835\")\n  ]);\n  stackedTrack.addTrack([\n    factory.createTrack(TrackType.LinearTrack, {\n      \"width\": 30,\n      \"border\": {\n        \"visible\": true\n      }\n    }).addChild([\n      createCurve(4500, 10, \"GR\", \"#7cb342\"),\n      createCurve(4500, 10, \"DLT\", \"#212121\")\n    ]),\n    factory.createTrack(TrackType.LinearTrack, {\n      \"width\": 50,\n      \"border\": {\n        \"visible\": true\n      }\n    }).addChild([\n      createCurve(4500, 10, \"CALI\", \"#ef6c00\")\n    ])\n  ]);\n  const nestedStackedTrack = factory.createTrack(TrackType.StackedTrack, {\n    \"width\": 100\n  }).addChild([\n    createCurve(4500, 4, \"CALI\", \"#2196f3\")\n  ]);\n  nestedStackedTrack.addTrack([\n    factory.createTrack(TrackType.LinearTrack, {\n      \"width\": 30,\n      \"border\": {\n        \"visible\": true\n      }\n    }).addChild([\n      createCurve(4500, 10, \"GR\", \"#7cb342\")\n    ]),\n    factory.createTrack(TrackType.LinearTrack, {\n      \"width\": 50,\n      \"border\": {\n        \"visible\": true\n      }\n    }).addChild([\n      createCurve(4500, 10, \"DLT\", \"#212121\")\n    ])\n  ]);\n  widget.addTrack(stackedTrack);\n  widget.addTrack(TrackType.IndexTrack);\n  stackedTrack.addTrack(nestedStackedTrack);\n  widget.setHeaderHeight(\"auto\");\n  return {\n    plot: new Plot({\n      \"canvaselement\": canvas,\n      \"root\": widget\n    }),\n    widget\n  };\n}\nfunction changeOrientation(widget) {\n  if (widget.getOrientation() === Orientation.Vertical) {\n    widget.setOrientation(Orientation.Horizontal);\n  } else {\n    widget.setOrientation(Orientation.Vertical);\n  }\n}\nfunction addCurve(widget) {\n  const tracks = widget.getSelectedTracks();\n  const track = tracks.length === 2 ? tracks[1] : widget.getTrackContainer().getChildren().toArray().find((track2) => track2 instanceof StackedTrack);\n  if (track == null) {\n    return;\n  }\n  const mnemonics = [\"CALI\", \"DLT\", \"GR\", \"RILD\", \"RHOB\", \"RILM\", \"RLL8\", \"SP\"];\n  const curve = mnemonics[Math.floor(Math.random() * mnemonics.length)];\n  const r = Math.random() * 255 >> 0;\n  const g = Math.random() * 255 >> 0;\n  const b = Math.random() * 255 >> 0;\n  track.addChild([\n    createCurve(4500, 10, curve, \"rgb(\" + r + \",\" + g + \",\" + b + \")\")\n  ]);\n}\nfunction addTrack(widget) {\n  const stackedTrack = widget.getTrackContainer().getChildren().toArray().find((track) => track instanceof StackedTrack);\n  if (stackedTrack == null)\n    return;\n  stackedTrack.addTrack(\n    TrackFactory.getInstance().createTrack(TrackType.LinearTrack, {\n      \"width\": 50,\n      \"border\": {\n        \"visible\": true\n      }\n    })\n  );\n}\nfunction deleteSelection(widget) {\n  const selection = widget.getToolByName(\"pick\").getSelection();\n  let logVisualDeleted = false;\n  for (let i = selection.length - 1; i >= 0; i--) {\n    const node = selection[i];\n    if (node instanceof LogAbstractVisual && node.getParent() != null) {\n      node.getParent().removeChild(node);\n      logVisualDeleted = true;\n    }\n    if (logVisualDeleted === false && node instanceof LogTrack) {\n      const stackedTrack = Node.findParent(node, StackedTrack);\n      if (stackedTrack != null) {\n        stackedTrack.removeTrack(node);\n      }\n      return;\n    }\n  }\n}\nexport { addCurve, addTrack, changeOrientation, createScene, deleteSelection };\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/Visuals/StackedTrack/stackedTrack?section=introduction&extract=true","width":"100%","height":"748.5px","style":{"border":"none"}},"children":[]}]},"headings":[{"value":"Stacked Track","id":"stacked-track","depth":1}],"frontmatter":{"title":"Stacked Track","seo":{"title":"Stacked Track"}},"lastModified":"2026-02-11T19:54:32.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/solutions/geotoolkit/tutorials/well-log/visuals/stacked-track","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}