このエントリーは Adobe XD プラグイン制作 Advent Calendar 2日目の記事です。
「XDのグラデーションの角度(数値)ってどうやったら分かるの?」というコメントを見かけ,改めて確認しました。この設定は手作業のみだったのですね。90度や45度ならわかりやすいですが,それ以外は大雑把になりそうでした。
@OsatoCom さんによると,開発用に共有を使うと正確な数値を取得できるそうです。ところがこの方法はインターネット接続が必要で,実行には結構な時間がかかります。
せっかく Advent Calendar の季節ですし,XDプラグインを作ってみることにしました。
そこで今回は,線形グラデーションの角度をGet/SetするAdobe XD用プラグインGradientAngleを紹介します。
GradientAngleって何?
線形グラデーションの角度の数値を取得したり,設定したりするAdobe XD用プラグインです。線形グラデーションの塗りを持つアイテムを1つ選択すると,プラグインパネルのテキストフィールドに角度が表示されます。新しい角度を入力すれば,グラデーションはその通りに回転されます。
インストール方法
今回のXDのプラグインは現状では野良プラグインです。こちらのファイルをダウンロードし,ダブルクリックするなどして開いてください。自動的にXDが起動しインストールされます。
審査に通り,プラグインマネージャからインストールできるようになりました。GradientAngleのリンクに飛ぶとすぐに完了します。
仕様
- 開発用に共有で出てくる角度がピンとこないので,Illustratorと同じ形式(左から右まっすぐで0度,上から下で-90度)にしました
- 新しい角度をセットする際は,アイテムの中心を軸にしてグラデーション制御点を回転します
- グラデーション始点から終点までの長さを変更しないため,制御点は必ずしもアイテム枠上ぴったりになりません
これでまた少し仕事が速くなりました。今日もさっさと仕事を切り上げて好きなことをしましょう!
プラグインを紹介していただきました。
コードはこちら
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
/** * @file LinearGradientFillの角度をget/setする * @version 1.0.1 * @author sttk3.com * @copyright (c) 2019 sttk3.com */ let panel ; /** * 指定したアイテムの線形グラデーションの角度を取得する * @param {Scenenode} targetItem 対象のnode * @return {Number} 角度(ラジアン) */ function getGradientAngle(targetItem) { // 縦横比を取得する const ratio = getHVRatio(targetItem) ; /* 線形グラデーションからはgetEndPoints()で制御点の座標 [0: startX, 1: startY, 2: endX, 3: endY] が取れる。 これはアイテムの幅・高さをそれぞれ1とした比率で表しているため,正方形でないと角度が正しくならない。 比率から縦横比を考慮した座標に変換し,その角度を取得する */ const points = targetItem.fill.getEndPoints() ; const res = Math.atan2((points[3] - points[1]) * -1, (points[2] - points[0]) * ratio) ; return res ; } /** * 指定したアイテムの線形グラデーションの角度をセットする * @param {Scenenode} targetItem 対象のnode * @param {Number} dstAngle 傾き角度(ラジアン) * @return なし */ function setGradientAngle(targetItem, dstAngle) { const oldAngle = getGradientAngle(targetItem) ; const rotationAngle = oldAngle - radians(dstAngle) ; const ratio = getHVRatio(targetItem) ; // 比率から縦横比を考慮した座標に変換し,目標の角度まで回転した後に比率に戻す let targetColor = targetItem.fill ; const points = targetColor.getEndPoints() ; // [0: startX, 1: startY, 2: endX, 3: endY] const centerAnchor = [0.5 * ratio, 0.5] ; const newStartAnchor = rotateAnchor([centerAnchor[0], centerAnchor[1]], [points[0] * ratio, points[1]], rotationAngle) ; const newEndAnchor = rotateAnchor([centerAnchor[0], centerAnchor[1]], [points[2] * ratio, points[3]], rotationAngle) ; const ratio2 = 1 / ratio ; targetColor.setEndPoints(newStartAnchor[0] * ratio2, newStartAnchor[1], newEndAnchor[0] * ratio2, newEndAnchor[1]) ; // グラデーションを再セットする targetItem.fill = targetColor ; } /** * 指定したアイテムの 幅/高さ 比率を算出する * @param {Scenenode} targetItem 対象のnode * @return {Number} */ function getHVRatio(targetItem) { const bounds = targetItem.boundsInParent ; const res = bounds.width / bounds.height ; return res ; } /** * 座標を回転した時の新しい座標を取得する * @param {Array} origin 中心点座標 * @param {Array} p1 回転対象座標 * @param {Number} angle 回転角度(ラジアン) * @return {Array} [x, y] */ function rotateAnchor(origin, p1, angle) { var vx = p1[0] - origin[0] ; var vy = p1[1] - origin[1] ; var cosNum = Math.cos(angle) ; var sinNum = Math.sin(angle) ; var x = vx * cosNum - vy * sinNum ; var y = vx * sinNum + vy * cosNum ; return [origin[0] + x, origin[1] + y] ; } /** * ラジアンから角度に変換 * @param {Number} rad 角度(ラジアン) * @return {Number} 角度(度) */ function degrees(rad) { return rad * 180 / Math.PI ; } /** * 角度からラジアンに変換 * @param {Number} deg 角度(度) * @return {Number} 角度(ラジアン) */ function radians(deg) { return deg * Math.PI / 180 ; } /** * パネルを生成する * @return {Panel} */ function create() { const html = ` <style> .break { flex-wrap: wrap; } label.row > span { color: #8E8E8E; width: 16px; text-align: right; font-size: 9px; } label.row input { flex: 1 1 auto; } form { width:100%; margin: 0px; padding: 0px; } .show { display: block; } .hide { display: none; } </style> <form method="dialog" id="main"> <div class="row break"> <label class="row"> <span>angle</span> <input type="number" uxp-quiet="true" id="txtO" value="-90" placeholder="offset" /> </label> </div> </form> <p id="warning">This plugin requires you to select a object with linear gradients in the document.</p> `; /** * パネルのフォーム送信時実行するアクション */ function panelAction() { const dstAngle = Number(document.querySelector('#txtO').value) ; require('application').editDocument({editLabel: 'Set gradient angle'}, function() { const {selection} = require('scenegraph') ; const targetItem = selection.items[0] ; setGradientAngle(targetItem, dstAngle) ; }) ; } panel = document.createElement('div') ; panel.innerHTML = html ; panel.querySelector('form').addEventListener('submit', panelAction) ; return panel ; } /** * パネルを表示する */ function show(event) { if(!panel) event.node.appendChild(create()) ; } /** * パネルを隠す */ function hide(event) {} /** * 選択変更時パネルをアップデートする */ function update(selection) { const form = document.querySelector("form") ; const warning = document.querySelector("#warning") ; if(selection && selection.items[0] && selection.items[0].fill.constructor.name == 'LinearGradientFill') { let oldAngle = degrees(getGradientAngle(selection.items[0])).toFixed(3).replace(/\.0+$/, '') ; document.querySelector('#txtO').value = oldAngle ; form.className = 'show' ; warning.className = 'hide' ; } else { form.className = 'hide' ; warning.className = 'show' ; } } module.exports = { panels: { gradientAngle: { show, hide, update } } } ; |
このサイトで配布しているスクリプトやその他のファイルを,無断で転載・配布・販売することを禁じます。
それらの使用により生じたあらゆる損害について,私どもは責任を負いません。
スクリプトやファイルのダウンロードを行った時点で,上記の規定に同意したとみなします。
コメント