Created
February 18, 2023 09:43
-
-
Save sttk3/6e3f8c23de3954beb74875cfc1af17d7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @file 指定した数の色でランダムに塗るIllustratorスクリプト。 | |
* 線と塗り両方に対応。テキスト,複合パス/グループの配下への適用可能。 | |
* 元ネタは→[【Illustratorスクリプト】指定した数の色でランダムに塗るスクリプト。 - ふわふわぷかぷか](https://fuwafuwapukapuka.hatenablog.com/entry/2023/02/16/032354) | |
* @version 1.0.0 | |
* @author sttk3.com | |
*/ | |
//@target 'illustrator' | |
(function() { | |
$.localize = true ; | |
if(app.documents.length <= 0) {return ;} | |
var doc = app.documents[0] ; | |
var sel = doc.selection ; | |
if(sel.length <= 0) {return ;} | |
try { | |
showDialog(sel) ; | |
} catch(e) { | |
alert(e) ; | |
} | |
})() ; | |
handleChanging = null ; | |
/** | |
* RGBColorを生成して返す | |
* @param {Integer} r Red | |
* @param {Integer} g Green | |
* @param {Integer} b Blue | |
* @return {RGBColor} | |
*/ | |
function makeRGBColor(r, g, b) { | |
var tmpColor = new RGBColor() ; | |
tmpColor.red = r ; | |
tmpColor.green = g ; | |
tmpColor.blue = b ; | |
return tmpColor ; | |
} | |
/** | |
* 0からmaxまでのランダムな整数を返す | |
* @param {Integer} max 最大値 | |
* @return {Integer} | |
*/ | |
function getRandomInt(max) { | |
return Math.floor(Math.random() * max) ; | |
} | |
/** | |
* ランダムなRGBカラーを生成して返す | |
* @return {RGBColor} | |
*/ | |
function getRandomColor() { | |
var max = 255 ; | |
return makeRGBColor(getRandomInt(max), getRandomInt(max), getRandomInt(max)) ; | |
} | |
/** | |
* 対象のアイテムに色を適用する。文字属性と,複合パス・グループの配下への適用に対応する | |
* @param {PageItem} targetItem 対象のPageItem | |
* @param {Color} dstColor 適用する色 | |
* @param {Boolean} applyToStroke strokeに色を適用するかどうか | |
* @param {Boolean} applyToFill fillに色を適用するかどうか | |
* @return {Boolean} 色の適用が1つでも行われたかどうか | |
*/ | |
function applyColor(targetItem, dstColor, applyToStroke, applyToFill) { | |
var res = false ; | |
var itemClass = targetItem.constructor.name ; | |
var targetProps = [] ; | |
if(applyToStroke) {targetProps.push('strokeColor') ;} | |
if(applyToFill) {targetProps.push('fillColor') ;} | |
try { | |
for(var i = 0, len = targetProps.length ; i < len ; i++) { | |
switch(itemClass) { | |
case 'TextFrame': | |
targetItem.textRange[targetProps[i]] = dstColor ; | |
res = true ; | |
break ; | |
case 'CompoundPathItem': | |
var children = targetItem.pathItems ; | |
for(var j = 0, childrenLength = children.length ; j < childrenLength ; j++) { | |
if(applyColor(children[j], dstColor, applyToStroke, applyToFill)) { | |
res = true ; | |
} | |
} | |
break ; | |
case 'GroupItem': | |
var children = targetItem.pageItems ; | |
for(var j = 0, childrenLength = children.length ; j < childrenLength ; j++) { | |
if(applyColor(children[j], dstColor, applyToStroke, applyToFill)) { | |
res = true ; | |
} | |
} | |
break ; | |
default: | |
if(targetProps[i] in targetItem) { | |
targetItem[targetProps[i]] = dstColor ; | |
res = true ; | |
} | |
break ; | |
} | |
} | |
} catch(e) { | |
// skip | |
} | |
return res ; | |
} | |
/** | |
* 色割り当てメイン動作。対象のアイテムにランダムな色を適用する | |
* @param {Array} targetItems 対象のアイテム(複数) | |
* @param {String} colorLengthText 適用する色の数 | |
* @param {Boolean} applyToStroke strokeに色を適用するかどうか | |
* @param {Boolean} applyToFill fillに色を適用するかどうか | |
* @return {Boolean} 色の適用が行われたかどうか | |
*/ | |
function setColorTo(targetItems, colorLengthText, applyToStroke, applyToFill) { | |
var res = false ; | |
if( !(applyToStroke || applyToFill) ) { | |
return res ; | |
} | |
var colorLengthInt | |
try { | |
colorLengthInt = parseInt(colorLengthText, 10) ; | |
// 色の作成 | |
var colorList = [] ; | |
for(var i = 0 ; i < colorLengthInt ; i++) { | |
colorList.push(getRandomColor()) ; | |
} | |
// 色の適用 | |
for(var j = 0, itemLength = targetItems.length ; j < itemLength ; j++) { | |
applyColor(targetItems[j], colorList[getRandomInt(colorLengthInt)], applyToStroke, applyToFill) ; | |
} | |
res = true ; | |
} catch(e) { | |
//alert(e) ; | |
} | |
return res ; | |
} | |
/** | |
* このスクリプトによる変更があったときのみapp.undo()を実行する | |
* @param {Boolean} modified 変更したかどうか | |
* @return {} | |
*/ | |
function undoIf(modified) { | |
if(modified) {app.undo() ;} | |
} | |
/** | |
* 全角数値などいくつかの文字を半角に変換する | |
* @param {String} srcText 対象の文字列 | |
* @return {String} | |
*/ | |
function toHankaku(srcText) { | |
return srcText.toString().replace(/[0-9A-Za-z]/g, function(s) {return String.fromCharCode(s.charCodeAt(0) - 0xFEE0)}) ; | |
} | |
/** | |
* 色数指定&適用ダイアログを開く | |
* @param {Array} targetItems 処理対象のアイテム | |
* @return {} | |
*/ | |
function showDialog(targetItems) { | |
var defaultColorLength = '3' ; | |
var minimumColorLength = 1 ; | |
var lastInput = defaultColorLength ; | |
var modified = false ; | |
// DIALOG | |
// ====== | |
var dialog = new Window('dialog') ; | |
dialog.text = 'Apply Random Color' ; | |
dialog.orientation = 'column' ; | |
dialog.alignChildren = ['center', 'center'] ; | |
dialog.spacing = 16 ; | |
dialog.margins = 16 ; | |
// PANELMAIN | |
// ========= | |
var panelMain = dialog.add('panel', undefined, undefined, {name: 'panelMain'}) ; | |
panelMain.orientation = 'row' ; | |
panelMain.alignChildren = ['left', 'center'] ; | |
panelMain.spacing = 26 ; | |
panelMain.margins = 10 ; | |
// GROUPCOLORLENGTH | |
// ================ | |
var groupColorLength = panelMain.add('group', undefined, {name: 'groupColorLength'}) ; | |
groupColorLength.orientation = 'row' ; | |
groupColorLength.alignChildren = ['left', 'center'] ; | |
groupColorLength.spacing = 6 ; | |
groupColorLength.margins = 0 ; | |
var label = groupColorLength.add('statictext', undefined, undefined, {name: 'label'}) ; | |
label.text = {ja: '色の数', en: 'Colors'} ; | |
var fieldColorLength = groupColorLength.add("edittext {justify: 'right', properties: {name: 'fieldColorLength'}}") ; | |
fieldColorLength.text = defaultColorLength ; | |
fieldColorLength.preferredSize.width = 82 ; | |
// GROUPTARGETPROP | |
// =============== | |
var groupTargetProp = panelMain.add('group', undefined, {name: 'groupTargetProp'}) ; | |
groupTargetProp.orientation = 'row' ; | |
groupTargetProp.alignChildren = ['left','center'] ; | |
groupTargetProp.spacing = 12 ; | |
groupTargetProp.margins = 0 ; | |
var checkStroke = groupTargetProp.add('checkbox', undefined, undefined, {name: 'checkStroke'}) ; | |
checkStroke.text = {ja: '線', en: 'Stroke'} ; | |
checkStroke.value = false ; | |
var checkFill = groupTargetProp.add('checkbox', undefined, undefined, {name: 'checkFill'}) ; | |
checkFill.text = {ja: '塗り', en: 'Fill'} ; | |
checkFill.value = true ; | |
// GROUPFOOTER | |
// =========== | |
var groupFooter = dialog.add('group', undefined, {name: 'groupFooter'}) ; | |
groupFooter.orientation = 'row' ; | |
groupFooter.alignChildren = ['left', 'center'] ; | |
groupFooter.spacing = 12 ; | |
groupFooter.margins = 0 ; | |
var buttonWidth = 80 ; | |
var buttonUpdate = groupFooter.add('button', undefined, undefined, {name: 'buttonUpdate'}) ; | |
buttonUpdate.text = {ja: '再適用', en: 'Apply'} ; | |
buttonUpdate.preferredSize.width = buttonWidth ; | |
var buttonOK, buttonCancel ; | |
var labelOK = 'OK' ; | |
var labelCancel = 'Cancel' ; | |
if(/^w/i.test($.os)) { | |
buttonOK = groupFooter.add('button', undefined, labelOK) ; | |
buttonCancel = groupFooter.add('button', undefined, labelCancel) ; | |
} else { | |
buttonCancel = groupFooter.add('button', undefined, labelCancel) ; | |
buttonOK = groupFooter.add('button', undefined, labelOK) ; | |
} | |
// 色数入力フィールドにフォーカスする | |
fieldColorLength.active = true ; | |
// 初回の適用 | |
dialog.onShow = function() { | |
modified = setColorTo(targetItems, fieldColorLength.text, checkStroke.value, checkFill.value) ; | |
app.redraw() ; // ドキュメントを再描画 | |
} ; | |
// 色数入力フィールド入力時プレビュー | |
var handleChanging = function() { | |
try { | |
var hankakuText = toHankaku(fieldColorLength.text) ; | |
var newInt = Math.max(parseInt(hankakuText, 10), minimumColorLength) ; | |
if(isNaN(newInt)) { | |
fieldColorLength.text = lastInput ; | |
} else { | |
fieldColorLength.text = newInt.toString() ; | |
} | |
lastInput = fieldColorLength.text ; | |
undoIf(modified) ; | |
modified = setColorTo(targetItems, lastInput, checkStroke.value, checkFill.value) ; | |
app.redraw() ; | |
} catch(e) { | |
// skip | |
} | |
} ; | |
fieldColorLength.onChanging = handleChanging ; | |
// 色数入力フィールドUp/Downキー動作 | |
fieldColorLength.addEventListener('keyup', function(event) { | |
event.preventDefault() ; | |
var keyName = event.keyName ; | |
if(keyName === 'Up' || keyName === 'Down') { | |
var oldText = fieldColorLength.text ; | |
var addition = 1 ; | |
if(event.shiftKey) {addition = 10 ;} | |
var inverter = {'Up': 1, 'Down': -1} ; | |
try { | |
var currentInt = parseInt(oldText, 10) ; | |
var newInt = Math.max((Math.floor(currentInt / addition) * addition) + (addition * inverter[keyName]), minimumColorLength) ; | |
fieldColorLength.text = newInt.toString() ; | |
lastInput = fieldColorLength.text ; | |
handleChanging() ; | |
} catch(e) { | |
// skip | |
} | |
} | |
}) ; | |
// 再適用の処理 | |
checkStroke.onClick = handleChanging ; | |
checkFill.onClick = handleChanging ; | |
buttonUpdate.onClick = handleChanging ; | |
// キャンセルボタンの処理 | |
buttonCancel.onClick = function() { | |
undoIf(modified) ; | |
dialog.close() ; | |
} ; | |
// OKボタンの処理 | |
buttonOK.onClick = function() { | |
dialog.close() ; // ダイアログを閉じる | |
} ; | |
dialog.center() ; // ダイアログ表示位置をモニターの中心に | |
dialog.show() ; // 作成したダイアログを表示 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment