返回 presentation-ai
pyramid-geometry.ts
根目录 / src / components / notebook / presentation / editor / custom-elements / pyramid-geometry.ts
1 const MAX_PYRAMID_WIDTH_PERCENTAGE = 100;
2
3 type PyramidSegmentGeometryOptions = {
4 index: number;
5 totalItems: number;
6 isFunnel?: boolean;
7 };
8
9 function getSafePyramidGeometryValues({
10 index,
11 totalItems,
12 }: PyramidSegmentGeometryOptions) {
13 const safeTotalItems = Math.max(totalItems, 1);
14 const safeIndex = Math.min(Math.max(index, 0), safeTotalItems - 1);
15 const increment = MAX_PYRAMID_WIDTH_PERCENTAGE / (2 * safeTotalItems);
16
17 return {
18 increment,
19 safeIndex,
20 safeTotalItems,
21 };
22 }
23
24 export function getPyramidSegmentClipPath(
25 options: PyramidSegmentGeometryOptions,
26 ) {
27 const { increment, safeIndex, safeTotalItems } =
28 getSafePyramidGeometryValues(options);
29
30 if (options.isFunnel) {
31 const topOffset = increment * (safeTotalItems - safeIndex);
32 const topLeft = 50 - topOffset;
33 const topRight = 50 + topOffset;
34
35 if (safeIndex === safeTotalItems - 1) {
36 return `polygon(${topLeft}% 0%, ${topRight}% 0%, 50% 100%)`;
37 }
38
39 const bottomOffset = increment * (safeTotalItems - safeIndex - 1);
40 const bottomLeft = 50 - bottomOffset;
41 const bottomRight = 50 + bottomOffset;
42
43 return `polygon(${topLeft}% 0%, ${topRight}% 0%, ${bottomRight}% 100%, ${bottomLeft}% 100%)`;
44 }
45
46 if (safeIndex === 0) {
47 return `polygon(50% 0%, ${50 - increment}% 100%, ${50 + increment}% 100%)`;
48 }
49
50 const topOffset = increment * safeIndex;
51 const bottomOffset = increment * (safeIndex + 1);
52 const topLeft = 50 - topOffset;
53 const topRight = 50 + topOffset;
54 const bottomLeft = 50 - bottomOffset;
55 const bottomRight = 50 + bottomOffset;
56
57 return `polygon(${topLeft}% 0%, ${topRight}% 0%, ${bottomRight}% 100%, ${bottomLeft}% 100%)`;
58 }
59
60 export function getPyramidTextOffset(options: PyramidSegmentGeometryOptions) {
61 const { increment, safeIndex, safeTotalItems } =
62 getSafePyramidGeometryValues(options);
63 const halfMaxWidth = MAX_PYRAMID_WIDTH_PERCENTAGE / 2;
64
65 if (options.isFunnel) {
66 // Widest is at the top of the segment
67 return halfMaxWidth - (safeTotalItems - safeIndex) * increment;
68 }
69
70 // Widest is at the bottom of the segment
71 return halfMaxWidth - (safeIndex + 1) * increment;
72 }
73
74 export function getPyramidBorderExtension(
75 options: PyramidSegmentGeometryOptions,
76 ) {
77 const { increment } = getSafePyramidGeometryValues(options);
78 // For Funnel, the border (at bottom) is at the narrowest point, so it needs extension to reach the slanted side
79 // For Pyramid, the border (at bottom) is at the widest point, so it already touches
80 if (options.isFunnel) {
81 return increment;
82 }
83 return 0;
84 }
85
85 lines TYPESCRIPT