###############
Advanced Markup
###############

In addition to the default markup provided, you can create your own customized markup. You will need a class for your markup item that extends the :doc:`Markup.MarkupItem  </api_ref/viewing/classes/Communicator.Markup.MarkupItem>` class. Typically, you will also want an operator that can interact with the model and respond to mouse events to add your markup to the scene. Additionally, you may want your markup included with the default markup when :ref:`exportMarkup() <api_ref/viewing/classes/Communicator.MarkupManager:exportmarkup>` is called, which will require a custom markup item manager class to serialize and deserialize your markup items.


Custom markup item
==================

Creating a custom markup item class that extends the markup item base class allows you to customize its behavior and appearance. Typically, markup items will be registered with the markup manager, which will manage calling the functions on the markup item like draw, remove, hit, etc. 

#. :ref:`draw() <api_ref/viewing/classes/Communicator.Markup.MarkupItem:draw>` – The draw function is called when the markup item should be redrawn. When the camera changes, the scene is redrawn, and elements in the SVG layer are removed. If the markup is drawn with SVG, the markup renderer can be used to draw the markup. The markup renderer supports drawing predefined :doc:`shapes <api_ref/viewing/modules/Communicator.Markup.Shape>` (circle, rectangle, polyline, polygon, text box, etc.). If your markup involves non-SVG elements, you will need to manage those separately. For example, 3D geometry will not be removed when the camera changes, HTML elements may need to have position updated if the position depends on the markup location, etc.

#. :ref:`remove() <api_ref/viewing/classes/Communicator.Markup.MarkupItem:remove>` – Any cleanup that needs to be done when the markup item is removed should be done here. To remove a markup element, ``remove()`` should not be explicitly called. Instead, the markup should be unregistered with the markup manager using the :ref:`unregisterMarkup()  <api_ref/viewing/classes/Communicator.MarkupManager:unregistermarkup>` function. For SVG elements, there is no extra cleanup required (after the markup is unregistered with the markup manager, the SVG will no longer be rendered). If there are additional non-SVG elements that require removal, you will need to manage those separately. For example, removing 3D geometry or HTML elements. 

#. :ref:`hit() <api_ref/viewing/classes/Communicator.Markup.MarkupItem:hit>` – The hit function is called with a 2D screen space coordinate to determine if the markup element is at that coordinate. You will need to implement this function to be able to select your markup. It is up to you to determine what counts as a 'hit' for your markup item. Note: The markup renderer has useful functions for determining the size of text and text boxes (:ref:`measureTextBox()  <api_ref/viewing/interfaces/Communicator.Markup.MarkupRenderer:measuretextbox>` and :ref:`measureText()  <api_ref/viewing/interfaces/Communicator.Markup.MarkupRenderer:measuretext>`).

#. :ref:`toJson() <api_ref/viewing/classes/Communicator.Markup.MarkupItem:tojson>` – The ``toJson()`` function creates a JSON object with the markup data. Only data that is required to reconstruct the markup item needs to be included in the JSON object.


Custom markup item operator
===========================

Creating an operator for our markup item will allow us to place and interact with our markup in the scene. The operator will create the markup item and register it with the markup manager. If there is any interaction with the markup item after it has been created, the operator will handle that interaction as well.


Custom markup item manager
==========================

A markup item manager typically will store a list of markup items created. The markup item manager can be registered with the markup manager. This allows the markup manager to include the custom markup item with the default markup items exported when :ref:`exportMarkup()  <api_ref/viewing/classes/Communicator.MarkupManager:exportmarkup>` is called. A markup item manager needs to extend the :doc:`MarkupTypeManager  </api_ref/viewing/classes/Communicator.MarkupTypeManager>`. The two functions that are required to be implemented are :ref:`exportMarkup()  <api_ref/viewing/classes/Communicator.MarkupManager:exportmarkup>` and :ref:`loadData()  <api_ref/viewing/classes/Communicator.MarkupTypeManager:loaddata>`.

#. :ref:`exportMarkup() <api_ref/viewing/classes/Communicator.MarkupManager:exportmarkup>` – The ``exportMarkup()`` function creates an array of JSON objects. Each object corresponds to one markup item.
	
#. :ref:`loadData() <api_ref/viewing/classes/Communicator.MarkupTypeManager:loaddata>` – This function takes an array of JSON objects and uses them to reconstruct each markup item. It returns a promise with an array of Booleans indicating if each markup item was successfully constructed.


