Sketch のプラグインをCocoaScriptを使って作る

Sketch を触ってみるとデザイナー向けのツールでありながら、ディレクターの人が使ってくれると、デザイナーも、エンジニアも嬉しいのでは？と思います。

でも、ちょっと敷居が高いかもしれない。

そこで、それっぽいページを作るのにプラグインを用意して画面の検討をできるようにしてみてはどうだろう？と思いました。

※ 実際、作りたいものを手書きで書いてくれるので十分です。ただ、「それっぽい」データをを入れてみると「こんな感じか〜」と出来上がりを想像しやすいかな？と思います。あと、Excelの指示書をなくしたい...

## ありそうな指示書

<img width="374" alt="スクリーンショット 2015-12-19 0.54.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/21321/2269172c-ea26-6bb9-1185-0a11183c6a71.png">

# プラグインを作る

プラグインは無料で作れます。githubにアップしておくこともできます。
今回作ったプラグインは、下記から見ることができます。:octocat:

* https://github.com/matsuhisa/SketchTestPlugin1
* 動作確認：Sketch 3、Mac OS X 10.10
* forkして、こ自由にお使いください

今回、作ってみているプラグインは

* jsonデータにある文字列をランダムで表示する
* 数値の範囲を決めてランダムで表示する
* 範囲を決めて★を表示する
* 画像をランダムに表示する

になります。

# プラグインの全体構成

SketchTestPlugin1 という名前で制作します

## プラグインの置き場所

プラグインの置き場所（ディレクトリ）は、Sketch で決まられているので話を省きます。下記のような場所にディレクトリを作って、ファイルを置きます。

```
~/Library/Containers/com.bohemiancoding.sketch3/Data/Library/Application Support/com.bohemiancoding.sketch3/Plugins/SketchTestPlugin1
```

## ディレクトリ構成

「SketchTestPlugin1.sketchplugin」 というディレクトリを用意して開発します。
「*.sketchplugin」というディレクトリを作ると、ディレクトリの中身が見られないです。そこで、該当のディレクトリについてコントロール + クリックから表示されるメニューにある「パッケージの内容を表示」を使い表示させると、中身を見ることができます

```
├── SketchTestPlugin1.sketchplugin
│   └── Contents
│       └── Sketch
│           ├── between.cocoascript
│           ├── images.cocoascript
│           ├── manifest.json
│           ├── random_shop.cocoascript
│           ├── random_text.cocoascript
│           ├── random_tokyo.cocoascript
│           ├── revew_average.cocoascript
│           ├── revew_average_star.cocoascript
│           └── script.cocoascript
└── data
    ├── areas
    │   └── tokyo.js
    ├── names
    │   └── names.js
    ├── photo
    │   └── 1.jpg
    ├── reviews
    └── shops
        └── names.js
```

### プラグインの実体

`SketchTestPlugin1/SketchTestPlugin1.sketchplugin/Contents/Sketch` に置きます。パスを通せば他の構成でも良いみたいです（今回は、その辺を考えていません）。

### manifest.json

プラグインに関する設定を行います。プラグインの名前や、メニュー表示の設定や、プラグイン実行のショートカットの設定をします。

### データを置く

`SketchTestPlugin1/data` は、画像データや、json形式で作ったファイルを置く場所です
特に決まりがないようなのですが、置きやすい場所がいいと思ったので、今回はこの場所に置きました。

# プラグインを作る

## CocoaScript

Sketch でプラグインを作るには、`CocoaScript` を利用します。

* https://github.com/ccgus/CocoaScript

`JavaScript + the Cocoa frameworks` とあり、「JavaScript」に 「Objective-C」を足したらこうなった...という言語になっています（Sketch 4 になったら 「Swift でプラグイン書けます」というのが嬉しい...）

## jsonデータにある文字列をランダムで表示する

`SketchTestPlugin1/SketchTestPlugin1.sketchplugin/Contents/Sketch/random_shop.cocoascript`についてです。

`@import '../../../data/shops/names.js'` でお店の名前が入ったjsonデータを読み込んでいます（サンプルでは、台湾のお店の名前が入っています）

for文のところでは、選択したオブジェクト1つ１つを取り出して、読み込んだjsonデータからランダムで文字列を設定しています。

実際に使うときは、読み込むデータを地名にしたり、お店の名前にしたり、人名にしたり、口コミのタイトルにしたりできそうですね。

### サンプルソースコード

```JavaScript
@import "library.cocoascript";
@import '../../../data/shops/names.js'

var onRun = function(context) {
  var selection = context.selection

  for (var i = 0, l = [selection count]; i < l; i++) {
    var layer = selection[i];
    layer.stringValue = data[Math.floor(Math.random() * data.length)];
  }

};
```

## 数値の範囲を決めてランダムで表示する

1.00〜4.99 までの数値をランダムで表示します。食べログなどである 口コミの点数 3.51 みたいなのを表示します。max、minの値を変更すると幅も変わります。toFixed() で小数点の桁数を決めています。

あと、stringValueでは文字列を設定することが前提なので、String()で数字を文字列に変換して設定しています。

### サンプルソースコード

