@visactor/vutils 1.0.24 → 1.0.25

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 (435) hide show
  1. package/README.zh-CN.md +12 -0
  2. package/cjs/angle.d.ts +61 -0
  3. package/cjs/angle.js +73 -7
  4. package/cjs/angle.js.map +1 -1
  5. package/cjs/color/Color.d.ts +3 -0
  6. package/cjs/color/Color.js +64 -10
  7. package/cjs/color/Color.js.map +1 -1
  8. package/cjs/color/hexToRgb.d.ts +5 -0
  9. package/cjs/color/hexToRgb.js +5 -0
  10. package/cjs/color/hexToRgb.js.map +1 -1
  11. package/cjs/color/rgbToHsl.js +5 -1
  12. package/cjs/color/rgbToHsl.js.map +1 -1
  13. package/cjs/common/array.d.ts +43 -0
  14. package/cjs/common/array.js +44 -0
  15. package/cjs/common/array.js.map +1 -1
  16. package/cjs/common/ascending.js +1 -2
  17. package/cjs/common/bisect.d.ts +21 -0
  18. package/cjs/common/bisect.js +29 -0
  19. package/cjs/common/bisect.js.map +1 -1
  20. package/cjs/common/bootstrap.d.ts +5 -0
  21. package/cjs/common/bootstrap.js +22 -0
  22. package/cjs/common/bootstrap.js.map +1 -0
  23. package/cjs/common/clone.js +6 -0
  24. package/cjs/common/clone.js.map +1 -1
  25. package/cjs/common/cloneDeep.js +4 -1
  26. package/cjs/common/cloneDeep.js.map +1 -1
  27. package/cjs/common/correlation.d.ts +3 -0
  28. package/cjs/common/correlation.js +83 -0
  29. package/cjs/common/correlation.js.map +1 -0
  30. package/cjs/common/debounce.js +22 -4
  31. package/cjs/common/debounce.js.map +1 -1
  32. package/cjs/common/ecdf.d.ts +8 -0
  33. package/cjs/common/ecdf.js +11 -2
  34. package/cjs/common/ecdf.js.map +1 -1
  35. package/cjs/common/extent.d.ts +4 -0
  36. package/cjs/common/extent.js +4 -2
  37. package/cjs/common/extent.js.map +1 -1
  38. package/cjs/common/field.d.ts +6 -0
  39. package/cjs/common/field.js +3 -0
  40. package/cjs/common/field.js.map +1 -1
  41. package/cjs/common/getType.js +1 -2
  42. package/cjs/common/has.d.ts +17 -0
  43. package/cjs/common/has.js +18 -1
  44. package/cjs/common/has.js.map +1 -1
  45. package/cjs/common/index.d.ts +4 -0
  46. package/cjs/common/index.js +33 -6
  47. package/cjs/common/index.js.map +1 -1
  48. package/cjs/common/interpolate.js +16 -3
  49. package/cjs/common/interpolate.js.map +1 -1
  50. package/cjs/common/isBase64.d.ts +6 -0
  51. package/cjs/common/isBase64.js +6 -0
  52. package/cjs/common/isBase64.js.map +1 -1
  53. package/cjs/common/isBoolean.d.ts +13 -0
  54. package/cjs/common/isBoolean.js +13 -1
  55. package/cjs/common/isBoolean.js.map +1 -1
  56. package/cjs/common/isEmpty.js +11 -1
  57. package/cjs/common/isEmpty.js.map +1 -1
  58. package/cjs/common/isEqual.js +19 -7
  59. package/cjs/common/isEqual.js.map +1 -1
  60. package/cjs/common/isFunction.d.ts +25 -0
  61. package/cjs/common/isFunction.js +26 -0
  62. package/cjs/common/isFunction.js.map +1 -1
  63. package/cjs/common/isNull.js +2 -1
  64. package/cjs/common/isNumber.d.ts +23 -0
  65. package/cjs/common/isNumber.js +23 -1
  66. package/cjs/common/isNumber.js.map +1 -1
  67. package/cjs/common/isNumeric.d.ts +25 -0
  68. package/cjs/common/isNumeric.js +25 -0
  69. package/cjs/common/isNumeric.js.map +1 -1
  70. package/cjs/common/isObject.d.ts +21 -0
  71. package/cjs/common/isObject.js +23 -2
  72. package/cjs/common/isObject.js.map +1 -1
  73. package/cjs/common/isObjectLike.d.ts +20 -0
  74. package/cjs/common/isObjectLike.js +21 -0
  75. package/cjs/common/isObjectLike.js.map +1 -1
  76. package/cjs/common/isPlainObject.d.ts +25 -0
  77. package/cjs/common/isPlainObject.js.map +1 -1
  78. package/cjs/common/isShallowEqual.js +2 -1
  79. package/cjs/common/isShallowEqual.js.map +1 -1
  80. package/cjs/common/isString.d.ts +13 -0
  81. package/cjs/common/isString.js +14 -2
  82. package/cjs/common/isString.js.map +1 -1
  83. package/cjs/common/isType.d.ts +6 -0
  84. package/cjs/common/isType.js +7 -1
  85. package/cjs/common/isType.js.map +1 -1
  86. package/cjs/common/isValidNumber.js.map +1 -1
  87. package/cjs/common/isValidUrl.js.map +1 -1
  88. package/cjs/common/kde.d.ts +28 -0
  89. package/cjs/common/kde.js +29 -5
  90. package/cjs/common/kde.js.map +1 -1
  91. package/cjs/common/mean.d.ts +2 -0
  92. package/cjs/common/mean.js +25 -0
  93. package/cjs/common/mean.js.map +1 -0
  94. package/cjs/common/merge.js +20 -4
  95. package/cjs/common/merge.js.map +1 -1
  96. package/cjs/common/mixin.js +14 -3
  97. package/cjs/common/mixin.js.map +1 -1
  98. package/cjs/common/normalQuantile.d.ts +5 -0
  99. package/cjs/common/normalQuantile.js +21 -0
  100. package/cjs/common/normalQuantile.js.map +1 -0
  101. package/cjs/common/number.d.ts +24 -0
  102. package/cjs/common/number.js +24 -1
  103. package/cjs/common/number.js.map +1 -1
  104. package/cjs/common/pad.d.ts +21 -0
  105. package/cjs/common/pad.js +21 -1
  106. package/cjs/common/pad.js.map +1 -1
  107. package/cjs/common/random.d.ts +3 -0
  108. package/cjs/common/random.js +13 -0
  109. package/cjs/common/random.js.map +1 -1
  110. package/cjs/common/regression-linear.d.ts +4 -0
  111. package/cjs/common/regression-linear.js +19 -12
  112. package/cjs/common/regression-linear.js.map +1 -1
  113. package/cjs/common/regression-logistic.d.ts +6 -0
  114. package/cjs/common/regression-logistic.js +25 -14
  115. package/cjs/common/regression-logistic.js.map +1 -1
  116. package/cjs/common/regression-lowess.d.ts +9 -0
  117. package/cjs/common/regression-lowess.js +51 -23
  118. package/cjs/common/regression-lowess.js.map +1 -1
  119. package/cjs/common/regression-polynomial.js +26 -15
  120. package/cjs/common/regression-polynomial.js.map +1 -1
  121. package/cjs/common/regression-utils.d.ts +13 -1
  122. package/cjs/common/regression-utils.js +27 -12
  123. package/cjs/common/regression-utils.js.map +1 -1
  124. package/cjs/common/throttle.js +3 -0
  125. package/cjs/common/throttle.js.map +1 -1
  126. package/cjs/common/toDate.js +22 -3
  127. package/cjs/common/toDate.js.map +1 -1
  128. package/cjs/common/uuid.d.ts +7 -0
  129. package/cjs/common/uuid.js +15 -1
  130. package/cjs/common/uuid.js.map +1 -1
  131. package/cjs/data-structure/bounds.d.ts +101 -0
  132. package/cjs/data-structure/bounds.js +75 -8
  133. package/cjs/data-structure/bounds.js.map +1 -1
  134. package/cjs/data-structure/hashTable.d.ts +4 -0
  135. package/cjs/data-structure/hashTable.js +13 -3
  136. package/cjs/data-structure/hashTable.js.map +1 -1
  137. package/cjs/data-structure/index.js +7 -3
  138. package/cjs/data-structure/index.js.map +1 -1
  139. package/cjs/data-structure/matrix.d.ts +91 -0
  140. package/cjs/data-structure/matrix.js +53 -5
  141. package/cjs/data-structure/matrix.js.map +1 -1
  142. package/cjs/data-structure/point.d.ts +3 -0
  143. package/cjs/data-structure/point.js +6 -2
  144. package/cjs/data-structure/point.js.map +1 -1
  145. package/cjs/dom.d.ts +36 -0
  146. package/cjs/dom.js +43 -1
  147. package/cjs/dom.js.map +1 -1
  148. package/cjs/fmin/blas1.js +10 -1
  149. package/cjs/fmin/blas1.js.map +1 -1
  150. package/cjs/fmin/conjugate-gradient.js +18 -3
  151. package/cjs/fmin/conjugate-gradient.js.map +1 -1
  152. package/cjs/fmin/linesearch.js +15 -1
  153. package/cjs/fmin/linesearch.js.map +1 -1
  154. package/cjs/fmin/nelder-mead.d.ts +1 -0
  155. package/cjs/fmin/nelder-mead.js +30 -10
  156. package/cjs/fmin/nelder-mead.js.map +1 -1
  157. package/cjs/format/number/formatDecimal.js +9 -1
  158. package/cjs/format/number/formatDecimal.js.map +1 -1
  159. package/cjs/format/number/formatGroup.js +7 -0
  160. package/cjs/format/number/formatGroup.js.map +1 -1
  161. package/cjs/format/number/formatPrefixAuto.js +8 -0
  162. package/cjs/format/number/formatPrefixAuto.js.map +1 -1
  163. package/cjs/format/number/formatRounded.js +7 -0
  164. package/cjs/format/number/formatRounded.js.map +1 -1
  165. package/cjs/format/number/formatTrim.js +7 -0
  166. package/cjs/format/number/formatTrim.js.map +1 -1
  167. package/cjs/format/number/number.js +39 -9
  168. package/cjs/format/number/number.js.map +1 -1
  169. package/cjs/format/time.js +23 -6
  170. package/cjs/format/time.js.map +1 -1
  171. package/cjs/geo/circle-intersection.d.ts +12 -0
  172. package/cjs/geo/circle-intersection.js +54 -9
  173. package/cjs/geo/circle-intersection.js.map +1 -1
  174. package/cjs/geo/constant.js +8 -1
  175. package/cjs/geo/constant.js.map +1 -1
  176. package/cjs/geo/invariant.d.ts +22 -0
  177. package/cjs/geo/invariant.js +24 -1
  178. package/cjs/geo/invariant.js.map +1 -1
  179. package/cjs/graphics/algorithm/aabb.js +7 -3
  180. package/cjs/graphics/algorithm/aabb.js.map +1 -1
  181. package/cjs/graphics/algorithm/intersect.d.ts +48 -0
  182. package/cjs/graphics/algorithm/intersect.js +75 -7
  183. package/cjs/graphics/algorithm/intersect.js.map +1 -1
  184. package/cjs/graphics/bounds-util.js +4 -2
  185. package/cjs/graphics/bounds-util.js.map +1 -1
  186. package/cjs/graphics/graph-util.js +4 -0
  187. package/cjs/graphics/graph-util.js.map +1 -1
  188. package/cjs/graphics/index.js +7 -4
  189. package/cjs/graphics/index.js.map +1 -1
  190. package/cjs/graphics/polygon.d.ts +12 -0
  191. package/cjs/graphics/polygon.js +28 -5
  192. package/cjs/graphics/polygon.js.map +1 -1
  193. package/cjs/graphics/text/measure/interface.d.ts +12 -0
  194. package/cjs/graphics/text/measure/textMeasure.d.ts +23 -0
  195. package/cjs/graphics/text/measure/textMeasure.js +50 -22
  196. package/cjs/graphics/text/measure/textMeasure.js.map +1 -1
  197. package/cjs/graphics/text/measure/util.js +1 -0
  198. package/cjs/graphics/text/measure/util.js.map +1 -1
  199. package/cjs/graphics/text/stringWidth.js +7 -3
  200. package/cjs/graphics/text/stringWidth.js.map +1 -1
  201. package/cjs/index.d.ts +6 -0
  202. package/cjs/index.js +19 -4
  203. package/cjs/index.js.map +1 -1
  204. package/cjs/logger.js +12 -2
  205. package/cjs/logger.js.map +1 -1
  206. package/cjs/lru.js +14 -6
  207. package/cjs/lru.js.map +1 -1
  208. package/cjs/math.d.ts +9 -0
  209. package/cjs/math.js +10 -0
  210. package/cjs/math.js.map +1 -1
  211. package/cjs/padding.d.ts +5 -0
  212. package/cjs/padding.js +5 -0
  213. package/cjs/padding.js.map +1 -1
  214. package/cjs/time/formatUtils.d.ts +6 -0
  215. package/cjs/time/formatUtils.js +7 -0
  216. package/cjs/time/formatUtils.js.map +1 -1
  217. package/dist/index.js +1602 -109
  218. package/dist/index.min.js +128 -1
  219. package/es/angle.d.ts +61 -0
  220. package/es/angle.js +66 -10
  221. package/es/angle.js.map +1 -1
  222. package/es/color/Color.d.ts +3 -0
  223. package/es/color/Color.js +64 -9
  224. package/es/color/Color.js.map +1 -1
  225. package/es/color/hexToRgb.d.ts +5 -0
  226. package/es/color/hexToRgb.js +5 -0
  227. package/es/color/hexToRgb.js.map +1 -1
  228. package/es/color/rgbToHsl.js +5 -1
  229. package/es/color/rgbToHsl.js.map +1 -1
  230. package/es/common/array.d.ts +43 -0
  231. package/es/common/array.js +44 -8
  232. package/es/common/array.js.map +1 -1
  233. package/es/common/ascending.js +1 -2
  234. package/es/common/bisect.d.ts +21 -0
  235. package/es/common/bisect.js +29 -4
  236. package/es/common/bisect.js.map +1 -1
  237. package/es/common/bootstrap.d.ts +5 -0
  238. package/es/common/bootstrap.js +14 -0
  239. package/es/common/bootstrap.js.map +1 -0
  240. package/es/common/clone.js +6 -0
  241. package/es/common/clone.js.map +1 -1
  242. package/es/common/cloneDeep.js +4 -1
  243. package/es/common/cloneDeep.js.map +1 -1
  244. package/es/common/correlation.d.ts +3 -0
  245. package/es/common/correlation.js +77 -0
  246. package/es/common/correlation.js.map +1 -0
  247. package/es/common/debounce.js +22 -4
  248. package/es/common/debounce.js.map +1 -1
  249. package/es/common/ecdf.d.ts +8 -0
  250. package/es/common/ecdf.js +11 -1
  251. package/es/common/ecdf.js.map +1 -1
  252. package/es/common/extent.d.ts +4 -0
  253. package/es/common/extent.js +8 -3
  254. package/es/common/extent.js.map +1 -1
  255. package/es/common/field.d.ts +6 -0
  256. package/es/common/field.js +3 -1
  257. package/es/common/field.js.map +1 -1
  258. package/es/common/getType.js +1 -2
  259. package/es/common/has.d.ts +17 -0
  260. package/es/common/has.js +18 -1
  261. package/es/common/has.js.map +1 -1
  262. package/es/common/index.d.ts +4 -0
  263. package/es/common/index.js +22 -0
  264. package/es/common/index.js.map +1 -1
  265. package/es/common/interpolate.js +16 -3
  266. package/es/common/interpolate.js.map +1 -1
  267. package/es/common/isBase64.d.ts +6 -0
  268. package/es/common/isBase64.js +6 -0
  269. package/es/common/isBase64.js.map +1 -1
  270. package/es/common/isBoolean.d.ts +13 -0
  271. package/es/common/isBoolean.js +13 -1
  272. package/es/common/isBoolean.js.map +1 -1
  273. package/es/common/isEmpty.js +11 -1
  274. package/es/common/isEmpty.js.map +1 -1
  275. package/es/common/isEqual.js +19 -7
  276. package/es/common/isEqual.js.map +1 -1
  277. package/es/common/isFunction.d.ts +25 -0
  278. package/es/common/isFunction.js +26 -0
  279. package/es/common/isFunction.js.map +1 -1
  280. package/es/common/isNull.js +2 -1
  281. package/es/common/isNumber.d.ts +23 -0
  282. package/es/common/isNumber.js +23 -1
  283. package/es/common/isNumber.js.map +1 -1
  284. package/es/common/isNumeric.d.ts +25 -0
  285. package/es/common/isNumeric.js +25 -0
  286. package/es/common/isNumeric.js.map +1 -1
  287. package/es/common/isObject.d.ts +21 -0
  288. package/es/common/isObject.js +23 -2
  289. package/es/common/isObject.js.map +1 -1
  290. package/es/common/isObjectLike.d.ts +20 -0
  291. package/es/common/isObjectLike.js +21 -0
  292. package/es/common/isObjectLike.js.map +1 -1
  293. package/es/common/isPlainObject.d.ts +25 -0
  294. package/es/common/isPlainObject.js +26 -0
  295. package/es/common/isPlainObject.js.map +1 -1
  296. package/es/common/isShallowEqual.js +2 -1
  297. package/es/common/isShallowEqual.js.map +1 -1
  298. package/es/common/isString.d.ts +13 -0
  299. package/es/common/isString.js +14 -2
  300. package/es/common/isString.js.map +1 -1
  301. package/es/common/isType.d.ts +6 -0
  302. package/es/common/isType.js +7 -1
  303. package/es/common/isType.js.map +1 -1
  304. package/es/common/isValidNumber.js.map +1 -1
  305. package/es/common/isValidUrl.js.map +1 -1
  306. package/es/common/kde.d.ts +28 -0
  307. package/es/common/kde.js +29 -7
  308. package/es/common/kde.js.map +1 -1
  309. package/es/common/mean.d.ts +2 -0
  310. package/es/common/mean.js +19 -0
  311. package/es/common/mean.js.map +1 -0
  312. package/es/common/merge.js +22 -5
  313. package/es/common/merge.js.map +1 -1
  314. package/es/common/mixin.js +14 -3
  315. package/es/common/mixin.js.map +1 -1
  316. package/es/common/normalQuantile.d.ts +5 -0
  317. package/es/common/normalQuantile.js +15 -0
  318. package/es/common/normalQuantile.js.map +1 -0
  319. package/es/common/number.d.ts +24 -0
  320. package/es/common/number.js +24 -2
  321. package/es/common/number.js.map +1 -1
  322. package/es/common/pad.d.ts +21 -0
  323. package/es/common/pad.js +21 -1
  324. package/es/common/pad.js.map +1 -1
  325. package/es/common/random.d.ts +3 -0
  326. package/es/common/random.js +13 -1
  327. package/es/common/random.js.map +1 -1
  328. package/es/common/regression-linear.d.ts +4 -0
  329. package/es/common/regression-linear.js +18 -14
  330. package/es/common/regression-linear.js.map +1 -1
  331. package/es/common/regression-logistic.d.ts +6 -0
  332. package/es/common/regression-logistic.js +24 -16
  333. package/es/common/regression-logistic.js.map +1 -1
  334. package/es/common/regression-lowess.d.ts +9 -0
  335. package/es/common/regression-lowess.js +50 -24
  336. package/es/common/regression-lowess.js.map +1 -1
  337. package/es/common/regression-polynomial.js +25 -16
  338. package/es/common/regression-polynomial.js.map +1 -1
  339. package/es/common/regression-utils.d.ts +13 -1
  340. package/es/common/regression-utils.js +18 -9
  341. package/es/common/regression-utils.js.map +1 -1
  342. package/es/common/throttle.js +3 -0
  343. package/es/common/throttle.js.map +1 -1
  344. package/es/common/toDate.js +23 -3
  345. package/es/common/toDate.js.map +1 -1
  346. package/es/common/uuid.d.ts +7 -0
  347. package/es/common/uuid.js +15 -1
  348. package/es/common/uuid.js.map +1 -1
  349. package/es/data-structure/bounds.d.ts +101 -0
  350. package/es/data-structure/bounds.js +75 -9
  351. package/es/data-structure/bounds.js.map +1 -1
  352. package/es/data-structure/hashTable.d.ts +4 -0
  353. package/es/data-structure/hashTable.js +13 -3
  354. package/es/data-structure/hashTable.js.map +1 -1
  355. package/es/data-structure/index.js +3 -1
  356. package/es/data-structure/index.js.map +1 -1
  357. package/es/data-structure/matrix.d.ts +91 -0
  358. package/es/data-structure/matrix.js +53 -6
  359. package/es/data-structure/matrix.js.map +1 -1
  360. package/es/data-structure/point.d.ts +3 -0
  361. package/es/data-structure/point.js +6 -2
  362. package/es/data-structure/point.js.map +1 -1
  363. package/es/dom.d.ts +36 -0
  364. package/es/dom.js +43 -8
  365. package/es/dom.js.map +1 -1
  366. package/es/fmin/blas1.js +10 -0
  367. package/es/fmin/blas1.js.map +1 -1
  368. package/es/fmin/conjugate-gradient.js +18 -2
  369. package/es/fmin/conjugate-gradient.js.map +1 -1
  370. package/es/fmin/linesearch.js +15 -0
  371. package/es/fmin/linesearch.js.map +1 -1
  372. package/es/fmin/nelder-mead.d.ts +1 -0
  373. package/es/fmin/nelder-mead.js +29 -9
  374. package/es/fmin/nelder-mead.js.map +1 -1
  375. package/es/format/number/formatDecimal.js +9 -1
  376. package/es/format/number/formatDecimal.js.map +1 -1
  377. package/es/format/number/formatGroup.js +7 -0
  378. package/es/format/number/formatGroup.js.map +1 -1
  379. package/es/format/number/formatPrefixAuto.js +8 -0
  380. package/es/format/number/formatPrefixAuto.js.map +1 -1
  381. package/es/format/number/formatRounded.js +7 -0
  382. package/es/format/number/formatRounded.js.map +1 -1
  383. package/es/format/number/formatTrim.js +7 -0
  384. package/es/format/number/formatTrim.js.map +1 -1
  385. package/es/format/number/number.js +40 -8
  386. package/es/format/number/number.js.map +1 -1
  387. package/es/format/time.js +23 -5
  388. package/es/format/time.js.map +1 -1
  389. package/es/geo/circle-intersection.d.ts +12 -0
  390. package/es/geo/circle-intersection.js +54 -14
  391. package/es/geo/circle-intersection.js.map +1 -1
  392. package/es/geo/constant.js +8 -0
  393. package/es/geo/constant.js.map +1 -1
  394. package/es/geo/invariant.d.ts +22 -0
  395. package/es/geo/invariant.js +24 -0
  396. package/es/geo/invariant.js.map +1 -1
  397. package/es/graphics/algorithm/aabb.js +7 -3
  398. package/es/graphics/algorithm/aabb.js.map +1 -1
  399. package/es/graphics/algorithm/intersect.d.ts +48 -0
  400. package/es/graphics/algorithm/intersect.js +75 -12
  401. package/es/graphics/algorithm/intersect.js.map +1 -1
  402. package/es/graphics/bounds-util.js +4 -2
  403. package/es/graphics/bounds-util.js.map +1 -1
  404. package/es/graphics/graph-util.js +4 -0
  405. package/es/graphics/graph-util.js.map +1 -1
  406. package/es/graphics/index.js +2 -0
  407. package/es/graphics/index.js.map +1 -1
  408. package/es/graphics/polygon.d.ts +12 -0
  409. package/es/graphics/polygon.js +28 -6
  410. package/es/graphics/polygon.js.map +1 -1
  411. package/es/graphics/text/measure/interface.d.ts +12 -0
  412. package/es/graphics/text/measure/textMeasure.d.ts +23 -0
  413. package/es/graphics/text/measure/textMeasure.js +46 -21
  414. package/es/graphics/text/measure/textMeasure.js.map +1 -1
  415. package/es/graphics/text/measure/util.js +1 -0
  416. package/es/graphics/text/measure/util.js.map +1 -1
  417. package/es/graphics/text/stringWidth.js +7 -3
  418. package/es/graphics/text/stringWidth.js.map +1 -1
  419. package/es/index.d.ts +6 -0
  420. package/es/index.js +15 -1
  421. package/es/index.js.map +1 -1
  422. package/es/logger.js +12 -1
  423. package/es/logger.js.map +1 -1
  424. package/es/lru.js +14 -6
  425. package/es/lru.js.map +1 -1
  426. package/es/math.d.ts +9 -0
  427. package/es/math.js +10 -1
  428. package/es/math.js.map +1 -1
  429. package/es/padding.d.ts +5 -0
  430. package/es/padding.js +5 -1
  431. package/es/padding.js.map +1 -1
  432. package/es/time/formatUtils.d.ts +6 -0
  433. package/es/time/formatUtils.js +7 -1
  434. package/es/time/formatUtils.js.map +1 -1
  435. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -325,8 +325,27 @@
325
325
  var eventemitter3Exports = eventemitter3.exports;
326
326
  var index$1 = /*@__PURE__*/getDefaultExportFromCjs(eventemitter3Exports);
327
327
 
328
+ /**
329
+ * check value type
330
+ * @param value the value to check
331
+ * @param type type
332
+ * @returns
333
+ */
328
334
  const isType = (value, type) => Object.prototype.toString.call(value) === `[object ${type}]`;
329
335
 
336
+ /**
337
+ * Checks if `value` is classified as a boolean primitive or object.
338
+ * @param {*} value The value to check.
339
+ * @param {boolean} fuzzy Whether to perform fuzzy judgment, for better performance,default to `false`.
340
+ * @returns {boolean} Returns `true` if `value` is a boolean, else `false`.
341
+ * @example
342
+ *
343
+ * isBoolean(false)
344
+ * // => true
345
+ *
346
+ * isBoolean(null)
347
+ * // => false
348
+ */
330
349
  const isBoolean = (value, fuzzy = false) => {
331
350
  if (fuzzy) {
332
351
  return typeof value === 'boolean';
@@ -334,6 +353,32 @@
334
353
  return value === true || value === false || isType(value, 'Boolean');
335
354
  };
336
355
 
356
+ /**
357
+ * Checks if `value` is classified as a `Function` object.
358
+ *
359
+ * @param {*} value The value to check.
360
+ * @returns {boolean} Returns `true` if `value` is a function, else `false`.
361
+ * @example
362
+ *
363
+ * isFunction(class Any{})
364
+ * // => true
365
+ *
366
+ * isFunction(() => {})
367
+ * // => true
368
+ *
369
+ * isFunction(async () => {})
370
+ * // => true
371
+ *
372
+ * isFunction(function * Any() {})
373
+ * // => true
374
+ *
375
+ * isFunction(Math.round)
376
+ * // => true
377
+ *
378
+ * isFunction(/abc/)
379
+ * // => false
380
+ */
381
+ // eslint-disable-next-line @typescript-eslint/ban-types
337
382
  const isFunction = (value) => {
338
383
  return typeof value === 'function';
339
384
  };
@@ -350,15 +395,84 @@
350
395
  return value !== null && value !== undefined;
351
396
  };
