linny-r 2.0.8 → 2.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +3 -40
  2. package/package.json +6 -2
  3. package/server.js +19 -157
  4. package/static/images/solve-not-same-changed.png +0 -0
  5. package/static/images/solve-not-same-not-changed.png +0 -0
  6. package/static/images/solve-same-changed.png +0 -0
  7. package/static/images/solve-same-not-changed.png +0 -0
  8. package/static/index.html +137 -20
  9. package/static/linny-r.css +260 -23
  10. package/static/scripts/iro.min.js +7 -7
  11. package/static/scripts/linny-r-ctrl.js +126 -85
  12. package/static/scripts/linny-r-gui-actor-manager.js +23 -33
  13. package/static/scripts/linny-r-gui-chart-manager.js +56 -53
  14. package/static/scripts/linny-r-gui-constraint-editor.js +10 -14
  15. package/static/scripts/linny-r-gui-controller.js +644 -260
  16. package/static/scripts/linny-r-gui-dataset-manager.js +64 -66
  17. package/static/scripts/linny-r-gui-documentation-manager.js +11 -17
  18. package/static/scripts/linny-r-gui-equation-manager.js +22 -22
  19. package/static/scripts/linny-r-gui-experiment-manager.js +124 -141
  20. package/static/scripts/linny-r-gui-expression-editor.js +26 -12
  21. package/static/scripts/linny-r-gui-file-manager.js +42 -48
  22. package/static/scripts/linny-r-gui-finder.js +294 -55
  23. package/static/scripts/linny-r-gui-model-autosaver.js +2 -4
  24. package/static/scripts/linny-r-gui-monitor.js +35 -41
  25. package/static/scripts/linny-r-gui-paper.js +42 -70
  26. package/static/scripts/linny-r-gui-power-grid-manager.js +31 -34
  27. package/static/scripts/linny-r-gui-receiver.js +1 -2
  28. package/static/scripts/linny-r-gui-repository-browser.js +44 -46
  29. package/static/scripts/linny-r-gui-scale-unit-manager.js +32 -32
  30. package/static/scripts/linny-r-gui-sensitivity-analysis.js +61 -67
  31. package/static/scripts/linny-r-gui-undo-redo.js +94 -95
  32. package/static/scripts/linny-r-milp.js +20 -24
  33. package/static/scripts/linny-r-model.js +1932 -2274
  34. package/static/scripts/linny-r-utils.js +27 -27
  35. package/static/scripts/linny-r-vm.js +900 -998
  36. package/static/show-png.html +0 -113
package/README.md CHANGED
@@ -36,8 +36,8 @@ Linny-R is developed as a JavaScript package, and requires that **Node.js**
36
36
  is installed on your computer. This software can be downloaded from
37
37
  <a href="https://nodejs.org" target="_blank">https://nodejs.org</a>.
38
38
  Make sure that you choose the correct installer for your computer.
39
- Linny-R is developed using the _current_ release. Presently (December 2024)
40
- this is 23.3.0.
39
+ Linny-R is developed using the _current_ release. Presently (May 2025)
40
+ this is 24.1.0.
41
41
 
42
42
  Run the installer and accept the default settings.
43
43
  There is <u>**no**</u> need to install the optional _Tools for Native Modules_.
@@ -48,7 +48,7 @@ Verify the installation by typing:
48
48
 
49
49
  ``node --version``
50
50
 
51
- The response should be the version number of Node.js, for example: v23.3.0.
51
+ The response should be the version number of Node.js, for example: v24.1.0.
52
52
 
53
53
  ## Installing Linny-R
54
54
  It is advisable to install Linny-R in a directory on your computer, **not**
@@ -116,7 +116,6 @@ The `linny-r` package directory should contain this file `README.md`, the files
116
116
  `static`. This `static` directory should contain three HTML files:
117
117
 
118
118
  * `index.html` (the browser-based GUI)
