illustrator脚本 016 连续移动

这是一个继承 菜单 变换->移动 命令中的值,继续移动。

/*
  MirrorMove.jsx for Adobe Illustrator
  Description: Mirror movement the object or points using the last values of the Object > Transform > Move...

  Release notes:
  0.1 Initial version

  NOTICE:
  Tested with Adobe Illustrator CC 2018-2022 (Mac), 2022 (Win).
  This script is provided "as is" without warranty of any kind.
  Free to use, not for sale

*/

//@target illustrator
app.preferences.setBooleanPreference('ShowExternalJSXWarning', false); // Fix drag and drop a .jsx file

// Main function
function main() {
  var SCRIPT = {
        name    : 'Mirror Move',
        version : 'v.0.1'
      },
      CFG = {
        aiVers  : parseInt(app.version),
        axis    : 'XY', // XY, X, Y
        ratio   : 1.0, // Movement ratio
        showUI  : false // Silent mode or dialog
      },
      SETTINGS = {
        name    : SCRIPT.name.replace(/\s/g, '_') + '_data.json',
        folder  : Folder.myDocuments + '/Adobe Scripts/'
      };

  if (!documents.length) {
    alert('Error\nOpen a document and try again');
    return;
  }

  if (CFG.aiVers < 16) {
    alert('Error\nSorry, script only works in Illustrator CS6 and later');
    return;
  }

  if (selection.length == 0 || selection.typename == 'TextRange') {
    alert('Error\nPlease, select one or more paths or path points');
    return;
  }

  var isAltPressed = false;

  if (ScriptUI.environment.keyboardState.altKey) {
    isAltPressed = true;
  }

  if ((CFG.showUI && !isAltPressed) || (!CFG.showUI && isAltPressed)) { // Show dialog
    invokeUI(SCRIPT, CFG, SETTINGS);
  } else if (CFG.showUI && isAltPressed) { // Silent mode with the latest settings
    var params = loadSettings(SETTINGS);
    if (params.length) process(params[0], params[1]);
  } else { // Silent mode with the default settings
    process(CFG.axis, CFG.ratio);
  }
}

/**
 * Show UI
 * @param {Object} title - The script name
 * @param {Object} CFG - Default settings
 * @param {Object} cfgFile - Settings file
 * @param {Array} paths - Selected paths
 */
function invokeUI(title, cfg, cfgFile) {
  var params = loadSettings(cfgFile);

  var dialog = new Window('dialog', title.name + ' ' + title.version);
      dialog.orientation = 'column';
      dialog.alignChildren = ['fill', 'center'];
      dialog.opacity = .98;

  var axisPnl = dialog.add('panel', undefined, 'Movement axis');
      axisPnl.orientation = 'row';
      axisPnl.margins = [10, 15, 10, 7];
      axisPnl.alignChildren = ['fill', 'center'];

  var xyRb = axisPnl.add('radiobutton', undefined, 'XY');
  var xRb = axisPnl.add('radiobutton', undefined, 'X');
  var yRb = axisPnl.add('radiobutton', undefined, 'Y');

  if (params.length) {
    for (var i = 0; i < axisPnl.children.length; i++) {
      if (params[0] == axisPnl.children[i].text)
        axisPnl.children[i].value = true;
    }
  } else {
    xyRb.value = true;
  }

  var ratioGrp = dialog.add('group');
      ratioGrp.alignChildren = ['fill', 'center'];

  ratioGrp.add('statictext', undefined, 'Movement ratio');
  var ratioInp = ratioGrp.add('edittext', undefined, params.length ? params[1] : cfg.ratio);
      ratioInp.preferredSize.width = 60;

  var btns = dialog.add('group');
      btns.alignChildren = ['fill', 'center'];

  var cancel = btns.add('button', undefined, 'Cancel', { name: 'cancel' });
  var ok = btns.add('button', undefined, 'Ok',  { name: 'ok' });

  var copyright = dialog.add('statictext', undefined, '\u00A9 Sergey Osokin. Visit Github');
      copyright.justify = 'center';

  cancel.onClick = dialog.close;

  ok.onClick = function() {
    var params = [
          xyRb.value ? 'XY' : (xRb.value ? 'X' : 'Y'),
          strToAbsNum(ratioInp.text, cfg.ratio)
        ];

    saveSettings(cfgFile, params);
    process(params[0], params[1]);
    dialog.close();
  }

  copyright.addEventListener('mousedown', function () {
    openURL('https://github.com/creold');
  });

  dialog.center();
  dialog.show();
}

/**
 * Save UI options to file
 * @param {Object} cfgFile - Settings file
 * @param {Array} params - Options status
 */
function saveSettings(cfgFile, params) {
  if(!Folder(cfgFile.folder).exists) Folder(cfgFile.folder).create();
  var $file = new File(cfgFile.folder + cfgFile.name);
  $file.encoding = 'UTF-8';
  $file.open('w');
  var pref = {};
  pref.axis = params[0];
  pref.ratio = params[1];
  var data = pref.toSource();
  $file.write(data);
  $file.close();
}

/**
 * Load options from file
 * @param {Object} cfgFile - Settings file
 * @return {Array} out - Options status
 */
