JointJS解説　～基本図形編～

この記事は [JointJS Advent Calendar 2023](https://qiita.com/advent-calendar/2023/jointjs) の 4日目の記事です。

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

## はじめに

ここまでの記事でGraph, Paperに付いて見てきました。GraphとPaperはJointJSにおいて重要な要素ですが、それだけでは図を描くことはできません。今回は手っ取り早く図を描画するための基本図形を紹介します。

## 図形の使い方

図形は以下の流れで使用することができます。

1. GraphとPaperを準備する
1. 図形をインスタンス化する
1. インスタンス化した基本図形をGraphに追加する

```js
// GraphとPaperの準備
const graph = new joint.dia.Graph({}, {cellNamespace: joint.shapes});
const paper = new joint.dia.Paper({
  el: document.getElementById("paper-element");,
  model: graph
});

// 基本図形のインスタンス化
const rect = new joint.shapes.standard.Rectangle();

// 基本図形をGraphに追加
graph.addCell(rect);
```

## 基本図形でできること

基本図形ではインスタンス化の際にいくつかのオプションを指定することができます。指定できるのは位置・背景色・表示するラベルなどです。**カスタマイズ性には乏しい**ため、リッチな動作を期待する場合は拡張したカスタム要素を独自に定義する必要が出てきます。

## 属性値の指定方法

属性の指定方法は大きく分けて2通りあります。生成時に指定する方法と、生成後に指定する方法です。実際の指定方法は後述します。

また、各種図形にはSelectorと呼ばれる指定単位が用意されており、部品単位で属性をします。例えば`shapes.standard.Rectangle`の場合、`root`（全体）, `body`（四角形部分）, `label`（ラベル部分）の3つのSelectorが用意されており、指定単位ごとに別々の属性を設定できます。

### 生成時に指定

生成時に属性を指定する場合、引数のJSONで`attrs`>`Selector名`>`属性名`に値を設定します。

```js
const rect = new joint.shapes.standard.Rectangle({
  attrs: {
    body: {
      fill: 'lightblue',
      stroke: 'green'
    },
    label: {
      text: 'ラベル',
      stroke: 'white',
      fill: 'white'
    }
  }
});
```

### 生成後に指定

生成後に属性を指定する場合、生成したオブジェクトから`attr(path, value)`メソッドを呼び出して１つずつ値を設定します。第1引数の`path`には`Selector名/属性名`を、第2引数は設定値を指定します。

```js
const rect = new joint.shapes.standard.Rectangle();
rect.attr('body/fill', 'lightblue');
rect.attr('body/stroke', 'green');
rect.attr('label/text', 'ラベル');
rect.attr('label/stroke' 'white');
rect.attr('label/fill', 'white');
```

### `size`と`position`

描画する座標を指定するための`size`と`position`は特殊で、`attr`とは別に指定を行います。生成時、生成後それぞれに指定方法が用意されています。

```js
// 生成時に指定する場合…size, positionにそれぞれ指定する
const rect1 = new joint.shapes.standard.Rectangle({
  size: { width: 300, height: 100 },
  position { x: 20, y: 40 }
});

// 生成後に指定する場合…メソッドのresize(), position()を呼び出す
const rect1 = new joint.shapes.standard.Rectangle();
rect1.resize(200, 60);
rect1.position( x: 50, y: 300 ); 
```

## 代表的な基本図形

代表的な基本図形を紹介します。
なおJointJSのライブラリで用意されている基本図形は`joint.shapes.standard`配下に定義されています。全ては紹介しませんので、他の図形も知りたい方はドキュメントの[`shapes`](https://resources.jointjs.com/docs/jointjs/v3.7/joint.html#shapes)の項を御覧ください。

### `shapes.standard.Ellipse`

楕円を描画します。楕円の大きさは`size`に指定した大きさで自動で調整されます。

#### コード例

```js
const ellipse = new joint.shapes.standard.Ellipse({
  size: { width: 120, height: 50 },
  position: { x: 40, y: 50 },
});
ellipse.attr('label/text', 'これは楕円');
ellipse.attr('body/fill', 'lightblue');
ellipse.addTo(graph);
```
#### 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129526/c7511d6d-8977-54df-b358-bb7568d982ae.png)

### `shapes.standard.Image`

画像を表示します。

#### コード例

```js
const image = new joint.shapes.standard.Image({
  size: { width: 200, height: 100},
  position: { x: 180, y: 20 },
});
image.attr('label/text', 'これは画像');
image.attr('image/xlinkHref', 'image.jpeg');
image.addTo(graph);
```

#### 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129526/13de5d44-043c-b8f9-0626-e5bc0c6a4663.png)

### `shapes.standard.Path`

SVGの`path`を描画します。`path`は`d`属性に指定するパス情報次第で任意のベクター情報を描画できる要素です。JointJSでは`attr`で`refD`にパス情報を指定すると、要素のサイズ情報から計算した値を`d`の値として設定します。

#### コード例

```js
const path = new joint.shapes.standard.Path({
  size: { width: 200, height: 100},
  position: { x: 400, y: 30 }
});
path.attr('label/text', 'Pathの図形');
path.attr('body/refD', 'M 0 5 10 0 C 20 0 20 20 10 20 L 0 15 Z');
path.addTo(graph);
```

#### 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129526/3e25063a-9618-36ba-e2af-6f86cbd541a3.png)

#### （参考）実際に描画に使用された`path`のパス情報

```xml
d="M 0 25 L 114.28571428571429 0 C 228.57142857142858 0 228.57142857142858 100 114.28571428571429 100 L 0 75 Z"
```

### `shapes.standard.Rectangle`

四角形を表示します。

#### コード例

```js
const rectangle = new joint.shapes.standard.Rectangle({
  size: { width: 100, height: 100 },
  position: { x: 700, y: 30 },
});
rectangle.attr('label/text', 'これは四角形');
rectangle.attr('body/fill', 'yellow');
rectangle.addTo(graph);
```

#### 実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129526/f35b4aa1-78ec-3767-5563-c99a3f3be572.png)

## まとめ

今回は基本図形の使用方法を紹介しました。基本図形はカスタム性が低いため、実際の開発で直接使用する機会は少ない場合もありますが、カスタム図形を定義した場合でも利用するときの手順はほとんど同じになります。基本図形の利用を通してJointJSでの図形描画に慣れていきましょう。