Example
=======

We will create a custom callout markup item. When the model is selected, a callout with the part name will display. The callout will be drawn with SVG, and consist of an arrow, a line along the selection normal, and a text box with the part name.

.. image:: images/advanced_markup_example.png

*Custom callout markup item*

Create a ``CustomMarkupItem`` class that derives from the :doc:`Communicator.Markup.MarkupItem  </api_ref/viewing/classes/Communicator.Markup.MarkupItem>` class. The markup item class will store data about our markup item. We will need to implement the :ref:`draw()  <api_ref/viewing/classes/Communicator.Markup.MarkupItem:draw>` function, which will render our markup in the scene, and the :ref:`hit()  <api_ref/viewing/classes/Communicator.Markup.MarkupItem:hit>` function which will allow our markup to be selected.

.. literalinclude:: /../../applications/client/docs/markup.ts
	   :start-after: //! [markup_create_custom_item]
	   :end-before: //! [markup_create_custom_item]

Our callout markup item will have a line with an arrow pointing to the part that was selected and a text box containing the name of the part. The line and arrow can be drawn with a :doc:`Markup.Shape.Polyline </api_ref/viewing/classes/Communicator.Markup.Shape.Polyline>`, and the textbox will use a :doc:`Markup.Shape.TextBox  </api_ref/viewing/classes/Communicator.Markup.Shape.TextBox>`. In the constructor, we will create the polyline and text box, and set the styles that will be used.

.. literalinclude:: /../../applications/client/docs/markup.ts
	   :start-after: //! [markup_create_callout]
	   :end-before: //! [markup_create_callout]

Add the ``draw`` function to the custom markup item class. The draw function is used to render SVG to the screen. It is called each time the markup needs to be rendered. We will use the markup manager's :doc:`Markup.MarkupRender  </api_ref/viewing/interfaces/Communicator.Markup.MarkupRenderer>` to draw the SVG. The selection position is a world space coordinate, and will need to be converted to screen space to render the polyline. The box position will be calculated in world space, and also converted to screen space. Then the selection position and box position are used to update the polyline points and box position. Finally, the renderer draws the SVG.

.. literalinclude:: /../../applications/client/docs/markup.ts
	   :start-after: //! [markup_draw_item]
	   :end-before: //! [markup_draw_item]
	   
The ``hit`` function allows the markup item to be selected. It takes a 2D screen space point and decides if the markup item has been 'hit'. In this case, we will use the bounding of the text box, and declare a hit if the point is inside.

.. literalinclude:: /../../applications/client/docs/markup.ts
	   :start-after: //! [markup_hit_item]
	   :end-before: //! [markup_hit_item]

The next step in adding the markup to the scene will be creating an operator. The operator will create the markup, and update the length of the callout as the mouse is moved. In order to calculate the new length of the callout, the operator needs to have access to the selection position and normal, and set the markup length property. Add the following getters and setters to the custom markup item.

.. literalinclude:: /../../applications/client/docs/markup.ts
	   :start-after: //! [markup_access_data]
	   :end-before: //! [markup_access_data]


Custom markup operator
======================

Create a ``CustomMarkupOperator`` class that derives from the :doc:`Communicator.Operator.Operator  </api_ref/viewing/interfaces/Communicator.Operator.Operator>` class.

.. literalinclude:: /../../applications/client/docs/markup.ts
	   :start-after: //! [markup_create_custom_operator]
	   :end-before: //! [markup_create_custom_operator]

The first function, :ref:`addMarkupItem() <api_ref/viewing/classes/Communicator.Markup.MarkupView:addmarkupitem>`, accepts a 2D screen position coordinate and performs a selection on the model at that coordinate. If the selection is successful, it creates a callout markup at that selection position in world space. When ``onMouseDown`` is called, it will use the event parameter to get the position, and call :ref:`addMarkupItem() <api_ref/viewing/classes/Communicator.Markup.MarkupView:addmarkupitem>` with it. We will also need to add to class variables to keep track of the ``state``, ``handled``, and ``activeMarkupItem`` variables. The ``handled`` variable is used to prevent other operators on the stack from interacting with the scene at the same time we are dragging to create our markup item. The ``activeMarkupItem`` variable is used to keep track of the most recently created markup item.

.. literalinclude:: /../../applications/client/docs/markup.ts
	   :start-after: //! [markup_operator_add_markup_item]
	   :end-before: //! [markup_operator_add_markup_item]

