Konva.jsを使ってみる。

経緯

これまでクロームの拡張機能を作っていましたが、完成したので公開申請をして今審議中なので次に取り掛かろうかと思います。次に作ろうと思っているのは、ホワイトボードアプリです。趣味のチーム開発で知らない人と手を組んで開発をやっています。Slackとdiscordを使ってコミュニケーションを取っているのですが、言葉だけのコミュニケーションは何かと勘違いを産んでしまいます。ウェブアプリケーション開発の場面でページとページの関係やDBの構造などは、言葉で伝えるのは難しいし、誰かが書いた図をslackを見ながらやるとしても加筆修正をリアルタイムに行えないので効率が悪くなってしまいます。そこでホワイトボードのように自由に書き込めてリアルタイムに共有できるアプリを作りたいと思いました。もしかしたら既にそのようなアプリはあるかもしれませんが、私が簡単に調べた感じそのようなものは大抵有料か、こちらの要求を全て満たしていないものなので自分の実力をつけるためにも自作してみたいと思います。
まずは自由に書いたり消したりできるキャンバスを作ろうということで今回の本題のKonva.jsです。

Konva.jsとは?

Konva.jsはhtml5, javaScriptのフレームワークです。以下に私が公式を見た解釈を述べます。ざっくりとした情報を掴むのには今から書く内容で十分かと思いますが、英語は得意では無いですし私見も入るのでしっかりした情報はご自分で公式を確認された方がいいかと思います。

どのようなことができるかというと、HTML内の指定されたdivタグ内にcanvasを生成し、そのcanvas内で自由に線を引いたり、丸や四角などの図形を置いたりできます。設定を少し追加してあげるだけで図形をドラッグしたりもできます。私見ですが作り方次第ではpowerpointやkeynoteでスライドを作る感覚でcanvasをデザイン出来るUIができそうな感じです。

Konva.jsの仕組みは、まずKonva.stageという大元のオブジェクトを定義し、1つ以上のKonva.layerというレイヤーを配置します。layerにはシーン レンダラーとヒットグラフ レンダラーという 2 つのcanvasレンダラーがあります。シーンレンダラーが実際に図形などの見えるものを描画し、ヒットグラフレンダラーは見えない状態になっていて高性能なイベントを検出することに使用します。ちょっとわかりにくいですが、おそらくクリックやドラッグなどのイベントあるいはもっと高度なイベントを検出するためのレンダラーだと思います。layerに図形などのシェイプ、またはシェイプをグループにしたものを配置することで画面に図形を描画します。

Konva.jsを使ってみる

今回は試してみるだけなので以下のhtmlにCDNを使用してKonva.jsを読み込み実行していきます。canvasの大きさがわかるように背景色を付けようと思ったのですがKonvaの方で背景色の設定の仕方分からなかったので大元のdivタグに背景色を設定しています。

<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Konva Practice</title>
 <style>
   h1 {
     font-size: 32px;
   }
   #canvas-container {
     width: 400px;
     height: 400px;
     background-color: #f0f0f0;
     border: 1px solid #000;
   }
 </style>
</head>
<body>
 <h1>Konva canvas</h1>
 <div id="canvas-container"></div>
 <script src="https://unpkg.com/konva@6.0.0/konva.min.js"></script>
 <script src="script2.js"></script>
</body>
</html>

スクリーンショット 2020-06-11 16.23.54

まずは、stageとlayerを宣言します。layerは複数宣言出来るみたいですが、今回は一つだけにしておきます。宣言の仕方はKonva.jsが用意したクラスを変数に代入してインスタンス化します。各種パラメータの意味はコード内のコメントを見ていただくとわかるかと思います。

const stage = new Konva.Stage({
 container: 'canvas-container',   // 親要素のdivタグのidを指定
 width: 400, //キャンバスの横幅
 height: 400 //キャンバスの高さ
});
const layer = new Konva.Layer(); //図形などの要素は後で追加する

次に図形を宣言します。Konvaはいろいろな図形のクラスを用意しているので大抵の図形はそれをインスタンス化してあげれば作ることができます。今回はRectを使用して、四角形を配置します。配置する場所や大きさ、色のパラメータはここで宣言します。CSSのような書き方で書けるのでわかりやすいと思います。

