UNPKG

@antv/x6

Version:

JavaScript diagramming library that uses SVG and HTML for rendering

89 lines (69 loc) 2.62 kB
import { FunctionExt } from '../../common' import { toRad, normalize, Line, Point } from '../../geometry' import type { RouterDefinition } from './index' import { manhattan } from './manhattan/index' import { type ManhattanRouterOptions, resolve } from './manhattan/options' export interface MetroRouterOptions extends ManhattanRouterOptions {} const defaults: Partial<MetroRouterOptions> = { maxDirectionChange: 45, // an array of directions to find next points on the route // different from start/end directions directions() { const step = resolve(this.step, this) const cost = resolve(this.cost, this) const diagonalCost = Math.ceil(Math.sqrt((step * step) << 1)) // eslint-disable-line no-bitwise return [ { cost, offsetX: step, offsetY: 0 }, { cost: diagonalCost, offsetX: step, offsetY: step }, { cost, offsetX: 0, offsetY: step }, { cost: diagonalCost, offsetX: -step, offsetY: step }, { cost, offsetX: -step, offsetY: 0 }, { cost: diagonalCost, offsetX: -step, offsetY: -step }, { cost, offsetX: 0, offsetY: -step }, { cost: diagonalCost, offsetX: step, offsetY: -step }, ] }, // a simple route used in situations when main routing method fails // (exceed max number of loop iterations, inaccessible) fallbackRoute(from, to, options) { // Find a route which breaks by 45 degrees ignoring all obstacles. const theta = from.theta(to) const route = [] let a = { x: to.x, y: from.y } let b = { x: from.x, y: to.y } if (theta % 180 > 90) { const t = a a = b b = t } const p1 = theta % 90 < 45 ? a : b const l1 = new Line(from, p1) const alpha = 90 * Math.ceil(theta / 90) const p2 = Point.fromPolar(l1.squaredLength(), toRad(alpha + 135), p1) const l2 = new Line(to, p2) const intersectionPoint = l1.intersectsWithLine(l2) const point = intersectionPoint || to const directionFrom = intersectionPoint ? point : from const quadrant = 360 / options.directions.length const angleTheta = directionFrom.theta(to) const normalizedAngle = normalize(angleTheta + quadrant / 2) const directionAngle = quadrant * Math.floor(normalizedAngle / quadrant) options.previousDirectionAngle = directionAngle if (point) route.push(point.round()) route.push(to) return route }, } export const metro: RouterDefinition<Partial<MetroRouterOptions>> = function ( vertices, options, linkView, ) { return FunctionExt.call( manhattan, this, vertices, { ...defaults, ...options }, linkView, ) }