{"id":20461357,"url":"https://github.com/antvis/util","last_synced_at":"2025-04-09T05:10:43.579Z","repository":{"id":39905784,"uuid":"131400529","full_name":"antvis/util","owner":"antvis","description":"utility library for AntV products.","archived":false,"fork":false,"pushed_at":"2024-09-20T05:25:10.000Z","size":455,"stargazers_count":74,"open_issues_count":3,"forks_count":27,"subscribers_count":32,"default_branch":"master","last_synced_at":"2024-10-29T21:05:31.582Z","etag":null,"topics":["util"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/antvis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-04-28T10:36:13.000Z","updated_at":"2024-09-20T05:25:11.000Z","dependencies_parsed_at":"2023-10-15T13:25:37.850Z","dependency_job_id":"a980362f-13b0-41f6-ab61-d0d3e41d863e","html_url":"https://github.com/antvis/util","commit_stats":{"total_commits":34,"total_committers":9,"mean_commits":"3.7777777777777777","dds":0.7058823529411764,"last_synced_commit":"8c0851b355a4435cc7b964ec180f61764d5caf60"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antvis%2Futil","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antvis%2Futil/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antvis%2Futil/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/antvis%2Futil/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/antvis","download_url":"https://codeload.github.com/antvis/util/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247452902,"owners_count":20941186,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["util"],"created_at":"2024-11-15T12:24:58.851Z","updated_at":"2025-04-09T05:10:43.559Z","avatar_url":"https://github.com/antvis.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# util\n\n\u003e AntV 底层依赖的工具库，不建议在自己业务中使用。\n\n[![Build Status](https://github.com/antvis/util/workflows/build/badge.svg)](https://github.com/antvis/util/actions)\n[![npm Version](https://img.shields.io/npm/v/@antv/util.svg)](https://www.npmjs.com/package/@antv/util)\n[![npm Download](https://img.shields.io/npm/dm/@antv/util.svg)](https://www.npmjs.com/package/@antv/util)\n[![npm License](https://img.shields.io/npm/l/@antv/util.svg)](https://www.npmjs.com/package/@antv/util)\n\n## Usage\n\n```ts\nimport { gradient } from '@antv/util';\n```\n\n## 原则\n\n- util 只有一个 npm 包，按照目录来组织不同类型的方法，避免 monorepo 互相依赖\n- 内容和 AntV 强相关，避免做和 lodash 等相同的工具库\n- 不使用的方法，及时删除，并保持新增方法可以按需引入\n- 旧版本的不维护，如果 AntV 技术栈的旧版本需要迭代，请升级到 v3\n\n## API\n\n提供以下 Path 工具方法，包含转换、几何计算等。\n\n### path2String\n\n将 PathArray 转换成字符串形式，不会对原始定义中的命令进行修改：\n\n```js\nconst str: PathArray = [\n  ['M', 10, 10],\n  ['L', 100, 100],\n  ['l', 10, 10],\n  ['h', 20],\n  ['v', 20],\n];\nexpect(path2String(str)).toEqual('M10 10L100 100l10 10h20v20');\n```\n\n### path2Array\n\n将 PathArray 转换成数组，不会对原始定义中的命令进行修改：\n\n```js\nconst str = 'M10 10L100 100l10 10h20v20';\nexpect(path2Array(str)).toEqual([\n  ['M', 10, 10],\n  ['L', 100, 100],\n  ['l', 10, 10],\n  ['h', 20],\n  ['v', 20],\n]);\n```\n\n### path2Absolute\n\n将定义中的相对命令转换成绝对命令，例如：\n\n- l -\u003e L\n- h -\u003e H\n- v -\u003e V\n\n完整方法签名如下：\n\n```js\npath2Absolute(pathInput: string | PathArray): AbsoluteArray;\n```\n\n```js\nconst str: PathArray = [\n  ['M', 10, 10],\n  ['L', 100, 100],\n  ['l', 10, 10],\n  ['h', 20],\n  ['v', 20],\n];\nconst arr = path2Absolute(str);\nexpect(arr).toEqual([\n  ['M', 10, 10],\n  ['L', 100, 100],\n  ['L', 110, 110],\n  ['H', 130],\n  ['V', 130],\n]);\n```\n\n### path2Curve\n\n将部分命令转曲，例如 L / A 转成 C 命令，借助 cubic bezier 易于分割的特性用于实现形变动画。\n该方法内部会调用 [path2Absolute](#path2Absolute)，因此最终返回的 PathArray 中仅包含 M 和 C 命令。\n\n完整方法签名如下：\n\n```js\npath2Curve(pathInput: string | PathArray): CurveArray;\n```\n\n```js\nexpect(\n  path2Curve([\n    ['M', 0, 0],\n    ['L', 100, 100],\n  ]),\n).toEqual([\n  ['M', 0, 0],\n  ['C', 44.194173824159215, 44.194173824159215, 68.75, 68.75, 100, 100],\n]);\n```\n\n### clonePath\n\n复制路径：\n\n```js\nconst cloned = clonePath(pathInput);\n```\n\n### reverseCurve\n\n```js\nconst pathArray: CurveArray = [\n  ['M', 170, 90],\n  ['C', 150, 90, 155, 10, 130, 10],\n  ['C', 105, 10, 110, 90, 90, 90],\n  ['C', 70, 90, 75, 10, 50, 10],\n  ['C', 25, 10, 30, 90, 10, 90],\n];\n\nconst reversed = reverseCurve(pathArray);\n```\n\n### getPathBBox\n\n获取几何定义下的包围盒，形如：\n\n```js\nexport interface PathBBox {\n  width: number;\n  height: number;\n  x: number;\n  y: number;\n  x2: number;\n  y2: number;\n  cx: number;\n  cy: number;\n  cz: number;\n}\n```\n\n```js\nconst bbox = getPathBBox([['M', 0, 0], ['L', 100, 0], ['L', 100, 100], ['L', 0, 100], ['Z']]);\n\nexpect(bbox).toEqual({ cx: 50, cy: 50, cz: 150, height: 100, width: 100, x: 0, x2: 100, y: 0, y2: 100 });\n```\n\n### getTotalLength\n\n获取路径总长度。\n\n```js\nconst length = getTotalLength([['M', 0, 0], ['L', 100, 0], ['L', 100, 100], ['L', 0, 100], ['Z']]);\n\nexpect(length).toEqual(400);\n```\n\n### getPointAtLength\n\n获取路径上从起点出发，到指定距离的点。\n\n```js\nconst point = getPointAtLength([['M', 0, 0], ['L', 100, 0], ['L', 100, 100], ['L', 0, 100], ['Z']], 0);\nexpect(point).toEqual({ x: 0, y: 0 });\n```\n\n### getPathArea\n\n计算路径包围的面积。内部实现中首先通过 [path2Curve](#path2Curve) 转曲，再计算 cubic curve 面积，[详见](https://stackoverflow.com/a/15845996)。\n\n方法签名如下：\n\n```js\nfunction getPathArea(path: PathArray): number;\n```\n\n### isPointInStroke\n\n判断一个点是否在路径上，仅通过几何定义计算，不考虑其他样式属性例如线宽、lineJoin、miter 等。\n\n方法签名如下：\n\n```js\nisPointInStroke(pathInput: string | PathArray, point: Point): boolean;\n```\n\n```js\nconst result = isPointInStroke(segments, { x: 10, y: 10 });\n```\n\n### distanceSquareRoot\n\n计算两点之间的距离。\n\n方法签名如下：\n\n```js\ndistanceSquareRoot(a: [number, number], b: [number, number]): number;\n```\n\n### equalizeSegments\n\n将两条路径处理成段数相同，用于形变动画前的分割操作。\n\n```js\nconst [formattedPath1, formattedPath2] = equalizeSegments(path1, path2);\n```\n\n### isPointInPolygon\n\n判断一个点是否在多边形内。多边形形如：\n\n```js\nconst polygon = [\n  [0, 0],\n  [0, 100],\n  [30, 100],\n  [30, 0],\n];\n\n// [0, 0] 在多边形的边上\nisPointInPolygon(polygon, 0, 0); // true\n```\n\n### isPolygonsIntersect\n\n判断两个多边形是否相交：\n\n```js\nisPolygonsIntersect(polygon1, polygon2);\n```\n\n## Benchmarks\n\nBuild first.\n\n```bash\nyarn run benchmarks\n```\n\nWe can get the following output in the console, it can be seen that the same method from 5.0 is ~3 times faster than 4.0.\n\n```js\n// logs\n// Path2String#4.0 x 14,795 ops/sec ±3.35% (79 runs sampled)\n// Path2String#5.0 x 51,710 ops/sec ±2.05% (85 runs sampled)\n// Fastest is Path2String#5.0\n\n// Path2Absolute#4.0 x 14,524 ops/sec ±2.55% (80 runs sampled)\n// Path2Absolute#5.0 x 35,120 ops/sec ±3.10% (81 runs sampled)\n// Fastest is Path2Absolute#5.0\n```\n\n## License\n\nMIT@[AntV](https://github.com/antvis).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantvis%2Futil","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fantvis%2Futil","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fantvis%2Futil/lists"}