UNPKG

@antv/util

Version:

> AntV 底层依赖的工具库,不建议在自己业务中使用。

142 lines (132 loc) 3.6 kB
import { normalizePath } from '../process/normalize-path'; import type { PathCommand, PathArray, LengthFactory, PathLengthFactoryOptions } from '../types'; import { segmentLineFactory } from './segment-line-factory'; import { segmentArcFactory } from './segment-arc-factory'; import { segmentCubicFactory } from './segment-cubic-factory'; import { segmentQuadFactory } from './segment-quad-factory'; /** * Returns a {x,y} point at a given length * of a shape, the shape total length and * the shape minimum and maximum {x,y} coordinates. */ export function pathLengthFactory( pathInput: string | PathArray, distance?: number, options?: Partial<PathLengthFactoryOptions>, ): LengthFactory { const path = normalizePath(pathInput); const distanceIsNumber = typeof distance === 'number'; let isM: boolean; let data: number[] = []; let pathCommand: PathCommand; let x = 0; let y = 0; let mx = 0; let my = 0; let seg; const MIN = []; const MAX = []; let length = 0; let min = { x: 0, y: 0 }; let max = min; let point = min; let POINT = min; let LENGTH = 0; for (let i = 0, ll = path.length; i < ll; i += 1) { seg = path[i]; [pathCommand] = seg; isM = pathCommand === 'M'; data = !isM ? [x, y].concat(seg.slice(1)) : data; // this segment is always ZERO /* istanbul ignore else */ if (isM) { // remember mx, my for Z [, mx, my] = seg; min = { x: mx, y: my }; max = min; length = 0; if (distanceIsNumber && distance < 0.001) { POINT = min; } } else if (pathCommand === 'L') { ({ length, min, max, point } = segmentLineFactory(data[0], data[1], data[2], data[3], (distance || 0) - LENGTH)); } else if (pathCommand === 'A') { ({ length, min, max, point } = segmentArcFactory( data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], (distance || 0) - LENGTH, options || {}, )); } else if (pathCommand === 'C') { ({ length, min, max, point } = segmentCubicFactory( data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], (distance || 0) - LENGTH, options || {}, )); } else if (pathCommand === 'Q') { ({ length, min, max, point } = segmentQuadFactory( data[0], data[1], data[2], data[3], data[4], data[5], (distance || 0) - LENGTH, options || {}, )); } else if (pathCommand === 'Z') { data = [x, y, mx, my]; ({ length, min, max, point } = segmentLineFactory(data[0], data[1], data[2], data[3], (distance || 0) - LENGTH)); } if (distanceIsNumber && LENGTH < distance && LENGTH + length >= distance) { POINT = point; } MAX.push(max); MIN.push(min); LENGTH += length; [x, y] = pathCommand !== 'Z' ? seg.slice(-2) : [mx, my]; } // native `getPointAtLength` behavior when the given distance // is higher than total length if (distanceIsNumber && distance >= LENGTH) { POINT = { x, y }; } return { length: LENGTH, point: POINT, min: { x: Math.min.apply( null, MIN.map((n) => n.x), ), y: Math.min.apply( null, MIN.map((n) => n.y), ), }, max: { x: Math.max.apply( null, MAX.map((n) => n.x), ), y: Math.max.apply( null, MAX.map((n) => n.y), ), }, }; }