@yannelli/paseo-linear-plugin 1.1.0-beta.3 → 1.1.0-beta.4

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.
@@ -6,31 +6,36 @@ export interface Point {
6
6
  y: number;
7
7
  }
8
8
 
9
- export interface Route {
10
- points: Point[];
9
+ export interface Route<P extends Point = Point> {
10
+ points: P[];
11
11
  /** Each point's share of the whole distance, from 0 to 1. */
12
12
  stops: number[];
13
13
  length: number;
14
14
  }
15
15
 
16
- /** Where a route is at a share of its distance, from 0 to 1. */
17
- export function pointAt(path: Route, share: number): Point {
16
+ /** Where a route is at a share of its distance, from 0 to 1. Mixes every number of the points. */
17
+ export function pointAt<P extends Point>(path: Route<P>, share: number): P {
18
18
  const at = Math.min(1, Math.max(0, share));
19
19
  for (let index = 1; index < path.stops.length; index += 1) {
20
20
  const stop = path.stops[index] as number;
21
21
  if (at > stop) continue;
22
22
  const before = path.stops[index - 1] as number;
23
- const from = path.points[index - 1] as Point;
24
- const to = path.points[index] as Point;
23
+ const from = path.points[index - 1] as P;
24
+ const to = path.points[index] as P;
25
25
  const part = stop > before ? (at - before) / (stop - before) : 1;
26
- return { x: from.x + (to.x - from.x) * part, y: from.y + (to.y - from.y) * part };
26
+ const mixed: Record<string, unknown> = { ...(to as object) };
27
+ for (const [key, value] of Object.entries(to as object)) {
28
+ const start = (from as Record<string, unknown>)[key];
29
+ if (typeof value === "number" && typeof start === "number") mixed[key] = start + (value - start) * part;
30
+ }
31
+ return mixed as P;
27
32
  }
28
- return path.points[path.points.length - 1] as Point;
33
+ return path.points[path.points.length - 1] as P;
29
34
  }
30
35
 
31
36
  /** A route through the points without zero-length steps, or null when there is nowhere to go. */
32
- export function route(points: readonly Point[]): Route | null {
33
- const kept: Point[] = [];
37
+ export function route<P extends Point>(points: readonly P[]): Route<P> | null {
38
+ const kept: P[] = [];
34
39
  const steps = [0];
35
40
  for (const point of points) {
36
41
  const last = kept[kept.length - 1];
@@ -84,21 +89,27 @@ export interface PlacedLabel {
84
89
  short: boolean;
85
90
  }
86
91
 
87
- // Places labels in request order at the first spot that overlaps no node or placed label,
88
- // moved inside the box when it would cross an edge. A label with no free spot is hidden.
92
+ export interface Rect {
93
+ left: number;
94
+ top: number;
95
+ right: number;
96
+ bottom: number;
97
+ }
98
+
99
+ // Places labels in request order at the first spot that overlaps no node, other obstacle, or
100
+ // placed label, moved inside the box when it would cross an edge. Others are hidden.
89
101
  export function placeLabels(
90
102
  requests: readonly LabelRequest[],
91
103
  width: number,
92
104
  height: number,
93
- nodes: readonly { at: Point; radius: number }[] = [],
105
+ obstacles: readonly ({ at: Point; radius: number } | Rect)[] = [],
94
106
  gap = 3,
95
107
  ): Map<string, PlacedLabel> {
96
- const placed = nodes.map(({ at, radius }) => ({
97
- left: at.x - radius,
98
- right: at.x + radius,
99
- top: at.y - radius,
100
- bottom: at.y + radius,
101
- }));
108
+ const placed: Rect[] = obstacles.map((shape) =>
109
+ "at" in shape
110
+ ? { left: shape.at.x - shape.radius, right: shape.at.x + shape.radius, top: shape.at.y - shape.radius, bottom: shape.at.y + shape.radius }
111
+ : { ...shape },
112
+ );
102
113
  const shown = new Map<string, PlacedLabel>();
103
114
  for (const request of requests) {
104
115
  const tries = [{ ...request, short: false }];