{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-guides/sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["tabs","tab"]},"type":"markdown"},"seo":{"title":"Scene Editing Tools","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":"scene-editing-tools","__idx":0},"children":["Scene Editing Tools"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/Carnac/Tools/BasicTools/basicTools"},"children":["Basic Tools"]}," tutorial covered user interaction and scene control tools. This tutorial shows how editing/selection tools allows for quick addition of functionality to canvases."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"scene-editor","__idx":1},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/Carnac/Tools/SceneEditing/editor#Editor"},"children":["#"]}," Scene Editor"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The following canvas demonstrates the editing/selection tools such as shape selection, Rubber Band selection, polygon selection and tool for creating, moving and resizing shapes."]},{"$$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 { isNode } from \"@int/geotoolkit/scene/Node.ts\";\nimport { Plot } from \"@int/geotoolkit/plot/Plot.ts\";\nimport { Panning } from \"@int/geotoolkit/controls/tools/Panning.ts\";\nimport { Transformation } from \"@int/geotoolkit/util/Transformation.ts\";\nimport { Events as SelectionEvents, Selection } from \"@int/geotoolkit/controls/tools/Selection.ts\";\nimport { Shape } from \"@int/geotoolkit/scene/shapes/Shape.ts\";\nimport { Events as AbstractToolEvents } from \"@int/geotoolkit/controls/tools/AbstractTool.ts\";\nimport { PolygonSelection } from \"@int/geotoolkit/controls/tools/PolygonSelection.ts\";\nimport { Layer } from \"@int/geotoolkit/scene/Layer.ts\";\nimport { CompositeTool } from \"@int/geotoolkit/controls/tools/CompositeTool.ts\";\nimport { RubberBandShapeMode } from \"@int/geotoolkit/controls/tools/RubberBandShapeMode.ts\";\nimport { CircularMode } from \"@int/geotoolkit/controls/tools/CircularMode.ts\";\nimport { EditMode } from \"@int/geotoolkit/controls/tools/EditMode.ts\";\nimport { SelectionMode } from \"@int/geotoolkit/controls/tools/SelectionMode.ts\";\nimport { RubberBandMode } from \"@int/geotoolkit/controls/tools/RubberBandMode.ts\";\nimport { initializeDoubleClickHandler, initializeRubberBandZoom } from \"/src/code/Carnac/Tools/SceneEditing/ts/tools.ts\";\nimport { DATA_LAYER_ID } from \"/src/code/Carnac/Tools/SceneEditing/ts/model.ts\";\nimport { EditEvents } from \"@int/geotoolkit/controls/tools/EditEvents.ts\";\nimport { Helpers } from \"/src/code/Carnac/Tools/SceneEditing/ts/Helpers.ts\";\nimport { Rect } from \"@int/geotoolkit/util/Rect.ts\";\nimport { CustomShape } from \"/src/code/Carnac/Tools/SceneEditing/ts/shapes/CustomShape.ts\";\nimport { Rectangle } from \"@int/geotoolkit/scene/shapes/Rectangle.ts\";\nimport { KnownColors } from \"@int/geotoolkit/util/ColorUtil.ts\";\nimport { Spline } from \"@int/geotoolkit/scene/shapes/Spline.ts\";\nimport { Polyline } from \"@int/geotoolkit/scene/shapes/Polyline.ts\";\nimport { Text } from \"@int/geotoolkit/scene/shapes/Text.ts\";\nimport { BaseLineStyle } from \"@int/geotoolkit/attributes/TextStyle.ts\";\nimport { Line } from \"@int/geotoolkit/scene/shapes/Line.ts\";\nimport { Point } from \"@int/geotoolkit/util/Point.ts\";\nimport { SymbolShape } from \"@int/geotoolkit/scene/shapes/SymbolShape.ts\";\nimport { CirclePainter } from \"@int/geotoolkit/scene/shapes/painters/CirclePainter.ts\";\nexport const SelectionToolsMode = {\n  Panning: \"Panning\",\n  RubberBandZoom: \"RubberBandZoom\",\n  PointSelection: \"PointSelection\",\n  RubberBandSelection: \"RubberBandSelection\",\n  PolygonSelection: \"PolygonSelection\",\n  CircularSelection: \"CircularSelection\"\n};\nclass SceneEditor {\n  constructor(canvas, update) {\n    this._annotatedWidget = Helpers.createAnnotatedWidget(\n      new Rect(0, 0, 400, 400),\n      [\n        new CustomShape({\n          \"bounds\": new Rect(300, 200, 400, 300),\n          \"linestyle\": {\n            \"color\": \"black\",\n            \"pixelsnapmode\": true\n          },\n          \"fillstyle\": \"rgb(144, 238, 144)\"\n        }),\n        new Rectangle({\n          \"left\": 60,\n          \"top\": 60,\n          \"width\": 150,\n          \"height\": 150,\n          \"fillstyle\": KnownColors.Blue\n        }),\n        new Spline({\n          \"x\": [100, 50, 150, 200, 300, 350],\n          \"y\": [350, 300, 200, 150, 50, 100],\n          \"linestyle\": {\n            \"color\": KnownColors.Orange,\n            \"width\": 2\n          }\n        }),\n        new Polyline({\n          \"x\": [200, 250, 300],\n          \"y\": [350, 300, 350],\n          \"linestyle\": KnownColors.Red\n        }),\n        new Text({\n          \"text\": \"select me\",\n          \"ax\": 220,\n          \"ay\": 280,\n          \"textstyle\": {\n            \"baseline\": BaseLineStyle.Alphabetic\n          }\n        }).setUserSize(80, 20),\n        new Line({\n          \"from\": new Point(230, 230),\n          \"to\": new Point(330, 130),\n          \"linestyle\": KnownColors.Green\n        }),\n        new SymbolShape({\n          \"ax\": 150,\n          \"ay\": 330,\n          \"width\": 50,\n          \"height\": 50,\n          \"linestyle\": \"black\",\n          \"fillstyle\": \"white\",\n          \"painter\": CirclePainter\n        })\n      ]\n    );\n    this._plot = new Plot({\n      \"canvaselement\": canvas,\n      \"root\": this._annotatedWidget\n    });\n    this.initializeTools();\n    this._shapeManipulator.getHistory().on(EditEvents.CommandApplied, update);\n  }\n  initializeTools() {\n    this._panning = this._annotatedWidget.getToolByType(Panning);\n    const manipulatorLayer = this._annotatedWidget.getManipulatorLayer();\n    const selectionLayer = new Layer();\n    this._annotatedWidget.getModel().addChild([\n      selectionLayer\n    ]);\n    this._manipulators = [\n      this._rubberBandZoom = initializeRubberBandZoom(selectionLayer),\n      this._rubberBandSelection = this.initializeRubberBandSelection(selectionLayer),\n      this._polygonSelection = this.initializePolygonSelection(selectionLayer)\n    ];\n    const dataLayer = this._annotatedWidget.getModel().getChildren((child) => child.getId() === DATA_LAYER_ID).next();\n    this._annotatedWidget.getTool().insert(0, [\n      initializeDoubleClickHandler(this._plot, selectionLayer),\n      new CompositeTool(this._annotatedWidget.getModel(), \"shapeManipulator\").add([\n        this._shapeManipulator = Helpers.createShapeManipulator(dataLayer, manipulatorLayer)\n      ]),\n      new CompositeTool(this._annotatedWidget.getModel(), \"selectionTools\").add(this._manipulators)\n    ]);\n  }\n  onSelectionEnd(selectedItems) {\n    const selection = selectedItems.filter(isNode);\n    if (selection == null || selection.length === 0) {\n      return this;\n    }\n    const shapes = [];\n    for (let i = 0; i < selection.length; i++) {\n      const parent = selection[i].getParent();\n      if (parent != null && parent.getId() === DATA_LAYER_ID) {\n        shapes.push(selection[i]);\n      }\n    }\n    const node = shapes.length > 0 ? shapes.length > 1 ? shapes : shapes[0] : null;\n    this._shapeManipulator.editNode(node);\n    return this;\n  }\n  initializeRubberBandSelection(manipulatorLayer) {\n    return new Selection({\n      \"name\": \"RubberBandSelection\",\n      \"layer\": manipulatorLayer\n    }).setEnabled(false).setAutoDisabled(true).setSelectionMode(SelectionMode.RubberBand).setRubberBandMode(RubberBandMode.Inside).on(SelectionEvents.onSelectionEnd, (evt, sender, event) => {\n      this.onSelectionEnd(event.getSelection());\n    }).on(AbstractToolEvents.onEnabledStateChanged, (evt, sender) => {\n      if (sender.isEnabled() === false) {\n        this._shapeManipulator.setEnabled(true);\n        this.toggleTool(SelectionToolsMode.Panning);\n      }\n    });\n  }\n  initializePolygonSelection(manipulatorLayer) {\n    return new PolygonSelection({\n      \"name\": \"PolygonSelection\",\n      \"layer\": manipulatorLayer\n    }).setEnabled(false).setAutoDisabled(true).setNodeFilter((nodes) => nodes.filter((visual) => visual instanceof Shape)).on(SelectionEvents.onSelectionEnd, (eventType, sender, event) => {\n      this.onSelectionEnd(event.getSelection());\n      const editor = this._shapeManipulator.getEditor();\n      if (editor != null) {\n        editor.setEditMode(EditMode.EditNode);\n      }\n    }).on(AbstractToolEvents.onEnabledStateChanged, (eventType, sender) => {\n      if (sender.isEnabled() === false) {\n        this._shapeManipulator.setEnabled(true);\n        this.toggleTool(SelectionToolsMode.Panning);\n      }\n    });\n  }\n  execute(command) {\n    this._shapeManipulator.getHistory().push(command);\n  }\n  undo() {\n    this._shapeManipulator.undo();\n  }\n  getUIOptions() {\n    return {\n      canUndo: this._shapeManipulator.canUndo(),\n      canRedo: this._shapeManipulator.canRedo()\n    };\n  }\n  redo() {\n    this._shapeManipulator.redo();\n  }\n  toggleGhostMode(ghostMode) {\n    let mode = this._shapeManipulator.getEditMode();\n    if (ghostMode === true) {\n      const editor = this._shapeManipulator.getEditor();\n      if (editor != null) {\n        editor.setEditMode(EditMode.EditNode);\n      }\n      mode |= EditMode.Ghost;\n    } else if (ghostMode === false) {\n      mode &= ~EditMode.Ghost;\n    } else {\n      mode ^= EditMode.Ghost;\n    }\n    this._shapeManipulator.setEditMode(mode);\n  }\n  insertNode(nodeId) {\n    this._shapeManipulator.insertNode(nodeId);\n  }\n  scaleModel(scale) {\n    if (scale == null) {\n      this._annotatedWidget.setModelTransformation(new Transformation());\n    } else {\n      this._annotatedWidget.scaleModel(scale, scale);\n    }\n  }\n  getToolByName(toolName) {\n    return this._plot.getTool().getToolByName(toolName);\n  }\n  toggleTool(toolType) {\n    this._manipulators.forEach((tool) => {\n      tool.setEnabled(false);\n    });\n    let activeTool = SelectionToolsMode.Panning;\n    switch (toolType) {\n      case SelectionToolsMode.RubberBandZoom:\n        if (this._activeTool !== toolType) {\n          activeTool = toolType;\n          this._rubberBandZoom.setEnabled(true);\n        }\n        break;\n      case SelectionToolsMode.PointSelection:\n        if (this._activeTool !== toolType) {\n          activeTool = toolType;\n          this._rubberBandSelection.setEnabled(false);\n          this._polygonSelection.setEnabled(false);\n          this._shapeManipulator.setEnabled(true);\n        }\n        break;\n      case SelectionToolsMode.RubberBandSelection:\n        if (this._activeTool !== toolType) {\n          activeTool = toolType;\n          this._rubberBandSelection.setEnabled(true);\n          this._rubberBandSelection.setRubberBandShapeMode(RubberBandShapeMode.Rectangular);\n          this._shapeManipulator.setEnabled(false);\n        } else {\n          this._shapeManipulator.setEnabled(true);\n        }\n        break;\n      case SelectionToolsMode.PolygonSelection:\n        if (this._activeTool !== toolType) {\n          activeTool = toolType;\n          this._polygonSelection.setEnabled(true);\n          this._shapeManipulator.setEnabled(false);\n        } else {\n          this._shapeManipulator.setEnabled(true);\n        }\n        break;\n      case SelectionToolsMode.CircularSelection:\n        if (this._activeTool !== toolType) {\n          activeTool = toolType;\n          this._rubberBandSelection.setEnabled(true);\n          this._rubberBandSelection.setRubberBandShapeMode(RubberBandShapeMode.Circular);\n          this._rubberBandSelection.setCircularMode(CircularMode.Corner);\n          this._rubberBandSelection.setLineStyle({\n            color: \"red\",\n            width: 2\n          });\n          this._rubberBandSelection.setTextStyle(\"red\");\n          this._rubberBandSelection.setMeasureCallback((size) => size > 40 ? Math.round(size) + \" px\" : null);\n          this._shapeManipulator.setEnabled(false);\n        } else {\n          this._shapeManipulator.setEnabled(true);\n        }\n        break;\n      default:\n        break;\n    }\n    if (activeTool === SelectionToolsMode.Panning) {\n      this._panning.setEnabled(true);\n    }\n    this._activeTool = activeTool;\n    return this;\n  }\n  changeShape(shape) {\n    if (shape === \"circular\") {\n      this._rubberBandSelection.setRubberBandShapeMode(RubberBandShapeMode.Circular);\n    } else if (shape === \"rectangular\") {\n      this._rubberBandSelection.setRubberBandShapeMode(RubberBandShapeMode.Rectangular);\n    }\n  }\n  getActiveTool() {\n    return this._activeTool;\n  }\n  getPlot() {\n    return this._plot;\n  }\n}\nfunction createScene(canvas, update) {\n  const app = new SceneEditor(canvas, update);\n  return {\n    \"plot\": app.getPlot(),\n    \"editor\": app\n  };\n}\nexport { createScene };\n\ncreateScene(document.querySelector('[ref=\"plot\"]'), this.updateUI.bind(this));\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#/Carnac/Tools/SceneEditing/editor?section=Editor&extract=true","width":"100%","height":"598px","style":{"border":"none"}},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"managing-commands","__idx":2},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/Carnac/Tools/SceneEditing/editor#ManagingCommands"},"children":["#"]}," Managing Commands"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The example below demonstrates how to manage the editing process via ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["geotoolkit/controls/tools/editors/commands/AbstractCommand.reject()"]}," method."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Each editing action (resize, translate, drag point, etc.) raises the appropriate event set that can be used to manage (reject) this action if necessary. The event flow for every editing action is the following (in order of appearance):"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["geotoolkit/control/tools/EditEvents.BeforeCommandApplied"]}," - Before any command was applied (duplicates any other command event). The applied command can be rejected at this point."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["geotoolkit/control/tools/EditEvents.CommandApplying"]}," - After any command was applied (duplicates any other command event) but before ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["geotoolkit/control/tools/EditEvents.CommandApplied"]}," event was raised. The applied command still can be rejected at this point."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["geotoolkit/control/tools/EditEvents.CommandApplied"]}," - After any command was applied and pushed to the commands history (duplicates any other command event). The applied command can't be rejected at this point."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Let's add two rectangle shapes and implement the following common behavior for them:"]},{"$$mdtype":"Tag","name":"ol","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["rectangles cannot intersect each other."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["rectangles cannot be resized horizontally."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Note"]}," that for the option ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["1"]}," we use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["geotoolkit/control/tools/EditEvents.CommandApplying"]}," event as it is raised after the command was applied; for the option ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["2"]}," we use the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["geotoolkit/control/tools/EditEvents.BeforeCommandApplied"]}," event as it is raised before the command was applied."]},{"$$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 { Helpers } from \"/src/code/Carnac/Tools/SceneEditing/ts/Helpers.ts\";\nimport { Rect } from \"@int/geotoolkit/util/Rect.ts\";\nimport { Rectangle } from \"@int/geotoolkit/scene/shapes/Rectangle.ts\";\nimport { KnownColors } from \"@int/geotoolkit/util/ColorUtil.ts\";\nimport { DATA_LAYER_ID } from \"/src/code/Carnac/Tools/SceneEditing/ts/model.ts\";\nimport { EditEvents } from \"@int/geotoolkit/controls/tools/EditEvents.ts\";\nimport { Resize } from \"@int/geotoolkit/controls/tools/editors/commands/Resize.ts\";\nimport { Shape } from \"@int/geotoolkit/scene/shapes/Shape.ts\";\nconst hasBounds = (node) => node instanceof Shape && typeof node.getBounds === \"function\";\nfunction createScene(canvas) {\n  const widget = Helpers.createAnnotatedWidget(\n    new Rect(0, 0, 400, 400),\n    [\n      new Rectangle({\n        \"left\": 150,\n        \"top\": 60,\n        \"width\": 100,\n        \"height\": 100,\n        \"fillstyle\": KnownColors.Blue\n      }),\n      new Rectangle({\n        \"left\": 150,\n        \"top\": 250,\n        \"width\": 100,\n        \"height\": 100,\n        \"fillstyle\": KnownColors.Green\n      })\n    ]\n  );\n  initShapeManipulator(widget);\n  return new Plot({\n    \"canvaselement\": canvas,\n    \"root\": widget\n  });\n}\nfunction initShapeManipulator(widget) {\n  const rejectHorizontalResize = (eventType, sender, args) => {\n    const command = args.getCommand();\n    if (command instanceof Resize) {\n      const isHorizontalResize = command.getResizeDirections().some((direction) => Math.abs(direction.vx) !== 0);\n      if (isHorizontalResize) {\n        command.reject();\n      }\n    }\n  };\n  const rejectShapesCollision = (eventType, sender, args) => {\n    const command = args.getCommand();\n    const appliedEventName = command.getEventName();\n    if (appliedEventName !== EditEvents.Translated && appliedEventName !== EditEvents.Resized) {\n      return;\n    }\n    const currShape = args.getNode();\n    if (!hasBounds(currShape) || currShape.getBounds() == null) {\n      return;\n    }\n    const sceneTr = currShape.getSceneTransform();\n    const currNodeDeviceBounds = sceneTr.transformRect(currShape.getBounds());\n    const checkCollision = (node) => {\n      if (node === currShape || !hasBounds(node) || node.getBounds() == null) {\n        return false;\n      }\n      const nodeDeviceBounds = node.getSceneTransform().transformRect(node.getBounds());\n      return currNodeDeviceBounds.intersects(nodeDeviceBounds);\n    };\n    const hasCollision = sender.getDataLayer().getChildren(checkCollision).hasNext();\n    if (hasCollision) {\n      command.reject();\n    }\n  };\n  const dataLayer = widget.getModel().getChildren((child) => child.getId() === DATA_LAYER_ID).next();\n  const manipulatorLayer = widget.getManipulatorLayer();\n  const shapeManipulator = Helpers.createShapeManipulator(dataLayer, manipulatorLayer);\n  shapeManipulator.on(EditEvents.BeforeCommandApplied, rejectHorizontalResize).on(EditEvents.CommandApplying, rejectShapesCollision);\n  widget.getTool().insert(0, shapeManipulator);\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#/Carnac/Tools/SceneEditing/editor?section=ManagingCommands&extract=true","width":"100%","height":"688.5px","style":{"border":"none"}},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"edit-handles-customization","__idx":3},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/Carnac/Tools/SceneEditing/editor#HandlesCustomization"},"children":["#"]}," Edit Handles Customization"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This section shows how to customize edit handles styles. The sample property object for edit handles customization is shown below:"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Geotoolkit"]}," provides 2 ways to set custom properties on the edit handles that are currently captured ('active') and the ones that are hovered over with the cursor ('hover'). The approach with the property object was shown above. Below the css style for the manipulator layer approach is shown:"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Note"]}," that these 2 approaches can be used both separately and simultaneously but the property object always overrides css style in case of styles collision."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"rubber-band-selection","__idx":4},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/Carnac/Tools/SceneEditing/editor#RubberSelection"},"children":["#"]}," Rubber Band Selection"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This section shows how to use the SelectionMode in Selection tool. It also sets the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["RubberBandMode.Inside"]}," so only the objects completely inside the selection rectangle will be selected."]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"polygon-selection","__idx":5},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/Carnac/Tools/SceneEditing/editor#PolygonSelection"},"children":["#"]}," Polygon Selection"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"shape-editor","__idx":6},"children":[{"$$mdtype":"Tag","name":"MarkdownLink","attributes":{"href":"#/Carnac/Tools/SceneEditing/editor#ShapeEditor"},"children":["#"]}," Shape Editor"]},{"$$mdtype":"Tag","name":"Tabs","attributes":{"size":"medium"},"children":[]}]},"headings":[{"value":"Scene Editing Tools","id":"scene-editing-tools","depth":1},{"value":"Scene Editor","id":"scene-editor","depth":3},{"value":"Managing Commands","id":"managing-commands","depth":3},{"value":"Edit Handles Customization","id":"edit-handles-customization","depth":3},{"value":"Rubber Band Selection","id":"rubber-band-selection","depth":3},{"value":"Polygon Selection","id":"polygon-selection","depth":3},{"value":"Shape Editor","id":"shape-editor","depth":3}],"frontmatter":{"title":"Scene Editing Tools","seo":{"title":"Scene Editing Tools"}},"lastModified":"2026-02-11T19:54:32.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/solutions/geotoolkit/tutorials/carnac/tools/editor","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}