linny-r 1.6.4 → 1.6.6
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.
- package/package.json +1 -1
- package/static/scripts/linny-r-gui-actor-manager.js +4 -3
- package/static/scripts/linny-r-gui-controller.js +2 -2
- package/static/scripts/linny-r-gui-experiment-manager.js +7 -0
- package/static/scripts/linny-r-gui-file-manager.js +22 -8
- package/static/scripts/linny-r-gui-paper.js +28 -15
- package/static/scripts/linny-r-model.js +2 -2
- package/static/scripts/linny-r-vm.js +1 -1
package/package.json
CHANGED
@@ -305,14 +305,15 @@ class ActorManager {
|
|
305
305
|
// Set its round flags
|
306
306
|
a.round_flags = ali[2];
|
307
307
|
// Double-check: parse expression if weight has been changed.
|
308
|
-
|
309
|
-
|
308
|
+
const awx = monoSpacedVariables(ali[3]);
|
309
|
+
if(a.weight.text != awx) {
|
310
|
+
xp.expr = awx;
|
310
311
|
xp.compile();
|
311
312
|
if(xp.error) {
|
312
313
|
UI.warningInvalidWeightExpression(a, xp.error);
|
313
314
|
ok = false;
|
314
315
|
} else {
|
315
|
-
a.weight.update(
|
316
|
+
a.weight.update(xp);
|
316
317
|
}
|
317
318
|
}
|
318
319
|
// Update import/export status
|
@@ -549,9 +549,9 @@ class GUIController extends Controller {
|
|
549
549
|
this.buttons.actors.addEventListener('click',
|
550
550
|
() => ACTOR_MANAGER.showDialog());
|
551
551
|
this.buttons.diagram.addEventListener('click',
|
552
|
-
() => FILE_MANAGER.renderDiagramAsPNG());
|
552
|
+
() => FILE_MANAGER.renderDiagramAsPNG(event.shiftKey));
|
553
553
|
this.buttons.savediagram.addEventListener('click',
|
554
|
-
() => FILE_MANAGER.saveDiagramAsSVG());
|
554
|
+
() => FILE_MANAGER.saveDiagramAsSVG(event.shiftKey));
|
555
555
|
this.buttons.receiver.addEventListener('click',
|
556
556
|
() => RECEIVER.toggle());
|
557
557
|
// NOTE: All draggable & resizable dialogs "toggle" show/hide.
|
@@ -332,6 +332,9 @@ class GUIExperimentManager extends ExperimentManager {
|
|
332
332
|
document.getElementById('xp-reset-btn').classList.add('off');
|
333
333
|
}
|
334
334
|
this.updateParameters();
|
335
|
+
// NOTE: When UpdateDialog is called after an entity has been renamed,
|
336
|
+
// its variable list should be updated.
|
337
|
+
this.updateViewerVariable();
|
335
338
|
}
|
336
339
|
|
337
340
|
updateParameters() {
|
@@ -515,6 +518,10 @@ class GUIExperimentManager extends ExperimentManager {
|
|
515
518
|
addDistinct(vn, vl);
|
516
519
|
}
|
517
520
|
vl.sort((a, b) => UI.compareFullNames(a, b));
|
521
|
+
// NOTE: When the selected variable entity has been renamed, its
|
522
|
+
// name will not be in the list (and its old name cannot be inferred)
|
523
|
+
// so then clear it.
|
524
|
+
if(vl.indexOf(x.selected_variable) < 0) x.selected_variable = '';
|
518
525
|
for(let i = 0; i < vl.length; i++) {
|
519
526
|
const vn = vl[i];
|
520
527
|
// NOTE: FireFox selector dropdown areas have a pale gray
|
@@ -342,11 +342,18 @@ class GUIFileManager {
|
|
342
342
|
});
|
343
343
|
}
|
344
344
|
|
345
|
-
renderDiagramAsPNG() {
|
345
|
+
renderDiagramAsPNG(tight) {
|
346
|
+
// When `tight` is TRUE, add no whitespace around the diagram.
|
346
347
|
window.localStorage.removeItem('png-url');
|
347
|
-
|
348
|
-
|
349
|
-
|
348
|
+
if(tight) {
|
349
|
+
// First align to grid and then fit to size.
|
350
|
+
MODEL.alignToGrid();
|
351
|
+
UI.paper.fitToSize(1);
|
352
|
+
} else {
|
353
|
+
UI.paper.fitToSize();
|
354
|
+
MODEL.alignToGrid();
|
355
|
+
}
|
356
|
+
this.renderSVGAsPNG(UI.paper.opaqueSVG);
|
350
357
|
}
|
351
358
|
|
352
359
|
renderSVGAsPNG(svg) {
|
@@ -374,10 +381,17 @@ class GUIFileManager {
|
|
374
381
|
.catch((err) => UI.warn(UI.WARNING.NO_CONNECTION, err));
|
375
382
|
}
|
376
383
|
|
377
|
-
saveDiagramAsSVG() {
|
378
|
-
|
379
|
-
|
380
|
-
|
384
|
+
saveDiagramAsSVG(tight) {
|
385
|
+
// Output SVG as string with nodes and arrows 100% opaque.
|
386
|
+
if(tight) {
|
387
|
+
// First align to grid and then fit to size.
|
388
|
+
MODEL.alignToGrid();
|
389
|
+
UI.paper.fitToSize(1);
|
390
|
+
} else {
|
391
|
+
UI.paper.fitToSize();
|
392
|
+
MODEL.alignToGrid();
|
393
|
+
}
|
394
|
+
this.pushOutSVG(UI.paper.opaqueSVG);
|
381
395
|
}
|
382
396
|
|
383
397
|
pushOutSVG(svg) {
|
@@ -132,7 +132,11 @@ class Shape {
|
|
132
132
|
const ts = UI.paper.newSVGElement('tspan');
|
133
133
|
ts.setAttribute('x', x);
|
134
134
|
ts.setAttribute('dy', fh);
|
135
|
-
|
135
|
+
// NOTE: Non-breaking space must now (inside a TSPAN) be converted
|
136
|
+
// to normal spaces, or they will be rendered as ' ' and this
|
137
|
+
// will cause the SVG to break when it is inserted as picture into
|
138
|
+
// an MS Word document.
|
139
|
+
ts.textContent = lines[i].replaceAll('\u00A0', ' ');
|
136
140
|
el.appendChild(ts);
|
137
141
|
}
|
138
142
|
this.element.appendChild(el);
|
@@ -348,6 +352,13 @@ class Paper {
|
|
348
352
|
this.clear();
|
349
353
|
}
|
350
354
|
|
355
|
+
get opaqueSVG() {
|
356
|
+
// Return SVG as string with nodes and arrows 100% opaque.
|
357
|
+
// NOTE: The semi-transparent ovals behind rates on links have
|
358
|
+
// opacity 0.8 and hence are not affected.
|
359
|
+
return this.svg.outerHTML.replaceAll(' opacity="0.9"', ' opacity="1"');
|
360
|
+
}
|
361
|
+
|
351
362
|
clear() {
|
352
363
|
// First, clear the entire SVG
|
353
364
|
this.clearSVGElement(this.svg);
|
@@ -471,12 +482,12 @@ class Paper {
|
|
471
482
|
}
|
472
483
|
|
473
484
|
clearSVGElement(el) {
|
474
|
-
//
|
485
|
+
// Clear all sub-nodes of the specified SVG node.
|
475
486
|
if(el) while(el.lastChild) el.removeChild(el.lastChild);
|
476
487
|
}
|
477
488
|
|
478
489
|
addSVGAttributes(el, obj) {
|
479
|
-
//
|
490
|
+
// Add attributes specified by `obj` to (SVG) element `el`.
|
480
491
|
for(let prop in obj) {
|
481
492
|
if(obj.hasOwnProperty(prop)) el.setAttribute(prop, obj[prop]);
|
482
493
|
}
|
@@ -686,35 +697,35 @@ class Paper {
|
|
686
697
|
return el;
|
687
698
|
}
|
688
699
|
|
689
|
-
fitToSize() {
|
700
|
+
fitToSize(margin=30) {
|
690
701
|
// Adjust the dimensions of the main SVG to fit the graph plus 15px margin
|
691
702
|
// all around
|
692
703
|
this.removeInvisibleSVG();
|
693
704
|
const
|
694
705
|
bb = this.svg.getBBox(),
|
695
|
-
w = bb.width +
|
696
|
-
h = bb.height +
|
706
|
+
w = bb.width + margin,
|
707
|
+
h = bb.height + margin;
|
697
708
|
if(w !== this.width || h !== this.height) {
|
698
|
-
MODEL.translateGraph(-bb.x +
|
709
|
+
MODEL.translateGraph(-bb.x + margin / 2, -bb.y + margin);
|
699
710
|
this.width = w;
|
700
711
|
this.height = h;
|
701
712
|
this.svg.setAttribute('width', this.width);
|
702
713
|
this.svg.setAttribute('height', this.height);
|
703
714
|
this.zoom_factor = 1;
|
704
715
|
this.zoom_label.innerHTML = Math.round(100 / this.zoom_factor) + '%';
|
705
|
-
this.extend();
|
716
|
+
this.extend(margin);
|
706
717
|
}
|
707
718
|
}
|
708
719
|
|
709
|
-
extend() {
|
720
|
+
extend(margin=30) {
|
710
721
|
// Adjust the paper size to fit all objects WITHOUT changing the origin (0, 0)
|
711
722
|
// NOTE: keep a minimum page size to keep the scrolling more "natural"
|
712
723
|
this.removeInvisibleSVG();
|
713
724
|
const
|
714
725
|
bb = this.svg.getBBox(),
|
715
726
|
// Let `w` and `h` be the actual width and height in pixels
|
716
|
-
w = bb.x + bb.width +
|
717
|
-
h = bb.y + bb.height +
|
727
|
+
w = bb.x + bb.width + margin,
|
728
|
+
h = bb.y + bb.height + margin,
|
718
729
|
// Let `ccw` and `cch` be the size of the scrollable area
|
719
730
|
ccw = w / this.zoom_factor,
|
720
731
|
cch = h / this.zoom_factor;
|
@@ -1391,7 +1402,7 @@ class Paper {
|
|
1391
1402
|
// Add 2px margin
|
1392
1403
|
shift = 2;
|
1393
1404
|
const lfd = (luc.actualDelay(MODEL.t));
|
1394
|
-
if(lfd
|
1405
|
+
if(lfd != 0) {
|
1395
1406
|
// If delay, draw it in a circle behind arrow head
|
1396
1407
|
s = lfd;
|
1397
1408
|
bb = this.numberSize(s, 7);
|
@@ -1419,6 +1430,7 @@ class Paper {
|
|
1419
1430
|
{stroke:stroke_color, 'stroke-width': 0.5, fill: 'white'});
|
1420
1431
|
// MU symbol does not center prettily => raise by 1 px
|
1421
1432
|
const raise = (luc.multiplier === VM.LM_MEAN ||
|
1433
|
+
luc.multiplier === VM.LM_STARTUP ||
|
1422
1434
|
luc.multiplier === VM.LM_THROUGHPUT ? 1 :
|
1423
1435
|
(luc.multiplier === VM.LM_PEAK_INC ? 1.5 : 0));
|
1424
1436
|
arrw.shape.addText(epx, epy - raise, VM.LM_SYMBOLS[luc.multiplier],
|
@@ -1462,12 +1474,13 @@ class Paper {
|
|
1462
1474
|
epy = arrw.from_y + (shift + bi) * dy / l;
|
1463
1475
|
font_color = this.palette.produced;
|
1464
1476
|
}
|
1465
|
-
// Draw the rate in a semi-transparent white
|
1466
|
-
arrw.shape.
|
1477
|
+
// Draw the rate in a semi-transparent white roundbox.
|
1478
|
+
arrw.shape.addRect(epx, epy, tw, th,
|
1479
|
+
{fill: 'white', opacity: 0.8, rx: 2, ry: 2});
|
1467
1480
|
arrw.shape.addNumber(epx, epy, s, {fill: font_color, 'font-style': rrfs});
|
1468
1481
|
|
1469
1482
|
// Draw the share of cost (only if relevant and > 0) behind the rate
|
1470
|
-
// in a pale yellow filled box
|
1483
|
+
// in a pale yellow filled box.
|
1471
1484
|
if(MODEL.infer_cost_prices && luc.share_of_cost > 0) {
|
1472
1485
|
// Keep the right distance from the rate: the midpoint should
|
1473
1486
|
// increase by a varying length: number lengths / 2 when arrow is
|
@@ -8437,8 +8437,8 @@ class Link {
|
|
8437
8437
|
// Scales delay expression value to number of time steps on model
|
8438
8438
|
// time scale
|
8439
8439
|
let d = Math.floor(VM.SIG_DIF_FROM_ZERO + this.flow_delay.result(t));
|
8440
|
-
// NOTE:
|
8441
|
-
|
8440
|
+
// NOTE: Negative values are permitted. This might invalidate cost
|
8441
|
+
// price calculation -- to be checked!!
|
8442
8442
|
return d;
|
8443
8443
|
}
|
8444
8444
|
|
@@ -4295,7 +4295,7 @@ class VirtualMachine {
|
|
4295
4295
|
cv = this.chunk_variables[ci - this.chunk_offset];
|
4296
4296
|
}
|
4297
4297
|
// NOTE: Do not scale the coefficient of the cash variable.
|
4298
|
-
if(!cv[0].startsWith('C')) cc[ci] *= m;
|
4298
|
+
if(cv && !cv[0].startsWith('C')) cc[ci] *= m;
|
4299
4299
|
}
|
4300
4300
|
}
|
4301
4301
|
}
|