Konva は HTML5 Canvas を DOM のように操作できる高レベルなライブラリです。要素へのイベント処理、ドラッグ&ドロップ、グループ化、変形機能を内蔵しており、パズルゲームやインタラクティブなビジュアルエディタの実装に適しています。また、html2canvas がモバイル端末でレンダリング不安定になる問題を解決する代替手段としても有効です。
Stage、Layer、Shape の関係
Konva の基本構造は、Stage → Layer → Shape の階層で構成されます。
まず、レンダリング対象となる DOM 要素を指定して Stage を初期化します:
const stage = new Konva.Stage({
container: 'canvas-container',
width: 800,
height: 600
});
Stage にレイヤーを追加すると、内部で新たな <canvas> 要素が生成されます:
const mainLayer = new Konva.Layer();
stage.add(mainLayer);
レイヤー上に形状(Shape)を描画します。Konva は矩形、円、星、画像、テキストなど多様な Shape を提供します:
const rectangle = new Konva.Rect({
x: 50,
y: 30,
width: 150,
height: 80,
fill: '#3498db',
cornerRadius: 10,
stroke: '#2c3e50',
strokeWidth: 2
});
mainLayer.add(rectangle);
mainLayer.draw(); // 描画を反映
Shape の描画順序は追加順に従い、後から追加された要素が前面に表示されます。これは CSS の z-index と同様の動作です。
Group による要素のまとまり操作
Group は複数の Shape を論理的に束ねるためのコンテナです。Group を移動・回転させると、その子要素も一緒に変化します。Group 内の Shape の座標は、親 Group を基準とした相対位置で定義されます。
const controlGroup = new Konva.Group({
x: 200,
y: 150,
draggable: true,
rotation: 15
});
const colors = ['#e74c3c', '#f39c12', '#f1c40f'];
for (let i = 0; i < 3; i++) {
const block = new Konva.Rect({
x: i * 40,
y: i * 25,
width: 90,
height: 45,
name: colors[i],
fill: colors[i],
stroke: '#000',
strokeWidth: 3,
shadowColor: '#000',
shadowBlur: 5
});
controlGroup.add(block);
}
mainLayer.add(controlGroup);
mainLayer.draw();
Group はネスト可能で、複数階層の構造を構築できます:
const outerGroup = new Konva.Group({ x: 350, y: 220 });
const innerGroup = new Konva.Group({ x: 0, y: 30 });
const circle = new Konva.Circle({
x: 25,
y: 25,
radius: 35,
fill: '#27ae60',
stroke: '#2ecc71',
strokeWidth: 2
});
innerGroup.add(circle);
outerGroup.add(innerGroup);
mainLayer.add(outerGroup);
この構造では、outerGroup を動かすと、innerGroup とその子である円も一緒に移動します。
Transformer によるインタラクティブな変形
Konva.Transformer は、Shape や Group に選択・拡大・回転・スケーリングの UI を追加するための特殊なコンポーネントです。実験的機能とされていますが、プロトタイプ開発には非常に有効です。
使用方法は次の3ステップです:
- Transformer インスタンスを生成
- Layer に追加
- attachTo() で対象要素をバインド
const starShape = new Konva.Star({
x: stage.width() / 2,
y: stage.height() / 2,
numPoints: 8,
innerRadius: 25,
outerRadius: 60,
fill: '#f39c12',
stroke: '#d35400',
strokeWidth: 3,
draggable: true
});
const transformer = new Konva.Transformer();
mainLayer.add(transformer);
transformer.attachTo(starShape);
mainLayer.add(starShape);
mainLayer.draw();
Transformer を適用した Shape は、マウスで直接ドラッグして回転・サイズ変更が可能になります。
要素の検索とフィルタリング
Konva は jQuery に似たセレクタ機能を提供し、階層内の要素を効率的に取得できます。find() は複数の要素を返し、findOne() は最初に見つかった要素のみを返します。
// ID による検索(複数一致可能)
const rectById = stage.find('#target-rect');
// name 属性による検索
const coloredBlocks = stage.find('.yellow');
// クラス名による検索(Shape サブクラス)
const allStars = stage.find('Star');
// 全ての Shape を取得
const allShapes = stage.find('Shape');
// グループ内の子要素を検索
const innerElements = controlGroup.find('Rect');
注意点として、id は一意である必要はありません。複数要素に同じ ID を割り当ててもエラーにはならず、すべてが検索結果に含まれます。
参考: Konva 公式ドキュメント