{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["tabs","tab"]},"type":"markdown"},"seo":{"title":"Coordinate Transformation","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":"coordinate-transformation","__idx":0},"children":["Coordinate Transformation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Transforming internal depth coordinates into canvas ones is trivial task in the only case of ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["geotoolkit/schematics/scene/WellBoreNode/ViewMode/Regular"]},". In other view modes - ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Compressed"]}," and ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["KeepAspectRatio"]}," - depth axis scale is piece-linear one. So ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/doc/classes/geotoolkit.axis.piecelinearvaluetransformer.piecelinearvaluetransformer.html"},"children":["PieceLinearValueTransformer"]}]}," class is developed that handles \"internal\" transforming from linear to piece-linear model space (and vice versa).",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"Familiarization with ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/doc/enums/geotoolkit.schematics.scene.wellborenode.viewmode.html"},"children":["ViewMode"]}]}," enumeration type as well as ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/Schematics/GettingStarted/gettingStarted"},"children":["Getting Started"]}," tutorial in SchematicsJS is beneficial."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"transformation","__idx":1},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/Schematics/CoordinatesTransform/coordinatesTransform#transformation"},"children":["#"]}," Transformation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The tutorial displays ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/doc/classes/geotoolkit.schematics.widgets.schematicswidget.schematicswidget.html"},"children":["SchematicsWidget"]}]}," within HTML5 canvas limits.",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"On other hand set of ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["textarea"]}," HTML elements (one per each schematics component) are displayed ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["outside"]}]}," the canvas.",{"$$mdtype":"Tag","name":"br","attributes":{},"children":[]},"Method \"modelDepthToCanvas\" is used to synchronize the text areas vertically with their respective schematics components."]},{"$$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 { getPixelScale } from \"@int/geotoolkit/base.js\";\nimport { Plot } from \"@int/geotoolkit/plot/Plot.ts\";\nimport { CompositeSchematicsWidget } from \"@int/geotoolkit/schematics/widgets/CompositeSchematicsWidget.ts\";\nimport { WellBoreData } from \"@int/geotoolkit/schematics/data/WellBoreData.ts\";\nimport { Point } from \"@int/geotoolkit/util/Point.ts\";\nimport { Alignment } from \"@int/geotoolkit/layout/BoxLayout.ts\";\nimport { Mode } from \"@int/geotoolkit/schematics/labeling/Mode.ts\";\nconst depths = [\n  341,\n  1020,\n  3e3,\n  4500,\n  14589\n];\nconst descriptions = [\n  \"Drive Pipe\",\n  \"Surface Casing\",\n  \"Intermediate Casing-1\",\n  \"Intermediate Casing-2\",\n  \"Production Casing\"\n];\nconst diameters = [\n  [26, 25],\n  [20, 19],\n  [13, 12],\n  [9.5, 9],\n  [7, 6.5]\n];\nfunction createData() {\n  const wellBoreData = new WellBoreData();\n  for (let i = 0; i < depths.length; ++i) {\n    wellBoreData.addComponent(\"casing\", {\n      description: descriptions[i],\n      geometry: {\n        depth: { from: 0, to: depths[i] },\n        diameter: { outer: diameters[i][0], inner: diameters[i][1] }\n      }\n    });\n  }\n  return wellBoreData;\n}\nconst elementHeight = 75;\nconst elementWidth = 250;\nconst xGap = 5;\nconst pt = new Point();\nlet plot = null;\nlet widget = null;\nlet elements = [];\nfunction modelDepthToCanvas(depthModel) {\n  pt.setPoint(0, depthModel);\n  widget.getDevicePoint(pt, pt);\n  return pt.getY();\n}\nfunction updateTextAreas() {\n  const canvas = plot.getContainingElement();\n  const dxCanvas = (canvas.offsetLeft + canvas.width) / getPixelScale();\n  for (let i = 0; i < depths.length; ++i) {\n    let depthCanvas = modelDepthToCanvas(depths[i]);\n    depthCanvas = Math.round(depthCanvas);\n    const textElement = elements[i];\n    textElement.style.left = dxCanvas + xGap + \"px\";\n    textElement.style.top = depthCanvas - elementHeight + \"px\";\n  }\n}\nfunction getExtendedComponentInfo(i) {\n  return descriptions[i] + \":\\ndepth: \" + depths[i] + \"\\nod: \" + diameters[i][0] + \" id: \" + diameters[i][1];\n}\nfunction createTextAreas(refParent) {\n  for (let i = 0; i < depths.length; ++i) {\n    const textElement = document.createElement(\"textarea\");\n    textElement.value = getExtendedComponentInfo(i);\n    textElement.style.backgroundColor = \"lightgray\";\n    textElement.style.borderRadius = \"6px\";\n    textElement.style.borderWidth = \"1px\";\n    textElement.style.position = \"absolute\";\n    textElement.style.height = elementHeight + \"px\";\n    textElement.style.width = elementWidth + \"px\";\n    refParent.appendChild(textElement);\n    elements.push(textElement);\n  }\n}\nfunction createScene(refCanvas) {\n  const data = createData();\n  widget = new CompositeSchematicsWidget({\n    \"alignment\": Alignment.Left,\n    \"labeling\": { \"mode\": Mode.NoLabels },\n    \"wellborenode\": {},\n    \"annotationssizes\": {\n      \"north\": 0,\n      \"south\": 0\n    },\n    \"tooltip\": {\n      \"autoflip\": true\n    },\n    \"data\": {\n      \"elements\": data\n    }\n  });\n  plot = new Plot({\n    \"canvaselement\": refCanvas,\n    \"root\": widget\n  });\n}\nfunction disposeScene() {\n  if (plot) {\n    plot.dispose();\n  }\n}\nfunction disposeTextAreas() {\n  if (elements && elements.length > 0) {\n    const parent = elements[0].parentNode;\n    for (let i = elements.length - 1; i >= 0; --i) {\n      const textElement = elements[i];\n      parent.removeChild(textElement);\n    }\n    elements = [];\n  }\n}\nexport { createScene, createTextAreas, disposeScene, disposeTextAreas, updateTextAreas };\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#/Schematics/CoordinatesTransform/coordinatesTransform?section=transformation&extract=true","width":"100%","height":"888.5px","style":{"border":"none"}},"children":[]}]},"headings":[{"value":"Coordinate Transformation","id":"coordinate-transformation","depth":1},{"value":"Transformation","id":"transformation","depth":3}],"frontmatter":{"title":"Coordinate Transformation","seo":{"title":"Coordinate Transformation"}},"lastModified":"2026-02-11T19:54:32.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/solutions/geotoolkit/tutorials/schematics/coordinates-transform","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}