
日本式のトンボ(ダブルトンボ)を書くスクリプトを、ChatGPTさんに作成してもらいました。
一応作成してみたものの、自分、プログラムのことなんも分からないのでちゃんと使えるか不明です(´・ω・`)
(一応、自分で使ってて問題は起きてないけど)
コードを置いておくので、どなたか、プログラミング詳しい人!!
いい感じに改良して、なにとぞAffinityHubに登録お願いします……!!
AffinityHubに投稿されたら、このページはそのスクリプトを紹介するページに書き換えたいと思います(=・ω・=)
とりあえず、それまでの使い方とスクリプトをご紹介。
1.Affinityを開き、メニューの「編集」-「設定」をクリック
2.「スクリプト」から「Affinityスクリプティングを有効化」にチェックを入れる
左側から「スクリプト」を選び、「Affinityスクリプティングを有効化」にチェックを入れます。ファイルシステムとネットワークへのアクセスをどうするか確認する項目があるので、お好みでチェックを入れて下さい。
僕は両方ともチェックを入れてます。
3.Affinityを閉じて再起動する
設定を有効にするため、Affinityを閉じて開き直します。4.メニューから「ウィンドウ」-「スクリプト」-「スクリプトエディター」をクリック
スクリプトエディターを開きます
5.以下のコードをスクリプトエディターに貼り付ける
以下のコードをコピーして、スクリプトエディターの 1 と書かれている場所に貼り付けて下さい。1 というのが表示されてなかったら、左上にある「新規スクリプト」をクリックすると、張り付ける部分が出てきます。

'use strict';
// 日本式トンボ作成
// 選択オブジェクトの外接矩形を基準に生成
const { BlendMode } = require('affinity:common');
const { Colour } = require('/colours.js');
const {
AddChildNodesCommandBuilder,
CompoundCommandBuilder,
DocumentCommand
} = require('/commands.js');
const { Document } = require('/document.js');
const { FillDescriptor } = require('/fills.js');
const { Curve, PolyCurve } = require('/geometry.js');
const { LineStyleDescriptor } = require('/linestyle.js');
const {
ContainerNodeDefinition,
PolyCurveNodeDefinition
} = require('/nodes.js');
// ===================================
// 設定
// ===================================
const GAP_MM = 3;
// 四隅
const CORNER_LONG_MM = 12;
// 上下センタートンボ
const CENTER_TB_OFFSET_MM = 6.35;
const CENTER_TB_OUTER_MM = 12.7;
const CENTER_TB_INNER_MM = 4.23;
// 左右センタートンボ
const CENTER_LR_AXIS_OFFSET_MM = 6.35;
const CENTER_LR_NEAR_MM = 4.23;
const CENTER_LR_FAR_MM = 12.7;
// センタートンボの長さ
const CENTER_LONG_MM = 25.4;
const WEIGHT_MM = 0.1;
// ===================================
// 単位変換
// ===================================
function mm(value, dpi) {
return value * dpi / 25.4;
}
// ===================================
// トンボ生成クラス
// ===================================
class MarkBuilder {
constructor(dpi) {
this.dpi = dpi;
this.noFill = FillDescriptor.createNone();
// レジストレーション用CMYK
this.lineFill = FillDescriptor.createSolid(
Colour.createCMYKA8({
c: 255,
m: 255,
y: 255,
k: 255,
alpha: 255
}),
BlendMode.Normal
);
this.lineStyle = LineStyleDescriptor.createDefault(
mm(WEIGHT_MM, dpi)
);
this.defs = [];
}
// 直線
line(x1, y1, x2, y2) {
const poly = PolyCurve.create();
poly.addCurve(
Curve.createLineXY(x1, y1, x2, y2)
);
this.addPath(poly);
}
// 3点を結ぶ折れ線
path3(x1, y1, x2, y2, x3, y3) {
const poly = PolyCurve.create();
poly.addCurve(
Curve.createLineXY(x1, y1, x2, y2)
);
poly.addCurve(
Curve.createLineXY(x2, y2, x3, y3)
);
this.addPath(poly);
}
// パス登録
addPath(poly) {
const def = PolyCurveNodeDefinition.create(
poly,
this.noFill,
this.lineFill,
this.lineStyle,
this.noFill
);
def.userDescription = "トンボ";
this.defs.push(def);
}
// =================================
// 四隅の二重トンボ
// =================================
corner(x, y, sx, sy) {
const gap = mm(GAP_MM, this.dpi);
const long = mm(CORNER_LONG_MM, this.dpi);
// 1本目:垂直12mm、水平12mm
this.path3(
x,
y + sy * long,
x,
y + sy * gap,
x + sx * long,
y + sy * gap
);
// 2本目:水平12mm、垂直12mm
this.path3(
x + sx * long,
y,
x + sx * gap,
y,
x + sx * gap,
y + sy * long
);
}
// =================================
// 上下センタートンボ
// =================================
centerTopBottom(x, y, sy) {
const offset = mm(CENTER_TB_OFFSET_MM, this.dpi);
const outer = mm(CENTER_TB_OUTER_MM, this.dpi);
const inner = mm(CENTER_TB_INNER_MM, this.dpi);
const half = mm(CENTER_LONG_MM / 2, this.dpi);
// 横線
this.line(
x - half,
y + sy * offset,
x + half,
y + sy * offset
);
// 縦線
this.line(
x,
y + sy * outer,
x,
y + sy * inner
);
}
// =================================
// 左右センタートンボ
// =================================
centerLeftRight(x, y, sx) {
const axisOffset =
mm(CENTER_LR_AXIS_OFFSET_MM, this.dpi);
const near =
mm(CENTER_LR_NEAR_MM, this.dpi);
const far =
mm(CENTER_LR_FAR_MM, this.dpi);
const half =
mm(CENTER_LONG_MM / 2, this.dpi);
// 縦線
this.line(
x + sx * axisOffset,
y - half,
x + sx * axisOffset,
y + half
);
// 横線
this.line(
x + sx * far,
y,
x + sx * near,
y
);
}
}
// ===================================
// トンボ配置
// ===================================
function createJapaneseMarks(mb, rect) {
const x1 = rect.x;
const y1 = rect.y;
const x2 = rect.x + rect.width;
const y2 = rect.y + rect.height;
// 四隅
mb.corner(x1, y1, -1, -1);
mb.corner(x2, y1, 1, -1);
mb.corner(x1, y2, -1, 1);
mb.corner(x2, y2, 1, 1);
// 中心座標
const cx = x1 + rect.width / 2;
const cy = y1 + rect.height / 2;
// 上下センタートンボ
mb.centerTopBottom(cx, y1, -1);
mb.centerTopBottom(cx, y2, 1);
// 左右センタートンボ
mb.centerLeftRight(x1, cy, -1);
mb.centerLeftRight(x2, cy, 1);
}
// ===================================
// メイン処理
// ===================================
function main() {
const doc = Document.current;
if (!doc) {
alert("ドキュメントを開いてください");
return;
}
const originalSelection = doc.selection;
const nodes = originalSelection.nodes.toArray();
if (nodes.length === 0) {
alert("オブジェクトを選択してください");
return;
}
// 線幅を含まない外接矩形
let rects;
try {
rects = nodes.map(node => {
if (typeof node.getExactSpreadBaseBox !== "function") {
throw new Error("基準矩形を取得できません");
}
return node.getExactSpreadBaseBox();
});
} catch (e) {
alert("サイズ取得エラー:\n" + e.message);
return;
}
// 複数選択の場合は全体を囲む
const rect = rects.reduce((a, b) => {
const x = Math.min(a.x, b.x);
const y = Math.min(a.y, b.y);
const right = Math.max(
a.x + a.width,
b.x + b.width
);
const bottom = Math.max(
a.y + a.height,
b.y + b.height
);
return {
x,
y,
width: right - x,
height: bottom - y
};
});
// トンボ生成
const mb = new MarkBuilder(doc.dpi);
// 元の矩形をそのまま基準にする
createJapaneseMarks(mb, rect);
// グループ作成
const groupBuilder = AddChildNodesCommandBuilder.create();
groupBuilder.addNode(
ContainerNodeDefinition.create("日本式トンボ")
);
// 線を追加
const marksBuilder = AddChildNodesCommandBuilder.create();
for (const def of mb.defs) {
marksBuilder.addNode(def);
}
// Undoをまとめる
const compound = CompoundCommandBuilder.create()
.addCommand(groupBuilder.createCommand(true))
.addCommand(marksBuilder.createCommand(false))
.addCommand(
DocumentCommand.createSetSelection(originalSelection)
);
doc.executeCommand(compound.createCommand());
}
main();
6.「悪意のあるスクリプトアドバイザー…」をクリックして、安全性を確かめる
右上にある「悪意のあるスクリプトアドバイザー…」をクリックすると、張り付けたコードが悪意のあるものか確認することができます。

100%防げるって訳でもないですが、一応押して確認しておくと安心です。
知らないスクリプトはむやみやたらに使わないよう気をつけましょう(´・ω・`)ボクガ イウナッテ カンジダケド…
7.「名前をつけて保存」を押して、保存する
右下の「名前をつけて保存」を押し、好きな名前をつけて、好きなところに登録します。カテゴリは、特にこだわりがなかったら「デフォルト」のままでOKです。
使い方
1.仕上がりサイズの長方形を書く
長方形ツールで、仕上がりサイズの長方形を書きます。Ctrl+クリックすると、ダイヤログでサイズを指定できます。
2.メニューから「ウィンドウ」-「スクリプト」-「スクリプトライブラリ」をクリック
スクリプトライブラリを表示します。ここに、先ほど保存したスクリプトが保存されています。

