@antv/layout 2.0.0-beta.0 → 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/dist/index.js +296 -209
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.min.js +2 -2
  4. package/dist/index.min.js.map +1 -1
  5. package/dist/worker.js +1 -1
  6. package/dist/worker.js.map +1 -1
  7. package/lib/algorithm/antv-dagre/index.js +8 -7
  8. package/lib/algorithm/antv-dagre/index.js.map +1 -1
  9. package/lib/algorithm/antv-dagre/types.d.ts +3 -14
  10. package/lib/algorithm/circular/index.js +8 -7
  11. package/lib/algorithm/circular/index.js.map +1 -1
  12. package/lib/algorithm/circular/types.d.ts +0 -16
  13. package/lib/algorithm/combo-combined/index.js +9 -7
  14. package/lib/algorithm/combo-combined/index.js.map +1 -1
  15. package/lib/algorithm/combo-combined/types.d.ts +6 -18
  16. package/lib/algorithm/concentric/index.js +10 -16
  17. package/lib/algorithm/concentric/index.js.map +1 -1
  18. package/lib/algorithm/concentric/types.d.ts +3 -17
  19. package/lib/algorithm/d3-force/index.js +16 -12
  20. package/lib/algorithm/d3-force/index.js.map +1 -1
  21. package/lib/algorithm/d3-force/types.d.ts +10 -24
  22. package/lib/algorithm/d3-force-3d/index.js +1 -1
  23. package/lib/algorithm/d3-force-3d/index.js.map +1 -1
  24. package/lib/algorithm/d3-force-3d/types.d.ts +5 -4
  25. package/lib/algorithm/dagre/index.js +10 -7
  26. package/lib/algorithm/dagre/index.js.map +1 -1
  27. package/lib/algorithm/dagre/types.d.ts +8 -14
  28. package/lib/algorithm/force/index.d.ts +1 -1
  29. package/lib/algorithm/force/index.js +56 -44
  30. package/lib/algorithm/force/index.js.map +1 -1
  31. package/lib/algorithm/force/types.d.ts +39 -36
  32. package/lib/algorithm/force-atlas2/index.d.ts +1 -1
  33. package/lib/algorithm/force-atlas2/index.js +8 -7
  34. package/lib/algorithm/force-atlas2/index.js.map +1 -1
  35. package/lib/algorithm/force-atlas2/types.d.ts +0 -14
  36. package/lib/algorithm/fruchterman/index.d.ts +1 -1
  37. package/lib/algorithm/fruchterman/index.js +8 -10
  38. package/lib/algorithm/fruchterman/index.js.map +1 -1
  39. package/lib/algorithm/fruchterman/simulation.js +2 -1
  40. package/lib/algorithm/fruchterman/simulation.js.map +1 -1
  41. package/lib/algorithm/fruchterman/types.d.ts +2 -1
  42. package/lib/algorithm/grid/index.d.ts +1 -1
  43. package/lib/algorithm/grid/index.js +29 -34
  44. package/lib/algorithm/grid/index.js.map +1 -1
  45. package/lib/algorithm/grid/types.d.ts +5 -24
  46. package/lib/algorithm/mds/index.js +1 -0
  47. package/lib/algorithm/mds/index.js.map +1 -1
  48. package/lib/algorithm/radial/index.js +8 -5
  49. package/lib/algorithm/radial/index.js.map +1 -1
  50. package/lib/algorithm/radial/radial-nonoverlap-force.js +2 -4
  51. package/lib/algorithm/radial/radial-nonoverlap-force.js.map +1 -1
  52. package/lib/algorithm/radial/types.d.ts +3 -16
  53. package/lib/algorithm/random/index.js +1 -0
  54. package/lib/algorithm/random/index.js.map +1 -1
  55. package/lib/algorithm/types.d.ts +16 -0
  56. package/lib/index.d.ts +5 -3
  57. package/lib/index.js +3 -1
  58. package/lib/index.js.map +1 -1
  59. package/lib/node_modules/@antv/expr/dist/index.esm.js +4 -0
  60. package/lib/node_modules/@antv/expr/dist/index.esm.js.map +1 -0
  61. package/lib/types/common.d.ts +17 -1
  62. package/lib/types/data.d.ts +1 -1
  63. package/lib/util/expr.d.ts +12 -0
  64. package/lib/util/expr.js +26 -0
  65. package/lib/util/expr.js.map +1 -0
  66. package/lib/util/format.d.ts +37 -0
  67. package/lib/util/format.js +61 -17
  68. package/lib/util/format.js.map +1 -1
  69. package/lib/util/order.d.ts +3 -4
  70. package/lib/util/order.js.map +1 -1
  71. package/lib/util/size.d.ts +2 -1
  72. package/lib/util/size.js +9 -1
  73. package/lib/util/size.js.map +1 -1
  74. package/lib/worker.js +283 -227
  75. package/lib/worker.js.map +1 -1
  76. package/package.json +2 -1
  77. package/src/algorithm/antv-dagre/index.ts +15 -12
  78. package/src/algorithm/antv-dagre/types.ts +3 -14
  79. package/src/algorithm/circular/index.ts +5 -4
  80. package/src/algorithm/circular/types.ts +0 -15
  81. package/src/algorithm/combo-combined/index.ts +21 -17
  82. package/src/algorithm/combo-combined/types.ts +6 -21
  83. package/src/algorithm/concentric/index.ts +18 -16
  84. package/src/algorithm/concentric/types.ts +2 -16
  85. package/src/algorithm/d3-force/index.ts +25 -18
  86. package/src/algorithm/d3-force/types.ts +9 -22
  87. package/src/algorithm/d3-force-3d/index.ts +1 -1
  88. package/src/algorithm/d3-force-3d/types.ts +5 -0
  89. package/src/algorithm/dagre/index.ts +9 -7
  90. package/src/algorithm/dagre/types.ts +7 -15
  91. package/src/algorithm/force/index.ts +64 -40
  92. package/src/algorithm/force/types.ts +76 -45
  93. package/src/algorithm/force-atlas2/index.ts +13 -15
  94. package/src/algorithm/force-atlas2/types.ts +0 -12
  95. package/src/algorithm/fruchterman/index.ts +7 -15
  96. package/src/algorithm/fruchterman/simulation.ts +2 -2
  97. package/src/algorithm/fruchterman/types.ts +5 -2
  98. package/src/algorithm/grid/index.ts +45 -46
  99. package/src/algorithm/grid/types.ts +6 -35
  100. package/src/algorithm/radial/index.ts +14 -6
  101. package/src/algorithm/radial/radial-nonoverlap-force.ts +11 -6
  102. package/src/algorithm/radial/types.ts +2 -15
  103. package/src/algorithm/types.ts +18 -0
  104. package/src/types/common.ts +22 -0
  105. package/src/types/data.ts +1 -1
  106. package/src/util/expr.ts +26 -0
  107. package/src/util/format.ts +71 -27
  108. package/src/util/index.ts +2 -0
  109. package/src/util/order.ts +3 -9
  110. package/src/util/size.ts +8 -0
package/lib/worker.js CHANGED
@@ -634,21 +634,6 @@ function isEmpty(value) {
634
634
  return true;
635
635
  }
636
636
 
637
- /**
638
- * https://github.com/developit/dlv/blob/master/index.js
639
- * @param obj
640
- * @param key
641
- * @param defaultValue
642
- */
643
- var get$1 = (function (obj, key, defaultValue) {
644
- var p = 0;
645
- var keyArr = isString(key) ? key.split('.') : key;
646
- while (obj && p < keyArr.length) {
647
- obj = obj[keyArr[p++]];
648
- }
649
- return obj === undefined || p < keyArr.length ? defaultValue : obj;
650
- });
651
-
652
637
  var hasOwnProperty = Object.prototype.hasOwnProperty;
