- 1. 概要
- 2. 描画
- 3. 保存
- 4. 参考サイト
1. 概要
さて、前ページまで書いたものを操作する際、解像度の違うモニタ上で操作したり、「Windows」以外のクライアント、例えば、「iPad」で表示すると、背景画像と描画している図形の相対位置が、ずれたりします。
「node server.js」上で展開して、「.pdf」化する際(「JavaScript - express + bodyParser + puppeteer」参照)も同様に位置ずれを起こします。
本ページでは、そういう位置ずれを起こさないようにするには、どうしたらいいか、ということについて記述します。
ただし、うまく説明できていない恐れがありますので、ご注意ください。
2. 描画
ここも説明するのが、難しい。
スケーリングとオフセットを定義する変数を用意します。
let bgScale = 1;
let bgOffsetX = 0;
let bgOffsetY = 0;
背景画像を描画する際に、スケーリングとオフセットの変数に値を設定します。
(説明のため、便宜的に行番号をいれています)
const imageObj = new Image();
imageObj.src = "/path/背景画像.png";
imageObj.onload = () => {
const stage = this.stage;
const layer = this.layer;
// 論理サイズ(そのまま)
const stageWidth = stage.width();
const stageHeight = stage.height();
// 背景画像スケーリング
const imgWidth = imageObj.width;
const imgHeight = imageObj.height;
const scaleX = stageWidth / imgWidth;
const scaleY = stageHeight / imgHeight;
const scale = Math.min(scaleX, scaleY);
const background = new Konva.Image({
image: imageObj,
// 中央に配置
width: imgWidth * scale,
height: imgHeight * scale,
x: (stageWidth - imgWidth * scale) / 2,
y: (stageHeight - imgHeight * scale) / 2,
listening: false,
});
this.layer.add(background);
background.setZIndex(0);
this.layer.batchDraw();
// **ピクセル比は 1 に固定**
layer.getCanvas().setPixelRatio(1);
// ここで スケーリングとオフセットをとっている
// これを保存時に かけて 取得時に 逆変換しないと
// Windows と iOS で座標位置が 異なってしまう
bgScale = Math.min(stageWidth / imgWidth, stageHeight / imgHeight);
bgOffsetX = (stageWidth - imgWidth * bgScale) / 2;
bgOffsetY = (stageHeight - imgHeight * bgScale) / 2;
resolve();
};
7~27行で、描画領域(stage)に合わせて、背景画像をスケーリングしています。
描画領域の縦横比と背景画像の縦横比を比較して、小さいほうの拡大/縮小率で、背景画像が描画領域にすっぽり収まるようにスケーリングしています。
36~41行で、描画領域と背景画像のスケールに合わせて、座標の縦横オフセットに設定する値を取得しています。
実際に描画する際は。
円であれば。
// 逆スケーリングして 展開
const group1 = new Konva.Group({
x: bgOffsetX + item.circleX * bgScale,
y: bgOffsetY + item.circleY * bgScale,
draggable: this.is_ssdeploy_edit
});
const circle = new Konva.Circle({
radius: 10,
fill: '#D60000',
});
てな感じで、中心座標について、オフセットをプラスして座標値をスケーリングします。
矩形であれば。
const group2 = new Konva.Group({
x: bgOffsetX + item.rectX * bgScale,
y: bgOffsetY + item.rectY * bgScale,
listening: this.is_ssdeploy_edit,
});
const rect = new Konva.Rect({
width: 100, height: 50,
fill: '#cceeff', stroke: '#333',
cornerRadius: 10,
});
てな感じで、左上座標について、オフセットをプラスして座標値をスケーリングします。
3. 保存
上記で描画したものを保存する際。
const layout = this.groups.map(group => {
const circle = group.findOne(node => node.className === 'Circle');
const rect = group.findOne(node => node.className === 'Rect');
const circlePos = circle.getAbsolutePosition();
const rectPos = rect.getAbsolutePosition();
// スケーリングして保存
return {
id: text.text(),
circleX: (circlePos.x - bgOffsetX) / bgScale,
circleY: (circlePos.y - bgOffsetY) / bgScale,
rectX: (rectPos.x - bgOffsetX) / bgScale,
rectY: (rectPos.y - bgOffsetY) / bgScale,
};
});
try {
const response = await axios.post('/regist_deploy', {
pouring_id: this.pouring_id,
item_json: JSON.stringify(layout)
});
window.location.href = '/home';
} catch(err) {
this.errorSnackbar = true;
this.errorMessage = `登録に失敗しました。`;
}
と、描画の際と逆に変換して、いわゆる絶対座標的な値にして保存します。
こうすることで、この保存した座標値を描画の際にまたスケーリング・オフセット変換することで、別のプラットフォームで保存した内容をほぼ再現することができるようになります。
4. 参考サイト
本ページは、「ChatGPT」くんを参考にさせていただきました。
|