352
397
 
398
+ /**
399
+ * Checks if `value` is the
400
+ * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
401
+ * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
402
+ *
403
+ * @param {*} value The value to check.
404
+ * @returns {boolean} Returns `true` if `value` is an object, else `false`.
405
+ * @example
406
+ *
407
+ * isObject({})
408
+ * // => true
409
+ *
410
+ * isObject([1, 2, 3])
411
+ * // => true
412
+ *
413
+ * isObject(Function)
414
+ * // => true
415
+ *
416
+ * isObject(null)
417
+ * // => false
418
+ */
419
+ // eslint-disable-next-line @typescript-eslint/ban-types
353
420
  const isObject = (value) => {
354
421
  const type = typeof value;
355
422
  return (value !== null && type === 'object') || type === 'function';
356
423
  };
357
424
 
425
+ /**
426
+ * Checks if `value` is object-like. A value is object-like if it's not `null`
427
+ * and has a `typeof` result of "object".
428
+ *
429
+ * @param {*} value The value to check.
430
+ * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
431
+ * @example
432
+ *
433
+ * isObjectLike({})
434
+ * // => true
435
+ *
436
+ * isObjectLike([1, 2, 3])
437
+ * // => true
438
+ *
439
+ * isObjectLike(Function)
440
+ * // => false
441
+ *
442
+ * isObjectLike(null)
443
+ * // => false
444
+ */
445
+ // eslint-disable-next-line @typescript-eslint/ban-types
358
446
  const isObjectLike = (value) => {
359
447
  return typeof value === 'object' && value !== null;
360
448
  };
361
449
 