653
638
  var pick = (function (object, keys) {
654
639
  if (object === null || !isPlainObject(object)) {
@@ -681,6 +666,156 @@ function applySingleNodeLayout(model, center, dimensions = 2) {
681
666
  }
682
667
  }
683
668
 
669
+ const e={abs:Math.abs,ceil:Math.ceil,floor:Math.floor,max:Math.max,min:Math.min,round:Math.round,sqrt:Math.sqrt,pow:Math.pow};class n extends Error{constructor(e,t,n){super(e),this.position=t,this.token=n,this.name="ExpressionError";}}var r;!function(e){e[e.STRING=0]="STRING",e[e.NUMBER=1]="NUMBER",e[e.BOOLEAN=2]="BOOLEAN",e[e.NULL=3]="NULL",e[e.IDENTIFIER=4]="IDENTIFIER",e[e.OPERATOR=5]="OPERATOR",e[e.FUNCTION=6]="FUNCTION",e[e.DOT=7]="DOT",e[e.BRACKET_LEFT=8]="BRACKET_LEFT",e[e.BRACKET_RIGHT=9]="BRACKET_RIGHT",e[e.PAREN_LEFT=10]="PAREN_LEFT",e[e.PAREN_RIGHT=11]="PAREN_RIGHT",e[e.COMMA=12]="COMMA",e[e.QUESTION=13]="QUESTION",e[e.COLON=14]="COLON",e[e.DOLLAR=15]="DOLLAR";}(r||(r={}));const o=new Set([32,9,10,13]),a$2=new Set([43,45,42,47,37,33,38,124,61,60,62]),s=new Map([["true",r.BOOLEAN],["false",r.BOOLEAN],["null",r.NULL]]),i=new Map([["===",true],["!==",true],["<=",true],[">=",true],["&&",true],["||",true],["+",true],["-",true],["*",true],["/",true],["%",true],["!",true],["<",true],[">",true]]),u=new Map([[46,r.DOT],[91,r.BRACKET_LEFT],[93,r.BRACKET_RIGHT],[40,r.PAREN_LEFT],[41,r.PAREN_RIGHT],[44,r.COMMA],[63,r.QUESTION],[58,r.COLON],[36,r.DOLLAR]]),c$2=new Map;for(const[e,t]of u.entries())c$2.set(e,{type:t,value:String.fromCharCode(e)});function p(e){return e>=48&&e<=57}function l(e){return e>=97&&e<=122||e>=65&&e<=90||95===e}function f(e){return l(e)||p(e)}function E(e){return a$2.has(e)}var h;!function(e){e[e.Program=0]="Program",e[e.Literal=1]="Literal",e[e.Identifier=2]="Identifier",e[e.MemberExpression=3]="MemberExpression",e[e.CallExpression=4]="CallExpression",e[e.BinaryExpression=5]="BinaryExpression",e[e.UnaryExpression=6]="UnaryExpression",e[e.ConditionalExpression=7]="ConditionalExpression";}(h||(h={}));const d=new Map([["||",2],["&&",3],["===",4],["!==",4],[">",5],[">=",5],["<",5],["<=",5],["+",6],["-",6],["*",7],["/",7],["%",7],["!",8]]),R={type:h.Literal,value:null},T={type:h.Literal,value:true},w={type:h.Literal,value:false},y$4=e=>{let t=0;const o=e.length,a=()=>t>=o?null:e[t],s=()=>e[t++],i=e=>{const t=a();return null!==t&&t.type===e},u=e=>e.type===r.OPERATOR?d.get(e.value)||-1:e.type===r.DOT||e.type===r.BRACKET_LEFT?9:e.type===r.QUESTION?1:-1,c=e=>{let o,u;if(s().type===r.DOT){if(!i(r.IDENTIFIER)){const e=a();throw new n("Expected property name",t,e?e.value:"<end of input>")}const e=s();o={type:h.Identifier,name:e.value},u=false;}else {if(o=l(0),!i(r.BRACKET_RIGHT)){const e=a();throw new n("Expected closing bracket",t,e?e.value:"<end of input>")}s(),u=true;}return {type:h.MemberExpression,object:e,property:o,computed:u}},p=()=>{const e=a();if(!e)throw new n("Unexpected end of input",t,"<end of input>");if(e.type===r.OPERATOR&&("!"===e.value||"-"===e.value)){s();const t=p();return {type:h.UnaryExpression,operator:e.value,argument:t,prefix:true}}switch(e.type){case r.NUMBER:return s(),{type:h.Literal,value:Number(e.value)};case r.STRING:return s(),{type:h.Literal,value:e.value};case r.BOOLEAN:return s(),"true"===e.value?T:w;case r.NULL:return s(),R;case r.IDENTIFIER:return s(),{type:h.Identifier,name:e.value};case r.FUNCTION:return (()=>{const e=s(),o=[];if(!i(r.PAREN_LEFT)){const e=a();throw new n("Expected opening parenthesis after function name",t,e?e.value:"<end of input>")}for(s();;){if(i(r.PAREN_RIGHT)){s();break}if(!a()){const e=a();throw new n("Expected closing parenthesis",t,e?e.value:"<end of input>")}if(o.length>0){if(!i(r.COMMA)){const e=a();throw new n("Expected comma between function arguments",t,e?e.value:"<end of input>")}s();}const e=l(0);o.push(e);}return {type:h.CallExpression,callee:{type:h.Identifier,name:e.value},arguments:o}})();case r.PAREN_LEFT:{s();const e=l(0);if(!i(r.PAREN_RIGHT)){const e=a();throw new n("Expected closing parenthesis",t,e?e.value:"<end of input>")}return s(),e}default:throw new n(`Unexpected token: ${e.type}`,t,e.value)}},l=(f=0)=>{let E=p();for(;t<o;){const o=e[t],p=u(o);if(p<=f)break;if(o.type!==r.QUESTION)if(o.type!==r.OPERATOR){if(o.type!==r.DOT&&o.type!==r.BRACKET_LEFT)break;E=c(E);}else {s();const e=l(p);E={type:h.BinaryExpression,operator:o.value,left:E,right:e};}else {s();const e=l(0);if(!i(r.COLON)){const e=a();throw new n("Expected : in conditional expression",t,e?e.value:"<end of input>")}s();const o=l(0);E={type:h.ConditionalExpression,test:E,consequent:e,alternate:o};}}return E},f=l();return {type:h.Program,body:f}},O=(e,t,r)=>{let o=t;r&&(o={...t,context:{...t.context,...r}});const a=e=>{switch(e.type){case h.Literal:return (e=>e.value)(e);case h.Identifier:return (e=>{if(!(e.name in o.context))throw new n(`Undefined variable: ${e.name}`);return o.context[e.name]})(e);case h.MemberExpression:return (e=>{const t=a(e.object);if(null==t)throw new n("Cannot access property of null or undefined");return t[e.computed?a(e.property):e.property.name]})(e);case h.CallExpression:return (e=>{const t=o.functions[e.callee.name];if(!t)throw new n(`Undefined function: ${e.callee.name}`);return t(...e.arguments.map((e=>a(e))))})(e);case h.BinaryExpression:return (e=>{if("&&"===e.operator){const t=a(e.left);return t?a(e.right):t}if("||"===e.operator){return a(e.left)||a(e.right)}const t=a(e.left),r=a(e.right);switch(e.operator){case "+":return t+r;case "-":return t-r;case "*":return t*r;case "/":return t/r;case "%":return t%r;case "===":return t===r;case "!==":return t!==r;case ">":return t>r;case ">=":return t>=r;case "<":return t<r;case "<=":return t<=r;default:throw new n(`Unknown operator: ${e.operator}`)}})(e);case h.UnaryExpression:return (e=>{const t=a(e.argument);if(e.prefix)switch(e.operator){case "!":return !t;case "-":if("number"!=typeof t)throw new n(`Cannot apply unary - to non-number: ${t}`);return -t;default:throw new n(`Unknown operator: ${e.operator}`)}throw new n(`Postfix operators are not supported: ${e.operator}`)})(e);case h.ConditionalExpression:return (e=>{const t=a(e.test);return a(t?e.consequent:e.alternate)})(e);default:throw new n(`Evaluation error: Unsupported node type: ${e.type}`)}};return a(e.body)};function A(t){const a=(e=>{const t=e,a=t.length,u=new Array(Math.ceil(a/3));let h=0,d=0;function R(e){const o=d+1;d++;let s="",i=false;for(;d<a;){const n=t.charCodeAt(d);if(n===e)return i||(s=t.substring(o,d)),d++,{type:r.STRING,value:s};92===n?(i||(s=t.substring(o,d),i=true),d++,s+=t[d]):i&&(s+=t[d]),d++;}throw new n(`Unterminated string starting with ${String.fromCharCode(e)}`,d,t.substring(Math.max(0,d-10),d))}function T(){const e=d;for(45===t.charCodeAt(d)&&d++;d<a&&p(t.charCodeAt(d));)d++;if(d<a&&46===t.charCodeAt(d))for(d++;d<a&&p(t.charCodeAt(d));)d++;const n=t.slice(e,d);return {type:r.NUMBER,value:n}}function w(){d++;const e=d;if(d<a&&l(t.charCodeAt(d)))for(d++;d<a&&f(t.charCodeAt(d));)d++;const n=t.slice(e,d);return {type:r.FUNCTION,value:n}}function y(){const e=d++;for(;d<a&&f(t.charCodeAt(d));)d++;const n=t.slice(e,d),o=s.get(n);return o?{type:o,value:n}:{type:r.IDENTIFIER,value:n}}function O(){if(d+2<a){const e=t.substring(d,d+3);if(i.has(e))return d+=3,{type:r.OPERATOR,value:e}}if(d+1<a){const e=t.substring(d,d+2);if(i.has(e))return d+=2,{type:r.OPERATOR,value:e}}const e=t[d];if(i.has(e))return d++,{type:r.OPERATOR,value:e};throw new n(`Unknown operator at position ${d}: ${t.substring(d,d+1)}`,d,t.substring(Math.max(0,d-10),d))}for(;d<a;){const e=t.charCodeAt(d);if(A=e,o.has(A)){d++;continue}const r=c$2.get(e);if(r)u[h++]=r,d++;else if(34!==e&&39!==e)if(p(e)||45===e&&d+1<a&&p(t.charCodeAt(d+1)))u[h++]=T();else if(64!==e)if(l(e))u[h++]=y();else {if(!E(e))throw new n(`Unexpected character: ${t[d]}`,d,t.substring(Math.max(0,d-10),d));u[h++]=O();}else u[h++]=w();else u[h++]=R(e);}var A;return h===u.length?u:u.slice(0,h)})(t),u=y$4(a),h=((e={},t={})=>({context:e,functions:t}))({},e);return (e={})=>O(u,h,e)}function N(e,t={}){return A(e)(t)}
670
+
671
+ /**
672
+ * Evaluate an expression if (and only if) it's a valid string expression.
673
+ * - Returns `undefined` when `expression` is not a string, empty, or invalid.
674
+ *
675
+ * @example
676
+ * evaluateExpression('x + y', { x: 10, y: 20 }) // 30
677
+ */
678
+ function evaluateExpression(expression, context) {
679
+ if (typeof expression !== 'string')
680
+ return undefined;
681
+ const source = expression.trim();
682
+ if (!source)
683
+ return undefined;
684
+ try {
685
+ A(source);
686
+ return N(source, context);
687
+ }
688
+ catch (_a) {
689
+ return undefined;
690
+ }
691
+ }
692
+
693
+ function parseSize(size) {
694
+ if (!size)
695
+ return [0, 0, 0];
696
+ if (isNumber(size))
697
+ return [size, size, size];
698
+ else if (Array.isArray(size) && size.length === 0)
699
+ return [0, 0, 0];
700
+ const [x, y = x, z = x] = size;
701
+ return [x, y, z];
702
+ }
703
+ function isSize(value) {
704
+ if (isNumber(value))
705
+ return true;
706
+ if (Array.isArray(value)) {
707
+ return value.every((item) => isNumber(item));
708
+ }
709
+ return false;
710
+ }
711
+
712
+ /**
713
+ * Format a value into a callable function when it is a string expression.
714
+ * - `string` => `(context) => evaluateExpression(string, context)`
715
+ * - `function` => returned as-is
716
+ * - other => returned as-is
717
+ */
718
+ function formatFn(value, argNames) {
719
+ if (typeof value === 'function')
720
+ return value;
721
+ if (typeof value === 'string') {
722
+ const expr = value;
723
+ return (...argv) => {
724
+ const ctx = {};
725
+ for (let i = 0; i < argNames.length; i++) {
726
+ ctx[argNames[i]] = argv[i];
727
+ }
728
+ return evaluateExpression(expr, ctx);
729
+ };
730
+ }
731
+ return () => value;
732
+ }
733
+ /**
734
+ * Format value with multiple types into a function that returns a number
735
+ * @param value The value to be formatted
736
+ * @param defaultValue The default value when value is invalid
737
+ * @returns A function that returns a number
738
+ */
739
+ function formatNumberFn(value, defaultValue, type = 'node') {
740
+ // If value is undefined, return default value function
741
+ if (isNil(value)) {
742
+ return () => defaultValue;
743
+ }
744
+ // If value is an expression, return a function that evaluates the expression
745
+ if (isString(value)) {
746
+ const numberFn = formatFn(value, [type]);
747
+ return (d) => {
748
+ const evaluated = numberFn(d);
749
+ if (isNumber(evaluated))
750
+ return evaluated;
751
+ return defaultValue;
752
+ };
753
+ }
754
+ // If value is a function, return it directly
755
+ if (isFunction(value)) {
756
+ return value;
757
+ }
758
+ // If value is a number, return a function that returns this number
759
+ if (isNumber(value)) {
760
+ return () => value;
761
+ }
762
+ // For other cases (undefined or invalid values), return default value function
763
+ return () => defaultValue;
764
+ }
765
+ /**
766
+ * Format size config with multiple types into a function that returns a size
767
+ * @param value The value to be formatted
768
+ * @param defaultValue The default value when value is invalid
769
+ * @param resultIsNumber Whether to return a number (max of width/height) or size array
770
+ * @returns A function that returns a size
771
+ */
772
+ function formatSizeFn(value, defaultValue = 10, type = 'node') {
773
+ // If value is undefined, return default value function
774
+ if (isNil(value)) {
775
+ return () => defaultValue;
776
+ }
777
+ // If value is an expression, return a function that evaluates the expression
778
+ if (isString(value)) {
779
+ const sizeFn = formatFn(value, [type]);
780
+ return (d) => {
781
+ const evaluated = sizeFn(d);
782
+ if (isSize(evaluated))
783
+ return evaluated;
784
+ return defaultValue;
785
+ };
786
+ }
787
+ // If value is a function, return it directly
788
+ if (isFunction(value)) {
789
+ return value;
790
+ }
791
+ // If value is a number, return a function that returns this number
792
+ if (isNumber(value)) {
793
+ return () => value;
794
+ }
795
+ // If value is an array, return max or the array itself
796
+ if (Array.isArray(value)) {
797
+ return () => value;
798
+ }
799
+ return () => defaultValue;
800
+ }
801
+ /**
802
+ * Format nodeSize and nodeSpacing into a function that returns the total size
803
+ * @param nodeSize The size of the node
804
+ * @param nodeSpacing The spacing around the node
805
+ * @param defaultNodeSize The default node size when value is invalid
806
+ * @param defaultNodeSpacing The default node spacing when value is invalid
807
+ * @returns A function that returns the total size (node size + spacing)
808
+ */
809
+ const formatNodeSizeFn = (nodeSize, nodeSpacing, defaultNodeSize = 10, defaultNodeSpacing = 0) => {
810
+ const nodeSpacingFunc = formatSizeFn(nodeSpacing, defaultNodeSpacing);
811
+ const nodeSizeFunc = formatSizeFn(nodeSize, defaultNodeSize);
812
+ return (d) => {
813
+ const [sizeW, sizeH, sizeD] = parseSize(nodeSizeFunc(d));
814
+ const [spacingW, spacingH, spacingD] = parseSize(nodeSpacingFunc(d));
815
+ return [sizeW + spacingW, sizeH + spacingH, sizeD + spacingD];
816
+ };
817
+ };
818
+
684
819
  /**
685
820
  * Get the adjacency list of the graph model.
686
821
  */
@@ -816,14 +951,6 @@ class MinHeap {
816
951
  }
817
952
  }
818
953
 
819
- /**
820
- * Get nested property value
821
- * For example: getNestedValue(obj, 'a.b.c') will return obj.a.b.c
822
- */
823
- function getNestedValue(obj, path) {
824
- const keys = String(path).split('.');
825
- return get$1(obj, keys);
826
- }
827
954
  /**
828
955
  * Merge objects, but undefined values in source objects will not override existing values
829
956
  * @param target - The target object
@@ -960,17 +1087,6 @@ function parsePoint(point) {
960
1087
  return [point.x, point.y, (_a = point.z) !== null && _a !== void 0 ? _a : 0];
961
1088
  }
962
1089
 
963
- function parseSize(size) {
964
- if (!size)
965
- return [0, 0, 0];
966
- if (isNumber(size))
967
- return [size, size, size];
968
- else if (Array.isArray(size) && size.length === 0)
969
- return [0, 0, 0];
970
- const [x, y = x, z = x] = size;
971
- return [x, y, z];
972
- }
973
-
974
1090
  /**
975
1091
  * Viewport configuration such as width, height and center point.
976
1092
  */
@@ -986,71 +1102,6 @@ const normalizeViewport = (options) => {
986
1102
  };
987
1103
  };
