├── .appcast.xml ├── .gitignore ├── LICENSE ├── README.md ├── assets └── smubar.png ├── chippen-charts.sketchplugin └── Contents │ ├── Resources │ ├── .DS_Store │ └── smubar.png │ └── Sketch │ ├── barchart.js │ ├── barchart.js.map │ ├── cliptexttosymbol.js │ ├── cliptexttosymbol.js.map │ ├── manifest.json │ ├── nonrandom-barchart.js │ ├── nonrandom-barchart.js.map │ ├── randomfill.js │ └── randomfill.js.map ├── images ├── 1_selectLayers.png ├── 2_random2.png ├── 3_randomResult.png ├── 4_trendUp2.png ├── 5_trendUpResult.png ├── 6_showcase.png ├── dialogs.png ├── header-original.gif ├── showcase-paste-clipboard-into-symbols.gif ├── showcase-paste-clipboard-into-symbols_640px.gif ├── showcase1-o.gif ├── showcase2-definedValues.gif └── showcase_random-fill_chippencharts_sketch-plugin.gif ├── package-lock.json ├── package.json └── src ├── barchart.js ├── cliptexttosymbol.js ├── manifest.json ├── nonrandom-barchart.js ├── randomfill.js └── utils.js /.appcast.xml: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | node_modules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Martin von Lupin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Chippen charts