自分は「デフォルト」ではなく、「3046」カテゴリに登録しました。
右上の「V」から、新規カテゴリを作れます。
ドラッグ&ドロップでカテゴリの移動もできます。
3.長方形を選択した状態で、スクリプトをクリックする
仕上がりサイズの長方形を選択した状態で、スクリプトをクリックすると、日本式トンボを作成します。一応、境界線の幅が設定されていても、無視して長方形の大きさで書くスクリプトにしてあります。
(Illustratorだと線幅が反映されるので、トンボがズレる事故が多発中)


たたき台は……!!たたき台は作成したので、どなたかプログラミング強い方!!AffinityHubへの登録、よろしくお願いします……!!
ボクへの連絡不要ですので!!
たたき台作ったのはさまシロです、とか、そういうの全然いらないので!!(そもそも作ったのはChatGPTでボクではない)
ずっと待ってるけど、誰も日本式トンボ作ってくれないんだ……!!
たたき台は作ったので、誰か頼む~~!!
もしくは、これで大丈夫だというお墨付きをください!
改良の必要がないなら、自分で申請頑張ってみる!!(=・ω・=)
自分で頑張ってコード読んだ限り、問題はないと思うんだけど、なにぶん素人なので……
プログラミングのお作法というか、ルーーーーールが分からん💀
どなたか、お力を貸していただけると嬉しいです<(_ _)>
