0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

#177 FigmaPluginでの仮想ガイドのスナップ機能を考える

0
Posted at

はじめに

以前の記事では、Figmaのフレーム内に設定された個別ガイドは補正対象として取得できないことを確認しました。

また、2025年5月に追加されたレイアウトグリッドには自動スナップ機能があり、ガイド代わりに使われるケースも増えています。しかし、レイアウトグリッドを使用した場合も、表示はフレーム単位のみでページ全体には引けなかったり、任意の位置に1本だけ引く、指定座標に引くといった使い方が難しいという制約があります。

そこで今回は、Nodeオブジェクトを使用してページ全体に任意の位置で仮想ガイドを引き、スナップ機能を持たせることができるのか、条件を整理してみました。

LineNodeを使用した場合

今回はLineNodeを使用した場合を想定して検討してみました。
矩形ではなく線を選んだ理由は面積があると基準部分がわかりづらくなるのではないかと考えたからですが、ここで問題となったのが、LineNodeでは垂直線を直接作れないということです。

LineNodeの制約

createLine()でLineNodeを追加して位置を決めた後、resize()メソッドを使って線の幅と高さを設定しますが、以下のようにすると水平ガイドは描画できるのに垂直方向には描画されませんでした。
※ページサイズなどに合わせて作成すると移動時に見切れてしまうため、十分な長さで描画する必要がありますが、今回は仮に30000px程度としています。

type Direction = 'vertical' | 'horizontal';

// ------(中略)------ //

  // ガイド作成ボタンが押されたとき
  figma.ui.onmessage = (msg: { type: string, direction: Direction, offset: number }) => {
    if (msg.type === 'create-guide') {

      // ガイドを作成する
      guideDirection = msg.direction;
      guideOffset = msg.offset;
      guideLine = figma.createLine();
      guideLine.name = "GuideLine";

      // ガイド線の位置と見た目の設定
      const guideLength = 30000;
      guideLine.strokeWeight = 1;
      guideLine.strokes = [{ type: 'SOLID', color: { r: 1, g: 0, b: 0 } }];
      guideLine.x = guideDirection === 'vertical' ? guideOffset : -guideLength / 2;
      guideLine.y = guideDirection === 'horizontal' ? guideOffset : -guideLength / 2;
      guideLine.resize(
        guideDirection === 'vertical' ? 0 : guideLength,
        guideDirection === 'horizontal' ? 0 : guideLength
      );
      figma.currentPage.appendChild(guideLine);
      figma.notify(`仮想ガイドを追加しました`);
    }

以下は水平、垂直それぞれページ基準で1200pxの位置にガイドを作成してみた状態です。
垂直のガイドは、正確には存在はするのですが見えない状態です。



resize()の挙動はNodeごとに異なっており、LineNodeのresize()はheightが常に0になるという制約があります。LineNodeは水平線を描くためのNodeのようでした。

height

New height of the node. Must be >= 0.01, except for LineNode which must always be given a height of exactly 0.

ノードの新しい高さ。0.01以上である必要があります。ただし、 LineNodeの場合は常に高さ0を指定する必要があります。

(Figma Developers resizeのページより引用・Google翻訳)

この制約のため、 heightに0以外を設定しようとしても無視されるようです。





FigmaのUI上で線ツール(LineNode)で縦線を描いた場合は回転が約90°と表示されていたので、Pluginから作成した水平ガイドもUI上で90°回転させると垂直線のように表示ができました。そのため、垂直ガイドには回転させた水平線を使用してみることにします。

// ガイド線の位置と見た目の設定
const guideLength = 30000;
guideLine.strokeWeight = 1;
guideLine.strokes = [{ type: 'SOLID', color: { r: 1, g: 0, b: 0 } }];
guideLine.x = guideDirection === 'vertical' ? guideOffset : -guideLength / 2;
// 垂直ガイドのみ、線の中心が回転軸になるよう位置を調整
guideLine.y = guideDirection === 'horizontal' ? guideOffset : guideLength / 2;
// どちらも最初は水平線にする
guideLine.resize(guideLength, 0);
// 垂直ガイドのみ、回転を追加
guideLine.rotation = guideDirection === 'vertical' ? 90 : 0;
これで垂直ガイドも見えるようになりました。

スナップのための座標の変換

ページ全体に仮想ガイドを引きたい場合、LineNodeはPageNodeの子要素として追加され、ページ基準の座標(絶対座標)を持ちます。
一方、スナップ対象となるオブジェクトは多くの場合、FrameNodeの子要素として配置されており、フレーム基準の座標(相対座標)を持ちます。また、ページ全体に一度配置した仮想ガイドも、フレーム内に動かした場合絶対座標ではなくフレーム基準の相対座標を持つようになります。
この違いにより、仮想ガイドと任意のオブジェクトとの位置を比較するには、双方の座標を一度絶対座標に変換して比較する必要があると考えられます。

Figma Plugin APIでは、Nodeオブジェクトの absoluteTransformプロパティ を使うことで、ページ基準の変換行列を取得できます。

absoluteTransformプロパティの行列には、拡大縮小・回転・平行移動の値が含まれています。変形のない単純な移動であれば、座標の差分を取ることで相対位置を求めることができますが、LineNodeを垂直な仮想ガイドに使用する場合は回転を加えてしまうため、座標を元の基準に戻すには逆行列が必要です。また、変形したオブジェクトをスナップさせる場合も同様に逆行列を使わなければなりません。
Figma Plugin APIで提供されているのは絶対座標への変換行列のみのため、ガイドとの位置を比較したあと元のフレーム基準の座標上で調整するには逆行列を自分で計算する必要がありそうです。

おわりに

今回は、LineNodeを使用した場合における仮想ガイドにスナップ機能を持たせるために必要な条件について整理してみました。
LineNodeの制約や座標変換の仕組み、逆行列の必要性など、実装に向けて考慮すべき点がいくつか明らかになりました。
課題は残るものの、工夫次第でページ全体に引いた仮想ガイドにもスナップ機能を持たせられる可能性が見えてきたように思います。

最後までお読みいただき、ありがとうございました。

参考

参考書籍:
結城浩(2018)『数学ガールの秘密ノート/行列が描くもの』SBクリエイティブ

参考サイト:
https://help.figma.com/hc/en-us/articles/31289469907863-Use-the-grid-auto-layout-flow
https://help.figma.com/hc/ja/articles/360040450513-グリッド-列-行を使用したレイアウトグリッドの作成
https://qiita.com/degudegu2510/items/4c1c4578be3f456fe6c5
https://jp.mathworks.com/discovery/affine-transformation.html

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?