JavaScriptでキャンバスを扱う場合、Fabric.jsを使うと色々な操作がやりやすくなる。
キャンバス上で絵を描くだけなら、オブジェクトの座標について意識することはあまりないかもしれないが、プログラム上でオブジェクトの原点や幅、高さ等を設定することはあるかもしれない。
複数のオブジェクトを選択し、まとめて移動したり大きさを変えたりする場合、座標の取得や計算方法は1つのオブジェクトを操作する場合よりも複雑になる。
今回は四角形を描画する場合を例にして、オブジェクトの左端(x1)、上端(y1)、右端(x2)、下端(y2)を取得する方法をまとめる。
前提(Fabric.jsの特性)
Fabric.jsはオブジェクトの大きさを原点(originX、originY)と高さ(height)、幅(width)、半径(radius)等で表す。
水平方向の原点(originX)は左端(left)、中央(center)、右端(right)の3種類がある。
垂直方向の原点(originY)は上端(top)、中央(center)、下端(bottom)の3種類がある。
1つのオブジェクトを扱う
1つのオブジェクトを扱う場合、オブジェクトだけで全ての情報が取得でき、座標の計算も簡単にできる。
オブジェクトの作成
キャンバスに適当な四角形を描画し、オブジェクトが選択されたり、変更された際のイベントリスナーを登録する。
<!-- html -->
<canvas class="imageCanvas" id="imageCanvas"></canvas>
var canvas;
/**
* 画面ロード時にオブジェクト描画とイベントリスナー登録
*/
function load(){
canvas = new fabric.Canvas('imageCanvas'); //キャンバス取得
canvas.isDrawingMode = false; //フリー描画禁止
//オブジェクト描画
let rect = new fabric.Rect({
left: 10,
top: 10,
width: 50,
height: 30,
originX: 'left',
originY: 'top',
});
canvas.add(rect);
//オブジェクトが選択された場合のイベントリスナー登録
canvas.on('selection:created', function(e) { getObjPosition(e); });
canvas.on('selection:updated', function(e) { getObjPosition(e); });
//オブジェクトが変更された場合のイベントリスナー登録
canvas.on('object:modified', function(e) { getObjPosition(e); });
}
window.addEventListener('DOMContentLoaded', load, false);
オブジェクト情報の取得
オブジェクトの、座標に関連する情報を取得する。
/**
* オブジェクトの座標を取得する処理
*/
function getObjPosition(e) {
//選択されたオブジェクトの取得
let activeObjects = canvas.getActiveObjects();
//取得したオブジェクトが1個の場合のみ処理を行う
if ( (activeObjects) && (activeObjects.length == 1) ){
//左端のX座標
const x1 = activeObjects[0].left;
//上端のY座標
const y1 = activeObjects[0].top;
//右端のX座標
//オブジェクトの実際の幅はwidth × scaleXで計算する必要がある
const x2 = x1 + (activeObjects[0].width * activeObjects[0].scaleX);
//下端のY座標
//オブジェクトの実際の幅はwidth × scaleXで計算する必要がある
const y2 = y1 + (activeObjects[0].height * activeObjects[0].scaleY);
}
}
getActiveObjects()では選択状態のオブジェクトの配列が返ってくるため、オブジェクトが1個の場合は[0]を指定する必要がある。
四角形でoriginXをleft、originYをtopに設定している場合、左端と上端はそのままleftとtopで取得可能。
右端と下端は、scaleX、scaleYにそれぞれ拡大倍率を保持しているため、それを踏まえて計算する必要がある。
複数のオブジェクトを扱う
複数のオブジェクトを扱う場合、オブジェクト個別の情報とグループとしての情報の両方を考慮する必要がある。
オブジェクトの作成
適当に2個の四角形を作成する。
//オブジェクト描画
let rect1 = new fabric.Rect({
left: 10,
top: 10,
width: 50,
height: 30,
originX: 'left',
originY: 'top',
});
canvas.add(rect1);
let rect2 = new fabric.Rect({
left: 10,
top: 100,
width: 50,
height: 30,
originX: 'left',
originY: 'top',
});
canvas.add(rect2);
描画する四角形が2個になる以外は、1個のオブジェクトの場合と同じ。
オブジェクト情報の取得
複数のオブジェクトを選択したり、操作した場合に、座標を取得する。
/**
* オブジェクトの座標を取得する処理
*/
function getObjPosition(e) {
//選択されたオブジェクトの取得
let activeObjects = canvas.getActiveObjects();
//取得したオブジェクトが2個以上の場合のみ処理を行う
if ( (activeObjects) && (activeObjects.length > 1) ){
//グループ情報の取得
const groupLeft = activeObjects[0].group.left;
const groupTop = activeObjects[0].group.top;
const groupWidth = activeObjects[0].group.width;
const groupHeight = activeObjects[0].group.height;
const groupScaleX = activeObjects[0].group.scaleX;
const groupScaleY = activeObjects[0].group.scaleY;
//中心点を計算
const groupCenterX = groupLeft + (groupWidth * groupScaleX / 2);
const groupCenterY = groupTop + (groupHeight * groupScaleX / 2);
//各オブジェクトの座標取得
activeObjects.forEach(obj => {
//左端のX座標
const objLeft = groupCenterX + (obj.left * groupScaleX);
//上端のY座標
const objTop = groupCenterY + (obj.top * groupScaleY);
//右端のX座標
const objRight = objLeft + (obj.width * groupScaleX * obj.scaleX);
//下端のY座標
const objBottom = objTop + (obj.height * groupScaleY * obj.scaleY);
}
}
}
グループとして選択されたオブジェクトのleftやtopはグループの中心点からの相対距離になる。
そのため、まずはグループの中心点を計算する必要がある。
グループの情報は各オブジェクトで同じ情報を保持しているので、先頭オブジェクトのグループ情報から計算する。
各オブジェクトの左端、上端は中心点にleft、topを加算すれば計算できるが、グループのscaleX、scaleYをここでも掛ける必要がある。
右端、下端はさらに各オブジェクトのscaleX、scaleYも掛ける必要がある。
グループ選択した場合は少し計算が面倒だが、これで座標を取得することができる。