├── .babelrc ├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── browser-sync.config.js ├── build ├── .bundle.js.swo ├── bundle.js └── demo.js ├── demo.html ├── demo.js ├── demo.json ├── demo.webpack.config.js ├── demo.xml ├── package.json ├── pages ├── build ├── demo.json └── index.html ├── src ├── index.js └── sbgnStyle │ ├── element.js │ ├── glyph │ ├── auxiliaryItems.js │ ├── baseShapes.js │ ├── containerNodes.js │ ├── entityPoolNodes.js │ ├── index.js │ └── processNodes.js │ ├── index.js │ └── util │ ├── sbgn.js │ └── svg.js ├── test-data.js ├── test ├── shapeTest.js ├── test.js └── testenv │ └── tests.html └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "env" 4 | ], 5 | "ignore": "node_modules/**/*" 6 | } 7 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "es6": true, 6 | "node": true, 7 | "mocha": true 8 | }, 9 | "extends": "eslint:recommended", 10 | "parserOptions": { 11 | "ecmaFeatures": { 12 | "jsx": true 13 | } 14 | }, 15 | "plugins": [], 16 | "rules": { 17 | "semi": "error" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | 4 | 5 | test/testenv/test-bundle.js 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | 11 | # Runtime data 12 | pids 13 | *.pid 14 | *.seed 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # node-waf configuration 29 | .lock-wscript 30 | 31 | # Compiled binary addons (http://nodejs.org/api/addons.html) 32 | build/Release 33 | 34 | # Dependency directories 35 | node_modules 36 | jspm_packages 37 | 38 | # Optional npm cache directory 39 | .npm 40 | 41 | # Optional REPL history 42 | .node_repl_history 43 | 44 | .DS_Store 45 | 46 | demo/browserify-bundle.js 47 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6" 4 | - "7" 5 | - "8" 6 | - "stable" 7 | sudo: false 8 | script: npm run test 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Dylan Fong 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the “Software”), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cytoscape-sbgn-stylesheet 2 | A Cytoscape.js package that provides SBGN specific glyph styles ([demo](https://pathwaycommons.github.io/cytoscape-sbgn-stylesheet/)) 3 | 4 | ### Purpose 5 | To render SBGN-PD(Systems Biology Graphical Notation) graphs -- a visual language for representing biological processes. 6 | 7 | ### Installation 8 | Install via npm 9 | 10 | ``` 11 | npm install cytoscape-sbgn-stylesheet 12 | ``` 13 | 14 | ### Usage 15 | 16 | Initialize cytoscape.js and call this module as a stylesheet parameter 17 | 18 | ```js 19 | var cytoscape = require('cytoscape'); 20 | var sbgnStylesheet = require('cytoscape-sbgn-stylesheet'); 21 | 22 | var cy = cytoscape({ 23 | container: container, 24 | style: sbgnStylesheet(cytoscape), 25 | // other arguments here 26 | }); 27 | 28 | ``` 29 | 30 | ### Requirements 31 | Input needs to be formatted Cytoscape.js graph JSON. 32 | 33 | The following graph JSON structure is required: 34 | ``` 35 | { 36 | nodes: [], // array of nodes 37 | edges: [] // array of edges 38 | } 39 | ``` 40 | 41 | #### Supported SBGN PD glyphs 42 | * simple chemical multimer 43 | * macromolecule multimer 44 | * nucleic acid feature multimer 45 | * complex multimer 46 | * simple chemical 47 | * macromolecule 48 | * nucleic acid feature 49 | * compartment 50 | * unspecified entity 51 | * perturbing agent 52 | * complex 53 | * phenotype 54 | * tag 55 | * process 56 | * uncertain process 57 | * omitted process 58 | * source and sink 59 | * dissociation 60 | * association 61 | * and 62 | * or 63 | * not 64 | 65 | #### Supported SBGN PD arcs 66 | * necessary stimulation 67 | * production 68 | * consumption 69 | * stimulation 70 | * catalysis 71 | * inhibition 72 | 73 | #### Unsupported SBGN PD glyphs 74 | * submap 75 | * ports 76 | 77 | 78 | The following node JSON structure is required: 79 | ``` 80 | "data": { 81 | "id": "glyph23", // id of the node 82 | "class": "simple chemical", // class of the node (see classes section for a list of supported sbgn glyphs 83 | "label": "Ca2+", // label to be displayed on the node 84 | "parent": "glyph2", // parent node id if any 85 | "clonemarker": false, // whether the node has a clonemarker or not 86 | "stateVariables": [], // an array of state variables 87 | "unitsOfInformation": [], // an array of units of information 88 | } 89 | ``` 90 | The following edge JSON structure is required: 91 | ``` 92 | "data": { 93 | "id": "glyph19-glyph5", // id 94 | "class": "production", // sbgn class 95 | "cardinality": 0, // cardinality 96 | "source": "glyph19", // source node id 97 | "target": "glyph5", // target node id 98 | "portSource": "glyph19", // port of the source 99 | "portTarget": "glyph5" // port of the target 100 | } 101 | ``` 102 | 103 | To get Cytoscape.js graph JSON, you need the following: 104 | * SBGN-ML files; xml files that represent biological networks. 105 | * An [SBGN-ML to Cytoscape.js converter](https://github.com/PathwayCommons/sbgnml-to-cytoscape). 106 | 107 | 108 | #### Style Incompatibilities 109 | 110 | The following cytoscape.js style properties are used to render SBGN PD graphics. Overriding these entirely will produce unexpected behaviour: 111 | * ```shape``` 112 | * ```width``` 113 | * ```height``` 114 | * ```background-image``` 115 | * ```background-width``` 116 | * ```background-position-x``` 117 | * ```background-position-y``` 118 | * ```background-fit``` 119 | * ```background-clip``` 120 | * ```padding``` 121 | * ```border-width``` 122 | 123 | ## Run targets 124 | 125 | - `npm run build` : build project 126 | - `npm run build-prod` : build the project for production 127 | - `npm run bundle-profile` : visualise the bundle dependencies 128 | - `npm run clean` : clean the project 129 | - `npm run watch` : watch mode (debug mode enabled, autorebuild, autoreload) 130 | - `npm test` : run tests 131 | - `npm run lint` : lint the project 132 | 133 | ## Testing 134 | 135 | All files `/test` will be run by [Mocha](https://mochajs.org/). You can `npm test` to run all tests, or you can run `mocha -g specific-test-name` (prerequisite: `npm install -g mocha`) to run specific tests. 136 | 137 | [Chai](http://chaijs.com/) is included to make the tests easier to read and write. 138 | 139 | ## Publishing a release 140 | 141 | 1. Make sure the tests are passing: `npm test` 142 | 1. Do a prod build: `npm run build-prod` 143 | 1. Make sure the linting is passing: `npm run lint` 144 | 1. Bump the version number with `npm version`, in accordance with [semver](http://semver.org/). The `version` command in `npm` updates both `package.json` and git tags, but note that it uses a `v` prefix on the tags (e.g. `v1.2.3`). 145 | 1. For a bug fix / patch release, run `npm version patch`. 146 | 1. For a new feature release, run `npm version minor`. 147 | 1. For a breaking API change, run `npm version major.` 148 | 1. For a specific version number (e.g. 1.2.3), run `npm version 1.2.3`. 149 | 1. Push the release: `git push origin --tags` 150 | 1. Publish to npm: `npm publish .` 151 | -------------------------------------------------------------------------------- /browser-sync.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | port: 3001, 3 | ghostMode: false, 4 | notify: false, 5 | server: true, 6 | startPath: "demo.html", 7 | files: [ 'build/*', 'demo.html' ] 8 | }; 9 | -------------------------------------------------------------------------------- /build/.bundle.js.swo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PathwayCommons/cytoscape-sbgn-stylesheet/c5760ad13788f23c2b72774c304467c5018254ed/build/.bundle.js.swo -------------------------------------------------------------------------------- /build/bundle.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(require("lodash.memoize"), require("text-width")); 4 | else if(typeof define === 'function' && define.amd) 5 | define(["lodash.memoize", "text-width"], factory); 6 | else if(typeof exports === 'object') 7 | exports["cytoscapeSbgnStylesheet"] = factory(require("lodash.memoize"), require("text-width")); 8 | else 9 | root["cytoscapeSbgnStylesheet"] = factory(root["lodash.memoize"], root["text-width"]); 10 | })(typeof self !== 'undefined' ? self : this, function(__WEBPACK_EXTERNAL_MODULE_5__, __WEBPACK_EXTERNAL_MODULE_10__) { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | /******/ 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | /******/ 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) { 20 | /******/ return installedModules[moduleId].exports; 21 | /******/ } 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ i: moduleId, 25 | /******/ l: false, 26 | /******/ exports: {} 27 | /******/ }; 28 | /******/ 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | /******/ 32 | /******/ // Flag the module as loaded 33 | /******/ module.l = true; 34 | /******/ 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | /******/ 39 | /******/ 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | /******/ 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | /******/ 46 | /******/ // define getter function for harmony exports 47 | /******/ __webpack_require__.d = function(exports, name, getter) { 48 | /******/ if(!__webpack_require__.o(exports, name)) { 49 | /******/ Object.defineProperty(exports, name, { 50 | /******/ configurable: false, 51 | /******/ enumerable: true, 52 | /******/ get: getter 53 | /******/ }); 54 | /******/ } 55 | /******/ }; 56 | /******/ 57 | /******/ // getDefaultExport function for compatibility with non-harmony modules 58 | /******/ __webpack_require__.n = function(module) { 59 | /******/ var getter = module && module.__esModule ? 60 | /******/ function getDefault() { return module['default']; } : 61 | /******/ function getModuleExports() { return module; }; 62 | /******/ __webpack_require__.d(getter, 'a', getter); 63 | /******/ return getter; 64 | /******/ }; 65 | /******/ 66 | /******/ // Object.prototype.hasOwnProperty.call 67 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 68 | /******/ 69 | /******/ // __webpack_public_path__ 70 | /******/ __webpack_require__.p = ""; 71 | /******/ 72 | /******/ // Load entry module and return exports 73 | /******/ return __webpack_require__(__webpack_require__.s = 6); 74 | /******/ }) 75 | /************************************************************************/ 76 | /******/ ([ 77 | /* 0 */ 78 | /***/ (function(module, exports, __webpack_require__) { 79 | 80 | "use strict"; 81 | 82 | 83 | var sbgnDataHandler = { 84 | isMultimer: function isMultimer(node) { 85 | return node.data('class').includes('multimer'); 86 | }, 87 | hasClonemarker: function hasClonemarker(node) { 88 | return node.data('clonemarker'); 89 | }, 90 | getStateVars: function getStateVars(node) { 91 | return node.data('stateVariables'); 92 | }, 93 | getUnitInfos: function getUnitInfos(node) { 94 | return node.data('unitsOfInformation'); 95 | }, 96 | hasAuxItems: function hasAuxItems(node) { 97 | return node.data('stateVariables').length + node.data('unitsOfInformation').length > 0; 98 | }, 99 | sbgnClass: function sbgnClass(element) { 100 | return element.data('class'); 101 | }, 102 | sbgnLabel: function sbgnLabel(element) { 103 | return element.data('label'); 104 | }, 105 | stateVarLabel: function stateVarLabel(stateVar) { 106 | var variable = stateVar.state.variable; 107 | var value = stateVar.state.value; 108 | if (value && variable) { 109 | return value + '@' + variable; 110 | } 111 | if (value) { 112 | return value; 113 | } 114 | 115 | if (variable) { 116 | return variable; 117 | } 118 | return ''; 119 | } 120 | }; 121 | 122 | module.exports = sbgnDataHandler; 123 | 124 | /***/ }), 125 | /* 1 */ 126 | /***/ (function(module, exports, __webpack_require__) { 127 | 128 | "use strict"; 129 | 130 | 131 | var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); 132 | 133 | var styleMap2Str = function styleMap2Str(styleMap) { 134 | if (!styleMap) { 135 | return ''; 136 | } 137 | 138 | var s = ''; 139 | 140 | var _iteratorNormalCompletion = true; 141 | var _didIteratorError = false; 142 | var _iteratorError = undefined; 143 | 144 | try { 145 | for (var _iterator = styleMap[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 146 | var _ref = _step.value; 147 | 148 | var _ref2 = _slicedToArray(_ref, 2); 149 | 150 | var k = _ref2[0]; 151 | var v = _ref2[1]; 152 | 153 | s += k + '=' + '"' + v + '"' + ' '; 154 | } 155 | } catch (err) { 156 | _didIteratorError = true; 157 | _iteratorError = err; 158 | } finally { 159 | try { 160 | if (!_iteratorNormalCompletion && _iterator.return) { 161 | _iterator.return(); 162 | } 163 | } finally { 164 | if (_didIteratorError) { 165 | throw _iteratorError; 166 | } 167 | } 168 | } 169 | 170 | return s; 171 | }; 172 | 173 | var svg = function svg(svgStr) { 174 | var width = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100; 175 | var height = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 100; 176 | 177 | var parser = new DOMParser(); 178 | var svgText = '' + svgStr + ''; 179 | return parser.parseFromString(svgText, 'text/xml').documentElement; 180 | }; 181 | 182 | var svgStr = function svgStr(svgText, viewPortWidth, viewPortHeight, viewBoxX, viewBoxY, viewBoxWidth, viewBoxHeight) { 183 | var s = svg(svgText, viewPortWidth, viewPortHeight, viewBoxX, viewBoxY, viewBoxWidth, viewBoxHeight); 184 | 185 | // base64 186 | // let data = 'data:image/svg+xml;base64,' + btoa(s.outerHTML); 187 | 188 | // uri component string 189 | var data = 'data:image/svg+xml;utf8,' + encodeURIComponent(s.outerHTML); 190 | 191 | return data; 192 | }; 193 | 194 | module.exports = { 195 | svgStr: svgStr, 196 | styleMap2Str: styleMap2Str 197 | }; 198 | 199 | /***/ }), 200 | /* 2 */ 201 | /***/ (function(module, exports, __webpack_require__) { 202 | 203 | "use strict"; 204 | 205 | 206 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } 207 | 208 | var styleMap2Str = __webpack_require__(1).styleMap2Str; 209 | 210 | var baseRectangle = function baseRectangle(x, y, w, h, r1, r2, r3, r4, styleMap) { 211 | return '\n \n '; 212 | }; 213 | 214 | var baseShapes = { 215 | barrel: function barrel(x, y, width, height, styleMap) { 216 | return '\n\n \n \n\n \n\n \n\n \n \n\n '; 217 | }, 218 | circle: function circle(cx, cy, r, styleMap) { 219 | return ''; 220 | }, 221 | clipPath: function clipPath(id, baseShapeFn, baseShapeFnArgs, styleMap) { 222 | return '\n \n \n ' + baseShapeFn.apply(undefined, _toConsumableArray(baseShapeFnArgs)) + '\n \n \n '; 223 | }, 224 | concaveHexagon: function concaveHexagon(x, y, width, height, styleMap) { 225 | return '\n '; 226 | }, 227 | cutRectangle: function cutRectangle(x, y, width, height, cornerLength, styleMap) { 228 | return '\n \n '; 229 | }, 230 | ellipse: function ellipse(cx, cy, rx, ry, styleMap) { 231 | return '\n \n '; 232 | }, 233 | hexagon: function hexagon(x, y, width, height, styleMap) { 234 | return '\n '; 235 | }, 236 | line: function line(x1, y1, x2, y2, styleMap) { 237 | return ''; 238 | }, 239 | rectangle: function rectangle(x, y, width, height, styleMap) { 240 | return baseRectangle(x, y, width, height, 0, 0, 0, 0, styleMap); 241 | }, 242 | roundBottomRectangle: function roundBottomRectangle(x, y, width, height, styleMap) { 243 | return baseRectangle(x, y, width, height, 0, 0, .3 * height, .3 * height, styleMap); 244 | }, 245 | roundRectangle: function roundRectangle(x, y, width, height, styleMap) { 246 | return baseRectangle(x, y, width, height, .04 * width, .04 * width, .04 * width, .04 * width, styleMap); 247 | }, 248 | stadium: function stadium(x, y, width, height, styleMap) { 249 | var radiusRatio = .24 * Math.max(width, height); 250 | return baseRectangle(x, y, width, height, radiusRatio, radiusRatio, radiusRatio, radiusRatio, styleMap); 251 | }, 252 | square: function square(x, y, length, styleMap) { 253 | return baseRectangle(x, y, length, length, 0, 0, 0, 0, styleMap); 254 | }, 255 | text: function text(t, x, y, styleMap) { 256 | return '' + t + ''; 257 | } 258 | }; 259 | 260 | module.exports = baseShapes; 261 | 262 | /***/ }), 263 | /* 3 */ 264 | /***/ (function(module, exports, __webpack_require__) { 265 | 266 | "use strict"; 267 | 268 | 269 | var sbgnData = __webpack_require__(0); 270 | 271 | var sbgnStyle = new Map().set('unspecified entity', { w: 32, h: 32, shape: 'ellipse' }).set('simple chemical', { w: 48, h: 48, shape: 'ellipse' }).set('simple chemical multimer', { w: 48, h: 48, shape: 'ellipse' }).set('macromolecule', { w: 96, h: 48, shape: 'roundrectangle' }).set('macromolecule multimer', { w: 96, h: 48, shape: 'roundrectangle' }).set('nucleic acid feature', { w: 88, h: 56, shape: 'bottomroundrectangle' }).set('nucleic acid feature multimer', { w: 88, h: 52, shape: 'bottomroundrectangle' }).set('complex', { w: 10, h: 10, shape: 'cutrectangle' }).set('complex multimer', { w: 10, h: 10, shape: 'cutrectangle' }).set('source and sink', { w: 60, h: 60, shape: 'polygon' }).set('perturbing agent', { w: 140, h: 60, shape: 'concavehexagon' }).set('phenotype', { w: 140, h: 60, shape: 'hexagon' }).set('process', { w: 25, h: 25, shape: 'square' }).set('uncertain process', { w: 25, h: 25, shape: 'square' }).set('omitted process', { w: 25, h: 25, shape: 'square' }).set('association', { w: 25, h: 25, shape: 'ellipse' }).set('dissociation', { w: 25, h: 25, shape: 'ellipse' }).set('compartment', { w: 50, h: 50, shape: 'barrel' }).set('tag', { w: 100, h: 65, shape: 'tag' }).set('and', { w: 40, h: 40, shape: 'ellipse' }).set('or', { w: 40, h: 40, shape: 'ellipse' }).set('not', { w: 40, h: 40, shape: 'ellipse' }); 272 | 273 | var sbgnArrowMap = new Map().set('necessary stimulation', 'triangle-cross').set('inhibition', 'tee').set('catalysis', 'circle').set('stimulation', 'triangle').set('production', 'triangle').set('modulation', 'diamond'); 274 | 275 | var elementStyle = { 276 | sbgnShape: function sbgnShape(node) { 277 | var sbgnClass = sbgnData.sbgnClass(node).replace(' multimer', ''); 278 | var style = sbgnStyle.get(sbgnClass); 279 | return style ? style.shape : 'ellipse'; 280 | }, 281 | sbgnArrowShape: function sbgnArrowShape(edge) { 282 | var sbgnClass = sbgnData.sbgnClass(edge); 283 | var shape = sbgnArrowMap.get(sbgnClass); 284 | return shape ? shape : 'none'; 285 | }, 286 | sbgnContent: function sbgnContent(node) { 287 | var sbgnClass = sbgnData.sbgnClass(node).replace(' multimer', ''); 288 | var content = sbgnData.sbgnLabel(node); 289 | 290 | if (sbgnClass == 'and') { 291 | content = 'AND'; 292 | } 293 | if (sbgnClass == 'or') { 294 | content = 'OR'; 295 | } 296 | if (sbgnClass == 'not') { 297 | content = 'NOT'; 298 | } 299 | if (sbgnClass == 'omitted process') { 300 | content = '\\\\'; 301 | } 302 | if (sbgnClass == 'uncertain process') { 303 | content = '?'; 304 | } 305 | 306 | return content; 307 | }, 308 | dimensions: function dimensions(node) { 309 | var sbgnClass = sbgnData.sbgnClass(node); 310 | var dim = sbgnStyle.get(sbgnClass); 311 | if (dim == null) { 312 | throw new TypeError(sbgnClass + ' does not have a default width / height'); 313 | } 314 | return dim; 315 | }, 316 | width: function width(node) { 317 | return this.dimensions(node).w; 318 | }, 319 | height: function height(node) { 320 | return this.dimensions(node).h; 321 | } 322 | }; 323 | 324 | module.exports = elementStyle; 325 | 326 | /***/ }), 327 | /* 4 */ 328 | /***/ (function(module, exports, __webpack_require__) { 329 | 330 | "use strict"; 331 | 332 | 333 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } 334 | 335 | var textWidth = __webpack_require__(10); 336 | 337 | var baseShapes = __webpack_require__(2); 338 | var sbgnData = __webpack_require__(0); 339 | 340 | var auxiliaryItems = { 341 | multiImgCloneMarker: function multiImgCloneMarker(x, y, width, height) { 342 | 343 | var cloneStyle = new Map().set('stroke', '#6A6A6A').set('stroke-width', '1').set('fill', '#D2D2D2'); 344 | 345 | return baseShapes.rectangle(x, y, width, height, cloneStyle); 346 | }, 347 | multiImgUnitOfInformation: function multiImgUnitOfInformation(x, y, width, height, uInfo) { 348 | var borderWidth = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 3; 349 | var fontSize = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 14; 350 | 351 | var text = uInfo.label.text; 352 | var uinfoRectStyle = new Map().set('stroke', '#555555').set('stroke-width', '' + borderWidth).set('fill', 'white').set('fill-opacity', 1); 353 | 354 | var textStyle = new Map().set('alignment-baseline', 'middle').set('font-size', fontSize + 'px').set('font-family', 'Helvetica Neue, Helvetica, sans-serif').set('text-anchor', 'middle'); 355 | 356 | var uInfoWidth = textWidth(text, { family: textStyle.get('font-family'), size: fontSize }) + 5; 357 | 358 | var unitOfInformationSvg = '\n ' + baseShapes.roundRectangle(x, y, uInfoWidth, height, uinfoRectStyle) + '\n ' + baseShapes.text(text, x + uInfoWidth / 2, y + height / 2, textStyle) + '\n '; 359 | 360 | return unitOfInformationSvg; 361 | }, 362 | multiImgStateVar: function multiImgStateVar(x, y, width, height, stateVar) { 363 | var borderWidth = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : 3; 364 | var fontSize = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : 14; 365 | 366 | 367 | var stateVarStyle = new Map().set('stroke', '#555555').set('stroke-width', '' + borderWidth).set('fill', 'white').set('fill-opacity', 1); 368 | 369 | var textStyle = new Map().set('alignment-baseline', 'middle').set('font-size', fontSize + 'px').set('font-family', 'Helvetica Neue, Helvetica, sans-serif').set('text-anchor', 'middle'); 370 | 371 | var tw = textWidth(sbgnData.stateVarLabel(stateVar), { family: textStyle.get('font-family'), size: fontSize }) + 10; 372 | var w = Math.max(tw, 30); 373 | var statevariableSvg = '\n ' + baseShapes.stadium(x, y, w, height, stateVarStyle) + '\n ' + baseShapes.text(sbgnData.stateVarLabel(stateVar), x + w / 2, y + height / 2, textStyle) + '\n '; 374 | 375 | return statevariableSvg; 376 | }, 377 | cloneMarker: function cloneMarker(nodeWidth, nodeHeight, shapeFn, shapeFnArgs) { 378 | var clipId = 'clonemarker'; 379 | 380 | var cloneMarkerStyle = new Map().set('stroke', '#6A6A6A').set('stroke-width', '1.5').set('clip-path', 'url(#' + clipId + ')').set('fill', '#D2D2D2'); 381 | 382 | var cloneMarkerSvg = '\n ' + baseShapes.clipPath(clipId, baseShapes.rectangle, [0, 3 * nodeHeight / 4, nodeWidth, nodeHeight, new Map()]) + '\n ' + shapeFn.apply(undefined, _toConsumableArray(shapeFnArgs).concat([cloneMarkerStyle])) + '\n '; 383 | 384 | return cloneMarkerSvg; 385 | } 386 | }; 387 | 388 | module.exports = auxiliaryItems; 389 | 390 | /***/ }), 391 | /* 5 */ 392 | /***/ (function(module, exports) { 393 | 394 | module.exports = __WEBPACK_EXTERNAL_MODULE_5__; 395 | 396 | /***/ }), 397 | /* 6 */ 398 | /***/ (function(module, exports, __webpack_require__) { 399 | 400 | "use strict"; 401 | 402 | 403 | var sbgnStyleSheet = __webpack_require__(7); 404 | 405 | var defaultOptions = {}; 406 | 407 | module.exports = function (cytoscape) { 408 | return sbgnStyleSheet(cytoscape); 409 | }; 410 | 411 | /***/ }), 412 | /* 7 */ 413 | /***/ (function(module, exports, __webpack_require__) { 414 | 415 | "use strict"; 416 | 417 | 418 | var elementStyle = __webpack_require__(3); 419 | var sbgnsvg = __webpack_require__(8); 420 | 421 | var sbgnStyleSheet = function sbgnStyleSheet(cytoscape) { 422 | 423 | return cytoscape.stylesheet() 424 | // general node style 425 | .selector('node').css({ 426 | 'shape': function shape(node) { 427 | return elementStyle.sbgnShape(node); 428 | }, 429 | 'content': function content(node) { 430 | return elementStyle.sbgnContent(node); 431 | }, 432 | 'font-size': 20, 433 | 'width': function width(node) { 434 | return elementStyle.width(node); 435 | }, 436 | 'height': function height(node) { 437 | return elementStyle.height(node); 438 | }, 439 | 'text-valign': 'center', 440 | 'text-halign': 'center', 441 | 'border-width': 1.5, 442 | 'border-color': '#555', 443 | 'background-color': '#f6f6f6', 444 | 'text-opacity': 1, 445 | 'opacity': 1, 446 | 'text-outline-color': 'white', 447 | 'text-outline-opacity': 1, 448 | 'text-outline-width': 0.75 449 | }).selector('node:selected').css({ 450 | 'background-color': '#d67614', 451 | 'target-arrow-color': '#000', 452 | 'text-outline-color': '#000' 453 | }).selector('node:active').css({ 454 | 'overlay-color': '#d67614', 455 | 'overlay-padding': '14' 456 | }) 457 | 458 | // draw sbgn specific styling (auxiliary items, clonemarker, etc.) 459 | .selector('\n node[class="unspecified entity"],\n node[class="simple chemical"], node[class="simple chemical multimer"],\n node[class="macromolecule"], node[class="macromolecule multimer"],\n node[class="nucleic acid feature"], node[class="nucleic acid feature multimer"],\n node[class="perturbing agent"],\n node[class="phenotype"],\n node[class="complex"], node[class="complex multimer"], node[class="compartment"]\n ').css({ 460 | 'background-image': function backgroundImage(node) { 461 | return sbgnsvg.draw(node).bgImage; 462 | }, 463 | 'background-width': function backgroundWidth(node) { 464 | return sbgnsvg.draw(node).bgWidth; 465 | }, 466 | 'background-position-x': function backgroundPositionX(node) { 467 | return sbgnsvg.draw(node).bgPosX; 468 | }, 469 | 'background-position-y': function backgroundPositionY(node) { 470 | return sbgnsvg.draw(node).bgPosY; 471 | }, 472 | 'background-fit': function backgroundFit(node) { 473 | return sbgnsvg.draw(node).bgFit; 474 | }, 475 | 'background-clip': function backgroundClip(node) { 476 | return sbgnsvg.draw(node).bgClip; 477 | }, 478 | 'padding': function padding(node) { 479 | return sbgnsvg.draw(node).padding; 480 | }, 481 | 'border-width': function borderWidth(node) { 482 | return sbgnsvg.draw(node).borderWidth; 483 | } 484 | }).selector('\n node[class="simple chemical multimer"],\n node[class="macromolecule multimer"],\n node[class="nucleic acid feature multimer"],\n node[class="complex multimer"]\n ').css({ 485 | 'ghost': 'yes', 486 | 'ghost-opacity': 1 487 | }).selector('\n node[class="macromolecule multimer"],\n node[class="nucleic acid feature multimer"]\n ').css({ 488 | 'ghost-offset-x': 12, 489 | 'ghost-offset-y': 12 490 | }).selector('\n node[class="simple chemical multimer"]\n ').css({ 491 | 'ghost-offset-x': 5, 492 | 'ghost-offset-y': 5 493 | }).selector('\n node[class="complex multimer"]\n ').css({ 494 | 'ghost-offset-x': 16, 495 | 'ghost-offset-y': 16 496 | }) 497 | 498 | // compound node specific style 499 | .selector('node[class="complex"], node[class="complex multimer"], node[class="compartment"]').css({ 500 | 'compound-sizing-wrt-labels': 'exclude', 501 | 'text-valign': 'bottom', 502 | 'text-halign': 'center' 503 | }) 504 | 505 | // process node specific style 506 | .selector('node[class="association"], node[class="dissociation"]').css({ 507 | 'background-opacity': 1 508 | }).selector('node[class="association"]').css({ 509 | 'background-color': '#6B6B6B' 510 | }) 511 | 512 | // source and sink and dissociation are drawn differently because 513 | // of their unique shape 514 | .selector('node[class="source and sink"]').css({ 515 | 'background-image': function backgroundImage(node) { 516 | return sbgnsvg.draw(node); 517 | }, 518 | 'background-fit': 'none', 519 | 'background-width': '100%', 520 | 'background-height': '100%', 521 | 'background-clip': 'none', 522 | 'background-repeat': 'no-repeat', 523 | 'border-width': 0, 524 | 'shape-polygon-points': '-0.86, 0.5, -0.75, 0.65, -1, 0.95, -0.95, 1, -0.65, 0.75, -0.5, 0.86, 0, 1, 0.5, 0.86, 0.71, 0.71, 0.86, 0.5, 1, 0, 0.86, -0.5, 0.75, -0.65, 1, -0.95, 0.95, -1, 0.65, -0.75, 0.5, -0.86, 0, -1, -0.5, -0.86, -0.71, -0.71, -0.86, -0.5, -1, 0' 525 | }) 526 | 527 | // source and sink and dissociation are drawn differently because 528 | // of their unique shape 529 | .selector('node[class="dissociation"]').css({ 530 | 'background-image': function backgroundImage(node) { 531 | return sbgnsvg.draw(node); 532 | }, 533 | 'background-fit': 'none', 534 | 'background-width': '100%', 535 | 'background-height': '100%', 536 | 'background-clip': 'none', 537 | 'background-repeat': 'no-repeat', 538 | 'border-width': 0 539 | }) 540 | 541 | // edge styling 542 | .selector('edge').css({ 543 | 'arrow-scale': 1.75, 544 | 'curve-style': 'bezier', 545 | 'line-color': '#555', 546 | 'target-arrow-fill': 'hollow', 547 | 'source-arrow-fill': 'hollow', 548 | 'width': 1.5, 549 | 'target-arrow-color': '#555', 550 | 'source-arrow-color': '#555', 551 | 'text-border-color': '#555', 552 | 'color': '#555' 553 | }).selector('edge:selected').css({ 554 | 'color': '#d67614', 555 | 'line-color': '#d67614', 556 | 'text-border-color': '#d67614', 557 | 'source-arrow-color': '#d67614', 558 | 'target-arrow-color': '#d67614' 559 | }).selector('edge:active').css({ 560 | 'background-opacity': 0.7, 'overlay-color': '#d67614', 561 | 'overlay-padding': '8' 562 | }).selector('edge[cardinality > 0]').css({ 563 | 'text-background-shape': 'rectangle', 564 | 'text-border-opacity': '1', 565 | 'text-border-width': '1', 566 | 'text-background-color': 'white', 567 | 'text-background-opacity': '1' 568 | }).selector('edge[class="consumption"][cardinality > 0], edge[class="production"][cardinality > 0]').css({ 569 | 'source-label': function sourceLabel(edge) { 570 | return '' + edge.data('cardinality'); 571 | }, 572 | 'source-text-offset': 10 573 | }).selector('edge[class]').css({ 574 | 'target-arrow-shape': function targetArrowShape(edge) { 575 | return elementStyle.sbgnArrowShape(edge); 576 | }, 577 | 'source-arrow-shape': 'none' 578 | }).selector('edge[class="inhibition"]').css({ 579 | 'target-arrow-fill': 'filled' 580 | }).selector('edge[class="production"]').css({ 581 | 'target-arrow-fill': 'filled' 582 | }) 583 | 584 | // core 585 | .selector('core').css({ 586 | 'selection-box-color': '#d67614', 587 | 'selection-box-opacity': '0.2', 'selection-box-border-color': '#d67614' 588 | }); 589 | }; 590 | 591 | module.exports = sbgnStyleSheet; 592 | 593 | /***/ }), 594 | /* 8 */ 595 | /***/ (function(module, exports, __webpack_require__) { 596 | 597 | "use strict"; 598 | 599 | 600 | var memoize = __webpack_require__(5); 601 | 602 | var containerNodes = __webpack_require__(9); 603 | var entityPoolNodes = __webpack_require__(11); 604 | var processNodes = __webpack_require__(12); 605 | 606 | var sbgnData = __webpack_require__(0); 607 | 608 | var cacheKeyFn = function cacheKeyFn(node) { 609 | return '' + JSON.stringify(node.id()); 610 | }; 611 | 612 | var sbgnNodeShapeMap = new Map() 613 | // process nodes 614 | .set('dissociation', memoize(processNodes.dissociation, cacheKeyFn)).set('phenotype', memoize(processNodes.phenotype, cacheKeyFn)) 615 | 616 | // entity pool nodes 617 | .set('source and sink', memoize(entityPoolNodes.sourceAndSink, cacheKeyFn)).set('unspecified entity', memoize(entityPoolNodes.unspecifiedEntity, cacheKeyFn)).set('simple chemical', memoize(entityPoolNodes.simpleChemical, cacheKeyFn)).set('macromolecule', memoize(entityPoolNodes.macromolecule, cacheKeyFn)).set('nucleic acid feature', memoize(entityPoolNodes.nucleicAcidFeature, cacheKeyFn)).set('complex', memoize(entityPoolNodes.complex, cacheKeyFn)).set('perturbing agent', memoize(entityPoolNodes.perturbingAgent, cacheKeyFn)) 618 | 619 | // container nodes 620 | .set('compartment', memoize(containerNodes.compartment, cacheKeyFn)); 621 | 622 | var draw = function draw(node) { 623 | var sbgnClass = sbgnData.sbgnClass(node).replace(' multimer', ''); 624 | var shapeFn = sbgnNodeShapeMap.get(sbgnClass); 625 | if (shapeFn == null) { 626 | throw new TypeError(sbgnClass + ' does not have a shape implementation'); 627 | } 628 | return shapeFn(node); 629 | }; 630 | 631 | module.exports = { 632 | draw: draw 633 | }; 634 | 635 | /***/ }), 636 | /* 9 */ 637 | /***/ (function(module, exports, __webpack_require__) { 638 | 639 | "use strict"; 640 | 641 | 642 | var svgStr = __webpack_require__(1).svgStr; 643 | var sbgnData = __webpack_require__(0); 644 | var memoize = __webpack_require__(5); 645 | 646 | var auxiliaryItems = __webpack_require__(4); 647 | var baseShapes = __webpack_require__(2); 648 | 649 | var containerNodes = { 650 | compartment: function compartment(node) { 651 | var auxItemWidth = 60; 652 | var auxItemHeight = 40; 653 | var uInfos = sbgnData.getUnitInfos(node); 654 | 655 | var style = new Map().set('stroke', '#555555').set('stroke-width', '6'); 656 | 657 | var uInfoSvg = svgStr(uInfos.length > 0 ? auxiliaryItems.multiImgUnitOfInformation(2, 0, auxItemWidth - 5, auxItemHeight - 3, uInfos[0]) : '', auxItemWidth, auxItemHeight); 658 | 659 | var lineSvg = svgStr(uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', auxItemWidth, auxItemHeight); 660 | 661 | return { 662 | bgImage: [lineSvg, uInfoSvg], 663 | bgWidth: ['100%'], 664 | bgPosX: ['0%', '25%'], 665 | bgPosY: ['19px', '0%'], 666 | bgFit: ['contain', 'none'], 667 | bgClip: 'node', 668 | padding: '38px', 669 | borderWidth: '4' 670 | }; 671 | } 672 | }; 673 | 674 | module.exports = containerNodes; 675 | 676 | /***/ }), 677 | /* 10 */ 678 | /***/ (function(module, exports) { 679 | 680 | module.exports = __WEBPACK_EXTERNAL_MODULE_10__; 681 | 682 | /***/ }), 683 | /* 11 */ 684 | /***/ (function(module, exports, __webpack_require__) { 685 | 686 | "use strict"; 687 | 688 | 689 | var baseShapes = __webpack_require__(2); 690 | var auxiliaryItems = __webpack_require__(4); 691 | 692 | var svgStr = __webpack_require__(1).svgStr; 693 | var getUnitInfos = __webpack_require__(0).getUnitInfos; 694 | var getStateVars = __webpack_require__(0).getStateVars; 695 | var hasClonemarker = __webpack_require__(0).hasClonemarker; 696 | 697 | var element = __webpack_require__(3); 698 | 699 | var entityPoolNodes = { 700 | unspecifiedEntity: function unspecifiedEntity(node) { 701 | var auxItemWidth = 100; 702 | var auxItemHeight = 20; 703 | var borderWidth = 2; 704 | var fontSize = 10; 705 | var uInfos = getUnitInfos(node); 706 | var sVars = getStateVars(node); 707 | 708 | var style = new Map().set('stroke', '#6A6A6A').set('stroke-width', '1'); 709 | 710 | var cloneMarkerSvg = svgStr(hasClonemarker(node) ? auxiliaryItems.multiImgCloneMarker(0, 2, auxItemWidth, auxItemHeight - 3) : '', auxItemWidth, auxItemHeight); 711 | 712 | var uInfoSvg = svgStr(uInfos.length > 0 ? auxiliaryItems.multiImgUnitOfInformation(2, 0, auxItemWidth - 5, auxItemHeight - 3, uInfos[0], borderWidth, fontSize) : '', auxItemWidth, auxItemHeight); 713 | 714 | var sVarSvg = svgStr(sVars.length > 0 ? auxiliaryItems.multiImgStateVar(2, 0, auxItemWidth - 5, auxItemHeight - 3, sVars[0], borderWidth, fontSize) : '', auxItemWidth, auxItemHeight); 715 | 716 | var topLine = svgStr(uInfos.length + sVars.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', auxItemWidth, auxItemHeight); 717 | 718 | var bottomLine = svgStr(hasClonemarker(node) || uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', auxItemWidth, auxItemHeight); 719 | return { 720 | bgImage: [bottomLine, topLine, cloneMarkerSvg, uInfoSvg, sVarSvg], 721 | bgWidth: ['100%', '100%', '100%'], 722 | bgPosX: ['0%', '0%', '0%', '20px', '40px'], 723 | bgPosY: ['52px', '8px', '32px', '44px', '0%'], 724 | bgFit: ['cover', 'cover', 'none', 'none'], 725 | bgClip: 'node', 726 | padding: '8px', 727 | borderWidth: 2 728 | }; 729 | }, 730 | simpleChemical: function simpleChemical(node) { 731 | var auxItemWidth = 100; 732 | var auxItemHeight = 20; 733 | var borderWidth = 2; 734 | var fontSize = 10; 735 | var uInfos = getUnitInfos(node); 736 | 737 | var style = new Map().set('stroke', '#6A6A6A').set('stroke-width', '1'); 738 | 739 | var cloneMarkerSvg = svgStr(hasClonemarker(node) ? auxiliaryItems.multiImgCloneMarker(0, 2, auxItemWidth, auxItemHeight - 3) : '', auxItemWidth, auxItemHeight); 740 | 741 | var uInfoSvg = svgStr(uInfos.length > 0 ? auxiliaryItems.multiImgUnitOfInformation(2, 0, auxItemWidth - 5, auxItemHeight - 3, uInfos[0], borderWidth, fontSize) : '', auxItemWidth, auxItemHeight); 742 | 743 | var topLine = svgStr(uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', auxItemWidth, auxItemHeight); 744 | 745 | var bottomLine = svgStr(hasClonemarker(node) || uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', auxItemWidth, auxItemHeight); 746 | 747 | return { 748 | bgImage: [bottomLine, topLine, cloneMarkerSvg, uInfoSvg], 749 | bgWidth: ['100%', '100%', '100%'], 750 | bgPosX: ['0%', '0%', '0%', '12px'], 751 | bgPosY: ['52px', '8px', '48px', '0px'], 752 | bgFit: ['cover', 'cover', 'none', 'none'], 753 | bgClip: 'node', 754 | padding: '8px', 755 | borderWidth: 2 756 | }; 757 | }, 758 | macromolecule: function macromolecule(node) { 759 | var auxItemWidth = 100; 760 | var auxItemHeight = 20; 761 | var borderWidth = 2; 762 | var fontSize = 10; 763 | var uInfos = getUnitInfos(node); 764 | var sVars = getStateVars(node); 765 | 766 | var style = new Map().set('stroke', '#6A6A6A').set('stroke-width', '1'); 767 | 768 | var cloneMarkerSvg = svgStr(hasClonemarker(node) ? auxiliaryItems.multiImgCloneMarker(0, 2, auxItemWidth, auxItemHeight - 3) : '', auxItemWidth, auxItemHeight); 769 | 770 | var uInfoSvg = svgStr(uInfos.length > 0 ? auxiliaryItems.multiImgUnitOfInformation(2, 0, auxItemWidth - 5, auxItemHeight - 3, uInfos[0], borderWidth, fontSize) : '', auxItemWidth, auxItemHeight); 771 | 772 | var sVarSvg = svgStr(sVars.length > 0 ? auxiliaryItems.multiImgStateVar(2, 0, auxItemWidth - 5, auxItemHeight - 3, sVars[0], borderWidth, fontSize) : '', auxItemWidth, auxItemHeight); 773 | 774 | var topLine = svgStr(uInfos.length + sVars.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', auxItemWidth, auxItemHeight); 775 | 776 | var bottomLine = svgStr(hasClonemarker(node) || uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', auxItemWidth, auxItemHeight); 777 | 778 | return { 779 | bgImage: [bottomLine, topLine, cloneMarkerSvg, uInfoSvg, sVarSvg], 780 | bgWidth: ['100%', '100%', '100%'], 781 | bgPosX: ['0%', '0%', '0%', '20px', '40px'], 782 | bgPosY: ['52px', '8px', '52px', '44px', '0%'], 783 | bgFit: ['cover', 'cover', 'none', 'none'], 784 | bgClip: 'node', 785 | padding: '8px', 786 | borderWidth: 2 787 | }; 788 | }, 789 | nucleicAcidFeature: function nucleicAcidFeature(node) { 790 | var auxItemWidth = 100; 791 | var auxItemHeight = 20; 792 | var borderWidth = 2; 793 | var fontSize = 10; 794 | var uInfos = getUnitInfos(node); 795 | var sVars = getStateVars(node); 796 | 797 | var style = new Map().set('stroke', '#6A6A6A').set('stroke-width', '1'); 798 | 799 | var cloneMarkerSvg = svgStr(hasClonemarker(node) ? auxiliaryItems.multiImgCloneMarker(0, 2, auxItemWidth, auxItemHeight - 3) : '', auxItemWidth, auxItemHeight); 800 | 801 | var uInfoSvg = svgStr(uInfos.length > 0 ? auxiliaryItems.multiImgUnitOfInformation(2, 0, auxItemWidth - 5, auxItemHeight - 3, uInfos[0], borderWidth, fontSize) : '', auxItemWidth, auxItemHeight); 802 | 803 | var sVarSvg = svgStr(sVars.length > 0 ? auxiliaryItems.multiImgStateVar(2, 0, auxItemWidth - 5, auxItemHeight - 3, sVars[0], borderWidth, fontSize) : '', auxItemWidth, auxItemHeight); 804 | 805 | var topLine = svgStr(sVars.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', auxItemWidth, auxItemHeight); 806 | 807 | var bottomLine = svgStr(hasClonemarker(node) || uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', auxItemWidth, auxItemHeight); 808 | 809 | return { 810 | bgImage: [bottomLine, topLine, cloneMarkerSvg, uInfoSvg, sVarSvg], 811 | bgWidth: ['100%', '100%', '100%'], 812 | bgPosX: ['0%', '0%', '0%', '20px', '40px'], 813 | bgPosY: ['52px', '8px', '52px', '44px', '0%'], 814 | bgFit: ['cover', 'cover', 'none', 'none'], 815 | bgClip: 'node', 816 | padding: '8px', 817 | borderWidth: 2 818 | }; 819 | }, 820 | complex: function complex(node) { 821 | var itemW = 60; 822 | var itemH = 24; 823 | var uInfos = getUnitInfos(node); 824 | var sVars = getStateVars(node); 825 | 826 | var images = []; 827 | var bgWidth = []; 828 | var bgHeight = []; 829 | var bgPosX = []; 830 | var bgPosY = []; 831 | var bgFit = []; 832 | 833 | var style = new Map().set('stroke', '#555555').set('stroke-width', '6'); 834 | 835 | // order of svg image generation matters 836 | if (uInfos.length + sVars.length > 0) { 837 | var topLineSvg = svgStr(baseShapes.line(0, 0, itemW, 0, style), itemW, itemH); 838 | images.push(topLineSvg); 839 | bgWidth.push('100%'); 840 | bgPosX.push('0%'); 841 | bgPosY.push('11px'); 842 | bgFit.push('none'); 843 | } 844 | 845 | if (hasClonemarker(node)) { 846 | var bottomLineSvg = svgStr(baseShapes.line(0, 0, itemW, 0, style), itemW, itemH); 847 | images.push(bottomLineSvg); 848 | bgWidth.push('100%'); 849 | bgPosX.push('0%'); 850 | bgPosY.push('100%'); 851 | bgFit.push('none'); 852 | } 853 | 854 | if (hasClonemarker(node)) { 855 | var cloneSvg = svgStr(auxiliaryItems.multiImgCloneMarker(0, 2, itemW, itemH - 3), itemW, itemH); 856 | images.push(cloneSvg); 857 | bgWidth.push('100%'); 858 | bgPosX.push('0%'); 859 | bgPosY.push('100%'); 860 | bgFit.push('none'); 861 | } 862 | 863 | if (uInfos.length > 0) { 864 | var uInfoSvg = svgStr(auxiliaryItems.multiImgUnitOfInformation(2, 0, itemW - 5, itemH - 3, uInfos[0]), itemW, itemH); 865 | images.push(uInfoSvg); 866 | bgPosX.push('25%'); 867 | bgPosY.push('0%'); 868 | bgFit.push('none'); 869 | } 870 | 871 | if (sVars.length > 0) { 872 | var sVarSvg = svgStr(auxiliaryItems.multiImgStateVar(2, 0, itemW - 5, itemH - 3, sVars[0]), itemW, itemH); 873 | images.push(sVarSvg); 874 | bgPosX.push('88%'); 875 | bgPosY.push('0%'); 876 | bgFit.push('none'); 877 | } 878 | 879 | return { 880 | bgImage: images, 881 | bgWidth: bgWidth, 882 | bgPosX: bgPosX, 883 | bgPosY: bgPosY, 884 | bgFit: bgFit, 885 | bgClip: 'node', 886 | padding: '22px', 887 | borderWidth: 4 888 | }; 889 | }, 890 | sourceAndSink: function sourceAndSink(node) { 891 | var _element$dimensions = element.dimensions(node), 892 | nw = _element$dimensions.w, 893 | nh = _element$dimensions.h; 894 | 895 | var centerX = nw / 2; 896 | var centerY = nh / 2; 897 | var radius = (nw - 2) / 2; 898 | 899 | var styleMap = new Map().set('stroke', '#6A6A6A').set('stroke-linecap', 'square').set('stroke-width', '1.5').set('fill', 'none'); 900 | 901 | var shapeArgs = [centerX, centerY, radius]; 902 | 903 | var sourceAndSinkSvg = '\n ' + baseShapes.circle.apply(baseShapes, shapeArgs.concat([styleMap])) + '\n ' + (hasClonemarker(node) ? auxiliaryItems.cloneMarker(nw, nh, baseShapes.circle, shapeArgs) : '') + '\n ' + baseShapes.line(0, nh, nw, 0, styleMap) + '\n '; 904 | 905 | return svgStr(sourceAndSinkSvg, nw, nh, 0, 0, nw, nh); 906 | }, 907 | perturbingAgent: function perturbingAgent(node) { 908 | var auxItemWidth = 100; 909 | var auxItemHeight = 20; 910 | var borderWidth = 2; 911 | var fontSize = 10; 912 | var uInfos = getUnitInfos(node); 913 | 914 | var style = new Map().set('stroke', '#6A6A6A').set('stroke-width', '1'); 915 | 916 | var cloneMarkerSvg = svgStr(hasClonemarker(node) ? auxiliaryItems.multiImgCloneMarker(0, 2, auxItemWidth, auxItemHeight - 3) : '', auxItemWidth, auxItemHeight); 917 | 918 | var uInfoSvg = svgStr(uInfos.length > 0 ? auxiliaryItems.multiImgUnitOfInformation(2, 0, auxItemWidth - 5, auxItemHeight - 3, uInfos[0], borderWidth, fontSize) : '', auxItemWidth, auxItemHeight); 919 | 920 | var topLine = svgStr(uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', auxItemWidth, auxItemHeight); 921 | 922 | var bottomLine = svgStr(hasClonemarker(node) || uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', auxItemWidth, auxItemHeight); 923 | 924 | return { 925 | bgImage: [bottomLine, topLine, cloneMarkerSvg, uInfoSvg], 926 | bgWidth: ['100%', '100%', '100%'], 927 | bgPosX: ['0%', '0%', '0%', '20px'], 928 | bgPosY: ['56px', '8px', '56px', '0%'], 929 | bgFit: ['cover', 'cover', 'none', 'none'], 930 | bgClip: 'node', 931 | padding: '8px', 932 | borderWidth: 2 933 | }; 934 | } 935 | }; 936 | 937 | module.exports = entityPoolNodes; 938 | 939 | /***/ }), 940 | /* 12 */ 941 | /***/ (function(module, exports, __webpack_require__) { 942 | 943 | "use strict"; 944 | 945 | 946 | var baseShapes = __webpack_require__(2); 947 | var auxiliaryItems = __webpack_require__(4); 948 | 949 | var svgStr = __webpack_require__(1).svgStr; 950 | var hasClonemarker = __webpack_require__(0).hasClonemarker; 951 | 952 | var element = __webpack_require__(3); 953 | 954 | var processNodes = { 955 | dissociation: function dissociation(node) { 956 | var _element$dimensions = element.dimensions(node), 957 | nw = _element$dimensions.w, 958 | nh = _element$dimensions.h; 959 | 960 | var centerX = nw / 2; 961 | var centerY = nh / 2; 962 | var outerRadius = (Math.min(nw, nh) - 2) / 2; 963 | var innerRadius = (Math.min(nw, nh) - 2) / 3; 964 | 965 | var styleMap = new Map().set('stroke', '#6A6A6A').set('stroke-width', '2').set('fill', 'none'); 966 | 967 | var dissociationSvg = '\n ' + baseShapes.circle(centerX, centerY, outerRadius, styleMap) + '\n ' + baseShapes.circle(centerX, centerY, innerRadius, styleMap) + '\n '; 968 | return svgStr(dissociationSvg, nw, nh); 969 | }, 970 | phenotype: function phenotype(node) { 971 | var auxItemWidth = 100; 972 | var auxItemHeight = 20; 973 | 974 | var style = new Map().set('stroke', '#6A6A6A').set('stroke-width', '1'); 975 | 976 | var cloneMarkerSvg = svgStr(hasClonemarker(node) ? auxiliaryItems.multiImgCloneMarker(0, 2, auxItemWidth, auxItemHeight - 3) : '', auxItemWidth, auxItemHeight, 0, 0, auxItemWidth, auxItemHeight); 977 | 978 | var bottomLine = svgStr(hasClonemarker(node) ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', auxItemWidth, auxItemHeight, 0, 0, auxItemWidth, auxItemHeight); 979 | 980 | return { 981 | bgImage: [bottomLine, cloneMarkerSvg], 982 | bgWidth: ['100%', '100%'], 983 | bgPosX: ['0%', '0%'], 984 | bgPosY: ['56px', '56px'], 985 | bgFit: ['cover', 'none'], 986 | bgClip: 'node', 987 | padding: '8px', 988 | borderWidth: 2 989 | }; 990 | } 991 | }; 992 | 993 | module.exports = processNodes; 994 | 995 | /***/ }) 996 | /******/ ]); 997 | }); -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | SBGN stylesheet demo 8 | 9 | 10 | 11 | 12 | 35 | 36 | 37 | 38 |

cytoscape-sbgn-stylesheet demo

39 | 40 |
41 |
42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /demo.js: -------------------------------------------------------------------------------- 1 | var sbgnStylesheet = require('./build/bundle.js'); 2 | var cytoscape = window.cytoscape; 3 | 4 | var cy = window.cy = cytoscape({ 5 | container: document.getElementById('cy'), 6 | elements: fetch('./demo.json').then( res => res.json() ), 7 | layout: { name: 'preset' }, 8 | style: sbgnStylesheet(cytoscape) 9 | }); -------------------------------------------------------------------------------- /demo.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "data": { 4 | "id": "glyph23", 5 | "class": "simple chemical", 6 | "label": "Ca2+", 7 | "parent": "glyph2", 8 | "clonemarker": false, 9 | "stateVariables": [], 10 | "unitsOfInformation": [], 11 | "bbox": { 12 | "x": 1409.3416303507177, 13 | "y": 170.3243361927971, 14 | "w": 60, 15 | "h": 60 16 | } 17 | }, 18 | "position": { 19 | "x": 1234.605196936252, 20 | "y": 69.5655680733905 21 | }, 22 | "group": "nodes", 23 | "removed": false, 24 | "selected": false, 25 | "selectable": true, 26 | "locked": false, 27 | "grabbable": true, 28 | "pannable": false, 29 | "classes": "" 30 | }, 31 | { 32 | "data": { 33 | "id": "glyph32", 34 | "class": "phenotype", 35 | "label": "muscle contraction", 36 | "parent": "glyph2", 37 | "clonemarker": false, 38 | "stateVariables": [], 39 | "unitsOfInformation": [], 40 | "bbox": { 41 | "x": 1976.8873538946682, 42 | "y": 651.7369383828263, 43 | "w": 160, 44 | "h": 60 45 | } 46 | }, 47 | "position": { 48 | "x": 2197.7323146171566, 49 | "y": 1095.7604895957215 50 | }, 51 | "group": "nodes", 52 | "removed": false, 53 | "selected": false, 54 | "selectable": true, 55 | "locked": false, 56 | "grabbable": true, 57 | "pannable": false, 58 | "classes": "" 59 | }, 60 | { 61 | "data": { 62 | "id": "glyph37", 63 | "class": "complex", 64 | "label": "", 65 | "parent": "glyph2", 66 | "clonemarker": false, 67 | "stateVariables": [ 68 | { 69 | "id": "glyph37a", 70 | "class": "state variable", 71 | "state": { 72 | "variable": "", 73 | "value": "tense" 74 | } 75 | } 76 | ], 77 | "unitsOfInformation": [], 78 | "bbox": { 79 | "x": 1891.4159362399225, 80 | "y": 479.6244130185455, 81 | "w": 121.5, 82 | "h": 136.5 83 | } 84 | }, 85 | "position": { 86 | "x": 2200.592163339548, 87 | "y": 824.7365081837149 88 | }, 89 | "group": "nodes", 90 | "removed": false, 91 | "selected": false, 92 | "selectable": true, 93 | "locked": false, 94 | "grabbable": true, 95 | "pannable": false, 96 | "classes": "" 97 | }, 98 | { 99 | "data": { 100 | "id": "glyph39", 101 | "class": "macromolecule", 102 | "label": "myosin", 103 | "parent": "glyph37", 104 | "clonemarker": false, 105 | "stateVariables": [], 106 | "unitsOfInformation": [], 107 | "bbox": { 108 | "x": 1891.4159362399225, 109 | "y": 517.1244130185455, 110 | "w": 120, 111 | "h": 60 112 | } 113 | }, 114 | "position": { 115 | "x": 2201.011704216743, 116 | "y": 780.2521185889852 117 | }, 118 | "group": "nodes", 119 | "removed": false, 120 | "selected": false, 121 | "selectable": true, 122 | "locked": false, 123 | "grabbable": true, 124 | "pannable": false, 125 | "classes": "" 126 | }, 127 | { 128 | "data": { 129 | "id": "glyph31", 130 | "class": "macromolecule", 131 | "label": "actin", 132 | "parent": "glyph37", 133 | "clonemarker": false, 134 | "stateVariables": [], 135 | "unitsOfInformation": [], 136 | "bbox": { 137 | "x": 1891.4159362399225, 138 | "y": 442.1244130185455, 139 | "w": 120, 140 | "h": 60 141 | } 142 | }, 143 | "position": { 144 | "x": 2200.1726224623526, 145 | "y": 869.2208977784445 146 | }, 147 | "group": "nodes", 148 | "removed": false, 149 | "selected": false, 150 | "selectable": true, 151 | "locked": false, 152 | "grabbable": true, 153 | "pannable": false, 154 | "classes": "" 155 | }, 156 | { 157 | "data": { 158 | "id": "glyph41", 159 | "class": "process", 160 | "label": "", 161 | "parent": "glyph2", 162 | "clonemarker": false, 163 | "stateVariables": [], 164 | "unitsOfInformation": [], 165 | "bbox": { 166 | "x": 1488.6367504586137, 167 | "y": 248.3516476521878, 168 | "w": 20, 169 | "h": 20 170 | } 171 | }, 172 | "position": { 173 | "x": 1371.5738448257136, 174 | "y": 69.14739321378485 175 | }, 176 | "group": "nodes", 177 | "removed": false, 178 | "selected": false, 179 | "selectable": true, 180 | "locked": false, 181 | "grabbable": true, 182 | "pannable": false, 183 | "classes": "" 184 | }, 185 | { 186 | "data": { 187 | "id": "glyph21", 188 | "class": "macromolecule", 189 | "label": "nAChR", 190 | "parent": "glyph2", 191 | "clonemarker": false, 192 | "stateVariables": [ 193 | { 194 | "id": "glyph21a", 195 | "class": "state variable", 196 | "state": { 197 | "variable": "", 198 | "value": "open" 199 | } 200 | } 201 | ], 202 | "unitsOfInformation": [], 203 | "bbox": { 204 | "x": 1384.4372296707947, 205 | "y": 318.76950553546544, 206 | "w": 120, 207 | "h": 60 208 | } 209 | }, 210 | "position": { 211 | "x": 1369.384921498512, 212 | "y": 215.979564984629 213 | }, 214 | "group": "nodes", 215 | "removed": false, 216 | "selected": false, 217 | "selectable": true, 218 | "locked": false, 219 | "grabbable": true, 220 | "pannable": false, 221 | "classes": "" 222 | }, 223 | { 224 | "data": { 225 | "id": "glyph36", 226 | "class": "complex", 227 | "label": "", 228 | "parent": "glyph2", 229 | "clonemarker": false, 230 | "stateVariables": [], 231 | "unitsOfInformation": [], 232 | "bbox": { 233 | "x": 1804.8844575025842, 234 | "y": 102.97480600819699, 235 | "w": 121.5, 236 | "h": 136.5 237 | } 238 | }, 239 | "position": { 240 | "x": 1817.9165947430324, 241 | "y": 230.45301725763466 242 | }, 243 | "group": "nodes", 244 | "removed": false, 245 | "selected": false, 246 | "selectable": true, 247 | "locked": false, 248 | "grabbable": true, 249 | "pannable": false, 250 | "classes": "" 251 | }, 252 | { 253 | "data": { 254 | "id": "glyph35", 255 | "class": "simple chemical", 256 | "label": "ATP", 257 | "parent": "glyph36", 258 | "clonemarker": false, 259 | "stateVariables": [], 260 | "unitsOfInformation": [], 261 | "bbox": { 262 | "x": 1774.8844575025842, 263 | "y": 140.474806008197, 264 | "w": 60, 265 | "h": 60 266 | } 267 | }, 268 | "position": { 269 | "x": 1819.1560429828219, 270 | "y": 188.21180713306424 271 | }, 272 | "group": "nodes", 273 | "removed": false, 274 | "selected": false, 275 | "selectable": true, 276 | "locked": false, 277 | "grabbable": true, 278 | "pannable": false, 279 | "classes": "" 280 | }, 281 | { 282 | "data": { 283 | "id": "glyph28", 284 | "class": "macromolecule", 285 | "label": "myosin", 286 | "parent": "glyph36", 287 | "clonemarker": false, 288 | "stateVariables": [], 289 | "unitsOfInformation": [], 290 | "bbox": { 291 | "x": 1804.8844575025842, 292 | "y": 65.47480600819699, 293 | "w": 120, 294 | "h": 60 295 | } 296 | }, 297 | "position": { 298 | "x": 1817.9165947430324, 299 | "y": 272.6942273822051 300 | }, 301 | "group": "nodes", 302 | "removed": false, 303 | "selected": false, 304 | "selectable": true, 305 | "locked": false, 306 | "grabbable": true, 307 | "pannable": false, 308 | "classes": "" 309 | }, 310 | { 311 | "data": { 312 | "id": "glyph45", 313 | "class": "association", 314 | "label": "", 315 | "parent": "glyph2", 316 | "clonemarker": false, 317 | "stateVariables": [], 318 | "unitsOfInformation": [], 319 | "bbox": { 320 | "x": 1967.0754642626248, 321 | "y": 151.57845482385733, 322 | "w": 20, 323 | "h": 20 324 | } 325 | }, 326 | "position": { 327 | "x": 1642.8063632769129, 328 | "y": 230.12306141176143 329 | }, 330 | "group": "nodes", 331 | "removed": false, 332 | "selected": false, 333 | "selectable": true, 334 | "locked": false, 335 | "grabbable": true, 336 | "pannable": false, 337 | "classes": "" 338 | }, 339 | { 340 | "data": { 341 | "id": "glyph27", 342 | "class": "macromolecule", 343 | "label": "myosin", 344 | "parent": "glyph2", 345 | "clonemarker": false, 346 | "stateVariables": [], 347 | "unitsOfInformation": [], 348 | "bbox": { 349 | "x": 2003.3717441786537, 350 | "y": 245.72390413349126, 351 | "w": 120, 352 | "h": 60 353 | } 354 | }, 355 | "position": { 356 | "x": 1540.132053723101, 357 | "y": 279.80120982473704 358 | }, 359 | "group": "nodes", 360 | "removed": false, 361 | "selected": false, 362 | "selectable": true, 363 | "locked": false, 364 | "grabbable": true, 365 | "pannable": false, 366 | "classes": "" 367 | }, 368 | { 369 | "data": { 370 | "id": "glyph25", 371 | "class": "simple chemical", 372 | "label": "ATP", 373 | "parent": "glyph2", 374 | "clonemarker": false, 375 | "stateVariables": [], 376 | "unitsOfInformation": [], 377 | "bbox": { 378 | "x": 2054.788436248919, 379 | "y": 96.8211999690675, 380 | "w": 60, 381 | "h": 60 382 | } 383 | }, 384 | "position": { 385 | "x": 1539.5639014474805, 386 | "y": 183.31193386431147 387 | }, 388 | "group": "nodes", 389 | "removed": false, 390 | "selected": false, 391 | "selectable": true, 392 | "locked": false, 393 | "grabbable": true, 394 | "pannable": false, 395 | "classes": "" 396 | }, 397 | { 398 | "data": { 399 | "id": "glyph26", 400 | "class": "macromolecule", 401 | "label": "actin", 402 | "parent": "glyph2", 403 | "clonemarker": false, 404 | "stateVariables": [], 405 | "unitsOfInformation": [], 406 | "bbox": { 407 | "x": 1820.439889522249, 408 | "y": 268.820483039897, 409 | "w": 120, 410 | "h": 60 411 | } 412 | }, 413 | "position": { 414 | "x": 1815.1991122293518, 415 | "y": 382.139183750573 416 | }, 417 | "group": "nodes", 418 | "removed": false, 419 | "selected": false, 420 | "selectable": true, 421 | "locked": false, 422 | "grabbable": true, 423 | "pannable": false, 424 | "classes": "" 425 | }, 426 | { 427 | "data": { 428 | "id": "glyph44", 429 | "class": "dissociation", 430 | "label": "", 431 | "parent": "glyph2", 432 | "clonemarker": false, 433 | "stateVariables": [], 434 | "unitsOfInformation": [], 435 | "bbox": { 436 | "x": 1935.250386913732, 437 | "y": 330.8071031300308, 438 | "w": 20, 439 | "h": 20 440 | } 441 | }, 442 | "position": { 443 | "x": 1813.0103916593941, 444 | "y": 495.46808601139895 445 | }, 446 | "group": "nodes", 447 | "removed": false, 448 | "selected": false, 449 | "selectable": true, 450 | "locked": false, 451 | "grabbable": true, 452 | "pannable": false, 453 | "classes": "" 454 | }, 455 | { 456 | "data": { 457 | "id": "glyph40", 458 | "class": "simple chemical", 459 | "label": "ADP", 460 | "parent": "glyph2", 461 | "clonemarker": false, 462 | "stateVariables": [], 463 | "unitsOfInformation": [], 464 | "bbox": { 465 | "x": 1759.2930830609844, 466 | "y": 647.3483839558924, 467 | "w": 60, 468 | "h": 60 469 | } 470 | }, 471 | "position": { 472 | "x": 2122.661865282198, 473 | "y": 665.6326904740338 474 | }, 475 | "group": "nodes", 476 | "removed": false, 477 | "selected": false, 478 | "selectable": true, 479 | "locked": false, 480 | "grabbable": true, 481 | "pannable": false, 482 | "classes": "" 483 | }, 484 | { 485 | "data": { 486 | "id": "glyph43", 487 | "class": "process", 488 | "label": "", 489 | "parent": "glyph2", 490 | "clonemarker": false, 491 | "stateVariables": [], 492 | "unitsOfInformation": [], 493 | "bbox": { 494 | "x": 1751.2193616265988, 495 | "y": 549.6009389943749, 496 | "w": 20, 497 | "h": 20 498 | } 499 | }, 500 | "position": { 501 | "x": 2201.540688499251, 502 | "y": 568.5858231560827 503 | }, 504 | "group": "nodes", 505 | "removed": false, 506 | "selected": false, 507 | "selectable": true, 508 | "locked": false, 509 | "grabbable": true, 510 | "pannable": false, 511 | "classes": "" 512 | }, 513 | { 514 | "data": { 515 | "id": "glyph33", 516 | "class": "simple chemical", 517 | "label": "Pi", 518 | "parent": "glyph2", 519 | "clonemarker": false, 520 | "stateVariables": [], 521 | "unitsOfInformation": [], 522 | "bbox": { 523 | "x": 1657.0448245589985, 524 | "y": 580.5826529205284, 525 | "w": 60, 526 | "h": 60 527 | } 528 | }, 529 | "position": { 530 | "x": 2279.8999661788876, 531 | "y": 665.7298263988102 532 | }, 533 | "group": "nodes", 534 | "removed": false, 535 | "selected": false, 536 | "selectable": true, 537 | "locked": false, 538 | "grabbable": true, 539 | "pannable": false, 540 | "classes": "" 541 | }, 542 | { 543 | "data": { 544 | "id": "glyph38", 545 | "class": "complex multimer", 546 | "label": "", 547 | "parent": "glyph2", 548 | "clonemarker": false, 549 | "stateVariables": [ 550 | { 551 | "id": "glyph38a", 552 | "class": "state variable", 553 | "state": { 554 | "variable": "", 555 | "value": "relaxed" 556 | } 557 | } 558 | ], 559 | "unitsOfInformation": [], 560 | "bbox": { 561 | "x": 1624.6397609318626, 562 | "y": 402.55565593238714, 563 | "w": 196.5, 564 | "h": 136.5 565 | } 566 | }, 567 | "position": { 568 | "x": 2202.1722769486146, 569 | "y": 281.97139861309836 570 | }, 571 | "group": "nodes", 572 | "removed": false, 573 | "selected": false, 574 | "selectable": true, 575 | "locked": false, 576 | "grabbable": true, 577 | "pannable": false, 578 | "classes": "" 579 | }, 580 | { 581 | "data": { 582 | "id": "glyph46", 583 | "class": "simple chemical", 584 | "label": "ATP", 585 | "parent": "glyph38", 586 | "clonemarker": false, 587 | "stateVariables": [], 588 | "unitsOfInformation": [], 589 | "bbox": { 590 | "x": 1692.1397609318626, 591 | "y": 365.05565593238714, 592 | "w": 60, 593 | "h": 60 594 | } 595 | }, 596 | "position": { 597 | "x": 2201.8585383740638, 598 | "y": 193.410429481047 599 | }, 600 | "group": "nodes", 601 | "removed": false, 602 | "selected": false, 603 | "selectable": true, 604 | "locked": false, 605 | "grabbable": true, 606 | "pannable": false, 607 | "classes": "" 608 | }, 609 | { 610 | "data": { 611 | "id": "glyph30", 612 | "class": "macromolecule", 613 | "label": "actin", 614 | "parent": "glyph38", 615 | "clonemarker": false, 616 | "stateVariables": [], 617 | "unitsOfInformation": [], 618 | "bbox": { 619 | "x": 1587.1397609318626, 620 | "y": 440.05565593238714, 621 | "w": 120, 622 | "h": 60 623 | } 624 | }, 625 | "position": { 626 | "x": 2203.329337099064, 627 | "y": 370.53236774514977 628 | }, 629 | "group": "nodes", 630 | "removed": false, 631 | "selected": false, 632 | "selectable": true, 633 | "locked": false, 634 | "grabbable": true, 635 | "pannable": false, 636 | "classes": "" 637 | }, 638 | { 639 | "data": { 640 | "id": "glyph29", 641 | "class": "macromolecule", 642 | "label": "myosin", 643 | "parent": "glyph38", 644 | "clonemarker": false, 645 | "stateVariables": [], 646 | "unitsOfInformation": [], 647 | "bbox": { 648 | "x": 1587.1397609318626, 649 | "y": 365.05565593238714, 650 | "w": 120, 651 | "h": 60 652 | } 653 | }, 654 | "position": { 655 | "x": 2201.015216798165, 656 | "y": 276.61286375336715 657 | }, 658 | "group": "nodes", 659 | "removed": false, 660 | "selected": false, 661 | "selectable": true, 662 | "locked": false, 663 | "grabbable": true, 664 | "pannable": false, 665 | "classes": "" 666 | }, 667 | { 668 | "data": { 669 | "id": "glyph42", 670 | "class": "association", 671 | "label": "", 672 | "parent": "glyph2", 673 | "clonemarker": false, 674 | "stateVariables": [], 675 | "unitsOfInformation": [], 676 | "bbox": { 677 | "x": 1690.9446371300062, 678 | "y": 251.92937531016833, 679 | "w": 20, 680 | "h": 20 681 | } 682 | }, 683 | "position": { 684 | "x": 2007.2230653255717, 685 | "y": 283.7108784686492 686 | }, 687 | "group": "nodes", 688 | "removed": false, 689 | "selected": false, 690 | "selectable": true, 691 | "locked": false, 692 | "grabbable": true, 693 | "pannable": false, 694 | "classes": "" 695 | }, 696 | { 697 | "data": { 698 | "id": "glyph22", 699 | "class": "simple chemical", 700 | "label": "Ca2+", 701 | "parent": "glyph2", 702 | "clonemarker": false, 703 | "stateVariables": [], 704 | "unitsOfInformation": [], 705 | "bbox": { 706 | "x": 1589.5695675154066, 707 | "y": 232.05000581952652, 708 | "w": 60, 709 | "h": 60 710 | } 711 | }, 712 | "position": { 713 | "x": 2008.9438830755585, 714 | "y": 72.23150482055803 715 | }, 716 | "group": "nodes", 717 | "removed": false, 718 | "selected": false, 719 | "selectable": true, 720 | "locked": false, 721 | "grabbable": true, 722 | "pannable": false, 723 | "classes": "" 724 | }, 725 | { 726 | "data": { 727 | "id": "glyph24", 728 | "class": "process", 729 | "label": "", 730 | "parent": "glyph2", 731 | "clonemarker": false, 732 | "stateVariables": [], 733 | "unitsOfInformation": [], 734 | "bbox": { 735 | "x": 1301.6362730997278, 736 | "y": 398.6650341622118, 737 | "w": 20, 738 | "h": 20 739 | } 740 | }, 741 | "position": { 742 | "x": 1368.5291072898137, 743 | "y": 359.5976077972136 744 | }, 745 | "group": "nodes", 746 | "removed": false, 747 | "selected": false, 748 | "selectable": true, 749 | "locked": false, 750 | "grabbable": true, 751 | "pannable": false, 752 | "classes": "" 753 | }, 754 | { 755 | "data": { 756 | "id": "glyph20", 757 | "class": "macromolecule", 758 | "label": "nAChR", 759 | "parent": "glyph2", 760 | "clonemarker": false, 761 | "stateVariables": [ 762 | { 763 | "id": "glyph20a", 764 | "class": "state variable", 765 | "state": { 766 | "variable": "", 767 | "value": "closed" 768 | } 769 | } 770 | ], 771 | "unitsOfInformation": [], 772 | "bbox": { 773 | "x": 1283.999018133457, 774 | "y": 492.58732111519737, 775 | "w": 120, 776 | "h": 60 777 | } 778 | }, 779 | "position": { 780 | "x": 1365.3513405760298, 781 | "y": 498.03249059468095 782 | }, 783 | "group": "nodes", 784 | "removed": false, 785 | "selected": false, 786 | "selectable": true, 787 | "locked": false, 788 | "grabbable": true, 789 | "pannable": false, 790 | "classes": "" 791 | }, 792 | { 793 | "data": { 794 | "id": "glyph2", 795 | "class": "compartment", 796 | "label": "muscle cytosol", 797 | "clonemarker": false, 798 | "stateVariables": [], 799 | "unitsOfInformation": [], 800 | "bbox": { 801 | "x": 1654.393727191188, 802 | "y": 350.73087219551167, 803 | "w": 862.289418115462, 804 | "h": 663.5121323746293 805 | } 806 | }, 807 | "position": { 808 | "x": 1757.2525815575698, 809 | "y": 585.663028834556 810 | }, 811 | "group": "nodes", 812 | "removed": false, 813 | "selected": false, 814 | "selectable": true, 815 | "locked": false, 816 | "grabbable": true, 817 | "pannable": false, 818 | "classes": "" 819 | }, 820 | { 821 | "data": { 822 | "id": "glyph16", 823 | "class": "process", 824 | "label": "", 825 | "parent": "glyph0", 826 | "clonemarker": false, 827 | "stateVariables": [], 828 | "unitsOfInformation": [], 829 | "bbox": { 830 | "x": 207.27865035440527, 831 | "y": 260.8070789152547, 832 | "w": 20, 833 | "h": 20 834 | } 835 | }, 836 | "position": { 837 | "x": -87.88227756031358, 838 | "y": 351.9597184183295 839 | }, 840 | "group": "nodes", 841 | "removed": false, 842 | "selected": false, 843 | "selectable": true, 844 | "locked": false, 845 | "grabbable": true, 846 | "pannable": false, 847 | "classes": "" 848 | }, 849 | { 850 | "data": { 851 | "id": "glyph47", 852 | "class": "simple chemical", 853 | "label": "acetyl CoA", 854 | "parent": "glyph0", 855 | "clonemarker": false, 856 | "stateVariables": [], 857 | "unitsOfInformation": [], 858 | "bbox": { 859 | "x": 155.17928220362705, 860 | "y": 171.2675330945018, 861 | "w": 60, 862 | "h": 60 863 | } 864 | }, 865 | "position": { 866 | "x": -208.0103304062723, 867 | "y": 273.135587371003 868 | }, 869 | "group": "nodes", 870 | "removed": false, 871 | "selected": false, 872 | "selectable": true, 873 | "locked": false, 874 | "grabbable": true, 875 | "pannable": false, 876 | "classes": "" 877 | }, 878 | { 879 | "data": { 880 | "id": "glyph12", 881 | "class": "simple chemical", 882 | "label": "choline", 883 | "parent": "glyph0", 884 | "clonemarker": false, 885 | "stateVariables": [], 886 | "unitsOfInformation": [], 887 | "bbox": { 888 | "x": 273.0840166839621, 889 | "y": 349.41797443653786, 890 | "w": 60, 891 | "h": 60 892 | } 893 | }, 894 | "position": { 895 | "x": -212.23274557501688, 896 | "y": 423.89923769794325 897 | }, 898 | "group": "nodes", 899 | "removed": false, 900 | "selected": false, 901 | "selectable": true, 902 | "locked": false, 903 | "grabbable": true, 904 | "pannable": false, 905 | "classes": "" 906 | }, 907 | { 908 | "data": { 909 | "id": "glyph15", 910 | "class": "process", 911 | "label": "", 912 | "parent": "glyph0", 913 | "clonemarker": false, 914 | "stateVariables": [], 915 | "unitsOfInformation": [], 916 | "bbox": { 917 | "x": 352.0061729818583, 918 | "y": 433.5590129724641, 919 | "w": 20, 920 | "h": 20 921 | } 922 | }, 923 | "position": { 924 | "x": 275.88008415416454, 925 | "y": 504.97508201006804 926 | }, 927 | "group": "nodes", 928 | "removed": false, 929 | "selected": false, 930 | "selectable": true, 931 | "locked": false, 932 | "grabbable": true, 933 | "pannable": false, 934 | "classes": "" 935 | }, 936 | { 937 | "data": { 938 | "id": "glyph9", 939 | "class": "macromolecule", 940 | "label": "SNARE", 941 | "parent": "glyph0", 942 | "clonemarker": false, 943 | "stateVariables": [], 944 | "unitsOfInformation": [], 945 | "bbox": { 946 | "x": 432.77215278290015, 947 | "y": 618.9409568808867, 948 | "w": 120, 949 | "h": 60 950 | } 951 | }, 952 | "position": { 953 | "x": 471.8375697127895, 954 | "y": 151.32063347240833 955 | }, 956 | "group": "nodes", 957 | "removed": false, 958 | "selected": false, 959 | "selectable": true, 960 | "locked": false, 961 | "grabbable": true, 962 | "pannable": false, 963 | "classes": "" 964 | }, 965 | { 966 | "data": { 967 | "id": "glyph3", 968 | "class": "macromolecule", 969 | "label": "ChAT", 970 | "parent": "glyph0", 971 | "clonemarker": false, 972 | "stateVariables": [], 973 | "unitsOfInformation": [], 974 | "bbox": { 975 | "x": 80.62697950944448, 976 | "y": 284.8423494357676, 977 | "w": 120, 978 | "h": 60 979 | } 980 | }, 981 | "position": { 982 | "x": -88.65649385340895, 983 | "y": 153.6186718124465 984 | }, 985 | "group": "nodes", 986 | "removed": false, 987 | "selected": false, 988 | "selectable": true, 989 | "locked": false, 990 | "grabbable": true, 991 | "pannable": false, 992 | "classes": "" 993 | }, 994 | { 995 | "data": { 996 | "id": "glyph18", 997 | "class": "process", 998 | "label": "", 999 | "parent": "glyph0", 1000 | "clonemarker": false, 1001 | "stateVariables": [], 1002 | "unitsOfInformation": [], 1003 | "bbox": { 1004 | "x": 391.3423913539207, 1005 | "y": 175.79855923606135, 1006 | "w": 20, 1007 | "h": 20 1008 | } 1009 | }, 1010 | "position": { 1011 | "x": 174.31229729898033, 1012 | "y": 353.76323636111226 1013 | }, 1014 | "group": "nodes", 1015 | "removed": false, 1016 | "selected": false, 1017 | "selectable": true, 1018 | "locked": false, 1019 | "grabbable": true, 1020 | "pannable": false, 1021 | "classes": "" 1022 | }, 1023 | { 1024 | "data": { 1025 | "id": "glyph4", 1026 | "class": "macromolecule", 1027 | "label": "vAChT", 1028 | "parent": "glyph0", 1029 | "clonemarker": false, 1030 | "stateVariables": [], 1031 | "unitsOfInformation": [], 1032 | "bbox": { 1033 | "x": 401.0948426971652, 1034 | "y": 80.0319137104878, 1035 | "w": 120, 1036 | "h": 60 1037 | } 1038 | }, 1039 | "position": { 1040 | "x": 175.38354488002722, 1041 | "y": 150.64622355826125 1042 | }, 1043 | "group": "nodes", 1044 | "removed": false, 1045 | "selected": false, 1046 | "selectable": true, 1047 | "locked": false, 1048 | "grabbable": true, 1049 | "pannable": false, 1050 | "classes": "" 1051 | }, 1052 | { 1053 | "data": { 1054 | "id": "glyph13", 1055 | "class": "simple chemical", 1056 | "label": "Ach", 1057 | "parent": "glyph0", 1058 | "clonemarker": false, 1059 | "stateVariables": [], 1060 | "unitsOfInformation": [], 1061 | "bbox": { 1062 | "x": 296.06141509780923, 1063 | "y": 204.40035574974667, 1064 | "w": 60, 1065 | "h": 60 1066 | } 1067 | }, 1068 | "position": { 1069 | "x": 52.987709756276075, 1070 | "y": 354.1511206476554 1071 | }, 1072 | "group": "nodes", 1073 | "removed": false, 1074 | "selected": false, 1075 | "selectable": true, 1076 | "locked": false, 1077 | "grabbable": true, 1078 | "pannable": false, 1079 | "classes": "" 1080 | }, 1081 | { 1082 | "data": { 1083 | "id": "glyph8", 1084 | "class": "macromolecule", 1085 | "label": "CHT1", 1086 | "parent": "glyph0", 1087 | "clonemarker": false, 1088 | "stateVariables": [], 1089 | "unitsOfInformation": [], 1090 | "bbox": { 1091 | "x": 233.13067713678856, 1092 | "y": 493.88399094919043, 1093 | "w": 120, 1094 | "h": 60 1095 | } 1096 | }, 1097 | "position": { 1098 | "x": 271.3344503874855, 1099 | "y": 673.8201635022664 1100 | }, 1101 | "group": "nodes", 1102 | "removed": false, 1103 | "selected": false, 1104 | "selectable": true, 1105 | "locked": false, 1106 | "grabbable": true, 1107 | "pannable": false, 1108 | "classes": "" 1109 | }, 1110 | { 1111 | "data": { 1112 | "id": "glyph6", 1113 | "class": "simple chemical", 1114 | "label": "ACh", 1115 | "parent": "glyph14", 1116 | "clonemarker": false, 1117 | "stateVariables": [], 1118 | "unitsOfInformation": [], 1119 | "bbox": { 1120 | "x": 492.2542134972042, 1121 | "y": 240.85518711003323, 1122 | "w": 60, 1123 | "h": 60 1124 | } 1125 | }, 1126 | "position": { 1127 | "x": 337.4193930595747, 1128 | "y": 354.3103607223483 1129 | }, 1130 | "group": "nodes", 1131 | "removed": false, 1132 | "selected": false, 1133 | "selectable": true, 1134 | "locked": false, 1135 | "grabbable": true, 1136 | "pannable": false, 1137 | "classes": "" 1138 | }, 1139 | { 1140 | "data": { 1141 | "id": "glyph14", 1142 | "class": "compartment", 1143 | "label": "synaptic vesicle", 1144 | "parent": "glyph0", 1145 | "clonemarker": false, 1146 | "stateVariables": [], 1147 | "unitsOfInformation": [], 1148 | "bbox": { 1149 | "x": 492.2542134972042, 1150 | "y": 240.85518711003323, 1151 | "w": 61.5, 1152 | "h": 61.5 1153 | } 1154 | }, 1155 | "position": { 1156 | "x": 337.4193930595747, 1157 | "y": 354.3103607223483 1158 | }, 1159 | "group": "nodes", 1160 | "removed": false, 1161 | "selected": false, 1162 | "selectable": true, 1163 | "locked": false, 1164 | "grabbable": true, 1165 | "pannable": false, 1166 | "classes": "" 1167 | }, 1168 | { 1169 | "data": { 1170 | "id": "glyph0", 1171 | "class": "compartment", 1172 | "label": "synaptic button", 1173 | "clonemarker": false, 1174 | "stateVariables": [], 1175 | "unitsOfInformation": [], 1176 | "bbox": { 1177 | "x": 284.06559650332434, 1178 | "y": 349.4864352956872, 1179 | "w": 528.3772339877597, 1180 | "h": 600.409043170399 1181 | } 1182 | }, 1183 | "position": { 1184 | "x": 141.80241206888627, 1185 | "y": 412.2331935302638 1186 | }, 1187 | "group": "nodes", 1188 | "removed": false, 1189 | "selected": false, 1190 | "selectable": true, 1191 | "locked": false, 1192 | "grabbable": true, 1193 | "pannable": false, 1194 | "classes": "" 1195 | }, 1196 | { 1197 | "data": { 1198 | "id": "glyph5", 1199 | "class": "simple chemical", 1200 | "label": "choline", 1201 | "parent": "glyph1", 1202 | "clonemarker": false, 1203 | "stateVariables": [], 1204 | "unitsOfInformation": [], 1205 | "bbox": { 1206 | "x": 673.7541361913168, 1207 | "y": 591.1376395474406, 1208 | "w": 60, 1209 | "h": 60 1210 | } 1211 | }, 1212 | "position": { 1213 | "x": 793.480241396369, 1214 | "y": 605.1306967237942 1215 | }, 1216 | "group": "nodes", 1217 | "removed": false, 1218 | "selected": false, 1219 | "selectable": true, 1220 | "locked": false, 1221 | "grabbable": true, 1222 | "pannable": false, 1223 | "classes": "" 1224 | }, 1225 | { 1226 | "data": { 1227 | "id": "glyph7", 1228 | "class": "simple chemical", 1229 | "label": "ACh", 1230 | "parent": "glyph1", 1231 | "clonemarker": false, 1232 | "stateVariables": [], 1233 | "unitsOfInformation": [], 1234 | "bbox": { 1235 | "x": 842.867868440539, 1236 | "y": 547.3570926019304, 1237 | "w": 60, 1238 | "h": 60 1239 | } 1240 | }, 1241 | "position": { 1242 | "x": 882.2928388452633, 1243 | "y": 357.34186136664005 1244 | }, 1245 | "group": "nodes", 1246 | "removed": false, 1247 | "selected": false, 1248 | "selectable": true, 1249 | "locked": false, 1250 | "grabbable": true, 1251 | "pannable": false, 1252 | "classes": "" 1253 | }, 1254 | { 1255 | "data": { 1256 | "id": "glyph17", 1257 | "class": "process", 1258 | "label": "", 1259 | "parent": "glyph1", 1260 | "clonemarker": false, 1261 | "stateVariables": [], 1262 | "unitsOfInformation": [], 1263 | "bbox": { 1264 | "x": 780.4404211840899, 1265 | "y": 462.2172628114067, 1266 | "w": 20, 1267 | "h": 20 1268 | } 1269 | }, 1270 | "position": { 1271 | "x": 646.8941101946878, 1272 | "y": 359.3586638434937 1273 | }, 1274 | "group": "nodes", 1275 | "removed": false, 1276 | "selected": false, 1277 | "selectable": true, 1278 | "locked": false, 1279 | "grabbable": true, 1280 | "pannable": false, 1281 | "classes": "" 1282 | }, 1283 | { 1284 | "data": { 1285 | "id": "glyph11", 1286 | "class": "simple chemical", 1287 | "label": "acetate", 1288 | "parent": "glyph1", 1289 | "clonemarker": false, 1290 | "stateVariables": [], 1291 | "unitsOfInformation": [], 1292 | "bbox": { 1293 | "x": 866.343685007812, 1294 | "y": 672.9950321120291, 1295 | "w": 60, 1296 | "h": 60 1297 | } 1298 | }, 1299 | "position": { 1300 | "x": 962.1964798668208, 1301 | "y": 611.0275563691539 1302 | }, 1303 | "group": "nodes", 1304 | "removed": false, 1305 | "selected": false, 1306 | "selectable": true, 1307 | "locked": false, 1308 | "grabbable": true, 1309 | "pannable": false, 1310 | "classes": "" 1311 | }, 1312 | { 1313 | "data": { 1314 | "id": "glyph19", 1315 | "class": "process", 1316 | "label": "", 1317 | "parent": "glyph1", 1318 | "clonemarker": false, 1319 | "stateVariables": [], 1320 | "unitsOfInformation": [], 1321 | "bbox": { 1322 | "x": 771.6065327100307, 1323 | "y": 632.7047526281501, 1324 | "w": 20, 1325 | "h": 20 1326 | } 1327 | }, 1328 | "position": { 1329 | "x": 878.3108322717865, 1330 | "y": 492.6064430254964 1331 | }, 1332 | "group": "nodes", 1333 | "removed": false, 1334 | "selected": false, 1335 | "selectable": true, 1336 | "locked": false, 1337 | "grabbable": true, 1338 | "pannable": false, 1339 | "classes": "" 1340 | }, 1341 | { 1342 | "data": { 1343 | "id": "glyph10", 1344 | "class": "macromolecule", 1345 | "label": "AChE", 1346 | "parent": "glyph1", 1347 | "clonemarker": false, 1348 | "stateVariables": [], 1349 | "unitsOfInformation": [], 1350 | "bbox": { 1351 | "x": 729.7050429901893, 1352 | "y": 725.5935040834514, 1353 | "w": 120, 1354 | "h": 60 1355 | } 1356 | }, 1357 | "position": { 1358 | "x": 1038.2473300230395, 1359 | "y": 496.5128559182721 1360 | }, 1361 | "group": "nodes", 1362 | "removed": false, 1363 | "selected": false, 1364 | "selectable": true, 1365 | "locked": false, 1366 | "grabbable": true, 1367 | "pannable": false, 1368 | "classes": "" 1369 | }, 1370 | { 1371 | "data": { 1372 | "id": "glyph1", 1373 | "class": "compartment", 1374 | "label": "synaptic cleft", 1375 | "clonemarker": false, 1376 | "stateVariables": [], 1377 | "unitsOfInformation": [], 1378 | "bbox": { 1379 | "x": 770.0489105995644, 1380 | "y": 603.9053834474291, 1381 | "w": 254.08954881649527, 1382 | "h": 304.8762412720447 1383 | } 1384 | }, 1385 | "position": { 1386 | "x": 864.4457201088636, 1387 | "y": 484.184708867897 1388 | }, 1389 | "group": "nodes", 1390 | "removed": false, 1391 | "selected": false, 1392 | "selectable": true, 1393 | "locked": false, 1394 | "grabbable": true, 1395 | "pannable": false, 1396 | "classes": "" 1397 | }, 1398 | { 1399 | "data": { 1400 | "id": "glyph8-glyph15", 1401 | "class": "necessary stimulation", 1402 | "cardinality": 0, 1403 | "source": "glyph8", 1404 | "target": "glyph15", 1405 | "bendPointPositions": [], 1406 | "portSource": "glyph8", 1407 | "portTarget": "glyph15" 1408 | }, 1409 | "position": { 1410 | "x": 0, 1411 | "y": 0 1412 | }, 1413 | "group": "edges", 1414 | "removed": false, 1415 | "selected": false, 1416 | "selectable": true, 1417 | "locked": false, 1418 | "grabbable": true, 1419 | "pannable": true, 1420 | "classes": "" 1421 | }, 1422 | { 1423 | "data": { 1424 | "id": "glyph12-glyph16", 1425 | "class": "consumption", 1426 | "cardinality": 0, 1427 | "source": "glyph12", 1428 | "target": "glyph16", 1429 | "bendPointPositions": [], 1430 | "portSource": "glyph12", 1431 | "portTarget": "glyph16" 1432 | }, 1433 | "position": { 1434 | "x": 0, 1435 | "y": 0 1436 | }, 1437 | "group": "edges", 1438 | "removed": false, 1439 | "selected": false, 1440 | "selectable": true, 1441 | "locked": false, 1442 | "grabbable": true, 1443 | "pannable": true, 1444 | "classes": "" 1445 | }, 1446 | { 1447 | "data": { 1448 | "id": "glyph16-glyph13", 1449 | "class": "production", 1450 | "cardinality": 0, 1451 | "source": "glyph16", 1452 | "target": "glyph13", 1453 | "bendPointPositions": [], 1454 | "portSource": "glyph16", 1455 | "portTarget": "glyph13" 1456 | }, 1457 | "position": { 1458 | "x": 0, 1459 | "y": 0 1460 | }, 1461 | "group": "edges", 1462 | "removed": false, 1463 | "selected": false, 1464 | "selectable": true, 1465 | "locked": false, 1466 | "grabbable": true, 1467 | "pannable": true, 1468 | "classes": "" 1469 | }, 1470 | { 1471 | "data": { 1472 | "id": "glyph13-glyph18", 1473 | "class": "consumption", 1474 | "cardinality": 0, 1475 | "source": "glyph13", 1476 | "target": "glyph18", 1477 | "bendPointPositions": [], 1478 | "portSource": "glyph13", 1479 | "portTarget": "glyph18" 1480 | }, 1481 | "position": { 1482 | "x": 0, 1483 | "y": 0 1484 | }, 1485 | "group": "edges", 1486 | "removed": false, 1487 | "selected": false, 1488 | "selectable": true, 1489 | "locked": false, 1490 | "grabbable": true, 1491 | "pannable": true, 1492 | "classes": "" 1493 | }, 1494 | { 1495 | "data": { 1496 | "id": "glyph18-glyph6", 1497 | "class": "production", 1498 | "cardinality": 0, 1499 | "source": "glyph18", 1500 | "target": "glyph6", 1501 | "bendPointPositions": [], 1502 | "portSource": "glyph18", 1503 | "portTarget": "glyph6" 1504 | }, 1505 | "position": { 1506 | "x": 0, 1507 | "y": 0 1508 | }, 1509 | "group": "edges", 1510 | "removed": false, 1511 | "selected": false, 1512 | "selectable": true, 1513 | "locked": false, 1514 | "grabbable": true, 1515 | "pannable": true, 1516 | "classes": "" 1517 | }, 1518 | { 1519 | "data": { 1520 | "id": "glyph4-glyph18", 1521 | "class": "necessary stimulation", 1522 | "cardinality": 0, 1523 | "source": "glyph4", 1524 | "target": "glyph18", 1525 | "bendPointPositions": [], 1526 | "portSource": "glyph4", 1527 | "portTarget": "glyph18" 1528 | }, 1529 | "position": { 1530 | "x": 0, 1531 | "y": 0 1532 | }, 1533 | "group": "edges", 1534 | "removed": false, 1535 | "selected": false, 1536 | "selectable": true, 1537 | "locked": false, 1538 | "grabbable": true, 1539 | "pannable": true, 1540 | "classes": "" 1541 | }, 1542 | { 1543 | "data": { 1544 | "id": "glyph3-glyph16", 1545 | "class": "catalysis", 1546 | "cardinality": 0, 1547 | "source": "glyph3", 1548 | "target": "glyph16", 1549 | "bendPointPositions": [], 1550 | "portSource": "glyph3", 1551 | "portTarget": "glyph16" 1552 | }, 1553 | "position": { 1554 | "x": 0, 1555 | "y": 0 1556 | }, 1557 | "group": "edges", 1558 | "removed": false, 1559 | "selected": false, 1560 | "selectable": true, 1561 | "locked": false, 1562 | "grabbable": true, 1563 | "pannable": true, 1564 | "classes": "" 1565 | }, 1566 | { 1567 | "data": { 1568 | "id": "glyph10-glyph19", 1569 | "class": "catalysis", 1570 | "cardinality": 0, 1571 | "source": "glyph10", 1572 | "target": "glyph19", 1573 | "bendPointPositions": [], 1574 | "portSource": "glyph10", 1575 | "portTarget": "glyph19" 1576 | }, 1577 | "position": { 1578 | "x": 0, 1579 | "y": 0 1580 | }, 1581 | "group": "edges", 1582 | "removed": false, 1583 | "selected": false, 1584 | "selectable": true, 1585 | "locked": false, 1586 | "grabbable": true, 1587 | "pannable": true, 1588 | "classes": "" 1589 | }, 1590 | { 1591 | "data": { 1592 | "id": "glyph7-glyph19", 1593 | "class": "consumption", 1594 | "cardinality": 0, 1595 | "source": "glyph7", 1596 | "target": "glyph19", 1597 | "bendPointPositions": [], 1598 | "portSource": "glyph7", 1599 | "portTarget": "glyph19" 1600 | }, 1601 | "position": { 1602 | "x": 0, 1603 | "y": 0 1604 | }, 1605 | "group": "edges", 1606 | "removed": false, 1607 | "selected": false, 1608 | "selectable": true, 1609 | "locked": false, 1610 | "grabbable": true, 1611 | "pannable": true, 1612 | "classes": "" 1613 | }, 1614 | { 1615 | "data": { 1616 | "id": "glyph19-glyph5", 1617 | "class": "production", 1618 | "cardinality": 0, 1619 | "source": "glyph19", 1620 | "target": "glyph5", 1621 | "bendPointPositions": [], 1622 | "portSource": "glyph19", 1623 | "portTarget": "glyph5" 1624 | }, 1625 | "position": { 1626 | "x": 0, 1627 | "y": 0 1628 | }, 1629 | "group": "edges", 1630 | "removed": false, 1631 | "selected": false, 1632 | "selectable": true, 1633 | "locked": false, 1634 | "grabbable": true, 1635 | "pannable": true, 1636 | "classes": "" 1637 | }, 1638 | { 1639 | "data": { 1640 | "id": "glyph19-glyph11", 1641 | "class": "production", 1642 | "cardinality": 0, 1643 | "source": "glyph19", 1644 | "target": "glyph11", 1645 | "bendPointPositions": [], 1646 | "portSource": "glyph19", 1647 | "portTarget": "glyph11" 1648 | }, 1649 | "position": { 1650 | "x": 0, 1651 | "y": 0 1652 | }, 1653 | "group": "edges", 1654 | "removed": false, 1655 | "selected": false, 1656 | "selectable": true, 1657 | "locked": false, 1658 | "grabbable": true, 1659 | "pannable": true, 1660 | "classes": "" 1661 | }, 1662 | { 1663 | "data": { 1664 | "id": "glyph9-glyph17", 1665 | "class": "necessary stimulation", 1666 | "cardinality": 0, 1667 | "source": "glyph9", 1668 | "target": "glyph17", 1669 | "bendPointPositions": [], 1670 | "portSource": "glyph9", 1671 | "portTarget": "glyph17" 1672 | }, 1673 | "position": { 1674 | "x": 0, 1675 | "y": 0 1676 | }, 1677 | "group": "edges", 1678 | "removed": false, 1679 | "selected": false, 1680 | "selectable": true, 1681 | "locked": false, 1682 | "grabbable": true, 1683 | "pannable": true, 1684 | "classes": "" 1685 | }, 1686 | { 1687 | "data": { 1688 | "id": "glyph6-glyph17", 1689 | "class": "consumption", 1690 | "cardinality": 0, 1691 | "source": "glyph6", 1692 | "target": "glyph17", 1693 | "bendPointPositions": [], 1694 | "portSource": "glyph6", 1695 | "portTarget": "glyph17" 1696 | }, 1697 | "position": { 1698 | "x": 0, 1699 | "y": 0 1700 | }, 1701 | "group": "edges", 1702 | "removed": false, 1703 | "selected": false, 1704 | "selectable": true, 1705 | "locked": false, 1706 | "grabbable": true, 1707 | "pannable": true, 1708 | "classes": "" 1709 | }, 1710 | { 1711 | "data": { 1712 | "id": "glyph17-glyph7", 1713 | "class": "production", 1714 | "cardinality": 0, 1715 | "source": "glyph17", 1716 | "target": "glyph7", 1717 | "bendPointPositions": [], 1718 | "portSource": "glyph17", 1719 | "portTarget": "glyph7" 1720 | }, 1721 | "position": { 1722 | "x": 0, 1723 | "y": 0 1724 | }, 1725 | "group": "edges", 1726 | "removed": false, 1727 | "selected": false, 1728 | "selectable": true, 1729 | "locked": false, 1730 | "grabbable": true, 1731 | "pannable": true, 1732 | "classes": "" 1733 | }, 1734 | { 1735 | "data": { 1736 | "id": "glyph7-glyph24", 1737 | "class": "necessary stimulation", 1738 | "cardinality": 0, 1739 | "source": "glyph7", 1740 | "target": "glyph24", 1741 | "bendPointPositions": [], 1742 | "portSource": "glyph7", 1743 | "portTarget": "glyph24" 1744 | }, 1745 | "position": { 1746 | "x": 0, 1747 | "y": 0 1748 | }, 1749 | "group": "edges", 1750 | "removed": false, 1751 | "selected": false, 1752 | "selectable": true, 1753 | "locked": false, 1754 | "grabbable": true, 1755 | "pannable": true, 1756 | "classes": "" 1757 | }, 1758 | { 1759 | "data": { 1760 | "id": "glyph20-glyph24", 1761 | "class": "consumption", 1762 | "cardinality": 0, 1763 | "source": "glyph20", 1764 | "target": "glyph24", 1765 | "bendPointPositions": [], 1766 | "portSource": "glyph20", 1767 | "portTarget": "glyph24" 1768 | }, 1769 | "position": { 1770 | "x": 0, 1771 | "y": 0 1772 | }, 1773 | "group": "edges", 1774 | "removed": false, 1775 | "selected": false, 1776 | "selectable": true, 1777 | "locked": false, 1778 | "grabbable": true, 1779 | "pannable": true, 1780 | "classes": "" 1781 | }, 1782 | { 1783 | "data": { 1784 | "id": "glyph24-glyph21", 1785 | "class": "production", 1786 | "cardinality": 0, 1787 | "source": "glyph24", 1788 | "target": "glyph21", 1789 | "bendPointPositions": [], 1790 | "portSource": "glyph24", 1791 | "portTarget": "glyph21" 1792 | }, 1793 | "position": { 1794 | "x": 0, 1795 | "y": 0 1796 | }, 1797 | "group": "edges", 1798 | "removed": false, 1799 | "selected": false, 1800 | "selectable": true, 1801 | "locked": false, 1802 | "grabbable": true, 1803 | "pannable": true, 1804 | "classes": "" 1805 | }, 1806 | { 1807 | "data": { 1808 | "id": "glyph41-glyph22", 1809 | "class": "production", 1810 | "cardinality": 0, 1811 | "source": "glyph41", 1812 | "target": "glyph22", 1813 | "bendPointPositions": [], 1814 | "portSource": "glyph41", 1815 | "portTarget": "glyph22" 1816 | }, 1817 | "position": { 1818 | "x": 0, 1819 | "y": 0 1820 | }, 1821 | "group": "edges", 1822 | "removed": false, 1823 | "selected": false, 1824 | "selectable": true, 1825 | "locked": false, 1826 | "grabbable": true, 1827 | "pannable": true, 1828 | "classes": "" 1829 | }, 1830 | { 1831 | "data": { 1832 | "id": "glyph22-glyph42", 1833 | "class": "stimulation", 1834 | "cardinality": 0, 1835 | "source": "glyph22", 1836 | "target": "glyph42", 1837 | "bendPointPositions": [], 1838 | "portSource": "glyph22", 1839 | "portTarget": "glyph42" 1840 | }, 1841 | "position": { 1842 | "x": 0, 1843 | "y": 0 1844 | }, 1845 | "group": "edges", 1846 | "removed": false, 1847 | "selected": false, 1848 | "selectable": true, 1849 | "locked": false, 1850 | "grabbable": true, 1851 | "pannable": true, 1852 | "classes": "" 1853 | }, 1854 | { 1855 | "data": { 1856 | "id": "glyph36-glyph42", 1857 | "class": "consumption", 1858 | "cardinality": 0, 1859 | "source": "glyph36", 1860 | "target": "glyph42", 1861 | "bendPointPositions": [], 1862 | "portSource": "glyph36", 1863 | "portTarget": "glyph42" 1864 | }, 1865 | "position": { 1866 | "x": 0, 1867 | "y": 0 1868 | }, 1869 | "group": "edges", 1870 | "removed": false, 1871 | "selected": false, 1872 | "selectable": true, 1873 | "locked": false, 1874 | "grabbable": true, 1875 | "pannable": true, 1876 | "classes": "" 1877 | }, 1878 | { 1879 | "data": { 1880 | "id": "glyph26-glyph42", 1881 | "class": "consumption", 1882 | "cardinality": 0, 1883 | "source": "glyph26", 1884 | "target": "glyph42", 1885 | "bendPointPositions": [], 1886 | "portSource": "glyph26", 1887 | "portTarget": "glyph42" 1888 | }, 1889 | "position": { 1890 | "x": 0, 1891 | "y": 0 1892 | }, 1893 | "group": "edges", 1894 | "removed": false, 1895 | "selected": false, 1896 | "selectable": true, 1897 | "locked": false, 1898 | "grabbable": true, 1899 | "pannable": true, 1900 | "classes": "" 1901 | }, 1902 | { 1903 | "data": { 1904 | "id": "glyph42-glyph38", 1905 | "class": "production", 1906 | "cardinality": 0, 1907 | "source": "glyph42", 1908 | "target": "glyph38", 1909 | "bendPointPositions": [], 1910 | "portSource": "glyph42", 1911 | "portTarget": "glyph38" 1912 | }, 1913 | "position": { 1914 | "x": 0, 1915 | "y": 0 1916 | }, 1917 | "group": "edges", 1918 | "removed": false, 1919 | "selected": false, 1920 | "selectable": true, 1921 | "locked": false, 1922 | "grabbable": true, 1923 | "pannable": true, 1924 | "classes": "" 1925 | }, 1926 | { 1927 | "data": { 1928 | "id": "glyph38-glyph43", 1929 | "class": "consumption", 1930 | "cardinality": 0, 1931 | "source": "glyph38", 1932 | "target": "glyph43", 1933 | "bendPointPositions": [], 1934 | "portSource": "glyph38", 1935 | "portTarget": "glyph43" 1936 | }, 1937 | "position": { 1938 | "x": 0, 1939 | "y": 0 1940 | }, 1941 | "group": "edges", 1942 | "removed": false, 1943 | "selected": false, 1944 | "selectable": true, 1945 | "locked": false, 1946 | "grabbable": true, 1947 | "pannable": true, 1948 | "classes": "" 1949 | }, 1950 | { 1951 | "data": { 1952 | "id": "glyph43-glyph37", 1953 | "class": "production", 1954 | "cardinality": 0, 1955 | "source": "glyph43", 1956 | "target": "glyph37", 1957 | "bendPointPositions": [], 1958 | "portSource": "glyph43", 1959 | "portTarget": "glyph37" 1960 | }, 1961 | "position": { 1962 | "x": 0, 1963 | "y": 0 1964 | }, 1965 | "group": "edges", 1966 | "removed": false, 1967 | "selected": false, 1968 | "selectable": true, 1969 | "locked": false, 1970 | "grabbable": true, 1971 | "pannable": true, 1972 | "classes": "" 1973 | }, 1974 | { 1975 | "data": { 1976 | "id": "glyph43-glyph33", 1977 | "class": "production", 1978 | "cardinality": 0, 1979 | "source": "glyph43", 1980 | "target": "glyph33", 1981 | "bendPointPositions": [], 1982 | "portSource": "glyph43", 1983 | "portTarget": "glyph33" 1984 | }, 1985 | "position": { 1986 | "x": 0, 1987 | "y": 0 1988 | }, 1989 | "group": "edges", 1990 | "removed": false, 1991 | "selected": false, 1992 | "selectable": true, 1993 | "locked": false, 1994 | "grabbable": true, 1995 | "pannable": true, 1996 | "classes": "" 1997 | }, 1998 | { 1999 | "data": { 2000 | "id": "glyph43-glyph40", 2001 | "class": "production", 2002 | "cardinality": 0, 2003 | "source": "glyph43", 2004 | "target": "glyph40", 2005 | "bendPointPositions": [], 2006 | "portSource": "glyph43", 2007 | "portTarget": "glyph40" 2008 | }, 2009 | "position": { 2010 | "x": 0, 2011 | "y": 0 2012 | }, 2013 | "group": "edges", 2014 | "removed": false, 2015 | "selected": false, 2016 | "selectable": true, 2017 | "locked": false, 2018 | "grabbable": true, 2019 | "pannable": true, 2020 | "classes": "" 2021 | }, 2022 | { 2023 | "data": { 2024 | "id": "glyph37-glyph44", 2025 | "class": "consumption", 2026 | "cardinality": 0, 2027 | "source": "glyph37", 2028 | "target": "glyph44", 2029 | "bendPointPositions": [], 2030 | "portSource": "glyph37", 2031 | "portTarget": "glyph44" 2032 | }, 2033 | "position": { 2034 | "x": 0, 2035 | "y": 0 2036 | }, 2037 | "group": "edges", 2038 | "removed": false, 2039 | "selected": false, 2040 | "selectable": true, 2041 | "locked": false, 2042 | "grabbable": true, 2043 | "pannable": true, 2044 | "classes": "" 2045 | }, 2046 | { 2047 | "data": { 2048 | "id": "glyph44-glyph27", 2049 | "class": "production", 2050 | "cardinality": 0, 2051 | "source": "glyph44", 2052 | "target": "glyph27", 2053 | "bendPointPositions": [], 2054 | "portSource": "glyph44", 2055 | "portTarget": "glyph27" 2056 | }, 2057 | "position": { 2058 | "x": 0, 2059 | "y": 0 2060 | }, 2061 | "group": "edges", 2062 | "removed": false, 2063 | "selected": false, 2064 | "selectable": true, 2065 | "locked": false, 2066 | "grabbable": true, 2067 | "pannable": true, 2068 | "classes": "" 2069 | }, 2070 | { 2071 | "data": { 2072 | "id": "glyph44-glyph26", 2073 | "class": "production", 2074 | "cardinality": 0, 2075 | "source": "glyph44", 2076 | "target": "glyph26", 2077 | "bendPointPositions": [], 2078 | "portSource": "glyph44", 2079 | "portTarget": "glyph26" 2080 | }, 2081 | "position": { 2082 | "x": 0, 2083 | "y": 0 2084 | }, 2085 | "group": "edges", 2086 | "removed": false, 2087 | "selected": false, 2088 | "selectable": true, 2089 | "locked": false, 2090 | "grabbable": true, 2091 | "pannable": true, 2092 | "classes": "" 2093 | }, 2094 | { 2095 | "data": { 2096 | "id": "glyph25-glyph45", 2097 | "class": "consumption", 2098 | "cardinality": 0, 2099 | "source": "glyph25", 2100 | "target": "glyph45", 2101 | "bendPointPositions": [], 2102 | "portSource": "glyph25", 2103 | "portTarget": "glyph45" 2104 | }, 2105 | "position": { 2106 | "x": 0, 2107 | "y": 0 2108 | }, 2109 | "group": "edges", 2110 | "removed": false, 2111 | "selected": false, 2112 | "selectable": true, 2113 | "locked": false, 2114 | "grabbable": true, 2115 | "pannable": true, 2116 | "classes": "" 2117 | }, 2118 | { 2119 | "data": { 2120 | "id": "glyph27-glyph45", 2121 | "class": "consumption", 2122 | "cardinality": 0, 2123 | "source": "glyph27", 2124 | "target": "glyph45", 2125 | "bendPointPositions": [], 2126 | "portSource": "glyph27", 2127 | "portTarget": "glyph45" 2128 | }, 2129 | "position": { 2130 | "x": 0, 2131 | "y": 0 2132 | }, 2133 | "group": "edges", 2134 | "removed": false, 2135 | "selected": false, 2136 | "selectable": true, 2137 | "locked": false, 2138 | "grabbable": true, 2139 | "pannable": true, 2140 | "classes": "" 2141 | }, 2142 | { 2143 | "data": { 2144 | "id": "glyph45-glyph36", 2145 | "class": "production", 2146 | "cardinality": 0, 2147 | "source": "glyph45", 2148 | "target": "glyph36", 2149 | "bendPointPositions": [], 2150 | "portSource": "glyph45", 2151 | "portTarget": "glyph36" 2152 | }, 2153 | "position": { 2154 | "x": 0, 2155 | "y": 0 2156 | }, 2157 | "group": "edges", 2158 | "removed": false, 2159 | "selected": false, 2160 | "selectable": true, 2161 | "locked": false, 2162 | "grabbable": true, 2163 | "pannable": true, 2164 | "classes": "" 2165 | }, 2166 | { 2167 | "data": { 2168 | "id": "glyph21-glyph41", 2169 | "class": "necessary stimulation", 2170 | "cardinality": 0, 2171 | "source": "glyph21", 2172 | "target": "glyph41", 2173 | "bendPointPositions": [], 2174 | "portSource": "glyph21", 2175 | "portTarget": "glyph41" 2176 | }, 2177 | "position": { 2178 | "x": 0, 2179 | "y": 0 2180 | }, 2181 | "group": "edges", 2182 | "removed": false, 2183 | "selected": false, 2184 | "selectable": true, 2185 | "locked": false, 2186 | "grabbable": true, 2187 | "pannable": true, 2188 | "classes": "" 2189 | }, 2190 | { 2191 | "data": { 2192 | "id": "glyph5-glyph15", 2193 | "class": "consumption", 2194 | "cardinality": 0, 2195 | "source": "glyph5", 2196 | "target": "glyph15", 2197 | "bendPointPositions": [], 2198 | "portSource": "glyph5", 2199 | "portTarget": "glyph15" 2200 | }, 2201 | "position": { 2202 | "x": 0, 2203 | "y": 0 2204 | }, 2205 | "group": "edges", 2206 | "removed": false, 2207 | "selected": false, 2208 | "selectable": true, 2209 | "locked": false, 2210 | "grabbable": true, 2211 | "pannable": true, 2212 | "classes": "" 2213 | }, 2214 | { 2215 | "data": { 2216 | "id": "glyph15-glyph12", 2217 | "class": "production", 2218 | "cardinality": 0, 2219 | "source": "glyph15", 2220 | "target": "glyph12", 2221 | "bendPointPositions": [], 2222 | "portSource": "glyph15", 2223 | "portTarget": "glyph12" 2224 | }, 2225 | "position": { 2226 | "x": 0, 2227 | "y": 0 2228 | }, 2229 | "group": "edges", 2230 | "removed": false, 2231 | "selected": false, 2232 | "selectable": true, 2233 | "locked": false, 2234 | "grabbable": true, 2235 | "pannable": true, 2236 | "classes": "" 2237 | }, 2238 | { 2239 | "data": { 2240 | "id": "glyph47-glyph16", 2241 | "class": "consumption", 2242 | "cardinality": 0, 2243 | "source": "glyph47", 2244 | "target": "glyph16", 2245 | "bendPointPositions": [], 2246 | "portSource": "glyph47", 2247 | "portTarget": "glyph16" 2248 | }, 2249 | "position": { 2250 | "x": 0, 2251 | "y": 0 2252 | }, 2253 | "group": "edges", 2254 | "removed": false, 2255 | "selected": false, 2256 | "selectable": true, 2257 | "locked": false, 2258 | "grabbable": true, 2259 | "pannable": true, 2260 | "classes": "" 2261 | }, 2262 | { 2263 | "data": { 2264 | "id": "glyph37-glyph32", 2265 | "class": "stimulation", 2266 | "cardinality": 0, 2267 | "source": "glyph37", 2268 | "target": "glyph32", 2269 | "bendPointPositions": [], 2270 | "portSource": "glyph37", 2271 | "portTarget": "glyph32" 2272 | }, 2273 | "position": { 2274 | "x": 0, 2275 | "y": 0 2276 | }, 2277 | "group": "edges", 2278 | "removed": false, 2279 | "selected": false, 2280 | "selectable": true, 2281 | "locked": false, 2282 | "grabbable": true, 2283 | "pannable": true, 2284 | "classes": "" 2285 | }, 2286 | { 2287 | "data": { 2288 | "id": "glyph23-glyph41", 2289 | "class": "consumption", 2290 | "cardinality": 0, 2291 | "source": "glyph23", 2292 | "target": "glyph41", 2293 | "bendPointPositions": [], 2294 | "portSource": "glyph23", 2295 | "portTarget": "glyph41" 2296 | }, 2297 | "position": { 2298 | "x": 0, 2299 | "y": 0 2300 | }, 2301 | "group": "edges", 2302 | "removed": false, 2303 | "selected": false, 2304 | "selectable": true, 2305 | "locked": false, 2306 | "grabbable": true, 2307 | "pannable": true, 2308 | "classes": "" 2309 | } 2310 | ] -------------------------------------------------------------------------------- /demo.webpack.config.js: -------------------------------------------------------------------------------- 1 | let conf = { 2 | entry: './demo.js', 3 | 4 | devtool: 'inline-source-map', 5 | 6 | output: { 7 | filename: './build/demo.js' 8 | }, 9 | 10 | module: { 11 | rules: [ 12 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' } 13 | ] 14 | } 15 | }; 16 | 17 | module.exports = conf; 18 | -------------------------------------------------------------------------------- /demo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | 22 | 23 | 26 | 27 | 30 | 31 | 34 | 35 | 38 | 39 | 42 | 43 | 46 | 47 | 50 | 51 | 54 | 55 | 56 | 57 | 58 | 61 | 62 | 65 | 66 | 67 | 68 | 69 | 72 | 73 | 76 | 77 | 78 | 79 | 80 | 83 | 84 | 91 | 92 | 93 | 94 | 95 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 111 | 112 | 115 | 116 | 119 | 120 | 121 | 124 | 125 | 126 | 127 | 128 | 131 | 132 | 133 | 134 | 135 | 138 | 139 | 142 | 143 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 155 | 156 | 159 | 160 | 161 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 181 | 182 | 185 | 186 | 187 | 190 | 191 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cytoscape-sbgn-stylesheet", 3 | "version": "4.0.2", 4 | "description": "cytoscape.js stylesheet for sbgn PD glyphs ", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/PathwayCommons/cytoscape-sbgn-stylesheet.git" 8 | }, 9 | "bugs": { 10 | "url": "https://github.com/PathwayCommons/cytoscape-sbgn-stylesheet/issues" 11 | }, 12 | "homepage": "https://github.com/PathwayCommons/cytoscape-sbgn-stylesheet", 13 | "main": "./build/bundle.js", 14 | "scripts": { 15 | "postpublish": "run-s gh-pages", 16 | "gh-pages": "gh-pages -d pages", 17 | "prepublish": "run-s build", 18 | "lint:js": "eslint ./src", 19 | "bundle:js": "webpack", 20 | "bundle:demojs": "webpack --config demo.webpack.config.js", 21 | "watch:js": "webpack --watch", 22 | "watch:sync-bundle": "browser-sync start --config browser-sync.config.js", 23 | "dev": "webpack-dev-server --watch --open --open-page demo.html", 24 | "bundle": "run-s bundle:*", 25 | "build": "run-p bundle", 26 | "build-prod": "cross-env NODE_ENV=production run-s build", 27 | "clean": "rimraf build/*", 28 | "lint": "run-s lint:*", 29 | "watch": "run-p watch:*", 30 | "test": "mocha" 31 | }, 32 | "dependencies": { 33 | "camelcase": "^4.1.0", 34 | "extend": "^3.0.0", 35 | "lodash.defaultsdeep": "^4.6.0", 36 | "lodash.memoize": "^4.1.2", 37 | "text-width": "^1.2.0" 38 | }, 39 | "peerDependencies": { 40 | "cytoscape": "^3.2.0" 41 | }, 42 | "devDependencies": { 43 | "babel-core": "^6.26.0", 44 | "babel-loader": "^7.1.2", 45 | "babel-polyfill": "^6.9.1", 46 | "babel-preset-env": "^1.6.0", 47 | "browser-sync": "^2.18.13", 48 | "chai": "^4.1.2", 49 | "cross-env": "^5.0.0", 50 | "echo-cli": "^1.0.8", 51 | "eslint": "^4.6.1", 52 | "eslint-config-standard": "^10.2.1", 53 | "eslint-plugin-import": "^2.7.0", 54 | "eslint-plugin-node": "^5.1.1", 55 | "eslint-plugin-promise": "^3.5.0", 56 | "eslint-plugin-standard": "^3.0.1", 57 | "gh-pages": "^2.2.0", 58 | "mocha": "^3.5.3", 59 | "npm-run-all": "^4.1.1", 60 | "rimraf": "^2.6.2", 61 | "uglifyjs-webpack-plugin": "^0.4.6", 62 | "webpack": "^3.10.0", 63 | "webpack-bundle-analyzer": "^2.9.0", 64 | "webpack-dev-server": "^2.11.1" 65 | }, 66 | "engines": { 67 | "node": ">=6.3.0" 68 | }, 69 | "browserslist": "last 3 versions, >1%" 70 | } 71 | -------------------------------------------------------------------------------- /pages/build: -------------------------------------------------------------------------------- 1 | ../build -------------------------------------------------------------------------------- /pages/demo.json: -------------------------------------------------------------------------------- 1 | ../demo.json -------------------------------------------------------------------------------- /pages/index.html: -------------------------------------------------------------------------------- 1 | ../demo.html -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | let sbgnStyleSheet = require('./sbgnStyle/'); 2 | 3 | let defaultOptions = { 4 | }; 5 | 6 | module.exports = function(cytoscape){ 7 | return sbgnStyleSheet(cytoscape); 8 | }; 9 | -------------------------------------------------------------------------------- /src/sbgnStyle/element.js: -------------------------------------------------------------------------------- 1 | const sbgnData = require('./util/sbgn.js'); 2 | 3 | const sbgnStyle = new Map() 4 | .set('unspecified entity', {w: 32, h: 32, shape: 'ellipse'}) 5 | .set('simple chemical', {w: 48, h: 48, shape: 'ellipse'}) 6 | .set('simple chemical multimer', {w: 48, h: 48, shape: 'ellipse'}) 7 | .set('macromolecule', {w: 96, h: 48, shape: 'roundrectangle'}) 8 | .set('macromolecule multimer', {w: 96, h: 48, shape: 'roundrectangle'}) 9 | .set('nucleic acid feature', {w: 88, h: 56, shape: 'bottomroundrectangle'}) 10 | .set('nucleic acid feature multimer', {w: 88, h: 52, shape: 'bottomroundrectangle'}) 11 | .set('complex', {w: 10, h: 10, shape: 'cutrectangle'}) 12 | .set('complex multimer', {w: 10, h: 10, shape: 'cutrectangle'}) 13 | .set('source and sink', {w: 60, h: 60, shape: 'polygon'}) 14 | .set('perturbing agent', {w: 140, h: 60, shape: 'concavehexagon'}) 15 | 16 | .set('phenotype', {w: 140, h: 60, shape: 'hexagon'}) 17 | .set('process', {w:25, h: 25, shape: 'square'}) 18 | .set('uncertain process', {w:25, h: 25, shape: 'square'}) 19 | .set('omitted process', {w:25, h: 25, shape: 'square'}) 20 | .set('association', {w:25, h: 25, shape: 'ellipse'}) 21 | .set('dissociation', {w:25, h: 25, shape: 'ellipse'}) 22 | 23 | .set('compartment', {w: 50, h: 50, shape: 'barrel'}) 24 | 25 | .set('tag', {w: 100, h: 65, shape: 'tag'}) 26 | .set('and', {w: 40, h: 40, shape: 'ellipse'}) 27 | .set('or', {w: 40, h: 40, shape: 'ellipse'}) 28 | .set('not', {w: 40, h: 40, shape: 'ellipse'}); 29 | 30 | const sbgnArrowMap = new Map() 31 | .set('necessary stimulation', 'triangle-cross') 32 | .set('inhibition', 'tee') 33 | .set('catalysis', 'circle') 34 | .set('stimulation', 'triangle') 35 | .set('production', 'triangle') 36 | .set('modulation', 'diamond'); 37 | 38 | const elementStyle = { 39 | sbgnShape (node) { 40 | const sbgnClass = sbgnData.sbgnClass(node).replace(' multimer', ''); 41 | const style = sbgnStyle.get(sbgnClass); 42 | return style ? style.shape : 'ellipse'; 43 | }, 44 | 45 | sbgnArrowShape (edge) { 46 | const sbgnClass = sbgnData.sbgnClass(edge); 47 | const shape = sbgnArrowMap.get(sbgnClass); 48 | return shape ? shape : 'none'; 49 | }, 50 | 51 | sbgnContent (node) { 52 | const sbgnClass = sbgnData.sbgnClass(node).replace(' multimer', ''); 53 | let content = sbgnData.sbgnLabel(node); 54 | 55 | if (sbgnClass == 'and') { 56 | content = 'AND'; 57 | } 58 | if (sbgnClass == 'or') { 59 | content = 'OR'; 60 | } 61 | if (sbgnClass == 'not') { 62 | content = 'NOT'; 63 | } 64 | if (sbgnClass == 'omitted process') { 65 | content = '\\\\'; 66 | } 67 | if (sbgnClass == 'uncertain process') { 68 | content = '?'; 69 | } 70 | 71 | return content; 72 | }, 73 | 74 | dimensions (node) { 75 | const sbgnClass = sbgnData.sbgnClass(node); 76 | const dim = sbgnStyle.get(sbgnClass); 77 | if (dim == null) { 78 | throw new TypeError(`${sbgnClass} does not have a default width / height`); 79 | } 80 | return dim; 81 | }, 82 | 83 | width (node) { 84 | return this.dimensions(node).w; 85 | }, 86 | 87 | height (node) { 88 | return this.dimensions(node).h; 89 | } 90 | }; 91 | 92 | module.exports = elementStyle; 93 | -------------------------------------------------------------------------------- /src/sbgnStyle/glyph/auxiliaryItems.js: -------------------------------------------------------------------------------- 1 | const textWidth = require('text-width'); 2 | 3 | const baseShapes = require('./baseShapes.js'); 4 | const sbgnData = require('../util/sbgn'); 5 | 6 | const auxiliaryItems = { 7 | 8 | multiImgCloneMarker (x, y, width, height) { 9 | 10 | const cloneStyle = new Map() 11 | .set('stroke', '#6A6A6A') 12 | .set('stroke-width', '1') 13 | .set('fill', '#D2D2D2'); 14 | 15 | return baseShapes.rectangle(x, y, width, height, cloneStyle); 16 | }, 17 | 18 | multiImgUnitOfInformation (x, y, width, height, uInfo, borderWidth=3, fontSize=14) { 19 | const text = uInfo.label.text; 20 | const uinfoRectStyle = new Map() 21 | .set('stroke', '#555555') 22 | .set('stroke-width', `${borderWidth}`) 23 | .set('fill', 'white') 24 | .set('fill-opacity', 1); 25 | 26 | 27 | const textStyle = new Map() 28 | .set('alignment-baseline', 'middle') 29 | .set('font-size', `${fontSize}px`) 30 | .set('font-family', 'Helvetica Neue, Helvetica, sans-serif') 31 | .set('text-anchor', 'middle'); 32 | 33 | const uInfoWidth = textWidth(text, { family: textStyle.get('font-family'), size: fontSize}) + 5; 34 | 35 | const unitOfInformationSvg = 36 | ` 37 | ${baseShapes.roundRectangle(x, y, uInfoWidth, height, uinfoRectStyle)} 38 | ${baseShapes.text(text, x + (uInfoWidth / 2), y + ( height / 2), textStyle)} 39 | `; 40 | 41 | return unitOfInformationSvg; 42 | }, 43 | 44 | multiImgStateVar (x, y, width, height, stateVar, borderWidth=3, fontSize=14) { 45 | 46 | const stateVarStyle = new Map() 47 | .set('stroke', '#555555') 48 | .set('stroke-width', `${borderWidth}`) 49 | .set('fill', 'white') 50 | .set('fill-opacity', 1); 51 | 52 | const textStyle = new Map() 53 | .set('alignment-baseline', 'middle') 54 | .set('font-size', `${fontSize}px`) 55 | .set('font-family', 'Helvetica Neue, Helvetica, sans-serif') 56 | .set('text-anchor', 'middle'); 57 | 58 | const tw = textWidth(sbgnData.stateVarLabel(stateVar), { family: textStyle.get('font-family'), size: fontSize}) + 10; 59 | const w = Math.max(tw, 30); 60 | const statevariableSvg = 61 | ` 62 | ${baseShapes.stadium(x, y, w, height, stateVarStyle)} 63 | ${baseShapes.text(sbgnData.stateVarLabel(stateVar), x + ( w / 2 ), y + height / 2, textStyle)} 64 | `; 65 | 66 | return statevariableSvg; 67 | }, 68 | 69 | cloneMarker (nodeWidth, nodeHeight, shapeFn, shapeFnArgs) { 70 | const clipId = 'clonemarker'; 71 | 72 | const cloneMarkerStyle = new Map() 73 | .set('stroke', '#6A6A6A') 74 | .set('stroke-width', '1.5') 75 | .set('clip-path', `url(#${clipId})`) 76 | .set('fill', '#D2D2D2'); 77 | 78 | const cloneMarkerSvg = 79 | ` 80 | ${baseShapes.clipPath(clipId, baseShapes.rectangle, [0, 3 * nodeHeight / 4, nodeWidth, nodeHeight, new Map()])} 81 | ${shapeFn(...shapeFnArgs, cloneMarkerStyle)} 82 | `; 83 | 84 | return cloneMarkerSvg; 85 | } 86 | }; 87 | 88 | module.exports = auxiliaryItems; 89 | -------------------------------------------------------------------------------- /src/sbgnStyle/glyph/baseShapes.js: -------------------------------------------------------------------------------- 1 | const styleMap2Str = require('../util/svg.js').styleMap2Str; 2 | 3 | let baseRectangle = function (x, y, w, h, r1, r2, r3, r4, styleMap) { 4 | return ` 5 | 13 | `; 14 | }; 15 | 16 | const baseShapes = { 17 | barrel (x, y, width, height, styleMap) { 18 | return ` 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | `; 31 | }, 32 | 33 | circle (cx, cy, r, styleMap) { 34 | return ``; 35 | }, 36 | 37 | clipPath (id, baseShapeFn, baseShapeFnArgs, styleMap) { 38 | return ` 39 | 40 | 41 | ${baseShapeFn(...baseShapeFnArgs)} 42 | 43 | 44 | `; 45 | }, 46 | 47 | concaveHexagon (x, y, width, height, styleMap) { 48 | return ` 49 | `; 52 | }, 53 | 54 | cutRectangle (x, y, width, height, cornerLength, styleMap) { 55 | return ` 56 | 62 | `; 63 | }, 64 | 65 | ellipse (cx, cy, rx, ry, styleMap) { 66 | return ` 67 | 68 | `; 69 | }, 70 | 71 | hexagon (x, y, width, height, styleMap) { 72 | return ` 73 | `; 76 | }, 77 | 78 | line (x1, y1, x2, y2, styleMap) { 79 | return ``; 80 | }, 81 | 82 | rectangle (x, y, width, height, styleMap) { 83 | return baseRectangle(x, y, width, height, 0, 0, 0, 0, styleMap); 84 | }, 85 | 86 | roundBottomRectangle (x, y, width, height, styleMap) { 87 | return baseRectangle(x, y, width, height, 0, 0, .3*height, .3*height, styleMap); 88 | }, 89 | 90 | roundRectangle (x, y, width, height, styleMap) { 91 | return baseRectangle(x, y, width, height, .04*width, .04*width, .04*width, .04*width, styleMap); 92 | }, 93 | 94 | stadium (x, y, width, height, styleMap) { 95 | const radiusRatio = .24 * Math.max(width, height); 96 | return baseRectangle(x, y, width, height, radiusRatio, radiusRatio, radiusRatio, radiusRatio, styleMap); 97 | }, 98 | 99 | square (x, y, length, styleMap) { 100 | return baseRectangle(x, y, length, length, 0, 0, 0, 0, styleMap); 101 | }, 102 | 103 | text (t, x, y, styleMap) { 104 | return `${t}`; 105 | } 106 | 107 | }; 108 | 109 | 110 | module.exports = baseShapes; 111 | -------------------------------------------------------------------------------- /src/sbgnStyle/glyph/containerNodes.js: -------------------------------------------------------------------------------- 1 | const svgStr = require('../util/svg').svgStr; 2 | const sbgnData = require('../util/sbgn'); 3 | const memoize = require('lodash.memoize'); 4 | 5 | const auxiliaryItems = require('./auxiliaryItems'); 6 | const baseShapes = require('./baseShapes'); 7 | 8 | const containerNodes = { 9 | 10 | compartment (node) { 11 | const auxItemWidth = 60; 12 | const auxItemHeight = 40; 13 | const uInfos = sbgnData.getUnitInfos(node); 14 | 15 | const style = new Map() 16 | .set('stroke', '#555555') 17 | .set('stroke-width', '6'); 18 | 19 | const uInfoSvg = svgStr( 20 | uInfos.length > 0 ? auxiliaryItems.multiImgUnitOfInformation(2, 0, auxItemWidth - 5, auxItemHeight - 3, uInfos[0]) : '', 21 | auxItemWidth, auxItemHeight 22 | ); 23 | 24 | let lineSvg = svgStr( 25 | uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', 26 | auxItemWidth, auxItemHeight 27 | ); 28 | 29 | return { 30 | bgImage: [lineSvg, uInfoSvg], 31 | bgWidth: ['100%'], 32 | bgPosX: ['0%', '25%'], 33 | bgPosY: ['19px', '0%'], 34 | bgFit: ['contain', 'none'], 35 | bgClip: 'node', 36 | padding: '38px', 37 | borderWidth: '4' 38 | }; 39 | } 40 | }; 41 | 42 | module.exports = containerNodes; 43 | -------------------------------------------------------------------------------- /src/sbgnStyle/glyph/entityPoolNodes.js: -------------------------------------------------------------------------------- 1 | const baseShapes = require('./baseShapes'); 2 | const auxiliaryItems = require('./auxiliaryItems'); 3 | 4 | const svgStr = require('../util/svg').svgStr; 5 | const getUnitInfos = require('../util/sbgn').getUnitInfos; 6 | const getStateVars = require('../util/sbgn').getStateVars; 7 | const hasClonemarker = require('../util/sbgn').hasClonemarker; 8 | 9 | const element = require('../element'); 10 | 11 | 12 | const entityPoolNodes = { 13 | 14 | unspecifiedEntity (node) { 15 | const auxItemWidth = 100; 16 | const auxItemHeight = 20; 17 | const borderWidth = 2; 18 | const fontSize = 10; 19 | const uInfos = getUnitInfos(node); 20 | const sVars = getStateVars(node); 21 | 22 | const style = new Map() 23 | .set('stroke', '#6A6A6A') 24 | .set('stroke-width', '1'); 25 | 26 | const cloneMarkerSvg = svgStr( 27 | hasClonemarker(node) ? auxiliaryItems.multiImgCloneMarker(0, 2, auxItemWidth, auxItemHeight - 3) : '', 28 | auxItemWidth, auxItemHeight 29 | ); 30 | 31 | const uInfoSvg = svgStr( 32 | uInfos.length > 0 ? auxiliaryItems.multiImgUnitOfInformation(2, 0, auxItemWidth - 5, auxItemHeight - 3, uInfos[0], borderWidth, fontSize) : '', 33 | auxItemWidth, auxItemHeight 34 | ); 35 | 36 | const sVarSvg = svgStr( 37 | sVars.length > 0 ? auxiliaryItems.multiImgStateVar(2, 0, auxItemWidth - 5, auxItemHeight - 3, sVars[0], borderWidth, fontSize) : '', 38 | auxItemWidth, auxItemHeight 39 | ); 40 | 41 | const topLine = svgStr( 42 | uInfos.length + sVars.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', 43 | auxItemWidth, auxItemHeight 44 | ); 45 | 46 | const bottomLine = svgStr( 47 | hasClonemarker(node) || uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', 48 | auxItemWidth, auxItemHeight 49 | ); 50 | return { 51 | bgImage: [bottomLine, topLine, cloneMarkerSvg, uInfoSvg, sVarSvg], 52 | bgWidth: ['100%', '100%', '100%'], 53 | bgPosX: ['0%', '0%', '0%', '20px', '40px'], 54 | bgPosY: ['52px', '8px', '32px', '44px', '0%'], 55 | bgFit: ['cover', 'cover', 'none', 'none'], 56 | bgClip: 'node', 57 | padding: '8px', 58 | borderWidth: 2 59 | }; 60 | 61 | }, 62 | 63 | simpleChemical (node) { 64 | const auxItemWidth = 100; 65 | const auxItemHeight = 20; 66 | const borderWidth = 2; 67 | const fontSize = 10; 68 | const uInfos = getUnitInfos(node); 69 | 70 | const style = new Map() 71 | .set('stroke', '#6A6A6A') 72 | .set('stroke-width', '1'); 73 | 74 | const cloneMarkerSvg = svgStr( 75 | hasClonemarker(node) ? auxiliaryItems.multiImgCloneMarker(0, 2, auxItemWidth, auxItemHeight - 3) : '', 76 | auxItemWidth, auxItemHeight 77 | ); 78 | 79 | const uInfoSvg = svgStr( 80 | uInfos.length > 0 ? auxiliaryItems.multiImgUnitOfInformation(2, 0, auxItemWidth - 5, auxItemHeight - 3, uInfos[0], borderWidth, fontSize) : '', 81 | auxItemWidth, auxItemHeight 82 | ); 83 | 84 | const topLine = svgStr( 85 | uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', 86 | auxItemWidth, auxItemHeight 87 | ); 88 | 89 | const bottomLine = svgStr( 90 | hasClonemarker(node) || uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', 91 | auxItemWidth, auxItemHeight 92 | ); 93 | 94 | return { 95 | bgImage: [bottomLine, topLine, cloneMarkerSvg, uInfoSvg], 96 | bgWidth: ['100%', '100%', '100%'], 97 | bgPosX: ['0%', '0%', '0%', '12px'], 98 | bgPosY: ['52px', '8px', '48px', '0px'], 99 | bgFit: ['cover', 'cover', 'none', 'none'], 100 | bgClip: 'node', 101 | padding: '8px', 102 | borderWidth: 2 103 | }; 104 | }, 105 | 106 | macromolecule(node) { 107 | const auxItemWidth = 100; 108 | const auxItemHeight = 20; 109 | const borderWidth = 2; 110 | const fontSize = 10; 111 | const uInfos = getUnitInfos(node); 112 | const sVars = getStateVars(node); 113 | 114 | const style = new Map() 115 | .set('stroke', '#6A6A6A') 116 | .set('stroke-width', '1'); 117 | 118 | const cloneMarkerSvg = svgStr( 119 | hasClonemarker(node) ? auxiliaryItems.multiImgCloneMarker(0, 2, auxItemWidth, auxItemHeight - 3) : '', 120 | auxItemWidth, auxItemHeight 121 | ); 122 | 123 | const uInfoSvg = svgStr( 124 | uInfos.length > 0 ? auxiliaryItems.multiImgUnitOfInformation(2, 0, auxItemWidth - 5, auxItemHeight - 3, uInfos[0], borderWidth, fontSize) : '', 125 | auxItemWidth, auxItemHeight 126 | ); 127 | 128 | const sVarSvg = svgStr( 129 | sVars.length > 0 ? auxiliaryItems.multiImgStateVar(2, 0, auxItemWidth - 5, auxItemHeight - 3, sVars[0], borderWidth, fontSize) : '', 130 | auxItemWidth, auxItemHeight 131 | ); 132 | 133 | const topLine = svgStr( 134 | uInfos.length + sVars.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', 135 | auxItemWidth, auxItemHeight 136 | ); 137 | 138 | const bottomLine = svgStr( 139 | hasClonemarker(node) || uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', 140 | auxItemWidth, auxItemHeight 141 | ); 142 | 143 | return { 144 | bgImage: [bottomLine, topLine, cloneMarkerSvg, uInfoSvg, sVarSvg], 145 | bgWidth: ['100%', '100%', '100%'], 146 | bgPosX: ['0%', '0%', '0%', '20px', '40px'], 147 | bgPosY: ['52px', '8px', '52px', '44px', '0%'], 148 | bgFit: ['cover', 'cover', 'none', 'none'], 149 | bgClip: 'node', 150 | padding: '8px', 151 | borderWidth: 2 152 | }; }, 153 | 154 | nucleicAcidFeature (node) { 155 | const auxItemWidth = 100; 156 | const auxItemHeight = 20; 157 | const borderWidth = 2; 158 | const fontSize = 10; 159 | const uInfos = getUnitInfos(node); 160 | const sVars = getStateVars(node); 161 | 162 | const style = new Map() 163 | .set('stroke', '#6A6A6A') 164 | .set('stroke-width', '1'); 165 | 166 | const cloneMarkerSvg = svgStr( 167 | hasClonemarker(node) ? auxiliaryItems.multiImgCloneMarker(0, 2, auxItemWidth, auxItemHeight - 3) : '', 168 | auxItemWidth, auxItemHeight 169 | ); 170 | 171 | const uInfoSvg = svgStr( 172 | uInfos.length > 0 ? auxiliaryItems.multiImgUnitOfInformation(2, 0, auxItemWidth - 5, auxItemHeight - 3, uInfos[0], borderWidth, fontSize) : '', 173 | auxItemWidth, auxItemHeight 174 | ); 175 | 176 | const sVarSvg = svgStr( 177 | sVars.length > 0 ? auxiliaryItems.multiImgStateVar(2, 0, auxItemWidth - 5, auxItemHeight - 3, sVars[0], borderWidth, fontSize) : '', 178 | auxItemWidth, auxItemHeight 179 | ); 180 | 181 | const topLine = svgStr( 182 | sVars.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', 183 | auxItemWidth, auxItemHeight 184 | ); 185 | 186 | const bottomLine = svgStr( 187 | hasClonemarker(node) || uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', 188 | auxItemWidth, auxItemHeight 189 | ); 190 | 191 | return { 192 | bgImage: [bottomLine, topLine, cloneMarkerSvg, uInfoSvg, sVarSvg], 193 | bgWidth: ['100%', '100%', '100%'], 194 | bgPosX: ['0%', '0%', '0%', '20px', '40px'], 195 | bgPosY: ['52px', '8px', '52px', '44px', '0%'], 196 | bgFit: ['cover', 'cover', 'none', 'none'], 197 | bgClip: 'node', 198 | padding: '8px', 199 | borderWidth: 2 200 | }; 201 | }, 202 | 203 | complex (node) { 204 | const itemW = 60; 205 | const itemH = 24; 206 | const uInfos = getUnitInfos(node); 207 | const sVars = getStateVars(node); 208 | 209 | const images = []; 210 | const bgWidth = []; 211 | const bgHeight = []; 212 | const bgPosX = []; 213 | const bgPosY = []; 214 | const bgFit = []; 215 | 216 | const style = new Map() 217 | .set('stroke', '#555555') 218 | .set('stroke-width', '6'); 219 | 220 | // order of svg image generation matters 221 | if (uInfos.length + sVars.length > 0) { 222 | const topLineSvg = svgStr(baseShapes.line(0, 0, itemW, 0, style), itemW, itemH); 223 | images.push(topLineSvg); 224 | bgWidth.push('100%'); 225 | bgPosX.push('0%'); 226 | bgPosY.push('11px'); 227 | bgFit.push('none'); 228 | } 229 | 230 | if (hasClonemarker(node)) { 231 | const bottomLineSvg = svgStr(baseShapes.line(0, 0, itemW, 0, style), itemW, itemH); 232 | images.push(bottomLineSvg); 233 | bgWidth.push('100%'); 234 | bgPosX.push('0%'); 235 | bgPosY.push('100%'); 236 | bgFit.push('none'); 237 | } 238 | 239 | if (hasClonemarker(node)) { 240 | const cloneSvg = svgStr(auxiliaryItems.multiImgCloneMarker(0, 2, itemW, itemH - 3), itemW, itemH); 241 | images.push(cloneSvg); 242 | bgWidth.push('100%'); 243 | bgPosX.push('0%'); 244 | bgPosY.push('100%'); 245 | bgFit.push('none'); 246 | } 247 | 248 | if (uInfos.length > 0) { 249 | const uInfoSvg = svgStr(auxiliaryItems.multiImgUnitOfInformation(2, 0, itemW - 5, itemH - 3, uInfos[0]), itemW, itemH); 250 | images.push(uInfoSvg); 251 | bgPosX.push('25%'); 252 | bgPosY.push('0%'); 253 | bgFit.push('none'); 254 | } 255 | 256 | if (sVars.length > 0) { 257 | const sVarSvg = svgStr(auxiliaryItems.multiImgStateVar(2, 0, itemW - 5, itemH - 3, sVars[0]), itemW, itemH); 258 | images.push(sVarSvg); 259 | bgPosX.push('88%'); 260 | bgPosY.push('0%'); 261 | bgFit.push('none'); 262 | } 263 | 264 | return { 265 | bgImage: images, 266 | bgWidth: bgWidth, 267 | bgPosX: bgPosX, 268 | bgPosY: bgPosY, 269 | bgFit: bgFit, 270 | bgClip: 'node', 271 | padding: '22px', 272 | borderWidth: 4 273 | }; 274 | }, 275 | 276 | sourceAndSink (node) { 277 | const {w: nw, h: nh} = element.dimensions(node); 278 | 279 | const centerX = nw / 2; 280 | const centerY = nh / 2; 281 | const radius = (nw - 2) / 2; 282 | 283 | const styleMap = new Map() 284 | .set('stroke', '#6A6A6A') 285 | .set('stroke-linecap', 'square') 286 | .set('stroke-width', '1.5') 287 | .set('fill', 'none'); 288 | 289 | const shapeArgs = [centerX, centerY, radius]; 290 | 291 | const sourceAndSinkSvg = 292 | ` 293 | ${baseShapes.circle(...shapeArgs, styleMap)} 294 | ${hasClonemarker(node) ? auxiliaryItems.cloneMarker(nw, nh, baseShapes.circle, shapeArgs) : ''} 295 | ${baseShapes.line(0, nh, nw, 0, styleMap)} 296 | `; 297 | 298 | return svgStr(sourceAndSinkSvg, nw, nh, 0, 0, nw, nh); 299 | }, 300 | 301 | perturbingAgent (node) { 302 | const auxItemWidth = 100; 303 | const auxItemHeight = 20; 304 | const borderWidth = 2; 305 | const fontSize = 10; 306 | const uInfos = getUnitInfos(node); 307 | 308 | const style = new Map() 309 | .set('stroke', '#6A6A6A') 310 | .set('stroke-width', '1'); 311 | 312 | const cloneMarkerSvg = svgStr( 313 | hasClonemarker(node) ? auxiliaryItems.multiImgCloneMarker(0, 2, auxItemWidth, auxItemHeight - 3) : '', 314 | auxItemWidth, auxItemHeight 315 | ); 316 | 317 | const uInfoSvg = svgStr( 318 | uInfos.length > 0 ? auxiliaryItems.multiImgUnitOfInformation(2, 0, auxItemWidth - 5, auxItemHeight - 3, uInfos[0], borderWidth, fontSize) : '', 319 | auxItemWidth, auxItemHeight 320 | ); 321 | 322 | const topLine = svgStr( 323 | uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', 324 | auxItemWidth, auxItemHeight 325 | ); 326 | 327 | const bottomLine = svgStr( 328 | hasClonemarker(node) || uInfos.length > 0 ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', 329 | auxItemWidth, auxItemHeight 330 | ); 331 | 332 | return { 333 | bgImage: [bottomLine, topLine, cloneMarkerSvg, uInfoSvg], 334 | bgWidth: ['100%', '100%', '100%'], 335 | bgPosX: ['0%', '0%', '0%', '20px'], 336 | bgPosY: ['56px', '8px', '56px', '0%'], 337 | bgFit: ['cover', 'cover', 'none', 'none'], 338 | bgClip: 'node', 339 | padding: '8px', 340 | borderWidth: 2 341 | }; 342 | } 343 | }; 344 | 345 | module.exports = entityPoolNodes; 346 | -------------------------------------------------------------------------------- /src/sbgnStyle/glyph/index.js: -------------------------------------------------------------------------------- 1 | const memoize = require('lodash.memoize'); 2 | 3 | const containerNodes = require('./containerNodes.js'); 4 | const entityPoolNodes = require('./entityPoolNodes.js'); 5 | const processNodes = require('./processNodes.js'); 6 | 7 | const sbgnData = require('../util/sbgn.js'); 8 | 9 | const cacheKeyFn = (node) => '' + JSON.stringify(node.id()); 10 | 11 | const sbgnNodeShapeMap = new Map() 12 | // process nodes 13 | .set('dissociation', memoize(processNodes.dissociation, cacheKeyFn)) 14 | .set('phenotype', memoize(processNodes.phenotype, cacheKeyFn)) 15 | 16 | // entity pool nodes 17 | .set('source and sink', memoize(entityPoolNodes.sourceAndSink, cacheKeyFn)) 18 | .set('unspecified entity', memoize(entityPoolNodes.unspecifiedEntity, cacheKeyFn)) 19 | .set('simple chemical', memoize(entityPoolNodes.simpleChemical, cacheKeyFn)) 20 | .set('macromolecule', memoize(entityPoolNodes.macromolecule, cacheKeyFn)) 21 | .set('nucleic acid feature', memoize(entityPoolNodes.nucleicAcidFeature, cacheKeyFn)) 22 | .set('complex', memoize(entityPoolNodes.complex, cacheKeyFn)) 23 | .set('perturbing agent', memoize(entityPoolNodes.perturbingAgent, cacheKeyFn)) 24 | 25 | // container nodes 26 | .set('compartment', memoize(containerNodes.compartment, cacheKeyFn)); 27 | 28 | 29 | const draw = (node) => { 30 | const sbgnClass = sbgnData.sbgnClass(node).replace(' multimer', ''); 31 | let shapeFn = sbgnNodeShapeMap.get(sbgnClass); 32 | if (shapeFn == null) { 33 | throw new TypeError(`${sbgnClass} does not have a shape implementation`); 34 | } 35 | return shapeFn(node); 36 | }; 37 | 38 | module.exports = { 39 | draw: draw 40 | }; 41 | -------------------------------------------------------------------------------- /src/sbgnStyle/glyph/processNodes.js: -------------------------------------------------------------------------------- 1 | const baseShapes = require('./baseShapes'); 2 | const auxiliaryItems = require('./auxiliaryItems'); 3 | 4 | const svgStr = require('../util/svg').svgStr; 5 | const hasClonemarker = require('../util/sbgn').hasClonemarker; 6 | 7 | const element = require('../element'); 8 | 9 | const processNodes = { 10 | 11 | dissociation (node) { 12 | const {w: nw, h: nh} = element.dimensions(node); 13 | 14 | const centerX = nw / 2; 15 | const centerY = nh / 2; 16 | const outerRadius = (Math.min(nw, nh) - 2) / 2; 17 | const innerRadius = (Math.min(nw, nh) - 2) / 3; 18 | 19 | const styleMap = new Map() 20 | .set('stroke', '#6A6A6A') 21 | .set('stroke-width', '2') 22 | .set('fill', 'none'); 23 | 24 | const dissociationSvg = 25 | ` 26 | ${baseShapes.circle(centerX, centerY, outerRadius, styleMap)} 27 | ${baseShapes.circle(centerX, centerY, innerRadius, styleMap)} 28 | `; 29 | return svgStr(dissociationSvg, nw, nh); 30 | }, 31 | 32 | phenotype (node) { 33 | const auxItemWidth = 100; 34 | const auxItemHeight = 20; 35 | 36 | const style = new Map() 37 | .set('stroke', '#6A6A6A') 38 | .set('stroke-width', '1'); 39 | 40 | const cloneMarkerSvg = svgStr( 41 | hasClonemarker(node) ? auxiliaryItems.multiImgCloneMarker(0, 2, auxItemWidth, auxItemHeight - 3) : '', 42 | auxItemWidth, auxItemHeight, 0, 0, auxItemWidth, auxItemHeight 43 | ); 44 | 45 | const bottomLine = svgStr( 46 | hasClonemarker(node) ? baseShapes.line(0, 0, auxItemWidth, 0, style) : '', 47 | auxItemWidth, auxItemHeight, 0, 0, auxItemWidth, auxItemHeight 48 | ); 49 | 50 | return { 51 | bgImage: [bottomLine, cloneMarkerSvg], 52 | bgWidth: ['100%', '100%'], 53 | bgPosX: ['0%', '0%'], 54 | bgPosY: ['56px', '56px'], 55 | bgFit: ['cover', 'none'], 56 | bgClip: 'node', 57 | padding: '8px', 58 | borderWidth: 2 59 | }; 60 | } 61 | }; 62 | 63 | module.exports = processNodes; 64 | -------------------------------------------------------------------------------- /src/sbgnStyle/index.js: -------------------------------------------------------------------------------- 1 | const elementStyle = require('./element'); 2 | const sbgnsvg = require('./glyph'); 3 | 4 | const sbgnStyleSheet = function (cytoscape) { 5 | 6 | return cytoscape.stylesheet() 7 | // general node style 8 | .selector('node') 9 | .css({ 10 | 'shape': (node) => elementStyle.sbgnShape(node), 11 | 'content': (node) => elementStyle.sbgnContent(node), 12 | 'font-size': 20, 13 | 'width': (node) => elementStyle.width(node), 14 | 'height': (node) => elementStyle.height(node), 15 | 'text-valign': 'center', 16 | 'text-halign': 'center', 17 | 'border-width': 1.5, 18 | 'border-color': '#555', 19 | 'background-color': '#f6f6f6', 20 | 'text-opacity': 1, 21 | 'opacity': 1, 22 | 'text-outline-color': 'white', 23 | 'text-outline-opacity': 1, 24 | 'text-outline-width': 0.75 25 | }) 26 | .selector('node:selected') 27 | .css({ 28 | 'background-color': '#d67614', 29 | 'target-arrow-color': '#000', 30 | 'text-outline-color': '#000' 31 | }) 32 | .selector('node:active') 33 | .css({ 34 | 'overlay-color': '#d67614', 35 | 'overlay-padding': '14' 36 | }) 37 | 38 | // draw sbgn specific styling (auxiliary items, clonemarker, etc.) 39 | .selector(` 40 | node[class="unspecified entity"], 41 | node[class="simple chemical"], node[class="simple chemical multimer"], 42 | node[class="macromolecule"], node[class="macromolecule multimer"], 43 | node[class="nucleic acid feature"], node[class="nucleic acid feature multimer"], 44 | node[class="perturbing agent"], 45 | node[class="phenotype"], 46 | node[class="complex"], node[class="complex multimer"], node[class="compartment"] 47 | `) 48 | .css({ 49 | 'background-image': (node) => sbgnsvg.draw(node).bgImage, 50 | 'background-width': (node) => sbgnsvg.draw(node).bgWidth, 51 | 'background-position-x': (node) => sbgnsvg.draw(node).bgPosX, 52 | 'background-position-y': (node) => sbgnsvg.draw(node).bgPosY, 53 | 'background-fit': (node) => sbgnsvg.draw(node).bgFit, 54 | 'background-clip': (node) => sbgnsvg.draw(node).bgClip, 55 | 'padding': (node) => sbgnsvg.draw(node).padding, 56 | 'border-width': (node) => sbgnsvg.draw(node).borderWidth 57 | }) 58 | 59 | .selector(` 60 | node[class="simple chemical multimer"], 61 | node[class="macromolecule multimer"], 62 | node[class="nucleic acid feature multimer"], 63 | node[class="complex multimer"] 64 | `) 65 | .css({ 66 | 'ghost': 'yes', 67 | 'ghost-opacity': 1 68 | }) 69 | 70 | .selector(` 71 | node[class="macromolecule multimer"], 72 | node[class="nucleic acid feature multimer"] 73 | `) 74 | .css({ 75 | 'ghost-offset-x': 12, 76 | 'ghost-offset-y': 12 77 | }) 78 | 79 | .selector(` 80 | node[class="simple chemical multimer"] 81 | `) 82 | .css({ 83 | 'ghost-offset-x': 5, 84 | 'ghost-offset-y': 5 85 | }) 86 | 87 | .selector(` 88 | node[class="complex multimer"] 89 | `) 90 | .css({ 91 | 'ghost-offset-x': 16, 92 | 'ghost-offset-y': 16 93 | }) 94 | 95 | // compound node specific style 96 | .selector('node[class="complex"], node[class="complex multimer"], node[class="compartment"]') 97 | .css({ 98 | 'compound-sizing-wrt-labels': 'exclude', 99 | 'text-valign': 'bottom', 100 | 'text-halign': 'center', 101 | }) 102 | 103 | // process node specific style 104 | .selector('node[class="association"], node[class="dissociation"]') 105 | .css({ 106 | 'background-opacity': 1 107 | }) 108 | .selector('node[class="association"]') 109 | .css({ 110 | 'background-color': '#6B6B6B' 111 | }) 112 | 113 | // source and sink and dissociation are drawn differently because 114 | // of their unique shape 115 | .selector('node[class="source and sink"]') 116 | .css({ 117 | 'background-image': (node) => sbgnsvg.draw(node), 118 | 'background-fit': 'none', 119 | 'background-width': '100%', 120 | 'background-height': '100%', 121 | 'background-clip': 'none', 122 | 'background-repeat': 'no-repeat', 123 | 'border-width': 0, 124 | 'shape-polygon-points': '-0.86, 0.5, -0.75, 0.65, -1, 0.95, -0.95, 1, -0.65, 0.75, -0.5, 0.86, 0, 1, 0.5, 0.86, 0.71, 0.71, 0.86, 0.5, 1, 0, 0.86, -0.5, 0.75, -0.65, 1, -0.95, 0.95, -1, 0.65, -0.75, 0.5, -0.86, 0, -1, -0.5, -0.86, -0.71, -0.71, -0.86, -0.5, -1, 0', 125 | }) 126 | 127 | // source and sink and dissociation are drawn differently because 128 | // of their unique shape 129 | .selector('node[class="dissociation"]') 130 | .css({ 131 | 'background-image': (node) => sbgnsvg.draw(node), 132 | 'background-fit': 'none', 133 | 'background-width': '100%', 134 | 'background-height': '100%', 135 | 'background-clip': 'none', 136 | 'background-repeat': 'no-repeat', 137 | 'border-width': 0, 138 | }) 139 | 140 | // edge styling 141 | .selector('edge') 142 | .css({ 143 | 'arrow-scale': 1.75, 144 | 'curve-style': 'bezier', 145 | 'line-color': '#555', 146 | 'target-arrow-fill': 'hollow', 147 | 'source-arrow-fill': 'hollow', 148 | 'width': 1.5, 149 | 'target-arrow-color': '#555', 150 | 'source-arrow-color': '#555', 151 | 'text-border-color': '#555', 152 | 'color': '#555' 153 | }) 154 | .selector('edge:selected') 155 | .css({ 156 | 'color': '#d67614', 157 | 'line-color': '#d67614', 158 | 'text-border-color': '#d67614', 159 | 'source-arrow-color': '#d67614', 160 | 'target-arrow-color': '#d67614' 161 | }) 162 | .selector('edge:active') 163 | .css({ 164 | 'background-opacity': 0.7, 'overlay-color': '#d67614', 165 | 'overlay-padding': '8' 166 | }) 167 | .selector('edge[cardinality > 0]') 168 | .css({ 169 | 'text-background-shape': 'rectangle', 170 | 'text-border-opacity': '1', 171 | 'text-border-width': '1', 172 | 'text-background-color': 'white', 173 | 'text-background-opacity': '1' 174 | }) 175 | .selector('edge[class="consumption"][cardinality > 0], edge[class="production"][cardinality > 0]') 176 | .css({ 177 | 'source-label': (edge) => '' + edge.data('cardinality'), 178 | 'source-text-offset': 10 179 | }) 180 | .selector('edge[class]') 181 | .css({ 182 | 'target-arrow-shape': (edge) => elementStyle.sbgnArrowShape(edge), 183 | 'source-arrow-shape': 'none' 184 | }) 185 | .selector('edge[class="inhibition"]') 186 | .css({ 187 | 'target-arrow-fill': 'filled' 188 | }) 189 | .selector('edge[class="production"]') 190 | .css({ 191 | 'target-arrow-fill': 'filled' 192 | }) 193 | 194 | 195 | // core 196 | .selector('core') 197 | .css({ 198 | 'selection-box-color': '#d67614', 199 | 'selection-box-opacity': '0.2', 'selection-box-border-color': '#d67614' 200 | }); 201 | }; 202 | 203 | module.exports = sbgnStyleSheet; 204 | -------------------------------------------------------------------------------- /src/sbgnStyle/util/sbgn.js: -------------------------------------------------------------------------------- 1 | const sbgnDataHandler = { 2 | isMultimer (node) { 3 | return node.data('class').includes('multimer'); 4 | }, 5 | hasClonemarker (node) { 6 | return node.data('clonemarker'); 7 | }, 8 | getStateVars (node) { 9 | return node.data('stateVariables'); 10 | }, 11 | getUnitInfos (node) { 12 | return node.data('unitsOfInformation'); 13 | }, 14 | hasAuxItems (node) { 15 | return (node.data('stateVariables').length + node.data('unitsOfInformation').length > 0); 16 | }, 17 | sbgnClass (element) { 18 | return element.data('class'); 19 | }, 20 | sbgnLabel (element) { 21 | return element.data('label'); 22 | }, 23 | stateVarLabel (stateVar) { 24 | const variable = stateVar.state.variable; 25 | const value = stateVar.state.value; 26 | if (value && variable) { 27 | return `${value}@${variable}`; 28 | } 29 | if (value) { 30 | return value; 31 | } 32 | 33 | if (variable) { 34 | return variable; 35 | } 36 | return ''; 37 | } 38 | }; 39 | 40 | module.exports = sbgnDataHandler; 41 | -------------------------------------------------------------------------------- /src/sbgnStyle/util/svg.js: -------------------------------------------------------------------------------- 1 | const styleMap2Str = (styleMap) => { 2 | if( !styleMap ){ 3 | return ''; 4 | } 5 | 6 | let s = ''; 7 | 8 | for( let [k, v] of styleMap ){ 9 | s += k + '=' + '"' + v + '"' + ' '; 10 | } 11 | 12 | return s; 13 | }; 14 | 15 | const svg = (svgStr, width = 100, height = 100) => { 16 | const parser = new DOMParser(); 17 | let svgText = 18 | `${svgStr}`; 19 | return parser.parseFromString(svgText, 'text/xml').documentElement; 20 | }; 21 | 22 | const svgStr = (svgText, viewPortWidth, viewPortHeight, viewBoxX, viewBoxY, viewBoxWidth, viewBoxHeight) => { 23 | let s = svg(svgText, viewPortWidth, viewPortHeight, viewBoxX, viewBoxY, viewBoxWidth, viewBoxHeight); 24 | 25 | // base64 26 | // let data = 'data:image/svg+xml;base64,' + btoa(s.outerHTML); 27 | 28 | // uri component string 29 | let data = 'data:image/svg+xml;utf8,' + encodeURIComponent(s.outerHTML); 30 | 31 | return data; 32 | }; 33 | 34 | module.exports = { 35 | svgStr: svgStr, 36 | styleMap2Str: styleMap2Str 37 | }; 38 | -------------------------------------------------------------------------------- /test/shapeTest.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | 3 | const expect = require('chai').expect; 4 | 5 | const svgUtil = require('../src/sbgnStyle/util/svg.js'); 6 | const s = require('../src/sbgnStyle/glyph/baseShapes.js'); 7 | 8 | const sbgnShapes = require('../src/sbgnStyle/glyph/'); 9 | 10 | const browser = !(typeof window === 'undefined'); 11 | 12 | describe('shape style', () => { 13 | it('should convert style maps to a svg style string', () => { 14 | const styleMap = new Map() 15 | .set('stroke-width', '3') 16 | .set('fill', 'none') 17 | .set('stroke', '#6A6A6A'); 18 | 19 | const styleString = `stroke-width="3" fill="none" stroke="#6A6A6A" `; 20 | expect(svgUtil.styleMap2Str(styleMap)).to.equal(styleString); 21 | }); 22 | it('should produce an empty string for an empty map', () => { 23 | const styleMap = new Map(); 24 | 25 | const styleString = ''; 26 | 27 | expect(svgUtil.styleMap2Str(styleMap)).to.equal(styleString); 28 | }); 29 | }); 30 | 31 | describe('shape svg', function () { 32 | it('(browser only) should produce valid svg when parsed', function () { 33 | 34 | if (browser) { 35 | 36 | const validSvg = (svg) => { 37 | const parser = new DOMParser(); 38 | let doc = parser.parseFromString(svg, 'text/xml'); 39 | let parseError = doc.getElementsByTagName('parsererror'); 40 | return parseError.length === 0; 41 | }; 42 | 43 | const styleMap = new Map() 44 | .set('stroke-width', '3') 45 | .set('fill', 'none') 46 | .set('stroke', '#6A6A6A'); 47 | 48 | const x = 0; 49 | const y = 0; 50 | const w = 100; 51 | const h = 100; 52 | 53 | expect(validSvg(s.rectangle(x, y, w, h, styleMap))).to.equal(true); 54 | expect(validSvg(s.roundBottomRectangle(x, y, w, h, styleMap))).to.equal(true); 55 | expect(validSvg(s.roundRectangle(x, y, w, h, styleMap))).to.equal(true); 56 | expect(validSvg(s.square(x, y, w, styleMap))).to.equal(true); 57 | expect(validSvg(s.barrel(x, y, w, h, styleMap))).to.equal(true); 58 | expect(validSvg(s.circle(x, y, w, styleMap))).to.equal(true); 59 | expect(validSvg(s.concaveHexagon(x, y, w, h, styleMap))).to.equal(true); 60 | expect(validSvg(s.cutRectangle(x, y, w, h, 10, styleMap))).to.equal(true); 61 | expect(validSvg(s.ellipse(x, y, w, h, styleMap))).to.equal(true); 62 | expect(validSvg(s.hexagon(x, y, w, h, styleMap))).to.equal(true); 63 | expect(validSvg(s.line(x, y, w, h, styleMap))).to.equal(true); 64 | expect(validSvg(s.text('blah', x, y, styleMap))).to.equal(true); 65 | } else { 66 | this.skip(); 67 | } 68 | }); 69 | }); 70 | 71 | describe('sbgn shape svg', function () { 72 | it('should throw an error when a incorrect node class is specified', function () { 73 | let dummyNode = { 74 | data() { 75 | return 'not a sbgn class'; 76 | } 77 | }; 78 | expect(sbgnShapes.draw.bind(dummyNode)).to.throw(TypeError); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /* global describe, it */ 2 | const expect = require('chai').expect; 3 | 4 | describe('dummy test', () => { 5 | it('should run and not crash and not fail', () => { 6 | const a = 1; 7 | 8 | expect(a + a).to.equal(2); 9 | }); 10 | }); -------------------------------------------------------------------------------- /test/testenv/tests.html: -------------------------------------------------------------------------------- 1 | Mocha Tests 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const { env } = require('process'); 3 | const isProd = env.NODE_ENV === 'production'; 4 | const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); 5 | const isNonNil = x => x != null; 6 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 7 | const isProfile = env.PROFILE == 'true'; 8 | const minify = env.MINIFY == 'true'; 9 | const package = require('./package.json'); 10 | const camelcase = require('camelcase'); 11 | 12 | let conf = { 13 | entry: './src/index.js', 14 | 15 | devtool: isProd ? false : 'inline-source-map', 16 | 17 | output: { 18 | filename: './build/bundle.js', 19 | library: camelcase( package.name ), 20 | libraryTarget: 'umd' 21 | }, 22 | 23 | externals: isProd ? Object.keys( package.dependencies || {} ) : [], 24 | 25 | module: { 26 | rules: [ 27 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' } 28 | ] 29 | }, 30 | 31 | plugins: [ 32 | new webpack.EnvironmentPlugin(['NODE_ENV']), 33 | 34 | minify ? new UglifyJSPlugin() : null 35 | ].filter( isNonNil ) 36 | }; 37 | 38 | module.exports = conf; 39 | --------------------------------------------------------------------------------