> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/web/annotation/custom-selection-model.md).

# Custom selection model

Enhance user experience with a custom selection model using HTML Canvas APIs. Customize ControlHandle and SelectionModel classes to create unique selection handles and outlines. The Apryse Web SDK str

The annotation selection handles and outlines are drawn with HTML Canvas APIs and by customizing the `ControlHandle` and `SelectionModel` classes, and utilizing Canvas APIs, it is possible to create a custom selection model.

## Creating the custom selection handles

The selection handles are rendered in the [ControlHandle](https://sdk.apryse.com/api/web/Core.Annotations.ControlHandle.html) class, and by overriding some of the static properties and the [`draw`](https://sdk.apryse.com/api/web/Core.Annotations.ControlHandle.html#draw__anchor) method, you can create custom handles. The static properties can be used to change the width, height, and color of the handle. The [`draw`](https://sdk.apryse.com/api/web/Core.Annotations.ControlHandle.html#draw__anchor) function will give total control draw the selection handles as you like.

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(
  // ...
).then(function(instance) {
  const { Annotations } = instance.Core;
  const { SelectionModel, Color, ControlHandle } = Annotations;

  ControlHandle.outlineColor = new Color(255, 99, 71);
  ControlHandle.color = new Color(255, 99, 71);
  // Defines the width of all control handles. Default is 10.
  ControlHandle.handleWidth = 15;
  // Defines the height of all control handles. Default is 10.
  ControlHandle.handleHeight = 15;

  ControlHandle.prototype.draw = function(ctx, annotation, selectionBox, zoom) {
    if (typeof zoom === 'undefined') {
      zoom = 1;
    }

    ctx.strokeStyle = ControlHandle.outlineColor.toString();
    ctx.fillStyle = ControlHandle.color.toString();
    ctx.shadowColor = ControlHandle.shadowColor.toString();
    ctx.shadowBlur = ControlHandle.shadowBlur;
    ctx.shadowOffsetY  = ControlHandle.shadowOffsetY;
    ctx.lineWidth = ControlHandle.selectionPointOutlineThickness / zoom;

    const dim = this.getDimensions(annotation, selectionBox, zoom);
    const x = dim.x1;
    const y = dim.y1;
    const width = dim.getWidth();
    const height = dim.getHeight();

    ctx.beginPath();
    ctx.rect(x + 10 / 2, y + 10 / 2, 10, 10);
    ctx.stroke();
    ctx.fill();
  };
});
```

{% endcode %}

[Annotations](https://sdk.apryse.com/api/web/Core.Annotations.html) [ControlHandle](https://sdk.apryse.com/api/web/Core.Annotations.ControlHandle.html) [Color](https://sdk.apryse.com/api/web/Core.Annotations.Color.html)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(
  // ...
).then(function(instance) {
  const { Annotations } = instance;
  const { SelectionModel, Color, ControlHandle } = Annotations;

  ControlHandle.outlineColor = new Color(255, 99, 71);
  ControlHandle.color = new Color(255, 99, 71);
  // Defines the width of all control handles. Default is 10.
  ControlHandle.handleWidth = 15;
  // Defines the height of all control handles. Default is 10.
  ControlHandle.handleHeight = 15;

  ControlHandle.prototype.draw = function(ctx, annotation, selectionBox, zoom) {
    if (typeof zoom === 'undefined') {
      zoom = 1;
    }

    ctx.strokeStyle = ControlHandle.outlineColor.toString();
    ctx.fillStyle = ControlHandle.color.toString();
    ctx.shadowColor = ControlHandle.shadowColor.toString();
    ctx.shadowBlur = ControlHandle.shadowBlur;
    ctx.shadowOffsetY  = ControlHandle.shadowOffsetY;
    ctx.lineWidth = ControlHandle.selectionPointOutlineThickness / zoom;

    const dim = this.getDimensions(annotation, selectionBox, zoom);
    const x = dim.x1;
    const y = dim.y1;
    const width = dim.getWidth();
    const height = dim.getHeight();

    ctx.beginPath();
    ctx.rect(x + 10 / 2, y + 10 / 2, 10, 10);
    ctx.stroke();
    ctx.fill();
  };
});
```

{% endcode %}

[Annotations](https://sdk.apryse.com/api/web/Core.Annotations.html) [ControlHandle](https://sdk.apryse.com/api/web/Core.Annotations.ControlHandle.html) [Color](https://sdk.apryse.com/api/web/Core.Annotations.Color.html)
{% endtab %}
{% endtabs %}

![](https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2Fgit-blob-787e5d5d573882d778597b143f4aa245aeb72957%2F0b4991cac8be8c256211aa6305b9d502bf8bf0a2-752x690.png?alt=media)

![](https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2Fgit-blob-ef2788bf4accc819f94de0472be787acd3133244%2F4e65e0065f012f420a1bf9b98166c82b86c9acad-752x690.png?alt=media)

*Figure 1. On the left side is the default selection handles and on the right side are custom selection hendles.*

## Creating the custom selection outlines

The selection outlines can be customized with the [SelectionModel](https://sdk.apryse.com/api/web/Core.Annotations.SelectionModel.html) class. For changing width, height, and color, use static properties as shown in the code sample. The [`drawSelectionOutline`](https://sdk.apryse.com/api/web/Core.Annotations.SelectionModel.html#drawSelectionOutline__anchor) can be overridden to access the canvas context and draw the outlines differently.

{% tabs %}
{% tab title="JavaScript (SDK v8.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(
  // ...
).then(function(instance) {
  const { Annotations } = instance.Core;
  const { SelectionModel, Color } = Annotations;

  SelectionModel.selectionOutlineThickness = 5;
  // Defines a padding for selection accuracy. Default is 2.
  // Increase this value to make selection more forgiving.
  SelectionModel.selectionOutlineThickness = 5;
  // Defines the default color for the annotation selection outline.
  SelectionModel.defaultSelectionOutlineColor = new Color(23, 23, 23);
  // Defines the default color for the annotation selection outline when the user is not permitted to make modifications.
  SelectionModel.defaultNoPermissionSelectionOutlineColor = new Color(23, 23, 23);
  // Defines the dash size for the selection outline. Default is 4;
  SelectionModel.selectionOutlineDashSize = 8;

  SelectionModel.prototype.drawSelectionOutline = function(ctx, annotation, zoom, pageMatrix) {
    if (typeof zoom !== 'undefined') {
      ctx.lineWidth = SelectionModel.selectionOutlineThickness / zoom;
    } else {
      ctx.lineWidth = SelectionModel.selectionOutlineThickness;
    }

    // changes the selection outline color if the user doesn't have permission to modify this annotation
    if (this.canModify()) {
      ctx.strokeStyle = SelectionModel.defaultSelectionOutlineColor.toString();
    } else {
      ctx.strokeStyle = SelectionModel.defaultNoPermissionSelectionOutlineColor.toString();
    }

    // modify this part
    ctx.beginPath();
    ctx.moveTo(annotation.X, annotation.Y);
    ctx.lineTo(annotation.X + annotation.Width, annotation.Y + annotation.Height);
    ctx.closePath();
    ctx.stroke();

    const dashUnit = SelectionModel.selectionOutlineDashSize / zoom;
    const sequence = [dashUnit, dashUnit];
    ctx.setLineDash(sequence);
    ctx.strokeStyle = 'rgb(255, 255, 255)';
    ctx.stroke();
  };

});
```

{% endcode %}

[Annotations](https://sdk.apryse.com/api/web/Core.Annotations.html) [SelectionModel](https://sdk.apryse.com/api/web/Core.Annotations.SelectionModel.html) [Color](https://sdk.apryse.com/api/web/Core.Annotations.Color.html)
{% endtab %}

{% tab title="JavaScript (SDK v6.0+)" %}
{% code lineNumbers="true" %}

```js
WebViewer(
  // ...
).then(function(instance) {
  const { Annotations } = instance;
  const { SelectionModel, Color } = instance.Annotations;

  SelectionModel.selectionOutlineThickness = 5;
  // Defines a padding for selection accuracy. Default is 2.
  // Increase this value to make selection more forgiving.
  SelectionModel.selectionOutlineThickness = 5;
  // Defines the default color for the annotation selection outline.
  SelectionModel.defaultSelectionOutlineColor = new Color(23, 23, 23);
  // Defines the default color for the annotation selection outline when the user is not permitted to make modifications.
  SelectionModel.defaultNoPermissionSelectionOutlineColor = new Color(23, 23, 23);
  // Defines the dash size for the selection outline. Default is 4;
  SelectionModel.selectionOutlineDashSize = 8;

  SelectionModel.prototype.drawSelectionOutline = function(ctx, annotation, zoom, pageMatrix) {
    if (typeof zoom !== 'undefined') {
      ctx.lineWidth = SelectionModel.selectionOutlineThickness / zoom;
    } else {
      ctx.lineWidth = SelectionModel.selectionOutlineThickness;
    }

    // changes the selection outline color if the user doesn't have permission to modify this annotation
    if (this.canModify()) {
      ctx.strokeStyle = SelectionModel.defaultSelectionOutlineColor.toString();
    } else {
      ctx.strokeStyle = SelectionModel.defaultNoPermissionSelectionOutlineColor.toString();
    }

    // modify this part
    ctx.beginPath();
    ctx.moveTo(annotation.X, annotation.Y);
    ctx.lineTo(annotation.X + annotation.Width, annotation.Y + annotation.Height);
    ctx.closePath();
    ctx.stroke();

    const dashUnit = SelectionModel.selectionOutlineDashSize / zoom;
    const sequence = [dashUnit, dashUnit];
    ctx.setLineDash(sequence);
    ctx.strokeStyle = 'rgb(255, 255, 255)';
    ctx.stroke();
  };
});
```

{% endcode %}

[Annotations](https://sdk.apryse.com/api/web/Core.Annotations.html) [SelectionModel](https://sdk.apryse.com/api/web/Core.Annotations.SelectionModel.html) [Color](https://sdk.apryse.com/api/web/Core.Annotations.Color.html)
{% endtab %}
{% endtabs %}

![](https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2Fgit-blob-787e5d5d573882d778597b143f4aa245aeb72957%2F0b4991cac8be8c256211aa6305b9d502bf8bf0a2-752x690.png?alt=media)

![](https://3532544125-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FX9YnTSKIHvV7m0A36LbO%2Fuploads%2Fgit-blob-397e690e6f1747659da699d11b288e0bfe084a4e%2F98825b437f9d99c0d4b0fc0d2335ef5a0ed1209d-752x690.png?alt=media)

*Figure 2. On the left side is the default selection outlines and on the right side are custom selection outlines.*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/web/annotation/custom-selection-model.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
