flocc 0.5.18 → 0.5.21
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/dist/agents/Agent.d.ts +170 -33
- package/dist/environments/Environment.d.ts +133 -37
- package/dist/environments/GridEnvironment.d.ts +20 -6
- package/dist/flocc.es.js +1489 -488
- package/dist/flocc.js +1489 -488
- package/dist/helpers/KDTree.d.ts +2 -2
- package/dist/helpers/Network.d.ts +143 -67
- package/dist/helpers/NumArray.d.ts +1 -0
- package/dist/helpers/Rule.d.ts +58 -0
- package/dist/helpers/Terrain.d.ts +134 -27
- package/dist/helpers/Vector.d.ts +151 -22
- package/dist/renderers/ASCIIRenderer.d.ts +32 -3
- package/dist/renderers/AbstractRenderer.d.ts +17 -2
- package/dist/renderers/CanvasRenderer.d.ts +55 -0
- package/dist/renderers/Heatmap.d.ts +51 -6
- package/dist/renderers/TableRenderer.d.ts +94 -2
- package/dist/types/HeatmapAxis.d.ts +10 -0
- package/dist/utils/clamp.d.ts +9 -5
- package/dist/utils/distance.d.ts +15 -6
- package/dist/utils/gaussian.d.ts +9 -3
- package/dist/utils/gcd.d.ts +8 -0
- package/dist/utils/internal/copyArray.d.ts +1 -1
- package/dist/utils/lerp.d.ts +13 -4
- package/dist/utils/manhattanDistance.d.ts +15 -7
- package/dist/utils/max.d.ts +9 -0
- package/dist/utils/mean.d.ts +9 -3
- package/dist/utils/median.d.ts +10 -2
- package/dist/utils/min.d.ts +8 -0
- package/dist/utils/sample.d.ts +2 -0
- package/dist/version.d.ts +3 -0
- package/package.json +7 -3
- package/dist/helpers/Data.d.ts +0 -5
- package/dist/utils/internal/torusNormalize.d.ts +0 -1
package/dist/flocc.es.js
CHANGED
|
@@ -372,10 +372,19 @@ function sum(arr) {
|
|
|
372
372
|
}
|
|
373
373
|
|
|
374
374
|
/**
|
|
375
|
-
* Linearly
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
*
|
|
375
|
+
* Linearly interpolates between `x` and `y`. The third parameter `t` (usually
|
|
376
|
+
* a value between `0` and `1`) is the amount by which to interpolate — a value of `0`
|
|
377
|
+
* returns the `x` value and `1` returns the `y` value.
|
|
378
|
+
*
|
|
379
|
+
* ```js
|
|
380
|
+
* lerp(5, 10, 0.5); // returns 7.5
|
|
381
|
+
* lerp(0, 100, 0.1); // returns 10
|
|
382
|
+
* lerp(22, 79, 1); // returns 79
|
|
383
|
+
* ```
|
|
384
|
+
*
|
|
385
|
+
* @param x The first value.
|
|
386
|
+
* @param y The second value.
|
|
387
|
+
* @param t The amount by which to interpolate (0 returns x, 1 returns y).
|
|
379
388
|
* @since 0.2.4
|
|
380
389
|
*/
|
|
381
390
|
function lerp(x, y, t) {
|
|
@@ -386,7 +395,7 @@ function lerp(x, y, t) {
|
|
|
386
395
|
* Copies the values of `source` to `arr`
|
|
387
396
|
* or to a new Array.
|
|
388
397
|
*
|
|
389
|
-
* @
|
|
398
|
+
* @hidden
|
|
390
399
|
* @param {Array} source The Array to copy values from.
|
|
391
400
|
* @param {Array} [arr=[]] The Array to copy values to.
|
|
392
401
|
* @returns {Array}
|
|
@@ -403,6 +412,8 @@ function copyArray(source, arr) {
|
|
|
403
412
|
}
|
|
404
413
|
|
|
405
414
|
/**
|
|
415
|
+
* A `Vector` contains multi-dimensional numeric data.
|
|
416
|
+
*
|
|
406
417
|
* @since 0.1.0
|
|
407
418
|
*/
|
|
408
419
|
var Vector = /** @class */ (function () {
|
|
@@ -415,20 +426,40 @@ var Vector = /** @class */ (function () {
|
|
|
415
426
|
this.dimension = data ? data.length : 0;
|
|
416
427
|
}
|
|
417
428
|
/**
|
|
429
|
+
* Retrieve a value from a `Vector` by its index. If the given index is greater than the
|
|
430
|
+
* `Vector`'s dimension, this returns `0` by default.
|
|
431
|
+
*
|
|
432
|
+
* ```js
|
|
433
|
+
* const v = new Vector(1, 2, 4);
|
|
434
|
+
*
|
|
435
|
+
* v.index(0); // returns 1
|
|
436
|
+
* v.index(2); // returns 4
|
|
437
|
+
* v.index(5); // returns 0
|
|
438
|
+
* ```
|
|
418
439
|
* @since 0.1.0
|
|
419
440
|
*/
|
|
420
|
-
Vector.prototype.index = function (
|
|
421
|
-
if (this.dimension >
|
|
422
|
-
return this.data[
|
|
441
|
+
Vector.prototype.index = function (i) {
|
|
442
|
+
if (this.dimension > i) {
|
|
443
|
+
return this.data[i];
|
|
423
444
|
}
|
|
424
445
|
// Attempting to access index ${n} on a vector greater than the vector's dimension returns 0 by default
|
|
425
446
|
return 0;
|
|
426
447
|
};
|
|
427
448
|
/**
|
|
428
|
-
*
|
|
429
|
-
* the dimension will be increased to the dimensionality implied by the index.
|
|
430
|
-
* @param i
|
|
431
|
-
* @param value
|
|
449
|
+
* Set the value at a given index. If the index is greater than the {@linkcode dimension}
|
|
450
|
+
* of this `Vector`, the dimension will be increased to the dimensionality implied by the index.
|
|
451
|
+
* @param i The numerical index (0-based) or lowercase string value (e.g. `"x"`) to set.
|
|
452
|
+
* @param value The value to set at this index/position.
|
|
453
|
+
*
|
|
454
|
+
* ```js
|
|
455
|
+
* const vector = new Vector();
|
|
456
|
+
* vector.set(0, 10);
|
|
457
|
+
* vector.set('y', 2);
|
|
458
|
+
* vector.set(2, 4);
|
|
459
|
+
*
|
|
460
|
+
* vector.xyz; // [10, 2, 4]
|
|
461
|
+
* ```
|
|
462
|
+
*
|
|
432
463
|
* @since 0.1.0
|
|
433
464
|
*/
|
|
434
465
|
Vector.prototype.set = function (i, value) {
|
|
@@ -456,128 +487,175 @@ var Vector = /** @class */ (function () {
|
|
|
456
487
|
return this;
|
|
457
488
|
};
|
|
458
489
|
Object.defineProperty(Vector.prototype, "x", {
|
|
490
|
+
/** @since 0.1.0 */
|
|
459
491
|
get: function () {
|
|
460
492
|
return this.index(0);
|
|
461
493
|
},
|
|
494
|
+
/** @since 0.1.0 */
|
|
462
495
|
set: function (n) {
|
|
463
496
|
this.set(0, n);
|
|
464
497
|
},
|
|
465
|
-
enumerable:
|
|
498
|
+
enumerable: false,
|
|
466
499
|
configurable: true
|
|
467
500
|
});
|
|
468
501
|
Object.defineProperty(Vector.prototype, "y", {
|
|
502
|
+
/** @since 0.1.0 */
|
|
469
503
|
get: function () {
|
|
470
504
|
return this.index(1);
|
|
471
505
|
},
|
|
506
|
+
/** @since 0.1.0 */
|
|
472
507
|
set: function (n) {
|
|
473
508
|
this.set(1, n);
|
|
474
509
|
},
|
|
475
|
-
enumerable:
|
|
510
|
+
enumerable: false,
|
|
476
511
|
configurable: true
|
|
477
512
|
});
|
|
478
513
|
Object.defineProperty(Vector.prototype, "z", {
|
|
514
|
+
/** @since 0.1.0 */
|
|
479
515
|
get: function () {
|
|
480
516
|
return this.index(2);
|
|
481
517
|
},
|
|
518
|
+
/** @since 0.1.0 */
|
|
482
519
|
set: function (n) {
|
|
483
520
|
this.set(2, n);
|
|
484
521
|
},
|
|
485
|
-
enumerable:
|
|
522
|
+
enumerable: false,
|
|
486
523
|
configurable: true
|
|
487
524
|
});
|
|
488
525
|
Object.defineProperty(Vector.prototype, "w", {
|
|
526
|
+
/** @since 0.1.0 */
|
|
489
527
|
get: function () {
|
|
490
528
|
return this.index(3);
|
|
491
529
|
},
|
|
530
|
+
/** @since 0.1.0 */
|
|
492
531
|
set: function (n) {
|
|
493
532
|
this.set(3, n);
|
|
494
533
|
},
|
|
495
|
-
enumerable:
|
|
534
|
+
enumerable: false,
|
|
496
535
|
configurable: true
|
|
497
536
|
});
|
|
498
537
|
Object.defineProperty(Vector.prototype, "xy", {
|
|
538
|
+
/** @since 0.2.4 */
|
|
499
539
|
get: function () {
|
|
500
540
|
return [this.index(0), this.index(1)];
|
|
501
541
|
},
|
|
502
|
-
enumerable:
|
|
542
|
+
enumerable: false,
|
|
503
543
|
configurable: true
|
|
504
544
|
});
|
|
505
545
|
Object.defineProperty(Vector.prototype, "xz", {
|
|
546
|
+
/** @since 0.2.4 */
|
|
506
547
|
get: function () {
|
|
507
548
|
return [this.index(0), this.index(2)];
|
|
508
549
|
},
|
|
509
|
-
enumerable:
|
|
550
|
+
enumerable: false,
|
|
510
551
|
configurable: true
|
|
511
552
|
});
|
|
512
553
|
Object.defineProperty(Vector.prototype, "yz", {
|
|
554
|
+
/** @since 0.2.4 */
|
|
513
555
|
get: function () {
|
|
514
556
|
return [this.index(1), this.index(2)];
|
|
515
557
|
},
|
|
516
|
-
enumerable:
|
|
558
|
+
enumerable: false,
|
|
517
559
|
configurable: true
|
|
518
560
|
});
|
|
519
561
|
Object.defineProperty(Vector.prototype, "xyz", {
|
|
562
|
+
/** @since 0.2.4 */
|
|
520
563
|
get: function () {
|
|
521
564
|
return [this.index(0), this.index(1), this.index(2)];
|
|
522
565
|
},
|
|
523
|
-
enumerable:
|
|
566
|
+
enumerable: false,
|
|
524
567
|
configurable: true
|
|
525
568
|
});
|
|
526
569
|
Object.defineProperty(Vector.prototype, "r", {
|
|
570
|
+
/**
|
|
571
|
+
* `r` for 'red' (the 1st value)
|
|
572
|
+
* @since 0.1.0
|
|
573
|
+
*/
|
|
527
574
|
get: function () {
|
|
528
575
|
return this.index(0);
|
|
529
576
|
},
|
|
577
|
+
/**
|
|
578
|
+
* `r` for 'red' (the 1st value)
|
|
579
|
+
* @since 0.1.0
|
|
580
|
+
*/
|
|
530
581
|
set: function (n) {
|
|
531
582
|
this.set(0, n);
|
|
532
583
|
},
|
|
533
|
-
enumerable:
|
|
584
|
+
enumerable: false,
|
|
534
585
|
configurable: true
|
|
535
586
|
});
|
|
536
587
|
Object.defineProperty(Vector.prototype, "g", {
|
|
588
|
+
/**
|
|
589
|
+
* `g` for 'green' (the 2nd value)
|
|
590
|
+
* @since 0.1.0
|
|
591
|
+
*/
|
|
537
592
|
get: function () {
|
|
538
593
|
return this.index(1);
|
|
539
594
|
},
|
|
595
|
+
/**
|
|
596
|
+
* `g` for 'green' (the 2nd value)
|
|
597
|
+
* @since 0.1.0
|
|
598
|
+
*/
|
|
540
599
|
set: function (n) {
|
|
541
600
|
this.set(1, n);
|
|
542
601
|
},
|
|
543
|
-
enumerable:
|
|
602
|
+
enumerable: false,
|
|
544
603
|
configurable: true
|
|
545
604
|
});
|
|
546
605
|
Object.defineProperty(Vector.prototype, "b", {
|
|
606
|
+
/**
|
|
607
|
+
* `b` for 'blue' (the 3rd value)
|
|
608
|
+
* @since 0.1.0
|
|
609
|
+
*/
|
|
547
610
|
get: function () {
|
|
548
611
|
return this.index(2);
|
|
549
612
|
},
|
|
613
|
+
/**
|
|
614
|
+
* `b` for 'blue' (the 3rd value)
|
|
615
|
+
* @since 0.1.0
|
|
616
|
+
*/
|
|
550
617
|
set: function (n) {
|
|
551
618
|
this.set(2, n);
|
|
552
619
|
},
|
|
553
|
-
enumerable:
|
|
620
|
+
enumerable: false,
|
|
554
621
|
configurable: true
|
|
555
622
|
});
|
|
556
623
|
Object.defineProperty(Vector.prototype, "a", {
|
|
624
|
+
/**
|
|
625
|
+
* `a` for 'alpha' (the 4th value)
|
|
626
|
+
* @since 0.1.0
|
|
627
|
+
*/
|
|
557
628
|
get: function () {
|
|
558
629
|
return this.index(3);
|
|
559
630
|
},
|
|
631
|
+
/**
|
|
632
|
+
* `a` for 'alpha' (the 4th value)
|
|
633
|
+
* @since 0.1.0
|
|
634
|
+
*/
|
|
560
635
|
set: function (n) {
|
|
561
636
|
this.set(3, n);
|
|
562
637
|
},
|
|
563
|
-
enumerable:
|
|
638
|
+
enumerable: false,
|
|
564
639
|
configurable: true
|
|
565
640
|
});
|
|
566
641
|
Object.defineProperty(Vector.prototype, "rgb", {
|
|
642
|
+
/** @since 0.2.4 */
|
|
567
643
|
get: function () {
|
|
568
644
|
return [this.index(0), this.index(1), this.index(2)];
|
|
569
645
|
},
|
|
570
|
-
enumerable:
|
|
646
|
+
enumerable: false,
|
|
571
647
|
configurable: true
|
|
572
648
|
});
|
|
573
649
|
Object.defineProperty(Vector.prototype, "rgba", {
|
|
650
|
+
/** @since 0.2.4 */
|
|
574
651
|
get: function () {
|
|
575
652
|
return [this.index(0), this.index(1), this.index(2), this.index(3)];
|
|
576
653
|
},
|
|
577
|
-
enumerable:
|
|
654
|
+
enumerable: false,
|
|
578
655
|
configurable: true
|
|
579
656
|
});
|
|
580
657
|
/**
|
|
658
|
+
* Add another `Vector` to this `Vector`. This *does* mutate the `Vector` that calls this method.
|
|
581
659
|
* @since 0.1.0
|
|
582
660
|
*/
|
|
583
661
|
Vector.prototype.add = function (v) {
|
|
@@ -592,6 +670,17 @@ var Vector = /** @class */ (function () {
|
|
|
592
670
|
return this;
|
|
593
671
|
};
|
|
594
672
|
/**
|
|
673
|
+
* Multiply this `Vector` by a scalar number. This *does* mutate the `Vector` that calls this method.
|
|
674
|
+
*
|
|
675
|
+
* ```js
|
|
676
|
+
* const v = new Vector(1, 2);
|
|
677
|
+
* v.multiplyScalar(5);
|
|
678
|
+
* v.xy; // returns [5, 10]
|
|
679
|
+
*
|
|
680
|
+
* v.multiplyScalar(-0.5);
|
|
681
|
+
* v.xy; // returns [-2.5, -5]
|
|
682
|
+
* ```
|
|
683
|
+
*
|
|
595
684
|
* @since 0.1.0
|
|
596
685
|
*/
|
|
597
686
|
Vector.prototype.multiplyScalar = function (n) {
|
|
@@ -599,6 +688,7 @@ var Vector = /** @class */ (function () {
|
|
|
599
688
|
return this;
|
|
600
689
|
};
|
|
601
690
|
/**
|
|
691
|
+
* Add a scalar number to all of this `Vector`'s values'. This *does* mutate the `Vector` that calls this method.
|
|
602
692
|
* @since 0.1.0
|
|
603
693
|
*/
|
|
604
694
|
Vector.prototype.addScalar = function (n) {
|
|
@@ -613,8 +703,14 @@ var Vector = /** @class */ (function () {
|
|
|
613
703
|
return Math.sqrt(sum(this.data.map(function (x) { return Math.pow(x, 2); })));
|
|
614
704
|
};
|
|
615
705
|
/**
|
|
616
|
-
* Normalize the
|
|
617
|
-
*
|
|
706
|
+
* Normalize the `Vector` (turn it into a `Vector` with length = `1`). Has no effect on the 0 `Vector`. This *does* mutate the `Vector` that calls this method.
|
|
707
|
+
*
|
|
708
|
+
* ```js
|
|
709
|
+
* const v = new Vector(5, 3, -1);
|
|
710
|
+
* v.normalize();
|
|
711
|
+
* v.length(); // returns 1
|
|
712
|
+
* ```
|
|
713
|
+
*
|
|
618
714
|
* @since 0.1.0
|
|
619
715
|
*/
|
|
620
716
|
Vector.prototype.normalize = function () {
|
|
@@ -625,6 +721,7 @@ var Vector = /** @class */ (function () {
|
|
|
625
721
|
return this;
|
|
626
722
|
};
|
|
627
723
|
/**
|
|
724
|
+
* Create a copy of this `Vector`.
|
|
628
725
|
* @since 0.1.0
|
|
629
726
|
*/
|
|
630
727
|
Vector.prototype.clone = function () {
|
|
@@ -632,8 +729,15 @@ var Vector = /** @class */ (function () {
|
|
|
632
729
|
return new (Vector.bind.apply(Vector, __spreadArrays([void 0], data)))();
|
|
633
730
|
};
|
|
634
731
|
/**
|
|
635
|
-
* Rotate
|
|
636
|
-
*
|
|
732
|
+
* Rotate the `Vector` about the z-axis by `angle` radians (updating its `x` and `y` values). This *does* mutate the `Vector` that calls this method.
|
|
733
|
+
*
|
|
734
|
+
* ```js
|
|
735
|
+
* const v = new Vector(1, 0);
|
|
736
|
+
* v.rotateZ(Math.PI / 2); // rotate by PI / 2 radians = 90 degrees
|
|
737
|
+
*
|
|
738
|
+
* v.xy; // returns [0, 1]
|
|
739
|
+
* ```
|
|
740
|
+
*
|
|
637
741
|
* @since 0.2.2
|
|
638
742
|
*/
|
|
639
743
|
Vector.prototype.rotateZ = function (angle) {
|
|
@@ -646,8 +750,8 @@ var Vector = /** @class */ (function () {
|
|
|
646
750
|
return this;
|
|
647
751
|
};
|
|
648
752
|
/**
|
|
649
|
-
* Get the dot product of this
|
|
650
|
-
* @
|
|
753
|
+
* Get the {@link https://en.wikipedia.org/wiki/Dot_product | dot product} of this `Vector` with another.
|
|
754
|
+
* @since 0.2.4
|
|
651
755
|
*/
|
|
652
756
|
Vector.prototype.dot = function (v) {
|
|
653
757
|
var dimension = Math.max(this.dimension, v.dimension);
|
|
@@ -657,11 +761,23 @@ var Vector = /** @class */ (function () {
|
|
|
657
761
|
return sum;
|
|
658
762
|
};
|
|
659
763
|
/**
|
|
660
|
-
* Linearly interpolate between this
|
|
661
|
-
*
|
|
662
|
-
*
|
|
663
|
-
*
|
|
764
|
+
* Linearly interpolate between this `Vector` and another `Vector`. This *does not* mutate the original `Vector` that calls this method, but returns a new `Vector`.
|
|
765
|
+
*
|
|
766
|
+
* ```js
|
|
767
|
+
* const a = new Vector(1, 3, -5);
|
|
768
|
+
* const b = new Vector(4, -2);
|
|
769
|
+
*
|
|
770
|
+
* a.lerp(b, 0); // returns a clone of Vector a
|
|
771
|
+
* a.lerp(b, 1); // returns a clone of Vector b
|
|
772
|
+
*
|
|
773
|
+
* const mid = a.lerp(b, 0.5); // returns a Vector halfway between a and b
|
|
774
|
+
* mid.xyz; // returns [2.5, 0.5, -2.5]
|
|
775
|
+
* ```
|
|
776
|
+
*
|
|
777
|
+
* @param v - The other vector.
|
|
778
|
+
* @param t - The amount by which to interpolate (usually between `0` and `1`, although it can be any number).
|
|
664
779
|
* @returns {Vector} - The new, interpolated vector.
|
|
780
|
+
* @since 0.2.4
|
|
665
781
|
*/
|
|
666
782
|
Vector.prototype.lerp = function (v, t) {
|
|
667
783
|
var longerVector = this.dimension > v.dimension ? this : v;
|
|
@@ -726,16 +842,70 @@ var method = function (obj, name) {
|
|
|
726
842
|
return obj[name].apply(obj, args);
|
|
727
843
|
};
|
|
728
844
|
/**
|
|
845
|
+
* The `Rule` class is an experimental interface for adding behavior to {@linkcode Agent}s. A `Rule` object may be used in place of a `tick` function to be added as `Agent` behavior using `agent.set('tick', tickRule)`. As a trivial example, consider the following `Rule`, which increments the `Agent`'s `x` value with every time step:
|
|
846
|
+
*
|
|
847
|
+
* ```js
|
|
848
|
+
* const rule = new Rule(environment, [
|
|
849
|
+
* "set", "x", [
|
|
850
|
+
* "add", 1, [
|
|
851
|
+
* "get", "x"
|
|
852
|
+
* ]
|
|
853
|
+
* ]
|
|
854
|
+
* ]);
|
|
855
|
+
* agent.set("tick", rule);
|
|
856
|
+
* ```
|
|
857
|
+
*
|
|
858
|
+
* Reading from the outer arrays inward, the steps of this `Rule` instructs the `Agent` to:
|
|
859
|
+
* - `set` the `Agent`'s `"x"` value to...
|
|
860
|
+
* - The result of `add`ing `1` and...
|
|
861
|
+
* - The `Agent`'s current `"x"` value
|
|
862
|
+
*
|
|
863
|
+
* Generally, `Rule` steps are a deeply nested array, where the first value of any given array is always an instruction or operator (e.g. `"set"`, `"add"`, `"filter"`). See the {@linkcode constructor} function for more information about steps.
|
|
729
864
|
* @since 0.3.0
|
|
730
865
|
*/
|
|
731
866
|
var Rule = /** @class */ (function () {
|
|
867
|
+
/**
|
|
868
|
+
* A single step may be as simple as `["get", "x"]`. This returns the `Agent`'s `"x"` value to the outer step that contains it. So, for example, the step `["add", 1, ["get", "x"]]`, working from the inside out, retrieves the `"x"` value and then adds `1` to it. More complex steps function similarly, always traversing to the deepest nested step, evaluating it, and 'unwrapping' until all steps have been executed.
|
|
869
|
+
*
|
|
870
|
+
* A step's first element should be a string that is one of the allowed operators, followed by a certain number of arguments.
|
|
871
|
+
*
|
|
872
|
+
* |Operator|Arguments|Notes|
|
|
873
|
+
* |---|---|---|
|
|
874
|
+
* |`"add"`|`2`|Pass 2 numbers, or two steps that evaluate to numbers|
|
|
875
|
+
* |`"subtract"`|`2`|""|
|
|
876
|
+
* |`"multiply"`|`2`|""|
|
|
877
|
+
* |`"divide"`|`2`|""|
|
|
878
|
+
* |`"mod"`|`2`|""|
|
|
879
|
+
* |`"power"`|`2`|""|
|
|
880
|
+
* |`"get"`|`1`|Pass the key of `Agent` data to retrieve|
|
|
881
|
+
* |`"set"`|`2`|Pass the key and value to set|
|
|
882
|
+
* |`"enqueue"`|`2`|Pass the key and value to enqueue|
|
|
883
|
+
* |`"local"`|`2`|Pass the key and value to set as local variables|
|
|
884
|
+
* |`"if"`|`3`|Pass the conditional (usually a step that evaluates to a boolean), the step to run when `true`, and the step to run when `false|
|
|
885
|
+
* |`"and"`|`2`|Pass the two steps to logically evaluate|
|
|
886
|
+
* |`"or"`|`2`|""|
|
|
887
|
+
* |`"gt"`|`2`|""|
|
|
888
|
+
* |`"gte"`|`2`|""|
|
|
889
|
+
* |`"lt"`|`2`|""|
|
|
890
|
+
* |`"lte"`|`2`|""|
|
|
891
|
+
* |`"eq"`|`2`|""|
|
|
892
|
+
* |`"map"`|`2`|Pass an array (or step that evaluates to an array) and a lambda to invoke for each element|
|
|
893
|
+
* |`"filter"`|`2`|""|
|
|
894
|
+
* |`"key"`|`2`|Pass an object (or step that evaluates to an object) and the key to retrieve from that object|
|
|
895
|
+
* |`"agent"`|`0`|No arguments; returns the `Agent`|
|
|
896
|
+
* |`"environment"`|`0`|No arguments, returns the `Environment`|
|
|
897
|
+
* |`"vector"`|`any`|Creates an n-dimensional {@linkcode Vector} from the supplied arguments|
|
|
898
|
+
*/
|
|
732
899
|
function Rule(environment, steps) {
|
|
733
900
|
var _this = this;
|
|
901
|
+
/** @hidden */
|
|
734
902
|
this.steps = [];
|
|
903
|
+
/** @hidden */
|
|
735
904
|
this.locals = {};
|
|
736
905
|
/**
|
|
737
906
|
* interpret single array step
|
|
738
907
|
* @since 0.3.0
|
|
908
|
+
* @hidden
|
|
739
909
|
*/
|
|
740
910
|
this.evaluate = function (agent, step) {
|
|
741
911
|
var first = step && step.length > 0 ? step[0] : null;
|
|
@@ -860,6 +1030,7 @@ var Rule = /** @class */ (function () {
|
|
|
860
1030
|
}
|
|
861
1031
|
/**
|
|
862
1032
|
* @since 0.3.0
|
|
1033
|
+
* @hidden
|
|
863
1034
|
*/
|
|
864
1035
|
Rule.prototype.call = function (agent) {
|
|
865
1036
|
return this.evaluate(agent, this.steps);
|
|
@@ -915,40 +1086,85 @@ var disallowed = ["tick", "queue"];
|
|
|
915
1086
|
var warnOnce1 = once(console.warn.bind(console));
|
|
916
1087
|
var warnOnce2 = once(console.warn.bind(console));
|
|
917
1088
|
/**
|
|
1089
|
+
* This class puts the `Agent` in 'agent-based modeling.' More specifically,
|
|
1090
|
+
* an `Agent` represents an individual unit of data and its associated
|
|
1091
|
+
* behaviors.
|
|
918
1092
|
* @since 0.0.5
|
|
919
1093
|
*/
|
|
920
1094
|
var Agent = /** @class */ (function () {
|
|
1095
|
+
/**
|
|
1096
|
+
* `Agent`s can be instantiated with or without data. Instantiating
|
|
1097
|
+
* with data is equivalent to creating an `Agent` and immediately
|
|
1098
|
+
* calling {@linkcode Agent.set} to add data.
|
|
1099
|
+
*
|
|
1100
|
+
* ```js
|
|
1101
|
+
* // instantiates an Agent without data
|
|
1102
|
+
* const a = new Agent();
|
|
1103
|
+
*
|
|
1104
|
+
* // instantiates an Agent with data
|
|
1105
|
+
* const b = new Agent({
|
|
1106
|
+
* x: 50,
|
|
1107
|
+
* y: 100
|
|
1108
|
+
* });
|
|
1109
|
+
* ```
|
|
1110
|
+
* @param data
|
|
1111
|
+
*/
|
|
921
1112
|
function Agent(data) {
|
|
922
1113
|
if (data === void 0) { data = {}; }
|
|
923
1114
|
/**
|
|
924
|
-
* @
|
|
925
|
-
*
|
|
926
|
-
*
|
|
927
|
-
*
|
|
1115
|
+
* An `Agent` can only belong to a single {@linkcode Environment}. When
|
|
1116
|
+
* `environment.addAgent(agent);` is called, this is value is updated
|
|
1117
|
+
* to point to that `Environment`.
|
|
1118
|
+
*
|
|
1119
|
+
* ```js
|
|
1120
|
+
* const environment = new Environment();
|
|
1121
|
+
* const agent = new Agent();
|
|
1122
|
+
* agent.environment; // returns `null`
|
|
1123
|
+
*
|
|
1124
|
+
* environment.addAgent(agent);
|
|
1125
|
+
* agent.environment === environment; // returns `true`
|
|
928
1126
|
*/
|
|
929
1127
|
this.environment = null;
|
|
1128
|
+
/** @hidden */
|
|
930
1129
|
this.rules = [];
|
|
1130
|
+
/** @hidden */
|
|
931
1131
|
this.queue = [];
|
|
1132
|
+
/** @hidden */
|
|
932
1133
|
this.data = {};
|
|
1134
|
+
/**
|
|
1135
|
+
* `Agent`s are automatically assigned a unique ID when they are created.
|
|
1136
|
+
* This can be useful when you need to refer to a specific `Agent`, and
|
|
1137
|
+
* they can be retrieved using their ID from their `Environment` by calling
|
|
1138
|
+
* {@link Environment.getAgentById | `environment.getAgentById(id);`}
|
|
1139
|
+
* ```js
|
|
1140
|
+
* const agent = new Agent();
|
|
1141
|
+
* const id = agent.id; // returns "59B4F928-46C8-..." (for example)
|
|
1142
|
+
* ```
|
|
1143
|
+
*/
|
|
933
1144
|
this.id = uuid$1();
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
1145
|
+
/**
|
|
1146
|
+
* This is used as a temporary store for data that
|
|
1147
|
+
* gets returned from rules. When enqueued rules are executed,
|
|
1148
|
+
* even if there aren't any enqueued rules, .set gets called
|
|
1149
|
+
* on any data that was placed here.
|
|
1150
|
+
* @hidden
|
|
1151
|
+
*/
|
|
938
1152
|
this.__newData = {};
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1153
|
+
/** When agent.get('key') is called, this pseudo-private member is set to 'key'.
|
|
1154
|
+
* Once it is retrieved, it is reset to null. If agent.get('key') is called before
|
|
1155
|
+
* this has been reset, that means that there is an infinite loop, and the call
|
|
1156
|
+
* will throw an error.
|
|
1157
|
+
* @hidden
|
|
1158
|
+
*/
|
|
943
1159
|
this.__retrievingData = null;
|
|
1160
|
+
/** @hidden */
|
|
944
1161
|
this.__subtree = null;
|
|
945
1162
|
this.set(data);
|
|
946
1163
|
}
|
|
947
1164
|
/**
|
|
948
1165
|
* Set a function value. `tick` and `queue` are not automatically called,
|
|
949
1166
|
* but any other named value will automatically be called when referenced.
|
|
950
|
-
* @
|
|
951
|
-
* @param {Function} fn
|
|
1167
|
+
* @hidden
|
|
952
1168
|
*/
|
|
953
1169
|
Agent.prototype._setFunctionValue = function (name, fn) {
|
|
954
1170
|
var _this = this;
|
|
@@ -964,9 +1180,8 @@ var Agent = /** @class */ (function () {
|
|
|
964
1180
|
}
|
|
965
1181
|
};
|
|
966
1182
|
/**
|
|
967
|
-
* Retrieve an arbitrary piece of data associated
|
|
968
|
-
*
|
|
969
|
-
* @param {string} name
|
|
1183
|
+
* Retrieve an arbitrary piece of data associated by name.
|
|
1184
|
+
* If the data has not been {@linkcode set}, returns `null`.
|
|
970
1185
|
* @since 0.0.5
|
|
971
1186
|
*/
|
|
972
1187
|
Agent.prototype.get = function (name) {
|
|
@@ -984,8 +1199,20 @@ var Agent = /** @class */ (function () {
|
|
|
984
1199
|
return data;
|
|
985
1200
|
};
|
|
986
1201
|
/**
|
|
987
|
-
* Retrieve all the data associated with this
|
|
988
|
-
*
|
|
1202
|
+
* Retrieve all the data associated with this `Agent` at once.
|
|
1203
|
+
*
|
|
1204
|
+
* ```js
|
|
1205
|
+
* agent.set('x', 3);
|
|
1206
|
+
* agent.set('color', 'blue');
|
|
1207
|
+
* agent.set('active', false);
|
|
1208
|
+
*
|
|
1209
|
+
* agent.getData();
|
|
1210
|
+
* // returns {
|
|
1211
|
+
* // x: 3,
|
|
1212
|
+
* // color: 'blue',
|
|
1213
|
+
* // active: false
|
|
1214
|
+
* // }
|
|
1215
|
+
* ```
|
|
989
1216
|
* @since 0.1.0
|
|
990
1217
|
*/
|
|
991
1218
|
Agent.prototype.getData = function () {
|
|
@@ -1019,6 +1246,7 @@ var Agent = /** @class */ (function () {
|
|
|
1019
1246
|
/**
|
|
1020
1247
|
* Helper function to set key-value pair depending on whether value
|
|
1021
1248
|
* is a function (callable) or not
|
|
1249
|
+
* @hidden
|
|
1022
1250
|
*/
|
|
1023
1251
|
Agent.prototype._setKeyValue = function (key, value) {
|
|
1024
1252
|
if (typeof value === "function") {
|
|
@@ -1057,25 +1285,57 @@ var Agent = /** @class */ (function () {
|
|
|
1057
1285
|
}
|
|
1058
1286
|
};
|
|
1059
1287
|
/**
|
|
1060
|
-
*
|
|
1061
|
-
*
|
|
1062
|
-
*
|
|
1063
|
-
*
|
|
1064
|
-
*
|
|
1288
|
+
* increment a numeric piece of data associated with this `Agent`
|
|
1289
|
+
* (increasing its value by 1). This method is *synchronous* —
|
|
1290
|
+
* it immediately increases the value (to *asynchronously* increase it,
|
|
1291
|
+
* the rule function should instead return a new value.
|
|
1292
|
+
*
|
|
1293
|
+
* ```js
|
|
1294
|
+
* agent.set('x', 50);
|
|
1295
|
+
* agent.increment('x');
|
|
1296
|
+
* agent.get('x'); // returns 51
|
|
1297
|
+
* ```
|
|
1298
|
+
*
|
|
1299
|
+
* If the second parameter `n` is included, decrements by that amount.
|
|
1300
|
+
*
|
|
1301
|
+
* ```js
|
|
1302
|
+
* agent.set('x', 50);
|
|
1303
|
+
* agent.increment('x', 10);
|
|
1304
|
+
* agent.get('x'); // returns 60
|
|
1305
|
+
* ```
|
|
1306
|
+
*
|
|
1307
|
+
* If the value has not yet been set, calling this method sets it to `1`
|
|
1308
|
+
* (or to `n`).
|
|
1065
1309
|
* @since 0.0.8
|
|
1066
1310
|
*/
|
|
1067
1311
|
Agent.prototype.increment = function (name, n) {
|
|
1068
1312
|
if (n === void 0) { n = 1; }
|
|
1069
|
-
if (
|
|
1313
|
+
if (this.get(name) === null)
|
|
1070
1314
|
this.set(name, 0);
|
|
1071
1315
|
this.set(name, this.get(name) + n);
|
|
1072
1316
|
};
|
|
1073
1317
|
/**
|
|
1074
|
-
* Decrement a numeric
|
|
1075
|
-
*
|
|
1076
|
-
*
|
|
1077
|
-
*
|
|
1078
|
-
*
|
|
1318
|
+
* Decrement a numeric piece of data associated with this `Agent`
|
|
1319
|
+
* (decreasing its value by 1). This method is *synchronous* —
|
|
1320
|
+
* it immediately decreases the value (to *asynchronously* decrease it,
|
|
1321
|
+
* the rule function should instead return a new value.
|
|
1322
|
+
*
|
|
1323
|
+
* ```js
|
|
1324
|
+
* agent.set('x', 50);
|
|
1325
|
+
* agent.decrement('x');
|
|
1326
|
+
* agent.get('x'); // returns 49
|
|
1327
|
+
* ```
|
|
1328
|
+
*
|
|
1329
|
+
* If the second parameter `n` is included, decrements by that amount.
|
|
1330
|
+
*
|
|
1331
|
+
* ```js
|
|
1332
|
+
* agent.set('x', 50);
|
|
1333
|
+
* agent.decrement('x', 10);
|
|
1334
|
+
* agent.get('x'); // returns 40
|
|
1335
|
+
* ```
|
|
1336
|
+
*
|
|
1337
|
+
* If the value has not yet been set, calling this method sets it to `-1`
|
|
1338
|
+
* (or to `-n`).
|
|
1079
1339
|
* @since 0.0.8
|
|
1080
1340
|
*/
|
|
1081
1341
|
Agent.prototype.decrement = function (name, n) {
|
|
@@ -1083,9 +1343,29 @@ var Agent = /** @class */ (function () {
|
|
|
1083
1343
|
this.increment(name, -n);
|
|
1084
1344
|
};
|
|
1085
1345
|
/**
|
|
1086
|
-
*
|
|
1087
|
-
*
|
|
1088
|
-
*
|
|
1346
|
+
* Until v0.5.14, this was the preferred way to add behavior to `Agent`s.
|
|
1347
|
+
* Now, the preferred method is by setting the `Agent`'s `"tick"` value (i.e. `agent.set({ tick: function(agt) { ... }})`).
|
|
1348
|
+
* This method will still be allowed until v0.7.0.
|
|
1349
|
+
*
|
|
1350
|
+
* Adds a rule (a function taking an `Agent` as a callback or a {@linkcode Rule} object) that may be run with every {@linkcode Environment.tick}.
|
|
1351
|
+
* It is possible to add *more than one rule* to an `Agent`, although it
|
|
1352
|
+
* is generally easier to write a longer function or to break it apart
|
|
1353
|
+
* into multiple functions.
|
|
1354
|
+
*
|
|
1355
|
+
* ```js
|
|
1356
|
+
* // adds a rule that *synchronously* increments the Agent's "x" value
|
|
1357
|
+
* agent.addRule(function(agt) {
|
|
1358
|
+
* agent.increment('x');
|
|
1359
|
+
* });
|
|
1360
|
+
*
|
|
1361
|
+
* // adds a rule that *asynchronously* increments the Agent's "x" value
|
|
1362
|
+
* agent.addRule(function(agt) {
|
|
1363
|
+
* return {
|
|
1364
|
+
* x: agt.get('x') + 1
|
|
1365
|
+
* };
|
|
1366
|
+
* });
|
|
1367
|
+
* ```
|
|
1368
|
+
*
|
|
1089
1369
|
* @deprecated since version 0.5.14
|
|
1090
1370
|
* @since 0.0.5
|
|
1091
1371
|
*/
|
|
@@ -1101,16 +1381,34 @@ var Agent = /** @class */ (function () {
|
|
|
1101
1381
|
});
|
|
1102
1382
|
};
|
|
1103
1383
|
/**
|
|
1104
|
-
*
|
|
1105
|
-
*
|
|
1106
|
-
*
|
|
1107
|
-
*
|
|
1108
|
-
*
|
|
1384
|
+
* Like {@linkcode Agent.addRule}, this method is deprecated and the
|
|
1385
|
+
* recommended way is to now call
|
|
1386
|
+
* `agent.set('queue', function(agt) { ... });`
|
|
1387
|
+
*
|
|
1388
|
+
* Calling this method enqueues a function to be executed
|
|
1389
|
+
* *asynchronously* (at the end of the {@linkcode Environment}'s tick cycle).
|
|
1390
|
+
* This is useful if a 'cleanup pass' should be performed between
|
|
1391
|
+
* time steps to adjust `Agent` data.
|
|
1392
|
+
*
|
|
1393
|
+
* Below, the `Agent` sets its `"x"` value to `30` whenever it is
|
|
1394
|
+
* activated during the `Environment`'s tick cycle. After all of that
|
|
1395
|
+
* cycle's `Agent`s have been activated, this `Agent` sets its `"x"`
|
|
1396
|
+
* value to `20`. So if any other `Agent` references its `"x"` value
|
|
1397
|
+
* during a tick cycle after it has been activated, it will return `30`,
|
|
1398
|
+
* but in between tick cycles it will return `20`.
|
|
1399
|
+
*
|
|
1400
|
+
* ```js
|
|
1401
|
+
* agent.addRule(agt => {
|
|
1402
|
+
* agt.set("x", 30);
|
|
1403
|
+
* agt.enqueue(a => {
|
|
1404
|
+
* a.set("x", 20);
|
|
1405
|
+
* });
|
|
1406
|
+
* });
|
|
1407
|
+
* ```
|
|
1408
|
+
*
|
|
1409
|
+
* Any additional parameters passed to the enqueued function will
|
|
1109
1410
|
* be remembered and passed through when the function is executed.
|
|
1110
1411
|
*
|
|
1111
|
-
* The `queue` array is cleared at the very end of
|
|
1112
|
-
* the environment's tick cycle.
|
|
1113
|
-
* @param {Function} enqueuedRule
|
|
1114
1412
|
* @deprecated since version 0.5.14
|
|
1115
1413
|
* @since 0.0.5
|
|
1116
1414
|
*/
|
|
@@ -1127,7 +1425,7 @@ var Agent = /** @class */ (function () {
|
|
|
1127
1425
|
};
|
|
1128
1426
|
/**
|
|
1129
1427
|
* From a RuleObj, execute a single rule (function or structured Rule).
|
|
1130
|
-
* @
|
|
1428
|
+
* @hidden
|
|
1131
1429
|
*/
|
|
1132
1430
|
Agent.prototype.executeRule = function (ruleObj) {
|
|
1133
1431
|
var rule = ruleObj.rule, args = ruleObj.args;
|
|
@@ -1142,6 +1440,7 @@ var Agent = /** @class */ (function () {
|
|
|
1142
1440
|
};
|
|
1143
1441
|
/**
|
|
1144
1442
|
* Execute all rules.
|
|
1443
|
+
* @hidden
|
|
1145
1444
|
*/
|
|
1146
1445
|
Agent.prototype.executeRules = function () {
|
|
1147
1446
|
var _this = this;
|
|
@@ -1158,6 +1457,7 @@ var Agent = /** @class */ (function () {
|
|
|
1158
1457
|
};
|
|
1159
1458
|
/**
|
|
1160
1459
|
* Execute all enqueued rules.
|
|
1460
|
+
* @hidden
|
|
1161
1461
|
*/
|
|
1162
1462
|
Agent.prototype.executeEnqueuedRules = function () {
|
|
1163
1463
|
// if new data from the rules
|
|
@@ -1187,9 +1487,15 @@ var Agent = /** @class */ (function () {
|
|
|
1187
1487
|
}());
|
|
1188
1488
|
|
|
1189
1489
|
/**
|
|
1190
|
-
*
|
|
1191
|
-
*
|
|
1192
|
-
*
|
|
1490
|
+
* Return the mean value from an array of numbers.
|
|
1491
|
+
*
|
|
1492
|
+
* ```js
|
|
1493
|
+
* mean([1, 2, 3]); // returns 2
|
|
1494
|
+
* mean([10]); // returns 10
|
|
1495
|
+
*
|
|
1496
|
+
* mean([]); // returns null for empty arrays
|
|
1497
|
+
* ```
|
|
1498
|
+
*
|
|
1193
1499
|
* @since 0.0.16
|
|
1194
1500
|
*/
|
|
1195
1501
|
function mean(arr) {
|
|
@@ -1224,6 +1530,7 @@ function shuffle(array) {
|
|
|
1224
1530
|
}
|
|
1225
1531
|
|
|
1226
1532
|
/**
|
|
1533
|
+
* @hidden
|
|
1227
1534
|
* @since 0.3.11
|
|
1228
1535
|
*/
|
|
1229
1536
|
var NumArray = /** @class */ (function () {
|
|
@@ -1235,7 +1542,7 @@ var NumArray = /** @class */ (function () {
|
|
|
1235
1542
|
get: function () {
|
|
1236
1543
|
return this._index;
|
|
1237
1544
|
},
|
|
1238
|
-
enumerable:
|
|
1545
|
+
enumerable: false,
|
|
1239
1546
|
configurable: true
|
|
1240
1547
|
});
|
|
1241
1548
|
NumArray.prototype.set = function (i, n) {
|
|
@@ -1286,24 +1593,33 @@ var Array2D = /** @class */ (function () {
|
|
|
1286
1593
|
}());
|
|
1287
1594
|
|
|
1288
1595
|
/**
|
|
1596
|
+
* A `Network` allows {@linkcode Agent}s to be connected to each other.
|
|
1289
1597
|
* @since 0.1.3
|
|
1290
1598
|
*/
|
|
1291
1599
|
var Network = /** @class */ (function () {
|
|
1292
1600
|
function Network() {
|
|
1601
|
+
/** @hidden */
|
|
1293
1602
|
this.adjacencyList = new Map();
|
|
1294
|
-
|
|
1603
|
+
/**
|
|
1604
|
+
* instantiated and updated in _resetAdjacencyMatrix
|
|
1605
|
+
* @hidden
|
|
1606
|
+
*/
|
|
1295
1607
|
this.adjacencyMatrix = null;
|
|
1296
1608
|
/**
|
|
1297
|
-
*
|
|
1298
|
-
* in the order they were added
|
|
1609
|
+
* An array of the {@linkcode Agent}s in this `Network`
|
|
1610
|
+
* (in the order they were added).
|
|
1299
1611
|
*/
|
|
1300
1612
|
this.agents = [];
|
|
1301
1613
|
}
|
|
1302
1614
|
/**
|
|
1303
1615
|
* Add an agent to the network.
|
|
1304
|
-
* Returns `true` if the
|
|
1305
|
-
*
|
|
1306
|
-
*
|
|
1616
|
+
* @returns Returns `true` if the `Agent` was successfully added, `false` otherwise.
|
|
1617
|
+
*
|
|
1618
|
+
* ```js
|
|
1619
|
+
* const a = new Agent();
|
|
1620
|
+
* network.addAgent(a); // returns true
|
|
1621
|
+
* network.addAgent(a); // returns false since `a` was already in the `Network`
|
|
1622
|
+
* ```
|
|
1307
1623
|
* @since 0.1.3
|
|
1308
1624
|
*/
|
|
1309
1625
|
Network.prototype.addAgent = function (agent) {
|
|
@@ -1316,8 +1632,8 @@ var Network = /** @class */ (function () {
|
|
|
1316
1632
|
return false;
|
|
1317
1633
|
};
|
|
1318
1634
|
/**
|
|
1319
|
-
*
|
|
1320
|
-
*
|
|
1635
|
+
* Given an {@linkcode Environment}, add all the {@linkcode Agent}s in that `Environment`
|
|
1636
|
+
* to this `Network`. (This is a shortcut for calling `environment.getAgents().forEach(a => network.addAgent(a)));`)
|
|
1321
1637
|
* @since 0.2.1
|
|
1322
1638
|
*/
|
|
1323
1639
|
Network.prototype.addFromEnvironment = function (environment) {
|
|
@@ -1325,10 +1641,20 @@ var Network = /** @class */ (function () {
|
|
|
1325
1641
|
environment.getAgents().forEach(function (agent) { return _this.addAgent(agent); });
|
|
1326
1642
|
};
|
|
1327
1643
|
/**
|
|
1328
|
-
*
|
|
1329
|
-
*
|
|
1644
|
+
* Removes an {@linkcode Agent} from the `Network`.
|
|
1645
|
+
*
|
|
1646
|
+
* ```js
|
|
1647
|
+
* const a = new Agent();
|
|
1648
|
+
* network.addAgent(a);
|
|
1649
|
+
*
|
|
1650
|
+
* network.removeAgent(a); // returns true
|
|
1651
|
+
*
|
|
1652
|
+
* network.removeAgent(a); // returns false since `a` was no longer in the `Network`
|
|
1653
|
+
* ```
|
|
1654
|
+
*
|
|
1655
|
+
* @returns Returns `true` if the agent was successfully removed.
|
|
1656
|
+
*
|
|
1330
1657
|
* Returns `false` if the agent was not in the network to begin with.
|
|
1331
|
-
* @param {Agent} agent
|
|
1332
1658
|
* @since 0.1.3
|
|
1333
1659
|
*/
|
|
1334
1660
|
Network.prototype.removeAgent = function (agent) {
|
|
@@ -1348,7 +1674,17 @@ var Network = /** @class */ (function () {
|
|
|
1348
1674
|
return true;
|
|
1349
1675
|
};
|
|
1350
1676
|
/**
|
|
1351
|
-
* Removes all
|
|
1677
|
+
* Removes all {@linkcode Agent}s from the `Network`.
|
|
1678
|
+
*
|
|
1679
|
+
* ```js
|
|
1680
|
+
* const network = new Network();
|
|
1681
|
+
* network.addAgent(new Agent());
|
|
1682
|
+
* network.size(); // returns 1
|
|
1683
|
+
*
|
|
1684
|
+
* network.clear();
|
|
1685
|
+
* network.size(); // returns 0
|
|
1686
|
+
* ```
|
|
1687
|
+
*
|
|
1352
1688
|
* @since 0.2.1
|
|
1353
1689
|
*/
|
|
1354
1690
|
Network.prototype.clear = function () {
|
|
@@ -1358,23 +1694,36 @@ var Network = /** @class */ (function () {
|
|
|
1358
1694
|
}
|
|
1359
1695
|
};
|
|
1360
1696
|
/**
|
|
1361
|
-
*
|
|
1362
|
-
*
|
|
1363
|
-
*
|
|
1364
|
-
*
|
|
1365
|
-
*
|
|
1697
|
+
* Attempts to create a connection between {@linkcode Agent}s `a` and `b`.
|
|
1698
|
+
* @returns Returns `true` if the connection was successfully created (i.e. if `a` and `b` were previously not connected and now are).
|
|
1699
|
+
*
|
|
1700
|
+
* ```js
|
|
1701
|
+
* const a = new Agent();
|
|
1702
|
+
* const b = new Agent();
|
|
1703
|
+
* network.addAgent(a);
|
|
1704
|
+
* network.addAgent(b);
|
|
1705
|
+
*
|
|
1706
|
+
* network.connect(a, b); // returns true
|
|
1707
|
+
*
|
|
1708
|
+
* network.connect(a, b); // returns false since they are now already connected
|
|
1709
|
+
*
|
|
1710
|
+
* const c = new Agent();
|
|
1711
|
+
* network.connect(a, c); // returns false since `c` is not in the `Network`
|
|
1712
|
+
* ```
|
|
1713
|
+
*
|
|
1714
|
+
* Returns `false` otherwise, for example if `a` and `b` are the same `Agent`, or if either is not in the `Network`.
|
|
1366
1715
|
* @since 0.1.3
|
|
1367
1716
|
*/
|
|
1368
|
-
Network.prototype.connect = function (
|
|
1369
|
-
if (
|
|
1717
|
+
Network.prototype.connect = function (a, b) {
|
|
1718
|
+
if (a === b)
|
|
1370
1719
|
return false;
|
|
1371
|
-
if (!this.isInNetwork(
|
|
1720
|
+
if (!this.isInNetwork(a) || !this.isInNetwork(b))
|
|
1372
1721
|
return false;
|
|
1373
|
-
if (!this.areConnected(
|
|
1374
|
-
this.adjacencyList.get(
|
|
1375
|
-
this.adjacencyList.get(
|
|
1376
|
-
var i1 = this.indexOf(
|
|
1377
|
-
var i2 = this.indexOf(
|
|
1722
|
+
if (!this.areConnected(a, b)) {
|
|
1723
|
+
this.adjacencyList.get(a).push(b);
|
|
1724
|
+
this.adjacencyList.get(b).push(a);
|
|
1725
|
+
var i1 = this.indexOf(a);
|
|
1726
|
+
var i2 = this.indexOf(b);
|
|
1378
1727
|
this.adjacencyMatrix.set(i1, i2, 1);
|
|
1379
1728
|
this.adjacencyMatrix.set(i2, i1, 1);
|
|
1380
1729
|
return true;
|
|
@@ -1382,24 +1731,42 @@ var Network = /** @class */ (function () {
|
|
|
1382
1731
|
return false;
|
|
1383
1732
|
};
|
|
1384
1733
|
/**
|
|
1385
|
-
* Returns `true` if
|
|
1386
|
-
*
|
|
1387
|
-
*
|
|
1734
|
+
* @returns Returns `true` if {@linkcode Agent}s `a` and `b` are connected, `false` if they are not.
|
|
1735
|
+
*
|
|
1736
|
+
* ```js
|
|
1737
|
+
* network.connect(a, b);
|
|
1738
|
+
* network.areConnected(a, b); // returns true since they have been connected
|
|
1739
|
+
*
|
|
1740
|
+
* network.disconnect(a, b);
|
|
1741
|
+
* network.areConnected(a, b); // returns false since they have been disconnected
|
|
1742
|
+
* ```
|
|
1743
|
+
*
|
|
1388
1744
|
* @since 0.1.3
|
|
1389
1745
|
*/
|
|
1390
|
-
Network.prototype.areConnected = function (
|
|
1391
|
-
if (!this.isInNetwork(
|
|
1746
|
+
Network.prototype.areConnected = function (a, b) {
|
|
1747
|
+
if (!this.isInNetwork(a) || !this.isInNetwork(b))
|
|
1392
1748
|
return false;
|
|
1393
|
-
var i1 = this.indexOf(
|
|
1394
|
-
var i2 = this.indexOf(
|
|
1749
|
+
var i1 = this.indexOf(a);
|
|
1750
|
+
var i2 = this.indexOf(b);
|
|
1395
1751
|
return (this.adjacencyMatrix.get(i1, i2) === 1 &&
|
|
1396
1752
|
this.adjacencyMatrix.get(i2, i1) === 1);
|
|
1397
1753
|
};
|
|
1398
1754
|
/**
|
|
1399
|
-
*
|
|
1400
|
-
*
|
|
1401
|
-
*
|
|
1402
|
-
*
|
|
1755
|
+
* Attempts to sever the connection between {@linkcode Agent}s `a` and `b`.
|
|
1756
|
+
* @returns Returns `true` if the `Agent`s were successfully disconnected, `false` otherwise.
|
|
1757
|
+
*
|
|
1758
|
+
* ```js
|
|
1759
|
+
* const a = new Agent();
|
|
1760
|
+
* const b = new Agent();
|
|
1761
|
+
* network.addAgent(a);
|
|
1762
|
+
* network.addAgent(b);
|
|
1763
|
+
*
|
|
1764
|
+
* network.connect(a, b);
|
|
1765
|
+
* network.disconnect(a, b); // returns true since they were connected and are no longer
|
|
1766
|
+
*
|
|
1767
|
+
* network.disconnect(a, b); // returns false since they were already not connected
|
|
1768
|
+
* ```
|
|
1769
|
+
*
|
|
1403
1770
|
* @since 0.1.3
|
|
1404
1771
|
*/
|
|
1405
1772
|
Network.prototype.disconnect = function (a1, a2) {
|
|
@@ -1419,40 +1786,50 @@ var Network = /** @class */ (function () {
|
|
|
1419
1786
|
return false;
|
|
1420
1787
|
};
|
|
1421
1788
|
/**
|
|
1422
|
-
*
|
|
1789
|
+
* @returns Returns the number of {@linkcode Agent}s in the `Network`.
|
|
1790
|
+
*
|
|
1791
|
+
* ```js
|
|
1792
|
+
* const a = new Agent();
|
|
1793
|
+
* const b = new Agent();
|
|
1794
|
+
* const c = new Agent();
|
|
1795
|
+
* [a, b, c].forEach(agt => network.addAgent(agt));
|
|
1796
|
+
*
|
|
1797
|
+
* network.size(); // returns 3
|
|
1798
|
+
* ```
|
|
1799
|
+
*
|
|
1423
1800
|
* @since 0.1.3
|
|
1424
1801
|
*/
|
|
1425
1802
|
Network.prototype.size = function () {
|
|
1426
1803
|
return this.agents.length;
|
|
1427
1804
|
};
|
|
1428
1805
|
/**
|
|
1429
|
-
*
|
|
1430
|
-
* and invoke the callback
|
|
1431
|
-
* @param {Function} cb
|
|
1806
|
+
* Loop over all the {@linkcode Agent}s in the `Network` (in the order they were added),
|
|
1807
|
+
* and invoke the `callback` function with the `Agent` and an index passed as parameters.
|
|
1432
1808
|
* @since 0.1.3
|
|
1433
1809
|
*/
|
|
1434
|
-
Network.prototype.forEach = function (
|
|
1435
|
-
this.agents.forEach(
|
|
1810
|
+
Network.prototype.forEach = function (callback) {
|
|
1811
|
+
this.agents.forEach(callback);
|
|
1436
1812
|
};
|
|
1437
1813
|
/**
|
|
1438
|
-
*
|
|
1439
|
-
* @param {Function} cb
|
|
1814
|
+
* The same method as {@linkcode forEach}, but executes in random order.
|
|
1440
1815
|
* @since 0.1.3
|
|
1441
1816
|
*/
|
|
1442
|
-
Network.prototype.forEachRand = function (
|
|
1443
|
-
shuffle(this.agents).forEach(
|
|
1817
|
+
Network.prototype.forEachRand = function (callback) {
|
|
1818
|
+
shuffle(this.agents).forEach(callback);
|
|
1444
1819
|
};
|
|
1445
1820
|
/**
|
|
1446
|
-
* Returns true if the
|
|
1447
|
-
* @param {Agent} agent
|
|
1821
|
+
* Returns `true` if the given {@linkcode Agent} is in the `Network`, `false` if it is not.
|
|
1448
1822
|
* @since 0.1.3
|
|
1449
1823
|
*/
|
|
1450
1824
|
Network.prototype.isInNetwork = function (agent) {
|
|
1451
1825
|
return this.adjacencyList.has(agent);
|
|
1452
1826
|
};
|
|
1453
1827
|
/**
|
|
1454
|
-
*
|
|
1455
|
-
*
|
|
1828
|
+
* Returns the {@linkcode Agent} at index `i`, where `i = 0` is the first `Agent`
|
|
1829
|
+
* added to the `Network`, `i = 1` the second, etc.
|
|
1830
|
+
*
|
|
1831
|
+
* Negative indices are allowed, so `network.get(-1)` returns the `Agent` that was most recently
|
|
1832
|
+
* added to the `Network`, `-2` the second-most recent, etc.
|
|
1456
1833
|
* @since 0.1.3
|
|
1457
1834
|
*/
|
|
1458
1835
|
Network.prototype.get = function (i) {
|
|
@@ -1463,17 +1840,26 @@ var Network = /** @class */ (function () {
|
|
|
1463
1840
|
return this.agents[i];
|
|
1464
1841
|
};
|
|
1465
1842
|
/**
|
|
1466
|
-
*
|
|
1467
|
-
* @param {Agent} agent
|
|
1843
|
+
* Returns the index of the given {@linkcode Agent} in the {@linkcode agents} array.
|
|
1468
1844
|
* @since 0.1.3
|
|
1469
1845
|
*/
|
|
1470
1846
|
Network.prototype.indexOf = function (agent) {
|
|
1471
1847
|
return this.agents.indexOf(agent);
|
|
1472
1848
|
};
|
|
1473
1849
|
/**
|
|
1474
|
-
*
|
|
1475
|
-
*
|
|
1476
|
-
*
|
|
1850
|
+
* Returns an array of {@linkcode Agent}s that are connected to the given `Agent` (in no guaranteed order).
|
|
1851
|
+
*
|
|
1852
|
+
* Returns `null` if the given `Agent` is not in the `Network`.
|
|
1853
|
+
*
|
|
1854
|
+
* ```js
|
|
1855
|
+
* // suppose a, b, and c are connected
|
|
1856
|
+
* network.neighbors(a); // returns [b, c] (or [c, b])
|
|
1857
|
+
*
|
|
1858
|
+
* network.disconnect(a, c);
|
|
1859
|
+
* network.neighbors(a); // returns [b]
|
|
1860
|
+
* network.neighbors(c); // returns [b]
|
|
1861
|
+
* ```
|
|
1862
|
+
*
|
|
1477
1863
|
* @since 0.1.3
|
|
1478
1864
|
*/
|
|
1479
1865
|
Network.prototype.neighbors = function (agent) {
|
|
@@ -1482,7 +1868,7 @@ var Network = /** @class */ (function () {
|
|
|
1482
1868
|
return this.adjacencyList.get(agent);
|
|
1483
1869
|
};
|
|
1484
1870
|
/**
|
|
1485
|
-
*
|
|
1871
|
+
* Draw a connection between every pair of {@linkcode Agent}s in the `Network`.
|
|
1486
1872
|
* @since 0.1.3
|
|
1487
1873
|
*/
|
|
1488
1874
|
Network.prototype.complete = function () {
|
|
@@ -1495,6 +1881,7 @@ var Network = /** @class */ (function () {
|
|
|
1495
1881
|
/**
|
|
1496
1882
|
* Internal helper function to reset the adjacencyMatrix.
|
|
1497
1883
|
* This gets called when agents are added to or removed from the network.
|
|
1884
|
+
* @hidden
|
|
1498
1885
|
*/
|
|
1499
1886
|
Network.prototype._resetAdjacencyMatrix = function () {
|
|
1500
1887
|
var size = this.size();
|
|
@@ -1511,11 +1898,7 @@ var Network = /** @class */ (function () {
|
|
|
1511
1898
|
this.adjacencyMatrix = newMatrix;
|
|
1512
1899
|
};
|
|
1513
1900
|
/**
|
|
1514
|
-
* Returns `true` if a, b, and c
|
|
1515
|
-
* if (at least) one of the three is connected to the other two.
|
|
1516
|
-
* @param {Agent} a
|
|
1517
|
-
* @param {Agent} b
|
|
1518
|
-
* @param {Agent} c
|
|
1901
|
+
* Returns `true` if `Agent`s a, b, and c form a 'triplet' — if (at least) one of the three is connected to the other two. Returns `false` otherwise.
|
|
1519
1902
|
* @since 0.5.17
|
|
1520
1903
|
*/
|
|
1521
1904
|
Network.prototype.isTriplet = function (a, b, c) {
|
|
@@ -1529,11 +1912,7 @@ var Network = /** @class */ (function () {
|
|
|
1529
1912
|
return connections >= 2;
|
|
1530
1913
|
};
|
|
1531
1914
|
/**
|
|
1532
|
-
* Returns `true` if a, b, and c
|
|
1533
|
-
* each connected to the other two.
|
|
1534
|
-
* @param {Agent} a
|
|
1535
|
-
* @param {Agent} b
|
|
1536
|
-
* @param {Agent} c
|
|
1915
|
+
* Returns `true` if `Agent`s a, b, and c form a 'closed triplet' — if each of the three are connected to the other two. Returns `false` otherwise.
|
|
1537
1916
|
* @since 0.5.17
|
|
1538
1917
|
*/
|
|
1539
1918
|
Network.prototype.isClosedTriplet = function (a, b, c) {
|
|
@@ -1546,6 +1925,7 @@ var Network = /** @class */ (function () {
|
|
|
1546
1925
|
].filter(function (v) { return v; }).length;
|
|
1547
1926
|
return connections === 3;
|
|
1548
1927
|
};
|
|
1928
|
+
/** @hidden */
|
|
1549
1929
|
Network.prototype._globalClusteringCoefficient = function () {
|
|
1550
1930
|
var _this = this;
|
|
1551
1931
|
var triplets = 0;
|
|
@@ -1567,12 +1947,15 @@ var Network = /** @class */ (function () {
|
|
|
1567
1947
|
return closedTriplets / triplets;
|
|
1568
1948
|
};
|
|
1569
1949
|
/**
|
|
1570
|
-
*
|
|
1571
|
-
*
|
|
1572
|
-
*
|
|
1573
|
-
* If
|
|
1574
|
-
*
|
|
1575
|
-
*
|
|
1950
|
+
* The {@link https://en.wikipedia.org/wiki/Clustering_coefficient | clustering coefficient} is a measure of how
|
|
1951
|
+
* closely connected either an individual {@linkcode Agent}'s connections are or the `Network` as a whole is.
|
|
1952
|
+
*
|
|
1953
|
+
* If an `Agent` is passed as the single parameter, returns the {@link https://en.wikipedia.org/wiki/Clustering_coefficient#Local_clustering_coefficient | local
|
|
1954
|
+
* clustering coefficient} for that `Agent`.
|
|
1955
|
+
*
|
|
1956
|
+
* If no parameter is passed, returns the {@link https://en.wikipedia.org/wiki/Clustering_coefficient#Global_clustering_coefficient | global clustering coefficient}
|
|
1957
|
+
* of the `Network` (an aggregate measure of how connected the `Agent`s are).
|
|
1958
|
+
*
|
|
1576
1959
|
* @since 0.5.17
|
|
1577
1960
|
*/
|
|
1578
1961
|
Network.prototype.clusteringCoefficient = function (agent) {
|
|
@@ -1596,9 +1979,11 @@ var Network = /** @class */ (function () {
|
|
|
1596
1979
|
return (2 * clusterConnections) / (k * (k - 1));
|
|
1597
1980
|
};
|
|
1598
1981
|
/**
|
|
1599
|
-
* Returns the average clustering coefficient for the
|
|
1600
|
-
* of the local clustering coefficient across all
|
|
1601
|
-
*
|
|
1982
|
+
* Returns the {@link https://en.wikipedia.org/wiki/Clustering_coefficient#Network_average_clustering_coefficient | average clustering coefficient} for the `Network` (the average
|
|
1983
|
+
* of the {@link Network.clusteringCoefficient | local clustering coefficient} across all `Agent`s).
|
|
1984
|
+
*
|
|
1985
|
+
* Note that this is a different measurement from the _global_ clustering coefficient
|
|
1986
|
+
* (i.e. calling {@linkcode clusteringCoefficient} without any parameters).
|
|
1602
1987
|
* @since 0.5.17
|
|
1603
1988
|
*/
|
|
1604
1989
|
Network.prototype.averageClusteringCoefficient = function () {
|
|
@@ -1654,6 +2039,14 @@ var BBox = /** @class */ (function () {
|
|
|
1654
2039
|
}());
|
|
1655
2040
|
|
|
1656
2041
|
/**
|
|
2042
|
+
* Return the minimum value from an array of numbers.
|
|
2043
|
+
*
|
|
2044
|
+
* ```js
|
|
2045
|
+
* min([1, 2, 3]); // returns 1
|
|
2046
|
+
* min([10]); // returns 10
|
|
2047
|
+
*
|
|
2048
|
+
* min([]); // returns null for empty arrays
|
|
2049
|
+
* ```
|
|
1657
2050
|
* @since 0.2.0
|
|
1658
2051
|
*/
|
|
1659
2052
|
function min(arr) {
|
|
@@ -1663,6 +2056,15 @@ function min(arr) {
|
|
|
1663
2056
|
}
|
|
1664
2057
|
|
|
1665
2058
|
/**
|
|
2059
|
+
* Return the maximum value from an array of numbers.
|
|
2060
|
+
*
|
|
2061
|
+
* ```js
|
|
2062
|
+
* max([1, 2, 3]); // returns 3
|
|
2063
|
+
* max([10]); // returns 10
|
|
2064
|
+
*
|
|
2065
|
+
* max([]); // returns null for empty arrays
|
|
2066
|
+
* ```
|
|
2067
|
+
*
|
|
1666
2068
|
* @since 0.2.0
|
|
1667
2069
|
*/
|
|
1668
2070
|
function max(arr) {
|
|
@@ -1704,8 +2106,16 @@ function percentile(arr, n) {
|
|
|
1704
2106
|
}
|
|
1705
2107
|
|
|
1706
2108
|
/**
|
|
1707
|
-
*
|
|
1708
|
-
*
|
|
2109
|
+
* Return the mean value from an array of numbers.
|
|
2110
|
+
*
|
|
2111
|
+
* ```js
|
|
2112
|
+
* median([1, 2, 3]); // returns 2
|
|
2113
|
+
* median([10]); // returns 10
|
|
2114
|
+
* median([1, 2, 3, 4]); // returns 2.5 (the mean of the two median values)
|
|
2115
|
+
*
|
|
2116
|
+
* median([]); // returns null for empty arrays
|
|
2117
|
+
* ```
|
|
2118
|
+
*
|
|
1709
2119
|
* @param {number[]} arr
|
|
1710
2120
|
* @since 0.2.0
|
|
1711
2121
|
*/
|
|
@@ -1713,6 +2123,9 @@ function median(arr) {
|
|
|
1713
2123
|
return percentile(arr, 0.5);
|
|
1714
2124
|
}
|
|
1715
2125
|
|
|
2126
|
+
function isMultipleSampleFunc(f) {
|
|
2127
|
+
return f([1]).length > 0;
|
|
2128
|
+
}
|
|
1716
2129
|
var sample;
|
|
1717
2130
|
/**
|
|
1718
2131
|
* Gets a random element from `array`.
|
|
@@ -1802,12 +2215,21 @@ function sampler(n) {
|
|
|
1802
2215
|
|
|
1803
2216
|
/// <reference path="../types/Point.d.ts" />
|
|
1804
2217
|
/**
|
|
1805
|
-
* Finds the distance between `p1` and `p2`.
|
|
1806
|
-
*
|
|
1807
|
-
* `x`, `y`, and/or `z`
|
|
1808
|
-
* @
|
|
1809
|
-
*
|
|
1810
|
-
*
|
|
2218
|
+
* Finds the distance between `p1` and `p2`.
|
|
2219
|
+
*
|
|
2220
|
+
* The inputs may be plain objects with `x`, `y`, and/or `z` keys, {@linkcode Vector}s,
|
|
2221
|
+
* or {@linkcode Agent}s with `x`, `y`, and/or `z` data.
|
|
2222
|
+
*
|
|
2223
|
+
* ```js
|
|
2224
|
+
* const a1 = new Agent();
|
|
2225
|
+
* const a2 = new Agent({ x: 3, y: 4 });
|
|
2226
|
+
* distance(a1, a2); // returns 5 (defaults to x = 0 and y = 0 for a1)
|
|
2227
|
+
*
|
|
2228
|
+
* const p1 = { x: 0, y: 2 };
|
|
2229
|
+
* const p2 = { x: 0, y: 4 };
|
|
2230
|
+
* distance(p1, p2); // returns 2
|
|
2231
|
+
* ```
|
|
2232
|
+
*
|
|
1811
2233
|
* @since 0.0.10
|
|
1812
2234
|
*/
|
|
1813
2235
|
function distance(p1, p2) {
|
|
@@ -2105,6 +2527,14 @@ var KDTree = /** @class */ (function () {
|
|
|
2105
2527
|
}());
|
|
2106
2528
|
|
|
2107
2529
|
/**
|
|
2530
|
+
* Finds the {@link https://en.wikipedia.org/wiki/Greatest_common_divisor | greatest common divisor} of `a` and `b`.
|
|
2531
|
+
*
|
|
2532
|
+
* ```js
|
|
2533
|
+
* gcd(7, 13); // returns 1
|
|
2534
|
+
* gcd(9, 15); // returns 3
|
|
2535
|
+
* gcd(12, 24); // returns 12
|
|
2536
|
+
* ```
|
|
2537
|
+
*
|
|
2108
2538
|
* @since 0.4.5
|
|
2109
2539
|
*/
|
|
2110
2540
|
function gcd(a, b) {
|
|
@@ -2173,32 +2603,80 @@ var defaultTerrainOptions = {
|
|
|
2173
2603
|
grayscale: false,
|
|
2174
2604
|
scale: 1
|
|
2175
2605
|
};
|
|
2606
|
+
var BLACK = { r: 0, g: 0, b: 0, a: 255 };
|
|
2607
|
+
var WHITE = { r: 255, g: 255, b: 255, a: 255 };
|
|
2608
|
+
var RED = { r: 255, g: 0, b: 0, a: 255 };
|
|
2609
|
+
var MAROON = { r: 127, g: 0, b: 0, a: 255 };
|
|
2610
|
+
var YELLOW = { r: 255, g: 255, b: 0, a: 255 };
|
|
2611
|
+
var BLUE = { r: 0, g: 0, b: 255, a: 255 };
|
|
2612
|
+
var GREEN = { r: 0, g: 127, b: 0, a: 255 };
|
|
2613
|
+
var LIME = { r: 0, g: 255, b: 0, a: 255 };
|
|
2614
|
+
var AQUA = { r: 0, g: 255, b: 255, a: 255 };
|
|
2615
|
+
var ORANGE = { r: 255, g: 165, b: 0, a: 255 };
|
|
2616
|
+
var FUCHSIA = { r: 255, g: 0, b: 255, a: 255 };
|
|
2617
|
+
var PURPLE = { r: 127, g: 0, b: 127, a: 255 };
|
|
2176
2618
|
/**
|
|
2619
|
+
* Each static member of the `Colors` class (e.g. `Colors.GREEN`, `Colors.RED`) is a pixel-like object with `r`, `g`, `b`, and `a` values that range from `0` to `255`.
|
|
2177
2620
|
* @since 0.4.0
|
|
2178
2621
|
*/
|
|
2179
|
-
var Colors = {
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2622
|
+
var Colors = /** @class */ (function () {
|
|
2623
|
+
function Colors() {
|
|
2624
|
+
}
|
|
2625
|
+
/** <div style="width: 100%; height: 20px; background-color: rgb(0, 0, 0);"></div> */
|
|
2626
|
+
Colors.BLACK = BLACK;
|
|
2627
|
+
/** <div style="width: 100%; height: 20px; background-color: rgb(255, 255, 255); border: 1px solid #eee;"></div> */
|
|
2628
|
+
Colors.WHITE = WHITE;
|
|
2629
|
+
/** <div style="width: 100%; height: 20px; background-color: rgb(255, 0, 0);"></div> */
|
|
2630
|
+
Colors.RED = RED;
|
|
2631
|
+
/** <div style="width: 100%; height: 20px; background-color: rgb(127, 0, 0);"></div> */
|
|
2632
|
+
Colors.MAROON = MAROON;
|
|
2633
|
+
/** <div style="width: 100%; height: 20px; background-color: rgb(255,255, 0);"></div> */
|
|
2634
|
+
Colors.YELLOW = YELLOW;
|
|
2635
|
+
/** <div style="width: 100%; height: 20px; background-color: rgb(0, 0, 255);"></div> */
|
|
2636
|
+
Colors.BLUE = BLUE;
|
|
2637
|
+
/** <div style="width: 100%; height: 20px; background-color: rgb(0, 127, 0);"></div> */
|
|
2638
|
+
Colors.GREEN = GREEN;
|
|
2639
|
+
/** <div style="width: 100%; height: 20px; background-color: rgb(0, 255, 0);"></div> */
|
|
2640
|
+
Colors.LIME = LIME;
|
|
2641
|
+
/** <div style="width: 100%; height: 20px; background-color: rgb(0, 255, 255);"></div> */
|
|
2642
|
+
Colors.AQUA = AQUA;
|
|
2643
|
+
/** <div style="width: 100%; height: 20px; background-color: rgb(255, 165, 0);"></div> */
|
|
2644
|
+
Colors.ORANGE = ORANGE;
|
|
2645
|
+
/** <div style="width: 100%; height: 20px; background-color: rgb(255, 0, 255);"></div> */
|
|
2646
|
+
Colors.FUCHSIA = FUCHSIA;
|
|
2647
|
+
/** <div style="width: 100%; height: 20px; background-color: rgb(127, 0, 127);"></div> */
|
|
2648
|
+
Colors.PURPLE = PURPLE;
|
|
2649
|
+
return Colors;
|
|
2650
|
+
}());
|
|
2193
2651
|
/**
|
|
2652
|
+
* The `Terrain` class lets {@linkcode Environment}s function as lattices upon which {@link https://en.wikipedia.org/wiki/Cellular_automaton | cellular automata} can grow. With a `Terrain`, {@linkcode Agent}s may not be necessary, since all the cells of a `Terrain` can follow update rules (similar to but simplified from `Agent`s).
|
|
2653
|
+
*
|
|
2654
|
+
* ### Usage
|
|
2655
|
+
*
|
|
2656
|
+
* ```js
|
|
2657
|
+
* const environment = new Environment();
|
|
2658
|
+
* const terrain = new Terrain(30, 30); // create a 30 x 30 Terrain
|
|
2659
|
+
* environment.use(terrain); // tell the Environment to 'use' this Terrain as a helper
|
|
2660
|
+
* ```
|
|
2661
|
+
*
|
|
2194
2662
|
* @since 0.4.0
|
|
2195
2663
|
*/
|
|
2196
2664
|
var Terrain = /** @class */ (function () {
|
|
2197
2665
|
/**
|
|
2666
|
+
* Instantiate a new `Terrain` by passing its `width` and `height` as the first two parameters, and an optional configuration object as the third.
|
|
2667
|
+
*
|
|
2668
|
+
* ### Options
|
|
2669
|
+
*
|
|
2670
|
+
* - `async` (*boolean* = `false`) — Whether to run the `Terrain` in synchronous (`true`) or asynchronous (`mode`). Defaults to synchronous. Depending on the timing mode, {@link addRule | Terrain update rules} should be written differently.
|
|
2671
|
+
* - `grayscale` (*boolean* = `false`)
|
|
2672
|
+
* - In **color mode** (the default), each cell of a `Terrain` is represented by a {@link Colors | pixel-like object} (an object with numeric keys `r`, `g`, `b`, and `a` ranging from 0-255).
|
|
2673
|
+
* - In **grayscale mode**, each cell of a `Terrain` is represented by a single number ranging from 0 (black) to 255 (white).
|
|
2674
|
+
* - `scale` (*number* = `1`) — The size, in pixels, of each cell's width and height when the `Terrain` is rendered using a {@linkcode CanvasRenderer}. In the below screenshots, the `Terrain` on the left uses a scale of `1` while the one on the right uses a scale of `5`:
|
|
2198
2675
|
*
|
|
2199
|
-
*
|
|
2200
|
-
*
|
|
2201
|
-
*
|
|
2676
|
+
* <img alt="Terrain with scale = 1" style="width: 49%;" src="https://cms.flocc.network/wp-content/uploads/2020/04/terrain-1.png">
|
|
2677
|
+
* <img alt="Terrain with scale = 5" style="width: 49%;" src="https://cms.flocc.network/wp-content/uploads/2020/04/terrain-5.png">
|
|
2678
|
+
*
|
|
2679
|
+
* In addition to the above setup, you will need to {@link init | initialize} the `Terrain` and {@link addRule | add an update rule}.
|
|
2202
2680
|
*/
|
|
2203
2681
|
function Terrain(width, height, options) {
|
|
2204
2682
|
if (options === void 0) { options = defaultTerrainOptions; }
|
|
@@ -2218,9 +2696,16 @@ var Terrain = /** @class */ (function () {
|
|
|
2218
2696
|
this.nextData = new Uint8ClampedArray(this.data);
|
|
2219
2697
|
}
|
|
2220
2698
|
/**
|
|
2221
|
-
* Initialize (or overwrite)
|
|
2222
|
-
*
|
|
2223
|
-
*
|
|
2699
|
+
* Initialize (or overwrite) all cell values. The rule you pass has the same signature
|
|
2700
|
+
* as {@linkcode addRule}, but should always return a value (either a number or {@linkcode Colors | pixel-like object}).
|
|
2701
|
+
*
|
|
2702
|
+
* ```js
|
|
2703
|
+
* // initializes cells randomly to either blue or red
|
|
2704
|
+
* terrain.init((x, y) => {
|
|
2705
|
+
* return utils.uniform() > 0.5 ? Colors.BLUE : Colors.RED;
|
|
2706
|
+
* });
|
|
2707
|
+
* ```
|
|
2708
|
+
*
|
|
2224
2709
|
* @since 0.4.0
|
|
2225
2710
|
*/
|
|
2226
2711
|
Terrain.prototype.init = function (rule) {
|
|
@@ -2243,12 +2728,41 @@ var Terrain = /** @class */ (function () {
|
|
|
2243
2728
|
}
|
|
2244
2729
|
}
|
|
2245
2730
|
}
|
|
2731
|
+
this.nextData = new Uint8ClampedArray(this.data);
|
|
2246
2732
|
};
|
|
2247
2733
|
/**
|
|
2248
|
-
*
|
|
2249
|
-
* passed as the rule should be called with the parameters (x
|
|
2250
|
-
* a
|
|
2251
|
-
*
|
|
2734
|
+
* Similar to adding behavior to {@linkcode Agent}s, this adds an update rule for the `Terrain`.
|
|
2735
|
+
* The function passed as the rule should be called with the parameters (`x`, `y`). In synchronous mode,
|
|
2736
|
+
* it should return a value that is the color of that cell on the next time step.
|
|
2737
|
+
*
|
|
2738
|
+
* ```js
|
|
2739
|
+
* // turns a cell red if the x-value is greater than 200,
|
|
2740
|
+
* // blue if the x-value is less than 100,
|
|
2741
|
+
* // and leaves it unchanged in between
|
|
2742
|
+
* terrain.addRule((x, y) => {
|
|
2743
|
+
* if (x > 200) {
|
|
2744
|
+
* return Colors.RED;
|
|
2745
|
+
* } else if (x < 100) {
|
|
2746
|
+
* return Colors.BLUE;
|
|
2747
|
+
* }
|
|
2748
|
+
* });
|
|
2749
|
+
* ```
|
|
2750
|
+
*
|
|
2751
|
+
* For grayscale mode, functions passed to `addRule` should return a number instead of a {@linkcode Colors | pixel-like object}.
|
|
2752
|
+
*
|
|
2753
|
+
* In asynchronous mode, functions should use the {@linkcode set} method to update either this cell
|
|
2754
|
+
* or a different cell.
|
|
2755
|
+
*
|
|
2756
|
+
* ```js
|
|
2757
|
+
* // swaps the colors of this cell and the one five cells to the right
|
|
2758
|
+
* terrain.addRule((x, y) => {
|
|
2759
|
+
* const here = terrain.sample(x, y);
|
|
2760
|
+
* const there = terrain.sample(x + 5, y);
|
|
2761
|
+
* terrain.set(x, y, there);
|
|
2762
|
+
* terrain.set(x + 5, y, here);
|
|
2763
|
+
* });
|
|
2764
|
+
* ```
|
|
2765
|
+
*
|
|
2252
2766
|
* @since 0.4.0
|
|
2253
2767
|
*/
|
|
2254
2768
|
Terrain.prototype.addRule = function (rule) {
|
|
@@ -2256,14 +2770,23 @@ var Terrain = /** @class */ (function () {
|
|
|
2256
2770
|
};
|
|
2257
2771
|
/**
|
|
2258
2772
|
* Given a local path or remote URL to an image, load that image and set
|
|
2259
|
-
*
|
|
2260
|
-
*
|
|
2773
|
+
* `Terrain` data accordingly. This will scale the image to match the
|
|
2774
|
+
* dimensions of the terrain.
|
|
2775
|
+
*
|
|
2261
2776
|
* A 2nd callback parameter fires once the image has been successfully loaded.
|
|
2262
|
-
*
|
|
2263
|
-
*
|
|
2777
|
+
*
|
|
2778
|
+
* ```js
|
|
2779
|
+
* const terrain = new Terrain(400, 400);
|
|
2780
|
+
* terrain.load("/path/to/local/image.jpg", function() {
|
|
2781
|
+
* console.log("Image loaded successfully!");
|
|
2782
|
+
* });
|
|
2783
|
+
* ```
|
|
2784
|
+
*
|
|
2785
|
+
* @param {string} path - The path to or URL of the image
|
|
2786
|
+
* @param {Function} cb - The function to call once the image loads (takes no parameters)
|
|
2264
2787
|
* @since 0.4.0
|
|
2265
2788
|
*/
|
|
2266
|
-
Terrain.prototype.load = function (path,
|
|
2789
|
+
Terrain.prototype.load = function (path, callback) {
|
|
2267
2790
|
var _this = this;
|
|
2268
2791
|
var img = document.createElement("img");
|
|
2269
2792
|
img.src = path;
|
|
@@ -2277,8 +2800,8 @@ var Terrain = /** @class */ (function () {
|
|
|
2277
2800
|
.getContext("2d")
|
|
2278
2801
|
.getImageData(0, 0, _this.width, _this.height).data;
|
|
2279
2802
|
_this.data = data;
|
|
2280
|
-
if (
|
|
2281
|
-
|
|
2803
|
+
if (callback)
|
|
2804
|
+
callback();
|
|
2282
2805
|
};
|
|
2283
2806
|
img.onerror = function () {
|
|
2284
2807
|
console.error("There was an error loading the image for the terrain. Check the path to the URL to make sure that it exists, \n or consider saving a local copy to pull from the same origin: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors");
|
|
@@ -2319,16 +2842,21 @@ var Terrain = /** @class */ (function () {
|
|
|
2319
2842
|
}
|
|
2320
2843
|
};
|
|
2321
2844
|
/**
|
|
2322
|
-
* Get the neighbors of a
|
|
2323
|
-
* Depending on the fourth parameter, retrieves either the von Neumann neighborhood
|
|
2324
|
-
*
|
|
2325
|
-
* (https://en.wikipedia.org/wiki/Moore_neighborhood).
|
|
2845
|
+
* Get the values of the neighbors of a cell within a certain radius.
|
|
2846
|
+
* Depending on the fourth parameter, retrieves either the {@link https://en.wikipedia.org/wiki/Von_Neumann_neighborhood | von Neumann neighborhood}
|
|
2847
|
+
* or the {@link https://en.wikipedia.org/wiki/Moore_neighborhood | Moore neighborhood}.
|
|
2326
2848
|
*
|
|
2327
|
-
*
|
|
2328
|
-
*
|
|
2329
|
-
*
|
|
2330
|
-
*
|
|
2331
|
-
*
|
|
2849
|
+
* ```js
|
|
2850
|
+
* // in grayscale mode:
|
|
2851
|
+
* terrain.neighbors(5, 5, 1); // returns [127, 100, 255, 255] (4 values)
|
|
2852
|
+
*
|
|
2853
|
+
* // in color mode:
|
|
2854
|
+
* terrain.neighbors(5, 5, 1, true);
|
|
2855
|
+
* // returns [{ r: 255, g: 0, b: 0, a: 255 }, { r: 127, ... }, ...] (8 values)
|
|
2856
|
+
* ```
|
|
2857
|
+
*
|
|
2858
|
+
* @param moore - Defaults to using the von Neumann neighborhood.
|
|
2859
|
+
* @returns Either an array of numbers (grayscale mode) or {@link Colors | pixel-like objects} (color mode).
|
|
2332
2860
|
* @since 0.4.0
|
|
2333
2861
|
*/
|
|
2334
2862
|
Terrain.prototype.neighbors = function (x, y, radius, moore) {
|
|
@@ -2350,6 +2878,7 @@ var Terrain = /** @class */ (function () {
|
|
|
2350
2878
|
}
|
|
2351
2879
|
return neighbors;
|
|
2352
2880
|
};
|
|
2881
|
+
/** @hidden */
|
|
2353
2882
|
Terrain.prototype._setAbstract = function (data, x, y, r, g, b, a) {
|
|
2354
2883
|
var _a = this, width = _a.width, height = _a.height, opts = _a.opts;
|
|
2355
2884
|
var grayscale = opts.grayscale, scale = opts.scale;
|
|
@@ -2402,9 +2931,11 @@ var Terrain = /** @class */ (function () {
|
|
|
2402
2931
|
Terrain.prototype.set = function (x, y, r, g, b, a) {
|
|
2403
2932
|
this._setAbstract(this.data, x, y, r, g, b, a);
|
|
2404
2933
|
};
|
|
2934
|
+
/** @hidden */
|
|
2405
2935
|
Terrain.prototype._setNext = function (x, y, r, g, b, a) {
|
|
2406
2936
|
this._setAbstract(this.nextData, x, y, r, g, b, a);
|
|
2407
2937
|
};
|
|
2938
|
+
/** @hidden */
|
|
2408
2939
|
Terrain.prototype._execute = function (x, y) {
|
|
2409
2940
|
var _a = this, rule = _a.rule, opts = _a.opts;
|
|
2410
2941
|
var async = opts.async;
|
|
@@ -2417,6 +2948,7 @@ var Terrain = /** @class */ (function () {
|
|
|
2417
2948
|
// update on nextData
|
|
2418
2949
|
this._setNext(x, y, result);
|
|
2419
2950
|
};
|
|
2951
|
+
/** @hidden */
|
|
2420
2952
|
Terrain.prototype._loop = function (_a) {
|
|
2421
2953
|
var _b = _a.randomizeOrder, randomizeOrder = _b === void 0 ? false : _b;
|
|
2422
2954
|
var _c = this, rule = _c.rule, width = _c.width, height = _c.height, opts = _c.opts;
|
|
@@ -2446,52 +2978,272 @@ var Terrain = /** @class */ (function () {
|
|
|
2446
2978
|
return Terrain;
|
|
2447
2979
|
}());
|
|
2448
2980
|
|
|
2449
|
-
var defaultTickOptions = {
|
|
2450
|
-
activation: "uniform",
|
|
2451
|
-
count: 1,
|
|
2452
|
-
randomizeOrder: false
|
|
2453
|
-
};
|
|
2454
|
-
var defaultEnvironmentOptions = {
|
|
2455
|
-
torus: true,
|
|
2456
|
-
height: 0,
|
|
2457
|
-
width: 0
|
|
2458
|
-
};
|
|
2459
|
-
var warnOnce = once(console.warn.bind(console));
|
|
2460
2981
|
/**
|
|
2461
|
-
*
|
|
2462
|
-
*
|
|
2463
|
-
*
|
|
2982
|
+
* Given a `number` and `min` and `max` values, restrict the number
|
|
2983
|
+
* to the range specified.
|
|
2984
|
+
*
|
|
2985
|
+
* ```js
|
|
2986
|
+
* clamp(5, 1, 10); // returns 5
|
|
2987
|
+
* clamp(5, 2, 4); // returns 4
|
|
2988
|
+
* clamp(0, -4, -3); // returns -3
|
|
2989
|
+
* ```
|
|
2990
|
+
*
|
|
2464
2991
|
* @since 0.0.5
|
|
2465
2992
|
*/
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2993
|
+
function clamp(x, min, max) {
|
|
2994
|
+
if (x < min)
|
|
2995
|
+
return min;
|
|
2996
|
+
if (x > max)
|
|
2997
|
+
return max;
|
|
2998
|
+
return x;
|
|
2999
|
+
}
|
|
3000
|
+
|
|
3001
|
+
/**
|
|
3002
|
+
* Given a mean and standard deviation,
|
|
3003
|
+
* returns a value from a normal/Gaussian distribution.
|
|
3004
|
+
*
|
|
3005
|
+
* ```js
|
|
3006
|
+
* // returns values mostly between 5 and 15 (but sometimes lower or higher)
|
|
3007
|
+
* gaussian(10, 5);
|
|
3008
|
+
*
|
|
3009
|
+
* // no parameters defaults to mean = 0, std. dev. = 1
|
|
3010
|
+
* gaussian(); // mostly values between -1 and 1
|
|
3011
|
+
* ```
|
|
3012
|
+
*
|
|
3013
|
+
* @since 0.0.8
|
|
3014
|
+
*/
|
|
3015
|
+
function gaussian(mean, sd) {
|
|
3016
|
+
if (mean === void 0) { mean = 0; }
|
|
3017
|
+
if (sd === void 0) { sd = 1; }
|
|
3018
|
+
var y, x1, x2, w;
|
|
3019
|
+
do {
|
|
3020
|
+
x1 = 2 * uniform() - 1;
|
|
3021
|
+
x2 = 2 * uniform() - 1;
|
|
3022
|
+
w = x1 * x1 + x2 * x2;
|
|
3023
|
+
} while (w >= 1);
|
|
3024
|
+
w = Math.sqrt((-2 * Math.log(w)) / w);
|
|
3025
|
+
y = x1 * w;
|
|
3026
|
+
return y * sd + mean;
|
|
3027
|
+
}
|
|
3028
|
+
|
|
3029
|
+
/// <reference path="../types/Point.d.ts" />
|
|
3030
|
+
/**
|
|
3031
|
+
* Finds the {@link https://en.wikipedia.org/wiki/Taxicab_geometry | Manhattan distance} between `p1` and `p2`.
|
|
3032
|
+
*
|
|
3033
|
+
* The inputs may be plain objects with `x`, `y`, and/or `z` keys, {@linkcode Vector}s,
|
|
3034
|
+
* or {@linkcode Agent}s with `x`, `y`, and/or `z` data.
|
|
3035
|
+
*
|
|
3036
|
+
* ```js
|
|
3037
|
+
* const a1 = new Agent();
|
|
3038
|
+
* const a2 = new Agent({ x: 3, y: 4 });
|
|
3039
|
+
* manhattanDistance(a1, a2); // returns 7 (defaults to x = 0 and y = 0 for a1)
|
|
3040
|
+
*
|
|
3041
|
+
* const p1 = { x: 3, y: 2 };
|
|
3042
|
+
* const p2 = { x: 0, y: 4 };
|
|
3043
|
+
* manhattanDistance(p1, p2); // returns 5
|
|
3044
|
+
* ```
|
|
3045
|
+
*
|
|
3046
|
+
* @since 0.0.12
|
|
3047
|
+
*/
|
|
3048
|
+
function manhattanDistance(p1, p2) {
|
|
3049
|
+
var x1 = (p1 instanceof Agent ? p1.get("x") : p1.x) || 0;
|
|
3050
|
+
var y1 = (p1 instanceof Agent ? p1.get("y") : p1.y) || 0;
|
|
3051
|
+
var z1 = (p1 instanceof Agent ? p1.get("z") : p1.z) || 0;
|
|
3052
|
+
var x2 = (p2 instanceof Agent ? p2.get("x") : p2.x) || 0;
|
|
3053
|
+
var y2 = (p2 instanceof Agent ? p2.get("y") : p2.y) || 0;
|
|
3054
|
+
var z2 = (p2 instanceof Agent ? p2.get("z") : p2.z) || 0;
|
|
3055
|
+
var dx = Math.abs(x2 - x1);
|
|
3056
|
+
var dy = Math.abs(y2 - y1);
|
|
3057
|
+
var dz = Math.abs(z2 - z1);
|
|
3058
|
+
// distance for toroidal environments
|
|
3059
|
+
if (p1 instanceof Agent &&
|
|
3060
|
+
p2 instanceof Agent &&
|
|
3061
|
+
p1.environment &&
|
|
3062
|
+
p2.environment &&
|
|
3063
|
+
p1.environment === p2.environment &&
|
|
3064
|
+
p1.environment.width &&
|
|
3065
|
+
p1.environment.height &&
|
|
3066
|
+
p1.environment.opts.torus) {
|
|
3067
|
+
var environment = p1.environment;
|
|
3068
|
+
var width = environment.width, height = environment.height;
|
|
3069
|
+
if (dx > width / 2)
|
|
3070
|
+
dx = width - dx;
|
|
3071
|
+
if (dy > height / 2)
|
|
3072
|
+
dy = height - dy;
|
|
2489
3073
|
}
|
|
3074
|
+
return dx + dy + dz;
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
/**
|
|
3078
|
+
* Maps a number x, from the given domain aMin --> aMax,
|
|
3079
|
+
* onto the given range bMin --> bMax.
|
|
3080
|
+
* Ex: remap(5, 0, 10, 0, 100) => 50.
|
|
3081
|
+
* @param {number} x
|
|
3082
|
+
* @param {number} aMin
|
|
3083
|
+
* @param {number} aMax
|
|
3084
|
+
* @param {number} bMin
|
|
3085
|
+
* @param {number} bMax
|
|
3086
|
+
* @returns {number} The remapped value.
|
|
3087
|
+
* @since 0.0.5
|
|
3088
|
+
*/
|
|
3089
|
+
function remap(x, aMin, aMax, bMin, bMax) {
|
|
3090
|
+
return bMin + ((bMax - bMin) * (x - aMin)) / (aMax - aMin);
|
|
3091
|
+
}
|
|
3092
|
+
|
|
3093
|
+
/**
|
|
3094
|
+
* Seed a pseudo-random number generator with a value.
|
|
3095
|
+
* This can be used to produce predictable pseudo-random numbers.
|
|
3096
|
+
* When calling `utils.random`, `utils.sample`, or other functions
|
|
3097
|
+
* relying on randomness with the same initial seed, the values
|
|
3098
|
+
* generated will always be the same.
|
|
3099
|
+
*
|
|
3100
|
+
* Predictable randomness can be turned off by calling `seed(null)`, or reset
|
|
3101
|
+
* by calling `seed(value)` again with the initial value you used.
|
|
3102
|
+
* @param value
|
|
3103
|
+
* @since 0.5.0
|
|
3104
|
+
*/
|
|
3105
|
+
var seed = function (value) { return PRNG.seed(value); };
|
|
3106
|
+
|
|
3107
|
+
/**
|
|
3108
|
+
* Find the standard deviation of an Array of numbers.
|
|
3109
|
+
* @param {Array<number>} arr
|
|
3110
|
+
* @returns {number}
|
|
3111
|
+
* @since 0.0.16
|
|
3112
|
+
*/
|
|
3113
|
+
function stdDev(arr) {
|
|
3114
|
+
if (arr.length === 0)
|
|
3115
|
+
return null;
|
|
3116
|
+
var ave = mean(arr);
|
|
3117
|
+
return Math.sqrt(mean(arr.map(function (x) { return (x - ave) * (x - ave); })));
|
|
3118
|
+
}
|
|
3119
|
+
|
|
3120
|
+
/**
|
|
3121
|
+
* @since 0.1.4
|
|
3122
|
+
*/
|
|
3123
|
+
function zfill(str, width) {
|
|
3124
|
+
if (width === void 0) { width = 0; }
|
|
3125
|
+
var output = str;
|
|
3126
|
+
while (output.length < width)
|
|
3127
|
+
output = "0" + output;
|
|
3128
|
+
return output;
|
|
3129
|
+
}
|
|
3130
|
+
|
|
3131
|
+
|
|
3132
|
+
|
|
3133
|
+
var utils = /*#__PURE__*/Object.freeze({
|
|
3134
|
+
__proto__: null,
|
|
3135
|
+
clamp: clamp,
|
|
3136
|
+
distance: distance,
|
|
3137
|
+
gaussian: gaussian,
|
|
3138
|
+
gcd: gcd,
|
|
3139
|
+
manhattanDistance: manhattanDistance,
|
|
3140
|
+
lerp: lerp,
|
|
3141
|
+
remap: remap,
|
|
3142
|
+
random: random,
|
|
3143
|
+
sample: sample$1,
|
|
3144
|
+
sampler: sampler,
|
|
3145
|
+
seed: seed,
|
|
3146
|
+
series: series,
|
|
3147
|
+
shuffle: shuffle,
|
|
3148
|
+
sum: sum,
|
|
3149
|
+
max: max,
|
|
3150
|
+
mean: mean,
|
|
3151
|
+
median: median,
|
|
3152
|
+
min: min,
|
|
3153
|
+
percentile: percentile,
|
|
3154
|
+
stdDev: stdDev,
|
|
3155
|
+
uniform: uniform,
|
|
3156
|
+
uuid: uuid$1,
|
|
3157
|
+
zfill: zfill
|
|
3158
|
+
});
|
|
3159
|
+
|
|
3160
|
+
var defaultTickOptions = {
|
|
3161
|
+
activation: "uniform",
|
|
3162
|
+
activationCount: 1,
|
|
3163
|
+
count: 1,
|
|
3164
|
+
randomizeOrder: false
|
|
3165
|
+
};
|
|
3166
|
+
var defaultEnvironmentOptions = {
|
|
3167
|
+
torus: true,
|
|
3168
|
+
height: 0,
|
|
3169
|
+
width: 0
|
|
3170
|
+
};
|
|
3171
|
+
var warnOnce = once(console.warn.bind(console));
|
|
3172
|
+
/**
|
|
3173
|
+
* An environment provides the space and time in which Agents interact.
|
|
3174
|
+
* Environments are themselves Agents, and can store data in key-value
|
|
3175
|
+
* pairs that can be manipulated just like Agent data.
|
|
3176
|
+
* @since 0.0.5
|
|
3177
|
+
*/
|
|
3178
|
+
var Environment = /** @class */ (function (_super) {
|
|
3179
|
+
__extends(Environment, _super);
|
|
2490
3180
|
/**
|
|
2491
|
-
*
|
|
2492
|
-
*
|
|
2493
|
-
*
|
|
2494
|
-
*
|
|
3181
|
+
* Although `Environment`s inherit {@linkcode Agent} methods
|
|
3182
|
+
* like {@linkcode Agent.set}, {@linkcode Agent.get}, etc. they have
|
|
3183
|
+
* a different `constructor` signature.
|
|
3184
|
+
*
|
|
3185
|
+
* Pass in predefined `Environment` options for:
|
|
3186
|
+
* - `torus` — Whether the `Environment` should wrap around in 2d space (with `Agent`s that move off the right reappearing on the left, off the top reappearing on the bottom, etc.)
|
|
3187
|
+
* - `width` — The width of the `Environment` (used when `torus = true`)
|
|
3188
|
+
* - `height` — The height of the `Environment` (used when `torus = true`)
|
|
3189
|
+
* @override
|
|
3190
|
+
*/
|
|
3191
|
+
function Environment(opts) {
|
|
3192
|
+
if (opts === void 0) { opts = defaultEnvironmentOptions; }
|
|
3193
|
+
var _this = _super.call(this) || this;
|
|
3194
|
+
/** @hidden */
|
|
3195
|
+
_this.agents = [];
|
|
3196
|
+
/** @hidden */
|
|
3197
|
+
_this.agentsById = new Map();
|
|
3198
|
+
/** @hidden */
|
|
3199
|
+
_this.environment = null;
|
|
3200
|
+
/** @hidden */
|
|
3201
|
+
_this.cache = new Map();
|
|
3202
|
+
/** @hidden */
|
|
3203
|
+
_this.helpers = {
|
|
3204
|
+
kdtree: null,
|
|
3205
|
+
network: null,
|
|
3206
|
+
terrain: null
|
|
3207
|
+
};
|
|
3208
|
+
/**
|
|
3209
|
+
* An array of the renderers associated with this `Environment`.
|
|
3210
|
+
* An `Environment` can have multiple renderers, usually one to render
|
|
3211
|
+
* the {@linkcode Agent}s spatially and others for data visualization,
|
|
3212
|
+
* such as a {@linkcode LineChartRenderer}, {@linkcode Histogram}, etc.
|
|
3213
|
+
*/
|
|
3214
|
+
_this.renderers = [];
|
|
3215
|
+
/**
|
|
3216
|
+
* This property will always equal the number of tick cycles that
|
|
3217
|
+
* have passed since the `Environment` was created. If you call
|
|
3218
|
+
* {@linkcode tick} so that it goes forward multiple time steps, it will
|
|
3219
|
+
* increase the `time` by that value (not by just `1`, even though
|
|
3220
|
+
* you only called `tick` once).
|
|
3221
|
+
*
|
|
3222
|
+
* ```js
|
|
3223
|
+
* const environment = new Environment();
|
|
3224
|
+
* environment.time; // returns 0
|
|
3225
|
+
*
|
|
3226
|
+
* environment.tick();
|
|
3227
|
+
* environment.time; // returns 1
|
|
3228
|
+
*
|
|
3229
|
+
* environment.tick(3);
|
|
3230
|
+
* environment.time; // returns 4
|
|
3231
|
+
* ```
|
|
3232
|
+
*
|
|
3233
|
+
* @since 0.1.4
|
|
3234
|
+
* */
|
|
3235
|
+
_this.time = 0;
|
|
3236
|
+
_this.opts = Object.assign({}, defaultEnvironmentOptions);
|
|
3237
|
+
_this.opts = Object.assign(_this.opts, opts);
|
|
3238
|
+
_this.width = _this.opts.width;
|
|
3239
|
+
_this.height = _this.opts.height;
|
|
3240
|
+
return _this;
|
|
3241
|
+
}
|
|
3242
|
+
/**
|
|
3243
|
+
* Add an {@linkcode Agent} to this `Environment`. Once this is called,
|
|
3244
|
+
* the `Agent`'s {@link Agent.environment | `environment`} property
|
|
3245
|
+
* will automatically be set to this `Environment`.
|
|
3246
|
+
* @param rebalance - Whether to rebalance if there is a `KDTree` (defaults to true)
|
|
2495
3247
|
* @since 0.0.5
|
|
2496
3248
|
*/
|
|
2497
3249
|
Environment.prototype.addAgent = function (agent, rebalance) {
|
|
@@ -2553,7 +3305,7 @@ var Environment = /** @class */ (function (_super) {
|
|
|
2553
3305
|
return this.agentsById.get(id) || null;
|
|
2554
3306
|
};
|
|
2555
3307
|
/**
|
|
2556
|
-
*
|
|
3308
|
+
* Remove all agents from the environment.
|
|
2557
3309
|
* @since 0.1.3
|
|
2558
3310
|
*/
|
|
2559
3311
|
Environment.prototype.clear = function () {
|
|
@@ -2563,64 +3315,132 @@ var Environment = /** @class */ (function (_super) {
|
|
|
2563
3315
|
}
|
|
2564
3316
|
};
|
|
2565
3317
|
/**
|
|
2566
|
-
* From the parameter passed to .tick, get a structured TickOptions object.
|
|
2567
|
-
* @
|
|
3318
|
+
* From the parameter passed to {@linkcode Environment.tick}, get a structured TickOptions object.
|
|
3319
|
+
* @hidden
|
|
2568
3320
|
*/
|
|
2569
3321
|
Environment.prototype._getTickOptions = function (opts) {
|
|
2570
|
-
var
|
|
3322
|
+
var baseOpts = Object.assign({}, defaultTickOptions);
|
|
2571
3323
|
if (typeof opts === "number") {
|
|
2572
|
-
count = opts;
|
|
3324
|
+
baseOpts.count = opts;
|
|
2573
3325
|
}
|
|
2574
3326
|
else if (!!opts) {
|
|
2575
|
-
|
|
2576
|
-
}
|
|
2577
|
-
if (opts &&
|
|
2578
|
-
typeof opts !== "number" &&
|
|
2579
|
-
opts.hasOwnProperty("randomizeOrder")) {
|
|
2580
|
-
randomizeOrder = opts.randomizeOrder;
|
|
3327
|
+
Object.assign(baseOpts, opts);
|
|
2581
3328
|
}
|
|
2582
|
-
|
|
3329
|
+
if (opts === undefined ||
|
|
2583
3330
|
(typeof opts !== "number" && !opts.hasOwnProperty("randomizeOrder"))) {
|
|
2584
3331
|
warnOnce("You called `environment.tick` without specifying a `randomizeOrder` option. Currently this defaults to `false` (i.e. each agent ticks in the order it was added to the environment). However, in **Flocc 0.6.0 this will default to `true`** — agent activation order will default to being randomized.");
|
|
2585
3332
|
}
|
|
2586
|
-
return
|
|
3333
|
+
return baseOpts;
|
|
2587
3334
|
};
|
|
2588
3335
|
/**
|
|
2589
|
-
*
|
|
2590
|
-
* @
|
|
3336
|
+
* For all agents passed, execute agent rules
|
|
3337
|
+
* @hidden
|
|
2591
3338
|
*/
|
|
2592
|
-
Environment.prototype._executeAgentRules = function (
|
|
2593
|
-
(
|
|
2594
|
-
return agent.executeRules();
|
|
2595
|
-
});
|
|
3339
|
+
Environment.prototype._executeAgentRules = function (agents) {
|
|
3340
|
+
agents.forEach(function (agent) { return agent === null || agent === void 0 ? void 0 : agent.executeRules(); });
|
|
2596
3341
|
};
|
|
2597
3342
|
/**
|
|
2598
|
-
*
|
|
2599
|
-
* @
|
|
3343
|
+
* For all agents passed, execute enqueued agent rules
|
|
3344
|
+
* @hidden
|
|
2600
3345
|
*/
|
|
2601
|
-
Environment.prototype._executeEnqueuedAgentRules = function (
|
|
2602
|
-
(
|
|
2603
|
-
return agent.executeEnqueuedRules();
|
|
2604
|
-
});
|
|
3346
|
+
Environment.prototype._executeEnqueuedAgentRules = function (agents) {
|
|
3347
|
+
agents.forEach(function (agent) { return agent === null || agent === void 0 ? void 0 : agent.executeEnqueuedRules(); });
|
|
2605
3348
|
};
|
|
2606
3349
|
/**
|
|
2607
|
-
*
|
|
2608
|
-
*
|
|
2609
|
-
*
|
|
2610
|
-
*
|
|
2611
|
-
*
|
|
2612
|
-
*
|
|
3350
|
+
* Runs the `Environment`s tick cycle. Depending on the parameters, one,
|
|
3351
|
+
* some, or all of the {@linkcode Agent}s in the `Environment`
|
|
3352
|
+
* might be activated, and all renderers associated with the
|
|
3353
|
+
* `Environment` will update. After the tick cycle finishes, any rules that were enqueued will be run and the `Environment`'s {@linkcode time} property will have incremented.
|
|
3354
|
+
*
|
|
3355
|
+
* ```js
|
|
3356
|
+
* environment.tick(); // ticks once
|
|
3357
|
+
*
|
|
3358
|
+
* // To run multiple tick cycles, you can pass a number
|
|
3359
|
+
* environment.tick(5); // ticks 5 times
|
|
3360
|
+
* ```
|
|
3361
|
+
*
|
|
3362
|
+
* Passing a configuration object (instead of a number) allows
|
|
3363
|
+
* you to have finer control over the tick cycle. The object can
|
|
3364
|
+
* have the following keys:
|
|
3365
|
+
* - `activation`: Either `"uniform"` or `"random"` (defaults to `"uniform"`).
|
|
3366
|
+
* - `activation = "uniform"` — All `Agent`s in the `Environment` are activated with every tick cycle.
|
|
3367
|
+
* - `activation = "random"` — One or more `Agent`s are randomly selected to be activated every tick cycle (see `activationCount` below).
|
|
3368
|
+
* - `activationCount`: For `"random"` activation, this many `Agent`s will be activated with each tick cycle. Defaults to `1`. If `activationCount` is greater than the number of `Agent`s in the `Environment`, then all the `Agent`s will be activated exactly once in random order.
|
|
3369
|
+
* - `count`: The number of tick cycles to run.
|
|
3370
|
+
* - `randomizeOrder`: When `activation = "uniform"`, if `randomizeOrder = true`, `Agent`s will be activated in random order, otherwise in the order they were added to the `Environment`. **This currently defaults to `false` but will default to `true` in v0.6.0.**
|
|
3371
|
+
*
|
|
3372
|
+
* ```js
|
|
3373
|
+
* // Ticks three times, activating 10 random agents with each tick cycle.
|
|
3374
|
+
* environment.tick({
|
|
3375
|
+
* activation: "random",
|
|
3376
|
+
* activationCount: 10,
|
|
3377
|
+
* count: 3
|
|
3378
|
+
* });
|
|
3379
|
+
* ```
|
|
3380
|
+
*
|
|
2613
3381
|
* @since 0.0.5
|
|
2614
3382
|
*/
|
|
2615
3383
|
Environment.prototype.tick = function (opts) {
|
|
2616
|
-
var _a = this._getTickOptions(opts), count = _a.count, randomizeOrder = _a.randomizeOrder;
|
|
2617
|
-
|
|
2618
|
-
|
|
3384
|
+
var _a = this._getTickOptions(opts), activation = _a.activation, activationCount = _a.activationCount, count = _a.count, randomizeOrder = _a.randomizeOrder;
|
|
3385
|
+
// for uniform activation, every agent is always activated
|
|
3386
|
+
if (activation === "uniform") {
|
|
3387
|
+
var agentsInOrder = randomizeOrder ? shuffle(this.agents) : this.agents;
|
|
3388
|
+
this._executeAgentRules(agentsInOrder);
|
|
3389
|
+
this._executeEnqueuedAgentRules(agentsInOrder);
|
|
3390
|
+
}
|
|
3391
|
+
// for random activation, the number of agents activated
|
|
3392
|
+
// per tick is determined by the `activationCount` option
|
|
3393
|
+
else if (activation === "random") {
|
|
3394
|
+
if (activationCount === 1) {
|
|
3395
|
+
var agent = sample$1(this.agents);
|
|
3396
|
+
if (agent !== null) {
|
|
3397
|
+
agent.executeRules();
|
|
3398
|
+
agent.executeEnqueuedRules();
|
|
3399
|
+
}
|
|
3400
|
+
}
|
|
3401
|
+
else if (activationCount > 1) {
|
|
3402
|
+
var sampleCount = sampler(activationCount);
|
|
3403
|
+
// this safety check should always return `true`
|
|
3404
|
+
if (isMultipleSampleFunc(sampleCount)) {
|
|
3405
|
+
var agents = sampleCount(this.getAgents());
|
|
3406
|
+
this._executeAgentRules(agents);
|
|
3407
|
+
this._executeEnqueuedAgentRules(agents);
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
else {
|
|
3411
|
+
warnOnce("You passed a zero or negative `activationCount` to the Environment's tick options. No agents will be activated.");
|
|
3412
|
+
}
|
|
3413
|
+
}
|
|
2619
3414
|
if (this.helpers.kdtree)
|
|
2620
3415
|
this.helpers.kdtree.rebalance();
|
|
2621
3416
|
var terrain = this.helpers.terrain;
|
|
2622
|
-
if (terrain && terrain.rule)
|
|
2623
|
-
|
|
3417
|
+
if (terrain && terrain.rule) {
|
|
3418
|
+
if (activation === "uniform") {
|
|
3419
|
+
terrain._loop({ randomizeOrder: randomizeOrder });
|
|
3420
|
+
}
|
|
3421
|
+
else if (activation === "random") {
|
|
3422
|
+
if (activationCount === 1) {
|
|
3423
|
+
var x = random(0, terrain.width);
|
|
3424
|
+
var y = random(0, terrain.height);
|
|
3425
|
+
terrain._execute(x, y);
|
|
3426
|
+
}
|
|
3427
|
+
else if (activationCount > 1) {
|
|
3428
|
+
var generator = series(terrain.width * terrain.height);
|
|
3429
|
+
var indices = [];
|
|
3430
|
+
while (indices.length < activationCount) {
|
|
3431
|
+
var index = generator.next().value;
|
|
3432
|
+
var x = index % terrain.width;
|
|
3433
|
+
var y = (index / terrain.width) | 0;
|
|
3434
|
+
terrain._execute(x, y);
|
|
3435
|
+
indices.push(index);
|
|
3436
|
+
}
|
|
3437
|
+
}
|
|
3438
|
+
// in synchronous mode, write the buffer to the data
|
|
3439
|
+
if (!terrain.opts.async) {
|
|
3440
|
+
terrain.data = new Uint8ClampedArray(terrain.nextData);
|
|
3441
|
+
}
|
|
3442
|
+
}
|
|
3443
|
+
}
|
|
2624
3444
|
this.time++;
|
|
2625
3445
|
if (count > 1) {
|
|
2626
3446
|
this.tick(count - 1);
|
|
@@ -2629,26 +3449,41 @@ var Environment = /** @class */ (function (_super) {
|
|
|
2629
3449
|
this.renderers.forEach(function (r) { return r.render(); });
|
|
2630
3450
|
};
|
|
2631
3451
|
/**
|
|
2632
|
-
* Use a helper with this environment.
|
|
2633
|
-
* @
|
|
3452
|
+
* Use a helper with this environment. A helper can be one of:
|
|
3453
|
+
* - {@linkcode KDTree}
|
|
3454
|
+
* - {@linkcode Network}
|
|
3455
|
+
* - {@linkcode Terrain}
|
|
2634
3456
|
* @since 0.1.3
|
|
2635
3457
|
*/
|
|
2636
|
-
Environment.prototype.use = function (
|
|
2637
|
-
if (
|
|
2638
|
-
this.helpers.kdtree =
|
|
2639
|
-
if (
|
|
2640
|
-
this.helpers.network =
|
|
2641
|
-
if (
|
|
2642
|
-
this.helpers.terrain =
|
|
3458
|
+
Environment.prototype.use = function (helper) {
|
|
3459
|
+
if (helper instanceof KDTree)
|
|
3460
|
+
this.helpers.kdtree = helper;
|
|
3461
|
+
if (helper instanceof Network)
|
|
3462
|
+
this.helpers.network = helper;
|
|
3463
|
+
if (helper instanceof Terrain)
|
|
3464
|
+
this.helpers.terrain = helper;
|
|
2643
3465
|
};
|
|
2644
3466
|
/**
|
|
2645
3467
|
* Get an array of data associated with agents in the environment by key.
|
|
2646
|
-
*
|
|
2647
|
-
*
|
|
2648
|
-
*
|
|
2649
|
-
*
|
|
2650
|
-
*
|
|
2651
|
-
*
|
|
3468
|
+
* Calling `environment.stat('name')` is equivalent to calling
|
|
3469
|
+
* `environment.getAgents().map(agent => agent.get('name'));`
|
|
3470
|
+
*
|
|
3471
|
+
* By default, calling this will calculate the result at most once
|
|
3472
|
+
* per time cycle, and return the cached value on subsequent calls (until
|
|
3473
|
+
* the next time cycle, when it will recalculate).
|
|
3474
|
+
*
|
|
3475
|
+
* @param key - The key for which to retrieve data.
|
|
3476
|
+
* @param useCache - Whether or not to cache the result.
|
|
3477
|
+
* @returns Array of data associated with `agent.get(key)` across all agents.
|
|
3478
|
+
*
|
|
3479
|
+
* ```js
|
|
3480
|
+
* environment.addAgent(new Agent({ name: "Alice" }));
|
|
3481
|
+
* environment.addAgent(new Agent({ name: "Bob" }));
|
|
3482
|
+
* environment.addAgent(new Agent({ name: "Chaz" }));
|
|
3483
|
+
*
|
|
3484
|
+
* environment.stat('name'); // returns ['Alice', 'Bob', 'Chaz']
|
|
3485
|
+
* ```
|
|
3486
|
+
*
|
|
2652
3487
|
* @since 0.3.14
|
|
2653
3488
|
*/
|
|
2654
3489
|
Environment.prototype.stat = function (key, useCache) {
|
|
@@ -2669,9 +3504,17 @@ var Environment = /** @class */ (function (_super) {
|
|
|
2669
3504
|
};
|
|
2670
3505
|
/**
|
|
2671
3506
|
* Pass a function to cache and use the return value within the same environment tick.
|
|
2672
|
-
* @param
|
|
2673
|
-
* @return
|
|
3507
|
+
* @param fn - The function to memoize.
|
|
3508
|
+
* @return The return value of the function that was passed.
|
|
2674
3509
|
* @since 0.3.14
|
|
3510
|
+
*
|
|
3511
|
+
* ```js
|
|
3512
|
+
* // Within the same time cycle, this function will only be called once.
|
|
3513
|
+
* // The cached value will be used on subsequent calls.
|
|
3514
|
+
* const blueAgents = environment.memo(() => {
|
|
3515
|
+
* return environment.getAgents().filter(a => a.get('color') === 'blue');
|
|
3516
|
+
* });
|
|
3517
|
+
* ```
|
|
2675
3518
|
*/
|
|
2676
3519
|
Environment.prototype.memo = function (fn, key) {
|
|
2677
3520
|
var serialized = (key ? key + "-" : "") + fn.toString();
|
|
@@ -2712,10 +3555,21 @@ var unhash = function (str) {
|
|
|
2712
3555
|
};
|
|
2713
3556
|
var warnOnce$1 = once(console.warn.bind(console));
|
|
2714
3557
|
/**
|
|
2715
|
-
*
|
|
3558
|
+
* A `GridEnvironment` is the **deprecated** version of a cellular automata.
|
|
3559
|
+
* It's now recommended that you use a standard {@linkcode Environment} with a
|
|
3560
|
+
* {@linkcode Terrain}. This class will be removed entirely in v0.6.0.
|
|
3561
|
+
*
|
|
3562
|
+
* In a `GridEnvironment` with an {@linkcode ASCIIRenderer}, {@linkcode Agent}s are rendered
|
|
3563
|
+
* using their `"value"` data (a single character).
|
|
3564
|
+
*
|
|
3565
|
+
* @deprecated since 0.4.0
|
|
3566
|
+
* @since 0.0.10
|
|
2716
3567
|
*/
|
|
2717
3568
|
var GridEnvironment = /** @class */ (function (_super) {
|
|
2718
3569
|
__extends(GridEnvironment, _super);
|
|
3570
|
+
/**
|
|
3571
|
+
* Create a `GridEnvironment` with the given `width` and `height`.
|
|
3572
|
+
*/
|
|
2719
3573
|
function GridEnvironment(width, height) {
|
|
2720
3574
|
if (width === void 0) { width = 2; }
|
|
2721
3575
|
if (height === void 0) { height = 2; }
|
|
@@ -2750,6 +3604,7 @@ var GridEnvironment = /** @class */ (function (_super) {
|
|
|
2750
3604
|
}
|
|
2751
3605
|
};
|
|
2752
3606
|
/**
|
|
3607
|
+
* @hidden
|
|
2753
3608
|
* @since 0.1.0
|
|
2754
3609
|
*/
|
|
2755
3610
|
GridEnvironment.prototype.normalize = function (x, y) {
|
|
@@ -2764,7 +3619,7 @@ var GridEnvironment = /** @class */ (function (_super) {
|
|
|
2764
3619
|
return { x: x, y: y };
|
|
2765
3620
|
};
|
|
2766
3621
|
/**
|
|
2767
|
-
* For
|
|
3622
|
+
* For `GridEnvironment`s, `addAgent` takes `x` and `y` values
|
|
2768
3623
|
* and automatically adds a Agent to that cell coordinate.
|
|
2769
3624
|
* @param {number} x_
|
|
2770
3625
|
* @param {number} y_
|
|
@@ -2793,8 +3648,8 @@ var GridEnvironment = /** @class */ (function (_super) {
|
|
|
2793
3648
|
return agent;
|
|
2794
3649
|
};
|
|
2795
3650
|
/**
|
|
2796
|
-
* For GridEnvironments, `
|
|
2797
|
-
* and removes the Agent (if there is one) at that cell coordinate.
|
|
3651
|
+
* For GridEnvironments, `removeAgentAt` takes `x` and `y` values
|
|
3652
|
+
* and removes the `Agent` (if there is one) at that cell coordinate.
|
|
2798
3653
|
* @param {number} x_
|
|
2799
3654
|
* @param {number} y_
|
|
2800
3655
|
* @since 0.1.0
|
|
@@ -2957,6 +3812,7 @@ var GridEnvironment = /** @class */ (function (_super) {
|
|
|
2957
3812
|
};
|
|
2958
3813
|
/**
|
|
2959
3814
|
* Execute all cell rules.
|
|
3815
|
+
* @hidden
|
|
2960
3816
|
* @param { boolean } randomizeOrder
|
|
2961
3817
|
*/
|
|
2962
3818
|
GridEnvironment.prototype._executeCellRules = function (randomizeOrder) {
|
|
@@ -2983,6 +3839,7 @@ var GridEnvironment = /** @class */ (function (_super) {
|
|
|
2983
3839
|
};
|
|
2984
3840
|
/**
|
|
2985
3841
|
* Execute all enqueued cell rules.
|
|
3842
|
+
* @hidden
|
|
2986
3843
|
* @param { boolean } randomizeOrder
|
|
2987
3844
|
*/
|
|
2988
3845
|
GridEnvironment.prototype._executeEnqueuedCellRules = function (randomizeOrder) {
|
|
@@ -3008,8 +3865,8 @@ var GridEnvironment = /** @class */ (function (_super) {
|
|
|
3008
3865
|
}
|
|
3009
3866
|
};
|
|
3010
3867
|
/**
|
|
3011
|
-
* Override/extend Environment.tick to include the
|
|
3012
|
-
* GridEnvironment's cells.
|
|
3868
|
+
* Override/extend {@linkcode Environment.tick} to include the
|
|
3869
|
+
* `GridEnvironment`'s cells.
|
|
3013
3870
|
* @override
|
|
3014
3871
|
* @param {number} opts
|
|
3015
3872
|
*/
|
|
@@ -3018,11 +3875,11 @@ var GridEnvironment = /** @class */ (function (_super) {
|
|
|
3018
3875
|
// execute all cell rules
|
|
3019
3876
|
this._executeCellRules(randomizeOrder);
|
|
3020
3877
|
// execute all agent rules
|
|
3021
|
-
this._executeAgentRules(randomizeOrder);
|
|
3878
|
+
this._executeAgentRules(randomizeOrder ? shuffle(this.agents) : this.agents);
|
|
3022
3879
|
// execute all enqueued cell rules
|
|
3023
3880
|
this._executeEnqueuedCellRules(randomizeOrder);
|
|
3024
3881
|
// execute all enqueued agent rules
|
|
3025
|
-
this._executeEnqueuedAgentRules(randomizeOrder);
|
|
3882
|
+
this._executeEnqueuedAgentRules(randomizeOrder ? shuffle(this.agents) : this.agents);
|
|
3026
3883
|
this.time++;
|
|
3027
3884
|
if (count > 1) {
|
|
3028
3885
|
this.tick(count - 1);
|
|
@@ -3035,13 +3892,24 @@ var GridEnvironment = /** @class */ (function (_super) {
|
|
|
3035
3892
|
|
|
3036
3893
|
var AbstractRenderer = /** @class */ (function () {
|
|
3037
3894
|
function AbstractRenderer() {
|
|
3895
|
+
/** @hidden */
|
|
3038
3896
|
this.canvas = document.createElement("canvas");
|
|
3897
|
+
/** @hidden */
|
|
3039
3898
|
this.context = this.canvas.getContext("2d");
|
|
3040
3899
|
}
|
|
3041
3900
|
AbstractRenderer.prototype.render = function () { };
|
|
3042
3901
|
/**
|
|
3043
3902
|
* Mount this renderer to a DOM element. Pass either a string representing a
|
|
3044
|
-
* CSS selector matching the element
|
|
3903
|
+
* CSS selector matching the element or the element itself.
|
|
3904
|
+
*
|
|
3905
|
+
* ```js
|
|
3906
|
+
* // mounts the renderer to the element with the ID `container`
|
|
3907
|
+
* renderer.mount('#container');
|
|
3908
|
+
*
|
|
3909
|
+
* // mounts the renderer to the element itself
|
|
3910
|
+
* const container = document.getElementById('container');
|
|
3911
|
+
* renderer.mount(container);
|
|
3912
|
+
* ```
|
|
3045
3913
|
* @param {string | HTMLElement} el
|
|
3046
3914
|
*/
|
|
3047
3915
|
AbstractRenderer.prototype.mount = function (el) {
|
|
@@ -3056,11 +3924,25 @@ var AbstractRenderer = /** @class */ (function () {
|
|
|
3056
3924
|
|
|
3057
3925
|
var warnOnce$2 = once(console.warn.bind(console));
|
|
3058
3926
|
/**
|
|
3927
|
+
* An `ASCIIRenderer` renders the {@link Agent | `Agent`}s in
|
|
3928
|
+
* a {@linkcode GridEnvironment}. `Agent`s are rendered
|
|
3929
|
+
* using their `"value"` data (a single character).
|
|
3930
|
+
* Since v0.4.0, this class has been **deprecated**, and it will be removed
|
|
3931
|
+
* entirely in v0.6.0.
|
|
3932
|
+
* ```js
|
|
3933
|
+
* const renderer = new ASCIIRenderer(grid);
|
|
3934
|
+
* renderer.mount("#container-id");
|
|
3935
|
+
* ```
|
|
3936
|
+
* @deprecated since 0.4.0
|
|
3059
3937
|
* @since 0.0.10
|
|
3060
3938
|
*/
|
|
3061
3939
|
var ASCIIRenderer = /** @class */ (function (_super) {
|
|
3062
3940
|
__extends(ASCIIRenderer, _super);
|
|
3063
|
-
|
|
3941
|
+
/**
|
|
3942
|
+
* Create a new `ASCIIRenderer` by passing in the
|
|
3943
|
+
* {@linkcode GridEnvironment} you want to be rendered.
|
|
3944
|
+
*/
|
|
3945
|
+
function ASCIIRenderer(environment) {
|
|
3064
3946
|
var _this = _super.call(this) || this;
|
|
3065
3947
|
warnOnce$2("As of Flocc v0.5.0, ASCIIEnvironment is **DEPRECATED**. It will be **REMOVED** in v0.6.0. The Terrain helper should be used for 2-dimensional grid-like data, with CanvasRenderer to visualize. Read more about Terrains here: https://flocc.network/docs/terrain");
|
|
3066
3948
|
_this.environment = environment;
|
|
@@ -3069,6 +3951,7 @@ var ASCIIRenderer = /** @class */ (function (_super) {
|
|
|
3069
3951
|
return _this;
|
|
3070
3952
|
}
|
|
3071
3953
|
/**
|
|
3954
|
+
* Renders the contents of the `ASCIIRenderer`'s {@linkcode GridEnvironment}.
|
|
3072
3955
|
* @since 0.0.10
|
|
3073
3956
|
*/
|
|
3074
3957
|
ASCIIRenderer.prototype.render = function () {
|
|
@@ -3104,12 +3987,46 @@ var defaultOptions = {
|
|
|
3104
3987
|
trace: false
|
|
3105
3988
|
};
|
|
3106
3989
|
/**
|
|
3990
|
+
* A `CanvasRenderer` renders an {@linkcode Environment} spatially in two dimensions.
|
|
3991
|
+
* Importantly, it expects that all {@linkcode Agent}s in the `Environment`
|
|
3992
|
+
* have numeric `"x"` and `"y"` values associated with them.
|
|
3993
|
+
*
|
|
3994
|
+
* `CanvasRenderer`s will render all `Agent`s that are visible in the rendered `Environment` space,
|
|
3995
|
+
* with the color of their `"color"` value (defaulting to black).
|
|
3996
|
+
* Depending on the `"shape"` of the `Agent`, additional data might be needed. `Agent` `"shape"`s can be:
|
|
3997
|
+
* - `"circle"` (default) — Draws a circle centered at the `Agent`'s `"x"` / `"y"` values.
|
|
3998
|
+
* - If the `Agent` has a `"size"` value, uses that for the circle radius (defaults to 1px).
|
|
3999
|
+
* - `"arrow"` — Draws an arrow centered at the `Agent`'s `"x"` / `"y"` values.
|
|
4000
|
+
* - The arrow will point in the direction of the `Agent`s `"vx"` / `"vy"` values. For example, an `Agent` with `"vx" = 1` and `"vy" = 0` will be rendered as an arrow pointing to the right.
|
|
4001
|
+
* - Also uses the `"size" value.
|
|
4002
|
+
* - `"rect"` — Draws a rectangle with the upper-left corner at `"x"` / `"y"`.
|
|
4003
|
+
* - Uses the `Agent`'s `"width"` and `"height"` values for the dimensions of the rectangle.
|
|
4004
|
+
* - `"triangle"` — Draws a triangle centered at the `Agent`'s `"x"` / `"y"` values.
|
|
4005
|
+
* - Also uses the `"size"` value.
|
|
4006
|
+
*
|
|
3107
4007
|
* @since 0.0.11
|
|
3108
4008
|
*/
|
|
3109
4009
|
var CanvasRenderer = /** @class */ (function (_super) {
|
|
3110
4010
|
__extends(CanvasRenderer, _super);
|
|
4011
|
+
/**
|
|
4012
|
+
* The first parameter must be the {@linkcode Environment} that this
|
|
4013
|
+
* `CanvasRenderer` will render.
|
|
4014
|
+
*
|
|
4015
|
+
* The second parameter specifies options, which can include:
|
|
4016
|
+
* - `autoPosition` (*boolean* = `false`) — For `Environment`s using a {@linkcode Network}, whether to automatically position the `Agent`s.
|
|
4017
|
+
* - `background` (*string* = `"transparent"`) — The background color to draw before rendering any `Agent`s.
|
|
4018
|
+
* - `connectionColor` (*string* = `"black"`) — For `Environment`s using a `Network`, the color of lines
|
|
4019
|
+
* - `connectionOpacity` (*number* = `1`) — For `Environment`s using a `Network`, the opacity of lines
|
|
4020
|
+
* - `connectionWidth` (*number* = `1`) — For `Environment`s using a `Network`, the width of lines
|
|
4021
|
+
* - `height` (*number* = `500`) — The height, in pixels, of the canvas on which to render
|
|
4022
|
+
* - `origin` (*{ x: number; y: number }* = `{ x: 0, y: 0 }`) — The coordinate of the upper-left point of the space to be rendered
|
|
4023
|
+
* - `scale` (*number* = `1`) — The scale at which to render (the larger the scale, the smaller the size of the space that is actually rendered)
|
|
4024
|
+
* - `trace` (*boolean* = `false`) — If `true`, the renderer will not clear old drawings, causing the `Agent`s to appear to *trace* their paths across space
|
|
4025
|
+
* - `width` (*number* = `500`) — The width, in pixels, of the canvas on which to render
|
|
4026
|
+
*/
|
|
3111
4027
|
function CanvasRenderer(environment, opts) {
|
|
3112
4028
|
var _this = _super.call(this) || this;
|
|
4029
|
+
/** @hidden */
|
|
3113
4030
|
_this.terrainBuffer = document.createElement("canvas");
|
|
3114
4031
|
_this.environment = environment;
|
|
3115
4032
|
environment.renderers.push(_this);
|
|
@@ -3130,14 +4047,17 @@ var CanvasRenderer = /** @class */ (function (_super) {
|
|
|
3130
4047
|
_this.context.fillRect(0, 0, width, height);
|
|
3131
4048
|
return _this;
|
|
3132
4049
|
}
|
|
4050
|
+
/** @hidden */
|
|
3133
4051
|
CanvasRenderer.prototype.x = function (v) {
|
|
3134
4052
|
var _a = this.opts, origin = _a.origin, scale = _a.scale;
|
|
3135
4053
|
return window.devicePixelRatio * scale * (v - origin.x);
|
|
3136
4054
|
};
|
|
4055
|
+
/** @hidden */
|
|
3137
4056
|
CanvasRenderer.prototype.y = function (v) {
|
|
3138
4057
|
var _a = this.opts, origin = _a.origin, scale = _a.scale;
|
|
3139
4058
|
return window.devicePixelRatio * scale * (v - origin.y);
|
|
3140
4059
|
};
|
|
4060
|
+
/** @hidden */
|
|
3141
4061
|
CanvasRenderer.prototype.createCanvas = function () {
|
|
3142
4062
|
var dpr = window.devicePixelRatio;
|
|
3143
4063
|
var _a = this.opts, width = _a.width, height = _a.height;
|
|
@@ -3146,6 +4066,117 @@ var CanvasRenderer = /** @class */ (function (_super) {
|
|
|
3146
4066
|
canvas.height = height * dpr;
|
|
3147
4067
|
return canvas;
|
|
3148
4068
|
};
|
|
4069
|
+
/** @hidden */
|
|
4070
|
+
CanvasRenderer.prototype.drawPath = function (points, dx, dy) {
|
|
4071
|
+
if (dx === void 0) { dx = 0; }
|
|
4072
|
+
if (dy === void 0) { dy = 0; }
|
|
4073
|
+
var bufferContext = this.buffer.getContext("2d");
|
|
4074
|
+
points.forEach(function (_a, i) {
|
|
4075
|
+
var px = _a[0], py = _a[1];
|
|
4076
|
+
if (i === 0) {
|
|
4077
|
+
bufferContext.moveTo(px + dx, py + dy);
|
|
4078
|
+
}
|
|
4079
|
+
else {
|
|
4080
|
+
bufferContext.lineTo(px + dx, py + dy);
|
|
4081
|
+
}
|
|
4082
|
+
});
|
|
4083
|
+
};
|
|
4084
|
+
/** @hidden */
|
|
4085
|
+
CanvasRenderer.prototype.drawPathWrap = function (points) {
|
|
4086
|
+
var _this = this;
|
|
4087
|
+
var _a = this, width = _a.width, height = _a.height;
|
|
4088
|
+
var right = false;
|
|
4089
|
+
var left = false;
|
|
4090
|
+
var lower = false;
|
|
4091
|
+
var upper = false;
|
|
4092
|
+
points.forEach(function (_a) {
|
|
4093
|
+
var px = _a[0], py = _a[1];
|
|
4094
|
+
if (_this.x(px) >= width)
|
|
4095
|
+
right = true;
|
|
4096
|
+
if (_this.x(px) < 0)
|
|
4097
|
+
left = true;
|
|
4098
|
+
if (_this.y(py) >= height)
|
|
4099
|
+
lower = true;
|
|
4100
|
+
if (_this.y(py) < 0)
|
|
4101
|
+
upper = true;
|
|
4102
|
+
});
|
|
4103
|
+
if (right)
|
|
4104
|
+
this.drawPath(points, -width, 0);
|
|
4105
|
+
if (left)
|
|
4106
|
+
this.drawPath(points, width, 0);
|
|
4107
|
+
if (lower && right)
|
|
4108
|
+
this.drawPath(points, -width, -height);
|
|
4109
|
+
if (upper && right)
|
|
4110
|
+
this.drawPath(points, -width, height);
|
|
4111
|
+
if (lower && left)
|
|
4112
|
+
this.drawPath(points, width, -height);
|
|
4113
|
+
if (upper && left)
|
|
4114
|
+
this.drawPath(points, width, height);
|
|
4115
|
+
if (lower)
|
|
4116
|
+
this.drawPath(points, 0, -height);
|
|
4117
|
+
if (upper)
|
|
4118
|
+
this.drawPath(points, 0, height);
|
|
4119
|
+
};
|
|
4120
|
+
/** @hidden */
|
|
4121
|
+
CanvasRenderer.prototype.drawCircle = function (x, y, r) {
|
|
4122
|
+
var bufferContext = this.buffer.getContext("2d");
|
|
4123
|
+
bufferContext.moveTo(this.x(x), this.y(y));
|
|
4124
|
+
bufferContext.arc(this.x(x), this.y(y), r, 0, 2 * Math.PI);
|
|
4125
|
+
};
|
|
4126
|
+
/** @hidden */
|
|
4127
|
+
CanvasRenderer.prototype.drawCircleWrap = function (x, y, size) {
|
|
4128
|
+
var _a = this, width = _a.width, height = _a.height;
|
|
4129
|
+
if (this.x(x + size) >= width) {
|
|
4130
|
+
this.drawCircle(x - width, y, size);
|
|
4131
|
+
if (this.y(y + size) >= height)
|
|
4132
|
+
this.drawCircle(x - width, y - height, size);
|
|
4133
|
+
if (this.y(y - size) < 0)
|
|
4134
|
+
this.drawCircle(x - width, y + height, size);
|
|
4135
|
+
}
|
|
4136
|
+
if (this.x(x - size) < 0) {
|
|
4137
|
+
this.drawCircle(x + width, y, size);
|
|
4138
|
+
if (this.y(y + size) >= height)
|
|
4139
|
+
this.drawCircle(x + width, y - height, size);
|
|
4140
|
+
if (this.y(y - size) < 0)
|
|
4141
|
+
this.drawCircle(x + width, y + height, size);
|
|
4142
|
+
}
|
|
4143
|
+
if (this.y(y + size) > height)
|
|
4144
|
+
this.drawCircle(x, y - height, size);
|
|
4145
|
+
if (this.y(y - size) < 0)
|
|
4146
|
+
this.drawCircle(x, y + height, size);
|
|
4147
|
+
};
|
|
4148
|
+
/**
|
|
4149
|
+
* Draw a rectangle centered at (x, y). Automatically calculates the offset
|
|
4150
|
+
* for both width and height.
|
|
4151
|
+
* @hidden
|
|
4152
|
+
*/
|
|
4153
|
+
CanvasRenderer.prototype.drawRect = function (x, y, width, height) {
|
|
4154
|
+
var bufferContext = this.buffer.getContext("2d");
|
|
4155
|
+
var dpr = window.devicePixelRatio;
|
|
4156
|
+
bufferContext.fillRect(this.x(x) - (width * dpr) / 2, this.y(y) - (height * dpr) / 2, width * dpr, height * dpr);
|
|
4157
|
+
};
|
|
4158
|
+
/** @hidden */
|
|
4159
|
+
CanvasRenderer.prototype.drawRectWrap = function (x, y, w, h) {
|
|
4160
|
+
var _a = this.opts, width = _a.width, height = _a.height;
|
|
4161
|
+
if (this.x(x + w / 2) >= width) {
|
|
4162
|
+
this.drawRect(x - width, y, w, h);
|
|
4163
|
+
if (this.y(y + h / 2) >= height)
|
|
4164
|
+
this.drawRect(x - width, y - height, w, h);
|
|
4165
|
+
if (this.y(y - height / 2) < 0)
|
|
4166
|
+
this.drawRect(x - width, y + height, w, h);
|
|
4167
|
+
}
|
|
4168
|
+
if (this.x(x - w / 2) < 0) {
|
|
4169
|
+
this.drawRect(x + width, y, w, h);
|
|
4170
|
+
if (this.y(y + h / 2) >= height)
|
|
4171
|
+
this.drawRect(x + width, y - height, w, h);
|
|
4172
|
+
if (this.y(y - height / 2) < 0)
|
|
4173
|
+
this.drawRect(x + width, y + height, w, h);
|
|
4174
|
+
}
|
|
4175
|
+
if (this.y(y + h / 2) > height)
|
|
4176
|
+
this.drawRect(x, y - height, w, h);
|
|
4177
|
+
if (this.y(y - height / 2) < 0)
|
|
4178
|
+
this.drawRect(x, y + height, w, h);
|
|
4179
|
+
};
|
|
3149
4180
|
CanvasRenderer.prototype.render = function () {
|
|
3150
4181
|
var _this = this;
|
|
3151
4182
|
var _a = this, buffer = _a.buffer, context = _a.context, environment = _a.environment, width = _a.width, height = _a.height, opts = _a.opts, terrainBuffer = _a.terrainBuffer;
|
|
@@ -3233,28 +4264,36 @@ var CanvasRenderer = /** @class */ (function (_super) {
|
|
|
3233
4264
|
var _vx = 3 * size * (vx / norm) * dpr;
|
|
3234
4265
|
var _vy = 3 * size * (vy / norm) * dpr;
|
|
3235
4266
|
bufferContext.beginPath();
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
4267
|
+
var points = [
|
|
4268
|
+
[_this.x(x) + 1.5 * _vx, _this.y(y) + 1.5 * _vy],
|
|
4269
|
+
[_this.x(x) + _vy / 2, _this.y(y) - _vx / 2],
|
|
4270
|
+
[_this.x(x) - _vy / 2, _this.y(y) + _vx / 2]
|
|
4271
|
+
];
|
|
4272
|
+
_this.drawPath(points);
|
|
4273
|
+
if (environment.opts.torus)
|
|
4274
|
+
_this.drawPathWrap(points);
|
|
3242
4275
|
}
|
|
3243
4276
|
else if (shape === "rect") {
|
|
3244
4277
|
var _h = agent.getData(), _j = _h.width, width_1 = _j === void 0 ? 1 : _j, _k = _h.height, height_1 = _k === void 0 ? 1 : _k;
|
|
3245
|
-
|
|
4278
|
+
_this.drawRect(x, y, width_1, height_1);
|
|
4279
|
+
if (environment.opts.torus)
|
|
4280
|
+
_this.drawRectWrap(x, y, width_1, height_1);
|
|
3246
4281
|
}
|
|
3247
4282
|
else if (shape === "triangle") {
|
|
3248
4283
|
bufferContext.beginPath();
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
4284
|
+
var points = [
|
|
4285
|
+
[_this.x(x), _this.y(y) - size / 2],
|
|
4286
|
+
[_this.x(x) + size / 2, _this.y(y) + size / 2],
|
|
4287
|
+
[_this.x(x) - size / 2, _this.y(y) + size / 2]
|
|
4288
|
+
];
|
|
4289
|
+
_this.drawPath(points);
|
|
4290
|
+
if (environment.opts.torus)
|
|
4291
|
+
_this.drawPathWrap(points);
|
|
3255
4292
|
}
|
|
3256
4293
|
else if (shape === "circle" || shape === undefined) {
|
|
3257
|
-
|
|
4294
|
+
_this.drawCircle(x, y, size * dpr);
|
|
4295
|
+
if (environment.opts.torus)
|
|
4296
|
+
_this.drawCircleWrap(x, y, size);
|
|
3258
4297
|
}
|
|
3259
4298
|
bufferContext.fill();
|
|
3260
4299
|
if (text) {
|
|
@@ -3276,22 +4315,6 @@ var CanvasRenderer = /** @class */ (function (_super) {
|
|
|
3276
4315
|
return CanvasRenderer;
|
|
3277
4316
|
}(AbstractRenderer));
|
|
3278
4317
|
|
|
3279
|
-
/**
|
|
3280
|
-
* Maps a number x, from the given domain aMin --> aMax,
|
|
3281
|
-
* onto the given range bMin --> bMax.
|
|
3282
|
-
* Ex: remap(5, 0, 10, 0, 100) => 50.
|
|
3283
|
-
* @param {number} x
|
|
3284
|
-
* @param {number} aMin
|
|
3285
|
-
* @param {number} aMax
|
|
3286
|
-
* @param {number} bMin
|
|
3287
|
-
* @param {number} bMax
|
|
3288
|
-
* @returns {number} The remapped value.
|
|
3289
|
-
* @since 0.0.5
|
|
3290
|
-
*/
|
|
3291
|
-
function remap(x, aMin, aMax, bMin, bMax) {
|
|
3292
|
-
return bMin + ((bMax - bMin) * (x - aMin)) / (aMax - aMin);
|
|
3293
|
-
}
|
|
3294
|
-
|
|
3295
4318
|
/// <reference path="../types/NRange.d.ts" />
|
|
3296
4319
|
function extractRoundNumbers(range) {
|
|
3297
4320
|
var min = range.min, max = range.max;
|
|
@@ -3603,7 +4626,7 @@ var LineChartRenderer = /** @class */ (function (_super) {
|
|
|
3603
4626
|
if (opts.autoScroll && t >= width) {
|
|
3604
4627
|
x -= t - width;
|
|
3605
4628
|
}
|
|
3606
|
-
else if (opts.autoScale
|
|
4629
|
+
else if (opts.autoScale) {
|
|
3607
4630
|
x *= width / t;
|
|
3608
4631
|
}
|
|
3609
4632
|
return x | 0;
|
|
@@ -3651,7 +4674,7 @@ var LineChartRenderer = /** @class */ (function (_super) {
|
|
|
3651
4674
|
context.restore();
|
|
3652
4675
|
// draw time values for horizontal axis
|
|
3653
4676
|
var min = opts.autoScroll && t >= width ? t - width : 0;
|
|
3654
|
-
var max = opts.autoScale
|
|
4677
|
+
var max = opts.autoScale ? Math.max(t, 5) : width;
|
|
3655
4678
|
var timeRange = { min: min, max: max };
|
|
3656
4679
|
var timeMarkers = extractRoundNumbers(timeRange);
|
|
3657
4680
|
context.save();
|
|
@@ -3731,14 +4754,61 @@ var precision = function (n, d) {
|
|
|
3731
4754
|
};
|
|
3732
4755
|
var escapeStringQuotes = function (s) { return "\"" + s.replace(/"/g, '\\"') + "\""; };
|
|
3733
4756
|
/**
|
|
4757
|
+
* A `TableRenderer` renders an HTML table (for browsers only) or CSV (comma-separated value)
|
|
4758
|
+
* representation of {@linkcode Agent} data.
|
|
4759
|
+
*
|
|
4760
|
+
* ```js
|
|
4761
|
+
* for (let i = 0; i < 3; i++) {
|
|
4762
|
+
* environment.addAgent(new Agent({
|
|
4763
|
+
* x: i * 10,
|
|
4764
|
+
* y: i - 2
|
|
4765
|
+
* }));
|
|
4766
|
+
* }
|
|
4767
|
+
*
|
|
4768
|
+
* const renderer = new TableRenderer(environment);
|
|
4769
|
+
* renderer.columns = ['x', 'y'];
|
|
4770
|
+
* renderer.mount('#container');
|
|
4771
|
+
* environment.tick();
|
|
4772
|
+
* ```
|
|
4773
|
+
*
|
|
4774
|
+
* The `TableRenderer` renders:
|
|
4775
|
+
*
|
|
4776
|
+
* |x |y |
|
|
4777
|
+
* |----|----|
|
|
4778
|
+
* |0 |-2 |
|
|
4779
|
+
* |10 |-1 |
|
|
4780
|
+
* |20 |0 |
|
|
4781
|
+
*
|
|
3734
4782
|
* @since 0.5.0
|
|
3735
4783
|
*/
|
|
3736
4784
|
var TableRenderer = /** @class */ (function (_super) {
|
|
3737
4785
|
__extends(TableRenderer, _super);
|
|
4786
|
+
/**
|
|
4787
|
+
* The first parameter must be the {@linkcode Environment} that this
|
|
4788
|
+
* `TableRenderer` will render.
|
|
4789
|
+
*
|
|
4790
|
+
* The second parameter specifies options, which can include:
|
|
4791
|
+
* - `"type"` (`"csv"` | `"table"` = `"table"`) — Whether to render output in CSV or HTML `<table>` format
|
|
4792
|
+
* - `"filter"` — Include a function (`Agent` => `boolean`) to specify which rows to include in the output. For example, if you only want to include `Agent`s with an x value greater than 100:
|
|
4793
|
+
* ```js
|
|
4794
|
+
* const renderer = new TableRenderer(environment, {
|
|
4795
|
+
* filter: agent => {
|
|
4796
|
+
* return agent.get('x') > 100;
|
|
4797
|
+
* }
|
|
4798
|
+
* });
|
|
4799
|
+
* ```
|
|
4800
|
+
* - `"limit"` (*number* = `Infinity`) — The maximum number of rows (`Agent`s) to render. If using a `filter` function, applies the `limit` *after* filtering.
|
|
4801
|
+
* - `"sortKey"` (*string* = `null`) — Sort the `Agent` data by this key of data
|
|
4802
|
+
* - `"order"` (`"asc"` | `"desc"` = `"desc"`) — When using a `"sortKey"`, specify whether `Agent`s should be listed in *asc*ending or *desc*ending order
|
|
4803
|
+
* - `"precision"` (*number* = `3`) — For floating point values, the number of decimal places to display
|
|
4804
|
+
* - `"refresh"` (*number* = `500`) — The number of milliseconds that should elapse between re-rendering (if this happens too quickly the effect can be visually jarring)
|
|
4805
|
+
*/
|
|
3738
4806
|
function TableRenderer(environment, options) {
|
|
3739
4807
|
if (options === void 0) { options = {}; }
|
|
3740
4808
|
var _this = _super.call(this) || this;
|
|
4809
|
+
/** @hidden */
|
|
3741
4810
|
_this.lastRendered = +new Date();
|
|
4811
|
+
/** @hidden */
|
|
3742
4812
|
_this.opts = Object.assign({}, defaultTableRendererOptions);
|
|
3743
4813
|
_this.environment = environment;
|
|
3744
4814
|
environment.renderers.push(_this);
|
|
@@ -3748,7 +4818,16 @@ var TableRenderer = /** @class */ (function (_super) {
|
|
|
3748
4818
|
}
|
|
3749
4819
|
/**
|
|
3750
4820
|
* Mount this renderer to a DOM element. Pass either a string representing a
|
|
3751
|
-
* CSS selector matching the element
|
|
4821
|
+
* CSS selector matching the element or the element itself.
|
|
4822
|
+
*
|
|
4823
|
+
* ```js
|
|
4824
|
+
* // mounts the renderer to the element with the ID `container`
|
|
4825
|
+
* renderer.mount('#container');
|
|
4826
|
+
*
|
|
4827
|
+
* // mounts the renderer to the element itself
|
|
4828
|
+
* const container = document.getElementById('container');
|
|
4829
|
+
* renderer.mount(container);
|
|
4830
|
+
* ```
|
|
3752
4831
|
* @override
|
|
3753
4832
|
* @param {string | HTMLElement} el
|
|
3754
4833
|
*/
|
|
@@ -3761,6 +4840,7 @@ var TableRenderer = /** @class */ (function (_super) {
|
|
|
3761
4840
|
}
|
|
3762
4841
|
this.table = container;
|
|
3763
4842
|
};
|
|
4843
|
+
/** @hidden */
|
|
3764
4844
|
TableRenderer.prototype.serializeColumns = function (joiner, start, end, escape) {
|
|
3765
4845
|
if (start === void 0) { start = ""; }
|
|
3766
4846
|
if (end === void 0) { end = ""; }
|
|
@@ -3772,6 +4852,7 @@ var TableRenderer = /** @class */ (function (_super) {
|
|
|
3772
4852
|
return "";
|
|
3773
4853
|
return start + columns.join(joiner) + end;
|
|
3774
4854
|
};
|
|
4855
|
+
/** @hidden */
|
|
3775
4856
|
TableRenderer.prototype.serializeRows = function (cellJoiner, rowJoiner, start, end, rowStart, rowEnd, escape) {
|
|
3776
4857
|
var _this = this;
|
|
3777
4858
|
if (start === void 0) { start = ""; }
|
|
@@ -3820,6 +4901,7 @@ var TableRenderer = /** @class */ (function (_super) {
|
|
|
3820
4901
|
.join(rowJoiner) +
|
|
3821
4902
|
end);
|
|
3822
4903
|
};
|
|
4904
|
+
/** @hidden */
|
|
3823
4905
|
TableRenderer.prototype.renderCSV = function () {
|
|
3824
4906
|
var columns = this.serializeColumns(",", "", "", true);
|
|
3825
4907
|
if (columns === "")
|
|
@@ -3829,12 +4911,28 @@ var TableRenderer = /** @class */ (function (_super) {
|
|
|
3829
4911
|
return columns;
|
|
3830
4912
|
return columns + "\n" + rows;
|
|
3831
4913
|
};
|
|
4914
|
+
/** @hidden */
|
|
3832
4915
|
TableRenderer.prototype.renderHTMLTable = function () {
|
|
3833
4916
|
var thead = this.serializeColumns("</td><td>", "<thead><tr><td>", "</td></tr></thead>");
|
|
3834
4917
|
var tbody = this.serializeRows("</td><td>", "", "<tbody>", "</tbody>", "<tr><td>", "</td></tr>");
|
|
3835
4918
|
return "<table>" + thead + tbody + "</table>";
|
|
3836
4919
|
};
|
|
3837
4920
|
/**
|
|
4921
|
+
* Returns the outer HTML of the table or the CSV data as a string. This can be useful for exporting data, particularly in a Node.js environment as opposed to in a browser. For instance, in a Node.js script, you could write the CSV data to a file as follows:
|
|
4922
|
+
*
|
|
4923
|
+
* ```js
|
|
4924
|
+
* const fs = require('fs'); // import the file system module
|
|
4925
|
+
*
|
|
4926
|
+
* const environment = new Environment();
|
|
4927
|
+
* for (let i = 0; i < 3; i++) environment.addAgent(new Agent({ i }));
|
|
4928
|
+
*
|
|
4929
|
+
* const renderer = new TableRenderer(environment, { type: 'csv' });
|
|
4930
|
+
* renderer.columns = ['i'];
|
|
4931
|
+
*
|
|
4932
|
+
* // write the TableRenderer's output to a CSV file named data.csv
|
|
4933
|
+
* fs.writeFileSync('./data.csv', renderer.output());
|
|
4934
|
+
* ```
|
|
4935
|
+
*
|
|
3838
4936
|
* @since 0.5.0
|
|
3839
4937
|
*/
|
|
3840
4938
|
TableRenderer.prototype.output = function () {
|
|
@@ -3860,22 +4958,6 @@ var TableRenderer = /** @class */ (function (_super) {
|
|
|
3860
4958
|
return TableRenderer;
|
|
3861
4959
|
}(AbstractRenderer));
|
|
3862
4960
|
|
|
3863
|
-
/**
|
|
3864
|
-
* Restricts a number x to the range min --> max.
|
|
3865
|
-
* @param {number} x
|
|
3866
|
-
* @param {number} min
|
|
3867
|
-
* @param {number} max
|
|
3868
|
-
* @return {number} The clamped value.
|
|
3869
|
-
* @since 0.0.5
|
|
3870
|
-
*/
|
|
3871
|
-
function clamp(x, min, max) {
|
|
3872
|
-
if (x < min)
|
|
3873
|
-
return min;
|
|
3874
|
-
if (x > max)
|
|
3875
|
-
return max;
|
|
3876
|
-
return x;
|
|
3877
|
-
}
|
|
3878
|
-
|
|
3879
4961
|
var PADDING_AT_BOTTOM$1 = 60;
|
|
3880
4962
|
var PADDING_AT_LEFT$1 = 60;
|
|
3881
4963
|
var isAxisObject = function (obj) {
|
|
@@ -3892,12 +4974,48 @@ var defaultHeatmapOptions = {
|
|
|
3892
4974
|
};
|
|
3893
4975
|
var warnOnce$3 = once(console.warn.bind(console));
|
|
3894
4976
|
/**
|
|
4977
|
+
* A `Heatmap` can be used to visualize the distribution of {@linkcode Agent}s across two metrics.
|
|
4978
|
+
* While {@linkcode Histogram}s are useful for showing the distribution of `Agent`s along a single metric
|
|
4979
|
+
* (or on multiple metrics using the same scale), a `Heatmap` can show how two metrics relate to one another —
|
|
4980
|
+
* correlation, inverse correlation, in a nonlinear manner, randomly (no correlation), etc.
|
|
4981
|
+
*
|
|
4982
|
+
* <img src="https://cms.flocc.network/wp-content/uploads/2020/11/heatmap-basic.png" />
|
|
4983
|
+
*
|
|
4984
|
+
* Note above that, although the output appears similar to what a {@linkcode CanvasRenderer} might output, the `y` axis is reversed here — low values are at the bottom and high at the top, whereas on a `CanvasRenderer` high values are at the bottom and low at the top.
|
|
4985
|
+
*
|
|
3895
4986
|
* @since 0.5.8
|
|
3896
4987
|
*/
|
|
3897
4988
|
var Heatmap = /** @class */ (function (_super) {
|
|
3898
4989
|
__extends(Heatmap, _super);
|
|
4990
|
+
/**
|
|
4991
|
+
* The first parameter must be the {@linkcode Environment} that this
|
|
4992
|
+
* `Heatmap` will render.
|
|
4993
|
+
*
|
|
4994
|
+
* The second parameter specifies options, which can include:
|
|
4995
|
+
* - `from` (*string* = `"white"`) — The color (name, hex value, or RGB) to draw when a cell contains `0` {@linkcode Agent}s
|
|
4996
|
+
* - `to` (*string* = `"black"`) — The color (name, hex value, or RGB) to draw when a cell contains the highest number of `Agent`s
|
|
4997
|
+
* - `x` and `y` can be either:
|
|
4998
|
+
* - *string* = `"x"`/`"y"` respectively — The name of `Agent` data to measure along the `x`/`y` axis
|
|
4999
|
+
* - *{ buckets: number; key: string; min: number; max: number }* = `{ buckets: 10, key: 'x' | 'y', min: 0, max: 1 }` — Include the number of buckets to divide the range `min → max` into, along with the name of `Agent` data
|
|
5000
|
+
* - `width` (*number* = `500`) — The width, in pixels, of the canvas on which to render
|
|
5001
|
+
* - `height` (*number* = `500`) — The height, in pixels, of the canvas on which to render
|
|
5002
|
+
* - `scale` (either `"relative"` or `"fixed"`, defaults to `"relative"`)
|
|
5003
|
+
* - `"relative"` — The maximum number of `Agent`s in any single cell is automatically used as the highest value in the scale. This updates over time based on `Agent` distribution.
|
|
5004
|
+
* - `"fixed"` — You supply the number to use as the maximum value (see `max` below).
|
|
5005
|
+
* - `max` (optional, *number*) — If you use `scale = "fixed"`, then setting a `max` will cause cells with that number (or higher) of `Agent`s to be drawn using the `to` color.
|
|
5006
|
+
*
|
|
5007
|
+
* ```js
|
|
5008
|
+
* // plots the correlation between age of agents (on the x-axis)
|
|
5009
|
+
* // vs. their wealth (on the y-axis)
|
|
5010
|
+
* const heatmap = new Heatmap(environment, {
|
|
5011
|
+
* x: 'age',
|
|
5012
|
+
* y: 'wealth'
|
|
5013
|
+
* });
|
|
5014
|
+
* ```
|
|
5015
|
+
*/
|
|
3899
5016
|
function Heatmap(environment, opts) {
|
|
3900
5017
|
var _this = _super.call(this) || this;
|
|
5018
|
+
/** @hidden */
|
|
3901
5019
|
_this.opts = defaultHeatmapOptions;
|
|
3902
5020
|
_this.environment = environment;
|
|
3903
5021
|
_this.opts = Object.assign({}, _this.opts, opts);
|
|
@@ -3916,7 +5034,7 @@ var Heatmap = /** @class */ (function (_super) {
|
|
|
3916
5034
|
}
|
|
3917
5035
|
/**
|
|
3918
5036
|
* Map a value (on the range x-min to x-max) onto canvas space to draw it along the x-axis.
|
|
3919
|
-
* @
|
|
5037
|
+
* @hidden
|
|
3920
5038
|
*/
|
|
3921
5039
|
Heatmap.prototype.x = function (value) {
|
|
3922
5040
|
var width = this.width;
|
|
@@ -3924,12 +5042,13 @@ var Heatmap = /** @class */ (function (_super) {
|
|
|
3924
5042
|
};
|
|
3925
5043
|
/**
|
|
3926
5044
|
* Map a value (on the range y-min to y-max) onto canvas space to draw it along the y-axis.
|
|
3927
|
-
* @
|
|
5045
|
+
* @hidden
|
|
3928
5046
|
*/
|
|
3929
5047
|
Heatmap.prototype.y = function (value) {
|
|
3930
5048
|
var height = this.height;
|
|
3931
5049
|
return remap(value, this.getMin("y"), this.getMax("y"), height - PADDING_AT_BOTTOM$1, 0);
|
|
3932
5050
|
};
|
|
5051
|
+
/** @hidden */
|
|
3933
5052
|
Heatmap.prototype.getKey = function (axis) {
|
|
3934
5053
|
var a = this.opts[axis];
|
|
3935
5054
|
if (isAxisObject(a)) {
|
|
@@ -3939,12 +5058,14 @@ var Heatmap = /** @class */ (function (_super) {
|
|
|
3939
5058
|
return a;
|
|
3940
5059
|
}
|
|
3941
5060
|
};
|
|
5061
|
+
/** @hidden */
|
|
3942
5062
|
Heatmap.prototype.getBuckets = function (axis) {
|
|
3943
5063
|
var a = this.opts[axis];
|
|
3944
5064
|
if (isAxisObject(a) && a.hasOwnProperty("buckets"))
|
|
3945
5065
|
return a.buckets;
|
|
3946
5066
|
return 10;
|
|
3947
5067
|
};
|
|
5068
|
+
/** @hidden */
|
|
3948
5069
|
Heatmap.prototype.getMin = function (axis) {
|
|
3949
5070
|
var a = this.opts[axis];
|
|
3950
5071
|
if (isAxisObject(a) && a.hasOwnProperty("min")) {
|
|
@@ -3954,6 +5075,7 @@ var Heatmap = /** @class */ (function (_super) {
|
|
|
3954
5075
|
return 0;
|
|
3955
5076
|
}
|
|
3956
5077
|
};
|
|
5078
|
+
/** @hidden */
|
|
3957
5079
|
Heatmap.prototype.getMax = function (axis) {
|
|
3958
5080
|
var a = this.opts[axis];
|
|
3959
5081
|
if (isAxisObject(a) && a.hasOwnProperty("max")) {
|
|
@@ -3963,6 +5085,7 @@ var Heatmap = /** @class */ (function (_super) {
|
|
|
3963
5085
|
return 1;
|
|
3964
5086
|
}
|
|
3965
5087
|
};
|
|
5088
|
+
/** @hidden */
|
|
3966
5089
|
Heatmap.prototype.drawMarkers = function () {
|
|
3967
5090
|
var _a = this, context = _a.context, width = _a.width, height = _a.height;
|
|
3968
5091
|
var _b = this.opts, from = _b.from, to = _b.to;
|
|
@@ -4015,6 +5138,7 @@ var Heatmap = /** @class */ (function (_super) {
|
|
|
4015
5138
|
}
|
|
4016
5139
|
}
|
|
4017
5140
|
};
|
|
5141
|
+
/** @hidden */
|
|
4018
5142
|
Heatmap.prototype.updateScale = function () {
|
|
4019
5143
|
var _a = this, context = _a.context, environment = _a.environment, height = _a.height;
|
|
4020
5144
|
var scale = this.opts.scale;
|
|
@@ -4036,6 +5160,7 @@ var Heatmap = /** @class */ (function (_super) {
|
|
|
4036
5160
|
this.lastUpdatedScale = new Date();
|
|
4037
5161
|
}
|
|
4038
5162
|
};
|
|
5163
|
+
/** @hidden */
|
|
4039
5164
|
Heatmap.prototype.drawRectangles = function () {
|
|
4040
5165
|
var _a = this, canvas = _a.canvas, environment = _a.environment, width = _a.width, height = _a.height;
|
|
4041
5166
|
var _b = this.opts, scale = _b.scale, from = _b.from, to = _b.to;
|
|
@@ -4062,11 +5187,13 @@ var Heatmap = /** @class */ (function (_super) {
|
|
|
4062
5187
|
}
|
|
4063
5188
|
context.globalAlpha = 1;
|
|
4064
5189
|
};
|
|
5190
|
+
/** @hidden */
|
|
4065
5191
|
Heatmap.prototype.resetBuckets = function () {
|
|
4066
5192
|
for (var i = 0; i < this.getBuckets("x") * this.getBuckets("y"); i++) {
|
|
4067
5193
|
this.buckets[i] = 0;
|
|
4068
5194
|
}
|
|
4069
5195
|
};
|
|
5196
|
+
/** @hidden */
|
|
4070
5197
|
Heatmap.prototype.updateBuckets = function () {
|
|
4071
5198
|
var _this = this;
|
|
4072
5199
|
var environment = this.environment;
|
|
@@ -4109,134 +5236,8 @@ var Heatmap = /** @class */ (function (_super) {
|
|
|
4109
5236
|
}(AbstractRenderer));
|
|
4110
5237
|
|
|
4111
5238
|
/**
|
|
4112
|
-
*
|
|
4113
|
-
* returns a value from a normal/Gaussian distribution.
|
|
4114
|
-
* @param {number} mean
|
|
4115
|
-
* @param {number} sd
|
|
4116
|
-
* @returns {number}
|
|
4117
|
-
* @since 0.0.8
|
|
4118
|
-
*/
|
|
4119
|
-
function gaussian(mean, sd) {
|
|
4120
|
-
if (mean === void 0) { mean = 0; }
|
|
4121
|
-
if (sd === void 0) { sd = 1; }
|
|
4122
|
-
var y, x1, x2, w;
|
|
4123
|
-
do {
|
|
4124
|
-
x1 = 2 * uniform() - 1;
|
|
4125
|
-
x2 = 2 * uniform() - 1;
|
|
4126
|
-
w = x1 * x1 + x2 * x2;
|
|
4127
|
-
} while (w >= 1);
|
|
4128
|
-
w = Math.sqrt((-2 * Math.log(w)) / w);
|
|
4129
|
-
y = x1 * w;
|
|
4130
|
-
return y * sd + mean;
|
|
4131
|
-
}
|
|
4132
|
-
|
|
4133
|
-
/// <reference path="../types/Point.d.ts" />
|
|
4134
|
-
/**
|
|
4135
|
-
* Finds the Manhattan distance between `p1` and `p2`.
|
|
4136
|
-
* The inputs may be plain objects
|
|
4137
|
-
* with `x`, `y`, and/or `z` keys, or Agent-like objects who have
|
|
4138
|
-
* `x`, `y`, and/or `z` data.
|
|
4139
|
-
* @param {Point|Agent} p1
|
|
4140
|
-
* @param {Point|Agent} p2
|
|
4141
|
-
* @return {number} The Manhattan distance between p1 and p2.
|
|
4142
|
-
* @since 0.0.12
|
|
4143
|
-
*/
|
|
4144
|
-
function manhattanDistance(p1, p2) {
|
|
4145
|
-
var x1 = (p1 instanceof Agent ? p1.get("x") : p1.x) || 0;
|
|
4146
|
-
var y1 = (p1 instanceof Agent ? p1.get("y") : p1.y) || 0;
|
|
4147
|
-
var z1 = (p1 instanceof Agent ? p1.get("z") : p1.z) || 0;
|
|
4148
|
-
var x2 = (p2 instanceof Agent ? p2.get("x") : p2.x) || 0;
|
|
4149
|
-
var y2 = (p2 instanceof Agent ? p2.get("y") : p2.y) || 0;
|
|
4150
|
-
var z2 = (p2 instanceof Agent ? p2.get("z") : p2.z) || 0;
|
|
4151
|
-
var dx = Math.abs(x2 - x1);
|
|
4152
|
-
var dy = Math.abs(y2 - y1);
|
|
4153
|
-
var dz = Math.abs(z2 - z1);
|
|
4154
|
-
// distance for toroidal environments
|
|
4155
|
-
if (p1 instanceof Agent &&
|
|
4156
|
-
p2 instanceof Agent &&
|
|
4157
|
-
p1.environment &&
|
|
4158
|
-
p2.environment &&
|
|
4159
|
-
p1.environment === p2.environment &&
|
|
4160
|
-
p1.environment.width &&
|
|
4161
|
-
p1.environment.height &&
|
|
4162
|
-
p1.environment.opts.torus) {
|
|
4163
|
-
var environment = p1.environment;
|
|
4164
|
-
var width = environment.width, height = environment.height;
|
|
4165
|
-
if (dx > width / 2)
|
|
4166
|
-
dx = width - dx;
|
|
4167
|
-
if (dy > height / 2)
|
|
4168
|
-
dy = height - dy;
|
|
4169
|
-
}
|
|
4170
|
-
return dx + dy + dz;
|
|
4171
|
-
}
|
|
4172
|
-
|
|
4173
|
-
/**
|
|
4174
|
-
* Seed a pseudo-random number generator with a value.
|
|
4175
|
-
* This can be used to produce predictable pseudo-random numbers.
|
|
4176
|
-
* When calling `utils.random`, `utils.sample`, or other functions
|
|
4177
|
-
* relying on randomness with the same initial seed, the values
|
|
4178
|
-
* generated will always be the same.
|
|
4179
|
-
*
|
|
4180
|
-
* Predictable randomness can be turned off by calling `seed(null)`, or reset
|
|
4181
|
-
* by calling `seed(value)` again with the initial value you used.
|
|
4182
|
-
* @param value
|
|
4183
|
-
* @since 0.5.0
|
|
4184
|
-
*/
|
|
4185
|
-
var seed = function (value) { return PRNG.seed(value); };
|
|
4186
|
-
|
|
4187
|
-
/**
|
|
4188
|
-
* Find the standard deviation of an Array of numbers.
|
|
4189
|
-
* @param {Array<number>} arr
|
|
4190
|
-
* @returns {number}
|
|
4191
|
-
* @since 0.0.16
|
|
4192
|
-
*/
|
|
4193
|
-
function stdDev(arr) {
|
|
4194
|
-
if (arr.length === 0)
|
|
4195
|
-
return null;
|
|
4196
|
-
var ave = mean(arr);
|
|
4197
|
-
return Math.sqrt(mean(arr.map(function (x) { return (x - ave) * (x - ave); })));
|
|
4198
|
-
}
|
|
4199
|
-
|
|
4200
|
-
/**
|
|
4201
|
-
* @since 0.1.4
|
|
5239
|
+
* The current version of the Flocc library.
|
|
4202
5240
|
*/
|
|
4203
|
-
|
|
4204
|
-
if (width === void 0) { width = 0; }
|
|
4205
|
-
var output = str;
|
|
4206
|
-
while (output.length < width)
|
|
4207
|
-
output = "0" + output;
|
|
4208
|
-
return output;
|
|
4209
|
-
}
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
var utils = /*#__PURE__*/Object.freeze({
|
|
4214
|
-
__proto__: null,
|
|
4215
|
-
clamp: clamp,
|
|
4216
|
-
distance: distance,
|
|
4217
|
-
gaussian: gaussian,
|
|
4218
|
-
gcd: gcd,
|
|
4219
|
-
manhattanDistance: manhattanDistance,
|
|
4220
|
-
lerp: lerp,
|
|
4221
|
-
remap: remap,
|
|
4222
|
-
random: random,
|
|
4223
|
-
sample: sample$1,
|
|
4224
|
-
sampler: sampler,
|
|
4225
|
-
seed: seed,
|
|
4226
|
-
series: series,
|
|
4227
|
-
shuffle: shuffle,
|
|
4228
|
-
sum: sum,
|
|
4229
|
-
max: max,
|
|
4230
|
-
mean: mean,
|
|
4231
|
-
median: median,
|
|
4232
|
-
min: min,
|
|
4233
|
-
percentile: percentile,
|
|
4234
|
-
stdDev: stdDev,
|
|
4235
|
-
uniform: uniform,
|
|
4236
|
-
uuid: uuid$1,
|
|
4237
|
-
zfill: zfill
|
|
4238
|
-
});
|
|
4239
|
-
|
|
4240
|
-
var version = "0.5.18";
|
|
5241
|
+
var version = "0.5.21";
|
|
4241
5242
|
|
|
4242
5243
|
export { ASCIIRenderer, Agent, CanvasRenderer, Colors, Environment, GridEnvironment, Heatmap, Histogram, KDTree, LineChartRenderer, Network, NumArray, Rule, TableRenderer, Terrain, version as VERSION, Vector, utils };
|