function loadSettings(cfgFile) {
  var out = [], $file = File(cfgFile.folder + cfgFile.name);
  if ($file.exists) {
    try {
      $file.encoding = 'UTF-8';
      $file.open('r');
      var json = $file.readln();
      var pref = new Function('return ' + json)();
      $file.close();
      if (typeof pref != 'undefined') {
        out[0] = pref.axis;
        out[1] = pref.ratio;
      }
    } catch (e) {}
  }
  return out;
}

/**
 * Run processing
 * @param {string} axis - Movement axis key
 * @param {number} ratio - Movement ratio
 */
function process(axis, ratio) {
  var items = getItems(selection),
      isX = /x/i.test(axis),
      isY = /y/i.test(axis),
      oldPos = getPositions(items); // Save current point positions

  app.executeMenuCommand('transformagain');

  // Update items positions
  items = getItems(selection);
  var newPos = getPositions(items);

  // Reduce operations in the Illustrator history
  app.undo();
  items = getItems(selection);

  for (var i = 0, len = oldPos.length; i < len; i++) {
    if (!isEqualArr(oldPos[i], newPos[i])) {
      move(items[i], oldPos[i], newPos[i], isX, isY, ratio);
    }
  }
}

/**
 * Get single item and points from selection
 * @param {(Object|Array)} collection - Set of items
 * @return {Array} out - Items 
 */
function getItems(collection) {
  var out = [];

  for (var i = 0; i < collection.length; i++) {
    var item = collection[i];
    if (item.pageItems && item.pageItems.length) {
      out = [].concat(out, getItems(item.pageItems));
    } else if (/compound/i.test(item.typename) && item.pathItems.length) {
      out = [].concat(out, getItems(item.pathItems));
    } else if (/pathitem/i.test(item.typename)) {
      out = out.concat(getPoints(item));
    } else {
      out.push(item);
    }
  }

  return out;
}

/**
 * Get selected points
 * @param {Object} item - Current object
 * @return {Array} out - Selected points 
 */
function getPoints(item) {
  var out = [];

  if (item.pathPoints && item.pathPoints.length > 1) {
    var points = item.pathPoints;
    for (var i = 0, len = points.length; i < len; i++) {
      if (isSelected(points[i])) out.push(points[i]);
    }
  }

  return out;
}

/**
 * Check PathPoint
 * @param {Object} item - Current object
 * @return {boolean} PathPoint or not
 */
function isPoint(item) {
  return /point/i.test(item.typename);
}

/**
 * Check PathPoint is selected
 * @param {Object} point - Current point
 * @return {boolean} Selected or not 
 */
function isSelected(point) {
  return point.selected == PathPointSelection.ANCHORPOINT;
}

/**
 * Get selected points on paths
 * @param {Array} items - Objects and points
 * @return {Array} out - Items coordinate pairs
 */
function getPositions(items) {
  var out = [];

  for (var i = 0, len = items.length; i < len; i++) {
    if (isPoint(items[i])) {
      out[i] = items[i].anchor;
    } else {
      out[i] = items[i].position;
    }
  }

  return out;
}

/**
 * Compare arrays
 * @param {Array} a
 * @param {Array} b
 * @return {boolean} Equal or not
 */
function isEqualArr(a, b) {
  if (a.length !== 0 && a.length === b.length) {
    for (var i = 0; i < a.length; i++) {
      if (a[i] !== b[i]) return false;
    }
    return true;
  }
  return false;
}

/**
 * Move item to position
 * @param {Object} item - Object or point
 * @param {Array} pos1 - Old position
 * @param {Array} pos2 - Current position
 * @param {boolean} isX - X-axis move
 * @param {boolean} isY - Y-axis move
 * @param {number} ratio - Movement ratio
 */
function move(item, pos1, pos2, isX, isY, ratio) {
  var x = (isX ? 1 : -1) * ratio * (pos1[0] - pos2[0]),
      y = (isY ? 1 : -1) * ratio * (pos1[1] - pos2[1]);

  if (isPoint(item)) {
    with (item) {
      anchor = [anchor[0] + x, anchor[1] + y];
      leftDirection = [leftDirection[0] + x, leftDirection[1] + y];
      rightDirection = [rightDirection[0] + x, rightDirection[1] + y];
    }
  } else {
    item.translate(x, y);
  }
}

/**
 * Convert string to absolute number
 * @param {string} str - Input data
 * @param {number} def - Default value if the string don't contain digits
 * @return {number}
 */
function strToAbsNum(str, def) {
  if (arguments.length == 1 || def == undefined) def = 1;
  str = str.replace(/,/g, '.').replace(/[^\d.]/g, '');
  str = str.split('.');
  str = str[0] ? str[0] + '.' + str.slice(1).join('') : '';
  if (isNaN(str) || !str.length) return parseFloat(def);
  else return parseFloat(str);
}

/**
 * Open link in browser
 * @param {string} url - Website adress
 */
function openURL(url) {
  var html = new File(Folder.temp.absoluteURI + '/aisLink.html');
  html.open('w');
  var htmlBody = '<html><head><META HTTP-EQUIV=Refresh CONTENT="0; URL=' + url + '"></head><body> <p></body></html>';
  html.write(htmlBody);
  html.close();
  html.execute();
}

// Run script
try {
  main();
} catch (e) {}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值