The next function, ``updateActiveMarkupItem``, takes a 2D screen position coordinate and updates the markup length. To do this, it creates a line along the view plane normal at the screen position, and finds the closest point on the line from the selection position along the selection normal using the utility function :ref:`lineLineIntersect  <api_ref/viewing/modules/Communicator.Util:linelineintersect>`. The markup length is then updated.

.. literalinclude:: /../../applications/client/docs/markup.ts
	   :start-after: //! [markup_operator_update_markup_item]
	   :end-before: //! [markup_operator_update_markup_item]

The ``onMouseDown()``, ``onMouseMove()``, and ``onMouseUp()`` functions allow an operator to interact with mouse events. We will use these functions to create our markup item on mouse down, and update it on mouse move. In ``onMouseDown``, we see if a markup item is under the cursor. If so, we will adjust the length of the selected markup item, otherwise, we will use the mouse position to add a markup item if the model selection is successful. If successful, the handled variable will be true, and ``activeMarkupItem`` will contain the created markup item. In ``onMouseMove``, we will use the mouse position to update the length of the markup item line segment. In ``onMouseUp``, we set the ``activeMarkupItem`` to ``null``, as we no longer want to update it afterwards.

.. literalinclude:: /../../applications/client/docs/markup.ts
	   :start-after: //! [markup_operator_mouse_events]
	   :end-before: //! [markup_operator_mouse_events]


HTML page
=========

Create an HTML page with an instance of the viewer. Make sure to include the *CustomMarkupExample.js* and *CustomMarkupOperator.js* files.

.. raw:: html

		<script type="text/javascript" src="CustomMarkupItem.js"></script> 
		<script type="text/javascript" src="CustomMarkupOperator.js"></script> 

Create an instance of our custom markup operator and push it onto the operator stack.

.. literalinclude:: /../../applications/client/docs/markup.ts
	   :start-after: //! [markup_activate_operator]
	   :end-before: //! [markup_activate_operator]


Markup callbacks
================

There are several callbacks that are triggered when markup is created, deleted, or manipulated.


Line markup
===========

Line markup items are 3D geometry that is drawn in the scene. It is exported by default with the markup manager :ref:`exportMarkup() <api_ref/viewing/classes/Communicator.MarkupManager:exportmarkup>` function. The following callbacks relate to line creation, deletion, and loading from exported markup data:

* :ref:`lineCreated <api_ref/viewing/interfaces/Communicator.CallbackMap:linecreated>`
* :ref:`lineDeleted <api_ref/viewing/interfaces/Communicator.CallbackMap:linedeleted>`
* :ref:`lineLoaded <api_ref/viewing/interfaces/Communicator.CallbackMap:lineloaded>`


Measurement
===========

Measurement markup items are drawn as 2D SVG and redrawn each time the camera changes to appear 3D. The following callbacks relate to measurement creation, deletion, visibility, and updating values:

* :ref:`measurementBegin <api_ref/viewing/interfaces/Communicator.CallbackMap:measurementbegin>`
* :ref:`measurementCreated <api_ref/viewing/interfaces/Communicator.CallbackMap:measurementcreated>`
* :ref:`measurementDeleted <api_ref/viewing/interfaces/Communicator.CallbackMap:measurementdeleted>`
* :ref:`measurementHidden <api_ref/viewing/interfaces/Communicator.CallbackMap:measurementhidden>`
* :ref:`measurementShown <api_ref/viewing/interfaces/Communicator.CallbackMap:measurementshown>`
* :ref:`measurementLoaded <api_ref/viewing/interfaces/Communicator.CallbackMap:measurementloaded>`
* :ref:`measurementValueSet <api_ref/viewing/interfaces/Communicator.CallbackMap:measurementvalueset>`


Redline
=======

Redline markup is a 2D markup drawn as SVG that is associated with a camera and markup view. If the camera changes, any redline shown will be hidden. The following callbacks relate to redline creation, deletion, and updating position / text:

* :ref:`redlineCreated <api_ref/viewing/interfaces/Communicator.CallbackMap:redlinecreated>`
* :ref:`redlineDeleted <api_ref/viewing/interfaces/Communicator.CallbackMap:redlinedeleted>`
* :ref:`redlineUpdated <api_ref/viewing/interfaces/Communicator.CallbackMap:redlineupdated>`
	