const box = new Konva.Rect({
 x: 50, //配置場所
 y: 50, //配置場所
 width: 100, //横幅
 height: 100, //高さ
 fill: "#00D2FF", //塗り潰しの色
 stroke: "#000", //枠線の色
 strokeWidth: 1, //枠線の太さ
});

最後に
作った図形をlayerに追加
→layerをstageに追加
→layerを描画
の順で書いてあげると図形を描画できます。

layer.add(box);
stage.add(layer);
layer.draw();

スクリーンショット 2020-06-11 16.42.46

基本的にはこれだけですが、せっかくなのでこれをドラッグで自由に移動出来るようにして、その座標を上に表示する機能も追加してみたいと思います。まずは先ほどの四角形をドラッグ出来るようにするためにパラメータを以下のように書き換えましょう。今回は必要無いですが、nameとidのパラメータも紹介するために追記しています。これはHTMLでいうところのclassとidにあたり複数の図形があるとき特定の図形を指定するのに便利です。

const box = new Konva.Rect({
 x: 50, //配置場所
 y: 50, //配置場所
 width: 100, //横幅
 height: 100, //高さ
 fill: "#00D2FF", //塗り潰しの色
 stroke: "#000", //枠線の色
 strokeWidth: 1, //枠線の太さ
 draggable: true, //ドラッグ可能か
 name: "shape", //HTML要素でいうところのclass
 id: "box", //HTML要素でいうところのid
});

次に座標を表示するためのテキストエリアを作ります。やり方はさっきの図形と一緒です。必要なパラメータを書き、変数に代入してインスタンス化してあげてください。

const text = new Konva.Text({
 x: 10, //配置する座標
 y: 10, //配置する座標
 fontFamily: "sans-serif", //フォントの設定
 fontSize: 24, //フォントのサイズ
 text: "", //表示するテキスト
 fill: "black" //テキストの色
});

次に四角形がドラッグされた時のイベントを追記します。記述の仕方はjQueryのようにonイベントで第一引数にイベントの種類、第二引数に操作を記述します。ここではドラッグムーブとテキストの変更を書きます。ここで注意してほしいのは、図形の宣言で書いたパラメータはプロパティではなく関数(メソッド?)が格納されているので呼び出して取得する場合でもかっこを付けてください。
ドラッグして動かす度に座標が変わるのでlayer.draw()で毎回再描画する必要があります。

box.on("dragmove", function() {
 text.text("x: " + this.x() + "y: " + this.y());
 layer.draw();
});

最後は次のように書き換えてtextもlayerに追加してあげてください。

layer.add(box, text);
stage.add(layer);
layer.draw();

するとこんな感じのものが出来上がります。

スクリーンショット 2020-06-11 17.11.44

最後にコードの全体を載せます。これができればあとは公式のドキュメントをみながらいろいろ作れると思います。いろいろ試してみてください!

const stage = new Konva.Stage({
 container: 'canvas-container',   // 親要素のdivタグのidを指定
 width: 400, //キャンバスの横幅
 height: 400 //キャンバスの高さ
});

const layer = new Konva.Layer(); //図形などの要素は後で追加する
// 図形を宣言
const box = new Konva.Rect({
 x: 50, //配置場所
 y: 50, //配置場所
 width: 100, //横幅
 height: 100, //高さ
 fill: "#00D2FF", //塗り潰しの色
 stroke: "#000", //枠線の色
 strokeWidth: 1, //枠線の太さ
 draggable: true, //ドラッグ可能か
 name: "shape", //HTML要素でいうところのclass
 id: "box", //HTML要素でいうところのid
});

const text = new Konva.Text({
 x: 10, //配置する座標
 y: 10, //配置する座標
 fontFamily: "sans-serif", //フォントの設定
 fontSize: 24, //フォントのサイズ
 text: "", //表示するテキスト
 fill: "black" //テキストの色
});

box.on("dragmove", function() {
 text.text("x: " + this.x() + "y: " + this.y());
 layer.draw();
});

layer.add(box, text);
stage.add(layer);
layer.draw();

この記事が気に入ったらサポートをしてみませんか?