{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["tabs","tab"]},"type":"markdown"},"seo":{"title":"Custom Visual","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":"custom-visual","__idx":0},"children":["Custom Visual"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This tutorial show how to create own simple visual with sinus and circle geometry"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To implement a custom visual, perform these steps:"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"i-extend-base-class-it-can-be-logabstractvisual","__idx":1},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#customvisual"},"children":["#"]}," I. Extend base class. It can be LogAbstractVisual"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"implement-rendering-method","__idx":2},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#Render"},"children":["#"]}," Implement rendering method"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement .renderContent() - the method determines what to draw"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"set-up-model-limits","__idx":3},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#Model"},"children":["#"]}," Set up model limits"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Override .getModelLimits() if need. By default visual has track's model limits"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"set-up-serialization","__idx":4},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#Serialization"},"children":["#"]}," Set up serialization"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Override .setProperties() and .getProperties() if serialisation is needed"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"provide-data","__idx":5},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#Data"},"children":["#"]}," Provide data"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Add data setting via .setData() or constructor. Name and type can vary, it's up to the author."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"ii-adding-own-tooltip","__idx":6},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#CustomTooltip"},"children":["#"]}," II. Adding own tooltip"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To add custom tooltip, perform these steps:"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"handle-selection-in-visual","__idx":7},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#Selection"},"children":["#"]}," Handle selection in visual"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In .renderContent() implement selection"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"add-hit-test-to-visual","__idx":8},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#HitTest"},"children":["#"]}," Add hit test to visual"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Add method .hitTest() which creates Selector"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"create-new-class-for-tooltip","__idx":9},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#TooltipClass"},"children":["#"]}," Create new class for Tooltip"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create own tooltip extending NodeTooltip, it should call .hitTest() to get the data"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"register-tooltip","__idx":10},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#RegisterTooltip"},"children":["#"]}," Register tooltip"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Create ToolTipTool instance and register there custom tooltip"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"iii-adding-own-header","__idx":11},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#CustomHeader"},"children":["#"]}," III. Adding own header"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["To add custom tooltip, perform these steps:"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"create-new-class-for-header","__idx":12},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#HeaderClass"},"children":["#"]}," Create new class for header"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Extend new class from LogVisualHeader, implement render() and clone() methods"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"register-header","__idx":13},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#RegisterHeader"},"children":["#"]}," Register header"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Add custom header to LogVisualHeaderProvider - existing one or new one"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"full-example","__idx":14},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/WellLog/Visuals/CustomVisual/customVisual#full"},"children":["#"]}," Full example"]},{"$$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 { TrackType } from \"@int/geotoolkit/welllog/TrackType.ts\";\nimport { Plot } from \"@int/geotoolkit/plot/Plot.ts\";\nimport { createWellLogWidget } from \"/src/code/WellLog/utils/common.ts\";\nimport { SineVisual } from \"/src/code/WellLog/Visuals/CustomVisual/SineVisual.ts\";\nimport { FillStyle } from \"@int/geotoolkit/attributes/FillStyle.ts\";\nimport { LineStyle } from \"@int/geotoolkit/attributes/LineStyle.ts\";\nimport { LogVisualHeaderProvider } from \"@int/geotoolkit/welllog/header/LogVisualHeaderProvider.ts\";\nimport { SineVisualHeader } from \"/src/code/WellLog/Visuals/CustomVisual/SineVisualHeader.ts\";\nimport { SineVisualTooltip } from \"/src/code/WellLog/Visuals/CustomVisual/SineVisualTooltip.ts\";\nimport { ToolTipTool } from \"@int/geotoolkit/controls/tools/ToolTipTool.ts\";\nimport { ToolTipRegistry } from \"@int/geotoolkit/controls/tooltip/ToolTipRegistry.ts\";\nimport { DisplayType as HeaderContainerDisplayType } from \"@int/geotoolkit/welllog/HeaderContainer.ts\";\nconst COLORS = [\"darkgreen\", \"red\", \"black\", \"yellow\"];\nlet i = 0;\nconst getNextColor = () => COLORS[i++ % COLORS.length];\nconst lineStyle = new LineStyle({\n  \"color\": getNextColor(),\n  \"width\": 3\n});\nconst fillStyle = new FillStyle(getNextColor());\nfunction createSinusoidVisual(data) {\n  return new SineVisual(data).setLineStyle(lineStyle).setFillStyle(fillStyle);\n}\nlet logSinusoid;\nlet widget;\nfunction createScene(canvas) {\n  widget = createWellLogWidget().setDepthLimits(1704, 1716);\n  widget.addTrack(TrackType.IndexTrack);\n  logSinusoid = createSinusoidVisual({\n    depth: 1710,\n    angle: Math.PI / 6\n  });\n  const headerProvider = LogVisualHeaderProvider.getDefaultInstance().clone();\n  headerProvider.registerHeaderProvider(SineVisual.getClassName(), new SineVisualHeader(logSinusoid));\n  widget.getHeaderContainer().setHeaderProvider(headerProvider);\n  widget.connectTool(\n    new ToolTipTool({\n      \"layer\": widget,\n      \"registry\": new ToolTipRegistry().register(SineVisual.getClassName(), new SineVisualTooltip(\"Depth: ${depth} <br/> Angle: ${angle}&#8451;\"))\n    })\n  );\n  widget.addTrack(TrackType.LinearTrack).setWidth(400).addChild(logSinusoid);\n  widget.setHeaderHeight(\"auto\");\n  const plot = new Plot({\n    \"canvaselement\": canvas,\n    \"root\": widget\n  });\n  widget.fitToHeight();\n  return plot;\n}\nfunction changeStyles() {\n  lineStyle.setColor(getNextColor());\n  fillStyle.setColor(getNextColor());\n}\nfunction changeMicropositions() {\n  if (logSinusoid.getMicroPositionLeft() === 0)\n    logSinusoid.setMicroPosition(0.2, 1);\n  else\n    logSinusoid.setMicroPosition(0, 1);\n}\nfunction addFooter() {\n  widget.setProperties({\n    \"footer\": {\n      \"visible\": true,\n      \"displaytype\": HeaderContainerDisplayType.Minimized,\n      \"margin\": 2,\n      \"padding\": 4,\n      \"height\": 50\n    }\n  });\n  widget.getFooterContainer().getHeaderProvider().registerHeaderProvider(SineVisual.getClassName(), new SineVisualHeader(logSinusoid));\n  widget.getFooterContainer().rebuild();\n}\nfunction toggleFooter() {\n  const isVisible = widget.getProperties()[\"footer\"][\"visible\"];\n  if (isVisible === \"none\")\n    addFooter();\n  else\n    widget.setProperties({ \"footer\": { \"visible\": !isVisible } });\n}\nexport { changeMicropositions, changeStyles, createScene, toggleFooter };\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/CustomVisual/customVisual?section=full&extract=true","width":"100%","height":"498.5px","style":{"border":"none"}},"children":[]}]},"headings":[{"value":"Custom Visual","id":"custom-visual","depth":1},{"value":"I. Extend base class. It can be LogAbstractVisual","id":"i-extend-base-class-it-can-be-logabstractvisual","depth":3},{"value":"Implement rendering method","id":"implement-rendering-method","depth":3},{"value":"Set up model limits","id":"set-up-model-limits","depth":3},{"value":"Set up serialization","id":"set-up-serialization","depth":3},{"value":"Provide data","id":"provide-data","depth":3},{"value":"II. Adding own tooltip","id":"ii-adding-own-tooltip","depth":3},{"value":"Handle selection in visual","id":"handle-selection-in-visual","depth":3},{"value":"Add hit test to visual","id":"add-hit-test-to-visual","depth":3},{"value":"Create new class for Tooltip","id":"create-new-class-for-tooltip","depth":3},{"value":"Register tooltip","id":"register-tooltip","depth":3},{"value":"III. Adding own header","id":"iii-adding-own-header","depth":3},{"value":"Create new class for header","id":"create-new-class-for-header","depth":3},{"value":"Register header","id":"register-header","depth":3},{"value":"Full example","id":"full-example","depth":3}],"frontmatter":{"title":"Custom Visual","seo":{"title":"Custom Visual"}},"lastModified":"2026-02-11T19:54:32.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/solutions/geotoolkit/tutorials/well-log/visuals/custom-visual","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}