```JavaScript
@import "library.cocoascript";

var onRun = function(context) {
  var documentName = context.document.displayName();
  var selection = context.selection
  var max = 4;
  var min = 1;

  for (var i = 0, l = [selection count]; i < l; i++) {
    var layer = selection[i];
    var avarage = ( Math.random() * max) ) + min;
    layer.stringValue = String(avarage.toFixed(2));
  }
};
```

### 実際に使ったときの画面

![shop.gif](https://qiita-image-store.s3.amazonaws.com/0/21321/4790fd2a-2597-45da-106a-ad3223e5bf5a.gif)


## 範囲を決めて★を表示する

口コミサイトで点数の横に星が表示されることがあります。あんな感じのを再現します（実際には、星の半分とかが出来ないので、雰囲気を作ってくれる感じです）。

今回は、色指定で`#FC4A78` を指定しました。Hex形式では指定ができないので、MSColor.colorWithRed_green_blue_alpha()で、UIColorの色指定をしています。このあたりが、Cocoaです。

```
@import "library.cocoascript";

var onRun = function(context) {
  var selection = context.selection
  for (var i = 0, l = [selection count]; i < l; i++) {
    var layer = selection[i];
    var color = MSColor.colorWithRed_green_blue_alpha(0.988, 0.29, 0.471, 1.0);

    layer.textColor = color;
    layer.stringValue = avarage_string();
  }
};

function avarage_string() {
  var max = 5;
  var min = 1;
  var avarage_string = "";
  var avarage = ( Math.random() * max) ) + min;
  var avarage_integer = Math.floor(avarage.toFixed(2));

  for(var i = min; i <= max; i++) {
    if( i <=  avarage_integer) {
      avarage_string = avarage_string + "★";
    }else {
      avarage_string = avarage_string + "☆";
    }
  }

  return avarage_string;
}
```

### 実際に使ったときの画面

![star.gif](https://qiita-image-store.s3.amazonaws.com/0/21321/e957ebe6-cfe2-2705-47bc-cd387d1b43b4.gif)


## 画像をランダムに表示する

`data/photo`にある画像ファイルをランダムで表示します。
だいぶ、Cocoa（Objective-C）で書いている量が増えています

```JavaScript:images.cocoascript
@import "library.cocoascript";

var onRun = function(context) {
  var selection = context.selection
  var data_path = 'data/photo/';
  var fileManager = [NSFileManager defaultManager];

  var script_path = context.scriptPath;
  var plugin_folder = script_path.match(/Plugins\/([\w -])*/)[0] + "/";
  var sketch_plugins_path = script_path.replace(/Plugins\/([\w -])*\/([\w -])*.sketchplugin(.*)/, "");
  var images_path =  sketch_plugins_path + plugin_folder + data_path;

  var imagesFileNames = [fileManager contentsOfDirectoryAtPath:images_path error:nil];
  var imageCount = [imagesFileNames count] - 1;

  var selected_paths = [];

  for(var i = 1; i < 100; i++){
    var index = Math.floor(Math.random() * imageCount);
    index = index >= imageCount ? 0 : index + 1;
    var file_name = imagesFileNames[index];
    var file_path = images_path + file_name;
    selected_paths.push(file_path);
  }

  for(var i = 0; i < [selection count]; i++){
    var layer = selection[i];
    log(selected_paths[i]);
    var image = [[NSImage alloc] initWithContentsOfFile:selected_paths[i]];

    if([layer class] == MSShapeGroup){
      var fill = layer.style().fills().firstObject();
      fill.setFillType(4);
      var coll = layer.style().fills().firstObject().documentData().images();
      [fill setPatternImage:image collection:coll]
      layer.style().fills().firstObject().setPatternFillType(1);
    }
  }
};

```

### 実際に使ったときの画面

サンプルに入れている画像ファイルが重くて（1ファイル1MBぐらいある）時間がかかっております...

![images.gif](https://dl.dropboxusercontent.com/u/538606/images/images.gif)

## デバッグ

デバッグするときには、便利なツールがあるらしいのですが、今回は「コンソール」を利用します。Mac OS X に標準で入っているツールになります。

### 設定

メニューにある「ファイル」 -> 「新規システムログクエリー」で下記のように設定します

<img width="822" alt="スクリーンショット 2015-12-20 1.07.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/21321/5d22b181-5965-8e69-51aa-d212c2ef7ccc.png">


# まとめ

実際、口コミサイトであれば、今回作ったプラグインを少しいじったりコピーして作ってみると、大体できそうな気がします。Cocoa（Objective-C）を使いこなせれたら、もっと色々と出来そうです。

## ありそうな指示書にプラグインを使ってみた結果

実際に使ってみると、「画像は全部バラバラにしてほしい」「金額のランダムプラグインがほしい」「日付を自動で入れてほしい」「口コミのタイトルをランダムで入れたい」とか、色々と要望が出てくると思います。

今回のプラグインをコピーすれば、大体はJavaScriptで作られているので作れそうな気がしてもらえたら嬉しいです（もしくは、エンジニアの人に作ってもらってもいいと思います）。

<img width="344" alt="スクリーンショット 2015-12-20 1.55.16.png" src="https://qiita-image-store.s3.amazonaws.com/0/21321/20ab2d2f-98f3-4cd9-0c3a-9504f29ff808.png">