2 | 3 | 4 | 5 | 6 |
7 | Random bar charts for your data driven mockups 8 |
9 |
10 | 11 | This is a Sketch plugin for creating charts with random or user defined data for use in mockups. Change the size of selected rectangles. Chose between random and linear. Works for both horizontal and vertical bar charts. 12 | Furthermore, the latest feature allows you to paste text from the clipboard straight into symbol overrides. How good is that, heh? 13 | 14 | Made with love by [Small Multiples](https://smallmultiples.com.au/) in Chippendale, Sydney. 15 | 16 | **List of current features** 17 | - Bar chart with random values 18 | - Bar chart with actual data 19 | - Paste clipboard text into symbols 20 | - Apply random fill to selection **(new)** 21 | 22 | 23 | ## How to install 24 | 25 | 1. Click the `Clone or download` button in the top right and choose `Download Zip` 26 | 2. Save the ZIP file to your harddrive 27 | 3. Open the downloaded file and double click the sketch file `chippen-charts.sketchplugin` 28 | 4. The plugin is installed and you can use it via the menu `Plugins` > `Chippen charts` 29 | 30 | 31 | ## Features 32 | 33 | ### 1. Random bar chart from selected layers 34 | 35 | If you don't have data yet but still want to design a bar chart for your mockup, you can use the option to apply random values. You can also apply not-so-random values when choosing trend up or trend down. 36 | 37 | 38 | 39 | --- 40 | 41 | ### 2. Defined bar chart from selected layers 42 | 43 | If you have data that you want to apply to your chart this option is for you. You can even copy / paste from Excel columns or rows. How cool is that, right? In case your number values don't exactly match your desired pixel values, you have the option to apply a multiplier or set a maximum height. By default values don't get scaled. 44 | 45 | 46 | 47 | --- 48 | 49 | ### 3. Paste clipboard text into symbols 50 | 51 | Get your clipboard loaded with amazing text content, fire up the plugin, and let the magic of the plugin paste everything into your symbol override of choice. It's as simple as that. 52 | 53 | You might wonder why you wouldn't wanna use the Sketch Data feature for that. The thing is, the Sketch Data feature does not preserve the order of elements, which this plugin does. 54 | 55 | 56 | 57 | ### 4. Random fill 58 | 59 | Apply random colours to selected layers or choose to apply colours based on the order layers in order to create a gradient. All that needs to be done is choosing two hex colours and the number of colours you want to be generated. 60 | 61 | 62 | 63 | --- 64 | 65 | 66 | ## How the plugin works 67 | 68 | ### Dialog boxes for random and user defined action 69 | 70 | Those dialog boxes give you a good summary of what the plugin is capable of. Just have a look at the various input options. 71 | 72 | 73 | 74 | ### Workflow 75 | 1. **Create** desired amount of rectangles 76 | 2. Layers must be in the correct **order** 77 | 3. Make sure layers are either bottom or left **aligned** 78 | 4. **Run the plugin** and adjust _settings_ in dialog window if necessary 79 | 5. The size of you bars will be adjusted 80 | 81 | ### Settings 82 | #### Horizontal or vertical bar chart 83 | Chippen Chart detects wheter you are about to create a vertical or horizontal bar chart using the x and y-position of your selected layers. If there is no common x or y-value it will by default apply the logic for vertical bars. 84 | 85 | #### Min and max size (pixel) 86 | Chippen chart detects minimum and maximum pixel height of selected layers and apply those to the new bar chart. You can also adjust your desired extrema in the dialog window. If all selected layers share the same height the plugin will apply a default value for either min or max. 87 | 88 | #### Trend type 89 | You can choose between 5 trend types. All of them will use the min and max value you define. _Random_ will apply completely random integer numbers. Linear_ will interpolate values between min and max. _Natural_ will do the same while adding a notion of randomness. 90 | 91 | - [x] Random 92 | - [ ] Trend going up ↑ (linear) 93 | - [ ] Trend going up ↑ (natural) 94 | - [ ] Trend going down ↓ (linear) 95 | - [ ] Trend going down ↓ (natural) 96 | 97 | ### Examples 98 | 99 | #### Defining a chart with trend going up 100 | Besindes random numbers you can choose between linear trends and natural trends. Natural trends are like linear ones, but they have a little bit of randomeness aplpied to them. 101 | 102 | 103 | #### This is how a trend up (natural) chart looks like 104 | 105 | 106 | #### Showcase of different types 107 | 108 | 109 | ## Version history 110 | 111 | ##### 3.6.1 112 | 113 | - Random fill: add option to use layer order 114 | 115 | ##### 3.6 116 | 117 | - New feature: Random fill 118 | - Bar charts: Force vertical or horizontal bar chart type 119 | - Updates to popup 120 | 121 | ##### 3.5.4 122 | 123 | - Bugfix for wrong adjustment of bars when data point has value zero 124 | 125 | ##### 3.5.3 126 | 127 | - Add data value to layer name in the format "Layer name {:value:}" 128 | - Optimise workflow with negative values for both, random and user-defined charts 129 | 130 | ##### 3.5.2 131 | 132 | - Bug fix for "Defined bar chart from selected layers" where bars wouldn't reposition correctly when first value is negative. 133 | - Overall improvements in dealing with negative values. 134 | 135 | ##### 3.5.1 136 | 137 | - Bug fix for "Defined bar chart from selected layers" where the scale values from the input fields would not be used properly to calculate heights of bars 138 | 139 | ##### 3.5 140 | 141 | - Introducing new feature: Paste clipboard text into symbol overrides 142 | 143 | ##### 3.4 144 | 145 | - Introducing new feature: Create bar charts using user defined values 146 | - Enhancements to dialog design 147 | 148 | ##### 3.3.3 149 | 150 | - Fixing update issues 151 | 152 | ## Troubleshooting 153 | Unintended results will appear when the proportional resizing is set between a layer's width and height. **Proportional resizing must be disabled** 🔓 154 | 155 | ## Love it or hate it? 156 | Let us know. info@small.mu | @smallmultiples 157 | 158 | 159 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /assets/smubar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smallmultiples/sketch-chippencharts/0cef328ad86b40f35a04776996acecb2c797dac8/assets/smubar.png -------------------------------------------------------------------------------- /chippen-charts.sketchplugin/Contents/Resources/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smallmultiples/sketch-chippencharts/0cef328ad86b40f35a04776996acecb2c797dac8/chippen-charts.sketchplugin/Contents/Resources/.DS_Store -------------------------------------------------------------------------------- /chippen-charts.sketchplugin/Contents/Resources/smubar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/smallmultiples/sketch-chippencharts/0cef328ad86b40f35a04776996acecb2c797dac8/chippen-charts.sketchplugin/Contents/Resources/smubar.png -------------------------------------------------------------------------------- /chippen-charts.sketchplugin/Contents/Sketch/barchart.js: -------------------------------------------------------------------------------- 1 | var that = this; 2 | function __skpm_run (key, context) { 3 | that.context = context; 4 | 5 | var exports = 6 | /******/ (function(modules) { // webpackBootstrap 7 | /******/ // The module cache 8 | /******/ var installedModules = {}; 9 | /******/ 10 | /******/ // The require function 11 | /******/ function __webpack_require__(moduleId) { 12 | /******/ 13 | /******/ // Check if module is in cache 14 | /******/ if(installedModules[moduleId]) { 15 | /******/ return installedModules[moduleId].exports; 16 | /******/ } 17 | /******/ // Create a new module (and put it into the cache) 18 | /******/ var module = installedModules[moduleId] = { 19 | /******/ i: moduleId, 20 | /******/ l: false, 21 | /******/ exports: {} 22 | /******/ }; 23 | /******/ 24 | /******/ // Execute the module function 25 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 26 | /******/ 27 | /******/ // Flag the module as loaded 28 | /******/ module.l = true; 29 | /******/ 30 | /******/ // Return the exports of the module 31 | /******/ return module.exports; 32 | /******/ } 33 | /******/ 34 | /******/ 35 | /******/ // expose the modules object (__webpack_modules__) 36 | /******/ __webpack_require__.m = modules; 37 | /******/ 38 | /******/ // expose the module cache 39 | /******/ __webpack_require__.c = installedModules; 40 | /******/ 41 | /******/ // define getter function for harmony exports 42 | /******/ __webpack_require__.d = function(exports, name, getter) { 43 | /******/ if(!__webpack_require__.o(exports, name)) { 44 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 45 | /******/ } 46 | /******/ }; 47 | /******/ 48 | /******/ // define __esModule on exports 49 | /******/ __webpack_require__.r = function(exports) { 50 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 51 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 52 | /******/ } 53 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 54 | /******/ }; 55 | /******/ 56 | /******/ // create a fake namespace object 57 | /******/ // mode & 1: value is a module id, require it 58 | /******/ // mode & 2: merge all properties of value into the ns 59 | /******/ // mode & 4: return value when already ns object 60 | /******/ // mode & 8|1: behave like require 61 | /******/ __webpack_require__.t = function(value, mode) { 62 | /******/ if(mode & 1) value = __webpack_require__(value); 63 | /******/ if(mode & 8) return value; 64 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 65 | /******/ var ns = Object.create(null); 66 | /******/ __webpack_require__.r(ns); 67 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 68 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 69 | /******/ return ns; 70 | /******/ }; 71 | /******/ 72 | /******/ // getDefaultExport function for compatibility with non-harmony modules 73 | /******/ __webpack_require__.n = function(module) { 74 | /******/ var getter = module && module.__esModule ? 75 | /******/ function getDefault() { return module['default']; } : 76 | /******/ function getModuleExports() { return module; }; 77 | /******/ __webpack_require__.d(getter, 'a', getter); 78 | /******/ return getter; 79 | /******/ }; 80 | /******/ 81 | /******/ // Object.prototype.hasOwnProperty.call 82 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 83 | /******/ 84 | /******/ // __webpack_public_path__ 85 | /******/ __webpack_require__.p = ""; 86 | /******/ 87 | /******/ 88 | /******/ // Load entry module and return exports 89 | /******/ return __webpack_require__(__webpack_require__.s = "./src/barchart.js"); 90 | /******/ }) 91 | /************************************************************************/ 92 | /******/ ({ 93 | 94 | /***/ "./src/barchart.js": 95 | /*!*************************!*\ 96 | !*** ./src/barchart.js ***! 97 | \*************************/ 98 | /*! exports provided: default */ 99 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 100 | 101 | "use strict"; 102 | __webpack_require__.r(__webpack_exports__); 103 | /* harmony import */ var sketch__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sketch */ "sketch"); 104 | /* harmony import */ var sketch__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sketch__WEBPACK_IMPORTED_MODULE_0__); 105 | /* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils.js */ "./src/utils.js"); 106 | 107 | // documentation: https://developer.sketchapp.com/reference/api/ 108 | 109 | /* harmony default export */ __webpack_exports__["default"] = (function () { 110 | log('~~ Run Chippen charts ~~'); 111 | var doc = sketch__WEBPACK_IMPORTED_MODULE_0___default.a.getSelectedDocument(); 112 | var selectedLayers = doc.selectedLayers; 113 | /* 114 | Analyse selected layers 115 | */ 116 | 117 | var isVertical = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["isVerticalBarchart"])(doc.selectedLayers); 118 | var minMax_fromSelection = getMinMax(doc.selectedLayers, isVertical); 119 | /* 120 | User input 121 | */ 122 | 123 | var response = myinput(minMax_fromSelection, doc.selectedLayers.layers.length, isVertical); 124 | var minMax = [response.min, response.max]; 125 | 126 | if (response.code !== 1000) { 127 | return; 128 | } 129 | 130 | var myRandomSlots = []; 131 | 132 | if (response.trendTypeInput == 0) { 133 | // Only for random trend 134 | // Set 2 random bars to min and max 135 | myRandomSlots = twoRandomSlots(selectedLayers.layers.length, 'Random'); 136 | } // Force other type than detected if user has selected force type 137 | 138 | 139 | if (response.forcetype) { 140 | isVertical = !isVertical; 141 | } 142 | /* 143 | UI message 144 | */ 145 | 146 | 147 | var trendTypeInput_name = ["random data", "trend going up ↑ (linear)", "trend going up ↑ (natural)", "trend going down ↓ (linear)", "trend going down ↓ (natural)"]; 148 | var isVertical_name = "vertical"; 149 | 150 | if (!isVertical) { 151 | isVertical_name = "horizontal"; 152 | } 153 | 154 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.message("".concat(doc.selectedLayers.length, " ").concat(isVertical_name, " bars with ").concat(trendTypeInput_name[response.trendTypeInput], " (").concat(minMax[0], "px\u2013").concat(minMax[1], "px)")); 155 | /* 156 | Changing size 157 | */ 158 | 159 | var firstBarVal = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["getValFromLayerName"])(selectedLayers.layers[0].name); 160 | var baseLine = 0; 161 | 162 | if (isVertical) { 163 | baseLine = selectedLayers.layers[0].frame.y + selectedLayers.layers[0].frame.height; // Adjust when first value of existing bar is negative 164 | // Based on layer name 165 | 166 | if (firstBarVal < 0) { 167 | baseLine = baseLine - Math.abs(firstBarVal); 168 | } 169 | 170 | ; 171 | } else { 172 | if (firstBarVal >= 0) { 173 | baseLine = selectedLayers.layers[0].frame.x; 174 | } else if (firstBarVal < 0) { 175 | baseLine = selectedLayers.layers[0].frame.x + Math.abs(firstBarVal); 176 | } 177 | } 178 | 179 | for (var i = 0; i < selectedLayers.layers.length; i++) { 180 | var newLength = 1; 181 | 182 | if (response.trendTypeInput == 3 || response.trendTypeInput == 4) { 183 | // reverse minMax if trend is going down 184 | // and after that just use same code as for trend going up 185 | minMax = [minMax[1], minMax[0]]; 186 | response.trendTypeInput = response.trendTypeInput - 2; 187 | } // Random 188 | 189 | 190 | if (response.trendTypeInput == 0) { 191 | // random values between min and max 192 | newLength = Math.floor(Math.random() * (minMax[1] - minMax[0])) + minMax[0]; 193 | 194 | if (i == myRandomSlots[0]) { 195 | // force a random slot to be min 196 | newLength = minMax[0]; 197 | } 198 | 199 | if (i == myRandomSlots[1]) { 200 | // force a random slot to be max 201 | newLength = minMax[1]; 202 | } 203 | } // Trend going up 204 | 205 | 206 | if (response.trendTypeInput == 1 || response.trendTypeInput == 2) { 207 | var stepIncrease = (minMax[1] - minMax[0]) / selectedLayers.layers.length; 208 | 209 | if (response.trendTypeInput == 1) { 210 | newLength = stepIncrease * i + minMax[0]; 211 | } else if (response.trendTypeInput == 2) { 212 | var increase_random = stepIncrease * Math.random(); 213 | var plusOrMinus = Math.random() < 0.5 ? -1 : 1; 214 | newLength = stepIncrease * i + minMax[0] + increase_random * plusOrMinus; 215 | } // force first and last to be min and max 216 | 217 | 218 | if (i == 0) { 219 | newLength = minMax[0]; 220 | } else if (i == selectedLayers.layers.length - 1) { 221 | newLength = minMax[1]; 222 | } 223 | 224 | newLength = Math.round(newLength * 10) / 10; 225 | } // Length can't be zero 226 | 227 | 228 | if (newLength == 0) { 229 | newLength = 1; 230 | } // Change Width / Height 231 | 232 | 233 | if (isVertical) { 234 | // Change height 235 | selectedLayers.layers[i].frame.height = Math.abs(newLength); // Move to baseline 236 | 237 | if (newLength > 0) { 238 | // Reposition bars with positive values 239 | selectedLayers.layers[i].frame.y = baseLine - Math.abs(newLength); 240 | } else { 241 | // Reposition bars with negative values 242 | selectedLayers.layers[i].frame.y = baseLine; 243 | } 244 | } else { 245 | // Reset position, just in case 246 | selectedLayers.layers[i].frame.x = baseLine; // Change Width 247 | 248 | selectedLayers.layers[i].frame.width = Math.abs(newLength); // Reposition bars with negative values 249 | 250 | if (newLength < 0) { 251 | selectedLayers.layers[i].frame.x = selectedLayers.layers[i].frame.x - Math.abs(newLength); 252 | } 253 | } // Rename layer 254 | // Example: Rectangle ==> Rectangle {:12:} 255 | 256 | 257 | selectedLayers.layers[i].name = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["renameLayer"])(selectedLayers.layers[i].name, newLength); 258 | } 259 | }); 260 | 261 | function getMinMax(arr, isVertical) { 262 | // arr needs to be doc.selectedLayers 263 | var min = 0; 264 | var max = 0; 265 | 266 | if (isVertical) { 267 | // Vertical bar chart (get minMax height) 268 | for (var i = 0; i < arr.layers.length; i++) { 269 | var thisHeight = arr.layers[i].frame.height; // Max 270 | 271 | if (thisHeight > max) { 272 | max = thisHeight; 273 | } // Min 274 | 275 | 276 | if (min == 0) { 277 | // set min at first runfirst 278 | min = max; 279 | } 280 | 281 | if (thisHeight < min) { 282 | min = thisHeight; 283 | } 284 | } 285 | } else { 286 | // Horizontal bar chart (get minMax width) 287 | for (var i = 0; i < arr.layers.length; i++) { 288 | var thisWidth = arr.layers[i].frame.width; // Max 289 | 290 | if (thisWidth > max) { 291 | max = thisWidth; 292 | } // Min 293 | 294 | 295 | if (min == 0) { 296 | // set min at first run 297 | min = max; 298 | } 299 | 300 | if (thisWidth < min) { 301 | min = thisWidth; 302 | } 303 | } 304 | } 305 | 306 | return [Math.ceil(min), Math.ceil(max)]; 307 | } 308 | 309 | function twoRandomSlots(length, type) { 310 | var slotOne = 0; 311 | var slotTwo = 0; 312 | 313 | if (type == 'Random') { 314 | slotOne = Math.floor(Math.random() * length / 2); 315 | slotTwo = Math.floor(Math.random() * length / 2) + Math.floor(length / 2); 316 | } 317 | 318 | return [slotOne, slotTwo]; 319 | } 320 | 321 | function myinput() { 322 | var myMinMax = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [20, 100]; 323 | var numOfBars = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ""; 324 | var my_isVertical = arguments.length > 2 ? arguments[2] : undefined; 325 | var myresponse = {}; 326 | 327 | if (myMinMax.length != 2 || myMinMax[0] == myMinMax[1]) { 328 | if (myMinMax[0] > 100) { 329 | myMinMax = [20, myMinMax[1]]; 330 | } else { 331 | myMinMax = [myMinMax[0], 100]; 332 | } 333 | } 334 | 335 | if (numOfBars == 0) { 336 | myresponse.code == 1001; 337 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.alert("Sorry buddy", "You need to select multiple rectangles (bars) for this plugin to work."); 338 | } 339 | 340 | if (numOfBars != 0) { 341 | if (numOfBars == 1) { 342 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.alert("Hey, just letting you know", "Most awesome results come when selecting more than 1 bar."); 343 | } // Create initial view panel 344 | 345 | 346 | var width = 280; 347 | var height = 40; 348 | var view = NSView.alloc().initWithFrame(NSMakeRect(0, 0, width, height)); // Min Max input 349 | 350 | var minInput = NSTextField.alloc().initWithFrame(NSMakeRect(0.0, 15.0, 130, 25.0)); 351 | minInput.cell().setPlaceholderString(myMinMax[0] + " (min)"); 352 | view.addSubview(minInput); 353 | var maxInput = NSTextField.alloc().initWithFrame(NSMakeRect(150, 15.0, 130, 25.0)); 354 | maxInput.cell().setPlaceholderString(myMinMax[1] + " (max)"); 355 | view.addSubview(maxInput); // Nature of data 356 | 357 | var trendTypeInput = NSView.alloc().initWithFrame(NSMakeRect(0, 0, width, 135)); // Acts like a template (prototype) for our radio buttons 358 | 359 | var buttonFormat; 360 | buttonFormat = NSButtonCell.alloc().init(); 361 | buttonFormat.setButtonType(NSRadioButton); // The matrix will contain all the cells (radio buttons) 362 | 363 | var matrixFormat = NSMatrix.alloc().initWithFrame_mode_prototype_numberOfRows_numberOfColumns(NSMakeRect(0, 0, 260, 135), // Horizontal position, vertical position, width, height 364 | NSRadioModeMatrix, // This makes the radio buttons work together 365 | buttonFormat, 5, // 1 row 366 | 1 // 3 columns (for 3 radio buttons) 367 | ); // Settings the size of the radio buttons 368 | 369 | matrixFormat.setCellSize(CGSizeMake(260, 25)); // Adding the radio buttons to the form 370 | 371 | var cells = matrixFormat.cells(); 372 | cells.objectAtIndex(0).setTitle("Random"); 373 | cells.objectAtIndex(1).setTitle("Trend going up ↑ (linear)"); 374 | cells.objectAtIndex(2).setTitle("Trend going up ↑ (natural)"); 375 | cells.objectAtIndex(3).setTitle("Trend going down ↓ (linear)"); 376 | cells.objectAtIndex(4).setTitle("Trend going down ↓ (natural)"); // Adding the matrix to the form 377 | 378 | trendTypeInput.addSubview(matrixFormat); // Bar type: Vertical or horizontal 379 | 380 | var bartype_label = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("Vertical or horizontal?", 12, true, NSMakeRect(0, 0, width, 16)); 381 | var bartype_radio = NSView.alloc().initWithFrame(NSMakeRect(0, 0, width, 48)); 382 | var matrixFormat_bartype = NSMatrix.alloc().initWithFrame_mode_prototype_numberOfRows_numberOfColumns(NSMakeRect(0, 0, 260, 48), NSRadioModeMatrix, buttonFormat, 2, 1); 383 | matrixFormat_bartype.setCellSize(CGSizeMake(260, 25)); 384 | var bartype_radio1_label = my_isVertical ? "Automatic (vertical detected)" : "Automatic (horizontal detected)"; 385 | var bartype_radio2_label = my_isVertical ? "Force horizontal" : "Force vertical"; 386 | var cells_bartype = matrixFormat_bartype.cells(); 387 | cells_bartype.objectAtIndex(0).setTitle(bartype_radio1_label); 388 | cells_bartype.objectAtIndex(1).setTitle(bartype_radio2_label); 389 | bartype_radio.addSubview(matrixFormat_bartype); // Setup the window 390 | 391 | var alert = COSAlertWindow.new(); 392 | 393 | if (numOfBars == 1) { 394 | alert.setMessageText("Create your random bar chart \nwith 1 selected layer"); 395 | } else { 396 | alert.setMessageText("Create your random bar chart \nwith ".concat(numOfBars, " selected layers")); 397 | } 398 | 399 | alert.addButtonWithTitle("Run"); 400 | alert.addButtonWithTitle("Cancel"); 401 | alert.setInformativeText("This is for a bar chart where random values are applied \nto the layers of your selection."); 402 | var extrema_label = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("Define extrema of bars", 12, true, NSMakeRect(0, 0, width, 16)); 403 | alert.addAccessoryView(extrema_label); //alert.addTextLabelWithValue("Define extrema of bars"); 404 | 405 | alert.addAccessoryView(view); 406 | var trend_label = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("Specify the desired trend", 12, true, NSMakeRect(0, 0, width, 16)); 407 | alert.addAccessoryView(trend_label); //alert.addTextLabelWithValue("Specify the desired trend"); 408 | 409 | alert.addAccessoryView(trendTypeInput); 410 | alert.addAccessoryView(bartype_label); 411 | alert.addAccessoryView(bartype_radio); 412 | /* 413 | Key navigation (popup) 414 | */ 415 | 416 | alert.alert().window().setInitialFirstResponder(minInput); 417 | minInput.setNextKeyView(maxInput); 418 | maxInput.setNextKeyView(minInput); 419 | /* 420 | Note 421 | */ 422 | 423 | var note_line1 = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("\nPlease make sure proportional scaling is disabled", 11, false, NSMakeRect(0, 0, width, 16 * 2), 0.3); 424 | alert.addAccessoryView(note_line1); 425 | var responseCode = alert.runModal(); 426 | 427 | if (responseCode == 1000) { 428 | myresponse.code = 1000; // OK 429 | // pass minmax input 430 | 431 | if (minInput.stringValue() == "") { 432 | myresponse.min = myMinMax[0]; 433 | } else { 434 | myresponse.min = parseInt(minInput.stringValue()); 435 | } 436 | 437 | if (maxInput.stringValue() == "") { 438 | myresponse.max = myMinMax[1]; 439 | } else { 440 | myresponse.max = parseInt(maxInput.stringValue()); 441 | } // Force bar chart type 442 | 443 | 444 | var forcetype_index = matrixFormat_bartype.cells().indexOfObject(matrixFormat_bartype.selectedCell()); 445 | myresponse.forcetype = forcetype_index == 0 ? false : true; 446 | } else { 447 | // Cancel 448 | myresponse.code = 1001; 449 | } 450 | 451 | myresponse.trendTypeInput = matrixFormat.cells().indexOfObject(matrixFormat.selectedCell()); 452 | } 453 | 454 | return myresponse; 455 | } 456 | 457 | /***/ }), 458 | 459 | /***/ "./src/utils.js": 460 | /*!**********************!*\ 461 | !*** ./src/utils.js ***! 462 | \**********************/ 463 | /*! exports provided: getSymbolInstances, onlyUnique, iterativeGapFilling, createLabel, createTextField, createDropdown, createCheckbox, getValFromLayerName, renameLayer, isVerticalBarchart, getBarHeight */ 464 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 465 | 466 | "use strict"; 467 | __webpack_require__.r(__webpack_exports__); 468 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getSymbolInstances", function() { return getSymbolInstances; }); 469 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onlyUnique", function() { return onlyUnique; }); 470 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "iterativeGapFilling", function() { return iterativeGapFilling; }); 471 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createLabel", function() { return createLabel; }); 472 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createTextField", function() { return createTextField; }); 473 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createDropdown", function() { return createDropdown; }); 474 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createCheckbox", function() { return createCheckbox; }); 475 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getValFromLayerName", function() { return getValFromLayerName; }); 476 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renameLayer", function() { return renameLayer; }); 477 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isVerticalBarchart", function() { return isVerticalBarchart; }); 478 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBarHeight", function() { return getBarHeight; }); 479 | function getSymbolInstances(source, symbolMaster) { 480 | // https://github.com/sonburn/ 481 | var symbolInstances = NSMutableArray.array(); 482 | source.sketchObject.pages().forEach(function (page) { 483 | var predicate = NSPredicate.predicateWithFormat('className == %@ && symbolMaster.objectID == %@', 'MSSymbolInstance', symbolMaster.sketchObject.objectID()); 484 | page.children().filteredArrayUsingPredicate(predicate).forEach(function (instance) { 485 | return symbolInstances.addObject(instance); 486 | }); 487 | }); 488 | return symbolInstances; 489 | } 490 | function onlyUnique(value, index, self) { 491 | return self.indexOf(value) === index; 492 | } 493 | function iterativeGapFilling(array, length) { 494 | var newArray = []; 495 | 496 | for (var i = 0; i < length; i++) { 497 | var loop = Math.floor(i / array.length); 498 | var index = i - loop * array.length; 499 | newArray.push(array[index]); 500 | } 501 | 502 | return newArray; 503 | } 504 | /**********************/ 505 | 506 | /* POPUP */ 507 | 508 | /**********************/ 509 | 510 | /* 511 | Utils from Marc Bouchenoire 512 | for easier UI design 513 | https://github.com/bouchenoiremarc 514 | */ 515 | 516 | function createLabel(text, fontSize, bold, frame, opacity) { 517 | var label = NSTextField.alloc().initWithFrame(frame); 518 | label.setStringValue(text); 519 | label.setFont(bold ? NSFont.boldSystemFontOfSize(fontSize) : NSFont.systemFontOfSize(fontSize)); 520 | label.setBezeled(false); 521 | label.setDrawsBackground(false); 522 | label.setEditable(false); 523 | label.setSelectable(false); 524 | if (opacity) label.setAlphaValue(opacity); 525 | return label; 526 | } 527 | function createTextField(value, placeholder, frame) { 528 | var textfield = NSTextField.alloc().initWithFrame(frame); 529 | textfield.cell().setWraps(false); 530 | textfield.cell().setScrollable(true); 531 | textfield.setStringValue(value); 532 | if (placeholder) textfield.setPlaceholderString(placeholder); 533 | return textfield; 534 | } 535 | function createDropdown(values, frame) { 536 | var dropdown = NSPopUpButton.alloc().initWithFrame(frame); 537 | dropdown.addItemsWithTitles(values); 538 | return dropdown; 539 | } 540 | function createCheckbox(text, checked, frame) { 541 | checked = checked == false ? NSOffState : NSOnState; 542 | var checkbox = NSButton.alloc().initWithFrame(frame); 543 | checkbox.setButtonType(NSSwitchButton); 544 | checkbox.setBezelStyle(0); 545 | checkbox.setTitle(text); 546 | checkbox.setState(checked); 547 | return checkbox; 548 | } 549 | /**********************/ 550 | 551 | /* VAL IN LAYER NAME */ 552 | 553 | /**********************/ 554 | 555 | function getValFromLayerName(name) { 556 | var a = name.split("{:"); 557 | 558 | if (a.length == 1) { 559 | return false; 560 | } 561 | 562 | var b = a[1].split(":}"); 563 | var val = parseFloat(b[0]); 564 | 565 | if (isNaN(val)) { 566 | return false; 567 | } 568 | 569 | return val; 570 | } 571 | function renameLayer(name, newVal) { 572 | var a = name.split("{:"); 573 | var newName = name + " {:" + newVal + ":}"; 574 | 575 | if (a.length > 1) { 576 | var b = a[1].split(":}"); 577 | 578 | if (b.length == 1) { 579 | return newName; 580 | } 581 | 582 | var newName = a[0] + "{:" + newVal + ":}" + b[1]; 583 | } 584 | 585 | return newName; 586 | } 587 | /**********************/ 588 | 589 | /* BARCHART */ 590 | 591 | /**********************/ 592 | 593 | function isVerticalBarchart(arr) { 594 | // arr needs to be doc.selectedLayers 595 | var isVertical = true; 596 | 597 | if (arr.layers.length >= 2 && arr.layers[0].frame.y != arr.layers[1].frame.y) { 598 | // It's horizontal if 599 | // 1. First two bars share same x value (works for positive values) 600 | if (arr.layers[0].frame.x == arr.layers[1].frame.x) { 601 | isVertical = false; 602 | } // 2. Same y-baseline (works if first value is negative) 603 | // and they share same height 604 | // ! Needs check if first / second val is negative 605 | else if (arr.layers[0].frame.x + arr.layers[0].frame.width == arr.layers[1].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height) { 606 | isVertical = false; 607 | } else if (arr.layers[1].frame.x + arr.layers[1].frame.width == arr.layers[0].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height) { 608 | isVertical = false; 609 | } 610 | } 611 | 612 | return isVertical; 613 | } 614 | /**********************/ 615 | 616 | /* NON-RANDO BARCHART */ 617 | 618 | /**********************/ 619 | 620 | function getBarHeight(arr, isVertical) { 621 | // arr needs to be doc.selectedLayers 622 | var barLength_str = ""; 623 | 624 | for (var i = 0; i < arr.layers.length; i++) { 625 | var thisLength = undefined; 626 | 627 | if (isVertical) { 628 | thisLength = arr.layers[i].frame.height.toFixed(2); // reduce to 2 decimals 629 | } else { 630 | thisLength = arr.layers[i].frame.width.toFixed(2); // reduce to 2 decimals 631 | } 632 | 633 | thisLength = parseFloat(thisLength); // to remove decimals from integers 634 | 635 | if (i == 0) { 636 | barLength_str = "" + thisLength; 637 | } else { 638 | barLength_str = barLength_str + "," + thisLength; 639 | } 640 | } 641 | 642 | return barLength_str; 643 | } 644 | 645 | /***/ }), 646 | 647 | /***/ "sketch": 648 | /*!*************************!*\ 649 | !*** external "sketch" ***! 650 | \*************************/ 651 | /*! no static exports found */ 652 | /***/ (function(module, exports) { 653 | 654 | module.exports = require("sketch"); 655 | 656 | /***/ }) 657 | 658 | /******/ }); 659 | if (key === 'default' && typeof exports === 'function') { 660 | exports(context); 661 | } else { 662 | exports[key](context); 663 | } 664 | } 665 | that['onRun'] = __skpm_run.bind(this, 'default') 666 | 667 | //# sourceMappingURL=barchart.js.map -------------------------------------------------------------------------------- /chippen-charts.sketchplugin/Contents/Sketch/cliptexttosymbol.js: -------------------------------------------------------------------------------- 1 | var that = this; 2 | function __skpm_run (key, context) { 3 | that.context = context; 4 | 5 | var exports = 6 | /******/ (function(modules) { // webpackBootstrap 7 | /******/ // The module cache 8 | /******/ var installedModules = {}; 9 | /******/ 10 | /******/ // The require function 11 | /******/ function __webpack_require__(moduleId) { 12 | /******/ 13 | /******/ // Check if module is in cache 14 | /******/ if(installedModules[moduleId]) { 15 | /******/ return installedModules[moduleId].exports; 16 | /******/ } 17 | /******/ // Create a new module (and put it into the cache) 18 | /******/ var module = installedModules[moduleId] = { 19 | /******/ i: moduleId, 20 | /******/ l: false, 21 | /******/ exports: {} 22 | /******/ }; 23 | /******/ 24 | /******/ // Execute the module function 25 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 26 | /******/ 27 | /******/ // Flag the module as loaded 28 | /******/ module.l = true; 29 | /******/ 30 | /******/ // Return the exports of the module 31 | /******/ return module.exports; 32 | /******/ } 33 | /******/ 34 | /******/ 35 | /******/ // expose the modules object (__webpack_modules__) 36 | /******/ __webpack_require__.m = modules; 37 | /******/ 38 | /******/ // expose the module cache 39 | /******/ __webpack_require__.c = installedModules; 40 | /******/ 41 | /******/ // define getter function for harmony exports 42 | /******/ __webpack_require__.d = function(exports, name, getter) { 43 | /******/ if(!__webpack_require__.o(exports, name)) { 44 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 45 | /******/ } 46 | /******/ }; 47 | /******/ 48 | /******/ // define __esModule on exports 49 | /******/ __webpack_require__.r = function(exports) { 50 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 51 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 52 | /******/ } 53 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 54 | /******/ }; 55 | /******/ 56 | /******/ // create a fake namespace object 57 | /******/ // mode & 1: value is a module id, require it 58 | /******/ // mode & 2: merge all properties of value into the ns 59 | /******/ // mode & 4: return value when already ns object 60 | /******/ // mode & 8|1: behave like require 61 | /******/ __webpack_require__.t = function(value, mode) { 62 | /******/ if(mode & 1) value = __webpack_require__(value); 63 | /******/ if(mode & 8) return value; 64 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 65 | /******/ var ns = Object.create(null); 66 | /******/ __webpack_require__.r(ns); 67 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 68 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 69 | /******/ return ns; 70 | /******/ }; 71 | /******/ 72 | /******/ // getDefaultExport function for compatibility with non-harmony modules 73 | /******/ __webpack_require__.n = function(module) { 74 | /******/ var getter = module && module.__esModule ? 75 | /******/ function getDefault() { return module['default']; } : 76 | /******/ function getModuleExports() { return module; }; 77 | /******/ __webpack_require__.d(getter, 'a', getter); 78 | /******/ return getter; 79 | /******/ }; 80 | /******/ 81 | /******/ // Object.prototype.hasOwnProperty.call 82 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 83 | /******/ 84 | /******/ // __webpack_public_path__ 85 | /******/ __webpack_require__.p = ""; 86 | /******/ 87 | /******/ 88 | /******/ // Load entry module and return exports 89 | /******/ return __webpack_require__(__webpack_require__.s = "./src/cliptexttosymbol.js"); 90 | /******/ }) 91 | /************************************************************************/ 92 | /******/ ({ 93 | 94 | /***/ "./src/cliptexttosymbol.js": 95 | /*!*********************************!*\ 96 | !*** ./src/cliptexttosymbol.js ***! 97 | \*********************************/ 98 | /*! exports provided: default */ 99 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 100 | 101 | "use strict"; 102 | __webpack_require__.r(__webpack_exports__); 103 | /* harmony import */ var sketch__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sketch */ "sketch"); 104 | /* harmony import */ var sketch__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sketch__WEBPACK_IMPORTED_MODULE_0__); 105 | /* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils.js */ "./src/utils.js"); 106 | 107 | // documentation: https://developer.sketchapp.com/reference/api/ 108 | // https://github.com/sonburn/symbol-instance-locator/blob/master/Symbol%20Instance%20Locator.sketchplugin/Contents/Sketch/script.js 109 | 110 | var symbolOverrideLayers; 111 | /* harmony default export */ __webpack_exports__["default"] = (function () { 112 | log('~~ Run Chippen charts ~~'); 113 | var doc = sketch__WEBPACK_IMPORTED_MODULE_0___default.a.getSelectedDocument(); 114 | var selectedLayers = doc.selectedLayers; 115 | 116 | var pluginName = __command.pluginBundle().name(); 117 | 118 | if (selectedLayers.layers.length == 0) { 119 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.alert(pluginName, 'Please select at least 1 layer that contains a symbol override.'); 120 | return false; 121 | } 122 | /* 123 | CLIPBOARD 124 | */ 125 | 126 | 127 | var newLineSeparator = "\n"; 128 | var sep = newLineSeparator; 129 | var pasteBoard = NSPasteboard.generalPasteboard(); // Turn a data in the string type 130 | 131 | var stringFromPasteBoard = pasteBoard.stringForType(NSPasteboardTypeString); 132 | 133 | if (stringFromPasteBoard == null) { 134 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.alert(pluginName, 'Your clipboard does not seem to be just text. Try again with only lines of text.'); 135 | return false; 136 | } 137 | 138 | var pasteboardLines = stringFromPasteBoard.split(newLineSeparator); 139 | /* 140 | SELECTED SYMBOLS 141 | */ 142 | 143 | var selectedSymbols = selectedLayers.layers.filter(function (layer) { 144 | return layer.type == "SymbolInstance" || layer.type == "SymbolMaster"; 145 | }); 146 | 147 | if (selectedSymbols.length == 0) { 148 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.alert(pluginName, 'Please select at least 1 layer that contains a symbol.'); 149 | return false; 150 | } 151 | 152 | var symbolsWithOverrides = selectedSymbols.filter(function (symbol) { 153 | return symbol.overrides.length != 0; 154 | }); 155 | 156 | if (symbolsWithOverrides.length == 0) { 157 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.alert(pluginName, 'Please select at least 1 symbol that contains a text override.'); 158 | return false; 159 | } 160 | 161 | var symbolsIDs = symbolsWithOverrides.map(function (symbol) { 162 | return symbol.symbolId; 163 | }); 164 | var uniqueSymbolIDs = symbolsIDs.filter(_utils_js__WEBPACK_IMPORTED_MODULE_1__["onlyUnique"]); 165 | 166 | if (uniqueSymbolIDs.length > 1) { 167 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.alert(pluginName, "Please use only symbols of the same kind. Maybe you want to try to use only symbols like \"".concat(symbolsWithOverrides[0].name, "\".")); 168 | return false; 169 | } 170 | /* 171 | Informative Text 172 | */ 173 | 174 | 175 | var warningMsg = ""; 176 | 177 | if (pasteboardLines.length > symbolsWithOverrides.length) { 178 | warningMsg = "There are more lines of text in the clipboard (".concat(pasteboardLines.length, ") than there are symbols in the selection (").concat(symbolsWithOverrides.length, "). That means not all content from clipboard will be used."); 179 | } else if (symbolsWithOverrides.length > pasteboardLines.length) { 180 | warningMsg = "There are more symbols selected (".concat(symbolsWithOverrides.length, ") than there are lines of text in the clipboard (").concat(pasteboardLines.length, "). Clipboard text will be repeated in the overflow symbols."); 181 | } 182 | 183 | var informativeText = ""; 184 | 185 | if (warningMsg != "") { 186 | informativeText = "⚠️ Watch out! - " + warningMsg + " \n\nYou can go ahead but outcomes might not be as expected."; 187 | } else { 188 | informativeText = "You are about to alter ".concat(symbolsWithOverrides.length, " symbol overrides using text from the clipboard."); 189 | } 190 | /* 191 | Dropdown options 192 | */ 193 | 194 | 195 | var stringvalueOverrides = symbolsWithOverrides[0].overrides.filter(function (override) { 196 | return override.property == 'stringValue'; 197 | }); 198 | var overrideOptions = stringvalueOverrides.map(function (override, index) { 199 | return "Override " + (parseInt(index) + 1) + " (" + override.value + ")"; 200 | }); 201 | /* 202 | Setup the window 203 | */ 204 | 205 | var alert = COSAlertWindow.new(); 206 | alert.setMessageText("Paste clipboard text into symbol overrides"); 207 | alert.addButtonWithTitle("Run"); 208 | alert.addButtonWithTitle("Cancel"); 209 | alert.setInformativeText(informativeText); 210 | /* 211 | Input 212 | */ 213 | // OVERRIDE DROPDOWN 214 | 215 | var alert_width = 280; 216 | var overrideOptions_label = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("What override shall it be? ", 12, true, NSMakeRect(0, 0, alert_width, 16)); 217 | var overrideOptions_dropdown = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createDropdown"])(overrideOptions, NSMakeRect(-2, -1, 280, 24)); 218 | 219 | if (overrideOptions.length > 1) { 220 | alert.addAccessoryView(overrideOptions_label); 221 | alert.addAccessoryView(overrideOptions_dropdown); 222 | } // REVERSE CHECKBOX 223 | 224 | 225 | var reverse_checkbox = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createCheckbox"])("Reverse order of clipboard text", false, NSMakeRect(-2, -1, 280, 24)); 226 | 227 | if (pasteboardLines.length > 1) { 228 | alert.addAccessoryView(reverse_checkbox); 229 | } 230 | /* 231 | Response 232 | */ 233 | 234 | 235 | var overrideIndex; 236 | var responseCode = alert.runModal(); 237 | 238 | if (responseCode == 1000) { 239 | // Dropdown input 240 | var dropddownIndex = overrideOptions_dropdown.indexOfSelectedItem(); 241 | var overrideID = stringvalueOverrides[dropddownIndex].id; // Mapping index of dropdown to index of overrides. 242 | // Dropdown does only include stringValue overrides 243 | // and no symbolID overrides (top level of nested symbol). 244 | // That's why the length can differ. 245 | 246 | for (var i = 0; i < symbolsWithOverrides[0].overrides.length; i++) { 247 | if (symbolsWithOverrides[0].overrides[i].id == overrideID) { 248 | overrideIndex = i; 249 | } 250 | } // Checkbox input 251 | 252 | 253 | var reverse = false; 254 | 255 | if (Number(reverse_checkbox.state()) == 1) { 256 | reverse = true; 257 | } 258 | } else { 259 | // 1001 260 | return false; 261 | } 262 | /* 263 | OVERRIDE 264 | */ 265 | 266 | 267 | var clip = pasteboardLines; 268 | 269 | if (reverse) { 270 | clip.reverse(); 271 | } 272 | 273 | if (symbolsWithOverrides.length > clip.length) { 274 | var clip_filled = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["iterativeGapFilling"])(clip, symbolsWithOverrides.length); 275 | clip = clip_filled; 276 | } 277 | 278 | for (var i = 0; i < symbolsWithOverrides.length; i++) { 279 | symbolsWithOverrides[i].overrides[overrideIndex].value = clip[i]; 280 | } 281 | 282 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.message("Text from clipboard was pasted into ".concat(symbolsWithOverrides.length, " symbols")); 283 | }); 284 | 285 | /***/ }), 286 | 287 | /***/ "./src/utils.js": 288 | /*!**********************!*\ 289 | !*** ./src/utils.js ***! 290 | \**********************/ 291 | /*! exports provided: getSymbolInstances, onlyUnique, iterativeGapFilling, createLabel, createTextField, createDropdown, createCheckbox, getValFromLayerName, renameLayer, isVerticalBarchart, getBarHeight */ 292 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 293 | 294 | "use strict"; 295 | __webpack_require__.r(__webpack_exports__); 296 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getSymbolInstances", function() { return getSymbolInstances; }); 297 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onlyUnique", function() { return onlyUnique; }); 298 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "iterativeGapFilling", function() { return iterativeGapFilling; }); 299 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createLabel", function() { return createLabel; }); 300 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createTextField", function() { return createTextField; }); 301 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createDropdown", function() { return createDropdown; }); 302 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createCheckbox", function() { return createCheckbox; }); 303 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getValFromLayerName", function() { return getValFromLayerName; }); 304 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renameLayer", function() { return renameLayer; }); 305 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isVerticalBarchart", function() { return isVerticalBarchart; }); 306 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBarHeight", function() { return getBarHeight; }); 307 | function getSymbolInstances(source, symbolMaster) { 308 | // https://github.com/sonburn/ 309 | var symbolInstances = NSMutableArray.array(); 310 | source.sketchObject.pages().forEach(function (page) { 311 | var predicate = NSPredicate.predicateWithFormat('className == %@ && symbolMaster.objectID == %@', 'MSSymbolInstance', symbolMaster.sketchObject.objectID()); 312 | page.children().filteredArrayUsingPredicate(predicate).forEach(function (instance) { 313 | return symbolInstances.addObject(instance); 314 | }); 315 | }); 316 | return symbolInstances; 317 | } 318 | function onlyUnique(value, index, self) { 319 | return self.indexOf(value) === index; 320 | } 321 | function iterativeGapFilling(array, length) { 322 | var newArray = []; 323 | 324 | for (var i = 0; i < length; i++) { 325 | var loop = Math.floor(i / array.length); 326 | var index = i - loop * array.length; 327 | newArray.push(array[index]); 328 | } 329 | 330 | return newArray; 331 | } 332 | /**********************/ 333 | 334 | /* POPUP */ 335 | 336 | /**********************/ 337 | 338 | /* 339 | Utils from Marc Bouchenoire 340 | for easier UI design 341 | https://github.com/bouchenoiremarc 342 | */ 343 | 344 | function createLabel(text, fontSize, bold, frame, opacity) { 345 | var label = NSTextField.alloc().initWithFrame(frame); 346 | label.setStringValue(text); 347 | label.setFont(bold ? NSFont.boldSystemFontOfSize(fontSize) : NSFont.systemFontOfSize(fontSize)); 348 | label.setBezeled(false); 349 | label.setDrawsBackground(false); 350 | label.setEditable(false); 351 | label.setSelectable(false); 352 | if (opacity) label.setAlphaValue(opacity); 353 | return label; 354 | } 355 | function createTextField(value, placeholder, frame) { 356 | var textfield = NSTextField.alloc().initWithFrame(frame); 357 | textfield.cell().setWraps(false); 358 | textfield.cell().setScrollable(true); 359 | textfield.setStringValue(value); 360 | if (placeholder) textfield.setPlaceholderString(placeholder); 361 | return textfield; 362 | } 363 | function createDropdown(values, frame) { 364 | var dropdown = NSPopUpButton.alloc().initWithFrame(frame); 365 | dropdown.addItemsWithTitles(values); 366 | return dropdown; 367 | } 368 | function createCheckbox(text, checked, frame) { 369 | checked = checked == false ? NSOffState : NSOnState; 370 | var checkbox = NSButton.alloc().initWithFrame(frame); 371 | checkbox.setButtonType(NSSwitchButton); 372 | checkbox.setBezelStyle(0); 373 | checkbox.setTitle(text); 374 | checkbox.setState(checked); 375 | return checkbox; 376 | } 377 | /**********************/ 378 | 379 | /* VAL IN LAYER NAME */ 380 | 381 | /**********************/ 382 | 383 | function getValFromLayerName(name) { 384 | var a = name.split("{:"); 385 | 386 | if (a.length == 1) { 387 | return false; 388 | } 389 | 390 | var b = a[1].split(":}"); 391 | var val = parseFloat(b[0]); 392 | 393 | if (isNaN(val)) { 394 | return false; 395 | } 396 | 397 | return val; 398 | } 399 | function renameLayer(name, newVal) { 400 | var a = name.split("{:"); 401 | var newName = name + " {:" + newVal + ":}"; 402 | 403 | if (a.length > 1) { 404 | var b = a[1].split(":}"); 405 | 406 | if (b.length == 1) { 407 | return newName; 408 | } 409 | 410 | var newName = a[0] + "{:" + newVal + ":}" + b[1]; 411 | } 412 | 413 | return newName; 414 | } 415 | /**********************/ 416 | 417 | /* BARCHART */ 418 | 419 | /**********************/ 420 | 421 | function isVerticalBarchart(arr) { 422 | // arr needs to be doc.selectedLayers 423 | var isVertical = true; 424 | 425 | if (arr.layers.length >= 2 && arr.layers[0].frame.y != arr.layers[1].frame.y) { 426 | // It's horizontal if 427 | // 1. First two bars share same x value (works for positive values) 428 | if (arr.layers[0].frame.x == arr.layers[1].frame.x) { 429 | isVertical = false; 430 | } // 2. Same y-baseline (works if first value is negative) 431 | // and they share same height 432 | // ! Needs check if first / second val is negative 433 | else if (arr.layers[0].frame.x + arr.layers[0].frame.width == arr.layers[1].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height) { 434 | isVertical = false; 435 | } else if (arr.layers[1].frame.x + arr.layers[1].frame.width == arr.layers[0].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height) { 436 | isVertical = false; 437 | } 438 | } 439 | 440 | return isVertical; 441 | } 442 | /**********************/ 443 | 444 | /* NON-RANDO BARCHART */ 445 | 446 | /**********************/ 447 | 448 | function getBarHeight(arr, isVertical) { 449 | // arr needs to be doc.selectedLayers 450 | var barLength_str = ""; 451 | 452 | for (var i = 0; i < arr.layers.length; i++) { 453 | var thisLength = undefined; 454 | 455 | if (isVertical) { 456 | thisLength = arr.layers[i].frame.height.toFixed(2); // reduce to 2 decimals 457 | } else { 458 | thisLength = arr.layers[i].frame.width.toFixed(2); // reduce to 2 decimals 459 | } 460 | 461 | thisLength = parseFloat(thisLength); // to remove decimals from integers 462 | 463 | if (i == 0) { 464 | barLength_str = "" + thisLength; 465 | } else { 466 | barLength_str = barLength_str + "," + thisLength; 467 | } 468 | } 469 | 470 | return barLength_str; 471 | } 472 | 473 | /***/ }), 474 | 475 | /***/ "sketch": 476 | /*!*************************!*\ 477 | !*** external "sketch" ***! 478 | \*************************/ 479 | /*! no static exports found */ 480 | /***/ (function(module, exports) { 481 | 482 | module.exports = require("sketch"); 483 | 484 | /***/ }) 485 | 486 | /******/ }); 487 | if (key === 'default' && typeof exports === 'function') { 488 | exports(context); 489 | } else { 490 | exports[key](context); 491 | } 492 | } 493 | that['onRun'] = __skpm_run.bind(this, 'default') 494 | 495 | //# sourceMappingURL=cliptexttosymbol.js.map -------------------------------------------------------------------------------- /chippen-charts.sketchplugin/Contents/Sketch/cliptexttosymbol.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap","webpack://exports/./src/cliptexttosymbol.js","webpack://exports/./src/utils.js","webpack://exports/external \"sketch\""],"names":["symbolOverrideLayers","log","doc","sketch","getSelectedDocument","selectedLayers","pluginName","__command","pluginBundle","name","layers","length","UI","alert","newLineSeparator","sep","pasteBoard","NSPasteboard","generalPasteboard","stringFromPasteBoard","stringForType","NSPasteboardTypeString","pasteboardLines","split","selectedSymbols","filter","layer","type","symbolsWithOverrides","symbol","overrides","symbolsIDs","map","symbolId","uniqueSymbolIDs","onlyUnique","warningMsg","informativeText","stringvalueOverrides","override","property","overrideOptions","index","parseInt","value","COSAlertWindow","new","setMessageText","addButtonWithTitle","setInformativeText","alert_width","overrideOptions_label","createLabel","NSMakeRect","overrideOptions_dropdown","createDropdown","addAccessoryView","reverse_checkbox","createCheckbox","overrideIndex","responseCode","runModal","dropddownIndex","indexOfSelectedItem","overrideID","id","i","reverse","Number","state","clip","clip_filled","iterativeGapFilling","message","getSymbolInstances","source","symbolMaster","symbolInstances","NSMutableArray","array","sketchObject","pages","forEach","page","predicate","NSPredicate","predicateWithFormat","objectID","children","filteredArrayUsingPredicate","instance","addObject","self","indexOf","newArray","loop","Math","floor","push","text","fontSize","bold","frame","opacity","label","NSTextField","alloc","initWithFrame","setStringValue","setFont","NSFont","boldSystemFontOfSize","systemFontOfSize","setBezeled","setDrawsBackground","setEditable","setSelectable","setAlphaValue","createTextField","placeholder","textfield","cell","setWraps","setScrollable","setPlaceholderString","values","dropdown","NSPopUpButton","addItemsWithTitles","checked","NSOffState","NSOnState","checkbox","NSButton","setButtonType","NSSwitchButton","setBezelStyle","setTitle","setState","getValFromLayerName","a","b","val","parseFloat","isNaN","renameLayer","newVal","newName","isVerticalBarchart","arr","isVertical","y","x","width","height","getBarHeight","barLength_str","thisLength","undefined","toFixed"],"mappings":"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","file":"cliptexttosymbol.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/cliptexttosymbol.js\");\n","import sketch from 'sketch'\nimport { onlyUnique, iterativeGapFilling, createLabel, createDropdown, createCheckbox } from \"./utils.js\";\n// documentation: https://developer.sketchapp.com/reference/api/\n// https://github.com/sonburn/symbol-instance-locator/blob/master/Symbol%20Instance%20Locator.sketchplugin/Contents/Sketch/script.js\n\nvar symbolOverrideLayers;\n\nexport default function() {\n\tlog('~~ Run Chippen charts ~~')\n\n\tconst doc = sketch.getSelectedDocument()\n\tconst selectedLayers = doc.selectedLayers\n\n\tvar pluginName = __command.pluginBundle().name();\n\n\tif(selectedLayers.layers.length == 0) {\n\t\tsketch.UI.alert(pluginName,'Please select at least 1 layer that contains a symbol override.');\n\n\t\treturn false;\n\t}\n\t\t\n\t\n\t/*\n\t\tCLIPBOARD\n\t*/\n\n\tvar newLineSeparator = \"\\n\";\n\tvar sep = newLineSeparator;\n\n\tvar pasteBoard = NSPasteboard.generalPasteboard();\n // Turn a data in the string type\n var stringFromPasteBoard = pasteBoard.stringForType(NSPasteboardTypeString);\n\n if(stringFromPasteBoard == null){\n \tsketch.UI.alert(pluginName,'Your clipboard does not seem to be just text. Try again with only lines of text.');\n \treturn false;\n }\n\n var pasteboardLines = stringFromPasteBoard.split(newLineSeparator)\n \n\n\t/*\n\t\tSELECTED SYMBOLS\n\t*/\n\n\tconst selectedSymbols = selectedLayers.layers.filter(layer => layer.type == \"SymbolInstance\" || layer.type == \"SymbolMaster\")\n\tif (selectedSymbols.length == 0) {\n\t\tsketch.UI.alert(pluginName,'Please select at least 1 layer that contains a symbol.');\n\t\treturn false;\n\t}\n\t\n\tconst symbolsWithOverrides = selectedSymbols.filter(symbol => symbol.overrides.length != 0)\n\tif (symbolsWithOverrides.length == 0) {\n\t\tsketch.UI.alert(pluginName,'Please select at least 1 symbol that contains a text override.');\n\t\treturn false;\n\t}\n\n\tconst symbolsIDs = symbolsWithOverrides.map(symbol => {\n\t\treturn symbol.symbolId\n\t})\n\n\tconst uniqueSymbolIDs = symbolsIDs.filter( onlyUnique ); \n\t\n\tif(uniqueSymbolIDs.length > 1){\n\t\tsketch.UI.alert(pluginName,`Please use only symbols of the same kind. Maybe you want to try to use only symbols like \"${symbolsWithOverrides[0].name}\".`);\n\t\treturn false;\n\t}\n\n\n\t/*\n\t\tInformative Text\n\t*/\n\n\tvar warningMsg = \"\"\n\tif(pasteboardLines.length > symbolsWithOverrides.length){\n\t\twarningMsg = `There are more lines of text in the clipboard (${pasteboardLines.length}) than there are symbols in the selection (${symbolsWithOverrides.length}). That means not all content from clipboard will be used.`\n\t}else if(symbolsWithOverrides.length > pasteboardLines.length){\n\t\twarningMsg = `There are more symbols selected (${symbolsWithOverrides.length}) than there are lines of text in the clipboard (${pasteboardLines.length}). Clipboard text will be repeated in the overflow symbols.`\n\t}\n\n\tvar informativeText = \"\"\n\tif(warningMsg != \"\"){\n\t\tinformativeText = \"⚠️ Watch out! - \" + warningMsg + \" \\n\\nYou can go ahead but outcomes might not be as expected.\"\n\t}else{\n\t\tinformativeText = `You are about to alter ${symbolsWithOverrides.length} symbol overrides using text from the clipboard.`\n\t}\n\n\n\t/*\n\t\tDropdown options\n\t*/\n\n\tconst stringvalueOverrides = symbolsWithOverrides[0].overrides.filter(override => override.property == 'stringValue')\n\t\n\tconst overrideOptions = stringvalueOverrides.map((override, index) => {\n\t\treturn \"Override \" + (parseInt(index)+1) + \" (\" + override.value + \")\"\n\t})\n\t\n\n\t/*\n\t\tSetup the window\n \t*/\n\t\n\tvar alert = COSAlertWindow.new()\n\talert.setMessageText(\"Paste clipboard text into symbol overrides\")\n\talert.addButtonWithTitle(\"Run\")\n\talert.addButtonWithTitle(\"Cancel\")\n\talert.setInformativeText(informativeText)\n\t\n\n\t/*\n\t\tInput\n \t*/\n\n \t// OVERRIDE DROPDOWN\n \tvar alert_width = 280;\n\tvar overrideOptions_label = createLabel(\"What override shall it be? \", 12, true, NSMakeRect(0, 0, alert_width, 16));\n \tvar overrideOptions_dropdown = createDropdown(overrideOptions, NSMakeRect(-2, -1, 280, 24));\n\n \tif(overrideOptions.length>1){\n \t\talert.addAccessoryView(overrideOptions_label);\n \t\talert.addAccessoryView(overrideOptions_dropdown);\t\n \t}\n\n \t// REVERSE CHECKBOX\n \tvar reverse_checkbox = createCheckbox(\"Reverse order of clipboard text\", false, NSMakeRect(-2, -1, 280, 24));\n \t\n \tif(pasteboardLines.length>1){\n \t\talert.addAccessoryView(reverse_checkbox);\n \t}\n \n\n \t/*\n\t\tResponse\n\t*/\n\n\tvar overrideIndex;\n\tvar responseCode = alert.runModal();\n\t\n\tif(responseCode == 1000){\n\t\t// Dropdown input\n\t\tvar dropddownIndex = overrideOptions_dropdown.indexOfSelectedItem();\n\t\tvar overrideID = stringvalueOverrides[dropddownIndex].id;\n\n\t\t// Mapping index of dropdown to index of overrides.\n\t\t// Dropdown does only include stringValue overrides\n\t\t// and no symbolID overrides (top level of nested symbol).\n\t\t// That's why the length can differ.\n\t\tfor(var i=0; i clip.length){\n\t\tvar clip_filled = iterativeGapFilling(clip, symbolsWithOverrides.length)\n\t\tclip = clip_filled;\n\t}\n\n\tfor(var i=0; i symbolInstances.addObject(instance));\n\t});\n\n\treturn symbolInstances;\n}\n\nexport function onlyUnique(value, index, self) { \n return self.indexOf(value) === index;\n}\n\nexport function iterativeGapFilling(array, length){\n\tvar newArray = [];\n\tfor(var i=0; i 1){\n\t\tvar b = a[1].split(\":}\");\n\t\tif(b.length == 1){return newName;}\n\t\tvar newName = a[0] + \"{:\" + newVal + \":}\" + b[1];\n\t}\n\n\treturn newName\n}\n\n\n/**********************/\n/* BARCHART */\n/**********************/\n\nexport function isVerticalBarchart(arr){\n\t// arr needs to be doc.selectedLayers\n\tvar isVertical = true\n\tif(arr.layers.length >= 2 && arr.layers[0].frame.y != arr.layers[1].frame.y){\n\t\t// It's horizontal if\n\t\t// 1. First two bars share same x value (works for positive values)\n\t\tif(arr.layers[0].frame.x == arr.layers[1].frame.x){\n\t\t\tisVertical = false;\n\t\t}\n\t\t// 2. Same y-baseline (works if first value is negative) \n\t\t// and they share same height\n\t\t// ! Needs check if first / second val is negative\n\t\telse if(arr.layers[0].frame.x + arr.layers[0].frame.width == arr.layers[1].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height){\n\t\t\tisVertical = false;\t\n\t\t}\n\t\telse if(arr.layers[1].frame.x + arr.layers[1].frame.width == arr.layers[0].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height){\n\t\t\tisVertical = false;\t\n\t\t}\n\t}\n\treturn isVertical\n}\n\n\n/**********************/\n/* NON-RANDO BARCHART */\n/**********************/\n\nexport function getBarHeight(arr, isVertical){\n\t// arr needs to be doc.selectedLayers\n\tvar barLength_str = \"\"\n\t\n\tfor(var i=0; i= 0) { 177 | baseLine = selectedLayers.layers[0].frame.x; 178 | } else if (firstBarVal < 0) { 179 | baseLine = selectedLayers.layers[0].frame.x + Math.abs(firstBarVal); 180 | } 181 | } 182 | 183 | for (var i = 0; i < selectedLayers.layers.length; i++) { 184 | var newLength = 1; 185 | 186 | if (response.numbers[i] == undefined) { 187 | newLength = undefined; // no bar will be changed and no error will be thrown (it's undefined by default anyway) 188 | } else { 189 | if (response.scaleType == 1) { 190 | // Multiplier 191 | newLength = response.numbers[i] * response.scaleValue; 192 | } else if (response.scaleType == 2) { 193 | // Set max height 194 | newLength = response.numbers[i] * response.scaleValue / response.max; 195 | } else { 196 | // none 197 | newLength = response.numbers[i]; 198 | } 199 | } // Length can't be zero 200 | 201 | 202 | if (newLength == 0) { 203 | newLength = 0.5; 204 | response.numbers[i] = 0.5; 205 | } // Change Width / Height 206 | 207 | 208 | if (isVertical) { 209 | // Change height 210 | selectedLayers.layers[i].frame.height = Math.abs(newLength); // Move to baseline 211 | 212 | if (newLength > 0) { 213 | // Reposition bars with positive values 214 | selectedLayers.layers[i].frame.y = baseLine - Math.abs(newLength); 215 | } else { 216 | // Reposition bars with negative values 217 | selectedLayers.layers[i].frame.y = baseLine; 218 | } 219 | } else { 220 | // Reset position, just in case 221 | selectedLayers.layers[i].frame.x = baseLine; // Change width 222 | 223 | selectedLayers.layers[i].frame.width = Math.abs(newLength); // Reposition bars with negative values 224 | 225 | if (newLength < 0) { 226 | selectedLayers.layers[i].frame.x = selectedLayers.layers[i].frame.x - Math.abs(newLength); 227 | } 228 | } // Rename layer 229 | // Data value will be added to layer name 230 | // Example: Rectangle ==> Rectangle {:12:} 231 | 232 | 233 | selectedLayers.layers[i].name = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["renameLayer"])(selectedLayers.layers[i].name, response.numbers[i]); 234 | } // Notification 235 | // Alert in case number of selected layers 236 | // does not match amount of numbers 237 | 238 | 239 | if (alert_diff != 0) { 240 | if (alert_diff > 0) { 241 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.alert("\uD83D\uDE07 Just letting you know", "Only the first ".concat(response.numbers.length, " of your selected layer(s) have been adjusted. There weren't enough number values to adjust the last ").concat(Math.abs(alert_diff), " layer(s). Maybe check the separator options (comma, etc).")); 242 | } else if (alert_diff < 0) { 243 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.alert("\uD83D\uDE07 Just letting you know", "The last ".concat(Math.abs(alert_diff), " values weren't used as there weren't enough layer(s) selected.")); 244 | } 245 | } 246 | }); 247 | 248 | function getMinMax(arr, isVertical) { 249 | // arr needs to be doc.selectedLayers 250 | var min = 0; 251 | var max = 0; 252 | 253 | if (isVertical) { 254 | // Vertical bar chart (get minMax height) 255 | for (var i = 0; i < arr.layers.length; i++) { 256 | var thisHeight = arr.layers[i].frame.height; // Max 257 | 258 | if (thisHeight > max) { 259 | max = thisHeight; 260 | } // Min 261 | 262 | 263 | if (min == 0) { 264 | // set min at first runfirst 265 | min = max; 266 | } 267 | 268 | if (thisHeight < min) { 269 | min = thisHeight; 270 | } 271 | } 272 | } else { 273 | // Horizontal bar chart (get minMax width) 274 | for (var i = 0; i < arr.layers.length; i++) { 275 | var thisWidth = arr.layers[i].frame.width; // Max 276 | 277 | if (thisWidth > max) { 278 | max = thisWidth; 279 | } // Min 280 | 281 | 282 | if (min == 0) { 283 | // set min at first run 284 | min = max; 285 | } 286 | 287 | if (thisWidth < min) { 288 | min = thisWidth; 289 | } 290 | } 291 | } 292 | 293 | return [Math.ceil(min), Math.ceil(max)]; 294 | } 295 | 296 | function myinput() { 297 | var myMinMax = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [20, 100]; 298 | var numOfBars = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ""; 299 | var myBarHeightFromSelection = arguments.length > 2 ? arguments[2] : undefined; 300 | var my_isVertical = arguments.length > 3 ? arguments[3] : undefined; 301 | var myresponse = { 302 | code: null, 303 | max: null, 304 | forcetype: false, 305 | numbers: [], 306 | trendTypeInput: null 307 | }; 308 | 309 | if (myMinMax.length != 2 || myMinMax[0] == myMinMax[1]) { 310 | if (myMinMax[0] > 100) { 311 | myMinMax = [20, myMinMax[1]]; 312 | } else { 313 | myMinMax = [myMinMax[0], 100]; 314 | } 315 | } 316 | 317 | if (numOfBars == 0) { 318 | myresponse.code == 1001; 319 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.alert("Sorry buddy", "You need to select multiple rectangles (bars) for this plugin to work."); 320 | } 321 | 322 | if (numOfBars != 0) { 323 | if (numOfBars == 1) { 324 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.alert("Hey, just letting you know", "Most awesome results come when selecting more than 1 bar."); 325 | } // Create initial view panel 326 | 327 | 328 | var width = 260; 329 | var height = 40; // Number input 330 | 331 | var sampleNumbers = myBarHeightFromSelection; 332 | /* 333 | Setup the window 334 | */ 335 | 336 | var alert = COSAlertWindow.new(); 337 | 338 | if (numOfBars == 1) { 339 | alert.setMessageText("1 layer selected to create bar chart"); 340 | } else { 341 | alert.setMessageText("".concat(numOfBars, " layers selected to create bar chart")); 342 | } 343 | 344 | alert.addButtonWithTitle("Run"); 345 | alert.addButtonWithTitle("Cancel"); 346 | alert.setInformativeText("This is for a bar chart with specific values, rather than random numbers."); 347 | /* 348 | Input 349 | */ 350 | 351 | var alert_width = 280; 352 | var numInput_separatorOptions = ["Comma separated", "Space separated", "Tab separated (Excel row)", "Line break separated (Excel column)"]; 353 | var numInput_label = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("Paste in your number values", 12, true, NSMakeRect(0, 0, alert_width, 16)); 354 | var numInput = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createTextField"])(sampleNumbers, null, NSMakeRect(0, 0, alert_width, 25)); 355 | var numInput_separator = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createDropdown"])([numInput_separatorOptions[0], numInput_separatorOptions[1], numInput_separatorOptions[2], numInput_separatorOptions[3]], NSMakeRect(-2, -1, 170, 30)); 356 | alert.addAccessoryView(numInput_label); 357 | alert.addAccessoryView(numInput); 358 | alert.addAccessoryView(numInput_separator); 359 | /* 360 | Bar type: Vertical or horizontal 361 | */ 362 | 363 | var bartype_label = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("Vertical or horizontal?", 12, true, NSMakeRect(0, 0, alert_width, 16)); 364 | alert.addAccessoryView(bartype_label); 365 | var bartype_radio = NSView.alloc().initWithFrame(NSMakeRect(0, 0, width, 48)); 366 | var buttonFormat; 367 | buttonFormat = NSButtonCell.alloc().init(); 368 | buttonFormat.setButtonType(NSRadioButton); 369 | var matrixFormat = NSMatrix.alloc().initWithFrame_mode_prototype_numberOfRows_numberOfColumns(NSMakeRect(0, 0, 260, 48), NSRadioModeMatrix, buttonFormat, 2, 1); 370 | matrixFormat.setCellSize(CGSizeMake(260, 25)); 371 | var bartype_radio1_label = my_isVertical ? "Automatic (vertical detected)" : "Automatic (horizontal detected)"; 372 | var bartype_radio2_label = my_isVertical ? "Force horizontal" : "Force vertical"; 373 | var cells = matrixFormat.cells(); 374 | cells.objectAtIndex(0).setTitle(bartype_radio1_label); 375 | cells.objectAtIndex(1).setTitle(bartype_radio2_label); 376 | bartype_radio.addSubview(matrixFormat); 377 | alert.addAccessoryView(bartype_radio); 378 | /* 379 | Options 380 | */ 381 | 382 | var optionsView_height = 85; 383 | var optionsView = NSView.alloc().initWithFrame(NSMakeRect(0, 0, alert_width, optionsView_height)); 384 | var optionsLabel = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("Do you want to scale the values?", 12, true, NSMakeRect(0, optionsView_height - 26, alert_width, 16)); //var optionsLabel_inlineNote = createLabel("(optional)", 12, false, NSMakeRect(215, optionsView_height - 26, alert_width, 16), 0.3); 385 | 386 | var option1_textField = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createTextField"])("", "e.g. 1.5", NSMakeRect(0, optionsView_height - 60, 120, 25)); 387 | var option1_label = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("Multiply by", 12, false, NSMakeRect(0, optionsView_height - 79, 130, 16)); 388 | var option2_textField = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createTextField"])("", "e.g. " + 100, NSMakeRect(140, optionsView_height - 60, 120, 25)); // prev version showed myMinMax[1] as option 389 | 390 | var option2_label = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("or set max height (px)", 12, false, NSMakeRect(140, optionsView_height - 79, 130, 16)); //var options_info = createLabel("You have the option to define the scaling in case the supplied values don't match your desired pixel values. You can either define a multiplier or set a maximum bar height in pixel.", 11, false, NSMakeRect(0, 0, 260, 16*4)) 391 | 392 | var options_info = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("Scale data values in case the supplied numbers don't match the desired pixel values.", 11, false, NSMakeRect(0, 0, 260, 16 * 2)); 393 | optionsView.addSubview(optionsLabel); //optionsView.addSubview(optionsLabel_inlineNote); 394 | 395 | optionsView.addSubview(option1_textField); 396 | optionsView.addSubview(option1_label); 397 | optionsView.addSubview(option2_textField); 398 | optionsView.addSubview(option2_label); 399 | alert.addAccessoryView(optionsView); // alert.addAccessoryView(options_info) 400 | 401 | /* 402 | Key navigation (popup) 403 | */ 404 | 405 | alert.alert().window().setInitialFirstResponder(numInput); 406 | numInput.setNextKeyView(option1_textField); 407 | option1_textField.setNextKeyView(option2_textField); 408 | option2_textField.setNextKeyView(numInput); 409 | /* 410 | Note 411 | */ 412 | 413 | var note_line1 = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("Please make sure proportional scaling is disabled", 11, false, NSMakeRect(0, 0, alert_width + 10, 16), 0.3); 414 | alert.addAccessoryView(note_line1); 415 | /* 416 | RESPONSE 417 | */ 418 | 419 | var responseCode = alert.runModal(); 420 | 421 | if (responseCode == 1000) { 422 | myresponse.code = 1000; // OK 423 | // Separator 424 | 425 | var sep = ","; 426 | var sep_input = numInput_separator.titleOfSelectedItem(); 427 | 428 | if (sep_input == numInput_separatorOptions[1]) { 429 | sep = " "; 430 | } 431 | 432 | if (sep_input == numInput_separatorOptions[2]) { 433 | sep = "\t"; 434 | } else if (sep_input == numInput_separatorOptions[3]) { 435 | sep = "\n"; 436 | } // Numbers 437 | 438 | 439 | var numbers_str = ""; 440 | 441 | if (numInput.stringValue() == "") { 442 | numbers_str = sampleNumbers; 443 | } else { 444 | numbers_str = numInput.stringValue(); 445 | } 446 | 447 | var numbers_arr = numbers_str.split(sep); 448 | 449 | for (var i = 0; i < numbers_arr.length; i++) { 450 | myresponse.numbers.push(parseFloat(numbers_arr[i])); 451 | } // Force bar chart type 452 | 453 | 454 | var forcetype_index = matrixFormat.cells().indexOfObject(matrixFormat.selectedCell()); 455 | myresponse.forcetype = forcetype_index == 0 ? false : true; // Options 456 | 457 | if (option2_textField.stringValue() != "") { 458 | // Option 2: Set max height 459 | myresponse.scaleType = 2; 460 | myresponse.scaleValue = parseFloat(option2_textField.stringValue()); 461 | } else if (option1_textField.stringValue() != "") { 462 | // Option 1: Multiplier 463 | myresponse.scaleType = 1; 464 | myresponse.scaleValue = parseFloat(option1_textField.stringValue()); 465 | } else { 466 | myresponse.scaleType = 0; 467 | } 468 | } else { 469 | // Cancel 470 | myresponse.code = 1001; 471 | } 472 | 473 | myresponse.max = myresponse.numbers.reduce(function (a, b) { 474 | return Math.max(a, b); 475 | }); 476 | } 477 | 478 | return myresponse; 479 | } 480 | 481 | /***/ }), 482 | 483 | /***/ "./src/utils.js": 484 | /*!**********************!*\ 485 | !*** ./src/utils.js ***! 486 | \**********************/ 487 | /*! exports provided: getSymbolInstances, onlyUnique, iterativeGapFilling, createLabel, createTextField, createDropdown, createCheckbox, getValFromLayerName, renameLayer, isVerticalBarchart, getBarHeight */ 488 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 489 | 490 | "use strict"; 491 | __webpack_require__.r(__webpack_exports__); 492 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getSymbolInstances", function() { return getSymbolInstances; }); 493 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onlyUnique", function() { return onlyUnique; }); 494 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "iterativeGapFilling", function() { return iterativeGapFilling; }); 495 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createLabel", function() { return createLabel; }); 496 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createTextField", function() { return createTextField; }); 497 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createDropdown", function() { return createDropdown; }); 498 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createCheckbox", function() { return createCheckbox; }); 499 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getValFromLayerName", function() { return getValFromLayerName; }); 500 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renameLayer", function() { return renameLayer; }); 501 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isVerticalBarchart", function() { return isVerticalBarchart; }); 502 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBarHeight", function() { return getBarHeight; }); 503 | function getSymbolInstances(source, symbolMaster) { 504 | // https://github.com/sonburn/ 505 | var symbolInstances = NSMutableArray.array(); 506 | source.sketchObject.pages().forEach(function (page) { 507 | var predicate = NSPredicate.predicateWithFormat('className == %@ && symbolMaster.objectID == %@', 'MSSymbolInstance', symbolMaster.sketchObject.objectID()); 508 | page.children().filteredArrayUsingPredicate(predicate).forEach(function (instance) { 509 | return symbolInstances.addObject(instance); 510 | }); 511 | }); 512 | return symbolInstances; 513 | } 514 | function onlyUnique(value, index, self) { 515 | return self.indexOf(value) === index; 516 | } 517 | function iterativeGapFilling(array, length) { 518 | var newArray = []; 519 | 520 | for (var i = 0; i < length; i++) { 521 | var loop = Math.floor(i / array.length); 522 | var index = i - loop * array.length; 523 | newArray.push(array[index]); 524 | } 525 | 526 | return newArray; 527 | } 528 | /**********************/ 529 | 530 | /* POPUP */ 531 | 532 | /**********************/ 533 | 534 | /* 535 | Utils from Marc Bouchenoire 536 | for easier UI design 537 | https://github.com/bouchenoiremarc 538 | */ 539 | 540 | function createLabel(text, fontSize, bold, frame, opacity) { 541 | var label = NSTextField.alloc().initWithFrame(frame); 542 | label.setStringValue(text); 543 | label.setFont(bold ? NSFont.boldSystemFontOfSize(fontSize) : NSFont.systemFontOfSize(fontSize)); 544 | label.setBezeled(false); 545 | label.setDrawsBackground(false); 546 | label.setEditable(false); 547 | label.setSelectable(false); 548 | if (opacity) label.setAlphaValue(opacity); 549 | return label; 550 | } 551 | function createTextField(value, placeholder, frame) { 552 | var textfield = NSTextField.alloc().initWithFrame(frame); 553 | textfield.cell().setWraps(false); 554 | textfield.cell().setScrollable(true); 555 | textfield.setStringValue(value); 556 | if (placeholder) textfield.setPlaceholderString(placeholder); 557 | return textfield; 558 | } 559 | function createDropdown(values, frame) { 560 | var dropdown = NSPopUpButton.alloc().initWithFrame(frame); 561 | dropdown.addItemsWithTitles(values); 562 | return dropdown; 563 | } 564 | function createCheckbox(text, checked, frame) { 565 | checked = checked == false ? NSOffState : NSOnState; 566 | var checkbox = NSButton.alloc().initWithFrame(frame); 567 | checkbox.setButtonType(NSSwitchButton); 568 | checkbox.setBezelStyle(0); 569 | checkbox.setTitle(text); 570 | checkbox.setState(checked); 571 | return checkbox; 572 | } 573 | /**********************/ 574 | 575 | /* VAL IN LAYER NAME */ 576 | 577 | /**********************/ 578 | 579 | function getValFromLayerName(name) { 580 | var a = name.split("{:"); 581 | 582 | if (a.length == 1) { 583 | return false; 584 | } 585 | 586 | var b = a[1].split(":}"); 587 | var val = parseFloat(b[0]); 588 | 589 | if (isNaN(val)) { 590 | return false; 591 | } 592 | 593 | return val; 594 | } 595 | function renameLayer(name, newVal) { 596 | var a = name.split("{:"); 597 | var newName = name + " {:" + newVal + ":}"; 598 | 599 | if (a.length > 1) { 600 | var b = a[1].split(":}"); 601 | 602 | if (b.length == 1) { 603 | return newName; 604 | } 605 | 606 | var newName = a[0] + "{:" + newVal + ":}" + b[1]; 607 | } 608 | 609 | return newName; 610 | } 611 | /**********************/ 612 | 613 | /* BARCHART */ 614 | 615 | /**********************/ 616 | 617 | function isVerticalBarchart(arr) { 618 | // arr needs to be doc.selectedLayers 619 | var isVertical = true; 620 | 621 | if (arr.layers.length >= 2 && arr.layers[0].frame.y != arr.layers[1].frame.y) { 622 | // It's horizontal if 623 | // 1. First two bars share same x value (works for positive values) 624 | if (arr.layers[0].frame.x == arr.layers[1].frame.x) { 625 | isVertical = false; 626 | } // 2. Same y-baseline (works if first value is negative) 627 | // and they share same height 628 | // ! Needs check if first / second val is negative 629 | else if (arr.layers[0].frame.x + arr.layers[0].frame.width == arr.layers[1].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height) { 630 | isVertical = false; 631 | } else if (arr.layers[1].frame.x + arr.layers[1].frame.width == arr.layers[0].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height) { 632 | isVertical = false; 633 | } 634 | } 635 | 636 | return isVertical; 637 | } 638 | /**********************/ 639 | 640 | /* NON-RANDO BARCHART */ 641 | 642 | /**********************/ 643 | 644 | function getBarHeight(arr, isVertical) { 645 | // arr needs to be doc.selectedLayers 646 | var barLength_str = ""; 647 | 648 | for (var i = 0; i < arr.layers.length; i++) { 649 | var thisLength = undefined; 650 | 651 | if (isVertical) { 652 | thisLength = arr.layers[i].frame.height.toFixed(2); // reduce to 2 decimals 653 | } else { 654 | thisLength = arr.layers[i].frame.width.toFixed(2); // reduce to 2 decimals 655 | } 656 | 657 | thisLength = parseFloat(thisLength); // to remove decimals from integers 658 | 659 | if (i == 0) { 660 | barLength_str = "" + thisLength; 661 | } else { 662 | barLength_str = barLength_str + "," + thisLength; 663 | } 664 | } 665 | 666 | return barLength_str; 667 | } 668 | 669 | /***/ }), 670 | 671 | /***/ "sketch": 672 | /*!*************************!*\ 673 | !*** external "sketch" ***! 674 | \*************************/ 675 | /*! no static exports found */ 676 | /***/ (function(module, exports) { 677 | 678 | module.exports = require("sketch"); 679 | 680 | /***/ }) 681 | 682 | /******/ }); 683 | if (key === 'default' && typeof exports === 'function') { 684 | exports(context); 685 | } else { 686 | exports[key](context); 687 | } 688 | } 689 | that['onRun'] = __skpm_run.bind(this, 'default') 690 | 691 | //# sourceMappingURL=nonrandom-barchart.js.map -------------------------------------------------------------------------------- /chippen-charts.sketchplugin/Contents/Sketch/randomfill.js: -------------------------------------------------------------------------------- 1 | var that = this; 2 | function __skpm_run (key, context) { 3 | that.context = context; 4 | 5 | var exports = 6 | /******/ (function(modules) { // webpackBootstrap 7 | /******/ // The module cache 8 | /******/ var installedModules = {}; 9 | /******/ 10 | /******/ // The require function 11 | /******/ function __webpack_require__(moduleId) { 12 | /******/ 13 | /******/ // Check if module is in cache 14 | /******/ if(installedModules[moduleId]) { 15 | /******/ return installedModules[moduleId].exports; 16 | /******/ } 17 | /******/ // Create a new module (and put it into the cache) 18 | /******/ var module = installedModules[moduleId] = { 19 | /******/ i: moduleId, 20 | /******/ l: false, 21 | /******/ exports: {} 22 | /******/ }; 23 | /******/ 24 | /******/ // Execute the module function 25 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 26 | /******/ 27 | /******/ // Flag the module as loaded 28 | /******/ module.l = true; 29 | /******/ 30 | /******/ // Return the exports of the module 31 | /******/ return module.exports; 32 | /******/ } 33 | /******/ 34 | /******/ 35 | /******/ // expose the modules object (__webpack_modules__) 36 | /******/ __webpack_require__.m = modules; 37 | /******/ 38 | /******/ // expose the module cache 39 | /******/ __webpack_require__.c = installedModules; 40 | /******/ 41 | /******/ // define getter function for harmony exports 42 | /******/ __webpack_require__.d = function(exports, name, getter) { 43 | /******/ if(!__webpack_require__.o(exports, name)) { 44 | /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 45 | /******/ } 46 | /******/ }; 47 | /******/ 48 | /******/ // define __esModule on exports 49 | /******/ __webpack_require__.r = function(exports) { 50 | /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 51 | /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 52 | /******/ } 53 | /******/ Object.defineProperty(exports, '__esModule', { value: true }); 54 | /******/ }; 55 | /******/ 56 | /******/ // create a fake namespace object 57 | /******/ // mode & 1: value is a module id, require it 58 | /******/ // mode & 2: merge all properties of value into the ns 59 | /******/ // mode & 4: return value when already ns object 60 | /******/ // mode & 8|1: behave like require 61 | /******/ __webpack_require__.t = function(value, mode) { 62 | /******/ if(mode & 1) value = __webpack_require__(value); 63 | /******/ if(mode & 8) return value; 64 | /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 65 | /******/ var ns = Object.create(null); 66 | /******/ __webpack_require__.r(ns); 67 | /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 68 | /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 69 | /******/ return ns; 70 | /******/ }; 71 | /******/ 72 | /******/ // getDefaultExport function for compatibility with non-harmony modules 73 | /******/ __webpack_require__.n = function(module) { 74 | /******/ var getter = module && module.__esModule ? 75 | /******/ function getDefault() { return module['default']; } : 76 | /******/ function getModuleExports() { return module; }; 77 | /******/ __webpack_require__.d(getter, 'a', getter); 78 | /******/ return getter; 79 | /******/ }; 80 | /******/ 81 | /******/ // Object.prototype.hasOwnProperty.call 82 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 83 | /******/ 84 | /******/ // __webpack_public_path__ 85 | /******/ __webpack_require__.p = ""; 86 | /******/ 87 | /******/ 88 | /******/ // Load entry module and return exports 89 | /******/ return __webpack_require__(__webpack_require__.s = "./src/randomfill.js"); 90 | /******/ }) 91 | /************************************************************************/ 92 | /******/ ({ 93 | 94 | /***/ "./src/randomfill.js": 95 | /*!***************************!*\ 96 | !*** ./src/randomfill.js ***! 97 | \***************************/ 98 | /*! exports provided: default */ 99 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 100 | 101 | "use strict"; 102 | __webpack_require__.r(__webpack_exports__); 103 | /* harmony import */ var sketch__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! sketch */ "sketch"); 104 | /* harmony import */ var sketch__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(sketch__WEBPACK_IMPORTED_MODULE_0__); 105 | /* harmony import */ var _utils_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utils.js */ "./src/utils.js"); 106 | 107 | 108 | /* harmony default export */ __webpack_exports__["default"] = (function () { 109 | log('~~ Run Chippen charts ~~'); 110 | var doc = sketch__WEBPACK_IMPORTED_MODULE_0___default.a.getSelectedDocument(); 111 | var selectedLayers = doc.selectedLayers; // Elements with these types will get fill colour applied 112 | 113 | var el_has_fillcolor = ["Rectangle", "ShapePath", "Shape"]; 114 | var el_has_textcolor = ["Text"]; // Default values for popup 115 | 116 | var defaultCol1 = "#eeeeee"; 117 | var defaultCol2 = "#891c55"; 118 | var defaultCategories = 5; 119 | /* 120 | CHECK SELECTION 121 | */ 122 | 123 | if (selectedLayers.length == 0) { 124 | sketch__WEBPACK_IMPORTED_MODULE_0___default.a.UI.alert("Chippencharts", 'Please select at least 1 shape or text layers to apply the random fill colours to.'); 125 | return false; 126 | } 127 | /* 128 | Setup the popup window 129 | */ 130 | 131 | 132 | var popup = COSAlertWindow.new(); 133 | popup.setMessageText("Random fill"); 134 | popup.addButtonWithTitle("Run"); 135 | popup.addButtonWithTitle("Cancel"); 136 | popup.setInformativeText("Get as many colours as you want between two colours and randomly apply as fill to selected layers."); 137 | /* 138 | Input 139 | */ 140 | 141 | var popup_width = 280; 142 | var colInput_label = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("Paste in your two colour values", 12, true, NSMakeRect(0, 0, popup_width, 16)); 143 | var col_view = NSView.alloc().initWithFrame(NSMakeRect(0, 0, popup_width, 25)); 144 | var col1Input = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createTextField"])(defaultCol1, null, NSMakeRect(0, 0, 130, 25)); 145 | var col2Input = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createTextField"])(defaultCol2, null, NSMakeRect(150, 0, 130, 25)); 146 | var categories_label = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createLabel"])("How many random colours do you want?", 12, true, NSMakeRect(0, 0, popup_width, 16)); 147 | var categoriesInput = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createTextField"])(defaultCategories, null, NSMakeRect(0, 0, 130, 25)); 148 | var sort_checkbox = Object(_utils_js__WEBPACK_IMPORTED_MODULE_1__["createCheckbox"])("Use layer order instead of random order", false, NSMakeRect(-2, -1, 280, 24)); 149 | popup.addAccessoryView(colInput_label); 150 | col_view.addSubview(col1Input); 151 | col_view.addSubview(col2Input); 152 | popup.addAccessoryView(col_view); 153 | popup.addAccessoryView(categories_label); 154 | popup.addAccessoryView(categoriesInput); 155 | popup.addAccessoryView(sort_checkbox); 156 | popup.alert().window().setInitialFirstResponder(col1Input); 157 | col1Input.setNextKeyView(col2Input); 158 | col2Input.setNextKeyView(categoriesInput); 159 | categoriesInput.setNextKeyView(col1Input); 160 | /* 161 | RESPONSE 162 | */ 163 | 164 | var responseCode = popup.runModal(); 165 | 166 | if (responseCode != 1000) { 167 | // User clicked "Cancel" 168 | return false; 169 | } 170 | 171 | var col1 = removeHash(col1Input.stringValue()); 172 | var col2 = removeHash(col2Input.stringValue()); 173 | var num_of_colours = parseFloat(categoriesInput.stringValue()); 174 | var apply_by_layer_order = Number(sort_checkbox.state()) == 1 ? true : false; 175 | /* 176 | CALCULATE COLOURS AND APPLY 177 | */ 178 | 179 | var col1_rgb = hexToRGB(col1); 180 | var col2_rgb = hexToRGB(col2); 181 | var colours = [col1]; // start colour 182 | 183 | for (var i = 0; i < num_of_colours - 2; i++) { 184 | var new_rgb = []; 185 | 186 | for (var j = 0; j < 3; j++) { 187 | var new_diff = col1_rgb[j] - col2_rgb[j]; 188 | var new_dir = new_diff >= 0 ? -1 : 1; 189 | var new_add = Math.abs(new_diff) / (num_of_colours - 1); 190 | var new_dim = col1_rgb[j] + new_dir * (i + 1) * new_add; 191 | new_rgb.push(Math.round(new_dim)); 192 | } 193 | 194 | colours.push(rgbToHex(new_rgb)); 195 | } 196 | 197 | colours.push(col2); // last colour 198 | // Apply new colours to selection 199 | 200 | for (var i = 0; i < selectedLayers.layers.length; i++) { 201 | var random_index = Math.floor(Math.random() * (+colours.length - +0)) + +0; 202 | var order_index = Math.floor(i * ((colours.length - 1) / (selectedLayers.layers.length - 1))); 203 | var col_index = apply_by_layer_order ? order_index : random_index; 204 | var random_col = hex_9(colours[col_index]); 205 | 206 | if (el_has_fillcolor.includes(selectedLayers.layers[i].type)) { 207 | // Change fill if it's shape layer 208 | selectedLayers.layers[i].style.fills[0].color = random_col; 209 | } else if (el_has_textcolor.includes(selectedLayers.layers[i].type)) { 210 | // Change fill if it's a text layer 211 | selectedLayers.layers[i].style.textColor = random_col; 212 | } 213 | } 214 | }); 215 | 216 | function hexToRGB(hex) { 217 | var rgb = []; 218 | 219 | for (var i = 0; i < 3; i++) { 220 | var sub1 = hex.substring(2 * i, 2 + 2 * i); 221 | var v = parseInt(sub1, 16); 222 | rgb.push(v); 223 | } 224 | 225 | return rgb; 226 | } 227 | 228 | function hex_6(hex) { 229 | // #d8d8d8ff > d8d8d8 230 | return hex.substr(1, 6); 231 | } 232 | 233 | function hex_9(hex_6) { 234 | // d8d8d8 > #d8d8d8ff 235 | return "#" + hex_6 + "ff"; 236 | } 237 | 238 | function rgbToHex(arr) { 239 | var hex = ""; 240 | 241 | for (var i = 0; i < 3; i++) { 242 | var sub = arr[i].toString(16).toUpperCase(); 243 | var padsub = ('0' + sub).slice(-2); 244 | hex = hex + padsub; 245 | } 246 | 247 | return hex; 248 | } 249 | 250 | function removeHash(hex) { 251 | return hex.substr(0, 1) == "#" ? hex.substr(1, 6) : hex; 252 | } 253 | 254 | /***/ }), 255 | 256 | /***/ "./src/utils.js": 257 | /*!**********************!*\ 258 | !*** ./src/utils.js ***! 259 | \**********************/ 260 | /*! exports provided: getSymbolInstances, onlyUnique, iterativeGapFilling, createLabel, createTextField, createDropdown, createCheckbox, getValFromLayerName, renameLayer, isVerticalBarchart, getBarHeight */ 261 | /***/ (function(module, __webpack_exports__, __webpack_require__) { 262 | 263 | "use strict"; 264 | __webpack_require__.r(__webpack_exports__); 265 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getSymbolInstances", function() { return getSymbolInstances; }); 266 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "onlyUnique", function() { return onlyUnique; }); 267 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "iterativeGapFilling", function() { return iterativeGapFilling; }); 268 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createLabel", function() { return createLabel; }); 269 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createTextField", function() { return createTextField; }); 270 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createDropdown", function() { return createDropdown; }); 271 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createCheckbox", function() { return createCheckbox; }); 272 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getValFromLayerName", function() { return getValFromLayerName; }); 273 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "renameLayer", function() { return renameLayer; }); 274 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "isVerticalBarchart", function() { return isVerticalBarchart; }); 275 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getBarHeight", function() { return getBarHeight; }); 276 | function getSymbolInstances(source, symbolMaster) { 277 | // https://github.com/sonburn/ 278 | var symbolInstances = NSMutableArray.array(); 279 | source.sketchObject.pages().forEach(function (page) { 280 | var predicate = NSPredicate.predicateWithFormat('className == %@ && symbolMaster.objectID == %@', 'MSSymbolInstance', symbolMaster.sketchObject.objectID()); 281 | page.children().filteredArrayUsingPredicate(predicate).forEach(function (instance) { 282 | return symbolInstances.addObject(instance); 283 | }); 284 | }); 285 | return symbolInstances; 286 | } 287 | function onlyUnique(value, index, self) { 288 | return self.indexOf(value) === index; 289 | } 290 | function iterativeGapFilling(array, length) { 291 | var newArray = []; 292 | 293 | for (var i = 0; i < length; i++) { 294 | var loop = Math.floor(i / array.length); 295 | var index = i - loop * array.length; 296 | newArray.push(array[index]); 297 | } 298 | 299 | return newArray; 300 | } 301 | /**********************/ 302 | 303 | /* POPUP */ 304 | 305 | /**********************/ 306 | 307 | /* 308 | Utils from Marc Bouchenoire 309 | for easier UI design 310 | https://github.com/bouchenoiremarc 311 | */ 312 | 313 | function createLabel(text, fontSize, bold, frame, opacity) { 314 | var label = NSTextField.alloc().initWithFrame(frame); 315 | label.setStringValue(text); 316 | label.setFont(bold ? NSFont.boldSystemFontOfSize(fontSize) : NSFont.systemFontOfSize(fontSize)); 317 | label.setBezeled(false); 318 | label.setDrawsBackground(false); 319 | label.setEditable(false); 320 | label.setSelectable(false); 321 | if (opacity) label.setAlphaValue(opacity); 322 | return label; 323 | } 324 | function createTextField(value, placeholder, frame) { 325 | var textfield = NSTextField.alloc().initWithFrame(frame); 326 | textfield.cell().setWraps(false); 327 | textfield.cell().setScrollable(true); 328 | textfield.setStringValue(value); 329 | if (placeholder) textfield.setPlaceholderString(placeholder); 330 | return textfield; 331 | } 332 | function createDropdown(values, frame) { 333 | var dropdown = NSPopUpButton.alloc().initWithFrame(frame); 334 | dropdown.addItemsWithTitles(values); 335 | return dropdown; 336 | } 337 | function createCheckbox(text, checked, frame) { 338 | checked = checked == false ? NSOffState : NSOnState; 339 | var checkbox = NSButton.alloc().initWithFrame(frame); 340 | checkbox.setButtonType(NSSwitchButton); 341 | checkbox.setBezelStyle(0); 342 | checkbox.setTitle(text); 343 | checkbox.setState(checked); 344 | return checkbox; 345 | } 346 | /**********************/ 347 | 348 | /* VAL IN LAYER NAME */ 349 | 350 | /**********************/ 351 | 352 | function getValFromLayerName(name) { 353 | var a = name.split("{:"); 354 | 355 | if (a.length == 1) { 356 | return false; 357 | } 358 | 359 | var b = a[1].split(":}"); 360 | var val = parseFloat(b[0]); 361 | 362 | if (isNaN(val)) { 363 | return false; 364 | } 365 | 366 | return val; 367 | } 368 | function renameLayer(name, newVal) { 369 | var a = name.split("{:"); 370 | var newName = name + " {:" + newVal + ":}"; 371 | 372 | if (a.length > 1) { 373 | var b = a[1].split(":}"); 374 | 375 | if (b.length == 1) { 376 | return newName; 377 | } 378 | 379 | var newName = a[0] + "{:" + newVal + ":}" + b[1]; 380 | } 381 | 382 | return newName; 383 | } 384 | /**********************/ 385 | 386 | /* BARCHART */ 387 | 388 | /**********************/ 389 | 390 | function isVerticalBarchart(arr) { 391 | // arr needs to be doc.selectedLayers 392 | var isVertical = true; 393 | 394 | if (arr.layers.length >= 2 && arr.layers[0].frame.y != arr.layers[1].frame.y) { 395 | // It's horizontal if 396 | // 1. First two bars share same x value (works for positive values) 397 | if (arr.layers[0].frame.x == arr.layers[1].frame.x) { 398 | isVertical = false; 399 | } // 2. Same y-baseline (works if first value is negative) 400 | // and they share same height 401 | // ! Needs check if first / second val is negative 402 | else if (arr.layers[0].frame.x + arr.layers[0].frame.width == arr.layers[1].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height) { 403 | isVertical = false; 404 | } else if (arr.layers[1].frame.x + arr.layers[1].frame.width == arr.layers[0].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height) { 405 | isVertical = false; 406 | } 407 | } 408 | 409 | return isVertical; 410 | } 411 | /**********************/ 412 | 413 | /* NON-RANDO BARCHART */ 414 | 415 | /**********************/ 416 | 417 | function getBarHeight(arr, isVertical) { 418 | // arr needs to be doc.selectedLayers 419 | var barLength_str = ""; 420 | 421 | for (var i = 0; i < arr.layers.length; i++) { 422 | var thisLength = undefined; 423 | 424 | if (isVertical) { 425 | thisLength = arr.layers[i].frame.height.toFixed(2); // reduce to 2 decimals 426 | } else { 427 | thisLength = arr.layers[i].frame.width.toFixed(2); // reduce to 2 decimals 428 | } 429 | 430 | thisLength = parseFloat(thisLength); // to remove decimals from integers 431 | 432 | if (i == 0) { 433 | barLength_str = "" + thisLength; 434 | } else { 435 | barLength_str = barLength_str + "," + thisLength; 436 | } 437 | } 438 | 439 | return barLength_str; 440 | } 441 | 442 | /***/ }), 443 | 444 | /***/ "sketch": 445 | /*!*************************!*\ 446 | !*** external "sketch" ***! 447 | \*************************/ 448 | /*! no static exports found */ 449 | /***/ (function(module, exports) { 450 | 451 | module.exports = require("sketch"); 452 | 453 | /***/ }) 454 | 455 | /******/ }); 456 | if (key === 'default' && typeof exports === 'function') { 457 | exports(context); 458 | } else { 459 | exports[key](context); 460 | } 461 | } 462 | that['onRun'] = __skpm_run.bind(this, 'default') 463 | 464 | //# sourceMappingURL=randomfill.js.map -------------------------------------------------------------------------------- /chippen-charts.sketchplugin/Contents/Sketch/randomfill.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://exports/webpack/bootstrap","webpack://exports/./src/randomfill.js","webpack://exports/./src/utils.js","webpack://exports/external \"sketch\""],"names":["log","doc","sketch","getSelectedDocument","selectedLayers","el_has_fillcolor","el_has_textcolor","defaultCol1","defaultCol2","defaultCategories","length","UI","alert","popup","COSAlertWindow","new","setMessageText","addButtonWithTitle","setInformativeText","popup_width","colInput_label","createLabel","NSMakeRect","col_view","NSView","alloc","initWithFrame","col1Input","createTextField","col2Input","categories_label","categoriesInput","sort_checkbox","createCheckbox","addAccessoryView","addSubview","window","setInitialFirstResponder","setNextKeyView","responseCode","runModal","col1","removeHash","stringValue","col2","num_of_colours","parseFloat","apply_by_layer_order","Number","state","col1_rgb","hexToRGB","col2_rgb","colours","i","new_rgb","j","new_diff","new_dir","new_add","Math","abs","new_dim","push","round","rgbToHex","layers","random_index","floor","random","order_index","col_index","random_col","hex_9","includes","type","style","fills","color","textColor","hex","rgb","sub1","substring","v","parseInt","hex_6","substr","arr","sub","toString","toUpperCase","padsub","slice","getSymbolInstances","source","symbolMaster","symbolInstances","NSMutableArray","array","sketchObject","pages","forEach","page","predicate","NSPredicate","predicateWithFormat","objectID","children","filteredArrayUsingPredicate","instance","addObject","onlyUnique","value","index","self","indexOf","iterativeGapFilling","newArray","loop","text","fontSize","bold","frame","opacity","label","NSTextField","setStringValue","setFont","NSFont","boldSystemFontOfSize","systemFontOfSize","setBezeled","setDrawsBackground","setEditable","setSelectable","setAlphaValue","placeholder","textfield","cell","setWraps","setScrollable","setPlaceholderString","createDropdown","values","dropdown","NSPopUpButton","addItemsWithTitles","checked","NSOffState","NSOnState","checkbox","NSButton","setButtonType","NSSwitchButton","setBezelStyle","setTitle","setState","getValFromLayerName","name","a","split","b","val","isNaN","renameLayer","newVal","newName","isVerticalBarchart","isVertical","y","x","width","height","getBarHeight","barLength_str","thisLength","undefined","toFixed"],"mappings":"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","file":"randomfill.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/randomfill.js\");\n","import sketch from 'sketch'\nimport { createLabel, createTextField, createCheckbox, onlyUnique } from \"./utils.js\";\n\nexport default function() {\n\tlog('~~ Run Chippen charts ~~')\n\tconst doc = sketch.getSelectedDocument()\n\tconst selectedLayers = doc.selectedLayers;\n\n\t// Elements with these types will get fill colour applied\n\tconst el_has_fillcolor = [\"Rectangle\", \"ShapePath\", \"Shape\"]\n\tconst el_has_textcolor = [\"Text\"]\n\n\t// Default values for popup\n\tconst defaultCol1 = \"#eeeeee\";\n\tconst defaultCol2 = \"#891c55\";\n\tconst defaultCategories = 5;\n\t\n\n\t/*\n\t\tCHECK SELECTION\n\t*/\n\t\n\tif (selectedLayers.length == 0) {\n\t\tsketch.UI.alert(\"Chippencharts\",'Please select at least 1 shape or text layers to apply the random fill colours to.');\n\t\treturn false;\n\t}\n\n\n\t/*\n\t\tSetup the popup window\n\t*/\n\n\tvar popup = COSAlertWindow.new()\n\tpopup.setMessageText(\"Random fill\")\n\tpopup.addButtonWithTitle(\"Run\");\n\tpopup.addButtonWithTitle(\"Cancel\");\n\tpopup.setInformativeText(`Get as many colours as you want between two colours and randomly apply as fill to selected layers.`);\n\n\n\t/*\n\t\tInput\n \t*/\n\n \tconst popup_width = 280;\n\n\tvar colInput_label = createLabel(\"Paste in your two colour values\", 12, true, NSMakeRect(0, 0, popup_width, 16));\n \t\n\tvar col_view = NSView.alloc().initWithFrame(NSMakeRect(0, 0, popup_width, 25));\n \tvar col1Input = createTextField(defaultCol1, null, NSMakeRect(0, 0, 130, 25));\n \tvar col2Input = createTextField(defaultCol2, null, NSMakeRect(150, 0, 130, 25));\n \t\n \tvar categories_label = createLabel(\"How many random colours do you want?\", 12, true, NSMakeRect(0, 0, popup_width, 16));\n \tvar categoriesInput = createTextField(defaultCategories, null, NSMakeRect(0, 0, 130, 25));\n\n\tvar sort_checkbox = createCheckbox(\"Use layer order instead of random order\", false, NSMakeRect(-2, -1, 280, 24));\n\t\n\tpopup.addAccessoryView(colInput_label)\n\tcol_view.addSubview(col1Input)\n\tcol_view.addSubview(col2Input)\n \tpopup.addAccessoryView(col_view);\n\n \tpopup.addAccessoryView(categories_label);\n \tpopup.addAccessoryView(categoriesInput);\n\n \tpopup.addAccessoryView(sort_checkbox);\n\n \tpopup.alert().window().setInitialFirstResponder(col1Input);\n\tcol1Input.setNextKeyView(col2Input)\n\tcol2Input.setNextKeyView(categoriesInput)\n\tcategoriesInput.setNextKeyView(col1Input)\n\n\n \t/*\n\t\tRESPONSE\n\t*/\n\n\tvar responseCode = popup.runModal();\n\t\n\tif(responseCode != 1000){\n\n\t\t// User clicked \"Cancel\"\n\t\treturn false;\n\t}\n\n\tvar col1 = removeHash(col1Input.stringValue());\n\tvar col2 = removeHash(col2Input.stringValue());\n\tvar num_of_colours = parseFloat(categoriesInput.stringValue());\n\tvar apply_by_layer_order = Number(sort_checkbox.state()) == 1 ? true : false;\n\t\n\n\t/*\n\t\tCALCULATE COLOURS AND APPLY\n\t*/\n\n\tvar col1_rgb = hexToRGB(col1);\n\tvar col2_rgb = hexToRGB(col2);\n\n\tvar colours = [col1] // start colour\n\n\tfor(var i=0; i<(num_of_colours-2); i++){\n\n\t\tvar new_rgb = []\n\n\t\tfor(var j=0; j<3; j++){\n\t\t\t\n\n\t\t\tvar new_diff = col1_rgb[j] - col2_rgb[j];\n\t\t\tvar new_dir = new_diff >=0 ? -1 : 1;\n\n\t\t\tvar new_add = Math.abs(new_diff) / (num_of_colours-1);\n\t\t\tvar new_dim = col1_rgb[j] + new_dir*(i+1)*new_add;\n\n\t\t\tnew_rgb.push(Math.round(new_dim))\n\t\t}\n\t\tcolours.push(rgbToHex(new_rgb))\n\t}\n\n\tcolours.push(col2) // last colour\n\n\n\t// Apply new colours to selection\n\tfor(var i = 0; i d8d8d8\n\treturn hex.substr(1,6);\n}\n\nfunction hex_9 (hex_6){\n\t// d8d8d8 > #d8d8d8ff\n\treturn \"#\" + hex_6 + \"ff\";\n}\n\nfunction rgbToHex(arr){\n\tvar hex = \"\";\n\tfor(var i=0; i<3; i++){\n\t\tvar sub = arr[i].toString(16).toUpperCase();\n\t\tvar padsub = ('0'+sub).slice(-2);\n\t\thex = hex + padsub\n\t}\n\treturn hex;\n}\n\nfunction removeHash(hex){\n\treturn hex.substr(0,1)==\"#\" ? hex.substr(1,6) : hex;\n\n}","export function getSymbolInstances(source,symbolMaster) {\n\t// https://github.com/sonburn/\n\tvar symbolInstances = NSMutableArray.array();\n\n\tsource.sketchObject.pages().forEach(function(page){\n\t\tvar predicate = NSPredicate.predicateWithFormat('className == %@ && symbolMaster.objectID == %@','MSSymbolInstance',symbolMaster.sketchObject.objectID());\n\n\t\tpage.children().filteredArrayUsingPredicate(predicate).forEach(instance => symbolInstances.addObject(instance));\n\t});\n\n\treturn symbolInstances;\n}\n\nexport function onlyUnique(value, index, self) { \n return self.indexOf(value) === index;\n}\n\nexport function iterativeGapFilling(array, length){\n\tvar newArray = [];\n\tfor(var i=0; i 1){\n\t\tvar b = a[1].split(\":}\");\n\t\tif(b.length == 1){return newName;}\n\t\tvar newName = a[0] + \"{:\" + newVal + \":}\" + b[1];\n\t}\n\n\treturn newName\n}\n\n\n/**********************/\n/* BARCHART */\n/**********************/\n\nexport function isVerticalBarchart(arr){\n\t// arr needs to be doc.selectedLayers\n\tvar isVertical = true\n\tif(arr.layers.length >= 2 && arr.layers[0].frame.y != arr.layers[1].frame.y){\n\t\t// It's horizontal if\n\t\t// 1. First two bars share same x value (works for positive values)\n\t\tif(arr.layers[0].frame.x == arr.layers[1].frame.x){\n\t\t\tisVertical = false;\n\t\t}\n\t\t// 2. Same y-baseline (works if first value is negative) \n\t\t// and they share same height\n\t\t// ! Needs check if first / second val is negative\n\t\telse if(arr.layers[0].frame.x + arr.layers[0].frame.width == arr.layers[1].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height){\n\t\t\tisVertical = false;\t\n\t\t}\n\t\telse if(arr.layers[1].frame.x + arr.layers[1].frame.width == arr.layers[0].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height){\n\t\t\tisVertical = false;\t\n\t\t}\n\t}\n\treturn isVertical\n}\n\n\n/**********************/\n/* NON-RANDO BARCHART */\n/**********************/\n\nexport function getBarHeight(arr, isVertical){\n\t// arr needs to be doc.selectedLayers\n\tvar barLength_str = \"\"\n\t\n\tfor(var i=0; i=3.0" 6 | }, 7 | "description": "Bar chart creator for your mockups using random or user defined data. Change the size of selected rectangles. Works for both horizontal and vertical bar charts. Made with love in Chippendale.", 8 | "skpm": { 9 | "name": "Chippen charts", 10 | "manifest": "src/manifest.json", 11 | "main": "chippen-charts.sketchplugin", 12 | "assets": [ 13 | "assets/**/*" 14 | ] 15 | }, 16 | "scripts": { 17 | "build": "skpm-build", 18 | "watch": "skpm-build --watch", 19 | "start": "skpm-build --watch --run", 20 | "postinstall": "npm run build && skpm-link" 21 | }, 22 | "devDependencies": { 23 | "@skpm/builder": "^0.5.2" 24 | }, 25 | "repository": "https://github.com/smallmultiples/sketch-chippencharts.git", 26 | "author": "Martin von Lupin" 27 | } 28 | -------------------------------------------------------------------------------- /src/barchart.js: -------------------------------------------------------------------------------- 1 | import sketch from 'sketch' 2 | import { getValFromLayerName, renameLayer, isVerticalBarchart, createLabel } from "./utils.js"; 3 | // documentation: https://developer.sketchapp.com/reference/api/ 4 | 5 | export default function() { 6 | log('~~ Run Chippen charts ~~') 7 | const doc = sketch.getSelectedDocument() 8 | const selectedLayers = doc.selectedLayers 9 | 10 | /* 11 | Analyse selected layers 12 | */ 13 | 14 | var isVertical = isVerticalBarchart(doc.selectedLayers) 15 | var minMax_fromSelection = getMinMax(doc.selectedLayers, isVertical) 16 | 17 | 18 | /* 19 | User input 20 | */ 21 | 22 | var response = myinput(minMax_fromSelection, doc.selectedLayers.layers.length, isVertical) 23 | var minMax = [response.min, response.max] 24 | if (response.code !== 1000) { 25 | return 26 | } 27 | var myRandomSlots = [] 28 | if(response.trendTypeInput == 0){ 29 | // Only for random trend 30 | // Set 2 random bars to min and max 31 | myRandomSlots = twoRandomSlots(selectedLayers.layers.length, 'Random') 32 | } 33 | 34 | // Force other type than detected if user has selected force type 35 | if(response.forcetype){isVertical = !isVertical} 36 | 37 | 38 | /* 39 | UI message 40 | */ 41 | 42 | var trendTypeInput_name = [ 43 | "random data", 44 | "trend going up ↑ (linear)", 45 | "trend going up ↑ (natural)", 46 | "trend going down ↓ (linear)", 47 | "trend going down ↓ (natural)" 48 | ] 49 | 50 | var isVertical_name = "vertical" 51 | if(!isVertical){isVertical_name = "horizontal"} 52 | sketch.UI.message(`${doc.selectedLayers.length} ${isVertical_name} bars with ${trendTypeInput_name[response.trendTypeInput]} (${minMax[0]}px–${minMax[1]}px)`) 53 | 54 | 55 | /* 56 | Changing size 57 | */ 58 | 59 | const firstBarVal = getValFromLayerName(selectedLayers.layers[0].name); 60 | var baseLine = 0; 61 | 62 | if(isVertical){ 63 | baseLine = selectedLayers.layers[0].frame.y + selectedLayers.layers[0].frame.height; 64 | // Adjust when first value of existing bar is negative 65 | // Based on layer name 66 | if(firstBarVal < 0){baseLine = baseLine - Math.abs(firstBarVal)}; 67 | }else{ 68 | if(firstBarVal >= 0){ 69 | baseLine = selectedLayers.layers[0].frame.x 70 | }else if(firstBarVal < 0){ 71 | baseLine = selectedLayers.layers[0].frame.x + Math.abs(firstBarVal) 72 | } 73 | } 74 | 75 | for(var i = 0; i 0){ 126 | // Reposition bars with positive values 127 | selectedLayers.layers[i].frame.y = baseLine - Math.abs(newLength); 128 | }else{ 129 | // Reposition bars with negative values 130 | selectedLayers.layers[i].frame.y = baseLine; 131 | } 132 | }else{ 133 | // Reset position, just in case 134 | selectedLayers.layers[i].frame.x = baseLine; 135 | 136 | // Change Width 137 | selectedLayers.layers[i].frame.width = Math.abs(newLength); 138 | 139 | // Reposition bars with negative values 140 | if(newLength < 0){ 141 | selectedLayers.layers[i].frame.x = selectedLayers.layers[i].frame.x - Math.abs(newLength) 142 | } 143 | } 144 | 145 | // Rename layer 146 | // Example: Rectangle ==> Rectangle {:12:} 147 | selectedLayers.layers[i].name = renameLayer(selectedLayers.layers[i].name, newLength) 148 | } 149 | } 150 | 151 | function getMinMax(arr, isVertical){ 152 | // arr needs to be doc.selectedLayers 153 | var min = 0; 154 | var max = 0; 155 | 156 | if(isVertical){ 157 | // Vertical bar chart (get minMax height) 158 | for(var i = 0; imax){ 162 | max = thisHeight 163 | } 164 | // Min 165 | if(min == 0){ 166 | // set min at first runfirst 167 | min = max 168 | } 169 | if(thisHeight < min){ 170 | min = thisHeight 171 | } 172 | } 173 | }else{ 174 | // Horizontal bar chart (get minMax width) 175 | for(var i = 0; i max){ 179 | max = thisWidth 180 | } 181 | // Min 182 | if(min == 0){ 183 | // set min at first run 184 | min = max 185 | } 186 | if(thisWidth < min){ 187 | min = thisWidth 188 | } 189 | } 190 | } 191 | 192 | return [Math.ceil(min), Math.ceil(max)] 193 | } 194 | 195 | function twoRandomSlots(length, type){ 196 | var slotOne = 0 197 | var slotTwo = 0 198 | 199 | if(type=='Random'){ 200 | slotOne = Math.floor( Math.random() * length/2) 201 | slotTwo = Math.floor( Math.random() * length/2) + Math.floor(length/2) 202 | } 203 | return [slotOne, slotTwo] 204 | } 205 | 206 | 207 | function myinput(myMinMax=[20,100], numOfBars="", my_isVertical){ 208 | var myresponse = {} 209 | 210 | if(myMinMax.length != 2 || myMinMax[0]==myMinMax[1]){ 211 | if(myMinMax[0] > 100){ 212 | myMinMax = [20,myMinMax[1]] 213 | }else{ 214 | myMinMax = [myMinMax[0],100] 215 | } 216 | 217 | } 218 | 219 | if(numOfBars==0){ 220 | myresponse.code == 1001 221 | sketch.UI.alert("Sorry buddy", "You need to select multiple rectangles (bars) for this plugin to work.") 222 | } 223 | if(numOfBars!=0){ 224 | 225 | if(numOfBars==1){ 226 | sketch.UI.alert("Hey, just letting you know", "Most awesome results come when selecting more than 1 bar.") 227 | } 228 | 229 | // Create initial view panel 230 | var width = 280 231 | var height = 40 232 | var view = NSView.alloc().initWithFrame(NSMakeRect(0, 0, width, height)) 233 | 234 | // Min Max input 235 | var minInput = NSTextField.alloc().initWithFrame(NSMakeRect(0.0, 15.0, 130, 25.0)); 236 | minInput.cell().setPlaceholderString(myMinMax[0] + " (min)"); 237 | view.addSubview(minInput); 238 | 239 | var maxInput = NSTextField.alloc().initWithFrame(NSMakeRect(150, 15.0, 130, 25.0)); 240 | maxInput.cell().setPlaceholderString(myMinMax[1] + " (max)"); 241 | view.addSubview(maxInput); 242 | 243 | // Nature of data 244 | var trendTypeInput = NSView.alloc().initWithFrame(NSMakeRect(0, 0, width, 135)) 245 | // Acts like a template (prototype) for our radio buttons 246 | var buttonFormat; 247 | buttonFormat = NSButtonCell.alloc().init(); 248 | buttonFormat.setButtonType(NSRadioButton); 249 | 250 | // The matrix will contain all the cells (radio buttons) 251 | var matrixFormat = NSMatrix.alloc().initWithFrame_mode_prototype_numberOfRows_numberOfColumns( 252 | NSMakeRect(0, 0, 260, 135), // Horizontal position, vertical position, width, height 253 | NSRadioModeMatrix, // This makes the radio buttons work together 254 | buttonFormat, 255 | 5, // 1 row 256 | 1 // 3 columns (for 3 radio buttons) 257 | ); 258 | 259 | // Settings the size of the radio buttons 260 | matrixFormat.setCellSize(CGSizeMake(260, 25)); 261 | 262 | // Adding the radio buttons to the form 263 | var cells = matrixFormat.cells(); 264 | cells.objectAtIndex(0).setTitle("Random"); 265 | cells.objectAtIndex(1).setTitle("Trend going up ↑ (linear)"); 266 | cells.objectAtIndex(2).setTitle("Trend going up ↑ (natural)"); 267 | cells.objectAtIndex(3).setTitle("Trend going down ↓ (linear)"); 268 | cells.objectAtIndex(4).setTitle("Trend going down ↓ (natural)"); 269 | 270 | // Adding the matrix to the form 271 | trendTypeInput.addSubview(matrixFormat); 272 | 273 | 274 | // Bar type: Vertical or horizontal 275 | 276 | var bartype_label = createLabel("Vertical or horizontal?", 12, true, NSMakeRect(0, 0, width, 16)); 277 | 278 | var bartype_radio = NSView.alloc().initWithFrame(NSMakeRect(0, 0, width, 48)) 279 | 280 | var matrixFormat_bartype = NSMatrix.alloc().initWithFrame_mode_prototype_numberOfRows_numberOfColumns( 281 | NSMakeRect(0, 0, 260, 48), 282 | NSRadioModeMatrix, 283 | buttonFormat, 2, 1 284 | ); 285 | 286 | matrixFormat_bartype.setCellSize(CGSizeMake(260, 25)); 287 | 288 | var bartype_radio1_label = my_isVertical ? "Automatic (vertical detected)" : "Automatic (horizontal detected)" 289 | var bartype_radio2_label = my_isVertical ? "Force horizontal" : "Force vertical" 290 | var cells_bartype = matrixFormat_bartype.cells(); 291 | cells_bartype.objectAtIndex(0).setTitle(bartype_radio1_label); 292 | cells_bartype.objectAtIndex(1).setTitle(bartype_radio2_label); 293 | 294 | bartype_radio.addSubview(matrixFormat_bartype); 295 | 296 | 297 | // Setup the window 298 | var alert = COSAlertWindow.new() 299 | if(numOfBars==1){ 300 | alert.setMessageText(`Create your random bar chart \nwith 1 selected layer`) 301 | }else{ 302 | alert.setMessageText(`Create your random bar chart \nwith ${numOfBars} selected layers`) 303 | } 304 | 305 | alert.addButtonWithTitle("Run") 306 | alert.addButtonWithTitle("Cancel") 307 | alert.setInformativeText(`This is for a bar chart where random values are applied \nto the layers of your selection.`) 308 | 309 | var extrema_label = createLabel("Define extrema of bars", 12, true, NSMakeRect(0, 0, width, 16)); 310 | alert.addAccessoryView(extrema_label) 311 | 312 | //alert.addTextLabelWithValue("Define extrema of bars"); 313 | alert.addAccessoryView(view) 314 | 315 | var trend_label = createLabel("Specify the desired trend", 12, true, NSMakeRect(0, 0, width, 16)); 316 | alert.addAccessoryView(trend_label) 317 | //alert.addTextLabelWithValue("Specify the desired trend"); 318 | alert.addAccessoryView(trendTypeInput) 319 | 320 | alert.addAccessoryView(bartype_label); 321 | alert.addAccessoryView(bartype_radio) 322 | 323 | /* 324 | Key navigation (popup) 325 | */ 326 | 327 | alert.alert().window().setInitialFirstResponder(minInput) 328 | minInput.setNextKeyView(maxInput) 329 | maxInput.setNextKeyView(minInput) 330 | 331 | 332 | /* 333 | Note 334 | */ 335 | var note_line1 = createLabel("\nPlease make sure proportional scaling is disabled", 11, false, NSMakeRect(0, 0, width, 16*2), 0.3); 336 | alert.addAccessoryView(note_line1); 337 | 338 | var responseCode = alert.runModal(); 339 | 340 | if(responseCode == 1000){ 341 | myresponse.code = 1000 342 | // OK 343 | // pass minmax input 344 | if(minInput.stringValue() == ""){ 345 | myresponse.min = myMinMax[0] 346 | }else{ 347 | myresponse.min = parseInt(minInput.stringValue()) 348 | } 349 | if(maxInput.stringValue() == ""){ 350 | myresponse.max = myMinMax[1] 351 | }else{ 352 | myresponse.max = parseInt(maxInput.stringValue()) 353 | } 354 | 355 | // Force bar chart type 356 | var forcetype_index = matrixFormat_bartype.cells().indexOfObject(matrixFormat_bartype.selectedCell()); 357 | myresponse.forcetype = forcetype_index == 0 ? false : true; 358 | }else{ 359 | // Cancel 360 | myresponse.code = 1001 361 | } 362 | myresponse.trendTypeInput = matrixFormat.cells().indexOfObject(matrixFormat.selectedCell()) 363 | } 364 | return myresponse 365 | } 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | -------------------------------------------------------------------------------- /src/cliptexttosymbol.js: -------------------------------------------------------------------------------- 1 | import sketch from 'sketch' 2 | import { onlyUnique, iterativeGapFilling, createLabel, createDropdown, createCheckbox } from "./utils.js"; 3 | // documentation: https://developer.sketchapp.com/reference/api/ 4 | // https://github.com/sonburn/symbol-instance-locator/blob/master/Symbol%20Instance%20Locator.sketchplugin/Contents/Sketch/script.js 5 | 6 | var symbolOverrideLayers; 7 | 8 | export default function() { 9 | log('~~ Run Chippen charts ~~') 10 | 11 | const doc = sketch.getSelectedDocument() 12 | const selectedLayers = doc.selectedLayers 13 | 14 | var pluginName = __command.pluginBundle().name(); 15 | 16 | if(selectedLayers.layers.length == 0) { 17 | sketch.UI.alert(pluginName,'Please select at least 1 layer that contains a symbol override.'); 18 | 19 | return false; 20 | } 21 | 22 | 23 | /* 24 | CLIPBOARD 25 | */ 26 | 27 | var newLineSeparator = "\n"; 28 | var sep = newLineSeparator; 29 | 30 | var pasteBoard = NSPasteboard.generalPasteboard(); 31 | // Turn a data in the string type 32 | var stringFromPasteBoard = pasteBoard.stringForType(NSPasteboardTypeString); 33 | 34 | if(stringFromPasteBoard == null){ 35 | sketch.UI.alert(pluginName,'Your clipboard does not seem to be just text. Try again with only lines of text.'); 36 | return false; 37 | } 38 | 39 | var pasteboardLines = stringFromPasteBoard.split(newLineSeparator) 40 | 41 | 42 | /* 43 | SELECTED SYMBOLS 44 | */ 45 | 46 | const selectedSymbols = selectedLayers.layers.filter(layer => layer.type == "SymbolInstance" || layer.type == "SymbolMaster") 47 | if (selectedSymbols.length == 0) { 48 | sketch.UI.alert(pluginName,'Please select at least 1 layer that contains a symbol.'); 49 | return false; 50 | } 51 | 52 | const symbolsWithOverrides = selectedSymbols.filter(symbol => symbol.overrides.length != 0) 53 | if (symbolsWithOverrides.length == 0) { 54 | sketch.UI.alert(pluginName,'Please select at least 1 symbol that contains a text override.'); 55 | return false; 56 | } 57 | 58 | const symbolsIDs = symbolsWithOverrides.map(symbol => { 59 | return symbol.symbolId 60 | }) 61 | 62 | const uniqueSymbolIDs = symbolsIDs.filter( onlyUnique ); 63 | 64 | if(uniqueSymbolIDs.length > 1){ 65 | sketch.UI.alert(pluginName,`Please use only symbols of the same kind. Maybe you want to try to use only symbols like "${symbolsWithOverrides[0].name}".`); 66 | return false; 67 | } 68 | 69 | 70 | /* 71 | Informative Text 72 | */ 73 | 74 | var warningMsg = "" 75 | if(pasteboardLines.length > symbolsWithOverrides.length){ 76 | warningMsg = `There are more lines of text in the clipboard (${pasteboardLines.length}) than there are symbols in the selection (${symbolsWithOverrides.length}). That means not all content from clipboard will be used.` 77 | }else if(symbolsWithOverrides.length > pasteboardLines.length){ 78 | warningMsg = `There are more symbols selected (${symbolsWithOverrides.length}) than there are lines of text in the clipboard (${pasteboardLines.length}). Clipboard text will be repeated in the overflow symbols.` 79 | } 80 | 81 | var informativeText = "" 82 | if(warningMsg != ""){ 83 | informativeText = "⚠️ Watch out! - " + warningMsg + " \n\nYou can go ahead but outcomes might not be as expected." 84 | }else{ 85 | informativeText = `You are about to alter ${symbolsWithOverrides.length} symbol overrides using text from the clipboard.` 86 | } 87 | 88 | 89 | /* 90 | Dropdown options 91 | */ 92 | 93 | const stringvalueOverrides = symbolsWithOverrides[0].overrides.filter(override => override.property == 'stringValue') 94 | 95 | const overrideOptions = stringvalueOverrides.map((override, index) => { 96 | return "Override " + (parseInt(index)+1) + " (" + override.value + ")" 97 | }) 98 | 99 | 100 | /* 101 | Setup the window 102 | */ 103 | 104 | var alert = COSAlertWindow.new() 105 | alert.setMessageText("Paste clipboard text into symbol overrides") 106 | alert.addButtonWithTitle("Run") 107 | alert.addButtonWithTitle("Cancel") 108 | alert.setInformativeText(informativeText) 109 | 110 | 111 | /* 112 | Input 113 | */ 114 | 115 | // OVERRIDE DROPDOWN 116 | var alert_width = 280; 117 | var overrideOptions_label = createLabel("What override shall it be? ", 12, true, NSMakeRect(0, 0, alert_width, 16)); 118 | var overrideOptions_dropdown = createDropdown(overrideOptions, NSMakeRect(-2, -1, 280, 24)); 119 | 120 | if(overrideOptions.length>1){ 121 | alert.addAccessoryView(overrideOptions_label); 122 | alert.addAccessoryView(overrideOptions_dropdown); 123 | } 124 | 125 | // REVERSE CHECKBOX 126 | var reverse_checkbox = createCheckbox("Reverse order of clipboard text", false, NSMakeRect(-2, -1, 280, 24)); 127 | 128 | if(pasteboardLines.length>1){ 129 | alert.addAccessoryView(reverse_checkbox); 130 | } 131 | 132 | 133 | /* 134 | Response 135 | */ 136 | 137 | var overrideIndex; 138 | var responseCode = alert.runModal(); 139 | 140 | if(responseCode == 1000){ 141 | // Dropdown input 142 | var dropddownIndex = overrideOptions_dropdown.indexOfSelectedItem(); 143 | var overrideID = stringvalueOverrides[dropddownIndex].id; 144 | 145 | // Mapping index of dropdown to index of overrides. 146 | // Dropdown does only include stringValue overrides 147 | // and no symbolID overrides (top level of nested symbol). 148 | // That's why the length can differ. 149 | for(var i=0; i clip.length){ 176 | var clip_filled = iterativeGapFilling(clip, symbolsWithOverrides.length) 177 | clip = clip_filled; 178 | } 179 | 180 | for(var i=0; i= 0){ 69 | baseLine = selectedLayers.layers[0].frame.x 70 | }else if(firstBarVal < 0){ 71 | baseLine = selectedLayers.layers[0].frame.x + Math.abs(firstBarVal) 72 | } 73 | } 74 | 75 | for(var i = 0; i 0){ 106 | // Reposition bars with positive values 107 | selectedLayers.layers[i].frame.y = baseLine - Math.abs(newLength); 108 | }else{ 109 | // Reposition bars with negative values 110 | selectedLayers.layers[i].frame.y = baseLine; 111 | } 112 | }else{ 113 | // Reset position, just in case 114 | selectedLayers.layers[i].frame.x = baseLine; 115 | 116 | // Change width 117 | selectedLayers.layers[i].frame.width = Math.abs(newLength); 118 | 119 | // Reposition bars with negative values 120 | if(newLength < 0){ 121 | selectedLayers.layers[i].frame.x = selectedLayers.layers[i].frame.x - Math.abs(newLength) 122 | } 123 | } 124 | 125 | // Rename layer 126 | // Data value will be added to layer name 127 | // Example: Rectangle ==> Rectangle {:12:} 128 | selectedLayers.layers[i].name = renameLayer(selectedLayers.layers[i].name, response.numbers[i]) 129 | } 130 | 131 | // Notification 132 | // Alert in case number of selected layers 133 | // does not match amount of numbers 134 | if(alert_diff != 0){ 135 | if(alert_diff > 0){ 136 | sketch.UI.alert(`😇 Just letting you know`, `Only the first ${response.numbers.length} of your selected layer(s) have been adjusted. There weren't enough number values to adjust the last ${Math.abs(alert_diff)} layer(s). Maybe check the separator options (comma, etc).`); 137 | }else if(alert_diff < 0){ 138 | sketch.UI.alert(`😇 Just letting you know`, `The last ${Math.abs(alert_diff)} values weren't used as there weren't enough layer(s) selected.`) 139 | } 140 | } 141 | } 142 | 143 | function getMinMax(arr, isVertical){ 144 | // arr needs to be doc.selectedLayers 145 | var min = 0; 146 | var max = 0; 147 | 148 | if(isVertical){ 149 | // Vertical bar chart (get minMax height) 150 | for(var i = 0; imax){ 154 | max = thisHeight 155 | } 156 | // Min 157 | if(min == 0){ 158 | // set min at first runfirst 159 | min = max 160 | } 161 | if(thisHeight < min){ 162 | min = thisHeight 163 | } 164 | } 165 | }else{ 166 | // Horizontal bar chart (get minMax width) 167 | for(var i = 0; i max){ 171 | max = thisWidth 172 | } 173 | // Min 174 | if(min == 0){ 175 | // set min at first run 176 | min = max 177 | } 178 | if(thisWidth < min){ 179 | min = thisWidth 180 | } 181 | } 182 | } 183 | 184 | return [Math.ceil(min), Math.ceil(max)] 185 | } 186 | 187 | function myinput(myMinMax=[20,100], numOfBars="", myBarHeightFromSelection, my_isVertical){ 188 | var myresponse = { 189 | code: null, 190 | max: null, 191 | forcetype : false, 192 | numbers: [], 193 | trendTypeInput: null 194 | } 195 | 196 | if(myMinMax.length != 2 || myMinMax[0]==myMinMax[1]){ 197 | if(myMinMax[0] > 100){ 198 | myMinMax = [20,myMinMax[1]] 199 | }else{ 200 | myMinMax = [myMinMax[0],100] 201 | } 202 | 203 | } 204 | 205 | if(numOfBars==0){ 206 | myresponse.code == 1001 207 | sketch.UI.alert("Sorry buddy", "You need to select multiple rectangles (bars) for this plugin to work.") 208 | } 209 | if(numOfBars!=0){ 210 | 211 | if(numOfBars==1){ 212 | sketch.UI.alert("Hey, just letting you know", "Most awesome results come when selecting more than 1 bar.") 213 | } 214 | 215 | // Create initial view panel 216 | var width = 260 217 | var height = 40 218 | 219 | // Number input 220 | var sampleNumbers = myBarHeightFromSelection; 221 | 222 | /* 223 | Setup the window 224 | */ 225 | 226 | var alert = COSAlertWindow.new() 227 | if(numOfBars==1){ 228 | alert.setMessageText("1 layer selected to create bar chart") 229 | }else{ 230 | alert.setMessageText(`${numOfBars} layers selected to create bar chart`) 231 | } 232 | alert.addButtonWithTitle("Run") 233 | alert.addButtonWithTitle("Cancel") 234 | alert.setInformativeText(`This is for a bar chart with specific values, rather than random numbers.`) 235 | 236 | /* 237 | Input 238 | */ 239 | var alert_width = 280; 240 | var numInput_separatorOptions = [ 241 | "Comma separated", 242 | "Space separated", 243 | "Tab separated (Excel row)", 244 | "Line break separated (Excel column)", 245 | ] 246 | 247 | var numInput_label = createLabel("Paste in your number values", 12, true, NSMakeRect(0, 0, alert_width, 16)); 248 | var numInput = createTextField(sampleNumbers, null, NSMakeRect(0, 0, alert_width, 25)); 249 | var numInput_separator = createDropdown([ 250 | numInput_separatorOptions[0], 251 | numInput_separatorOptions[1], 252 | numInput_separatorOptions[2], 253 | numInput_separatorOptions[3] 254 | ], NSMakeRect(-2, -1, 170, 30)); 255 | alert.addAccessoryView(numInput_label); 256 | alert.addAccessoryView(numInput); 257 | alert.addAccessoryView(numInput_separator); 258 | 259 | 260 | /* 261 | Bar type: Vertical or horizontal 262 | */ 263 | 264 | var bartype_label = createLabel("Vertical or horizontal?", 12, true, NSMakeRect(0, 0, alert_width, 16)); 265 | alert.addAccessoryView(bartype_label); 266 | 267 | var bartype_radio = NSView.alloc().initWithFrame(NSMakeRect(0, 0, width, 48)) 268 | var buttonFormat; 269 | buttonFormat = NSButtonCell.alloc().init(); 270 | buttonFormat.setButtonType(NSRadioButton); 271 | 272 | var matrixFormat = NSMatrix.alloc().initWithFrame_mode_prototype_numberOfRows_numberOfColumns( 273 | NSMakeRect(0, 0, 260, 48), 274 | NSRadioModeMatrix, 275 | buttonFormat, 2, 1 276 | ); 277 | 278 | matrixFormat.setCellSize(CGSizeMake(260, 25)); 279 | 280 | var bartype_radio1_label = my_isVertical ? "Automatic (vertical detected)" : "Automatic (horizontal detected)" 281 | var bartype_radio2_label = my_isVertical ? "Force horizontal" : "Force vertical" 282 | var cells = matrixFormat.cells(); 283 | cells.objectAtIndex(0).setTitle(bartype_radio1_label); 284 | cells.objectAtIndex(1).setTitle(bartype_radio2_label); 285 | 286 | bartype_radio.addSubview(matrixFormat); 287 | alert.addAccessoryView(bartype_radio) 288 | 289 | 290 | /* 291 | Options 292 | */ 293 | var optionsView_height = 85; 294 | 295 | var optionsView = NSView.alloc().initWithFrame(NSMakeRect(0, 0, alert_width, optionsView_height)); 296 | var optionsLabel = createLabel("Do you want to scale the values?", 12, true, NSMakeRect(0, optionsView_height - 26, alert_width, 16)); 297 | //var optionsLabel_inlineNote = createLabel("(optional)", 12, false, NSMakeRect(215, optionsView_height - 26, alert_width, 16), 0.3); 298 | 299 | var option1_textField = createTextField("", "e.g. 1.5", NSMakeRect(0, optionsView_height-60, 120, 25)); 300 | var option1_label = createLabel("Multiply by", 12, false, NSMakeRect(0, optionsView_height-79, 130, 16)); 301 | 302 | var option2_textField = createTextField("", "e.g. " + 100, NSMakeRect(140, optionsView_height-60, 120, 25)); // prev version showed myMinMax[1] as option 303 | var option2_label = createLabel("or set max height (px)", 12, false, NSMakeRect(140, optionsView_height-79, 130, 16)); 304 | 305 | //var options_info = createLabel("You have the option to define the scaling in case the supplied values don't match your desired pixel values. You can either define a multiplier or set a maximum bar height in pixel.", 11, false, NSMakeRect(0, 0, 260, 16*4)) 306 | var options_info = createLabel("Scale data values in case the supplied numbers don't match the desired pixel values.", 11, false, NSMakeRect(0, 0, 260, 16*2)) 307 | 308 | optionsView.addSubview(optionsLabel); 309 | //optionsView.addSubview(optionsLabel_inlineNote); 310 | 311 | optionsView.addSubview(option1_textField); 312 | optionsView.addSubview(option1_label); 313 | 314 | optionsView.addSubview(option2_textField); 315 | optionsView.addSubview(option2_label); 316 | 317 | alert.addAccessoryView(optionsView); 318 | // alert.addAccessoryView(options_info) 319 | 320 | 321 | /* 322 | Key navigation (popup) 323 | */ 324 | 325 | alert.alert().window().setInitialFirstResponder(numInput); 326 | numInput.setNextKeyView(option1_textField) 327 | option1_textField.setNextKeyView(option2_textField) 328 | option2_textField.setNextKeyView(numInput) 329 | 330 | 331 | /* 332 | Note 333 | */ 334 | 335 | var note_line1 = createLabel("Please make sure proportional scaling is disabled", 11, false, NSMakeRect(0, 0, alert_width+10, 16), 0.3); 336 | alert.addAccessoryView(note_line1); 337 | 338 | 339 | /* 340 | RESPONSE 341 | */ 342 | 343 | var responseCode = alert.runModal(); 344 | 345 | if(responseCode == 1000){ 346 | myresponse.code = 1000 347 | // OK 348 | 349 | // Separator 350 | var sep = "," 351 | var sep_input = numInput_separator.titleOfSelectedItem() 352 | if(sep_input == numInput_separatorOptions[1]){ 353 | sep = " " 354 | }if(sep_input == numInput_separatorOptions[2]){ 355 | sep = "\t" 356 | }else if(sep_input == numInput_separatorOptions[3]){ 357 | sep = "\n" 358 | } 359 | 360 | // Numbers 361 | var numbers_str = ""; 362 | if(numInput.stringValue() == ""){ 363 | numbers_str = sampleNumbers 364 | }else{ 365 | numbers_str = numInput.stringValue(); 366 | } 367 | var numbers_arr = numbers_str.split(sep) 368 | for(var i=0; i=0 ? -1 : 1; 109 | 110 | var new_add = Math.abs(new_diff) / (num_of_colours-1); 111 | var new_dim = col1_rgb[j] + new_dir*(i+1)*new_add; 112 | 113 | new_rgb.push(Math.round(new_dim)) 114 | } 115 | colours.push(rgbToHex(new_rgb)) 116 | } 117 | 118 | colours.push(col2) // last colour 119 | 120 | 121 | // Apply new colours to selection 122 | for(var i = 0; i d8d8d8 154 | return hex.substr(1,6); 155 | } 156 | 157 | function hex_9 (hex_6){ 158 | // d8d8d8 > #d8d8d8ff 159 | return "#" + hex_6 + "ff"; 160 | } 161 | 162 | function rgbToHex(arr){ 163 | var hex = ""; 164 | for(var i=0; i<3; i++){ 165 | var sub = arr[i].toString(16).toUpperCase(); 166 | var padsub = ('0'+sub).slice(-2); 167 | hex = hex + padsub 168 | } 169 | return hex; 170 | } 171 | 172 | function removeHash(hex){ 173 | return hex.substr(0,1)=="#" ? hex.substr(1,6) : hex; 174 | 175 | } -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | export function getSymbolInstances(source,symbolMaster) { 2 | // https://github.com/sonburn/ 3 | var symbolInstances = NSMutableArray.array(); 4 | 5 | source.sketchObject.pages().forEach(function(page){ 6 | var predicate = NSPredicate.predicateWithFormat('className == %@ && symbolMaster.objectID == %@','MSSymbolInstance',symbolMaster.sketchObject.objectID()); 7 | 8 | page.children().filteredArrayUsingPredicate(predicate).forEach(instance => symbolInstances.addObject(instance)); 9 | }); 10 | 11 | return symbolInstances; 12 | } 13 | 14 | export function onlyUnique(value, index, self) { 15 | return self.indexOf(value) === index; 16 | } 17 | 18 | export function iterativeGapFilling(array, length){ 19 | var newArray = []; 20 | for(var i=0; i 1){ 102 | var b = a[1].split(":}"); 103 | if(b.length == 1){return newName;} 104 | var newName = a[0] + "{:" + newVal + ":}" + b[1]; 105 | } 106 | 107 | return newName 108 | } 109 | 110 | 111 | /**********************/ 112 | /* BARCHART */ 113 | /**********************/ 114 | 115 | export function isVerticalBarchart(arr){ 116 | // arr needs to be doc.selectedLayers 117 | var isVertical = true 118 | if(arr.layers.length >= 2 && arr.layers[0].frame.y != arr.layers[1].frame.y){ 119 | // It's horizontal if 120 | // 1. First two bars share same x value (works for positive values) 121 | if(arr.layers[0].frame.x == arr.layers[1].frame.x){ 122 | isVertical = false; 123 | } 124 | // 2. Same y-baseline (works if first value is negative) 125 | // and they share same height 126 | // ! Needs check if first / second val is negative 127 | else if(arr.layers[0].frame.x + arr.layers[0].frame.width == arr.layers[1].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height){ 128 | isVertical = false; 129 | } 130 | else if(arr.layers[1].frame.x + arr.layers[1].frame.width == arr.layers[0].frame.x && arr.layers[0].frame.height == arr.layers[1].frame.height){ 131 | isVertical = false; 132 | } 133 | } 134 | return isVertical 135 | } 136 | 137 | 138 | /**********************/ 139 | /* NON-RANDO BARCHART */ 140 | /**********************/ 141 | 142 | export function getBarHeight(arr, isVertical){ 143 | // arr needs to be doc.selectedLayers 144 | var barLength_str = "" 145 | 146 | for(var i=0; i