119
- * `show-png.html` (to render SVG diagrams as PNG images)
120
119
  * `show-diff.html` (to display differences between two Linny-R models)
121
120
 
122
121
  It should also contain the style sheet `linny-r.css` required by the GUI.
@@ -379,7 +378,6 @@ You can customize Linny-R by adding more arguments to the `node` command
379
378
  in the launch script:
380
379
 
381
380
  <pre>
382
- dpi=[number] to overrule the default resolution (300 dpi) for Inkscape
383
381
  launch to automatically launch Linny-R in your default browser
384
382
  port=[number] to overrule the default port number (5050)
385
383
  solver=[name] to overrule the default sequence (Gurobi, MOSEK, CPLEX, SCIP, LP_solve)
@@ -402,8 +400,6 @@ The sub-directories of this directory `user` are used by Linny-R to store files.
402
400
  * `channel` and `callback` will be used to interact with Linny-R via its _Receiver_
403
401
  * `data` will be used by the _Dataset Manager_ to locate datasets for which
404
402
  a path has been specified
405
- * `diagrams` will be used to render Scalable Vector Graphics (SVG) files as
406
- Portable Network Graphics (PNG) using Inkscape (if installed)
407
403
  * `models` will contain models that you saved by Shift-clicking on the
408
404
  _Save_ button, or using the keyboard shortcut Ctrl-Shift-S
409
405
  * `modules` will contain models stored in the `local host` _repository_
@@ -419,39 +415,6 @@ The sub-directories of this directory `user` are used by Linny-R to store files.
419
415
  > option. This will create a new, empty workspace in the specified path.
420
416
  > It will **not** affect or duplicate information from existing workspaces.
421
417
 
422
- ## Installing Inkscape
423
-
424
- Linny-R creates its diagrams and charts as SVG images.
425
- When you download a diagram, it will be saved as a .svg file.
426
- These files can be viewed and edited using Inkscape, an open source
427
- vector graphics editor.
428
-
429
- As it may be tedious to first save a diagram as SVG and then render it
430
- manually as a bitmap image, Linny-R features a *Render diagram as bitmap*
431
- button on the top toolbar, and on the bottom toolbar of the _Chart manager_.
432
- When you click it, Linny-R will send the image as SVG to the server.
433
- The server script will save the SVG in the `user/diagrams` sub-directory,
434
- and then try to execute an Inkscape command that will convert this SVG to
435
- a PNG image file in the same directory.
436
- The file name will be `diagram-(date and time).png`.
437
- Meanwhile, the browser will have opened a new tab that will be "waiting"
438
- for this PNG image to become available.
439
- If rendering was successful, the image will appear in this browser tab;
440
- if rendering failed, the original SVG image will be shown.
441
-
442
- To install Inkscape, please look here:
443
- <a href="https://inkscape.org/release"
444
- target="_blank">https://inkscape.org/release</a>
445
-
446
- Linny-R will automatically detect whether Inkscape is installed by searching
447
- for it in the environment variable PATH on your computer. On a macOS computer,
448
- Linny-R will look for Inkscape in `/Applications/Inkscape.app/Contents/MacOS`.
449
-
450
- > [!NOTE]
451
- > The installation wizard for Inkscape (version 1.3) may **not**
452
- > add the application to the PATH variable. Please check whether you need to
453
- > do this yourself.
454
-
455
418
  ## Using Linny-R console
456
419
 
457
420
  The console-only version of Linny-R allows you to run a Linny-R model without
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "linny-r",
3
- "version": "2.0.8",
3
+ "version": "2.0.10",
4
4
  "description": "Executable graphical language with WYSIWYG editor for MILP models",
5
5
  "main": "server.js",
6
6
  "scripts": {
@@ -21,7 +21,11 @@
21
21
  "optimization",
22
22
  "simulation",
23
23
  "unit commitment",
24
- "generation expansion"
24
+ "industrial ecology",
25
+ "linearized power flow",
26
+ "loss approximation",
27
+ "generation expansion",
28
+ "grid expansion"
25
29
  ],