988
1104
 
989
- /**
990
- * Format value with multiple types into a function that returns a number
991
- * @param value The value to be formatted
992
- * @param defaultValue The default value when value is invalid
993
- * @returns A function that returns a number
994
- */
995
- function formatNumberFn(value, defaultValue) {
996
- // If value is a function, return it directly
997
- if (isFunction(value)) {
998
- return value;
999
- }
1000
- // If value is a number, return a function that returns this number
1001
- if (isNumber(value)) {
1002
- return () => value;
1003
- }
1004
- // For other cases (undefined or invalid values), return default value function
1005
- return () => defaultValue;
1006
- }
1007
- /**
1008
- * Format size config with multiple types into a function that returns a size
1009
- * @param value The value to be formatted
1010
- * @param defaultValue The default value when value is invalid
1011
- * @param resultIsNumber Whether to return a number (max of width/height) or size array
1012
- * @returns A function that returns a size
1013
- */
1014
- function formatSizeFn(value, defaultValue = 10) {
1015
- // If value is undefined, return default value function
1016
- if (!value) {
1017
- return () => defaultValue;
1018
- }
1019
- // If value is a function, return it directly
1020
- if (isFunction(value)) {
1021
- return value;
1022
- }
1023
- // If value is a number, return a function that returns this number
1024
- if (isNumber(value)) {
1025
- return () => value;
1026
- }
1027
- // If value is an array, return max or the array itself
1028
- if (Array.isArray(value)) {
1029
- return () => value;
1030
- }
1031
- // If value is an object with width and height
1032
- if (isObject(value) && value.width && value.height) {
1033
- return () => [value.width, value.height];
1034
- }
1035
- return () => defaultValue;
1036
- }
1037
- /**
1038
- * Format nodeSize and nodeSpacing into a function that returns the total size
1039
- * @param nodeSize The size of the node
1040
- * @param nodeSpacing The spacing around the node
1041
- * @param defaultNodeSize The default node size when value is invalid
1042
- * @returns A function that returns the total size (node size + spacing)
1043
- */
1044
- const formatNodeSizeFn = (nodeSize, nodeSpacing, defaultNodeSize = 10) => {
1045
- const nodeSpacingFunc = formatNumberFn(nodeSpacing, 0);
1046
- const nodeSizeFunc = formatSizeFn(nodeSize, defaultNodeSize);
1047
- return (node) => {
1048
- const size = nodeSizeFunc(node);
1049
- const spacing = nodeSpacingFunc(node);
1050
- return Math.max(...parseSize(size)) + spacing;
1051
- };
1052
- };
1053
-
1054
1105
  class GraphLib {
1055
1106
  constructor(data, options = {}) {
1056
1107
  this.edgeIdCounter = new Map();
@@ -4911,6 +4962,7 @@ const canonicalize = (attrs = {}) => {
4911
4962
 
4912
4963
  const DEFAULTS_LAYOUT_OPTIONS$8 = {
4913
4964
  nodeSize: 10,
4965
+ nodeSpacing: 0,
4914
4966
  rankdir: 'TB',
4915
4967
  nodesep: 50,
4916
4968
  ranksep: 50,
@@ -4935,27 +4987,27 @@ class AntVDagreLayout extends BaseLayout {
4935
4987
  }
4936
4988
  layout(options) {
4937
4989
  return __awaiter(this, void 0, void 0, function* () {
4938
- const { nodeSize, align, rankdir = 'TB', ranksep, nodesep, edgeLabelSpace, ranker = 'tight-tree', nodeOrder, begin, controlPoints, radial, sortByCombo,
4990
+ const { nodeSize, nodeSpacing, align, rankdir = 'TB', ranksep, nodesep, edgeLabelSpace, ranker = 'tight-tree', nodeOrder, begin, controlPoints, radial, sortByCombo,
4939
4991
  // focusNode,
4940
4992
  preset, ranksepFunc, nodesepFunc, } = options;
4941
- const ranksepfunc = formatNumberFn(ranksepFunc, ranksep !== null && ranksep !== void 0 ? ranksep : 50);
4942
- const nodesepfunc = formatNumberFn(nodesepFunc, nodesep !== null && nodesep !== void 0 ? nodesep : 50);
4993
+ const ranksepfunc = formatNumberFn(ranksepFunc, ranksep !== null && ranksep !== void 0 ? ranksep : 50, 'node');
4994
+ const nodesepfunc = formatNumberFn(nodesepFunc, nodesep !== null && nodesep !== void 0 ? nodesep : 50, 'node');
4943
4995
  let horisep = nodesepfunc;
4944
4996
  let vertisep = ranksepfunc;
4945
4997
  if (rankdir === 'LR' || rankdir === 'RL') {
4946
4998
  horisep = ranksepfunc;
4947
4999
  vertisep = nodesepfunc;
4948
5000
  }
4949
- const nodeSizeFunc = formatSizeFn(nodeSize, DEFAULTS_LAYOUT_OPTIONS$8.nodeSize);
4950
5001
  // Create internal graph
4951
5002
  const g = new DagreGraph({ tree: [] });
4952
5003
  // copy graph to g
4953
5004
  const nodes = this.model.nodes();
4954
5005
  const edges = this.model.edges();
5006
+ const sizeFn = formatNodeSizeFn(nodeSize, nodeSpacing, DEFAULTS_LAYOUT_OPTIONS$8.nodeSize, DEFAULTS_LAYOUT_OPTIONS$8.nodeSpacing);
4955
5007
  nodes.forEach((node) => {
4956
5008
  var _a;
4957
5009
  const raw = node._original;
4958
- const size = parseSize(nodeSizeFunc(raw));
5010
+ const size = sizeFn(raw);
4959
5011
  const verti = vertisep(raw);
4960
5012
  const hori = horisep(raw);
4961
5013
  const width = size[0] + 2 * hori;
@@ -5237,7 +5289,7 @@ const getControlPoints = (points, sourceNode, targetNode, layerCoordsArr, isHori
5237
5289
  return controlPoints;
5238
5290
  };
5239
5291
 
5240
- const DEFAULT_LAYOUT_OPTIONS = {
5292
+ const DEFAULT_LAYOUT_OPTIONS$1 = {
5241
5293
  radius: null,
5242
5294
  startRadius: null,
5243
5295
  endRadius: null,
@@ -5248,6 +5300,7 @@ const DEFAULT_LAYOUT_OPTIONS = {
5248
5300
  ordering: null,
5249
5301
  angleRatio: 1,
5250
5302
  nodeSize: 10,
5303
+ nodeSpacing: 0,
5251
5304
  };
5252
5305
  /**
5253
5306
  * <zh/> 环形布局
@@ -5260,7 +5313,7 @@ class CircularLayout extends BaseLayout {
5260
5313
  this.id = 'circular';
5261
5314
  }
5262
5315
  getDefaultOptions() {
5263
- return DEFAULT_LAYOUT_OPTIONS;
5316
+ return DEFAULT_LAYOUT_OPTIONS$1;
5264
5317
  }
5265
5318
  layout() {
5266
5319
  return __awaiter(this, void 0, void 0, function* () {
@@ -5286,11 +5339,11 @@ class CircularLayout extends BaseLayout {
5286
5339
  }
5287
5340
  let { radius, startRadius, endRadius } = this.options;
5288
5341
  const nodes = this.model.nodes();
5289
- const format = formatNodeSizeFn(nodeSize, nodeSpacing, DEFAULT_LAYOUT_OPTIONS.nodeSize);
5290
- if (!isNil(nodeSpacing)) {
5342
+ const sizeFn = formatNodeSizeFn(nodeSize, nodeSpacing, DEFAULT_LAYOUT_OPTIONS$1.nodeSize, DEFAULT_LAYOUT_OPTIONS$1.nodeSpacing);
5343
+ if (nodeSpacing) {
5291
5344
  let perimeter = 0;
5292
5345
  for (const node of nodes) {
5293
- perimeter += format(node._original);
5346
+ perimeter += Math.max(...sizeFn(node._original));
5294
5347
  }
5295
5348
  radius = perimeter / (2 * Math.PI);
5296
5349
  }
@@ -5367,17 +5420,10 @@ class ConcentricLayout extends BaseLayout {
5367
5420
  applySingleNodeLayout(this.model, center);
5368
5421
  return;
5369
5422
  }
5370
- const { sortBy: propsSortBy, maxLevelDiff: propsMaxLevelDiff, sweep: propsSweep, clockwise, equidistant, preventOverlap, startAngle = DEFAULTS_LAYOUT_OPTIONS$7.startAngle, nodeSize = DEFAULTS_LAYOUT_OPTIONS$7.nodeSize, nodeSpacing, } = this.options;
5371
- let sortBy = propsSortBy;
5372
- if (propsSortBy && typeof propsSortBy === 'function') {
5373
- const testNode = this.model.firstNode();
5374
- const testValue = propsSortBy(testNode._original);
5375
- if (typeof testValue !== 'number')
5376
- sortBy = 'degree';
5377
- }
5378
- else {
5379
- sortBy = 'degree';
5380
- }
5423
+ const { sortBy: propsSortBy, maxLevelDiff: propsMaxLevelDiff, sweep: propsSweep, clockwise, equidistant, preventOverlap, startAngle = DEFAULTS_LAYOUT_OPTIONS$7.startAngle, nodeSize, nodeSpacing, } = this.options;
5424
+ const sortBy = !propsSortBy || propsSortBy === 'degree'
5425
+ ? 'degree'
5426
+ : formatFn(propsSortBy, ['node']);
5381
5427
  if (sortBy === 'degree') {
5382
5428
  orderByDegree(this.model);
5383
5429
  }
@@ -5394,15 +5440,15 @@ class ConcentricLayout extends BaseLayout {
5394
5440
  for (const node of nodes) {
5395
5441
  const v = sortBy === 'degree'
5396
5442
  ? this.model.degree(node.id)
5397
- : sortBy === null || sortBy === void 0 ? void 0 : sortBy(node._original);
5443
+ : sortBy(node._original);
5398
5444
  sortKeys.set(node.id, v);
5399
5445
  }
5400
5446
  const maxValueNode = this.model.firstNode();
5401
5447
  const maxLevelDiff = propsMaxLevelDiff || sortKeys.get(maxValueNode.id) / 4;
5402
- const nodeSizeFn = formatNodeSizeFn(nodeSize, nodeSpacing);
5448
+ const sizeFn = formatNodeSizeFn(nodeSize, nodeSpacing, DEFAULTS_LAYOUT_OPTIONS$7.nodeSize, DEFAULTS_LAYOUT_OPTIONS$7.nodeSpacing);
5403
5449
  const nodeDistances = new Map();
5404
5450
  for (const node of nodes) {
5405
- nodeDistances.set(node.id, nodeSizeFn(node._original));
5451
+ nodeDistances.set(node.id, Math.max(...sizeFn(node._original)));
5406
5452
  }
5407
5453
  // put the values into levels
5408
5454
  const levels = [{ nodes: [] }];
@@ -7128,9 +7174,7 @@ function forceInABox() {
7128
7174
  }
7129
7175
 
7130
7176
  const DEFAULTS_LAYOUT_OPTIONS$6 = {
7131
- link: {
7132
- id: (d) => String(d.id),
7133
- },
7177
+ edgeId: 'edge.id',
7134
7178
  manyBody: {
7135
7179
  strength: -30,
7136
7180
  },
@@ -7385,7 +7429,9 @@ class D3ForceLayout extends BaseLayoutWithIterations {
7385
7429
  if (options.manyBody === false)
7386
7430
  return undefined;
7387
7431
  return assignDefined({}, options.manyBody || {}, {
7388
- strength: options.nodeStrength,
7432
+ strength: options.nodeStrength
7433
+ ? formatFn(options.nodeStrength, ['node'])
7434
+ : undefined,
7389
7435
  distanceMin: options.distanceMin,
7390
7436
  distanceMax: options.distanceMax,
7391
7437
  theta: options.theta,
@@ -7418,9 +7464,13 @@ class D3ForceLayout extends BaseLayoutWithIterations {
7418
7464
  if (options.link === false)
7419
7465
  return undefined;
7420
7466
  return assignDefined({}, options.link || {}, {
7421
- id: options.edgeId,
7422
- distance: options.linkDistance,
7423
- strength: options.edgeStrength,
7467
+ id: options.edgeId ? formatFn(options.edgeId, ['edge']) : undefined,
7468
+ distance: options.linkDistance
7469
+ ? formatFn(options.linkDistance, ['edge'])
7470
+ : undefined,
7471
+ strength: options.edgeStrength
7472
+ ? formatFn(options.edgeStrength, ['edge'])
7473
+ : undefined,
7424
7474
  iterations: options.edgeIterations,
7425
7475
  });
7426
7476
  }
@@ -7452,9 +7502,8 @@ class D3ForceLayout extends BaseLayoutWithIterations {
7452
7502
  if (options.preventOverlap === false &&
7453
7503
  (options.collide === false || options.collide === undefined))
7454
7504
  return undefined;
7455
- const radius = options.nodeSize || options.nodeSpacing
7456
- ? (d) => formatNodeSizeFn(options.nodeSize, options.nodeSpacing)(d._original) / 2
7457
- : undefined;
7505
+ const sizeFn = formatNodeSizeFn(options.nodeSize, options.nodeSpacing, DEFAULTS_LAYOUT_OPTIONS$6.nodeSize, DEFAULTS_LAYOUT_OPTIONS$6.nodeSpacing);
7506
+ const radius = (d) => Math.max(...sizeFn(d._original)) / 2;
7458
7507
  return assignDefined({}, options.collide || {}, {
7459
7508
  radius: (options.collide && options.collide.radius) || radius,
7460
7509
  strength: options.collideStrength,
@@ -7595,7 +7644,7 @@ class D3ForceLayout extends BaseLayoutWithIterations {
7595
7644
  ['centerY', center && center.y],
7596
7645
  ['template', 'force'],
7597
7646
  ['strength', clusterFociStrength],
7598
- ['groupBy', clusterBy],
7647
+ ['groupBy', clusterBy ? formatFn(clusterBy, ['node']) : undefined],
7599
7648
  ['nodes', this.model.nodes()],
7600
7649
  ['links', this.model.edges()],
7601
7650
  ['forceLinkDistance', clusterEdgeDistance],
@@ -9327,7 +9376,7 @@ class D3Force3DLayout extends D3ForceLayout {
9327
9376
  return {
9328
9377
  numDimensions: 3,
9329
9378
  link: {
9330
- id: (edge) => String(edge.id),
9379
+ id: (edge) => edge.id,
9331
9380
  },
9332
9381
  manyBody: {},
9333
9382
  center: {
@@ -23108,11 +23157,13 @@ class DagreLayout extends BaseLayout {
23108
23157
  }
23109
23158
  });
23110
23159
  const { edgeLabelSize, edgeLabelOffset, edgeLabelPos, edgeMinLen, edgeWeight, } = this.options;
23111
- const edgeLabelSizeFn = formatSizeFn(edgeLabelSize, 0);
23112
- const edgeLabelOffsetFn = formatNumberFn(edgeLabelOffset, 10);
23113
- const edgeLabelPosFn = typeof edgeLabelPos === 'function' ? edgeLabelPos : () => edgeLabelPos;
23114
- const edgeMinLenFn = formatNumberFn(edgeMinLen, 1);
23115
- const edgeWeightFn = formatNumberFn(edgeWeight, 1);
23160
+ const edgeLabelSizeFn = formatSizeFn(edgeLabelSize, 0, 'edge');
23161
+ const edgeLabelOffsetFn = formatNumberFn(edgeLabelOffset, 10, 'edge');
23162
+ const edgeLabelPosFn = typeof edgeLabelPos === 'string'
23163
+ ? () => edgeLabelPos
23164
+ : formatFn(edgeLabelPos, ['edge']);
23165
+ const edgeMinLenFn = formatNumberFn(edgeMinLen, 1, 'edge');
23166
+ const edgeWeightFn = formatNumberFn(edgeWeight, 1, 'edge');
23116
23167
  this.model.forEachEdge((edge) => {
23117
23168
  const raw = edge._original;
23118
23169
  const [lw, lh] = parseSize(edgeLabelSizeFn(raw));
@@ -24162,28 +24213,43 @@ class ForceLayout extends BaseLayoutWithIterations {
24162
24213
  */
24163
24214
  parseOptions(options) {
24164
24215
  const _ = Object.assign(Object.assign({}, options), normalizeViewport(options));
24216
+ // Format nodeClusterBy (for clustering / leafCluster)
24217
+ if (_.nodeClusterBy) {
24218
+ _.nodeClusterBy = formatFn(_.nodeClusterBy, ['node']);
24219
+ }
24165
24220
  // Format node mass
24166
24221
  if (!options.getMass) {
24167
- _.getMass = (d) => {
24168
- if (!d)
24222
+ _.getMass = (node) => {
24223
+ if (!node)
24169
24224
  return 1;
24170
24225
  const massWeight = 1;
24171
- const degree = this.model.degree(d.id, 'both');
24226
+ const degree = this.model.degree(node.id, 'both');
24172
24227
  return !degree || degree < 5 ? massWeight : degree * 5 * massWeight;
24173
24228
  };
24174
24229
  }
24230
+ else {
24231
+ _.getMass = formatNumberFn(options.getMass, 1);
24232
+ }
24233
+ // Format per-node center force callback
24234
+ if (options.getCenter) {
24235
+ const params = ['node', 'degree'];
24236
+ _.getCenter = formatFn(options.getCenter, params);
24237
+ }
24175
24238
  // Format node size
24176
- _.nodeSize = formatNodeSizeFn(options.nodeSize, options.nodeSpacing);
24239
+ const nodeSizeVec = formatNodeSizeFn(options.nodeSize, options.nodeSpacing);
24240
+ _.nodeSize = (node) => {
24241
+ if (!node)
24242
+ return 0;
24243
+ const [w, h, z] = nodeSizeVec(node);
24244
+ return Math.max(w, h, z);
24245
+ };
24177
24246
  // Format node / edge strengths
24178
24247
  _.linkDistance = options.linkDistance
24179
- ? formatNumberFn(options.linkDistance, 1)
24180
- : (edge) => {
24181
- return (1 +
24182
- _.nodeSize(this.model.node(edge.source)._original) +
24183
- _.nodeSize(this.model.node(edge.target)._original));
24184
- };
24248
+ ? formatFn(options.linkDistance, ['edge', 'source', 'target'])
24249
+ : (_, source, target) => 1 + _.nodeSize(source) + _.nodeSize(target);
24185
24250
  _.nodeStrength = formatNumberFn(options.nodeStrength, 1);
24186
- _.edgeStrength = formatNumberFn(options.edgeStrength, 1);
24251
+ _.edgeStrength = formatNumberFn(options.edgeStrength, 1, 'edge');
24252
+ _.clusterNodeStrength = formatNumberFn(options.clusterNodeStrength, 1);
24187
24253
  // Format centripetal options
24188
24254
  this.formatCentripetal(_);
24189
24255
  return _;
@@ -24192,23 +24258,30 @@ class ForceLayout extends BaseLayoutWithIterations {
24192
24258
  * Format centripetal options
24193
24259
  */
24194
24260
  formatCentripetal(options) {
24195
- var _a;
24196
- const { dimensions, centripetalOptions, center, clusterNodeStrength, leafCluster, clustering, nodeClusterBy, } = options;
24197
- // Basic centripetal settings
24198
- const basicCentripetal = centripetalOptions || {
24199
- leaf: 2,
24200
- single: 2,
24201
- others: 1,
24202
- center: (_) => {
24203
- return {
24204
- x: center[0],
24205
- y: center[1],
24206
- z: dimensions === 3 ? center[2] : undefined,
24207
- };
24208
- },
24209
- };
24210
- if (typeof clusterNodeStrength !== 'function') {
24211
- options.clusterNodeStrength = () => clusterNodeStrength;
24261
+ var _a, _b;
24262
+ const { dimensions, centripetalOptions, center, leafCluster, clustering, nodeClusterBy, } = options;
24263
+ const leafParams = ['node', 'nodes', 'edges'];
24264
+ const leafFn = formatFn(centripetalOptions === null || centripetalOptions === void 0 ? void 0 : centripetalOptions.leaf, leafParams);
24265
+ const singleFn = formatNumberFn(centripetalOptions === null || centripetalOptions === void 0 ? void 0 : centripetalOptions.single, 2);
24266
+ const othersFn = formatNumberFn(centripetalOptions === null || centripetalOptions === void 0 ? void 0 : centripetalOptions.others, 1);
24267
+ const centerRaw = (_a = centripetalOptions === null || centripetalOptions === void 0 ? void 0 : centripetalOptions.center) !== null && _a !== void 0 ? _a : ((_) => {
24268
+ return {
24269
+ x: center[0],
24270
+ y: center[1],
24271
+ z: dimensions === 3 ? center[2] : undefined,
24272
+ };
24273
+ });
24274
+ const centerFn = formatFn(centerRaw, [
24275
+ 'node',
24276
+ 'nodes',
24277
+ 'edges',
24278
+ 'width',
24279
+ 'height',
24280
+ ]);
24281
+ const basicCentripetal = Object.assign(Object.assign({}, centripetalOptions), { leaf: leafFn, single: singleFn, others: othersFn, center: centerFn });
24282
+ // If user provided centripetalOptions, normalize them even without clustering modes.
24283
+ if (centripetalOptions) {
24284
+ options.centripetalOptions = basicCentripetal;
24212
24285
  }
24213
24286
  let sameTypeLeafMap;
24214
24287
  let clusters;
@@ -24216,8 +24289,8 @@ class ForceLayout extends BaseLayoutWithIterations {
24216
24289
  if (leafCluster && nodeClusterBy) {
24217
24290
  sameTypeLeafMap = this.getSameTypeLeafMap(nodeClusterBy);
24218
24291
  clusters =
24219
- Array.from(new Set((_a = this.model
24220
- .nodes()) === null || _a === void 0 ? void 0 : _a.map((node) => nodeClusterBy(node._original)))) || [];
24292
+ Array.from(new Set((_b = this.model
24293
+ .nodes()) === null || _b === void 0 ? void 0 : _b.map((node) => nodeClusterBy(node._original)))) || [];
24221
24294
  options.centripetalOptions = Object.assign({}, basicCentripetal, {
24222
24295
  single: () => 100,
24223
24296
  leaf: (node) => {
@@ -24290,17 +24363,6 @@ class ForceLayout extends BaseLayoutWithIterations {
24290
24363
  },
24291
24364
  });
24292
24365
  }
24293
- // Normalize functions
24294
- const { leaf, single, others } = options.centripetalOptions || {};
24295
- if (leaf && typeof leaf !== 'function') {
24296
- options.centripetalOptions.leaf = () => leaf;
24297
- }
24298
- if (single && typeof single !== 'function') {
24299
- options.centripetalOptions.single = () => single;
24300
- }
24301
- if (others && typeof others !== 'function') {
24302
- options.centripetalOptions.others = () => others;
24303
- }
24304
24366
  }
24305
24367
  /**
24306
24368
  * Get same type leaf map for clustering
@@ -25136,9 +25198,9 @@ class ForceAtlas2Layout extends BaseLayoutWithIterations {
25136
25198
  }
25137
25199
  getSizes(nodeSize, nodeSpacing) {
25138
25200
  const result = {};
25201
+ const nodeSizeFn = formatNodeSizeFn(nodeSize, nodeSpacing, DEFAULTS_LAYOUT_OPTIONS$4.nodeSize, DEFAULTS_LAYOUT_OPTIONS$4.nodeSpacing);
25139
25202
  this.model.forEachNode((node) => {
25140
- const nodeSizeFn = formatNodeSizeFn(nodeSize, nodeSpacing);
25141
- result[node.id] = nodeSizeFn(node._original);
25203
+ result[node.id] = Math.max(...nodeSizeFn(node._original));
25142
25204
  });
25143
25205
  return result;
25144
25206
  }
@@ -25150,7 +25212,7 @@ class ForceAtlas2Layout extends BaseLayoutWithIterations {
25150
25212
  return this.simulation;
25151
25213
  }
25152
25214
  parseOptions(options = {}) {
25153
- const { barnesHut, prune, maxIteration, kr, kg, nodeSize, nodeSpacing } = options;
25215
+ const { barnesHut, prune, maxIteration, kr, kg } = options;
25154
25216
  const auto = {};
25155
25217
  const n = this.model.nodeCount();
25156
25218
  if (barnesHut === undefined && n > 250)
@@ -25185,7 +25247,7 @@ class ForceAtlas2Layout extends BaseLayoutWithIterations {
25185
25247
  else if (n > 500)
25186
25248
  auto.kg = 1;
25187
25249
  }
25188
- return Object.assign(Object.assign(Object.assign(Object.assign({}, options), auto), normalizeViewport(options)), { nodeSize: formatSizeFn(nodeSize, DEFAULTS_LAYOUT_OPTIONS$4.nodeSize), nodeSpacing: formatNumberFn(nodeSpacing, DEFAULTS_LAYOUT_OPTIONS$4.nodeSpacing) });
25250
+ return Object.assign(Object.assign(Object.assign({}, options), auto), normalizeViewport(options));
25189
25251
  }
25190
25252
  stop() {
25191
25253
  var _a;
@@ -25570,7 +25632,7 @@ const DEFAULTS_LAYOUT_OPTIONS$3 = {
25570
25632
  clusterGravity: 10,
25571
25633
  width: 300,
25572
25634
  height: 300,
25573
- nodeClusterBy: 'data.cluster',
25635
+ nodeClusterBy: 'node.cluster',
25574
25636
  dimensions: 2,
25575
25637
  };
25576
25638
  class FruchtermanLayout extends BaseLayoutWithIterations {
@@ -25582,15 +25644,12 @@ class FruchtermanLayout extends BaseLayoutWithIterations {
25582
25644
  getDefaultOptions() {
25583
25645
  return DEFAULTS_LAYOUT_OPTIONS$3;
25584
25646
  }
25585
- parseOptions(options) {
25647
+ parseOptions(options = {}) {
25586
25648
  const { clustering, nodeClusterBy } = this.options;
25587
25649
  const clusteringEnabled = clustering && !!nodeClusterBy;
25588
- const nodeClusterByFunc = typeof nodeClusterBy === 'string'
25589
- ? (node) => getNestedValue(node, nodeClusterBy)
25590
- : nodeClusterBy;
25591
- Object.assign((options || (options = {})), normalizeViewport(options), {
25650
+ Object.assign(options, normalizeViewport(options), {
25592
25651
  clustering: clusteringEnabled,
25593
- nodeClusterBy: nodeClusterByFunc,
25652
+ nodeClusterBy: formatFn(nodeClusterBy, ['node']),
25594
25653
  });
25595
25654
  return options;
25596
25655
  }
@@ -25645,6 +25704,19 @@ class FruchtermanLayout extends BaseLayoutWithIterations {
25645
25704
  }
25646
25705
  }
25647
25706
 
25707
+ const DEFAULT_LAYOUT_OPTIONS = {
25708
+ begin: [0, 0],
25709
+ preventOverlap: true,
25710
+ condense: false,
25711
+ rows: undefined,
25712
+ cols: undefined,
25713
+ position: undefined,
25714
+ sortBy: 'degree',
25715
+ nodeSize: 30,
25716
+ nodeSpacing: 10,
25717
+ width: 300,
25718
+ height: 300,
25719
+ };
25648
25720
  /**
25649
25721
  * <zh/> 网格布局
25650
25722
  *
@@ -25656,23 +25728,10 @@ class GridLayout extends BaseLayout {
25656
25728
  this.id = 'grid';
25657
25729
  }
25658
25730
  getDefaultOptions() {
25659
- return {
25660
- begin: [0, 0],
25661
- preventOverlap: true,
25662
- preventOverlapPadding: 10,
25663
- condense: false,
25664
- rows: undefined,
25665
- cols: undefined,
25666
- position: undefined,
25667
- sortBy: 'degree',
25668
- nodeSize: 30,
25669
- width: 300,
25670
- height: 300,
25671
- };
25731
+ return DEFAULT_LAYOUT_OPTIONS;
25672
25732
  }
25673
- normalizeOptions(options = {}, model) {
25674
- var _a;
25675
- const { rows: propRows, cols: propCols } = options;
25733
+ parseOptions(options = {}, model) {
25734
+ const { rows: propRows, cols: propCols, position: propPosition, sortBy: propSortBy, } = options;
25676
25735
  const { width, height, center } = normalizeViewport(options);
25677
25736
  let rows = options.rows;
25678
25737
  let cols = options.cols;
@@ -25727,20 +25786,20 @@ class GridLayout extends BaseLayout {
25727
25786
  }
25728
25787
  }
25729
25788
  }
25730
- const preventOverlap = options.preventOverlap || options.nodeSpacing !== undefined;
25731
- const nodeSpacing = formatNumberFn(options.nodeSpacing, 10);
25732
- const nodeSize = formatSizeFn(options.nodeSize, 30);
25733
- return Object.assign(Object.assign({}, options), { begin: options.begin || [0, 0], sortBy: options.sortBy || 'degree', preventOverlapPadding: (_a = options.preventOverlapPadding) !== null && _a !== void 0 ? _a : 0, preventOverlap,
25734
- nodeSpacing,
25735
- nodeSize,
25789
+ const sortBy = !propSortBy
25790
+ ? DEFAULT_LAYOUT_OPTIONS.sortBy
25791
+ : propSortBy === 'degree' || propSortBy === 'id'
25792
+ ? propSortBy
25793
+ : formatFn(propSortBy, ['nodeA', 'nodeB']);
25794
+ return Object.assign(Object.assign({}, options), { sortBy,
25736
25795
  rcs,
25737
25796
  center,
25738
25797
  width,
25739
- height });
25798
+ height, position: formatFn(propPosition, ['node']) });
25740
25799
  }
25741
25800
  layout() {
25742
25801
  return __awaiter(this, void 0, void 0, function* () {
25743
- const { begin, rcs, sortBy, width, height, condense, preventOverlapPadding, preventOverlap, nodeSpacing, nodeSize, position, } = this.normalizeOptions(this.options, this.model);
25802
+ const { begin, rcs, sortBy, width, height, condense, preventOverlap, nodeSpacing, nodeSize, position, } = this.parseOptions(this.options, this.model);
25744
25803
  const n = this.model.nodeCount();
25745
25804
  if (!n || n === 1) {
25746
25805
  applySingleNodeLayout(this.model, begin);
@@ -25758,14 +25817,9 @@ class GridLayout extends BaseLayout {
25758
25817
  let cellWidth = condense ? 0 : width / rcs.cols;
25759
25818
  let cellHeight = condense ? 0 : height / rcs.rows;
25760
25819
  if (preventOverlap) {
25820
+ const sizeFn = formatNodeSizeFn(nodeSize, nodeSpacing, DEFAULT_LAYOUT_OPTIONS.nodeSize, DEFAULT_LAYOUT_OPTIONS.nodeSpacing);
25761
25821
  this.model.forEachNode((node) => {
25762
- const nodeData = node._original;
25763
- const [nodeW, nodeH] = parseSize(nodeSize(nodeData) || 30);
25764
- const p = nodeSpacing !== undefined
25765
- ? nodeSpacing(nodeData)
25766
- : preventOverlapPadding;
25767
- const w = nodeW + p;
25768
- const h = nodeH + p;
25822
+ const [w, h] = sizeFn(node._original);
25769
25823
  cellWidth = Math.max(cellWidth, w);
25770
25824
  cellHeight = Math.max(cellHeight, h);
25771
25825
  });
@@ -31848,8 +31902,8 @@ const getRepulsion = (model, displacements, k, radiiMap, nodeSizeFunc) => {
31848
31902
  vecx = 0.01 * sign;
31849
31903
  vecy = 0.01 * sign;
31850
31904
  }
31851
- const nodeSizeU = Math.max(...parseSize(nodeSizeFunc(nodeU._original)));
31852
- const nodeSizeV = Math.max(...parseSize(nodeSizeFunc(nodeV._original)));
31905
+ const nodeSizeU = Math.max(...nodeSizeFunc(nodeU._original));
31906
+ const nodeSizeV = Math.max(...nodeSizeFunc(nodeV._original));
31853
31907
  // these two nodes overlap
31854
31908
  if (vecLength < nodeSizeV / 2 + nodeSizeU / 2) {
31855
31909
  const common = (k * k) / vecLength;
@@ -31932,6 +31986,8 @@ const DEFAULTS_LAYOUT_OPTIONS = {
31932
31986
  sortStrength: 10,
31933
31987
  strictRadial: true,
31934
31988
  unitRadius: null,
31989
+ nodeSize: 10,
31990
+ nodeSpacing: 0,
31935
31991
  };
31936
31992
  /**
31937
31993
  * <zh/> 径向布局
@@ -32000,7 +32056,7 @@ class RadialLayout extends BaseLayout {
32000
32056
  });
32001
32057
  // stagger the overlapped nodes
32002
32058
  if (preventOverlap) {
32003
- const nodeSizeFunc = formatNodeSizeFn(nodeSize, nodeSpacing);
32059
+ const nodeSizeFunc = formatNodeSizeFn(nodeSize, nodeSpacing, DEFAULTS_LAYOUT_OPTIONS.nodeSize, DEFAULTS_LAYOUT_OPTIONS.nodeSpacing);
32004
32060
  const nonoverlapForceParams = {
32005
32061
  nodeSizeFunc,
32006
32062
  radiiMap,
@@ -32079,7 +32135,7 @@ const eIdealDisMatrix = (model, distances, linkDistance, radii, unitRadius, sort
32079
32135
  radiusScale[i] = radii[i] / unitRadius;
32080
32136
  const baseLink = (linkDistance + unitRadius) / 2;
32081
32137
  const sortCache = new Map();
32082
- const sortFn = typeof sortBy === 'function' ? sortBy : null;
32138
+ const sortFn = !sortBy || sortBy === 'data' ? null : formatFn(sortBy, ['node']);
32083
32139
  const isDataSort = sortBy === 'data';
32084
32140
  for (let i = 0; i < n; i++) {
32085
32141
  const row = distances[i];