vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

461 lines
12 KiB

  1. /**
  2. * Created by Alex on 3/26/2015.
  3. */
  4. var util = require('../../util');
  5. class ConfigurationSystem {
  6. constructor(network) {
  7. this.network = network;
  8. this.possibleOptions = {
  9. nodes: {
  10. borderWidth: [1, 0, 10, 1],
  11. borderWidthSelected: [2, 0, 10, 1],
  12. color: {
  13. border: 'color',
  14. background: 'color',
  15. highlight: {
  16. border: 'color',
  17. background: 'color'
  18. },
  19. hover: {
  20. border: 'color',
  21. background: 'color'
  22. }
  23. },
  24. fixed: {
  25. x: false,
  26. y: false
  27. },
  28. font: {
  29. color: 'color',
  30. size: [14, 0, 100, 1], // px
  31. face: ['arial', 'verdana', 'tahoma'],
  32. background: 'color',
  33. stroke: [0, 0, 50, 1], // px
  34. strokeColor: 'color'
  35. },
  36. group: 'string',
  37. hidden: false,
  38. icon: {
  39. face: 'string', //'FontAwesome',
  40. code: 'string', //'\uf007',
  41. size: [50, 0, 200, 1], //50,
  42. color: 'color' //'#aa00ff'
  43. },
  44. image: 'string', // --> URL
  45. physics: true,
  46. scaling: {
  47. min: [10, 0, 200, 1],
  48. max: [30, 0, 200, 1],
  49. label: {
  50. enabled: true,
  51. min: [14, 0, 200, 1],
  52. max: [30, 0, 200, 1],
  53. maxVisible: [30, 0, 200, 1],
  54. drawThreshold: [3, 0, 20, 1]
  55. }
  56. },
  57. shape: ['ellipse', 'box', 'circle', 'circularImage', 'database', 'diamond', 'dot', 'icon', 'image', 'square', 'star', 'text', 'triangle', 'triangleDown'],
  58. size: [25, 0, 200, 1]
  59. },
  60. edges: {
  61. arrows: {
  62. to: {enabled: false, scaleFactor: [1, 0, 3, 0.05]}, // boolean / {arrowScaleFactor:1} / {enabled: false, arrowScaleFactor:1}
  63. middle: {enabled: false, scaleFactor: [1, 0, 3, 0.05]},
  64. from: {enabled: false, scaleFactor: [1, 0, 3, 0.05]}
  65. },
  66. color: {
  67. color: 'color',
  68. highlight: 'color',
  69. hover: 'color',
  70. inherit: {
  71. enabled: true,
  72. source: ['from', 'to'], // from / to
  73. useGradients: false
  74. },
  75. opacity: [1, 0, 1, 0.05]
  76. },
  77. dashes: {
  78. enabled: false,
  79. length: [5, 0, 50, 1],
  80. gap: [5, 0, 50, 1],
  81. altLength: [5, 0, 50, 1]
  82. },
  83. font: {
  84. color: 'color',
  85. size: [14, 0, 100, 1], // px
  86. face: ['arial', 'verdana', 'tahoma'],
  87. background: 'color',
  88. stroke: [0, 0, 50, 1], // px
  89. strokeColor: 'color',
  90. align: ['horizontal', 'top', 'middle', 'bottom']
  91. },
  92. hidden: false,
  93. hoverWidth: [1.5, 0, 10, 0.1],
  94. physics: true,
  95. scaling: {
  96. min: [10, 0, 200, 1],
  97. max: [30, 0, 200, 1],
  98. label: {
  99. enabled: true,
  100. min: [14, 0, 200, 1],
  101. max: [30, 0, 200, 1],
  102. maxVisible: [30, 0, 200, 1],
  103. drawThreshold: [3, 0, 20, 1]
  104. }
  105. },
  106. selfReferenceSize: [20, 0, 200, 1],
  107. smooth: {
  108. enabled: true,
  109. dynamic: true,
  110. type: ["continuous", 'discrete', 'diagonalCross', 'straightCross', 'horizontal', 'vertical', 'curvedCW', 'curvedCCW'],
  111. roundness: [0.5, 0, 1, 0.05]
  112. },
  113. width: [1, 0, 30, 1],
  114. widthSelectionMultiplier: [2, 0, 5, 0.1]
  115. },
  116. layout: {
  117. randomSeed: [0, 0, 500, 1],
  118. hierarchical: {
  119. enabled: false,
  120. levelSeparation: [150, 20, 500, 5],
  121. direction: ["UD", 'DU', 'LR', 'RL'], // UD, DU, LR, RL
  122. sortMethod: ["hubsize", 'directed'] // hubsize, directed
  123. }
  124. },
  125. interaction: {
  126. dragNodes: true,
  127. dragView: true,
  128. zoomView: true,
  129. hoverEnabled: false,
  130. showNavigationIcons: false,
  131. tooltip: {
  132. delay: [300, 0, 1000, 25],
  133. fontColor: 'color',
  134. fontSize: [14, 0, 40, 1], // px
  135. fontFace: ['arial', 'verdana', 'tahoma'],
  136. color: {
  137. border: 'color',
  138. background: 'color'
  139. }
  140. },
  141. keyboard: {
  142. enabled: false,
  143. speed: {x: [10, 0, 40, 1], y: [10, 0, 40, 1], zoom: [0.02, 0, 0.1, 0.005]},
  144. bindToWindow: true
  145. }
  146. },
  147. manipulation: {
  148. enabled: false,
  149. initiallyVisible: false,
  150. locale: ['en', 'nl'],
  151. functionality: {
  152. addNode: true,
  153. addEdge: true,
  154. editNode: true,
  155. editEdge: true,
  156. deleteNode: true,
  157. deleteEdge: true
  158. }
  159. },
  160. physics: {
  161. barnesHut: {
  162. theta: [0.5, 0.1, 1, 0.05],
  163. gravitationalConstant: [-2000, -300000, 0, 50],
  164. centralGravity: [0.3, 0, 10, 0.05],
  165. springLength: [95, 0, 500, 5],
  166. springConstant: [0.04, 0, 5, 0.005],
  167. damping: [0.09, 0, 1, 0.01]
  168. },
  169. repulsion: {
  170. centralGravity: [0.2, 0, 10, 0.05],
  171. springLength: [200, 0, 500, 5],
  172. springConstant: [0.05, 0, 5, 0.005],
  173. nodeDistance: [100, 0, 500, 5],
  174. damping: [0.09, 0, 1, 0.01]
  175. },
  176. hierarchicalRepulsion: {
  177. centralGravity: [0.2, 0, 10, 0.05],
  178. springLength: [100, 0, 500, 5],
  179. springConstant: [0.01, 0, 5, 0.005],
  180. nodeDistance: [120, 0, 500, 5],
  181. damping: [0.09, 0, 1, 0.01]
  182. },
  183. maxVelocity: [50, 0, 150, 1],
  184. minVelocity: [0.1, 0.01, 0.5, 0.01],
  185. solver: ['BarnesHut', 'Repulsion', 'HierarchicalRepulsion'],
  186. timestep: [0.5, 0, 1, 0.05]
  187. },
  188. selection: {
  189. select: true,
  190. selectConnectedEdges: true
  191. },
  192. renderer: {
  193. hideEdgesOnDrag: false,
  194. hideNodesOnDrag: false
  195. }
  196. }
  197. this.actualOptions = {};
  198. this.domElements = [];
  199. }
  200. setOptions(options) {
  201. if (options !== undefined) {
  202. util.deepExtend(this.actualOptions, options);
  203. if (options.configurationContainer !== undefined) {
  204. this.container = options.configurationContainer;
  205. }
  206. else {
  207. this.container = this.network.body.container;
  208. }
  209. if (options.configure !== undefined && options.configure !== false) {
  210. let config;
  211. if (options.configure instanceof Array) {
  212. config = options.configure.join();
  213. }
  214. else if (typeof options.configure === 'string') {
  215. config = options.configure;
  216. }
  217. else if (typeof options.configure === 'boolean') {
  218. config = options.configure;
  219. }
  220. else {
  221. this._clean();
  222. throw new Error("the option for configure has to be either a string, boolean or an array. Supplied:" + options.configure);
  223. return;
  224. }
  225. this._create(config);
  226. }
  227. else {
  228. this._clean();
  229. }
  230. }
  231. }
  232. /**
  233. *
  234. * @param {Boolean | String} config
  235. * @private
  236. */
  237. _create(config) {
  238. this._clean();
  239. let counter = 0;
  240. for (let option in this.possibleOptions) {
  241. if (this.possibleOptions.hasOwnProperty(option)) {
  242. if (config === true || config.indexOf(option) !== -1) {
  243. let optionObj = this.possibleOptions[option];
  244. if (counter > 0) {
  245. this._makeBreak();
  246. }
  247. // a header for the category
  248. this._makeHeader(option);
  249. // get the suboptions
  250. let path = [option];
  251. this._handleObject(optionObj, path);
  252. }
  253. counter++;
  254. }
  255. }
  256. this._push();
  257. }
  258. _push() {
  259. for (var i = 0; i < this.domElements.length; i++) {
  260. this.container.appendChild(this.domElements[i]);
  261. }
  262. }
  263. _clean() {
  264. }
  265. _getValue(path) {
  266. let base = this.actualOptions;
  267. for (let i = 0; i < path.length; i++) {
  268. if (base[path[i]] !== undefined) {
  269. base = base[path[i]];
  270. }
  271. else {
  272. base = undefined;
  273. break;
  274. }
  275. }
  276. return base;
  277. }
  278. _addToPath(path, newValue) {
  279. let newPath = [];
  280. for (let i = 0; i < path.length; i++) {
  281. newPath.push(path[i]);
  282. }
  283. newPath.push(newValue);
  284. return newPath;
  285. }
  286. _makeHeader(name) {
  287. let div = document.createElement('div');
  288. div.className = 'vis-network-configuration header';
  289. div.innerHTML = name;
  290. this.domElements.push(div);
  291. this._makeBreak();
  292. }
  293. _makeLabel(name, path) {
  294. let div = document.createElement('div');
  295. div.className = 'vis-network-configuration label';
  296. div.innerHTML = name;
  297. div.style.left = ((path.length - 1) * 10) + 'px';
  298. this.domElements.push(div);
  299. }
  300. _makeDropdown(arr, value) {
  301. let select = document.createElement('select');
  302. select.className = 'vis-network-configuration select';
  303. let selectedValue = 0;
  304. if (value !== undefined) {
  305. if (arr.indexOf(value) !== -1) {
  306. selectedValue = arr.indexOf(value);
  307. }
  308. }
  309. for (let i = 0; i < arr.length; i++) {
  310. let option = document.createElement("option");
  311. option.value = arr[i];
  312. if (i == selectedValue) {
  313. option.selected = 'selected';
  314. }
  315. option.innerHTML = arr[i];
  316. select.appendChild(option);
  317. }
  318. select.onchange = function () {me._update(this.value, path);}
  319. this.domElements.push(select);
  320. this._makeBreak();
  321. }
  322. _makeRange(arr, value, path) {
  323. let defaultValue = arr[0];
  324. let min = arr[1];
  325. let max = arr[2];
  326. let step = arr[3];
  327. let range = document.createElement('input');
  328. range.type = 'range';
  329. range.className = 'vis-network-configuration range'
  330. range.value = defaultValue;
  331. range.min = min;
  332. range.max = max;
  333. range.step = step;
  334. if (value !== undefined) {
  335. range.value = value;
  336. if (value * 0.1 < min) {
  337. range.min = value / 10;
  338. }
  339. if (value * 10 > max && max !== 1) {
  340. range.max = value * 10;
  341. }
  342. }
  343. let input = document.createElement("input");
  344. input.className = 'vis-network-configuration rangeinput'
  345. input.value = range.value;
  346. var me = this;
  347. range.onchange = function () {input.value = this.value; me._update(this.value, path);}
  348. range.oninput = function () {input.value = this.value;}
  349. this.domElements.push(range);
  350. this.domElements.push(input);
  351. this._makeBreak();
  352. }
  353. _makeCheckbox(defaultValue, value, path) {
  354. var checkbox = document.createElement('input');
  355. checkbox.type = "checkbox";
  356. checkbox.checked = defaultValue;
  357. if (value !== undefined) {
  358. checkbox.checked = value;
  359. }
  360. let me = this;
  361. checkbox.onchange = function() {me._update(this.value, path)}
  362. this.domElements.push(checkbox);
  363. }
  364. _makeBreak() {
  365. this.domElements.push(document.createElement("br"));
  366. }
  367. _handleObject(obj, path = []) {
  368. for (let subObj in obj) {
  369. if (obj.hasOwnProperty(subObj)) {
  370. let item = obj[subObj];
  371. let value = this._getValue(path);
  372. let newPath = this._addToPath(path, subObj);
  373. if (item instanceof Array) {
  374. this._handleArray(subObj, item, value, newPath);
  375. }
  376. else if (typeof item === 'string') {
  377. this._handleString(subObj, item, value, newPath);
  378. }
  379. else if (typeof item === 'boolean') {
  380. this._handleBoolean(subObj, item, value, newPath);
  381. }
  382. else if (item instanceof Object) {
  383. this._makeLabel(subObj, newPath);
  384. this._makeBreak();
  385. this._handleObject(item, newPath);
  386. }
  387. else {
  388. console.error("dont know how to handle", item, subObj, newPath);
  389. }
  390. }
  391. }
  392. }
  393. _handleArray(optionName, arr, value, path) {
  394. this._makeLabel(optionName, path);
  395. if (typeof arr[0] === 'string') {
  396. this._makeDropdown(arr, value, path);
  397. }
  398. else if (typeof arr[0] === 'number') {
  399. this._makeRange(arr, value, path);
  400. }
  401. }
  402. _handleString(optionName, string, value, path) {
  403. if (string !== 'color') {
  404. this._makeLabel(optionName, path);
  405. }
  406. else {
  407. this._makeLabel(optionName, path);
  408. //console.log("string", string, value, path);
  409. }
  410. this._makeLabel(string, []);
  411. this._makeBreak();
  412. }
  413. _handleBoolean(optionName, boolean, value, path) {
  414. this._makeLabel(optionName, path);
  415. this._makeCheckbox(boolean, value, path);
  416. this._makeBreak();
  417. }
  418. _update(value, path) {
  419. console.log("updated", value, path)
  420. }
  421. }
  422. export default ConfigurationSystem;