【JointJS】LinkToolsを使ってLinkを操作できるようにする

## LinkToolsとは

Linkに対して、ユーザーが操作可能なツールを表示できる機能です。例えばツールチップを表示するためのアイコンをLink上に表示することができます。

## 利用可能なLinkToolsの例

### `Remove`

対象のLinkを削除できるボタンを配置します。

![dadlink.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129526/63b0afe7-e163-eb09-0c52-be9ff89f0ec2.gif)

### `Segments`

Linkを縦・横方向に並行移動させるためのバーを表示します。

![Untitled.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129526/21115eeb-b278-0871-ca07-7b89623f07c2.gif)

### `SourceAnchor` / `TargetAnchor`

Linkの端点の基点を動かすことができるツマミを表示します。`source`と`target`が別々にあるため、両方必要な場合は2つとも有効にします。

![Untitled.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129526/ed80b389-5025-a523-f04a-e86ae344641d.gif)

### `Button`

カスタムのボタンを配置します。ボタンの描画情報は引数のJSONの`markup`で指定します。`markup`が指定されないと何も描画されません。JSONの`action`でクリック時の動作を指定できます。

#### コード例

```js
const button = new joint.linkTools.Button({
  markup: [
    {
      tagName: 'rect',
      selector: 'button',
      attributes: {
        width: 50,
        height: 20,
        fill: '#001DFF',
        cursor: 'pointer'
      },
    },
    {
      tagName: 'text',
      selector: 'inner-text',
      attributes: {
        fill: '#FFF',
        x: 14,
        y: 13,
        'font-size': 8,
        cursor: 'pointer'
      },
      children: [
        'ボタン'
      ]
    },
  ],
  distance: 60,
  offset: -10,
  
  // ボタンがクリックされたらLinkの色を変更する
  action: function(evt) {
    this.model.attr('line/stroke', 'red');
  }
});
```

#### 実行結果

![Untitled.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129526/5e0dfa75-1887-c106-4584-26bed84fe392.gif)

## LinkToolsの使い方

LinkToolsは以下の手順でLinkに追加します。

1. 使用するLinkToolsのインスタンスを生成する
1. `1`のLinkToolsをToolsViewにまとめる
1. LinkToolsを追加したいLinkのViewに対してToolsViewを追加する

`1`, `2`で複数のLinkToolsをまとめることで、1つのLinkに対して複数のLinkToolsを使用できます。

### コード例

```js
// 使用するLinkToolsを生成
const removeButton = new joint.linkTools.Remove();
const segments = new joint.linkTools.Segments();

// LinkToolsをToolsViewにまとめる
const toolsView = new joint.dia.ToolsView({
    tools: [
      removeButton,
      segments
    ]
});

// LinkのViewに対してToolsViewを追加する
const linkView = link.findView(paper);
linkView.addTools(toolsView);
```

## LinkToolsの位置調整

`RemoveButton`や`Button`等のボタン系のLinkToolsでは、`distance`, `offset`を使用することでボタンの位置を調整することができます。

### `distance`

Linkの起点（または終点）からどれくらい離れた位置にボタンを配置するかを設定します。実数値指定と百分率指定ができます。

- 実数値指定：Linkの起点から、指定された数値の座標分離れた位置にボタンを配置する。負数を指定することもでき、その場合はLinkの終点から指定されたの座標分となる。
- 百分率指定：Linkの起点を`0%`、終点を`100%`としたときに配置する位置の百分率を指定します。

### `offset`

`distance`で決定した位置からLinkの垂直方向にどれだけずらすかを指定します。ずらす座標の距離を実数値で指定します。

#### コード例

```js
const removeButton = new joint.linkTools.Remove({
  distance: '10%',
  offset: -10,  
});

const button = new joint.linkTools.Button({
  markup: [
    // 中略
  ],
  distance: -20,
  offset: -10,  
});
```

#### 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129526/181c21f9-ee39-db2a-0c9e-724a0a093704.png)

## まとめ

今回はLinkを操作できるようにするためのLinkToolsを紹介しました。
リッチなLinkの動作が必要になるときは、LinkToolsの使用を検討してみてください。

※この記事は [JointJS Advent Calendar 2023](https://qiita.com/advent-calendar/2023/jointjs) の記事です。他の記事を読む場合はカレンダーのページを参照してください。

https://qiita.com/advent-calendar/2023/jointjs