450
+ /**
451
+ * @see https://github.com/lodash/lodash/blob/master/isPlainObject.js
452
+ * Checks if `value` is a plain object, that is, an object created by the
453
+ * `Object` constructor or one with a `[[Prototype]]` of `null`.
454
+ *
455
+ * @param {*} value The value to check.
456
+ * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
457
+ * @example
458
+ *
459
+ * function Foo() {
460
+ * this.a = 1
461
+ * }
462
+ *
463
+ * isPlainObject(new Foo)
464
+ * // => false
465
+ *
466
+ * isPlainObject([1, 2, 3])
467
+ * // => false
468
+ *
469
+ * isPlainObject({ 'x': 0, 'y': 0 })
470
+ * // => true
471
+ *
472
+ * isPlainObject(Object.create(null))
473
+ * // => true
474
+ */
475
+ // eslint-disable-next-line @typescript-eslint/ban-types
362
476
  const isPlainObject = function (value) {
363
477
  if (!isObjectLike(value) || !isType(value, 'Object')) {
364
478
  return false;
@@ -377,6 +491,19 @@
377
491
  return value === undefined;
378
492
  };
379
493
 
494
+ /**
495
+ * Checks if `value` is classified as a `String` primitive or object.
496
+ * @param {*} value The value to check.
497
+ * @param {boolean} fuzzy Whether to perform fuzzy judgment, for better performance,default to `false`.
498
+ * @returns {boolean} Returns `true` if `value` is a string, else `false`.
499
+ * @example
500
+ *
501
+ * isString('abc')
502
+ * // => true
503
+ *
504
+ * isString(1)
505
+ * // => false
506
+ */
380
507
  const isString = (value, fuzzy = false) => {
381
508
  const type = typeof value;
382
509
  if (fuzzy) {
@@ -397,6 +524,29 @@
397
524
  return isType(value, 'Date');
398
525
  };
399
526
 
527
+ /**
528
+ * Checks if `value` is classified as a `Number` primitive or object.
529
+ *
530
+ * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are
531
+ * classified as numbers, use the `Number.isFinite` method.
532
+ *
533
+ * @param {*} value The value to check.
534
+ * @param {boolean} fuzzy Whether to perform fuzzy judgment, for better performance,default to `false`.
535
+ * @returns {boolean} Returns `true` if `value` is a number, else `false`.
536
+ * @example
537
+ *
538
+ * isNumber(3)
539
+ * // => true
540
+ *
541
+ * isNumber(Number.MIN_VALUE)
542
+ * // => true
543
+ *
544
+ * isNumber(Infinity)
545
+ * // => true
546
+ *
547
+ * isNumber('3')
548
+ * // => false
549
+ */
400
550
  const isNumber = (value, fuzzy = false) => {
401
551
  const type = typeof value;
402
552
  if (fuzzy) {
@@ -405,6 +555,31 @@
405
555
  return type === 'number' || isType(value, 'Number');
406
556
  };
407
557
 
558
+ /**
559
+ * Checks if `value` is classified as a legal string number
560
+ *
561
+ * @param {*} value The string value to check.
562
+ * @returns {boolean} Returns `true` if `value` is a legal string number, else `false`.
563
+ * @example
564
+ *
565
+ * isNumeric(1)
566
+ * // => false
567
+ *
568
+ * isNumeric('2.0')
569
+ * // => true
570
+ *
571
+ * isNumeric('3a')
572
+ * // => false
573
+ *
574
+ * isNumeric('4.a')
575
+ * // => false
576
+ *
577
+ * isNumeric(Infinity)
578
+ * // => false
579
+ *
580
+ * isNumeric('01')
581
+ * // => true
582
+ */
408
583
  const isNumeric = (value) => {
409
584
  if (typeof value !== 'string') {
410
585
  return false;
@@ -413,10 +588,12 @@
413
588
  };
414
589
 
415
590
  const isValidNumber = (value) => {
591
+ // isFinate 包含来 isNaN 的判断
416
592
  return isNumber(value) && Number.isFinite(value);
417
593
  };
418
594
 
419
595
  const isValidUrl = (value) => {
596
+ // TODO: 匹配其他形式的 url
420
597
  const exp = /^(http(s)?:\/\/)\w+[^\s]+(\.[^\s]+){1,}$/;
421
598
  const urlPattern = new RegExp(exp);
422
599
  return urlPattern.test(value);
@@ -426,6 +603,12 @@
426
603
  return isType(value, 'RegExp');
427
604
  };
428
605
 
606
+ /**
607
+ * 迁移至 sirius
608
+ * Checks if `value` is classified as a `Base64` string;
609
+ * @param {string} The value to check.
610
+ * @returns {boolean} Returns `true` if `value` is a boolean, else `false`.
611
+ */
429
612
  const isBase64 = (value) => {
430
613
  const exp = /^data:image\/(?:gif|png|jpeg|bmp|webp|svg\+xml)(?:;charset=utf-8)?;base64,(?:[A-Za-z0-9]|[+/])+={0,2}/g;
431
614
  const urlPattern = new RegExp(exp);
@@ -448,12 +631,22 @@
448
631
 
449
632
  const hasOwnProperty$2 = Object.prototype.hasOwnProperty;
450
633
  function isEmpty(value) {
634
+ /**
635
+ * isEmpty(null) => true
636
+ * isEmpty() => true
637
+ * isEmpty(true) => true
638
+ * isEmpty(1) => true
639
+ * isEmpty([1, 2, 3]) => false
640
+ * isEmpty('abc') => false
641
+ * isEmpty({ a: 1 }) => false
642
+ */
451
643
  if (isNil(value)) {
452
644
  return true;
453
645
  }
454
646
  if (isArrayLike(value)) {
455
647
  return !value.length;
456
648
  }
649
+ // TODO: 这里需要优化下
457
650
  const type = getType(value);
458
651
  if (type === 'Map' || type === 'Set') {
459
652
  return !value.size;
@@ -477,7 +670,25 @@
477
670
  return obj === undefined ? defaultValue : obj;
478
671
  };
479
672
 
673
+ /** Used to check objects for own properties. */
480
674
  const hasOwnProperty$1 = Object.prototype.hasOwnProperty;
675
+ /**
676
+ * Checks if `key` is a direct property of `object`.
677
+ *
678
+ * @param {Object} object The object to query.
679
+ * @param {string} key The key to check.
680
+ * @returns {boolean} Returns `true` if `key` exists, else `false`.
681
+ * @example
682
+ *
683
+ * const object = { 'a': { 'b': 2 } }
684
+ * const other = create({ 'a': create({ 'b': 2 }) })
685
+ *
686
+ * has(object, 'a')
687
+ * // => true
688
+ *
689
+ * has(other, 'a')
690
+ * // => false
691
+ */
481
692
  const has = (object, key) => {
482
693
  return object != null && hasOwnProperty$1.call(object, key);
483
694
  };
@@ -489,7 +700,11 @@
489
700
  re.multiline && (flags += 'm');
490
701
  return flags;
491
702
  }
703
+ // Adapted from https://github.com/pvorb/clone by Paul Vorbach
704
+ // License: https://github.com/pvorb/clone/blob/master/LICENSE
492
705
  function clone(parent, circular = false, depth = 0, prototype = undefined) {
706
+ // maintain two arrays for circular references, where corresponding parents
707
+ // and children have the same index
493
708
  const allParents = [];
494
709
  const allChildren = [];
495
710
  if (typeof circular === 'undefined') {
@@ -498,7 +713,9 @@
498
713
  if (typeof depth === 'undefined') {
499
714
  depth = Infinity;
500
715
  }
716
+ // recurse this function so we don't reset allParents and allChildren
501
717
  function _clone(parent, depth) {
718
+ // cloning null always returns null
502
719
  if (parent === null) {
503
720
  return null;
504
721
  }
@@ -552,21 +769,27 @@
552
769
  }
553
770
  const isArr = isArray(value);
554
771
  const length = value.length;
772
+ // 不考虑特殊数组的额外处理
555
773
  if (isArr) {
556
774
  result = new Array(length);
557
775
  }
776
+ // 不考虑 buffer / arguments 类型的处理以及 prototype 的额外处理
558
777
  else if (typeof value === 'object') {
559
778
  result = {};
560
779
  }
780
+ // 不建议使用作为 Boolean / Number / String 作为构造器
561
781
  else if (isBoolean(value) || isNumber(value) || isString(value)) {
562
782
  result = value;
563
783
  }
564
784
  else if (isDate(value)) {
565
785
  result = new Date(+value);
566
786
  }
787
+ // 不考虑 ArrayBuffer / DataView / TypedArray / map / set / regexp / symbol 类型
567
788
  else {
568
789
  result = undefined;
569
790
  }
791
+ // 不考虑 map / set / TypedArray 类型的赋值
792
+ // 不考虑对象的 symbol 属性
570
793
  const props = isArr ? undefined : Object.keys(Object(value));
571
794
  let index = -1;
572
795
  if (result) {
@@ -590,8 +813,10 @@
590
813
  return;
591
814
  }
592
815
  if (isValid(source) && typeof source === 'object') {
816
+ // baseFor
593
817
  const iterable = Object(source);
594
818
  const props = [];
819
+ // keysIn
595
820
  for (const key in iterable) {
596
821
  props.push(key);
597
822
  }
@@ -599,6 +824,7 @@
599
824
  let propIndex = -1;
600
825
  while (length--) {
601
826
  const key = props[++propIndex];
827
+ // skipArray 这个是vchart spec的特有逻辑
602
828
  if (isValid(iterable[key]) &&
603
829
  typeof iterable[key] === 'object' &&
604
830
  (!skipTargetArray || !isArray(target[key]))) {
@@ -611,19 +837,24 @@
611
837
  }
612
838
  }
613
839
  }
840
+ // 由于目前 ChartSpace 内部对 spec 会先执行一次深拷贝,merge 暂时不考虑 source 中有环的问题
841
+ // eslint-disable-next-line @typescript-eslint/ban-types
614
842
  function baseMergeDeep(target, source, key, shallowArray = false, skipTargetArray = false) {
615
843
  const objValue = target[key];
616
844
  const srcValue = source[key];
617
845
  let newValue = source[key];
618
846
  let isCommon = true;
847
+ // 不考虑 buffer / typedArray 类型
619
848
  if (isArray(srcValue)) {
620
849
  if (shallowArray) {
850
+ // 依据参数对数组做浅拷贝
621
851
  newValue = [];
622
852
  }
623
853
  else if (isArray(objValue)) {
624
854
  newValue = objValue;
625
855
  }
626
856
  else if (isArrayLike(objValue)) {
857
+ // 如果 source 为数组,则 target 的 arrayLike 对象也视作为数组处理
627
858
  newValue = new Array(objValue.length);
628
859
  let index = -1;
629
860
  const length = objValue.length;
@@ -632,8 +863,13 @@
632
863
  }
633
864
  }
634
865
  }
866
+ // else if (isArray(srcValue) && shallowArray) {
867
+ // newValue = [];
868
+ // }
869
+ // 不考虑 argument 类型
635
870
  else if (isPlainObject(srcValue)) {
636
871
  newValue = objValue !== null && objValue !== void 0 ? objValue : {};
872
+ // 不考虑 prototype 的额外处理
637
873
  if (typeof objValue === 'function' || typeof objValue !== 'object') {
638
874
  newValue = {};
639
875
  }
@@ -641,19 +877,24 @@
641
877
  else {
642
878
  isCommon = false;
643
879
  }
880
+ // 对 class 等复杂对象或者浅拷贝的 array 不做拷贝处理
644
881
  if (isCommon) {
645
882
  baseMerge(newValue, srcValue, shallowArray, skipTargetArray);
646
883
  }
647
884
  assignMergeValue(target, key, newValue);
648
885
  }
886
+ // eslint-disable-next-line @typescript-eslint/ban-types
649
887
  function assignMergeValue(target, key, value) {
650
888
  if ((value !== undefined && !eq(target[key], value)) || (value === undefined && !(key in target))) {
889
+ // 不考虑 __proto__ 的赋值处理
651
890
  target[key] = value;
652
891
  }
653
892
  }
654
893
  function eq(value, other) {
655
894
  return value === other || (Number.isNaN(value) && Number.isNaN(other));
656
895
  }
896
+ // 与原生的 lodash merge 差异在于对数组是否应用最后一个 source 的结果
897
+ // 例如 lineDash 等 spec 的 merge 使用这一操作更合适
657
898
  function merge(target, ...sources) {
658
899
  let sourceIndex = -1;
659
900
  const length = sources.length;
@@ -707,6 +948,8 @@
707
948
  function objectKeys(obj) {
708
949
  return Object.keys(obj);
709
950
  }
951
+ // Adapted from https://github.com/antvis/F2/blob/master/packages/f2/src/base/equal.ts by zengyue
952
+ // License: https://github.com/antvis/F2/blob/master/packages/f2/LICENSE
710
953
  function isEqual(a, b, options) {
711
954
  if (a === b) {
712
955
  return true;
@@ -714,18 +957,22 @@
714
957
  if (typeof a !== typeof b) {
715
958
  return false;
716
959
  }
960
+ // null 和 undefined
717
961
  if (a == null || b == null) {
718
962
  return false;
719
963
  }
964
+ // 特殊处理NaN
720
965
  if (Number.isNaN(a) && Number.isNaN(b)) {
721
966
  return true;
722
967
  }
723
968
  if (objToString(a) !== objToString(b)) {
724
969
  return false;
725
970
  }
971
+ // 如果是function,则不相等
726
972
  if (isFunction(a)) {
727
973
  return !!(options === null || options === void 0 ? void 0 : options.skipFunction);
728
974
  }
975
+ // 值类型,Number String Boolean
729
976
  if (typeof a !== 'object') {
730
977
  return false;
731
978
  }
@@ -745,16 +992,21 @@
745
992
  }
746
993
  const ka = objectKeys(a);
747
994
  const kb = objectKeys(b);
995
+ // having the same number of owned properties (keys incorporates hasOwnProperty)
748
996
  if (ka.length !== kb.length) {
749
997
  return false;
750
998
  }
999
+ // the same set of keys (although not necessarily the same order),
751
1000
  ka.sort();
752
1001
  kb.sort();
1002
+ // ~~~cheap key test
753
1003
  for (let i = ka.length - 1; i >= 0; i--) {
1004
+ // eslint-disable-next-line eqeqeq
754
1005
  if (ka[i] != kb[i]) {
755
1006
  return false;
756
1007
  }
757
1008
  }
1009
+ // equivalent values for every corresponding key, and ~~~possibly expensive deep test
758
1010
  for (let i = ka.length - 1; i >= 0; i--) {
759
1011
  const key = ka[i];
760
1012
  if (!isEqual(a[key], b[key], options)) {
@@ -768,7 +1020,8 @@
768
1020
  if (x === y) {
769
1021
  return x !== 0 || y !== 0 || 1 / x === 1 / y;
770
1022
  }
771
- return x !== x && y !== y;
1023
+ // eslint-disable-next-line no-self-compare
1024
+ return x !== x && y !== y; // NaN == NaN
772
1025
  }
773
1026
  function length(obj) {
774
1027
  if (isArray(obj)) {
@@ -804,6 +1057,7 @@
804
1057
  return ret;
805
1058
  }
806
1059
 
1060
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint
807
1061
  function keys(obj) {
808
1062
  if (!obj) {
809
1063
  return [];
@@ -813,6 +1067,7 @@
813
1067
  }
814
1068
  const keyList = [];
815
1069
  for (const key in obj) {
1070
+ // eslint-disable-next-line no-prototype-builtins
816
1071
  if (obj.hasOwnProperty(key)) {
817
1072
  keyList.push(key);
818
1073
  }
@@ -829,9 +1084,16 @@
829
1084
  }
830
1085
  return target;
831
1086
  }
1087
+ // eslint-disable-next-line @typescript-eslint/ban-types
832
1088
  function mixin(target, source, override = true) {
1089
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1090
+ // @ts-ignore
833
1091
  target = 'prototype' in target ? target.prototype : target;
1092
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1093
+ // @ts-ignore
834
1094
  source = 'prototype' in source ? source.prototype : source;
1095
+ // If build target is ES6 class. prototype methods is not enumerable. Use getOwnPropertyNames instead
1096
+ // TODO: Determine if source is ES6 class?
835
1097
  if (Object.getOwnPropertyNames) {
836
1098
  const keyList = Object.getOwnPropertyNames(source);
837
1099
  for (let i = 0; i < keyList.length; i++) {
@@ -848,12 +1110,22 @@
848
1110
  }
849
1111
  }
850
1112
 
1113
+ /**
1114
+ * 将传入数据转换为数组格式
1115
+ * @param arr 入参。
1116
+ * @returns 数组
1117
+ */
851
1118
  function array(arr) {
852
1119
  if (isValid(arr)) {
853
1120
  return isArray(arr) ? arr : [arr];
854
1121
  }
855
1122
  return [];
856
1123
  }
1124
+ /**
1125
+ * 获取数组的最后一个值,如果传入的参数为非数组,则返回 undefined
1126
+ * @param val any
1127
+ * @returns
1128
+ */
857
1129
  function last(val) {
858
1130
  if (isArrayLike(val)) {
859
1131
  const arr = val;
@@ -861,12 +1133,23 @@
861
1133
  }
862
1134
  return undefined;
863
1135
  }
1136
+ /**
1137
+ * 获取数组第一项与最后一项的差值,如果数组为空则返回 0
1138
+ * @param arr
1139
+ * @returns
1140
+ */
864
1141
  const span = (arr) => {
865
1142
  if (arr.length <= 1) {
866
1143
  return 0;
867
1144
  }
868
1145
  return last(arr) - arr[0];
869
1146
  };
1147
+ /**
1148
+ * 获取数组中的最大值
1149
+ * @param arr 数组
1150
+ * @param compareFn 比较函数,返回正数表示 a > b,返回负数表示 a < b,返回 0 表示相等
1151
+ * @returns
1152
+ */
870
1153
  const maxInArray = (arr, compareFn) => {
871
1154
  var _a;
872
1155
  if (arr.length === 0) {
@@ -881,6 +1164,12 @@
881
1164
  }
882
1165
  return max;
883
1166
  };
1167
+ /**
1168
+ * 获取数组中的最小值
1169
+ * @param arr 数组
1170
+ * @param compareFn 比较函数,返回正数表示 a > b,返回负数表示 a < b,返回 0 表示相等
1171
+ * @returns
1172
+ */
884
1173
  const minInArray = (arr, compareFn) => {
885
1174
  var _a;
886
1175
  if (arr.length === 0) {
@@ -895,6 +1184,12 @@
895
1184
  }
896
1185
  return min;
897
1186
  };
1187
+ /**
1188
+ * 判断两个数组是否相同
1189
+ * @param a
1190
+ * @param b
1191
+ * @returns
1192
+ */
898
1193
  function arrayEqual(a, b) {
899
1194
  if (!isArray(a) || !isArray(b)) {
900
1195
  return false;
@@ -909,12 +1204,18 @@
909
1204
  }
910
1205
  return true;
911
1206
  }
1207
+ /**
1208
+ * 封装并返回无重复的数组
1209
+ * @param arr
1210
+ * @returns
1211
+ */
912
1212
  function uniqArray(arr) {
913
1213
  if (!arr || !isArray(arr)) {
914
1214
  return arr;
915
1215
  }
916
1216
  return Array.from(new Set(array(arr)));
917
1217
  }
1218
+ // Based on http://jsfromhell.com/array/shuffle
918
1219
  function shuffleArray(arr, random = Math.random) {
919
1220
  let j;
920
1221
  let x;
@@ -927,6 +1228,11 @@
927
1228
  }
928
1229
  return arr;
929
1230
  }
1231
+ /**
1232
+ * 展开多层数组,非数组内容将变为 [input]
1233
+ * @param arr
1234
+ * @returns
1235
+ */
930
1236
  function flattenArray(arr) {
931
1237
  if (!isArray(arr)) {
932
1238
  return [arr];
@@ -981,11 +1287,74 @@
981
1287
  return value0 + (value1 - value0) * (i - i0);
982
1288
  }
983
1289
 
1290
+ /**
1291
+ * Approximate inverse normal CDF (probit) using Acklam's algorithm.
1292
+ * Returns z such that P(Z <= z) = p for standard normal Z.
1293
+ */
1294
+ function normalQuantile(p) {
1295
+ if (p === 0) {
1296
+ return -Infinity;
1297
+ }
1298
+ if (p === 1) {
1299
+ return Infinity;
1300
+ }
1301
+ if (!Number.isFinite(p) || p < 0 || p > 1) {
1302
+ return NaN;
1303
+ }
1304
+ const a1 = -39.6968302866538;
1305
+ const a2 = 220.946098424521;
1306
+ const a3 = -275.928510446969;
1307
+ const a4 = 138.357751867269;
1308
+ const a5 = -30.6647980661472;
1309
+ const a6 = 2.50662827745924;
1310
+ const b1 = -54.4760987982241;
1311
+ const b2 = 161.585836858041;
1312
+ const b3 = -155.698979859887;
1313
+ const b4 = 66.8013118877197;
1314
+ const b5 = -13.2806815528857;
1315
+ const c1 = -0.00778489400243029;
1316
+ const c2 = -0.322396458041136;
1317
+ const c3 = -2.40075827716184;
1318
+ const c4 = -2.54973253934373;
1319
+ const c5 = 4.37466414146497;
1320
+ const c6 = 2.93816398269878;
1321
+ const d1 = 0.00778469570904146;
1322
+ const d2 = 0.32246712907004;
1323
+ const d3 = 2.445134137143;
1324
+ const d4 = 3.75440866190742;
1325
+ const pLow = 0.02425;
1326
+ const pHigh = 1 - pLow;
1327
+ let q;
1328
+ let r;
1329
+ if (p < pLow) {
1330
+ q = Math.sqrt(-2 * Math.log(p));
1331
+ return (((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) / ((((d1 * q + d2) * q + d3) * q + d4) * q + 1);
1332
+ }
1333
+ if (p <= pHigh) {
1334
+ q = p - 0.5;
1335
+ r = q * q;
1336
+ return (((((((a1 * r + a2) * r + a3) * r + a4) * r + a5) * r + a6) * q) /
1337
+ (((((b1 * r + b2) * r + b3) * r + b4) * r + b5) * r + 1));
1338
+ }
1339
+ q = Math.sqrt(-2 * Math.log(1 - p));
1340
+ return -((((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) / ((((d1 * q + d2) * q + d3) * q + d4) * q + 1));
1341
+ }
1342
+
1343
+ /* Adapted from vega by University of Washington Interactive Data Lab
1344
+ * https://vega.github.io/vega/
1345
+ * Licensed under the BSD-3-Clause
1346
+
1347
+ * url: https://github.com/vega/vega/blob/main/packages/vega-util/src/logger.js
1348
+ * License: https://github.com/vega/vega/blob/main/LICENSE
1349
+ * @license
1350
+ */
1351
+ // check console
984
1352
  const hasConsole = typeof console !== 'undefined';
985
1353
  function log(method, level, input) {
986
1354
  const args = [level].concat([].slice.call(input));
987
1355
  if (hasConsole) {
988
- console[method].apply(console, args);
1356
+ // eslint-disable-next-line prefer-spread, no-undef
1357
+ console[method].apply(console, args); // eslint-disable-line no-console
989
1358
  }
990
1359
  }
991
1360
  exports.LoggerLevel = void 0;
@@ -1093,6 +1462,14 @@
1093
1462
  }
1094
1463
  Logger._instance = null;
1095
1464
 
1465
+ /**
1466
+ * 通过二分法,查找数组a中大于数值x的第一个元素的序号
1467
+ * @param a
1468
+ * @param x
1469
+ * @param lo
1470
+ * @param hi
1471
+ * @returns
1472
+ */
1096
1473
  function bisect(a, x, lo = 0, hi) {
1097
1474
  if (isNil(hi)) {
1098
1475
  hi = a.length;
@@ -1108,6 +1485,16 @@
1108
1485
  }
1109
1486
  return lo;
1110
1487
  }
1488
+ /* Adapted from fmin by Ben Frederickson
1489
+ * https://github.com/benfred/fmin
1490
+ * Licensed under the BSD-3-Clause
1491
+
1492
+ * url: https://github.com/benfred/fmin/blob/master/src/bisect.js
1493
+ * License: https://github.com/benfred/fmin/blob/master/LICENSE
1494
+ * @license
1495
+ */
1496
+ /** finds the zeros of a function, given two starting points (which must
1497
+ * have opposite signs */
1111
1498
  function findZeroOfFunction(f, a, b, parameters) {
1112
1499
  var _a, _b;
1113
1500
  const maxIterations = (_a = parameters === null || parameters === void 0 ? void 0 : parameters.maxIterations) !== null && _a !== void 0 ? _a : 100;
@@ -1139,16 +1526,27 @@
1139
1526
  }
1140
1527
  return a + delta;
1141
1528
  }
1529
+ /**
1530
+ * 二分靠近框架,返回数组中第一个大于等于目标值的数的索引
1531
+ * @param arr 数组
1532
+ * @param compareFn 比较函数,返回(当前值-目标值)
1533
+ */
1142
1534
  const binaryFuzzySearch = (arr, compareFn) => {
1143
1535
  return binaryFuzzySearchInNumberRange(0, arr.length, value => compareFn(arr[value]));
1144
1536
  };
1537
+ /**
1538
+ * 二分靠近框架,返回数字区间中第一个大于等于目标值的数字
1539
+ * @param x1 区间上界
1540
+ * @param x2 区间下界(不包含)
1541
+ * @param compareFn 比较函数,返回(当前值-目标值)
1542
+ */
1145
1543
  const binaryFuzzySearchInNumberRange = (x1, x2, compareFn) => {
1146
1544
  let left = x1;
1147
1545
  let right = x2;
1148
1546
  while (left < right) {
1149
1547
  const mid = Math.floor((left + right) / 2);
1150
1548
  if (compareFn(mid) >= 0) {
1151
- right = mid;
1549
+ right = mid; // 第一个大于等于目标值的数
1152
1550
  }
1153
1551
  else {
1154
1552
  left = mid + 1;
@@ -1219,16 +1617,40 @@
1219
1617
  return stop < start ? -step1 : step1;
1220
1618
  }
1221
1619
 
1620
+ /**
1621
+ * @description 处理数值相关的方法
1622
+ */
1222
1623
  const DEFAULT_ABSOLUTE_TOLERATE = 1e-10;
1223
1624
  const DEFAULT_RELATIVE_TOLERATE = 1e-10;
1625
+ /**
1626
+ * 判断两数是否接近相等,函数参数参照 python isClose 方法
1627
+ * @param {number} a
1628
+ * @param {number} b
1629
+ * @param refTol 指定的相对容差比例,将乘以两数的最大值作为相对容差
1630
+ * @param absTol 指定的绝对容差
1631
+ */
1224
1632
  function isNumberClose(a, b, relTol = DEFAULT_RELATIVE_TOLERATE, absTol = DEFAULT_ABSOLUTE_TOLERATE) {
1225
1633
  const abs = absTol;
1226
1634
  const rel = relTol * Math.max(a, b);
1227
1635
  return Math.abs(a - b) <= Math.max(abs, rel);
1228
1636
  }
1637
+ /**
1638
+ * 判断 a 是否大于 b,并排除容差范围
1639
+ * @param a
1640
+ * @param b
1641
+ * @param relTol 指定的相对容差比例,将乘以两数的最大值作为相对容差
1642
+ * @param absTol 指定的绝对容差
1643
+ */
1229
1644
  function isGreater(a, b, relTol, absTol) {
1230
1645
  return a > b && !isNumberClose(a, b, relTol, absTol);
1231
1646
  }
1647
+ /**
1648
+ * 判断 a 是否小于 b,并排除容差范围
1649
+ * @param a
1650
+ * @param b
1651
+ * @param relTol 指定的相对容差比例,将乘以两数的最大值作为相对容差
1652
+ * @param absTol 指定的绝对容差
1653
+ */
1232
1654
  function isLess(a, b, relTol, absTol) {
1233
1655
  return a < b && !isNumberClose(a, b, relTol, absTol);
1234
1656
  }
@@ -1263,6 +1685,27 @@
1263
1685
  }
1264
1686
  return s;
1265
1687
  };
1688
+ /**
1689
+ * Pads `string` on the left and right, left or right sides if it's shorter than `length`.
1690
+ * Padding characters are truncated if they can't be evenly divided by `length`.
1691
+ *
1692
+ * @since 3.0.0
1693
+ * @category String
1694
+ * @param {string} [string=''] The string to pad.
1695
+ * @param {number} [length=0] The padding length.
1696
+ * @param {string} [chars=' '] The string used as padding.
1697
+ * @returns {string} Returns the padded string.
1698
+ * @example
1699
+ *
1700
+ * pad('abc', 8)
1701
+ * // => ' abc '
1702
+ *
1703
+ * pad('abc', 8, '_-')
1704
+ * // => '_-abc_-_'
1705
+ *
1706
+ * pad('abc', 2)
1707
+ * // => 'abc'
1708
+ */
1266
1709
  const pad = (str, length, padChar = ' ', align = 'right') => {
1267
1710
  const c = padChar;
1268
1711
  const s = str + '';
@@ -1290,20 +1733,33 @@
1290
1733
  return align === 'center' ? s.slice(0, Math.ceil(l / 2)) + e + s.slice(n - Math.floor(l / 2)) : s.slice(0, l) + e;
1291
1734
  };
1292
1735
 
1736
+ // TODO: 性能不是很好,需要优化,后续升级到最新版本的 canvas 之后就可以删除了
1737
+ /**
1738
+ * 生成uuid字符串.
1739
+ * 参考https://github.com/yangjunning/issues/issues/56
1740
+ * @param len
1741
+ * @param radix
1742
+ * @returns
1743
+ */
1293
1744
  const uuid = (len, radix) => {
1294
1745
  const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
1295
1746
  const uuid = [];
1296
1747
  let i;
1297
1748
  radix = radix || chars.length;
1298
1749
  if (len) {
1750
+ // Compact form
1299
1751
  for (i = 0; i < len; i++) {
1300
1752
  uuid[i] = chars[0 | (Math.random() * radix)];
1301
1753
  }
1302
1754
  }
1303
1755
  else {
1756
+ // rfc4122, version 4 form
1304
1757
  let r;
1758
+ // rfc4122 requires these characters
1305
1759
  uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
1306
1760
  uuid[14] = '4';
1761
+ // Fill in random data. At i==19 set the high bits of clock sequence as
1762
+ // per rfc4122, sec. 4.1.5
1307
1763
  for (i = 0; i < 36; i++) {
1308
1764
  if (!uuid[i]) {
1309
1765
  r = 0 | (Math.random() * 16);
@@ -1350,6 +1806,9 @@
1350
1806
  };
1351
1807
  }
1352
1808
 
1809
+ /**
1810
+ * @see https://github.com/lodash/lodash/blob/master/debounce.js
1811
+ */
1353
1812
  let hasRaf = false;
1354
1813
  try {
1355
1814
  hasRaf = typeof requestAnimationFrame === 'function' && typeof cancelAnimationFrame === 'function';
@@ -1363,12 +1822,14 @@
1363
1822
  let lastThis;
1364
1823
  let maxWait;
1365
1824
  let result;
1825
+ // eslint-disable-next-line no-undef
1366
1826
  let timerId;
1367
1827
  let lastCallTime;
1368
1828
  let lastInvokeTime = 0;
1369
1829
  let leading = false;
1370
1830
  let maxing = false;
1371
1831
  let trailing = true;
1832
+ // Bypass `requestAnimationFrame` by explicitly setting `wait=0`.
1372
1833
  const useRAF = !wait && wait !== 0 && hasRaf;
1373
1834
  if (typeof func !== 'function') {
1374
1835
  throw new TypeError('Expected a function');
@@ -1404,8 +1865,11 @@
1404
1865
  clearTimeout(id);
1405
1866
  }
1406
1867
  function leadingEdge(time) {
1868
+ // Reset any `maxWait` timer.
1407
1869
  lastInvokeTime = time;
1870
+ // Start the timer for the trailing edge.
1408
1871
  timerId = startTimer(timerExpired, wait);
1872
+ // Invoke the leading edge.
1409
1873
  return leading ? invokeFunc(time) : result;
1410
1874
  }
1411
1875
  function remainingWait(time) {
@@ -1417,6 +1881,9 @@
1417
1881
  function shouldInvoke(time) {
1418
1882
  const timeSinceLastCall = time - lastCallTime;
1419
1883
  const timeSinceLastInvoke = time - lastInvokeTime;
1884
+ // Either this is the first call, activity has stopped and we're at the
1885
+ // trailing edge, the system time has gone backwards and we're treating
1886
+ // it as the trailing edge, or we've hit the `maxWait` limit.
1420
1887
  return (lastCallTime === undefined ||
1421
1888
  timeSinceLastCall >= wait ||
1422
1889
  timeSinceLastCall < 0 ||
@@ -1427,10 +1894,13 @@
1427
1894
  if (shouldInvoke(time)) {
1428
1895
  return trailingEdge(time);
1429
1896
  }
1897
+ // Restart the timer.
1430
1898
  timerId = startTimer(timerExpired, remainingWait(time));
1431
1899
  }
1432
1900
  function trailingEdge(time) {
1433
1901
  timerId = undefined;
1902
+ // Only invoke if we have `lastArgs` which means `func` has been
1903
+ // debounced at least once.
1434
1904
  if (trailing && lastArgs) {
1435
1905
  return invokeFunc(time);
1436
1906
  }
@@ -1454,6 +1924,7 @@
1454
1924
  const time = Date.now();
1455
1925
  const isInvoking = shouldInvoke(time);
1456
1926
  lastArgs = args;
1927
+ // @ts-ignore
1457
1928
  lastThis = this;
1458
1929
  lastCallTime = time;
1459
1930
  if (isInvoking) {
@@ -1461,6 +1932,7 @@
1461
1932
  return leadingEdge(lastCallTime);
1462
1933
  }
1463
1934
  if (maxing) {
1935
+ // Handle invocations in a tight loop.
1464
1936
  timerId = startTimer(timerExpired, wait);
1465
1937
  return invokeFunc(lastCallTime);
1466
1938
  }
@@ -1476,6 +1948,9 @@
1476
1948
  return debounced;
1477
1949
  }
1478
1950
 
1951
+ /**
1952
+ * @see https://github.com/lodash/lodash/blob/master/throttle.js
1953
+ */
1479
1954
  function throttle(func, wait, options) {
1480
1955
  let leading = true;
1481
1956
  let trailing = true;
@@ -1525,47 +2000,55 @@
1525
2000
  };
1526
2001
  }
1527
2002
  function interpolateString(a, b) {
1528
- let bi = (reA.lastIndex = reB.lastIndex = 0);
1529
- let am;
1530
- let bm;
1531
- let bs;
1532
- let i = -1;
1533
- const s = [];
1534
- const q = [];
2003
+ let bi = (reA.lastIndex = reB.lastIndex = 0); // scan index for next number in b
2004
+ let am; // current match in a
2005
+ let bm; // current match in b
2006
+ let bs; // string preceding current number in b, if any
2007
+ let i = -1; // index in s
2008
+ const s = []; // string constants and placeholders
2009
+ const q = []; // number interpolators
2010
+ // Coerce inputs to strings.
1535
2011
  (a = a + ''), (b = b + '');
2012
+ // Interpolate pairs of numbers in a & b.
1536
2013
  while ((am = reA.exec(a)) && (bm = reB.exec(b))) {
1537
2014
  if ((bs = bm.index) > bi) {
2015
+ // a string precedes the next number in b
1538
2016
  bs = b.slice(bi, bs);
1539
2017
  if (s[i]) {
1540
2018
  s[i] += bs;
1541
- }
2019
+ } // coalesce with previous string
1542
2020
  else {
1543
2021
  s[++i] = bs;
1544
2022
  }
1545
2023
  }
1546
2024
  if ((am = am[0]) === (bm = bm[0])) {
2025
+ // numbers in a & b match
1547
2026
  if (s[i]) {
1548
2027
  s[i] += bm;
1549
- }
2028
+ } // coalesce with previous string
1550
2029
  else {
1551
2030
  s[++i] = bm;
1552
2031
  }
1553
2032
  }
1554
2033
  else {
2034
+ // interpolate non-matching numbers
1555
2035
  s[++i] = null;
1556
2036
  q.push({ i: i, x: interpolateNumber(am, bm) });
1557
2037
  }
1558
2038
  bi = reB.lastIndex;
1559
2039
  }
2040
+ // Add remains of b.
1560
2041
  if (bi < b.length) {
1561
2042
  bs = b.slice(bi);
1562
2043
  if (s[i]) {
1563
2044
  s[i] += bs;
1564
- }
2045
+ } // coalesce with previous string
1565
2046
  else {
1566
2047
  s[++i] = bs;
1567
2048
  }
1568
2049
  }
2050
+ // Special optimization for only a single match.
2051
+ // Otherwise, interpolate each of the numbers and rejoin the string.
1569
2052
  return s.length < 2
1570
2053
  ? q[0]
1571
2054
  ? one(q[0].x)
@@ -1579,19 +2062,36 @@
1579
2062
  });
1580
2063
  }
1581
2064
 
1582
- const TIME_REG = /^(?:(\d{4})(?:[-\/](\d{1,2})(?:[-\/](\d{1,2})(?:[T ](\d{1,2})(?::(\d{1,2})(?::(\d{1,2})(?:[.,](\d+))?)?)?(Z|[\+\-]\d\d:?\d\d)?)?)?)?)?$/;
2065
+ // eslint-disable-next-line no-useless-escape
2066
+ const TIME_REG = /^(?:(\d{4})(?:[-\/](\d{1,2})(?:[-\/](\d{1,2})(?:[T ](\d{1,2})(?::(\d{1,2})(?::(\d{1,2})(?:[.,](\d+))?)?)?(Z|[\+\-]\d\d:?\d\d)?)?)?)?)?$/; // eslint-disable-line
1583
2067
  function toDate(val) {
1584
2068
  if (val instanceof Date) {
1585
2069
  return val;
1586
2070
  }
1587
2071
  else if (isString(val)) {
2072
+ // Different browsers parse date in different way, so we parse it manually.
2073
+ // Some other issues:
2074
+ // new Date('1970-01-01') is UTC,
2075
+ // new Date('1970/01/01') and new Date('1970-1-01') is local.
2076
+ // See issue #3623
1588
2077
  const match = TIME_REG.exec(val);
1589
2078
  if (!match) {
2079
+ // return Invalid Date.
1590
2080
  return new Date(NaN);
1591
2081
  }
2082
+ // Use local time when no timezone offset specifed.
1592
2083
  if (!match[8]) {
2084
+ // match[n] can only be string or undefined.
2085
+ // But take care of '12' + 1 => '121'.
1593
2086
  return new Date(+match[1], +(match[2] || 1) - 1, +match[3] || 1, +match[4] || 0, +(match[5] || 0), +match[6] || 0, match[7] ? +match[7].substring(0, 3) : 0);
1594
2087
  }
2088
+ // Timezoneoffset of Javascript Date has considered DST (Daylight Saving Time,
2089
+ // https://tc39.github.io/ecma262/#sec-daylight-saving-time-adjustment).
2090
+ // For example, system timezone is set as "Time Zone: America/Toronto",
2091
+ // then these code will get different result:
2092
+ // `new Date(1478411999999).getTimezoneOffset(); // get 240`
2093
+ // `new Date(1478412000000).getTimezoneOffset(); // get 300`
2094
+ // So we should not use `new Date`, but use `Date.UTC`.
1595
2095
  let hour = +match[4] || 0;
1596
2096
  if (match[8].toUpperCase() !== 'Z') {
1597
2097
  hour -= +match[8].slice(0, 3);
@@ -1635,13 +2135,25 @@
1635
2135
  function seedRandom(seed) {
1636
2136
  return parseFloat('0.' + Math.sin(seed).toString().substring(6));
1637
2137
  }
2138
+ /* Adapted from vega by University of Washington Interactive Data Lab
2139
+ * https://vega.github.io/vega/
2140
+ * Licensed under the BSD-3-Clause
2141
+
2142
+ * url: https://github.com/vega/vega/blob/main/packages/vega-statistics/src/lcg.js
2143
+ * License: https://github.com/vega/vega/blob/main/LICENSE
2144
+ * @license
2145
+ */
2146
+ // https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
1638
2147
  const a = 1664525;
1639
2148
  const c = 1013904223;
1640
- const m = 4294967296;
2149
+ const m = 4294967296; // 2^32
1641
2150
  function randomLCG(initS = 1) {
1642
2151
  let s = initS;
1643
2152
  return () => (s = (a * s + c) % m) / m;
1644
2153
  }
2154
+ /**
2155
+ * 随机拟合
2156
+ */
1645
2157
  const fakeRandom = () => {
1646
2158
  let i = -1;
1647
2159
  const arr = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9];
@@ -1670,6 +2182,9 @@
1670
2182
  }
1671
2183
  return fieldSingle(fieldStr, opt);
1672
2184
  };
2185
+ /**
2186
+ * 取数逻辑
2187
+ */
1673
2188
  const simpleField = (option) => {
1674
2189
  if (!option) {
1675
2190
  return null;
@@ -1692,12 +2207,17 @@
1692
2207
 
1693
2208
  const zero = (_) => 0;
1694
2209
 
2210
+ /**
2211
+ * Return an array with minimum and maximum values, in the
2212
+ * form [min, max]. Ignores null, undefined, and NaN values.
2213
+ */
1695
2214
  const extent = (array, func) => {
1696
2215
  const valueGetter = isFunction(func) ? func : (val) => val;
1697
2216
  let min;
1698
2217
  let max;
1699
2218
  if (array && array.length) {
1700
2219
  const n = array.length;
2220
+ // find first valid value
1701
2221
  for (let i = 0; i < n; i += 1) {
1702
2222
  let value = valueGetter(array[i]);
1703
2223
  if (!isNil(value) && isNumber((value = +value)) && !Number.isNaN(value)) {
@@ -1716,49 +2236,26 @@
1716
2236
  return [min, max];
1717
2237
  };
1718
2238
 
1719
- function invNorm(p) {
1720
- if (p <= 0 || p >= 1) {
1721
- return 0;
1722
- }
1723
- const a1 = -39.6968302866538;
1724
- const a2 = 220.946098424521;
1725
- const a3 = -275.928510446969;
1726
- const a4 = 138.357751867269;
1727
- const a5 = -30.6647980661472;
1728
- const a6 = 2.50662827745924;
1729
- const b1 = -54.4760987982241;
1730
- const b2 = 161.585836858041;
1731
- const b3 = -155.698979859887;
1732
- const b4 = 66.8013118877197;
1733
- const b5 = -13.2806815528857;
1734
- const c1 = -0.00778489400243029;
1735
- const c2 = -0.322396458041136;
1736
- const c3 = -2.40075827716184;
1737
- const c4 = -2.54973253934373;
1738
- const c5 = 4.37466414146497;
1739
- const c6 = 2.93816398269878;
1740
- const d1 = 0.00778469570904146;
1741
- const d2 = 0.32246712907004;
1742
- const d3 = 2.445134137143;
1743
- const d4 = 3.75440866190742;
1744
- const pLow = 0.02425;
1745
- const pHigh = 1 - pLow;
1746
- let q;
1747
- let r;
1748
- if (p < pLow) {
1749
- q = Math.sqrt(-2 * Math.log(p));
1750
- return (((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) / ((((d1 * q + d2) * q + d3) * q + d4) * q + 1);
2239
+ /** Compute a two-sided normal critical value without subtracting a small tail probability from one. */
2240
+ function confidenceCriticalValue(alpha) {
2241
+ if (!Number.isFinite(alpha) || alpha < 0 || alpha > 1) {
2242
+ return NaN;
1751
2243
  }
1752
- if (p <= pHigh) {
1753
- q = p - 0.5;
1754
- r = q * q;
1755
- return (((((((a1 * r + a2) * r + a3) * r + a4) * r + a5) * r + a6) * q) /
1756
- (((((b1 * r + b2) * r + b3) * r + b4) * r + b5) * r + 1));
2244
+ return -normalQuantile(alpha / 2);
2245
+ }
2246
+ /** A zero standard error gives a degenerate interval even when the critical value is infinite. */
2247
+ function confidenceHalfWidth(z, standardError) {
2248
+ if (Number.isNaN(z)) {
2249
+ return NaN;
1757
2250
  }
1758
- q = Math.sqrt(-2 * Math.log(1 - p));
1759
- return -((((((c1 * q + c2) * q + c3) * q + c4) * q + c5) * q + c6) / ((((d1 * q + d2) * q + d3) * q + d4) * q + 1));
2251
+ return standardError === 0 ? 0 : z * standardError;
1760
2252
  }
2253
+ /**
2254
+ * Compute basic components used for linear regression confidence / prediction intervals.
2255
+ * - scans data to compute min/max of x, n, mean X, SSE and Sxx (sum (xi - X)^2).
2256
+ */
1761
2257
  function computeLinearCIComponents(data, x, y, predict) {
2258
+ // simple local scanner to avoid circular imports
1762
2259
  let min = Infinity;
1763
2260
  let max = -Infinity;
1764
2261
  let n = 0;
@@ -1797,6 +2294,9 @@
1797
2294
  }
1798
2295
  return { min, max, n, X, SSE, Sxx };
1799
2296
  }
2297
+ /**
2298
+ * Compute standard errors for mean and prediction at px using components.
2299
+ */
1800
2300
  function stdErrorsAt(px, comps) {
1801
2301
  const { n, X, Sxx, SSE } = comps;
1802
2302
  const s2 = n > 2 ? SSE / (n - 2) : 0;
@@ -1805,6 +2305,10 @@
1805
2305
  return { seMean, sePred };
1806
2306
  }
1807
2307
 
2308
+ /**
2309
+ * Linear regression utilities (single clean implementation).
2310
+ * Exports: ordinaryLeastSquares, visitPoints, rSquared, regressionLinear
2311
+ */
1808
2312
  function ordinaryLeastSquares(uX, uY, uXY, uX2) {
1809
2313
  const denom = uX2 - uX * uX;
1810
2314
  if (Math.abs(denom) < Number.EPSILON) {
@@ -1843,6 +2347,7 @@
1843
2347
  function regressionLinear(data, x = d => d.x, y = d => d.y, options) {
1844
2348
  var _a;
1845
2349
  const alpha = (_a = options === null || options === void 0 ? void 0 : options.alpha) !== null && _a !== void 0 ? _a : 0.05;
2350
+ // accumulate online means (sufficient statistics)
1846
2351
  let n = 0;
1847
2352
  let meanX = 0;
1848
2353
  let meanY = 0;
@@ -1881,18 +2386,20 @@
1881
2386
  if (comps.n === 0 || N <= 0) {
1882
2387
  return out;
1883
2388
  }
1884
- const z = invNorm(1 - alpha / 2);
2389
+ const z = confidenceCriticalValue(alpha);
1885
2390
  if (comps.min === comps.max) {
1886
2391
  const m = predict(comps.min);
1887
2392
  const errs = stdErrorsAt(comps.min, comps);
2393
+ const meanHalfWidth = confidenceHalfWidth(z, errs.seMean);
2394
+ const predHalfWidth = confidenceHalfWidth(z, errs.sePred);
1888
2395
  for (let i = 0; i < N; i++) {
1889
2396
  out.push({
1890
2397
  x: comps.min,
1891
2398
  mean: m,
1892
- lower: m - z * errs.seMean,
1893
- upper: m + z * errs.seMean,
1894
- predLower: m - z * errs.sePred,
1895
- predUpper: m + z * errs.sePred
2399
+ lower: m - meanHalfWidth,
2400
+ upper: m + meanHalfWidth,
2401
+ predLower: m - predHalfWidth,
2402
+ predUpper: m + predHalfWidth
1896
2403
  });
1897
2404
  }
1898
2405
  return out;
@@ -1902,13 +2409,15 @@
1902
2409
  const px = i === N - 1 ? comps.max : comps.min + step * i;
1903
2410
  const m = predict(px);
1904
2411
  const errs = stdErrorsAt(px, comps);
2412
+ const meanHalfWidth = confidenceHalfWidth(z, errs.seMean);
2413
+ const predHalfWidth = confidenceHalfWidth(z, errs.sePred);
1905
2414
  out.push({
1906
2415
  x: px,
1907
2416
  mean: m,
1908
- lower: m - z * errs.seMean,
1909
- upper: m + z * errs.seMean,
1910
- predLower: m - z * errs.sePred,
1911
- predUpper: m + z * errs.sePred
2417
+ lower: m - meanHalfWidth,
2418
+ upper: m + meanHalfWidth,
2419
+ predLower: m - predHalfWidth,
2420
+ predUpper: m + predHalfWidth
1912
2421
  });
1913
2422
  }
1914
2423
  return out;
@@ -1922,11 +2431,18 @@
1922
2431
  };
1923
2432
  }
1924
2433
 
2434
+ /**
2435
+ * Simple logistic regression (binary) using Newton-Raphson (IRLS).
2436
+ * Returns { coef, predict, evaluateGrid }
2437
+ * - coef: [intercept, beta]
2438
+ * - predict(x): probability p(y=1|x)
2439
+ */
1925
2440
  function regressionLogistic(data, x = d => d.x, y = d => d.y, options) {
1926
2441
  var _a, _b, _c;
1927
2442
  const maxIter = (_a = options === null || options === void 0 ? void 0 : options.maxIteration) !== null && _a !== void 0 ? _a : 25;
1928
2443
  const tol = (_b = options === null || options === void 0 ? void 0 : options.tol) !== null && _b !== void 0 ? _b : 1e-6;
1929
2444
  const alpha = (_c = options === null || options === void 0 ? void 0 : options.alpha) !== null && _c !== void 0 ? _c : 0.05;
2445
+ // build arrays
1930
2446
  const xs = [];
1931
2447
  const ys = [];
1932
2448
  visitPoints(data, x, y, (dx, dy) => {
@@ -1942,6 +2458,7 @@
1942
2458
  confidenceInterval: (N = 50) => []
1943
2459
  };
1944
2460
  }
2461
+ // initial coef via linear regression rough guess
1945
2462
  let intercept = 0;
1946
2463
  let beta = 0;
1947
2464
  for (let iter = 0; iter < maxIter; iter++) {
@@ -1952,6 +2469,7 @@
1952
2469
  const pi = 1 / (1 + Math.exp(-z));
1953
2470
  p[i] = pi;
1954
2471
  }
2472
+ // compute gradient and hessian
1955
2473
  let g0 = 0;
1956
2474
  let g1 = 0;
1957
2475
  let h00 = 0;
@@ -1966,6 +2484,7 @@
1966
2484
  h01 += wi * xs[i];
1967
2485
  h11 += wi * xs[i] * xs[i];
1968
2486
  }
2487
+ // solve 2x2 system H * delta = g
1969
2488
  const det = h00 * h11 - h01 * h01;
1970
2489
  if (Math.abs(det) < 1e-12) {
1971
2490
  break;
@@ -2026,18 +2545,20 @@
2026
2545
  if (comps.n === 0) {
2027
2546
  return out;
2028
2547
  }
2029
- const z = Math.abs(invNorm(1 - alpha / 2));
2548
+ const z = confidenceCriticalValue(alpha);
2030
2549
  if (comps.min === comps.max) {
2031
2550
  const v = predict(comps.min);
2032
2551
  const errs = stdErrorsAt(comps.min, comps);
2552
+ const meanHalfWidth = confidenceHalfWidth(z, errs.seMean);
2553
+ const predHalfWidth = confidenceHalfWidth(z, errs.sePred);
2033
2554
  for (let i = 0; i < N; i++) {
2034
2555
  out.push({
2035
2556
  x: comps.min,
2036
2557
  mean: v,
2037
- lower: v - z * errs.seMean,
2038
- upper: v + z * errs.seMean,
2039
- predLower: v - z * errs.sePred,
2040
- predUpper: v + z * errs.sePred
2558
+ lower: v - meanHalfWidth,
2559
+ upper: v + meanHalfWidth,
2560
+ predLower: v - predHalfWidth,
2561
+ predUpper: v + predHalfWidth
2041
2562
  });
2042
2563
  }
2043
2564
  return out;
@@ -2047,13 +2568,15 @@
2047
2568
  const px = i === N - 1 ? comps.max : comps.min + step * i;
2048
2569
  const yh = predict(px);
2049
2570
  const errs = stdErrorsAt(px, comps);
2571
+ const meanHalfWidth = confidenceHalfWidth(z, errs.seMean);
2572
+ const predHalfWidth = confidenceHalfWidth(z, errs.sePred);
2050
2573
  out.push({
2051
2574
  x: px,
2052
2575
  mean: yh,
2053
- lower: yh - z * errs.seMean,
2054
- upper: yh + z * errs.seMean,
2055
- predLower: yh - z * errs.sePred,
2056
- predUpper: yh + z * errs.sePred
2576
+ lower: yh - meanHalfWidth,
2577
+ upper: yh + meanHalfWidth,
2578
+ predLower: yh - predHalfWidth,
2579
+ predUpper: yh + predHalfWidth
2057
2580
  });
2058
2581
  }
2059
2582
  return out;
@@ -2074,12 +2597,16 @@
2074
2597
  const t = 1 - uu * uu * uu;
2075
2598
  return t * t * t;
2076
2599
  }
2600
+ /**
2601
+ * Stratified sampling to reduce data size while preserving distribution
2602
+ */
2077
2603
  function stratifiedSample(sortedData, maxSamples) {
2078
2604
  const n = sortedData.length;
2079
2605
  if (n <= maxSamples) {
2080
2606
  return sortedData;
2081
2607
  }
2082
2608
  const sampled = [];
2609
+ // More aggressive sampling - use exact step size
2083
2610
  const step = n / maxSamples;
2084
2611
  for (let i = 0; i < maxSamples; i++) {
2085
2612
  const idx = Math.min(Math.floor(i * step), n - 1);
@@ -2087,6 +2614,15 @@
2087
2614
  }
2088
2615
  return sampled;
2089
2616
  }
2617
+ /**
2618
+ * Simple lowess implementation (univariate x)
2619
+ * options:
2620
+ * - span: fraction of points used in local regression (0,1]
2621
+ * - degree: 0 (constant) or 1 (linear)
2622
+ * - iterations: number of robustifying iterations
2623
+ * - alpha: confidence level for CI
2624
+ * - maxSamples: maximum number of points to use (default: 1000 for fast processing)
2625
+ */
2090
2626
  function regressionLowess(data, x = d => d.x, y = d => d.y, options = {}) {
2091
2627
  var _a;
2092
2628
  const span = options.span || 0.3;
@@ -2094,11 +2630,13 @@
2094
2630
  const alpha = (_a = options.alpha) !== null && _a !== void 0 ? _a : 0.05;
2095
2631
  const iterations = options.iterations == null ? 2 : options.iterations;
2096
2632
  const maxSamples = options.maxSamples || 1000;
2633
+ // Collect and sort data by x
2097
2634
  const rawPoints = [];
2098
2635
  visitPoints(data, x, y, (dx, dy, index) => {
2099
2636
  rawPoints.push({ x: dx, y: dy, index });
2100
2637
  });
2101
2638
  rawPoints.sort((a, b) => a.x - b.x);
2639
+ // Apply sampling if needed
2102
2640
  const sampledPoints = stratifiedSample(rawPoints, maxSamples);
2103
2641
  const n = sampledPoints.length;
2104
2642
  const ptsX = new Array(n);
@@ -2107,10 +2645,14 @@
2107
2645
  ptsX[i] = sampledPoints[i].x;
2108
2646
  ptsY[i] = sampledPoints[i].y;
2109
2647
  }
2648
+ /**
2649
+ * Optimized predictSingle using binary search on pre-sorted data
2650
+ */
2110
2651
  function predictSingle(x0, robustWeights) {
2111
2652
  if (n === 0) {
2112
2653
  return 0;
2113
2654
  }
2655
+ // Binary search to find insertion point
2114
2656
  let left = 0;
2115
2657
  let right = n;
2116
2658
  while (left < right) {
@@ -2123,6 +2665,7 @@
2123
2665
  }
2124
2666
  }
2125
2667
  const m = Math.min(n, Math.max(2, Math.floor(span * n)));
2668
+ // Expand by distance: equal numbers on either side need not be the nearest points.
2126
2669
  let lo = left - 1;
2127
2670
  let hi = left;
2128
2671
  for (let count = 0; count < m; count++) {
@@ -2135,6 +2678,7 @@
2135
2678
  }
2136
2679
  const actualStart = lo + 1;
2137
2680
  const end = hi;
2681
+ // Find max distance and compute weights in single pass
2138
2682
  let maxDist = 0;
2139
2683
  const windowSize = end - actualStart;
2140
2684
  const distances = new Array(windowSize);
@@ -2145,6 +2689,7 @@
2145
2689
  maxDist = dist;
2146
2690
  }
2147
2691
  }
2692
+ // Compute weights using pre-calculated distances
2148
2693
  let sumw = 0;
2149
2694
  const w = new Array(windowSize);
2150
2695
  for (let i = 0; i < windowSize; i++) {
@@ -2157,6 +2702,7 @@
2157
2702
  sumw += wi;
2158
2703
  }
2159
2704
  if (sumw === 0) {
2705
+ // Fall back to the nearest y, preserving input order for equal distances.
2160
2706
  let nearestIdx = 0;
2161
2707
  let nearestDistance = Math.abs(ptsX[0] - x0);
2162
2708
  for (let i = 1; i < n; i++) {
@@ -2176,6 +2722,7 @@
2176
2722
  }
2177
2723
  return s / sumw;
2178
2724
  }
2725
+ // weighted linear regression on local points
2179
2726
  let sw = 0;
2180
2727
  let sx = 0;
2181
2728
  let sy = 0;
@@ -2228,16 +2775,21 @@
2228
2775
  return out;
2229
2776
  }
2230
2777
  const step = (max - min) / (N - 1);
2778
+ // optionally add robust iterations
2231
2779
  let robustWeights;
2780
+ // Disable robustness iterations for large datasets to improve performance
2781
+ // Users can override by setting iterations explicitly
2232
2782
  const effectiveIterations = options.iterations != null ? iterations : n > 500 ? 0 : iterations;
2233
2783
  if (effectiveIterations > 0) {
2234
2784
  for (let iter = 0; iter < effectiveIterations; iter++) {
2785
+ // compute fits - pre-allocate arrays
2235
2786
  const fits = new Array(n);
2236
2787
  const res = new Array(n);
2237
2788
  for (let i = 0; i < n; i++) {
2238
2789
  fits[i] = predictSingle(ptsX[i], robustWeights);
2239
2790
  res[i] = Math.abs(ptsY[i] - fits[i]);
2240
2791
  }
2792
+ // median absolute deviation
2241
2793
  const sortedRes = res.slice().sort((a, b) => a - b);
2242
2794
  const med = sortedRes[Math.floor(n / 2)] || 0;
2243
2795
  robustWeights = new Array(n);
@@ -2262,6 +2814,7 @@
2262
2814
  if (n === 0) {
2263
2815
  return out;
2264
2816
  }
2817
+ // use data x-range (already sorted)
2265
2818
  const min = ptsX[0];
2266
2819
  const max = ptsX[n - 1];
2267
2820
  if (min === undefined || max === undefined || min === Infinity || max === -Infinity) {
@@ -2271,18 +2824,20 @@
2271
2824
  if (comps.n === 0) {
2272
2825
  return out;
2273
2826
  }
2274
- const z = Math.abs(invNorm(1 - alpha / 2));
2827
+ const z = confidenceCriticalValue(alpha);
2275
2828
  if (comps.min === comps.max) {
2276
2829
  const v = predictSingle(comps.min);
2277
2830
  const errs = stdErrorsAt(comps.min, comps);
2831
+ const meanHalfWidth = confidenceHalfWidth(z, errs.seMean);
2832
+ const predHalfWidth = confidenceHalfWidth(z, errs.sePred);
2278
2833
  for (let i = 0; i < N; i++) {
2279
2834
  out.push({
2280
2835
  x: comps.min,
2281
2836
  mean: v,
2282
- lower: v - z * errs.seMean,
2283
- upper: v + z * errs.seMean,
2284
- predLower: v - z * errs.sePred,
2285
- predUpper: v + z * errs.sePred
2837
+ lower: v - meanHalfWidth,
2838
+ upper: v + meanHalfWidth,
2839
+ predLower: v - predHalfWidth,
2840
+ predUpper: v + predHalfWidth
2286
2841
  });
2287
2842
  }
2288
2843
  return out;
@@ -2292,13 +2847,15 @@
2292
2847
  const px = i === N - 1 ? max : min + step * i;
2293
2848
  const yh = predictSingle(px);
2294
2849
  const errs = stdErrorsAt(px, comps);
2850
+ const meanHalfWidth = confidenceHalfWidth(z, errs.seMean);
2851
+ const predHalfWidth = confidenceHalfWidth(z, errs.sePred);
2295
2852
  out.push({
2296
2853
  x: px,
2297
2854
  mean: yh,
2298
- lower: yh - z * errs.seMean,
2299
- upper: yh + z * errs.seMean,
2300
- predLower: yh - z * errs.sePred,
2301
- predUpper: yh + z * errs.sePred
2855
+ lower: yh - meanHalfWidth,
2856
+ upper: yh + meanHalfWidth,
2857
+ predLower: yh - predHalfWidth,
2858
+ predUpper: yh + predHalfWidth
2302
2859
  });
2303
2860
  }
2304
2861
  return out;
@@ -2312,13 +2869,16 @@
2312
2869
  }
2313
2870
 
2314
2871
  function solveLinearSystem(A, b) {
2872
+ // Gaussian elimination with partial pivoting
2315
2873
  const n = b.length;
2874
+ // clone
2316
2875
  const M = new Array(n);
2317
2876
  for (let i = 0; i < n; i++) {
2318
2877
  M[i] = A[i].slice();
2319
2878
  M[i].push(b[i]);
2320
2879
  }
2321
2880
  for (let k = 0; k < n; k++) {
2881
+ // find pivot
2322
2882
  let maxRow = k;
2323
2883
  let maxVal = Math.abs(M[k][k]);
2324
2884
  for (let i = k + 1; i < n; i++) {
@@ -2333,14 +2893,18 @@
2333
2893
  M[k] = M[maxRow];
2334
2894
  M[maxRow] = tmp;
2335
2895
  }
2896
+ // singular check
2336
2897
  if (Math.abs(M[k][k]) < 1e-12) {
2898
+ // return least squares fallback zeros
2337
2899
  const res = new Array(n).fill(0);
2338
2900
  return res;
2339
2901
  }
2902
+ // normalize row
2340
2903
  for (let j = k + 1; j <= n; j++) {
2341
2904
  M[k][j] = M[k][j] / M[k][k];
2342
2905
  }
2343
2906
  M[k][k] = 1;
2907
+ // eliminate
2344
2908
  for (let i = 0; i < n; i++) {
2345
2909
  if (i === k) {
2346
2910
  continue;
@@ -2377,6 +2941,7 @@
2377
2941
  xp *= dx;
2378
2942
  }
2379
2943
  });
2944
+ // build normal matrix
2380
2945
  const A = new Array(m);
2381
2946
  for (let i = 0; i < m; i++) {
2382
2947
  A[i] = new Array(m).fill(0);
@@ -2407,6 +2972,7 @@
2407
2972
  coef,
2408
2973
  predict,
2409
2974
  rSquared: rSquared(data, x, y, (() => {
2975
+ // compute mean y
2410
2976
  let sum = 0;
2411
2977
  let cnt = 0;
2412
2978
  visitPoints(data, x, y, (_dx, dy) => {
@@ -2420,6 +2986,7 @@
2420
2986
  if (N <= 0) {
2421
2987
  return out;
2422
2988
  }
2989
+ // compute range
2423
2990
  let min = Infinity;
2424
2991
  let max = -Infinity;
2425
2992
  visitPoints(data, x, y, dx => {
@@ -2458,18 +3025,20 @@
2458
3025
  if (comps.n === 0) {
2459
3026
  return out;
2460
3027
  }
2461
- const z = Math.abs(invNorm(1 - alpha / 2));
3028
+ const z = confidenceCriticalValue(alpha);
2462
3029
  if (comps.min === comps.max) {
2463
3030
  const v = predict(comps.min);
2464
3031
  const errs = stdErrorsAt(comps.min, comps);
3032
+ const meanHalfWidth = confidenceHalfWidth(z, errs.seMean);
3033
+ const predHalfWidth = confidenceHalfWidth(z, errs.sePred);
2465
3034
  for (let i = 0; i < N; i++) {
2466
3035
  out.push({
2467
3036
  x: comps.min,
2468
3037
  mean: v,
2469
- lower: v - z * errs.seMean,
2470
- upper: v + z * errs.seMean,
2471
- predLower: v - z * errs.sePred,
2472
- predUpper: v + z * errs.sePred
3038
+ lower: v - meanHalfWidth,
3039
+ upper: v + meanHalfWidth,
3040
+ predLower: v - predHalfWidth,
3041
+ predUpper: v + predHalfWidth
2473
3042
  });
2474
3043
  }
2475
3044
  return out;
@@ -2479,13 +3048,15 @@
2479
3048
  const px = i === N - 1 ? comps.max : comps.min + step * i;
2480
3049
  const yh = predict(px);
2481
3050
  const errs = stdErrorsAt(px, comps);
3051
+ const meanHalfWidth = confidenceHalfWidth(z, errs.seMean);
3052
+ const predHalfWidth = confidenceHalfWidth(z, errs.sePred);
2482
3053
  out.push({
2483
3054
  x: px,
2484
3055
  mean: yh,
2485
- lower: yh - z * errs.seMean,
2486
- upper: yh + z * errs.seMean,
2487
- predLower: yh - z * errs.sePred,
2488
- predUpper: yh + z * errs.sePred
3056
+ lower: yh - meanHalfWidth,
3057
+ upper: yh + meanHalfWidth,
3058
+ predLower: yh - predHalfWidth,
3059
+ predUpper: yh + predHalfWidth
2489
3060
  });
2490
3061
  }
2491
3062
  return out;
@@ -2493,14 +3064,29 @@
2493
3064
  };
2494
3065
  }
2495
3066
 
3067
+ /**
3068
+ * Kernel Density Estimation (KDE) utilities
3069
+ *
3070
+ * Exports:
3071
+ * - Kernel functions: gaussian, epanechnikov
3072
+ * - bandwidth selectors: scott, silverman
3073
+ * - kde: main function to compute density estimates at provided points
3074
+ */
3075
+ /** Gaussian kernel (standard normal) */
2496
3076
  const gaussian = (u) => {
2497
3077
  const invSqrt2Pi = 1 / Math.sqrt(2 * Math.PI);
2498
3078
  return invSqrt2Pi * Math.exp(-0.5 * u * u);
2499
3079
  };
3080
+ /** Epanechnikov kernel (compact support) */
2500
3081
  const epanechnikov = (u) => {
2501
3082
  const absu = Math.abs(u);
2502
3083
  return absu <= 1 ? 0.75 * (1 - u * u) : 0;
2503
3084
  };
3085
+ /**
3086
+ * Bandwidth selectors
3087
+ * - scott: h = n^{-1/(d+4)} * std
3088
+ * - silverman: h = ( (4/(d+2))^{1/(d+4)} ) * n^{-1/(d+4)} * std
3089
+ */
2504
3090
  function scott(n, std, dim = 1) {
2505
3091
  if (n <= 0 || std === 0) {
2506
3092
  return 0;
@@ -2514,6 +3100,9 @@
2514
3100
  const factor = Math.pow(4 / (dim + 2), 1 / (dim + 4));
2515
3101
  return factor * std * Math.pow(n, -1 / (dim + 4));
2516
3102
  }
3103
+ /**
3104
+ * Compute standard deviation for numeric array
3105
+ */
2517
3106
  function std(values) {
2518
3107
  const n = values.length;
2519
3108
  if (n === 0) {
@@ -2531,6 +3120,10 @@
2531
3120
  }
2532
3121
  return Math.sqrt(s / n);
2533
3122
  }
3123
+ /**
3124
+ * Factory: create a KDE evaluator for given data and options.
3125
+ * Usage: const model = kde(data, options); model.evaluate(x) or model.evaluate([x1,x2])
3126
+ */
2534
3127
  function kde(data, options = {}) {
2535
3128
  const n = data.length;
2536
3129
  const kernel = options.kernel || gaussian;
@@ -2545,6 +3138,7 @@
2545
3138
  h = scott(n, sd, 1);
2546
3139
  }
2547
3140
  }
3141
+ // if still zero (constant data), evaluator returns zeros
2548
3142
  if (!h || h <= 0) {
2549
3143
  const zerosEval = (x) => {
2550
3144
  if (Array.isArray(x)) {
@@ -2561,6 +3155,7 @@
2561
3155
  if (N <= 0) {
2562
3156
  return out;
2563
3157
  }
3158
+ // compute data min (use data range if available)
2564
3159
  let min = Infinity;
2565
3160
  let max = -Infinity;
2566
3161
  for (let j = 0; j < n; j++) {
@@ -2617,6 +3212,7 @@
2617
3212
  if (N <= 0) {
2618
3213
  return out;
2619
3214
  }
3215
+ // compute data range
2620
3216
  let min = Infinity;
2621
3217
  let max = -Infinity;
2622
3218
  for (let i = 0; i < n; i++) {
@@ -2632,6 +3228,7 @@
2632
3228
  return out;
2633
3229
  }
2634
3230
  if (min === max) {
3231
+ // single point repeated
2635
3232
  for (let i = 0; i < N; i++) {
2636
3233
  out.push({ x: min, y: evalPoint(min) });
2637
3234
  }
@@ -2647,6 +3244,14 @@
2647
3244
  };
2648
3245
  }
2649
3246
 
3247
+ /**
3248
+ * Empirical Cumulative Distribution Function (ECDF)
3249
+ * Returns a factory that builds an evaluator over provided samples.
3250
+ * The evaluator exposes:
3251
+ * - evaluate(x:number) => proportion of samples <= x
3252
+ * - evaluate(xs:number[]) => number[]
3253
+ * - evaluateGrid(N:number) => { points: number[], cdf: number[] } over sample range
3254
+ */
2650
3255
  function ecdf(data) {
2651
3256
  const n = data.length;
2652
3257
  const sorted = data.slice().sort((a, b) => a - b);
@@ -2654,8 +3259,9 @@
2654
3259
  if (n === 0) {
2655
3260
  return 0;
2656
3261
  }
3262
+ // count of values <= x (upper bound index)
2657
3263
  let lo = 0;
2658
- let hi = n;
3264
+ let hi = n; // exclusive
2659
3265
  while (lo < hi) {
2660
3266
  const mid = (lo + hi) >>> 1;
2661
3267
  if (sorted[mid] <= x) {
@@ -2707,8 +3313,192 @@
2707
3313
  };
2708
3314
  }
2709
3315
 
3316
+ function pearson(x, y) {
3317
+ let sx = 0;
3318
+ let sy = 0;
3319
+ for (let i = 0; i < x.length; i++) {
3320
+ sx = Math.max(sx, Math.abs(x[i]));
3321
+ sy = Math.max(sy, Math.abs(y[i]));
3322
+ }
3323
+ if (!sx || !sy) {
3324
+ return undefined;
3325
+ }
3326
+ let mx = 0;
3327
+ let my = 0;
3328
+ let cx = 0;
3329
+ let cy = 0;
3330
+ for (let i = 0; i < x.length; i++) {
3331
+ const vx = x[i] / sx - cx;
3332
+ const vy = y[i] / sy - cy;
3333
+ const tx = mx + vx;
3334
+ const ty = my + vy;
3335
+ cx = tx - mx - vx;
3336
+ cy = ty - my - vy;
3337
+ mx = tx;
3338
+ my = ty;
3339
+ }
3340
+ mx /= x.length;
3341
+ my /= x.length;
3342
+ let xx = 0;
3343
+ let yy = 0;
3344
+ let xy = 0;
3345
+ for (let i = 0; i < x.length; i++) {
3346
+ const dx = x[i] / sx - mx;
3347
+ const dy = y[i] / sy - my;
3348
+ xx += dx * dx;
3349
+ yy += dy * dy;
3350
+ xy += dx * dy;
3351
+ }
3352
+ if (xx === 0 || yy === 0) {
3353
+ return undefined;
3354
+ }
3355
+ const result = xy / Math.sqrt(xx * yy);
3356
+ // 仅修正浮点舍入越过理论端点的几个 ulp。
3357
+ if (Math.abs(result) > 1 && Math.abs(result) <= 1 + 8 * Number.EPSILON) {
3358
+ return Math.sign(result);
3359
+ }
3360
+ return result;
3361
+ }
3362
+ function ranks(values) {
3363
+ const order = values.map((value, index) => ({ value, index })).sort((a, b) => a.value - b.value);
3364
+ const result = new Array(values.length);
3365
+ for (let start = 0; start < order.length;) {
3366
+ let end = start + 1;
3367
+ while (end < order.length && order[end].value === order[start].value) {
3368
+ end++;
3369
+ }
3370
+ const rank = (start + end + 1) / 2;
3371
+ for (let i = start; i < end; i++) {
3372
+ result[order[i].index] = rank;
3373
+ }
3374
+ start = end;
3375
+ }
3376
+ return result;
3377
+ }
3378
+ function kendall(x, y) {
3379
+ const pairs = x.map((value, index) => ({ x: value, y: y[index] })).sort((a, b) => a.x - b.x || a.y - b.y);
3380
+ const sortedY = [...y].sort((a, b) => a - b);
3381
+ const yRanks = new Map();
3382
+ let tiesY = 0;
3383
+ for (let start = 0; start < sortedY.length;) {
3384
+ let end = start + 1;
3385
+ while (end < sortedY.length && sortedY[end] === sortedY[start]) {
3386
+ end++;
3387
+ }
3388
+ tiesY += ((end - start) * (end - start - 1)) / 2;
3389
+ yRanks.set(sortedY[start], yRanks.size + 1);
3390
+ start = end;
3391
+ }
3392
+ const tree = new Float64Array(yRanks.size + 1);
3393
+ let tiesX = 0;
3394
+ let tiesBoth = 0;
3395
+ let discordant = 0;
3396
+ for (let start = 0; start < pairs.length;) {
3397
+ let end = start + 1;
3398
+ while (end < pairs.length && pairs[end].x === pairs[start].x) {
3399
+ end++;
3400
+ }
3401
+ tiesX += ((end - start) * (end - start - 1)) / 2;
3402
+ for (let i = start; i < end;) {
3403
+ let j = i + 1;
3404
+ while (j < end && pairs[j].y === pairs[i].y) {
3405
+ j++;
3406
+ }
3407
+ tiesBoth += ((j - i) * (j - i - 1)) / 2;
3408
+ i = j;
3409
+ }
3410
+ // 同 x 组先查询再更新,避免将 x ties 算成逆序。
3411
+ for (let i = start; i < end; i++) {
3412
+ let lessOrEqual = 0;
3413
+ for (let rank = yRanks.get(pairs[i].y); rank > 0; rank -= rank & -rank) {
3414
+ lessOrEqual += tree[rank];
3415
+ }
3416
+ discordant += start - lessOrEqual;
3417
+ }
3418
+ for (let i = start; i < end; i++) {
3419
+ for (let rank = yRanks.get(pairs[i].y); rank < tree.length; rank += rank & -rank) {
3420
+ tree[rank]++;
3421
+ }
3422
+ }
3423
+ start = end;
3424
+ }
3425
+ const total = (x.length * (x.length - 1)) / 2;
3426
+ if (total === tiesX || total === tiesY) {
3427
+ return undefined;
3428
+ }
3429
+ return (total - tiesX - tiesY + tiesBoth - 2 * discordant) / Math.sqrt((total - tiesX) * (total - tiesY));
3430
+ }
3431
+ /** 等长有限样本的相关系数;常量/不足两条返回 undefined,不修改数组。 */
3432
+ function correlation(x, y, method = 'pearson') {
3433
+ if (x.length !== y.length ||
3434
+ !['pearson', 'spearman', 'kendall'].includes(method) ||
3435
+ x.some(value => !Number.isFinite(value)) ||
3436
+ y.some(value => !Number.isFinite(value))) {
3437
+ throw new RangeError('correlation requires equal finite arrays and a supported method');
3438
+ }
3439
+ if (x.length < 2) {
3440
+ return undefined;
3441
+ }
3442
+ return method === 'kendall' ? kendall(x, y) : method === 'spearman' ? pearson(ranks(x), ranks(y)) : pearson(x, y);
3443
+ }
3444
+
3445
+ /** 有限数值的均值;空输入没有均值,不修改输入。 */
3446
+ function mean(values) {
3447
+ if (!values.length) {
3448
+ return undefined;
3449
+ }
3450
+ let scale = 0;
3451
+ for (const value of values) {
3452
+ if (!Number.isFinite(value)) {
3453
+ throw new RangeError('mean requires finite numbers');
3454
+ }
3455
+ scale = Math.max(scale, Math.abs(value));
3456
+ }
3457
+ if (scale === 0) {
3458
+ return 0;
3459
+ }
3460
+ let sum = 0;
3461
+ let correction = 0;
3462
+ for (const value of values) {
3463
+ const next = value / scale;
3464
+ const total = sum + next;
3465
+ // Neumaier compensation retains small contributions even when larger values cancel.
3466
+ correction += Math.abs(sum) >= Math.abs(next) ? sum - total + next : next - total + sum;
3467
+ sum = total;
3468
+ }
3469
+ return ((sum + correction) / values.length) * scale;
3470
+ }
3471
+
3472
+ /** 有放回重采样;回调不得修改或持有复用的只读样本缓冲区。 */
3473
+ function bootstrapEstimate(values, estimator, options) {
3474
+ if (!values.length ||
3475
+ values.some(value => !Number.isFinite(value)) ||
3476
+ !Number.isInteger(options.resamples) ||
3477
+ options.resamples < 1 ||
3478
+ !Number.isInteger(options.seed) ||
3479
+ options.seed < 0 ||
3480
+ options.seed > 0xffffffff) {
3481
+ throw new RangeError('bootstrap requires finite observations, positive resamples and a uint32 seed');
3482
+ }
3483
+ const random = randomLCG(options.seed);
3484
+ const sample = new Array(values.length);
3485
+ const estimates = new Array(options.resamples);
3486
+ for (let b = 0; b < options.resamples; b++) {
3487
+ for (let i = 0; i < sample.length; i++) {
3488
+ sample[i] = values[Math.floor(random() * values.length)];
3489
+ }
3490
+ const estimate = estimator(sample);
3491
+ if (!Number.isFinite(estimate)) {
3492
+ throw new RangeError('bootstrap estimator must return a finite number');
3493
+ }
3494
+ estimates[b] = estimate;
3495
+ }
3496
+ return estimates;
3497
+ }
3498
+
2710
3499
  class HashValue {
2711
3500
  }
3501
+ // 基于 array 和 object的 HashTable
2712
3502
  class HashTable {
2713
3503
  constructor() {
2714
3504
  this.items = {};
@@ -2744,6 +3534,10 @@
2744
3534
  this.resetIndex();
2745
3535
  }
2746
3536
  }
3537
+ /**
3538
+ * 不包含当前index
3539
+ * @param index
3540
+ */
2747
3541
  delFrom(index) {
2748
3542
  for (let i = index + 1; i < this.count(); i++) {
2749
3543
  const key = this.itemList[i].key;
@@ -2787,6 +3581,7 @@
2787
3581
  getKeyByIndex(index) {
2788
3582
  return this.itemList[index].key;
2789
3583
  }
3584
+ //遍历 扩展
2790
3585
  foreach(callback) {
2791
3586
  for (const key in this.items) {
2792
3587
  const returnVal = callback(key, this.items[key].value);
@@ -2813,12 +3608,14 @@
2813
3608
  }
2814
3609
  return false;
2815
3610
  }
3611
+ //获取index
2816
3612
  indexOf(key) {
2817
3613
  if (this.has(key)) {
2818
3614
  return this.items[key].index;
2819
3615
  }
2820
3616
  return -1;
2821
3617
  }
3618
+ //插入
2822
3619
  insertAt(index, value, key) {
2823
3620
  const hashV = new HashValue();
2824
3621
  hashV.index = index;
@@ -2851,6 +3648,7 @@
2851
3648
  return returnArr;
2852
3649
  }
2853
3650
  toImmutableMap() {
3651
+ // do nothing
2854
3652
  }
2855
3653
  }
2856
3654
 
@@ -2877,6 +3675,15 @@
2877
3675
  function asin(x) {
2878
3676
  return x >= 1 ? halfPi : x <= -1 ? -halfPi : Math.asin(x);
2879
3677
  }
3678
+ /**
3679
+ * 根据比例获直线上的点
3680
+ * @param {number} x1 起始点 x
3681
+ * @param {number} y1 起始点 y
3682
+ * @param {number} x2 结束点 x
3683
+ * @param {number} y2 结束点 y
3684
+ * @param {number} t 指定比例
3685
+ * @return {object} 包含 x, y 的点
3686
+ */
2880
3687
  function pointAt(x1, y1, x2, y2, t) {
2881
3688
  let x = x2;
2882
3689
  let y = y2;
@@ -2892,6 +3699,7 @@
2892
3699
  };
2893
3700
  }
2894
3701
  function lengthFromPointToLine(point, point1, point2) {
3702
+ // 面积
2895
3703
  const dir1X = point2.x - point1.x;
2896
3704
  const dir1Y = point2.y - point1.y;
2897
3705
  const dir2X = point.x - point1.x;
@@ -2936,6 +3744,9 @@
2936
3744
 
2937
3745
  class Point {
2938
3746
  constructor(x = 0, y = 0, x1, y1) {
3747
+ /**
3748
+ * 面积图的下点
3749
+ */
2939
3750
  this.x = 0;
2940
3751
  this.y = 0;
2941
3752
  this.x = x;
@@ -2988,6 +3799,7 @@
2988
3799
  }
2989
3800
  }
2990
3801
  class PointService {
3802
+ /* distance */
2991
3803
  static distancePP(p1, p2) {
2992
3804
  return sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2));
2993
3805
  }
@@ -2997,6 +3809,7 @@
2997
3809
  static distancePN(point, x, y) {
2998
3810
  return sqrt(pow(x - point.x, 2) + pow(y - point.y, 2));
2999
3811
  }
3812
+ /* point at */
3000
3813
  static pointAtPP(p1, p2, t) {
3001
3814
  return new Point((p2.x - p1.x) * t + p1.x, (p2.y - p1.y) * t + p1.y);
3002
3815
  }
@@ -3045,12 +3858,30 @@
3045
3858
  return new ImageData(flipClampBuffer, width, height);
3046
3859
  };
3047
3860
 
3861
+ /**
3862
+ * 处理角度相关的数据计算
3863
+ */
3864
+ /**
3865
+ * degree -> radian
3866
+ * @param degree
3867
+ * @returns radian
3868
+ */
3048
3869
  function degreeToRadian(degree) {
3049
3870
  return degree * (Math.PI / 180);
3050
3871
  }
3872
+ /**
3873
+ * radian -> degree
3874
+ * @param radian
3875
+ * @returns
3876
+ */
3051
3877
  function radianToDegree(radian) {
3052
3878
  return (radian * 180) / Math.PI;
3053
3879
  }
3880
+ /**
3881
+ * 对弧度进行格式化
3882
+ * @param a 传入的弧度
3883
+ * @returns
3884
+ */
3054
3885
  const clampRadian = (angle = 0) => {
3055
3886
  if (angle < 0) {
3056
3887
  while (angle < -tau) {
@@ -3064,14 +3895,28 @@
3064
3895
  }
3065
3896
  return angle;
3066
3897
  };
3898
+ // alias of clampRadian
3067
3899
  const clampAngleByRadian = clampRadian;
3900
+ /**
3901
+ * 对角度进行格式化
3902
+ * @param a 角度
3903
+ * @returns
3904
+ */
3068
3905
  const clampDegree = (a = 0) => {
3069
3906
  if (a > 360 || a < -360) {
3070
3907
  return a % 360;
3071
3908
  }
3072
3909
  return a;
3073
3910
  };
3911
+ // alias of clampDegree
3074
3912
  const clampAngleByDegree = clampDegree;
3913
+ /**
3914
+ * 根据弧度及半径计算极坐标系下的坐标点
3915
+ * @param centerX 圆心坐标
3916
+ * @param radius 半径
3917
+ * @param angleInRadian 弧度
3918
+ * @returns 返回笛卡尔坐标点
3919
+ */
3075
3920
  function polarToCartesian(center, radius, angleInRadian) {
3076
3921
  if (!radius) {
3077
3922
  return { x: center.x, y: center.y };
@@ -3081,6 +3926,14 @@
3081
3926
  y: center.y + radius * Math.sin(angleInRadian)
3082
3927
  };
3083
3928
  }
3929
+ /**
3930
+ * 根据笛卡尔坐标系坐标计算极坐标坐标点
3931
+ * @param point
3932
+ * @param center 极坐标系中心点坐标
3933
+ * @param startAngle 极坐标系起始角度
3934
+ * @param endAngle 极坐标系结束角度
3935
+ * @returns 极坐标系坐标点
3936
+ */
3084
3937
  function cartesianToPolar(point, center = { x: 0, y: 0 }, startAngle = 0, endAngle = 2 * Math.PI) {
3085
3938
  const { x, y } = point;
3086
3939
  const { x: centerX, y: centerY } = center;
@@ -3111,9 +3964,19 @@
3111
3964
  angle: radian
3112
3965
  };
3113
3966
  }
3967
+ /**
3968
+ * 根据点的笛卡尔坐标获取该点与圆心的连线同正 x 轴方向的夹角
3969
+ * @param center 圆心坐标
3970
+ * @param point 待求的点坐标
3971
+ * @returns 返回夹角对应的弧度值
3972
+ */
3114
3973
  function getAngleByPoint(center, point) {
3115
3974
  return Math.atan2(point.y - center.y, point.x - center.x);
3116
3975
  }
3976
+ /**
3977
+ * 角度标准化处理
3978
+ * @param angle 弧度角
3979
+ */
3117
3980
  function normalizeAngle(angle) {
3118
3981
  while (angle < 0) {
3119
3982
  angle += Math.PI * 2;
@@ -3123,6 +3986,14 @@
3123
3986
  }
3124
3987
  return angle;
3125
3988
  }
3989
+ /**
3990
+ * 指定开始角度和结束角度,计算这个范围内的边界角度,
3991
+ * 即起始角度以及经过的东、南、西、北四个方向的角度
3992
+ * 计算这个角度,可以用于计算一个弧度的bounding box 等
3993
+ * @param startAngle 起始角度的弧度值
3994
+ * @param endAngle 结束角度的弧度值
3995
+ * @returns 边界角度数组
3996
+ */
3126
3997
  function findBoundaryAngles(startAngle, endAngle) {
3127
3998
  const deltaAngle = Math.abs(endAngle - startAngle);
3128
3999
  if (deltaAngle >= 2 * Math.PI || 2 * Math.PI - deltaAngle < 1e-6) {
@@ -3141,6 +4012,14 @@
3141
4012
  }
3142
4013
  return steps;
3143
4014
  }
4015
+ /**
4016
+ * 计算指定范围内,指定中心的情况下,不超出边界的最大可用半径
4017
+ * @param rect 矩形的大小
4018
+ * @param center 中心点
4019
+ * @param startAngle 起始角度的弧度值
4020
+ * @param endAngle 结束角度的弧度值
4021
+ * @returns 最大半径
4022
+ */
3144
4023
  function calculateMaxRadius(rect, center, startAngle, endAngle) {
3145
4024
  const { x, y } = center;
3146
4025
  const steps = findBoundaryAngles(startAngle, endAngle);
@@ -3192,10 +4071,18 @@
3192
4071
  return 1;
3193
4072
  }
3194
4073
 
4074
+ /* 用于判断2d相交 */
3195
4075
  function sub(out, v1, v2) {
3196
4076
  out[0] = v1[0] - v2[0];
3197
4077
  out[1] = v1[1] - v2[1];
3198
4078
  }
4079
+ /**
4080
+ * 判断直线是否相交,投影法
4081
+ * @param left1
4082
+ * @param right1
4083
+ * @param left2
4084
+ * @param right2
4085
+ */
3199
4086
  function isIntersect(left1, right1, left2, right2) {
3200
4087
  let min1 = left1[0];
3201
4088
  let max1 = right1[0];
@@ -3222,6 +4109,15 @@
3222
4109
  }
3223
4110
  return true;
3224
4111
  }
4112
+ /**
4113
+ * 获取直线交点
4114
+ * 不相交返回false,共线返回true,相交返回交点
4115
+ * https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect/565282#565282
4116
+ * @param left1
4117
+ * @param right1
4118
+ * @param left2
4119
+ * @param right2
4120
+ */
3225
4121
  function getIntersectPoint(left1, right1, left2, right2) {
3226
4122
  if (!isIntersect(left1, right1, left2, right2)) {
3227
4123
  return false;
@@ -3231,9 +4127,16 @@
3231
4127
  const tempVec = [0, 0];
3232
4128
  sub(dir1, right1, left1);
3233
4129
  sub(dir2, right2, left2);
4130
+ // 判断共线
3234
4131
  if (fuzzyEqualVec(dir1, dir2)) {
3235
4132
  return true;
3236
4133
  }
4134
+ // https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect/565282#565282
4135
+ // line1: left1 + dir1 * t
4136
+ // line2: left2 + dir2 * u
4137
+ // 当 left1 + dir1 * t = left2 + dir2 * u => (left1 + dir1 * t) x dir2 = (left2 + dir2 * u) x dir2
4138
+ // => dir1 x dir2 * t = (left2 - left1) x dir2 => t = (left2 - left1) x dir2 / (dir1 x dir2)
4139
+ // 直线不平行,dir1 x dir2 ≠ 0,当0 <= t <= 1时,可以求出交点
3237
4140
  sub(tempVec, left2, left1);
3238
4141
  const t = crossProduct(tempVec, dir2) / crossProduct(dir1, dir2);
3239
4142
  if (t >= 0 && t <= 1) {
@@ -3241,6 +4144,13 @@
3241
4144
  }
3242
4145
  return false;
3243
4146
  }
4147
+ /**
4148
+ * 获取两个rect的相交部分
4149
+ * 如果有bbox为null,返回null,如果不相交返回{x1: 0, y1: 0, x2: 0, y2: 0}
4150
+ * @param bbox1
4151
+ * @param bbox2
4152
+ * @param format
4153
+ */
3244
4154
  function getRectIntersect(bbox1, bbox2, format) {
3245
4155
  if (bbox1 === null) {
3246
4156
  return bbox2;
@@ -3285,19 +4195,35 @@
3285
4195
  }
3286
4196
  return { x11, x12, y11, y12, x21, x22, y21, y22 };
3287
4197
  };
4198
+ /**
4199
+ * 矩形是否在另一个矩形内部
4200
+ * 返回InnerBBox
4201
+ * @param bbox1
4202
+ * @param bbox2
4203
+ * @param format
4204
+ */
3288
4205
  function rectInsideAnotherRect(bbox1, bbox2, format) {
3289
4206
  if (!bbox1 || !bbox2) {
3290
4207
  return exports.InnerBBox.NONE;
3291
4208
  }
3292
4209
  const { x11, x12, y11, y12, x21, x22, y21, y22 } = formatTwoBBox(bbox1, bbox2, format);
4210
+ // bbox1在bbox2内部
3293
4211
  if (x11 > x21 && x12 < x22 && y11 > y21 && y12 < y22) {
3294
4212
  return exports.InnerBBox.BBOX1;
3295
4213
  }
4214
+ // bbox2在bbox1内部
3296
4215
  if (x21 > x11 && x22 < x12 && y21 > y11 && y22 < y12) {
3297
4216
  return exports.InnerBBox.BBOX2;
3298
4217
  }
3299
4218
  return exports.InnerBBox.NONE;
3300
4219
  }
4220
+ /**
4221
+ * 两个矩形是否相交
4222
+ * 如果有矩形为null,判断为相交
4223
+ * @param bbox1
4224
+ * @param bbox2
4225
+ * @param format
4226
+ */
3301
4227
  function isRectIntersect(bbox1, bbox2, format) {
3302
4228
  if (bbox1 && bbox2) {
3303
4229
  if (!format) {
@@ -3314,6 +4240,12 @@
3314
4240
  }
3315
4241
  return true;
3316
4242
  }
4243
+ /**
4244
+ * 点在box内部
4245
+ * 如果bbox为null返回true
4246
+ * @param point
4247
+ * @param bbox
4248
+ */
3317
4249
  function pointInRect(point, bbox, format) {
3318
4250
  if (!bbox) {
3319
4251
  return true;
@@ -3333,9 +4265,20 @@
3333
4265
  }
3334
4266
  return point.x >= x11 && point.x <= x12 && point.y >= y11 && point.y <= y12;
3335
4267
  }
4268
+ // 参考https://github.com/francecil/leetcode/issues/1
4269
+ /**
4270
+ * 计算投影半径
4271
+ * @param {Array(Number)} checkAxis 检测轴 [cosθ,sinθ]
4272
+ * @param {Array} axis 目标轴 [x,y]
4273
+ */
3336
4274
  function getProjectionRadius(checkAxis, axis) {
3337
4275
  return Math.abs(axis[0] * checkAxis[0] + axis[1] * checkAxis[1]);
3338
4276
  }
4277
+ /**
4278
+ * 逆时针旋转矩阵(从正 x 轴开始,旋转到正 y 轴的方向)
4279
+ * [ cos(θ) -sin(θ) ]
4280
+ * [ sin(θ) cos(θ) ]
4281
+ */
3339
4282
  function rotatePoint({ x, y }, rad, origin = { x: 0, y: 0 }) {
3340
4283
  return {
3341
4284
  x: (x - origin.x) * Math.cos(rad) - (y - origin.y) * Math.sin(rad) + origin.x,
@@ -3348,6 +4291,10 @@
3348
4291
  y: (box.y1 + box.y2) / 2
3349
4292
  };
3350
4293
  }
4294
+ /**
4295
+ * 转化为顶点坐标数组
4296
+ * @param {Object} box
4297
+ */
3351
4298
  function toRect(box, isDeg) {
3352
4299
  const deg = isDeg ? degreeToRadian(box.angle) : box.angle;
3353
4300
  const cp = getCenterPoint(box);
@@ -3376,15 +4323,21 @@
3376
4323
  const vector = (start, end) => {
3377
4324
  return [end.x - start.x, end.y - start.y];
3378
4325
  };
4326
+ // 两个矩形的中心点
3379
4327
  const p1 = getCenterPoint(box1);
3380
4328
  const p2 = getCenterPoint(box2);
4329
+ // 向量 p1p2
3381
4330
  const vp1p2 = vector(p1, p2);
4331
+ //矩形1的两边向量
3382
4332
  const AB = vector(rect1[0], rect1[1]);
3383
4333
  const BC = vector(rect1[1], rect1[2]);
4334
+ //矩形2的两边向量
3384
4335
  const A1B1 = vector(rect2[0], rect2[1]);
3385
4336
  const B1C1 = vector(rect2[1], rect2[2]);
4337
+ // 矩形1 的两个弧度
3386
4338
  const deg11 = isDeg ? degreeToRadian(box1.angle) : box1.angle;
3387
4339
  let deg12 = isDeg ? degreeToRadian(90 - box1.angle) : box1.angle + halfPi;
4340
+ // 矩形2 的两个弧度
3388
4341
  const deg21 = isDeg ? degreeToRadian(box2.angle) : box2.angle;
3389
4342
  let deg22 = isDeg ? degreeToRadian(90 - box2.angle) : box2.angle + halfPi;
3390
4343
  if (deg12 > pi2) {
@@ -3393,10 +4346,12 @@
3393
4346
  if (deg22 > pi2) {
3394
4347
  deg22 -= pi2;
3395
4348
  }
4349
+ // 投影重叠
3396
4350
  const isCover = (checkAxisRadius, deg, targetAxis1, targetAxis2) => {
3397
4351
  const checkAxis = [Math.cos(deg), Math.sin(deg)];
3398
4352
  const targetAxisRadius = (getProjectionRadius(checkAxis, targetAxis1) + getProjectionRadius(checkAxis, targetAxis2)) / 2;
3399
4353
  const centerPointRadius = getProjectionRadius(checkAxis, vp1p2);
4354
+ // console.log('abc', `checkAxis:${checkAxis},三个投影:${checkAxisRadius}, ${targetAxisRadius}, ${centerPointRadius}`)
3400
4355
  return checkAxisRadius + targetAxisRadius > centerPointRadius;
3401
4356
  };
3402
4357
  return (isCover((box1.x2 - box1.x1) / 2, deg11, A1B1, B1C1) &&
@@ -3411,6 +4366,7 @@
3411
4366
  let y2;
3412
4367
  function getAABBFromPoints(points) {
3413
4368
  (x1 = Infinity), (y1 = Infinity), (x2 = -Infinity), (y2 = -Infinity);
4369
+ // todo 有优化空间
3414
4370
  points.forEach(point => {
3415
4371
  if (x1 > point.x) {
3416
4372
  x1 = point.x;
@@ -3462,6 +4418,7 @@
3462
4418
  y22 = temp;
3463
4419
  }
3464
4420
  }
4421
+ // 不相交直接跳过
3465
4422
  if (x11 >= x22 || x12 <= x21 || y11 >= y22 || y12 <= y21) {
3466
4423
  return [bounds1, bounds2];
3467
4424
  }
@@ -3483,6 +4440,7 @@
3483
4440
  const l = [];
3484
4441
  list.forEach(b => {
3485
4442
  let arr;
4443
+ // 相交
3486
4444
  if ((arr = unionAABB(baseBound, b)).length > 1) {
3487
4445
  l.push(b);
3488
4446
  return;
@@ -3596,8 +4554,10 @@
3596
4554
  };
3597
4555
  }
3598
4556
  estimate({ text, fontSize }) {
3599
- let eCharLen = 0;
3600
- let cCharLen = 0;
4557
+ // 假设只有英文和中文字符
4558
+ let eCharLen = 0; // 英文字符
4559
+ let cCharLen = 0; // 中文字符
4560
+ // 判断ascii码,如果是
3601
4561
  for (let i = 0; i < text.length; i++) {
3602
4562
  text.charCodeAt(i) < 128 ? eCharLen++ : cCharLen++;
3603
4563
  }
@@ -3615,6 +4575,14 @@
3615
4575
  }
3616
4576
 
3617
4577
  const EPSILON = 1e-8;
4578
+ // Adapted from https://github.com/apache/echarts/blob/master/src/util/graphic.ts by striezel
4579
+ // License: https://github.com/apache/echarts/blob/master/LICENSE
4580
+ /**
4581
+ * Return `true` if the given line (line `a`) and the given polygon
4582
+ * are intersect.
4583
+ * Note that we do not count colinear as intersect here because no
4584
+ * requirement for that. We could do that if required in future.
4585
+ */
3618
4586
  function lineIntersectPolygon(a1x, a1y, a2x, a2y, points) {
3619
4587
  for (let i = 0, p2 = points[points.length - 1]; i < points.length; i++) {
3620
4588
  const p = points[i];
@@ -3625,6 +4593,8 @@
3625
4593
  }
3626
4594
  return false;
3627
4595
  }
4596
+ // Adapted from https://github.com/ecomfe/zrender/blob/master/src/contain/polygon.ts by pissang
4597
+ // License: https://github.com/ecomfe/zrender/blob/master/LICENSE
3628
4598
  function polygonContainPoint(points, x, y) {
3629
4599
  let w = 0;
3630
4600
  let p = points[0];
@@ -3636,30 +4606,44 @@
3636
4606
  w += isPointInLine(p.x, p.y, p2.x, p2.y, x, y);
3637
4607
  p = p2;
3638
4608
  }
4609
+ // Close polygon
3639
4610
  const p0 = points[0];
3640
4611
  if (!isAroundEqual(p.x, p0.x) || !isAroundEqual(p.y, p0.y)) {
3641
4612
  w += isPointInLine(p.x, p.y, p0.x, p0.y, x, y);
3642
4613
  }
3643
4614
  return w !== 0;
3644
4615
  }
4616
+ // Adapted from https://github.com/ecomfe/zrender/blob/master/src/contain/windingLine.ts by pissang
4617
+ // License: https://github.com/ecomfe/zrender/blob/master/LICENSE
3645
4618
  function isPointInLine(x0, y0, x1, y1, x, y) {
3646
4619
  if ((y > y0 && y > y1) || (y < y0 && y < y1)) {
3647
4620
  return 0;
3648
4621
  }
4622
+ // Ignore horizontal line
3649
4623
  if (y1 === y0) {
3650
4624
  return 0;
3651
4625
  }
3652
4626
  const t = (y - y0) / (y1 - y0);
3653
4627
  let dir = y1 < y0 ? 1 : -1;
4628
+ // Avoid winding error when intersection point is the connect point of two line of polygon
3654
4629
  if (t === 1 || t === 0) {
3655
4630
  dir = y1 < y0 ? 0.5 : -0.5;
3656
4631
  }
3657
4632
  const x_ = t * (x1 - x0) + x0;
4633
+ // If (x, y) on the line, considered as "contain".
3658
4634
  return x_ === x ? Infinity : x_ > x ? dir : 0;
3659
4635
  }
4636
+ // Adapted from https://github.com/ecomfe/zrender/blob/master/src/contain/polygon.ts by pissang
4637
+ // License: https://github.com/ecomfe/zrender/blob/master/LICENSE
3660
4638
  function isAroundEqual(a, b) {
3661
4639
  return Math.abs(a - b) < EPSILON;
3662
4640
  }
4641
+ /**
4642
+ * polygon图元之间是否相交
4643
+ * @param pointsA 图元A的points
4644
+ * @param pointsB 图元B的points
4645
+ * @returns 是否相交
4646
+ */
3663
4647
  function polygonIntersectPolygon(pointsA, pointsB) {
3664
4648
  for (let i = 0; i < pointsB.length; i++) {
3665
4649
  if (polygonContainPoint(pointsA, pointsB[i].x, pointsB[i].y)) {
@@ -3716,9 +4700,11 @@
3716
4700
  let width = 0;
3717
4701
  for (const character of string) {
3718
4702
  const codePoint = character.codePointAt(0);
4703
+ // Ignore control characters
3719
4704
  if (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f)) {
3720
4705
  continue;
3721
4706
  }
4707
+ // Ignore combining characters
3722
4708
  if (codePoint >= 0x300 && codePoint <= 0x36f) {
3723
4709
  continue;
3724
4710
  }
@@ -3745,6 +4731,7 @@
3745
4731
  };
3746
4732
  const ansiRegex = ({ onlyFirst = false } = {}) => {
3747
4733
  const pattern = [
4734
+ // eslint-disable-next-line max-len
3748
4735
  '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
3749
4736
  '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))'
3750
4737
  ].join('|');
@@ -4001,9 +4988,12 @@
4001
4988
  return 'N';
4002
4989
  };
4003
4990
  const emojiRegex = () => {
4991
+ // https://mths.be/emoji
4992
+ // eslint-disable-next-line max-len
4004
4993
  return /[#*0-9]\uFE0F?\u20E3|[\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23ED-\u23EF\u23F1\u23F2\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB\u25FC\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692\u2694-\u2697\u2699\u269B\u269C\u26A0\u26A7\u26AA\u26B0\u26B1\u26BD\u26BE\u26C4\u26C8\u26CF\u26D1\u26D3\u26E9\u26F0-\u26F5\u26F7\u26F8\u26FA\u2702\u2708\u2709\u270F\u2712\u2714\u2716\u271D\u2721\u2733\u2734\u2744\u2747\u2757\u2763\u27A1\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B55\u3030\u303D\u3297\u3299]\uFE0F?|[\u261D\u270C\u270D](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\u270A\u270B](?:\uD83C[\uDFFB-\uDFFF])?|[\u23E9-\u23EC\u23F0\u23F3\u25FD\u2693\u26A1\u26AB\u26C5\u26CE\u26D4\u26EA\u26FD\u2705\u2728\u274C\u274E\u2753-\u2755\u2795-\u2797\u27B0\u27BF\u2B50]|\u26F9(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\u2764\uFE0F?(?:\u200D(?:\uD83D\uDD25|\uD83E\uDE79))?|\uD83C(?:[\uDC04\uDD70\uDD71\uDD7E\uDD7F\uDE02\uDE37\uDF21\uDF24-\uDF2C\uDF36\uDF7D\uDF96\uDF97\uDF99-\uDF9B\uDF9E\uDF9F\uDFCD\uDFCE\uDFD4-\uDFDF\uDFF5\uDFF7]\uFE0F?|[\uDF85\uDFC2\uDFC7](?:\uD83C[\uDFFB-\uDFFF])?|[\uDFC3\uDFC4\uDFCA](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDFCB\uDFCC](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDCCF\uDD8E\uDD91-\uDD9A\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF84\uDF86-\uDF93\uDFA0-\uDFC1\uDFC5\uDFC6\uDFC8\uDFC9\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF8-\uDFFF]|\uDDE6\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF]|\uDDE7\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF]|\uDDE8\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF]|\uDDE9\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF]|\uDDEA\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA]|\uDDEB\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7]|\uDDEC\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE]|\uDDED\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA]|\uDDEE\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9]|\uDDEF\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5]|\uDDF0\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF]|\uDDF1\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE]|\uDDF2\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF]|\uDDF3\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF]|\uDDF4\uD83C\uDDF2|\uDDF5\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE]|\uDDF6\uD83C\uDDE6|\uDDF7\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC]|\uDDF8\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF]|\uDDF9\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF]|\uDDFA\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF]|\uDDFB\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA]|\uDDFC\uD83C[\uDDEB\uDDF8]|\uDDFD\uD83C\uDDF0|\uDDFE\uD83C[\uDDEA\uDDF9]|\uDDFF\uD83C[\uDDE6\uDDF2\uDDFC]|\uDFF3\uFE0F?(?:\u200D(?:\u26A7\uFE0F?|\uD83C\uDF08))?|\uDFF4(?:\u200D\u2620\uFE0F?|\uDB40\uDC67\uDB40\uDC62\uDB40(?:\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDC73\uDB40\uDC63\uDB40\uDC74|\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F)?)|\uD83D(?:[\uDC08\uDC26](?:\u200D\u2B1B)?|[\uDC3F\uDCFD\uDD49\uDD4A\uDD6F\uDD70\uDD73\uDD76-\uDD79\uDD87\uDD8A-\uDD8D\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA\uDECB\uDECD-\uDECF\uDEE0-\uDEE5\uDEE9\uDEF0\uDEF3]\uFE0F?|[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDC8F\uDC91\uDCAA\uDD7A\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC](?:\uD83C[\uDFFB-\uDFFF])?|[\uDC6E\uDC70\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD74\uDD90](?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?|[\uDC00-\uDC07\uDC09-\uDC14\uDC16-\uDC25\uDC27-\uDC3A\uDC3C-\uDC3E\uDC40\uDC44\uDC45\uDC51-\uDC65\uDC6A\uDC79-\uDC7B\uDC7D-\uDC80\uDC84\uDC88-\uDC8E\uDC90\uDC92-\uDCA9\uDCAB-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDDA4\uDDFB-\uDE2D\uDE2F-\uDE34\uDE37-\uDE44\uDE48-\uDE4A\uDE80-\uDEA2\uDEA4-\uDEB3\uDEB7-\uDEBF\uDEC1-\uDEC5\uDED0-\uDED2\uDED5-\uDED7\uDEDC-\uDEDF\uDEEB\uDEEC\uDEF4-\uDEFC\uDFE0-\uDFEB\uDFF0]|\uDC15(?:\u200D\uD83E\uDDBA)?|\uDC3B(?:\u200D\u2744\uFE0F?)?|\uDC41\uFE0F?(?:\u200D\uD83D\uDDE8\uFE0F?)?|\uDC68(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDC68\uDC69]\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?)|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?\uDC68\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D\uDC68\uD83C[\uDFFB-\uDFFE])))?))?|\uDC69(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:\uDC8B\u200D\uD83D)?[\uDC68\uDC69]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D(?:[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?|\uDC69\u200D\uD83D(?:\uDC66(?:\u200D\uD83D\uDC66)?|\uDC67(?:\u200D\uD83D[\uDC66\uDC67])?))|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFC-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFD-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFD\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D\uD83D(?:[\uDC68\uDC69]|\uDC8B\u200D\uD83D[\uDC68\uDC69])\uD83C[\uDFFB-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83D[\uDC68\uDC69]\uD83C[\uDFFB-\uDFFE])))?))?|\uDC6F(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDD75(?:\uFE0F|\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|\uDE2E(?:\u200D\uD83D\uDCA8)?|\uDE35(?:\u200D\uD83D\uDCAB)?|\uDE36(?:\u200D\uD83C\uDF2B\uFE0F?)?)|\uD83E(?:[\uDD0C\uDD0F\uDD18-\uDD1F\uDD30-\uDD34\uDD36\uDD77\uDDB5\uDDB6\uDDBB\uDDD2\uDDD3\uDDD5\uDEC3-\uDEC5\uDEF0\uDEF2-\uDEF8](?:\uD83C[\uDFFB-\uDFFF])?|[\uDD26\uDD35\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD4\uDDD6-\uDDDD](?:\uD83C[\uDFFB-\uDFFF])?(?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDDDE\uDDDF](?:\u200D[\u2640\u2642]\uFE0F?)?|[\uDD0D\uDD0E\uDD10-\uDD17\uDD20-\uDD25\uDD27-\uDD2F\uDD3A\uDD3F-\uDD45\uDD47-\uDD76\uDD78-\uDDB4\uDDB7\uDDBA\uDDBC-\uDDCC\uDDD0\uDDE0-\uDDFF\uDE70-\uDE7C\uDE80-\uDE88\uDE90-\uDEBD\uDEBF-\uDEC2\uDECE-\uDEDB\uDEE0-\uDEE8]|\uDD3C(?:\u200D[\u2640\u2642]\uFE0F?|\uD83C[\uDFFB-\uDFFF])?|\uDDD1(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1))|\uD83C(?:\uDFFB(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFC-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFC(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFD-\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFD(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFE(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFD\uDFFF]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?|\uDFFF(?:\u200D(?:[\u2695\u2696\u2708]\uFE0F?|\u2764\uFE0F?\u200D(?:\uD83D\uDC8B\u200D)?\uD83E\uDDD1\uD83C[\uDFFB-\uDFFE]|\uD83C[\uDF3E\uDF73\uDF7C\uDF84\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E(?:[\uDDAF-\uDDB3\uDDBC\uDDBD]|\uDD1D\u200D\uD83E\uDDD1\uD83C[\uDFFB-\uDFFF])))?))?|\uDEF1(?:\uD83C(?:\uDFFB(?:\u200D\uD83E\uDEF2\uD83C[\uDFFC-\uDFFF])?|\uDFFC(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFD-\uDFFF])?|\uDFFD(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])?|\uDFFE(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFD\uDFFF])?|\uDFFF(?:\u200D\uD83E\uDEF2\uD83C[\uDFFB-\uDFFE])?))?)/g;
4005
4994
  };
4006
4995
 
4996
+ // FIXME: from VRender
4007
4997
  function getContextFont(text, defaultAttr = {}, fontSizeScale) {
4008
4998
  if (!fontSizeScale) {
4009
4999
  fontSizeScale = 1;
@@ -4020,16 +5010,25 @@
4020
5010
 
4021
5011
  class TextMeasure {
4022
5012
  constructor(option, textSpec) {
5013
+ /** 数字大小缓存 */
4023
5014
  this._numberCharSize = null;
5015
+ /** 全角字符大小缓存 */
4024
5016
  this._fullCharSize = null;
5017
+ /** 字母大小缓存 */
4025
5018
  this._letterCharSize = null;
5019
+ /** 特殊字符缓存 */
4026
5020
  this._specialCharSizeMap = {};
5021
+ /** 内置测量 canvas */
4027
5022
  this._canvas = null;
4028
5023
  this._context = null;
4029
5024
  this._contextSaved = false;
5025
+ /** 是否不支持 canvas */
4030
5026
  this._notSupportCanvas = false;
5027
+ /** 是否不支持 vrender */
4031
5028
  this._notSupportVRender = false;
5029
+ /** 文字 spec */
4032
5030
  this._userSpec = {};
5031
+ /** 特殊字符集 */
4033
5032
  this.specialCharSet = '-/: .,@%\'"~';
4034
5033
  this._option = option;
4035
5034
  this._userSpec = textSpec !== null && textSpec !== void 0 ? textSpec : {};
@@ -4041,6 +5040,7 @@
4041
5040
  ? this.fullMeasure.bind(this)
4042
5041
  : this.measureWithNaiveCanvas.bind(this);
4043
5042
  }
5043
+ /** 初始化测量相关上下文 */
4044
5044
  initContext() {
4045
5045
  if (this._notSupportCanvas) {
4046
5046
  return false;
@@ -4054,6 +5054,7 @@
4054
5054
  typeof window.document !== 'undefined' &&
4055
5055
  globalThis &&
4056
5056
  isValid(globalThis.document)) {
5057
+ // 默认创建方法
4057
5058
  this._canvas = globalThis.document.createElement('canvas');
4058
5059
  }
4059
5060
  }
@@ -4094,6 +5095,7 @@
4094
5095
  lineHeight
4095
5096
  };
4096
5097
  }
5098
+ /** 计算文本宽高 */
4097
5099
  measure(text, method) {
4098
5100
  switch (method) {
4099
5101
  case 'vrender':
@@ -4108,12 +5110,13 @@
4108
5110
  return this.quickMeasure(text);
4109
5111
  }
4110
5112
  }
5113
+ /** 精确计算文本宽高 */
4111
5114
  fullMeasure(text) {
4112
5115
  if (isNil(text)) {
4113
5116
  return { width: 0, height: 0 };
4114
5117
  }
4115
5118
  if (isNil(this._option.getTextBounds) || !this._notSupportVRender) {
4116
- return this.measureWithNaiveCanvas(text);
5119
+ return this.measureWithNaiveCanvas(text); // 降级
4117
5120
  }
4118
5121
  const { fontFamily, fontSize, fontWeight, textAlign, textBaseline, ellipsis, limit, lineHeight } = this.textSpec;
4119
5122
  let size;
@@ -4133,17 +5136,18 @@
4133
5136
  }
4134
5137
  catch (e) {
4135
5138
  this._notSupportVRender = true;
4136
- size = this.measureWithNaiveCanvas(text);
5139
+ size = this.measureWithNaiveCanvas(text); // 降级
4137
5140
  }
4138
5141
  return size;
4139
5142
  }
5143
+ /** 通过原生 canvas 精确计算文本宽度,高度为估算 */
4140
5144
  measureWithNaiveCanvas(text) {
4141
5145
  return this._measureReduce(text, this._measureWithNaiveCanvas.bind(this));
4142
5146
  }
4143
5147
  _measureWithNaiveCanvas(text) {
4144
5148
  var _a;
4145
5149
  if (!this.initContext()) {
4146
- return this._quickMeasureWithoutCanvas(text);
5150
+ return this._quickMeasureWithoutCanvas(text); // 降级
4147
5151
  }
4148
5152
  const metrics = this._context.measureText(text);
4149
5153
  const { fontSize, lineHeight } = this.textSpec;
@@ -4154,6 +5158,7 @@
4154
5158
  fontBoundingBoxDescent: metrics.fontBoundingBoxDescent
4155
5159
  };
4156
5160
  }
5161
+ /** 快速估算文本宽高 */
4157
5162
  quickMeasure(text) {
4158
5163
  return this._measureReduce(text, this._quickMeasure.bind(this));
4159
5164
  }
@@ -4164,13 +5169,17 @@
4164
5169
  };
4165
5170
  for (let i = 0; i < text.length; i++) {
4166
5171
  const char = text[i];
5172
+ // 先判断是否特殊字符
4167
5173
  let size = this._measureSpecialChar(char);
5174
+ // 再判断是否数字
4168
5175
  if (isNil(size) && TextMeasure.NUMBERS_CHAR_SET.includes(char)) {
4169
5176
  size = this._measureNumberChar();
4170
5177
  }
5178
+ // 再判断全角字符
4171
5179
  if (isNil(size) && ['F', 'W'].includes(eastAsianCharacterInfo(char))) {
4172
5180
  size = this._measureFullSizeChar();
4173
5181
  }
5182
+ // 最后按半角字符处理
4174
5183
  if (isNil(size)) {
4175
5184
  size = this._measureLetterChar();
4176
5185
  }
@@ -4181,6 +5190,7 @@
4181
5190
  }
4182
5191
  return totalSize;
4183
5192
  }
5193
+ /** 不使用 canvas 来快速估算文本宽高 */
4184
5194
  quickMeasureWithoutCanvas(text) {
4185
5195
  return this._measureReduce(text, this._quickMeasureWithoutCanvas.bind(this));
4186
5196
  }
@@ -4193,6 +5203,7 @@
4193
5203
  const { fontSize, lineHeight } = this.textSpec;
4194
5204
  for (let i = 0; i < text.length; i++) {
4195
5205
  const char = text[i];
5206
+ // 判断全角字符
4196
5207
  const size = ['F', 'W'].includes(eastAsianCharacterInfo(char)) ? 1 : 0.53;
4197
5208
  totalSize.width += size * fontSize;
4198
5209
  }
@@ -4216,11 +5227,12 @@
4216
5227
  }
4217
5228
  return {
4218
5229
  width: textArr.reduce((maxWidth, cur) => Math.max(maxWidth, processor(cur).width), 0),
4219
- height: textArr.length * (((_a = lineHeight) !== null && _a !== void 0 ? _a : fontSize) + 1) + 1
5230
+ height: textArr.length * (((_a = lineHeight) !== null && _a !== void 0 ? _a : fontSize) + 1) + 1 // 经验值
4220
5231
  };
4221
5232
  }
4222
5233
  return processor(text.toString());
4223
5234
  }
5235
+ /** 测量一个数字 */
4224
5236
  _measureNumberChar() {
4225
5237
  if (isNil(this._numberCharSize)) {
4226
5238
  const numberBounds = this._standardMethod(TextMeasure.NUMBERS_CHAR_SET);
@@ -4233,12 +5245,14 @@
4233
5245
  }
4234
5246
  return this._numberCharSize;
4235
5247
  }
5248
+ /** 测量一个全角字符 */
4236
5249
  _measureFullSizeChar() {
4237
5250
  if (isNil(this._fullCharSize)) {
4238
5251
  this._fullCharSize = this._standardMethod(TextMeasure.FULL_SIZE_CHAR);
4239
5252
  }
4240
5253
  return this._fullCharSize;
4241
5254
  }
5255
+ /** 测量一个英文字符 */
4242
5256
  _measureLetterChar() {
4243
5257
  if (isNil(this._letterCharSize)) {
4244
5258
  const alphabetBounds = this._standardMethod(TextMeasure.ALPHABET_CHAR_SET);
@@ -4251,6 +5265,7 @@
4251
5265
  }
4252
5266
  return this._letterCharSize;
4253
5267
  }
5268
+ /** 测量一个特殊字符 */
4254
5269
  _measureSpecialChar(char) {
4255
5270
  if (isValid(this._specialCharSizeMap[char])) {
4256
5271
  return this._specialCharSizeMap[char];
@@ -4274,8 +5289,11 @@
4274
5289
  }
4275
5290
  }
4276
5291
  }
5292
+ /** 英文字母集 */
4277
5293
  TextMeasure.ALPHABET_CHAR_SET = 'abcdefghijklmnopqrstuvwxyz';
5294
+ /** 数字集 */
4278
5295
  TextMeasure.NUMBERS_CHAR_SET = '0123456789';
5296
+ /** 全角字符 */
4279
5297
  TextMeasure.FULL_SIZE_CHAR = '字';
4280
5298
 
4281
5299
  const calculateAnchorOfBounds = (bounds, anchorType) => {
@@ -4331,26 +5349,28 @@
4331
5349
  { x: Math.cos(a.angle), y: Math.sin(a.angle) },
4332
5350
  { x: -Math.sin(a.angle), y: Math.cos(a.angle) },
4333
5351
  { x: Math.cos(b.angle), y: Math.sin(a.angle) },
4334
- { x: -Math.sin(b.angle), y: Math.cos(a.angle) }
5352
+ { x: -Math.sin(b.angle), y: Math.cos(a.angle) } // Rect B's second axis
4335
5353
  ];
5354
+ // calculate the projection range of a rectangle on a given axis
4336
5355
  function getProjectionRange(obb, axisX, axisY) {
4337
5356
  const corners = obb.getRotatedCorners();
4338
5357
  const projections = corners.map(p => p.x * axisX + p.y * axisY);
4339
5358
  return { min: Math.min(...projections), max: Math.max(...projections) };
4340
5359
  }
5360
+ // Calculate distances for all axes
4341
5361
  let maxDistance = 0;
4342
5362
  for (const axis of axes) {
4343
5363
  const rangeA = getProjectionRange(a, axis.x, axis.y);
4344
5364
  const rangeB = getProjectionRange(b, axis.x, axis.y);
4345
5365
  let distance;
4346
5366
  if (rangeA.max < rangeB.min) {
4347
- distance = rangeB.min - rangeA.max;
5367
+ distance = rangeB.min - rangeA.max; // B is to the right of A
4348
5368
  }
4349
5369
  else if (rangeB.max < rangeA.min) {
4350
- distance = rangeA.min - rangeB.max;
5370
+ distance = rangeA.min - rangeB.max; // A is to the right of B
4351
5371
  }
4352
5372
  else {
4353
- distance = 0;
5373
+ distance = 0; // Overlapping
4354
5374
  }
4355
5375
  maxDistance = Math.max(maxDistance, distance);
4356
5376
  }
@@ -4359,6 +5379,7 @@
4359
5379
 
4360
5380
  function transformBoundsWithMatrix(out, bounds, matrix) {
4361
5381
  const { x1, y1, x2, y2 } = bounds;
5382
+ // 如果没有旋转和缩放,那就直接translate
4362
5383
  if (matrix.onlyTranslate()) {
4363
5384
  if (out !== bounds) {
4364
5385
  out.setValue(bounds.x1, bounds.y1, bounds.x2, bounds.y2);
@@ -4373,6 +5394,16 @@
4373
5394
  out.add(matrix.a * x1 + matrix.c * y2 + matrix.e, matrix.b * x1 + matrix.d * y2 + matrix.f);
4374
5395
  return bounds;
4375
5396
  }
5397
+ /**
5398
+ * 依据graphic的属性对bounds进行变换
5399
+ * @param bounds
5400
+ * @param x
5401
+ * @param y
5402
+ * @param scaleX
5403
+ * @param scaleY
5404
+ * @param angle
5405
+ * @param rotateCenter
5406
+ */
4376
5407
  function transformBounds(bounds, x, y, scaleX, scaleY, angle, rotateCenter) {
4377
5408
  if (abs(scaleX) <= epsilon || abs(scaleY) <= epsilon) {
4378
5409
  return;
@@ -4390,6 +5421,37 @@
4390
5421
  }
4391
5422
  bounds.translate(x, y);
4392
5423
  }
5424
+ /**
5425
+ Copyright (c) 2015-2021, University of Washington Interactive Data Lab
5426
+ All rights reserved.
5427
+
5428
+ Redistribution and use in source and binary forms, with or without
5429
+ modification, are permitted provided that the following conditions are met:
5430
+
5431
+ 1. Redistributions of source code must retain the above copyright notice, this
5432
+ list of conditions and the following disclaimer.
5433
+
5434
+ 2. Redistributions in binary form must reproduce the above copyright notice,
5435
+ this list of conditions and the following disclaimer in the documentation
5436
+ and/or other materials provided with the distribution.
5437
+
5438
+ 3. Neither the name of the copyright holder nor the names of its contributors
5439
+ may be used to endorse or promote products derived from this software
5440
+ without specific prior written permission.
5441
+
5442
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
5443
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5444
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
5445
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
5446
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5447
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
5448
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
5449
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
5450
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
5451
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5452
+ */
5453
+ // 基于Vega的Bounds重构
5454
+ // https://github.com/vega/vega/blob/825bfaba6ccfe3306183df22b8c955a07bb30714/packages/vega-scenegraph/src/Bounds.js
4393
5455
  class Bounds {
4394
5456
  constructor(bounds) {
4395
5457
  if (bounds) {
@@ -4496,6 +5558,11 @@
4496
5558
  const p = this.scalePoints(sx, sy, x, y);
4497
5559
  return this.clear().add(p[0], p[1]).add(p[2], p[3]);
4498
5560
  }
5561
+ /**
5562
+ * 并集
5563
+ * @param b
5564
+ * @returns
5565
+ */
4499
5566
  union(b) {
4500
5567
  if (b.x1 < this.x1) {
4501
5568
  this.x1 = b.x1;
@@ -4511,6 +5578,11 @@
4511
5578
  }
4512
5579
  return this;
4513
5580
  }
5581
+ /**
5582
+ * 交集
5583
+ * @param b
5584
+ * @returns
5585
+ */
4514
5586
  intersect(b) {
4515
5587
  if (b.x1 > this.x1) {
4516
5588
  this.x1 = b.x1;
@@ -4526,15 +5598,36 @@
4526
5598
  }
4527
5599
  return this;
4528
5600
  }
5601
+ /**
5602
+ * 是否包含b
5603
+ * @param b
5604
+ * @returns
5605
+ */
4529
5606
  encloses(b) {
4530
5607
  return b && this.x1 <= b.x1 && this.x2 >= b.x2 && this.y1 <= b.y1 && this.y2 >= b.y2;
4531
5608
  }
5609
+ /**
5610
+ * 是否共边
5611
+ * @param b
5612
+ * @returns
5613
+ */
4532
5614
  alignsWith(b) {
4533
5615
  return b && (this.x1 === b.x1 || this.x2 === b.x2 || this.y1 === b.y1 || this.y2 === b.y2);
4534
5616
  }
5617
+ /**
5618
+ * 是否相交
5619
+ * @param b
5620
+ * @returns
5621
+ */
4535
5622
  intersects(b) {
4536
5623
  return b && !(this.x2 < b.x1 || this.x1 > b.x2 || this.y2 < b.y1 || this.y1 > b.y2);
4537
5624
  }
5625
+ /**
5626
+ * 是否包含
5627
+ * @param x
5628
+ * @param y
5629
+ * @returns
5630
+ */
4538
5631
  contains(x = 0, y = 0) {
4539
5632
  return !(x < this.x1 || x > this.x2 || y < this.y1 || y > this.y2);
4540
5633
  }
@@ -4640,6 +5733,7 @@
4640
5733
  this.f = f;
4641
5734
  }
4642
5735
  equalToMatrix(m2) {
5736
+ // ef -> ad -> bc
4643
5737
  return !(this.e !== m2.e ||
4644
5738
  this.f !== m2.f ||
4645
5739
  this.a !== m2.a ||
@@ -4648,6 +5742,7 @@
4648
5742
  this.c !== m2.c);
4649
5743
  }
4650
5744
  equalTo(a, b, c, d, e, f) {
5745
+ // ef -> ad -> bc
4651
5746
  return !(this.e !== e || this.f !== f || this.a !== a || this.d !== d || this.b !== b || this.c !== c);
4652
5747
  }
4653
5748
  setValue(a, b, c, d, e, f) {
@@ -4668,6 +5763,9 @@
4668
5763
  this.f = 0;
4669
5764
  return this;
4670
5765
  }
5766
+ /**
5767
+ * 获取当前矩阵的逆矩阵
5768
+ */
4671
5769
  getInverse() {
4672
5770
  const a = this.a;
4673
5771
  const b = this.b;
@@ -4699,6 +5797,17 @@
4699
5797
  return this;
4700
5798
  }
4701
5799
  rotateByCenter(rad, cx, cy) {
5800
+ /** rotate matrix
5801
+ * | cos -sin (1-cos)*cx+sin*cy |
5802
+ * | sin cos (1-cos)*cy-sin*cx |
5803
+ * | 0 0 1 |
5804
+ * after multiply
5805
+ * m13 = (1-cos)*cx+sin*cy;
5806
+ * m23 = (1-cos)*cy-sin*cx;
5807
+ * | cos*a-sin*b cos*c-sin*d cos*e-sin*f+m13 |
5808
+ * | sin*a+cos*b sin*c+cos*d sin*e+cos*f+m23 |
5809
+ * | 0 0 1 |
5810
+ */
4702
5811
  const cos = Math.cos(rad);
4703
5812
  const sin = Math.sin(rad);
4704
5813
  const rotateM13 = (1 - cos) * cx + sin * cy;
@@ -4741,6 +5850,15 @@
4741
5850
  return this;
4742
5851
  }
4743
5852
  transpose() {
5853
+ /** transpose matrix
5854
+ * | 0 1 0 |
5855
+ * | 1 0 0 |
5856
+ * | 0 0 1 |
5857
+ * after multiply
5858
+ * | b d f |
5859
+ * | a c e |
5860
+ * | 0 0 1 |
5861
+ */
4744
5862
  const { a, b, c, d, e, f } = this;
4745
5863
  this.a = b;
4746
5864
  this.b = a;
@@ -4750,6 +5868,10 @@
4750
5868
  this.f = e;
4751
5869
  return this;
4752
5870
  }
5871
+ /**
5872
+ * 矩阵相乘
5873
+ * @param matrix
5874
+ */
4753
5875
  multiply(a2, b2, c2, d2, e2, f2) {
4754
5876
  const a1 = this.a;
4755
5877
  const b1 = this.b;
@@ -4771,6 +5893,11 @@
4771
5893
  this.f = dy;
4772
5894
  return this;
4773
5895
  }
5896
+ /**
5897
+ * 插值计算
5898
+ * @param m2
5899
+ * @param t
5900
+ */
4774
5901
  interpolate(m2, t) {
4775
5902
  const m = new Matrix();
4776
5903
  m.a = this.a + (m2.a - this.a) * t;
@@ -4781,6 +5908,11 @@
4781
5908
  m.f = this.f + (m2.f - this.f) * t;
4782
5909
  return m;
4783
5910
  }
5911
+ /**
5912
+ * 将point转到当前矩阵的坐标空间中
5913
+ * @param source
5914
+ * @param target
5915
+ */
4784
5916
  transformPoint(source, target) {
4785
5917
  const { a, b, c, d, e, f } = this;
4786
5918
  const dt = a * d - b * c;
@@ -4794,6 +5926,7 @@
4794
5926
  target.x = x * nextA + y * nextC + nextE;
4795
5927
  target.y = x * nextB + y * nextD + nextF;
4796
5928
  }
5929
+ // 只有translate
4797
5930
  onlyTranslate(scale = 1) {
4798
5931
  return this.a === scale && this.b === 0 && this.c === 0 && this.d === scale;
4799
5932
  }
@@ -4817,6 +5950,7 @@
4817
5950
  skewX: 0,
4818
5951
  skewY: 0
4819
5952
  };
5953
+ // Apply the QR-like decomposition.
4820
5954
  if (a !== 0 || b !== 0) {
4821
5955
  const r = Math.sqrt(a * a + b * b);
4822
5956
  result.rotateDeg = b > 0 ? Math.acos(a / r) : -Math.acos(a / r);
@@ -4838,6 +5972,17 @@
4838
5972
  return result;
4839
5973
  }
4840
5974
  }
5975
+ /**
5976
+ * 对matrix进行通常的变换(基于rotateCenter进行旋转的同时进行translate和scale)
5977
+ * @param out
5978
+ * @param origin
5979
+ * @param x
5980
+ * @param y
5981
+ * @param scaleX
5982
+ * @param scaleY
5983
+ * @param angle
5984
+ * @param rotateCenter
5985
+ */
4841
5986
  function normalTransform(out, origin, x, y, scaleX, scaleY, angle, rotateCenter) {
4842
5987
  const oa = origin.a;
4843
5988
  const ob = origin.b;
@@ -4871,18 +6016,20 @@
4871
6016
  out.f = of + ob * rotateCenterX + od * rotateCenterY - b1 * offsetX - d1 * offsetY;
4872
6017
  }
4873
6018
 
6019
+ // LRU清除
4874
6020
  class LRU {
4875
6021
  constructor() {
4876
6022
  this.CLEAN_THRESHOLD = 1e3;
4877
- this.L_TIME = 1000;
4878
- this.R_COUNT = 1;
4879
- this.R_TIMESTAMP_MAX_SIZE = 20;
6023
+ this.L_TIME = 1000; // 1000ms以内
6024
+ this.R_COUNT = 1; // 使用次数为0
6025
+ this.R_TIMESTAMP_MAX_SIZE = 20; // timestamp最大长度
4880
6026
  }
4881
6027
  clearCache(cache, params) {
4882
6028
  const { CLEAN_THRESHOLD = this.CLEAN_THRESHOLD, L_TIME = this.L_TIME, R_COUNT = this.R_COUNT } = params;
4883
6029
  if (cache.size < CLEAN_THRESHOLD) {
4884
6030
  return 0;
4885
6031
  }
6032
+ // 开始清理,清理最近1000ms内使用次数为0的缓存
4886
6033
  let clearNum = 0;
4887
6034
  const clear = (key) => {
4888
6035
  clearNum++;
@@ -4892,7 +6039,7 @@
4892
6039
  cache.forEach((item, key) => {
4893
6040
  if (item.timestamp.length < R_COUNT) {
4894
6041
  return clear(key);
4895
- }
6042
+ } // 最近使用次数小于R_COUNT,清除
4896
6043
  let useCount = 0;
4897
6044
  while (now - item.timestamp[item.timestamp.length - 1 - useCount] < L_TIME) {
4898
6045
  useCount++;
@@ -4902,7 +6049,8 @@
4902
6049
  }
4903
6050
  if (useCount < R_COUNT) {
4904
6051
  return clear(key);
4905
- }
6052
+ } // 最近L_TIME以内使用次数小于R_COUNT,清除
6053
+ // 清除L_TIME以外的key,避免数组过长
4906
6054
  while (now - item.timestamp[0] > L_TIME) {
4907
6055
  item.timestamp.shift();
4908
6056
  }
@@ -4913,6 +6061,7 @@
4913
6061
  addLimitedTimestamp(cacheItem, t, params) {
4914
6062
  const { R_TIMESTAMP_MAX_SIZE = this.R_TIMESTAMP_MAX_SIZE } = params;
4915
6063
  if (cacheItem.timestamp.length > R_TIMESTAMP_MAX_SIZE) {
6064
+ // cacheItem.timestamp[cacheItem.timestamp.length-1] =
4916
6065
  cacheItem.timestamp.shift();
4917
6066
  }
4918
6067
  cacheItem.timestamp.push(t);
@@ -4984,6 +6133,7 @@
4984
6133
  r /= 255;
4985
6134
  g /= 255;
4986
6135
  b /= 255;
6136
+ // Find greatest and smallest channel values
4987
6137
  const cMin = Math.min(r, g, b);
4988
6138
  const cMax = Math.max(r, g, b);
4989
6139
  const delta = cMax - cMin;
@@ -4993,12 +6143,15 @@
4993
6143
  if (delta === 0) {
4994
6144
  h = 0;
4995
6145
  }
6146
+ // Red is max
4996
6147
  else if (cMax === r) {
4997
6148
  h = ((g - b) / delta) % 6;
4998
6149
  }
6150
+ // Green is max
4999
6151
  else if (cMax === g) {
5000
6152
  h = (b - r) / delta + 2;
5001
6153
  }
6154
+ // Blue is max
5002
6155
  else {
5003
6156
  h = (r - g) / delta + 4;
5004
6157
  }
@@ -5007,7 +6160,9 @@
5007
6160
  h += 360;
5008
6161
  }
5009
6162
  l = (cMax + cMin) / 2;
6163
+ // Calculate saturation
5010
6164
  s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
6165
+ // Multiply l and s by 100
5011
6166
  s = +(s * 100).toFixed(1);
5012
6167
  l = +(l * 100).toFixed(1);
5013
6168
  return {
@@ -5017,6 +6172,34 @@
5017
6172
  };
5018
6173
  }
5019
6174
 
6175
+ /*
6176
+ Copyright (c) 2013, Jason Davies.
6177
+ All rights reserved.
6178
+
6179
+ Redistribution and use in source and binary forms, with or without
6180
+ modification, are permitted provided that the following conditions are met:
6181
+
6182
+ * Redistributions of source code must retain the above copyright notice, this
6183
+ list of conditions and the following disclaimer.
6184
+
6185
+ * Redistributions in binary form must reproduce the above copyright notice,
6186
+ this list of conditions and the following disclaimer in the documentation
6187
+ and/or other materials provided with the distribution.
6188
+
6189
+ * The name Jason Davies may not be used to endorse or promote products
6190
+ derived from this software without specific prior written permission.
6191
+
6192
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
6193
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
6194
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
6195
+ DISCLAIMED. IN NO EVENT SHALL JASON DAVIES BE LIABLE FOR ANY DIRECT, INDIRECT,
6196
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
6197
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
6198
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
6199
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
6200
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
6201
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6202
+ */
5020
6203
  const REG_HEX = /^#([0-9a-f]{3,8})$/;
5021
6204
  const DEFAULT_COLORS_OPACITY = {
5022
6205
  transparent: 0xffffff00
@@ -5182,6 +6365,7 @@
5182
6365
  else if (isArray(value)) {
5183
6366
  return new RGB(value[0], value[1], value[2]);
5184
6367
  }
6368
+ // default return
5185
6369
  return new RGB(255, 255, 255);
5186
6370
  }
5187
6371
  function rgba(value) {
@@ -5191,6 +6375,7 @@
5191
6375
  else if (isArray(value)) {
5192
6376
  return new RGB(value[0], value[1], value[2], value[3]);
5193
6377
  }
6378
+ // default return
5194
6379
  return new RGB(255, 255, 255, 1);
5195
6380
  }
5196
6381
  function SRGBToLinear(c) {
@@ -5204,12 +6389,15 @@
5204
6389
  if (forceHex || isHex) {
5205
6390
  const hex = parseInt(isHex[1], 16);
5206
6391
  const hexLength = isHex[1].length;
6392
+ // #fff
5207
6393
  if (hexLength === 3) {
5208
6394
  return new RGB(((hex >> 8) & 0xf) + (((hex >> 8) & 0xf) << 4), ((hex >> 4) & 0xf) + (((hex >> 4) & 0xf) << 4), (hex & 0xf) + ((hex & 0xf) << 4), 1);
5209
6395
  }
6396
+ // #ffffff
5210
6397
  if (hexLength === 6) {
5211
6398
  return rgb(hex);
5212
6399
  }
6400
+ // #ffffffaa
5213
6401
  else if (hexLength === 8) {
5214
6402
  return new RGB((hex >> 24) & 0xff, (hex >> 16) & 0xff, (hex >> 8) & 0xff, (hex & 0xff) / 0xff);
5215
6403
  }
@@ -5250,21 +6438,26 @@
5250
6438
  }
5251
6439
  }
5252
6440
  static parseColorString(value) {
6441
+ // case0: transparent
5253
6442
  if (isValid(DEFAULT_COLORS_OPACITY[value])) {
5254
6443
  return rgba(DEFAULT_COLORS_OPACITY[value]);
5255
6444
  }
6445
+ // case1: 简写 ['blue','red']
5256
6446
  if (isValid(DEFAULT_COLORS[value])) {
5257
6447
  return rgb(DEFAULT_COLORS[value]);
5258
6448
  }
5259
6449
  const formatValue = `${value}`.trim().toLowerCase();
6450
+ // case2: 16进制
5260
6451
  const hexRes = setHex(formatValue);
5261
6452
  if (hexRes !== undefined) {
5262
6453
  return hexRes;
5263
6454
  }
6455
+ // case3 : rgb
5264
6456
  if (/^(rgb|RGB|rgba|RGBA)/.test(formatValue)) {
5265
6457
  const aColor = formatValue.replace(/(?:\(|\)|rgba|RGBA|rgb|RGB)*/g, '').split(',');
5266
6458
  return new RGB(parseInt(aColor[0], 10), parseInt(aColor[1], 10), parseInt(aColor[2], 10), parseFloat(aColor[3]));
5267
6459
  }
6460
+ // case4: hsl
5268
6461
  if (/^(hsl|HSL|hsla|HSLA)/.test(formatValue)) {
5269
6462
  const aColor = formatValue.replace(/(?:\(|\)|hsla|HSLA|hsl|HSL)*/g, '').split(',');
5270
6463
  const rgb = hslToRgb(parseInt(aColor[0], 10), parseInt(aColor[1], 10), parseInt(aColor[2], 10));
@@ -5274,10 +6467,12 @@
5274
6467
  }
5275
6468
  constructor(value) {
5276
6469
  const color = Color.parseColorString(value);
6470
+ // case0: transparent
5277
6471
  if (color) {
5278
6472
  this.color = color;
5279
6473
  }
5280
6474
  else {
6475
+ // default: 白色
5281
6476
  console.warn(`Warn: 传入${value}无法解析为Color`);
5282
6477
  this.color = new RGB(255, 255, 255);
5283
6478
  }
@@ -5321,6 +6516,7 @@
5321
6516
  this.color.b = Math.max(0, Math.min(255, Math.floor(b * color.color.b)));
5322
6517
  return this;
5323
6518
  }
6519
+ // todo: 这里亮度计算都没考虑alpha通道
5324
6520
  getHSVBrightness() {
5325
6521
  return Math.max(this.color.r, this.color.g, this.color.b) / 255;
5326
6522
  }
@@ -5348,11 +6544,14 @@
5348
6544
  return res !== null && res !== void 0 ? res : this;
5349
6545
  }
5350
6546
  setColorName(name) {
6547
+ // color keywords
5351
6548
  const hex = DEFAULT_COLORS[name.toLowerCase()];
5352
6549
  if (typeof hex !== 'undefined') {
6550
+ // red
5353
6551
  this.setHex(hex);
5354
6552
  }
5355
6553
  else {
6554
+ // unknown color
5356
6555
  console.warn('THREE.Color: Unknown color ' + name);
5357
6556
  }
5358
6557
  return this;
@@ -5376,6 +6575,9 @@
5376
6575
  getLuminance3() {
5377
6576
  return (0.299 * this.color.r + 0.587 * this.color.g + 0.114 * this.color.b) / 255;
5378
6577
  }
6578
+ /**
6579
+ * https://www.w3.org/TR/WCAG21/#use-of-color
6580
+ */
5379
6581
  getLuminanceWCAG() {
5380
6582
  const RsRGB = this.color.r / 255;
5381
6583
  const GsRGB = this.color.g / 255;
@@ -5461,6 +6663,7 @@
5461
6663
  this.opacity = 1;
5462
6664
  }
5463
6665
  }
6666
+ // 转为16进制
5464
6667
  formatHex() {
5465
6668
  return `#${hex(this.r) + hex(this.g) + hex(this.b) + (this.opacity === 1 ? '' : hex(this.opacity * 255))}`;
5466
6669
  }
@@ -5473,11 +6676,17 @@
5473
6676
  const { h, s, l } = rgbToHsl(this.r, this.g, this.b);
5474
6677
  return `${opacity === 1 ? 'hsl(' : 'hsla('}${h},${s}%,${l}%${opacity === 1 ? ')' : `,${opacity})`}`;
5475
6678
  }
6679
+ // 转为16进制
5476
6680
  toString() {
5477
6681
  return this.formatHex();
5478
6682
  }
5479
6683
  }
5480
6684
 
6685
+ /**
6686
+ * 将 hex 格式颜色转换为 rgb 格式
6687
+ * @param str hex 格式的颜色值
6688
+ * @returns rgb 格式
6689
+ */
5481
6690
  function hexToRgb(str) {
5482
6691
  let r = '';
5483
6692
  let g = '';
@@ -5539,6 +6748,11 @@
5539
6748
  rgbToHsl: rgbToHsl
5540
6749
  });
5541
6750
 
6751
+ /**
6752
+ * 将 padding 转换为通用的格式([上,右,下,左])
6753
+ * @param padding
6754
+ * @return [ top, right, bottom, left ]
6755
+ */
5542
6756
  function normalizePadding(padding) {
5543
6757
  if (isValidNumber(padding)) {
5544
6758
  return [padding, padding, padding, padding];
@@ -5610,6 +6824,12 @@
5610
6824
  function millisecondsSetterName(isUTC) {
5611
6825
  return isUTC ? 'setUTCMilliseconds' : 'setMilliseconds';
5612
6826
  }
6827
+ /**
6828
+ * 根据时间推断格式化字符串
6829
+ * @param value
6830
+ * @param isUTC
6831
+ * @returns
6832
+ */
5613
6833
  function getFormatFromValue(value, isUTC) {
5614
6834
  const date = toDate(value);
5615
6835
  const M = date[monthGetterName(isUTC)]() + 1;
@@ -5657,15 +6877,20 @@
5657
6877
  const m = date[minutesGetterName(isUTC)]();
5658
6878
  const s = date[secondsGetterName(isUTC)]();
5659
6879
  const S = date[millisecondsGetterName(isUTC)]();
6880
+ // 月份,周等需要管理管理locale的时间格式化暂时不支持
5660
6881
  return ((template || '')
5661
6882
  .replace(/YYYY/g, pad(y + '', 4, '0', 'left'))
5662
6883
  .replace(/yyyy/g, y + '')
5663
6884
  .replace(/yy/g, (y % 100) + '')
5664
6885
  .replace(/Q/g, q + '')
6886
+ // .replace(/{MMMM}/g, month[M - 1])
6887
+ // .replace(/{MMM}/g, monthAbbr[M - 1])
5665
6888
  .replace(/MM/g, pad(M, 2, '0', 'left'))
5666
6889
  .replace(/M/g, M + '')
5667
6890
  .replace(/dd/g, pad(d, 2, '0', 'left'))
5668
6891
  .replace(/d/g, d + '')
6892
+ // .replace(/{eeee}/g, dayOfWeek[e])
6893
+ // .replace(/{ee}/g, dayOfWeekAbbr[e])
5669
6894
  .replace(/e/g, e + '')
5670
6895
  .replace(/HH/g, pad(H, 2, '0', 'left'))
5671
6896
  .replace(/H/g, H + '')
@@ -5967,9 +7192,14 @@
5967
7192
  };
5968
7193
  }
5969
7194
  const style = getComputedStyle(el);
7195
+ // clientWidth/clientHeight: 默认整数,会向上取整,导致canvas > container
7196
+ // getBoundingClientRect:默认小数,但是在container上有css类似 transform: scale(0.5)时,获取结果不对
7197
+ // getComputedStyle:默认小数,获取最终结果,但是会包含padding;
5970
7198
  if (/^(\d*\.?\d+)(px)$/.exec(style.width)) {
7199
+ // 当dom元素的 display: 'none' 的时候,获取到的宽高会变成原始的样式配置,而不是计算后的像素值
5971
7200
  const computedWidth = parseFloat(style.width) - parseFloat(style.paddingLeft) - parseFloat(style.paddingRight) || el.clientWidth - 1;
5972
7201
  const computedHeight = parseFloat(style.height) - parseFloat(style.paddingTop) - parseFloat(style.paddingBottom) || el.clientHeight - 1;
7202
+ // 理论上不用向下取整,目前没加。
5973
7203
  return {
5974
7204
  width: computedWidth <= 0 ? defaultWidth : computedWidth,
5975
7205
  height: computedHeight <= 0 ? defaultHeight : computedHeight
@@ -5977,10 +7207,20 @@
5977
7207
  }
5978
7208
  return { width: defaultWidth, height: defaultHeight };
5979
7209
  }
7210
+ /**
7211
+ * 获取元素的绝对位置坐标(相对于页面左上角)
7212
+ * @param element
7213
+ * @returns
7214
+ */
5980
7215
  function getElementAbsolutePosition(element) {
5981
7216
  const { x, y } = element.getBoundingClientRect();
5982
7217
  return { x, y };
5983
7218
  }
7219
+ /**
7220
+ * 获取元素的相对位置坐标(相对于其他dom元素)
7221
+ * @param element
7222
+ * @returns
7223
+ */
5984
7224
  function getElementRelativePosition(element, base) {
5985
7225
  const posElement = getElementAbsolutePosition(element);
5986
7226
  const posBase = getElementAbsolutePosition(base);
@@ -6012,12 +7252,23 @@
6012
7252
  const getScaleY = (element) => {
6013
7253
  return element.getBoundingClientRect().height / element.offsetHeight;
6014
7254
  };
7255
+ /**
7256
+ * 获取目标元素的缩放因数
7257
+ * @param element 目标 dom 元素
7258
+ * @returns
7259
+ */
6015
7260
  const getScale = (element) => {
6016
7261
  if (element.offsetWidth > 0) {
6017
7262
  return getScaleX(element);
6018
7263
  }
6019
7264
  return getScaleY(element);
6020
7265
  };
7266
+ /**
7267
+ * 判断是否是元素的父元素
7268
+ * @param element 从其父元素开始查找的 DOM 元素
7269
+ * @param target 要查找的目标父元素
7270
+ * @returns boolean, true 代表查找到,false 表示未找到
7271
+ */
6021
7272
  function hasParentElement(element, target) {
6022
7273
  let parent = element.parentNode;
6023
7274
  while (parent !== null) {
@@ -6028,6 +7279,11 @@
6028
7279
  }
6029
7280
  return false;
6030
7281
  }
7282
+ /**
7283
+ * 将style字符串转换成对象形式
7284
+ * @param style字符串 例如:"color:red;line-height:20px;"
7285
+ * @returns style对象,如 { color: 'red', 'line-height': '20px' }
7286
+ */
6031
7287
  const styleStringToObject = (styleStr = '') => {
6032
7288
  const res = {};
6033
7289
  styleStr.split(';').forEach(item => {
@@ -6044,9 +7300,19 @@
6044
7300
  });
6045
7301
  return res;
6046
7302
  };
7303
+ /**
7304
+ * 将小驼峰转换成中划线连接的字符串
7305
+ * @param str 如:'lineHeight' => 'line-height'
7306
+ * @returns
7307
+ */
6047
7308
  const lowerCamelCaseToMiddle = (str) => {
6048
7309
  return str.replace(/([A-Z])/g, '-$1').toLowerCase();
6049
7310
  };
7311
+ /**
7312
+ * 将中划线连接的字符串转换成驼峰字符串
7313
+ * @param str 如:'line-height' => 'lineHeight'
7314
+ * @returns
7315
+ */
6050
7316
  function toCamelCase(str) {
6051
7317
  return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
6052
7318
  }
@@ -6055,6 +7321,7 @@
6055
7321
  return obj instanceof Element;
6056
7322
  }
6057
7323
  catch (_a) {
7324
+ // 跨端 plan B
6058
7325
  const htmlElementKeys = [
6059
7326
  'children',
6060
7327
  'innerHTML',
@@ -6122,6 +7389,29 @@
6122
7389
  return distance / factor;
6123
7390
  }
6124
7391
 
7392
+ /**
7393
+ * The MIT License (MIT)
7394
+ *
7395
+ * Copyright (c) 2019 Morgan Herlocker
7396
+ *
7397
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
7398
+ * this software and associated documentation files (the "Software"), to deal in
7399
+ * the Software without restriction, including without limitation the rights to
7400
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7401
+ * the Software, and to permit persons to whom the Software is furnished to do so,
7402
+ * subject to the following conditions:
7403
+ *
7404
+ * The above copyright notice and this permission notice shall be included in allcopies or substantial portions of the Software.
7405
+ *
7406
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
7407
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
7408
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
7409
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
7410
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
7411
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7412
+ *
7413
+ */
7414
+ // https://github.com/Turfjs/turf
6125
7415
  function getGeom(geojson) {
6126
7416
  if (geojson.type === 'Feature') {
6127
7417
  return geojson.geometry;
@@ -6137,6 +7427,7 @@
6137
7427
  }
6138
7428
  const geom = getGeom(polygon);
6139
7429
  const type = geom.type;
7430
+ // BBox [west, south, east, north]
6140
7431
  const bbox = polygon.bbox;
6141
7432
  let polys = geom.coordinates;
6142
7433
  if (bbox && pointInRect(point, { x1: bbox[0], x2: bbox[1], y1: bbox[1], y2: bbox[3] }, true) === true) {
@@ -6157,11 +7448,13 @@
6157
7448
  }
6158
7449
  return result;
6159
7450
  }
7451
+ // https://github.com/Turfjs/turf
6160
7452
  function destination(point, distance, bearing, options = {}) {
6161
7453
  const longitude1 = degreeToRadian(point[0]);
6162
7454
  const latitude1 = degreeToRadian(point[1]);
6163
7455
  const bearingRad = degreeToRadian(bearing);
6164
7456
  const radians = lengthToRadians(distance, options.units);
7457
+ // Main
6165
7458
  const latitude2 = Math.asin(Math.sin(latitude1) * Math.cos(radians) + Math.cos(latitude1) * Math.sin(radians) * Math.cos(bearingRad));
6166
7459
  const longitude2 = longitude1 +
6167
7460
  Math.atan2(Math.sin(bearingRad) * Math.sin(radians) * Math.cos(latitude1), Math.cos(radians) - Math.sin(latitude1) * Math.sin(latitude2));
@@ -6170,17 +7463,41 @@
6170
7463
  return { x: lng, y: lat };
6171
7464
  }
6172
7465
 
7466
+ /* Adapted from venn.js by Ben Frederickson
7467
+ * https://github.com/benfred/venn.js
7468
+ * Licensed under the MIT
7469
+
7470
+ * url: https://github.com/benfred/venn.js/blob/master/src/circleintersection.js
7471
+ * License: https://github.com/benfred/venn.js/blob/master/LICENSE
7472
+ * @license
7473
+ */
6173
7474
  const SMALL = 1e-10;
6174
7475
 
7476
+ /* Adapted from venn.js by Ben Frederickson
7477
+ * https://github.com/benfred/venn.js
7478
+ * Licensed under the MIT
7479
+
7480
+ * url: https://github.com/benfred/venn.js/blob/master/src/circleintersection.js
7481
+ * License: https://github.com/benfred/venn.js/blob/master/LICENSE
7482
+ * @license
7483
+ */
7484
+ /** Returns the intersection area of a bunch of circles (where each circle
7485
+ is an object having an x,y and radius property) */
6175
7486
  function intersectionArea(circles, stats) {
7487
+ // get all the intersection points of the circles
6176
7488
  const intersectionPoints = getIntersectionPoints(circles);
7489
+ // filter out points that aren't included in all the circles
6177
7490
  const innerPoints = intersectionPoints.filter(function (p) {
6178
7491
  return containedInCircles(p, circles);
6179
7492
  });
6180
7493
  let arcArea = 0;
6181
7494
  let polygonArea = 0;
6182
7495
  const arcs = [];
7496
+ // if we have intersection points that are within all the circles,
7497
+ // then figure out the area contained by them
6183
7498
  if (innerPoints.length > 1) {
7499
+ // sort the points by angle from the center of the polygon, which lets
7500
+ // us just iterate over points to get the edges
6184
7501
  const center = getCenter(innerPoints);
6185
7502
  for (let i = 0; i < innerPoints.length; ++i) {
6186
7503
  const p = innerPoints[i];
@@ -6189,14 +7506,20 @@
6189
7506
  innerPoints.sort(function (a, b) {
6190
7507
  return b.angle - a.angle;
6191
7508
  });
7509
+ // iterate over all points, get arc between the points
7510
+ // and update the areas
6192
7511
  let p2 = innerPoints[innerPoints.length - 1];
6193
7512
  for (let i = 0; i < innerPoints.length; ++i) {
6194
7513
  const p1 = innerPoints[i];
7514
+ // polygon area updates easily ...
6195
7515
  polygonArea += (p2.x + p1.x) * (p1.y - p2.y);
7516
+ // updating the arc area is a little more involved
6196
7517
  const midPoint = { x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2 };
6197
7518
  let arc = null;
6198
7519
  for (let j = 0; j < p1.parentIndex.length; ++j) {
6199
7520
  if (p2.parentIndex.indexOf(p1.parentIndex[j]) > -1) {
7521
+ // figure out the angle halfway between the two points
7522
+ // on the current circle
6200
7523
  const circle = circles[p1.parentIndex[j]];
6201
7524
  const a1 = Math.atan2(p1.x - circle.x, p1.y - circle.y);
6202
7525
  const a2 = Math.atan2(p2.x - circle.x, p2.y - circle.y);
@@ -6204,14 +7527,19 @@
6204
7527
  if (angleDiff < 0) {
6205
7528
  angleDiff += 2 * Math.PI;
6206
7529
  }
7530
+ // and use that angle to figure out the width of the
7531
+ // arc
6207
7532
  const a = a2 - angleDiff / 2;
6208
7533
  let width = PointService.distancePP(midPoint, {
6209
7534
  x: circle.x + circle.radius * Math.sin(a),
6210
7535
  y: circle.y + circle.radius * Math.cos(a)
6211
7536
  });
7537
+ // clamp the width to the largest is can actually be
7538
+ // (sometimes slightly overflows because of FP errors)
6212
7539
  if (width > circle.radius * 2) {
6213
7540
  width = circle.radius * 2;
6214
7541
  }
7542
+ // pick the circle whose arc has the smallest width
6215
7543
  if (arc === null || arc.width > width) {
6216
7544
  arc = { circle: circle, width: width, p1: p1, p2: p2 };
6217
7545
  }
@@ -6225,12 +7553,16 @@
6225
7553
  }
6226
7554
  }
6227
7555
  else {
7556
+ // no intersection points, is either disjoint - or is completely
7557
+ // overlapped. figure out which by examining the smallest circle
6228
7558
  let smallest = circles[0];
6229
7559
  for (let i = 1; i < circles.length; ++i) {
6230
7560
  if (circles[i].radius < smallest.radius) {
6231
7561
  smallest = circles[i];
6232
7562
  }
6233
7563
  }
7564
+ // make sure the smallest circle is completely contained in all
7565
+ // the other circles
6234
7566
  let disjoint = false;
6235
7567
  for (let i = 0; i < circles.length; ++i) {
6236
7568
  if (PointService.distancePP(circles[i], smallest) > Math.abs(smallest.radius - circles[i].radius)) {
@@ -6262,6 +7594,7 @@
6262
7594
  }
6263
7595
  return arcArea + polygonArea;
6264
7596
  }
7597
+ /** returns whether a point is contained by all of a list of circles */
6265
7598
  function containedInCircles(point, circles) {
6266
7599
  for (let i = 0; i < circles.length; ++i) {
6267
7600
  if (PointService.distancePP(point, circles[i]) > circles[i].radius + SMALL) {
@@ -6270,6 +7603,7 @@
6270
7603
  }
6271
7604
  return true;
6272
7605
  }
7606
+ /** Gets all intersection points between a bunch of circles */
6273
7607
  function getIntersectionPoints(circles) {
6274
7608
  const ret = [];
6275
7609
  for (let i = 0; i < circles.length; ++i) {
@@ -6284,13 +7618,19 @@
6284
7618
  }
6285
7619
  return ret;
6286
7620
  }
7621
+ /** Circular segment area calculation. See http://mathworld.wolfram.com/CircularSegment.html */
6287
7622
  function circleArea(r, width) {
6288
7623
  return r * r * Math.acos(1 - width / r) - (r - width) * Math.sqrt(width * (2 * r - width));
6289
7624
  }
7625
+ /** Returns the overlap area of two circles of radius r1 and r2 - that
7626
+ have their centers separated by distance d. Simpler faster
7627
+ circle intersection for only two circles */
6290
7628
  function circleOverlap(r1, r2, d) {
7629
+ // no overlap
6291
7630
  if (d >= r1 + r2) {
6292
7631
  return 0;
6293
7632
  }
7633
+ // completely overlapped
6294
7634
  if (d <= Math.abs(r1 - r2)) {
6295
7635
  return Math.PI * Math.min(r1, r2) * Math.min(r1, r2);
6296
7636
  }
@@ -6298,10 +7638,15 @@
6298
7638
  const w2 = r2 - (d * d - r1 * r1 + r2 * r2) / (2 * d);
6299
7639
  return circleArea(r1, w1) + circleArea(r2, w2);
6300
7640
  }
7641
+ /** Given two circles (containing a x/y/radius attributes),
7642
+ returns the intersecting points if possible.
7643
+ note: doesn't handle cases where there are infinitely many
7644
+ intersection points (circles are equivalent):, or only one intersection point*/
6301
7645
  function circleCircleIntersection(p1, p2) {
6302
7646
  const d = PointService.distancePP(p1, p2);
6303
7647
  const r1 = p1.radius;
6304
7648
  const r2 = p2.radius;
7649
+ // if to far away, or self contained - can't be done
6305
7650
  if (d >= r1 + r2 || d <= Math.abs(r1 - r2)) {
6306
7651
  return [];
6307
7652
  }
@@ -6316,6 +7661,7 @@
6316
7661
  { x: x0 - rx, y: y0 + ry }
6317
7662
  ];
6318
7663
  }
7664
+ /** Returns the center of a bunch of points */
6319
7665
  function getCenter(points) {
6320
7666
  const center = { x: 0, y: 0 };
6321
7667
  for (let i = 0; i < points.length; ++i) {
@@ -6327,6 +7673,14 @@
6327
7673
  return center;
6328
7674
  }
6329
7675
 
7676
+ /* Adapted from d3-time-format by Mike Bostock
7677
+ * https://github.com/d3/d3-time-format
7678
+ * Licensed under the ISC
7679
+
7680
+ * url: https://github.com/d3/d3-time-format/blob/d6feb945baa4b7a45898a9ca926ebca044e20657/src/locale.js
7681
+ * License: https://github.com/d3/d3-time-format/blob/main/LICENSE
7682
+ * @license
7683
+ */
6330
7684
  class TimeUtil {
6331
7685
  static getInstance() {
6332
7686
  if (!TimeUtil.instance) {
@@ -6339,8 +7693,9 @@
6339
7693
  this.locale_periods = ['AM', 'PM'];
6340
7694
  this.locale_weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
6341
7695
  this.locale_shortMonths = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
6342
- this.numberRe = /^\s*\d+/;
7696
+ this.numberRe = /^\s*\d+/; // note: ignores next directive
6343
7697
  this.pads = { '-': '', _: ' ', '0': '0' };
7698
+ // const percentRe = /^%/;
6344
7699
  this.requoteRe = /[\\^$*+?|[\]().{}]/g;
6345
7700
  this.locale_months = [
6346
7701
  'January',
@@ -6617,18 +7972,22 @@
6617
7972
  if (i !== string.length) {
6618
7973
  return null;
6619
7974
  }
7975
+ // If a UNIX timestamp is specified, return it.
6620
7976
  if ('Q' in d) {
6621
7977
  return new Date(d.Q);
6622
7978
  }
6623
7979
  if ('s' in d) {
6624
7980
  return new Date(d.s * 1000 + ('L' in d ? d.L : 0));
6625
7981
  }
7982
+ // If this is utcParse, never use the local timezone.
6626
7983
  if (Z && !('Z' in d)) {
6627
7984
  d.Z = 0;
6628
7985
  }
7986
+ // The am-pm flag is 0 for AM, and 1 for PM.
6629
7987
  if ('p' in d) {
6630
7988
  d.H = (d.H % 12) + d.p * 12;
6631
7989
  }
7990
+ // If the month was not specified, inherit from the quarter.
6632
7991
  if (d.m === undefined) {
6633
7992
  d.m = 'q' in d ? d.q : 0;
6634
7993
  }
@@ -6637,6 +7996,7 @@
6637
7996
  d.M += d.Z % 100;
6638
7997
  return that.utcDate(d);
6639
7998
  }
7999
+ // Otherwise, all fields are in local time.
6640
8000
  return that.localDate(d);
6641
8001
  };
6642
8002
  }
@@ -6678,6 +8038,13 @@
6678
8038
  }
6679
8039
  }
6680
8040
 
8041
+ /* Adapted from d3-time-format by Mike Bostock
8042
+ * https://github.com/d3/d3-format
8043
+ * Licensed under the ISC
8044
+
8045
+ * License: https://github.com/d3/d3-format/blob/main/LICENSE
8046
+ * @license
8047
+ */
6681
8048
  function formatDecimal(x) {
6682
8049
  return Math.abs((x = Math.round(x))) >= 1e21 ? x.toLocaleString('en').replace(/,/g, '') : x.toString(10);
6683
8050
  }
@@ -6685,12 +8052,19 @@
6685
8052
  const _x = p ? x.toExponential(p - 1) : x.toExponential();
6686
8053
  const i = _x.indexOf('e');
6687
8054
  if (i < 0) {
6688
- return null;
8055
+ return null; // NaN, ±Infinity
6689
8056
  }
6690
8057
  const coefficient = _x.slice(0, i);
6691
8058
  return [coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient, +_x.slice(i + 1)];
6692
8059
  }
6693
8060
 
8061
+ /* Adapted from d3-time-format by Mike Bostock
8062
+ * https://github.com/d3/d3-format
8063
+ * Licensed under the ISC
8064
+
8065
+ * License: https://github.com/d3/d3-format/blob/main/LICENSE
8066
+ * @license
8067
+ */
6694
8068
  function formatGroup(grouping, thousands) {
6695
8069
  return function (value, width) {
6696
8070
  let i = value.length;
@@ -6712,6 +8086,13 @@
6712
8086
  };
6713
8087
  }
6714
8088
 
8089
+ /* Adapted from d3-time-format by Mike Bostock
8090
+ * https://github.com/d3/d3-format
8091
+ * Licensed under the ISC
8092
+
8093
+ * License: https://github.com/d3/d3-format/blob/main/LICENSE
8094
+ * @license
8095
+ */
6715
8096
  let prefixExponent;
6716
8097
  function formatPrefixAuto(x, p) {
6717
8098
  const d = formatDecimalParts(x, p);
@@ -6728,9 +8109,16 @@
6728
8109
  ? coefficient + new Array(i - n + 1).join('0')
6729
8110
  : i > 0
6730
8111
  ? coefficient.slice(0, i) + '.' + coefficient.slice(i)
6731
- : '0.' + new Array(1 - i).join('0') + formatDecimalParts(x, Math.max(0, p + i - 1))[0];
8112
+ : '0.' + new Array(1 - i).join('0') + formatDecimalParts(x, Math.max(0, p + i - 1))[0]; // less than 1y!
6732
8113
  }
6733
8114
 
8115
+ /* Adapted from d3-time-format by Mike Bostock
8116
+ * https://github.com/d3/d3-format
8117
+ * Licensed under the ISC
8118
+
8119
+ * License: https://github.com/d3/d3-format/blob/main/LICENSE
8120
+ * @license
8121
+ */
6734
8122
  function formatRounded(x, p) {
6735
8123
  const d = formatDecimalParts(x, p);
6736
8124
  if (!d) {
@@ -6745,6 +8133,13 @@
6745
8133
  : coefficient + new Array(exponent - coefficient.length + 2).join('0');
6746
8134
  }
6747
8135
 
8136
+ /* Adapted from d3-time-format by Mike Bostock
8137
+ * https://github.com/d3/d3-format
8138
+ * Licensed under the ISC
8139
+
8140
+ * License: https://github.com/d3/d3-format/blob/main/LICENSE
8141
+ * @license
8142
+ */
6748
8143
  function formatTrim(s) {
6749
8144
  const n = s.length;
6750
8145
  let i0 = -1;
@@ -6820,6 +8215,13 @@
6820
8215
  });
6821
8216
  }
6822
8217
 
8218
+ /* Adapted from d3-time-format by Mike Bostock
8219
+ * https://github.com/d3/d3-format
8220
+ * Licensed under the ISC
8221
+
8222
+ * License: https://github.com/d3/d3-format/blob/main/LICENSE
8223
+ * @license
8224
+ */
6823
8225
  const prefixes = ['y', 'z', 'a', 'f', 'p', 'n', 'µ', 'm', '', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
6824
8226
  class NumberUtil {
6825
8227
  constructor() {
@@ -6868,19 +8270,33 @@
6868
8270
  let precision = specifierIns.precision;
6869
8271
  let trim = specifierIns.trim;
6870
8272
  let type = specifierIns.type;
8273
+ // The "n" type is an alias for ",g".
6871
8274
  if (type === 'n') {
6872
8275
  (comma = true), (type = 'g');
6873
8276
  }
8277
+ // The "" type, and any invalid type, is an alias for ".12~g".
8278
+ // @ts-ignore
6874
8279
  else if (!formatTypes[type]) {
6875
8280
  precision === undefined && (precision = 12), (trim = true), (type = 'g');
6876
8281
  }
8282
+ // If zero fill is specified, padding goes after sign and before digits.
8283
+ // @ts-ignore
6877
8284
  if (zero || (fill === '0' && align === '=')) {
6878
8285
  (zero = true), (fill = '0'), (align = '=');
6879
8286
  }
8287
+ // Compute the prefix and suffix.
8288
+ // For SI-prefix, the suffix is lazily computed.
6880
8289
  const prefix = symbol === '$' ? this.currencyPrefix : symbol === '#' && /[boxX]/.test(type) ? '0' + type.toLowerCase() : '';
6881
8290
  const suffix = symbol === '$' ? this.currencySuffix : /[%p]/.test(type) ? this.percent : '';
8291
+ // What format function should we use?
8292
+ // Is this an integer type?
8293
+ // Can this type generate exponential notation?
6882
8294
  const formatType = formatTypes[type];
6883
8295
  const maybeSuffix = /[defgprstz%]/.test(type);
8296
+ // Set the default precision if not specified,
8297
+ // or clamp the specified precision to the supported range.
8298
+ // For significant precision, it must be in [1, 21].
8299
+ // For fixed precision, it must be in [0, 20].
6884
8300
  precision =
6885
8301
  precision === undefined
6886
8302
  ? 6
@@ -6901,20 +8317,27 @@
6901
8317
  }
6902
8318
  else {
6903
8319
  _value = +_value;
8320
+ // Determine the sign. -0 is not less than 0, but 1 / -0 is!
6904
8321
  let valueNegative = _value < 0 || 1 / _value < 0;
8322
+ // Perform the initial formatting.
6905
8323
  _value = isNaN(_value) ? nan : formatType(Math.abs(_value), precision);
8324
+ // Trim insignificant zeros.
6906
8325
  if (trim) {
6907
8326
  _value = formatTrim(_value);
6908
8327
  }
8328
+ // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign.
6909
8329
  if (valueNegative && +_value === 0 && sign !== '+') {
6910
8330
  valueNegative = false;
6911
8331
  }
8332
+ // Compute the prefix and suffix.
6912
8333
  valuePrefix =
6913
8334
  (valueNegative ? (sign === '(' ? sign : minus) : sign === '-' || sign === '(' ? '' : sign) + valuePrefix;
6914
8335
  valueSuffix =
6915
8336
  (type === 's' ? prefixes[8 + prefixExponent / 3] : '') +
6916
8337
  valueSuffix +
6917
8338
  (valueNegative && sign === '(' ? ')' : '');
8339
+ // Break the formatted value into the integer “value” part that can be
8340
+ // grouped, and fractional or exponential “suffix” part that is not.
6918
8341
  if (maybeSuffix) {
6919
8342
  (i = -1), (n = _value.length);
6920
8343
  while (++i < n) {
@@ -6926,15 +8349,19 @@
6926
8349
  }
6927
8350
  }
6928
8351
  }
8352
+ // If the fill character is not "0", grouping is applied before padding.
6929
8353
  if (comma && !zero) {
6930
8354
  _value = group(_value, Infinity);
6931
8355
  }
8356
+ // Compute the padding.
6932
8357
  let length = valuePrefix.length + _value.length + valueSuffix.length;
6933
8358
  let padding = length < width ? new Array(width - length + 1).join(fill) : '';
8359
+ // If the fill character is "0", grouping is applied after padding.
6934
8360
  if (comma && zero) {
6935
8361
  _value = group(padding + _value, padding.length ? width - valueSuffix.length : Infinity);
6936
8362
  padding = '';
6937
8363
  }
8364
+ // Reconstruct the final output based on the desired alignment.
6938
8365
  switch (align) {
6939
8366
  case '<':
6940
8367
  _value = valuePrefix + _value + valueSuffix + padding;
@@ -6988,6 +8415,7 @@
6988
8415
  X: (x) => Math.round(x).toString(16).toUpperCase(),
6989
8416
  x: (x) => Math.round(x).toString(16),
6990
8417
  t: (x, p) => {
8418
+ // 判断是否为整数
6991
8419
  if (Number.isInteger(x)) {
6992
8420
  return x.toFixed(2);
6993
8421
  }
@@ -7005,6 +8433,16 @@
7005
8433
  };
7006
8434
  }
7007
8435
 
8436
+ /* Adapted from fmin by Ben Frederickson
8437
+ * https://github.com/benfred/fmin
8438
+ * Licensed under the BSD-3-Clause
8439
+
8440
+ * url: https://github.com/benfred/fmin/blob/master/src/blas1.js
8441
+ * License: https://github.com/benfred/fmin/blob/master/LICENSE
8442
+ * @license
8443
+ */
8444
+ // need some basic operations on vectors, rather than adding a dependency,
8445
+ // just define here
7008
8446
  function zeros(x) {
7009
8447
  const r = new Array(x);
7010
8448
  for (let i = 0; i < x; ++i) {
@@ -7036,6 +8474,15 @@
7036
8474
  }
7037
8475
  }
7038
8476
 
8477
+ /* Adapted from fmin by Ben Frederickson
8478
+ * https://github.com/benfred/fmin
8479
+ * Licensed under the BSD-3-Clause
8480
+
8481
+ * url: https://github.com/benfred/fmin/blob/master/src/nelderMead.js
8482
+ * License: https://github.com/benfred/fmin/blob/master/LICENSE
8483
+ * @license
8484
+ */
8485
+ /** minimizes a function using the downhill simplex method */
7039
8486
  function nelderMead(f, x0, parameters) {
7040
8487
  parameters = parameters || {};
7041
8488
  const maxIterations = parameters.maxIterations || x0.length * 200;
@@ -7048,6 +8495,7 @@
7048
8495
  const psi = parameters.psi !== undefined ? parameters.psi : -0.5;
7049
8496
  const sigma = parameters.sigma !== undefined ? parameters.sigma : 0.5;
7050
8497
  let maxDiff;
8498
+ // initialize simplex.
7051
8499
  const N = x0.length;
7052
8500
  const simplex = new Array(N + 1);
7053
8501
  simplex[0] = x0;
@@ -7076,6 +8524,8 @@
7076
8524
  for (let iteration = 0; iteration < maxIterations; ++iteration) {
7077
8525
  simplex.sort(sortOrder);
7078
8526
  if (parameters.history) {
8527
+ // copy the simplex (since later iterations will mutate) and
8528
+ // sort it to have a consistent order between iterations
7079
8529
  const sortedSimplex = simplex.map(function (x) {
7080
8530
  const state = x.slice();
7081
8531
  state.fx = x.fx;
@@ -7094,6 +8544,7 @@
7094
8544
  if (Math.abs(simplex[0].fx - simplex[N].fx) < minErrorDelta && maxDiff < minTolerance) {
7095
8545
  break;
7096
8546
  }
8547
+ // compute the centroid of all but the worst point in the simplex
7097
8548
  for (let i = 0; i < N; ++i) {
7098
8549
  centroid[i] = 0;
7099
8550
  for (let j = 0; j < N; ++j) {
@@ -7101,9 +8552,12 @@
7101
8552
  }
7102
8553
  centroid[i] /= N;
7103
8554
  }
8555
+ // reflect the worst point past the centroid and compute loss at reflected
8556
+ // point
7104
8557
  const worst = simplex[N];
7105
8558
  weightedSum(reflected, 1 + rho, centroid, -rho, worst);
7106
8559
  reflected.fx = f(reflected);
8560
+ // if the reflected point is the best seen, then possibly expand
7107
8561
  if (reflected.fx < simplex[0].fx) {
7108
8562
  weightedSum(expanded, 1 + chi, centroid, -chi, worst);
7109
8563
  expanded.fx = f(expanded);
@@ -7114,9 +8568,12 @@
7114
8568
  updateSimplex(reflected);
7115
8569
  }
7116
8570
  }
8571
+ // if the reflected point is worse than the second worst, we need to
8572
+ // contract
7117
8573
  else if (reflected.fx >= simplex[N - 1].fx) {
7118
8574
  let shouldReduce = false;
7119
8575
  if (reflected.fx > worst.fx) {
8576
+ // do an inside contraction
7120
8577
  weightedSum(contracted, 1 + psi, centroid, -psi, worst);
7121
8578
  contracted.fx = f(contracted);
7122
8579
  if (contracted.fx < worst.fx) {
@@ -7127,6 +8584,7 @@
7127
8584
  }
7128
8585
  }
7129
8586
  else {
8587
+ // do an outside contraction
7130
8588
  weightedSum(contracted, 1 - psi * rho, centroid, psi * rho, worst);
7131
8589
  contracted.fx = f(contracted);
7132
8590
  if (contracted.fx < reflected.fx) {
@@ -7137,9 +8595,11 @@
7137
8595
  }
7138
8596
  }
7139
8597
  if (shouldReduce) {
8598
+ // if we don't contract here, we're done
7140
8599
  if (sigma >= 1) {
7141
8600
  break;
7142
8601
  }
8602
+ // do a reduction
7143
8603
  for (let i = 1; i < simplex.length; ++i) {
7144
8604
  weightedSum(simplex[i], 1 - sigma, simplex[0], sigma, simplex[i]);
7145
8605
  simplex[i].fx = f(simplex[i]);
@@ -7154,6 +8614,21 @@
7154
8614
  return { fx: simplex[0].fx, x: simplex[0] };
7155
8615
  }
7156
8616
 
8617
+ /* Adapted from fmin by Ben Frederickson
8618
+ * https://github.com/benfred/fmin
8619
+ * Licensed under the BSD-3-Clause
8620
+
8621
+ * url: https://github.com/benfred/fmin/blob/master/src/linesearch.js
8622
+ * License: https://github.com/benfred/fmin/blob/master/LICENSE
8623
+ * @license
8624
+ */
8625
+ /// searches along line 'pk' for a point that satifies the wolfe conditions
8626
+ /// See 'Numerical Optimization' by Nocedal and Wright p59-60
8627
+ /// f : objective function
8628
+ /// pk : search direction
8629
+ /// current: object containing current gradient/loss
8630
+ /// next: output: contains next gradient/loss
8631
+ /// returns a: step size taken
7157
8632
  function wolfeLineSearch(f, pk, current, next, a, c1, c2) {
7158
8633
  const phi0 = current.fx;
7159
8634
  const phiPrime0 = dotProduct(current.fxprime, pk);
@@ -7206,7 +8681,17 @@
7206
8681
  return a;
7207
8682
  }
7208
8683
 
8684
+ /* Adapted from fmin by Ben Frederickson
8685
+ * https://github.com/benfred/fmin
8686
+ * Licensed under the BSD-3-Clause
8687
+
8688
+ * url: https://github.com/benfred/fmin/blob/master/src/conjugateGradient.js
8689
+ * License: https://github.com/benfred/fmin/blob/master/LICENSE
8690
+ * @license
8691
+ */
7209
8692
  function conjugateGradient(f, initial, params) {
8693
+ // allocate all memory up front here, keep out of the loop for perfomance
8694
+ // reasons
7210
8695
  let current = { x: initial.slice(), fx: 0, fxprime: initial.slice() };
7211
8696
  let next = { x: initial.slice(), fx: 0, fxprime: initial.slice() };
7212
8697
  const yk = initial.slice();
@@ -7219,13 +8704,17 @@
7219
8704
  scale(pk, current.fxprime, -1);
7220
8705
  for (let i = 0; i < maxIterations; ++i) {
7221
8706
  a = wolfeLineSearch(f, pk, current, next, a);
8707
+ // todo: history in wrong spot?
7222
8708
  if (params.history) {
7223
8709
  params.history.push({ x: current.x.slice(), fx: current.fx, fxprime: current.fxprime.slice(), alpha: a });
7224
8710
  }
7225
8711
  if (!a) {
8712
+ // faiiled to find point that satifies wolfe conditions.
8713
+ // reset direction for next iteration
7226
8714
  scale(pk, current.fxprime, -1);
7227
8715
  }
7228
8716
  else {
8717
+ // update direction using Polak–Ribiere CG method
7229
8718
  weightedSum(yk, 1, next.fxprime, -1, current.fxprime);
7230
8719
  const delta_k = dotProduct(current.fxprime, current.fxprime);
7231
8720
  const beta_k = Math.max(0, dotProduct(yk, next.fxprime) / delta_k);
@@ -7288,6 +8777,7 @@
7288
8777
  exports.binaryFuzzySearch = binaryFuzzySearch;
7289
8778
  exports.binaryFuzzySearchInNumberRange = binaryFuzzySearchInNumberRange;
7290
8779
  exports.bisect = bisect;
8780
+ exports.bootstrapEstimate = bootstrapEstimate;
7291
8781
  exports.calculateAnchorOfArc = calculateAnchorOfArc;
7292
8782
  exports.calculateAnchorOfBounds = calculateAnchorOfBounds;
7293
8783
  exports.calculateMaxRadius = calculateMaxRadius;
@@ -7308,6 +8798,7 @@
7308
8798
  exports.conjugateGradient = conjugateGradient;
7309
8799
  exports.constant = constant;
7310
8800
  exports.containedInCircles = containedInCircles;
8801
+ exports.correlation = correlation;
7311
8802
  exports.cos = cos;
7312
8803
  exports.crossProduct = crossProduct;
7313
8804
  exports.crossProductPoint = crossProductPoint;
@@ -7426,6 +8917,7 @@
7426
8917
  exports.lowerFirst = lowerFirst;
7427
8918
  exports.max = max;
7428
8919
  exports.maxInArray = maxInArray;
8920
+ exports.mean = mean;
7429
8921
  exports.median = median;
7430
8922
  exports.memoize = memoize;
7431
8923
  exports.merge = merge;
@@ -7452,6 +8944,7 @@
7452
8944
  exports.monthSetterName = monthSetterName;
7453
8945
  exports.nelderMead = nelderMead;
7454
8946
  exports.norm2 = norm2;
8947
+ exports.normalQuantile = normalQuantile;
7455
8948
  exports.normalTransform = normalTransform;
7456
8949
  exports.normalizeAngle = normalizeAngle;
7457
8950
  exports.normalizePadding = normalizePadding;