26
30
  "author": "Pieter W.G. Bots",
27
31
  "license": "MIT",
package/server.js CHANGED
@@ -1265,29 +1265,27 @@ function rcvrCallBack(res, rpath, rfile, script) {
1265
1265
  const STATIC_FILES = {
1266
1266
  // MIME types of files that can be served
1267
1267
  extensions: {
1268
- js: 'application/javascript',
1269
- xml: 'application/xml',
1270
- wav: 'audio/x-wav',
1271
- ttc: 'font/collection',
1272
- otf: 'font/otf',
1273
- ttf: 'font/ttf',
1274
- icns: 'image/icns',
1275
- png: 'image/png',
1276
- svg: 'image/svg+xml',
1277
- ico: 'image/x-icon',
1278
- css: 'text/css',
1279
- html: 'text/html',
1280
- txt: 'text/plain'
1281
- },
1268
+ js: 'application/javascript',
1269
+ xml: 'application/xml',
1270
+ wav: 'audio/x-wav',
1271
+ ttc: 'font/collection',
1272
+ otf: 'font/otf',
1273
+ ttf: 'font/ttf',
1274
+ icns: 'image/icns',
1275
+ png: 'image/png',
1276
+ svg: 'image/svg+xml',
1277
+ ico: 'image/x-icon',
1278
+ css: 'text/css',
1279
+ html: 'text/html',
1280
+ txt: 'text/plain'
1281
+ },
1282
1282
  // Subdirectories of (main)/static/ directory from which files with
1283
1283
  // accepted MIME types can be served
1284
1284
  directories: {
1285
1285
  '/scripts': ['js'],
1286
1286
  '/images': ['icns', 'ico', 'png', 'svg'],
1287
1287
  '/fonts': ['otf', 'ttc', 'ttf'],
1288
- '/sounds': ['wav'],
1289
- // NOTE: diagrams will actually be served from (main)/user/diagrams/
1290
- '/diagrams': ['png', 'svg']
1288
+ '/sounds': ['wav']
1291
1289
  },
1292
1290
  // Files that can be served from the (main)/static/ directory itself
1293
1291
  files: [
@@ -1417,17 +1415,11 @@ function permittedFile(path) {
1417
1415
  }
1418
1416
 
1419
1417
  function serveStaticFile(res, path) {
1420
- // Serve the specified path (if permitted: only diagrams and static files)
1418
+ // Serve the specified path (if permitted: only static files)
1421
1419
  if(path === '/' || path === '') path = '/index.html';
1422
- if(path.startsWith('/diagrams/')) {
1423
- // Serve diagrams from the (main)/user/diagrams/ sub-directory
1424
- logAction('Diagram: ' + path);
1425
- path = WORKING_DIRECTORY + '/user' + path;
1426
- } else {
1427
- // Other files from the (main)/static/ subdirectory
1428
- logAction('Static file: ' + path);
1429
- path = MODULE_DIRECTORY + '/static' + path;
1430
- }
1420
+ // Serve files from the (main)/static/ subdirectory
1421
+ logAction('Static file: ' + path);
1422
+ path = MODULE_DIRECTORY + '/static' + path;
1431
1423
  fs.readFile(path, (err, data) => {
1432
1424
  if(err) {
1433
1425
  console.log(err);
@@ -1442,75 +1434,6 @@ function serveStaticFile(res, path) {
1442
1434
  });
1443
1435
  }
1444
1436
 
1445
- function convertSVGtoPNG(req, res, sp) {
1446
- // Convert SVG data from browser to PNG image using Inkscape
1447
- // NOTE: images can be huge, so send only the file name as response;
1448
- // Linny-R will open a new browser window, load the file, and display it
1449
- const
1450
- svg = decodeURI(atob(sp.get('data'))),
1451
- // Use current time as file name
1452
- fn = 'diagram-' +
1453
- (new Date()).toISOString().slice(0, 19).replace(/[\-\:]/g, ''),
1454
- fp = path.join(WORKSPACE.diagrams, fn);
1455
- // NOTE: use binary encoding for SVG file
1456
- logAction('Saving SVG file: ' + fp);
1457
- try {
1458
- fs.writeFileSync(fp + '.svg', svg);
1459
- } catch(error) {
1460
- console.log('WARNING: Failed to save SVG --', error);
1461
- }
1462
- // Use Inkscape to convert SVG to the requested format
1463
- if(SETTINGS.inkscape) {
1464
- logAction('Rendering image');
1465
- let
1466
- cmd = SETTINGS.inkscape,
1467
- svg = fp + '.svg';
1468
- // Enclose paths in double quotes if they contain spaces
1469
- if(cmd.indexOf(' ') >= 0) cmd = `"${cmd}"`;
1470
- if(svg.indexOf(' ') >= 0) svg = `"${svg}"`;
1471
- cmd += ` --export-type=png --export-dpi=${SETTINGS.dpi} ${svg}`;
1472
- console.log(cmd);
1473
- child_process.exec(cmd,
1474
- (error, stdout, stderr) => {
1475
- let ext = '.svg';
1476
- console.log(stdout);
1477
- if(error) {
1478
- console.log('WARNING: Failed to run Inkscape --', error);
1479
- console.log(stderr);
1480
- } else {
1481
- // Look for the PNG file.
1482
- const mode = fs.constants.R_OK | fs.constants.W_O;
1483
- try {
1484
- fs.accessSync(fp + '.png', mode);
1485
- ext = '.png';
1486
- } catch(err) {
1487
- // NOTE: Inkscape 1.3 adds ".png" to the original file name,
1488
- // so this may end on ".svg.png"
1489
- try {
1490
- fs.accessSync(fp + '.svg.png', mode);
1491
- // If found, rename the PNG file.
1492
- fs.renameSync(fp + '.svg.png', fp + '.png');
1493
- ext = '.png';
1494
- } catch(err) {
1495
- console.log('WARNING: Inkscape did not output a PNG file');
1496
- }
1497
- }
1498
- // Delete the SVG file.
1499
- try {
1500
- fs.unlinkSync(fp + '.svg');
1501
- } catch(error) {
1502
- console.log(`NOTICE: Failed to delete SVG file "${fp}.svg"`);
1503
- }
1504
- }
1505
- // Return the image file name (PNG if successful, otherwise SVG)
1506
- servePlainText(res, 'diagrams/' + fn + ext);
1507
- }
1508
- );
1509
- } else {
1510
- servePlainText(res, 'diagrams/' + fn + '.svg');
1511
- }
1512
- }
1513
-
1514
1437
  // Convenience functions to fetch data from external URL
1515
1438
  // NOTE: the parameters `on_ok` and `on_error` must be functions with two
1516
1439
  // parameters:
@@ -1591,8 +1514,6 @@ function commandLineSettings() {
1591
1514
  // Sets default settings, and then checks the command line arguments.
1592
1515
  const settings = {
1593
1516
  cli_name: (PLATFORM.startsWith('win') ? 'Command Prompt' : 'Terminal'),
1594
- inkscape: '',
1595
- dpi: 300,
1596
1517
  launch: false,
1597
1518
  port: 5050,
1598
1519
  preferred_solver: '',
@@ -1604,7 +1525,6 @@ function commandLineSettings() {
1604
1525
  usage = `Usage: ${app} server [options]
1605
1526
 
1606
1527
  Possible options are:
1607
- dpi=[number] will make InkScape render SVGs in the specified resolution
1608
1528
  help will display these command line options
1609
1529
  launch will open the Linny-R GUI in a browser window
1610
1530
  port=[number] will listen at the specified port number
@@ -1635,14 +1555,6 @@ Possible options are:
1635
1555
  } else {
1636
1556
  settings.preferred_solver = av[1];
1637
1557
  }
1638
- } else if(av[0] === 'dpi') {
1639
- // Accept any number greater than or equal to 1024.
1640
- const n = parseInt(av[1]);
1641
- if(isNaN(n) || n > 1200) {
1642
- console.log(`WARNING: Invalid resolution ${av[1]} (max. 1200 dpi)`);
1643
- } else {
1644
- settings.dpi = n;
1645
- }
1646
1558
  } else if(av[0] === 'workspace') {
1647
1559
  // User directory must be READ/WRITE-accessible.
1648
1560
  try {
@@ -1665,55 +1577,6 @@ Possible options are:
1665
1577
  }
1666
1578
  }
1667
1579
  }
1668
- // Check whether Inkscape has been installed.
1669
- const path_list = process.env.PATH.split(path.delimiter);
1670
- for(let i = 0; i < path_list.length; i++) {
1671
- // Check whether it is an Inkscape path.
1672
- match = path_list[i].match(/inkscape/i);
1673
- // If so, use it (so the *last* matching path will be used).
1674
- if(match) settings.inkscape = path_list[i];
1675
- }
1676
- // NOTE: On macOS, Inkscape is not added to the PATH environment variable.
1677
- if(!settings.inkscape && PLATFORM === 'darwin') {
1678
- console.log('Looking for Inkscape in Applications...');
1679
- try {
1680
- // Look in the default directory.
1681
- const ip = '/Applications/Inkscape.app/Contents/MacOS';
1682
- fs.accessSync(ip);
1683
- settings.inkscape = ip;
1684
- } catch(err) {
1685
- // No real error, so no action needed.
1686
- }
1687
- }
1688
- // Verify that Inkscape is installed.
1689
- if(settings.inkscape) {
1690
- // NOTE: On Windows, the command line version is a .com file.
1691
- let ip = path.join(settings.inkscape,
1692
- 'inkscape' + (PLATFORM.startsWith('win') ? '.com' : ''));
1693
- try {
1694
- fs.accessSync(ip, fs.constants.X_OK);
1695
- } catch(err) {
1696
- // NOTE: As of Inkscape version 1.3, the command line executable
1697
- // is called inkscapecom(.com).
1698
- ip = path.join(settings.inkscape,
1699
- 'inkscapecom' + (PLATFORM.startsWith('win') ? '.com' : ''));
1700
- }
1701
- try {
1702
- fs.accessSync(ip, fs.constants.X_OK);
1703
- console.log('Path to Inkscape:', settings.inkscape);
1704
- settings.inkscape = ip;
1705
- console.log(
1706
- `SVG will be rendered with ${settings.dpi} dpi resolution`);
1707
- } catch(err) {
1708
- settings.inkscape = '';
1709
- console.log(err.message);
1710
- console.log(
1711
- 'WARNING: Failed to access the Inkscape command line application');
1712
- }
1713
- } else {
1714
- console.log(
1715
- 'Inkscape not installed, so images will not be rendered as PNG');
1716
- }
1717
1580
  return settings;
1718
1581
  }
1719
1582
 
@@ -1741,7 +1604,6 @@ function createWorkspace() {
1741
1604
  channel: path.join(SETTINGS.user_dir, 'channel'),
1742
1605
  callback: path.join(SETTINGS.user_dir, 'callback'),
1743
1606
  data: path.join(SETTINGS.user_dir, 'data'),
1744
- diagrams: path.join(SETTINGS.user_dir, 'diagrams'),
1745
1607
  models: path.join(SETTINGS.user_dir, 'models'),
1746
1608
  modules: path.join(SETTINGS.user_dir, 'modules'),
1747
1609
  reports: path.join(SETTINGS.user_dir, 'reports'),
package/static/index.html CHANGED
@@ -277,13 +277,9 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
277
277
  title="Sensitivity analysis (Ctrl-J)">
278
278
  <img id="experiment-btn" class="btn enab" src="images/experiment.png"
279
279
  title="Manage experiments (Ctrl-X)">
280
- <a href="show-png.html" target="_blank"
281
- style="text-decoration: none; outline: none">
282
- <img id="diagram-btn" class="btn enab" src="images/diagram.png"
283
- title="Render diagram as bitmap at 300 dpi (Ctrl-P)">
284
- </a>
285
280
  <img id="savediagram-btn" class="btn enab" src="images/save-diagram.png"
286
- title="Download diagram as Scalable Vector Graphics (Ctrl-G)">
281
+ title="Download diagram as Portable Network Graphics bitmap image (Ctrl-P)
282
+ &#x270E; Shift-click to download as Scalable Vector Graphics (Ctrl-Shift-P)">
287
283
  <img id="finder-btn" class="btn enab" src="images/find.png"
288
284
  title="Find model elements by their name (Ctrl-F)">
289
285
  <img id="monitor-btn" class="btn enab" src="images/monitor.png"
@@ -771,6 +767,24 @@ NOTE: Unit symbols are case-sensitive, so BTU &ne; Btu">
771
767
  <table id="power-grids-table">
772
768
  </table>
773
769
  </div>
770
+ <table>
771
+ <tr title="Checked aspects will be ignored for all power grids">
772
+ <td style="padding-bottom: 3px; font-style: italic">Disregard:</td>
773
+ <td style="padding: 0px; width: 20px">
774
+ <div id="power-grids-capacity" class="box clear"></div>
775
+ </td>
776
+ <td style="padding-bottom: 3px; width: 70px">Congestion</td>
777
+ <td style="padding: 0px; width: 20px">
778
+ <div id="power-grids-KVL" class="box clear"></div>
779
+ </td>
780
+ <td style="padding-bottom: 3px; width: 35px"
781
+ title="Kirchhoff's Voltage Law">KVL</td>
782
+ <td style="padding: 0px; width: 20px">
783
+ <div id="power-grids-losses" class="box clear"></div>
784
+ </td>
785
+ <td style="padding-bottom: 3px">Losses</td>
786
+ </tr>
787
+ </table>
774
788
  </div>
775
789
  </div>
776
790
 
@@ -1716,7 +1730,86 @@ Each line should represent the points of a different bound line.">
1716
1730
  </div>
1717
1731
  </div>
1718
1732
  </div>
1733
+
1734
+ <!-- the DATASET GROUP modal allows editing properties of multiple datasets -->
1735
+ <div id="datasetgroup-modal" class="modal">
1736
+ <div id="datasetgroup-dlg" class="inp-dlg">
1737
+ <div class="dlg-title">
1738
+ Dataset group properties
1739
+ <span id="datasetgroup-group"></span>
1740
+ <img class="cancel-btn" src="images/cancel.png">
1741
+ <img class="ok-btn" src="images/ok.png">
1742
+ </div>
1743
+ <div id="datasetgroup-prefix-lbl">Prefix:</div>
1744
+ <input id="datasetgroup-prefix" type="text" autocomplete="off">
1745
+ <div id="datasetgroup-default-lbl">Default value:</div>
1746
+ <input id="datasetgroup-default" type="text" autocomplete="off">
1747
+ <div id="datasetgroup-unit-lbl">Unit:</div>
1748
+ <input id="datasetgroup-unit" type="text" list="units-data" autocomplete="off">
1749
+ <div id="datasetgroup-periodic" class="box clear"></div>
1750
+ <div id="datasetgroup-periodic-lbl">Periodic</div>
1751
+ <div id="datasetgroup-array" class="box clear"></div>
1752
+ <div id="datasetgroup-array-lbl">Array</div>
1753
+ <div id="datasetgroup-no-time-msg">
1754
+ Arrays ignore time dimension
1755
+ </div>
1756
+ <div id="datasetgroup-time-step-lbl">Time step:</div>
1757
+ <input id="datasetgroup-time-scale" type="text" autocomplete="off">
1758
+ <select id="datasetgroup-time-unit">
1759
+ <option value="year">yr</option>
1760
+ <option value="week">wk</option>
1761
+ <option value="day">d</option>
1762
+ <option value="hour">h</option>
1763
+ <option value="minute">m</option>
1764
+ <option value="second">s</option>
1765
+ </select>
1766
+ <div id="datasetgroup-method-lbl">Method:</div>
1767
+ <select id="datasetgroup-method">
1768
+ <option value="nearest">at nearest t</option>
1769
+ <option value="w-mean">weighted mean</option>
1770
+ <option value="w-sum">weighted sum</option>
1771
+ <option value="max">maximum</option>
1772
+ </select>
1773
+ <div id="datasetgroup-separator"></div>
1774
+ <div id="datasetgroup-modif-header">Modifiers</div>
1775
+ <div id="datasetgroup-modif-titles">
1776
+ <span>Selector</span>
1777
+ <span style="margin-left: 35px">Expression</span>
1778
+ </div>
1779
+ <div id="datasetgroup-modif-scroll-area">
1780
+ <table id="datasetgroup-modif-table">
1781
+ </table>
1782
+ </div>
1783
+ <div id="datasetgroup-modif-buttons">
1784
+ <img id="dsg-add-modif-btn" class="btn enab"
1785
+ src="images/add-selector.png" title="Add new selector">
1786
+ <img id="dsg-rename-modif-btn" class="btn disab" src="images/rename.png"
1787
+ title="Rename selected modifier">
1788
+ <img id="dsg-edit-modif-btn" class="btn disab"
1789
+ src="images/edit.png" title="Edit expression of selected modifier">
1790
+ <img id="dsg-delete-modif-btn" class="btn disab"
1791
+ src="images/delete.png" title="Delete selected modifier"
1792
+ style="margin-left: 20px">
1793
+ </div>
1794
+ </div>
1795
+ </div>
1719
1796
 
1797
+ <!-- the GROUP SELECTOR dialog prompts for a new selector -->
1798
+ <div id="group-selector-modal" class="modal">
1799
+ <div id="group-selector-dlg" class="inp-dlg">
1800
+ <div class="dlg-title">
1801
+ <span id="group-selector-action">Add</span> selector
1802
+ <img class="cancel-btn" src="images/cancel.png">
1803
+ <img class="ok-btn" src="images/ok.png">
1804
+ </div>
1805
+ <input id="group-selector-name" type="text"
1806
+ title="Can contain only alphanumeric characters, +, -, and %
1807
+ NOTE: * and ? will be interpreted as wildcards"
1808
+ maxlength="10" autocomplete="off">
1809
+ <div id="group-selector-label">(1 to 10 characters)</div>
1810
+ </div>
1811
+ </div>
1812
+
1720
1813
  <!-- The CLONE dialog prompts for a prefix -->
1721
1814
  <div id="clone-modal" class="modal">
1722
1815
  <div id="clone-dlg" class="inp-dlg">
@@ -2234,13 +2327,8 @@ NOTE: * and ? will be interpreted as wildcards"
2234
2327
  </div>
2235
2328
  <div id="chart-only-buttons">
2236
2329
  <img id="chart-save-btn" class="btn enab" src="images/save-chart.png"
2237
- title="Save chart diagram">
2238
- <a id="chart-render-btn" href="show-png.html" target="_blank"
2239
- style="margin-left: 4px; text-decoration: none; outline: none">
2240
- <img class="btn enab" src="images/chart.png"
2241
- title="Render chart diagram as PNG"
2242
- style="height: 20px; width: 20px">
2243
- </a>
2330
+ title="Download chart as bitmap image (PNG)
2331
+ &#x270E; Shift-click to download chart as Scalable Vector Graphics (SVG)">
2244
2332
  <img id="chart-widen-btn" class="btn enab" src="images/stretch.png"
2245
2333
  title="Widen chart" style="margin-left: 24px">
2246
2334
  <img id="chart-narrow-btn" class="btn enab" src="images/compress.png"
@@ -2858,7 +2946,9 @@ NOTE: * and ? will be interpreted as wildcards"
2858
2946
  <label>Settings:</label>
2859
2947
  <input id="xp-settings-selector-string" type="text" autocomplete="off"
2860
2948
  title="Can specifiy time step, simulation period, block length and look-ahead.
2861
- Example: s=0.5h t=1-480 b=24 l=24 (in this order: s t b l)">
2949
+ Example: s=0.5h t=1-480 b=24 l=24
2950
+ When modeling power grids, -c indicates &ldquo;disregard grid capacity&rdquo;,
2951
+ -k &ldquo;disregard Kirchhoff's Voltage Law&rdquo;, and -l &ldquo;disregard power losses&rdquo;">
2862
2952
  </div>
2863
2953
  </div>
2864
2954
  </div>
@@ -3048,12 +3138,17 @@ where X can be one or several of these letters: ABCDELPQ">
3048
3138
  <div id="finder-status">
3049
3139
  <span id="finder-count"></span> found
3050
3140
  </div>
3051
- <img id="finder-edit-btn" class="btn enab"
3052
- src="images/edit.png"
3053
- title="Edit attributes">
3054
- <img id="finder-copy-btn" class="btn enab"
3055
- src="images/table-to-clpbrd.png"
3056
- title="Copy entity attributes to clipboard">
3141
+ <div id="finder-status-buttons">
3142
+ <img id="finder-edit-btn" class="btn enab"
3143
+ src="images/edit.png"
3144
+ title="Edit attributes">
3145
+ <img id="finder-chart-btn" class="btn enab"
3146
+ src="images/chart.png"
3147
+ title="Add attribute to chart">
3148
+ <img id="finder-copy-btn" class="btn enab"
3149
+ src="images/table-to-clpbrd.png"
3150
+ title="Copy entity attributes to clipboard">
3151
+ </div>
3057
3152
  <div id="finder-separator"></div>
3058
3153
  <div id="finder-item-header">(no item selected)</div>
3059
3154
  <div id="finder-item-scroll-area">
@@ -3068,6 +3163,28 @@ where X can be one or several of these letters: ABCDELPQ">
3068
3163
  <div id="finder-resize" class="resizer"></div>
3069
3164
  </div>
3070
3165
 
3166
+ <!-- the CONFIRM ADD CHART VARIABLES modal asks to confirm to add a
3167
+ specific attribute of the filtered entities to the current chart -->
3168
+ <div id="confirm-add-chart-variables-modal" class="modal">
3169
+ <div id="confirm-add-chart-variables-dlg" class="inp-dlg">
3170
+ <div class="dlg-title">
3171
+ Add to chart
3172
+ <img class="cancel-btn" src="images/cancel.png">
3173
+ <img class="ok-btn" src="images/ok.png">
3174
+ </div>
3175
+ <div style="margin: 2px; padding-right: 2px; white-space: nowrap">
3176
+ <select id="confirm-add-chart-variables-attribute"></select>
3177
+ of <span id="confirm-add-chart-variables-count"></span>
3178
+ </div>
3179
+ <div>
3180
+ <div id="confirm-add-chart-variables-stacked" class="box clear"></div>
3181
+ <div style="display:inline-block; vertical-align:top; margin-top: 3px">
3182
+ Display as stacked areas
3183
+ </div>
3184
+ </div>
3185
+ </div>
3186
+ </div>
3187
+
3071
3188
  <!-- the MONITOR dialog shows solver progress and messages, and model equations -->
3072
3189
  <div id="monitor-dlg" class="inp-dlg">
3073
3190
  <div id="monitor-hdr" class="dragger dlg-title">Solver monitor