@abyss-project/tools 1.1.1 → 1.2.0

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.
Files changed (166) hide show
  1. package/.eslintrc.js +33 -33
  2. package/.prettierrc +5 -5
  3. package/README.md +32 -32
  4. package/dist/api/extraction-plan-preset.api.js +1 -1
  5. package/dist/api/extraction-plan-preset.api.js.map +1 -1
  6. package/dist/api/extraction-settings.api.js +1 -1
  7. package/dist/api/extraction-settings.api.js.map +1 -1
  8. package/dist/api/extraction.api.js +1 -1
  9. package/dist/api/extraction.api.js.map +1 -1
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/utils/shape.utils.js +18 -18
  14. package/package.json +14 -9
  15. package/src/api/abyss.admin.api.ts +54 -54
  16. package/src/api/atlas-document.api.ts +68 -68
  17. package/src/api/atlas-group.api.ts +69 -69
  18. package/src/api/atlas-page.api.ts +124 -124
  19. package/src/api/atlas.api.ts +103 -103
  20. package/src/api/atlas.public.api.ts +42 -42
  21. package/src/api/board-card-checklist.api.ts +99 -99
  22. package/src/api/board-card-comment.api.ts +57 -57
  23. package/src/api/board-card-document.api.ts +57 -57
  24. package/src/api/board-card.api.ts +137 -137
  25. package/src/api/board-column.api.ts +54 -54
  26. package/src/api/board-label.api.ts +87 -87
  27. package/src/api/board.api.ts +122 -122
  28. package/src/api/draw.api.ts +97 -97
  29. package/src/api/draw.public.api.ts +48 -48
  30. package/src/api/extraction-plan-preset.api.ts +1 -1
  31. package/src/api/extraction-settings.api.ts +1 -1
  32. package/src/api/extraction.api.ts +1 -1
  33. package/src/api/memo.api.ts +97 -97
  34. package/src/api/metrics.api.ts +27 -27
  35. package/src/api/monitor.api.ts +6 -6
  36. package/src/api/organization.api.ts +14 -14
  37. package/src/api/retrospective-card.api.ts +74 -74
  38. package/src/api/retrospective-member.api.ts +54 -54
  39. package/src/api/retrospective-section.api.ts +74 -74
  40. package/src/api/retrospective.api.ts +124 -124
  41. package/src/api/retrospective.public.api.ts +147 -147
  42. package/src/api/short-link.admin.api.ts +39 -39
  43. package/src/api/short-link.api.ts +125 -125
  44. package/src/api/short-link.public.api.ts +60 -60
  45. package/src/api/tag.api.ts +72 -72
  46. package/src/constants/atlas.constants.ts +2 -2
  47. package/src/constants/board.constants.ts +7 -7
  48. package/src/constants/memo.constants.ts +3 -3
  49. package/src/constants/short-link.constants.ts +11 -11
  50. package/src/constants/tag.constants.ts +3 -3
  51. package/src/index.ts +1 -1
  52. package/src/server-sent-events/index.ts +13 -13
  53. package/src/server-sent-events/protocols/atlas/atlas.sse-protocol.ts +90 -90
  54. package/src/server-sent-events/protocols/atlas/index.ts +1 -1
  55. package/src/server-sent-events/protocols/board/board.sse-protocol.ts +115 -115
  56. package/src/server-sent-events/protocols/board/index.ts +1 -1
  57. package/src/server-sent-events/protocols/board-card/board-card.sse-protocol.ts +26 -26
  58. package/src/server-sent-events/protocols/board-card/index.ts +1 -1
  59. package/src/server-sent-events/protocols/index.ts +26 -26
  60. package/src/server-sent-events/protocols/retrospective/index.ts +1 -1
  61. package/src/server-sent-events/protocols/retrospective/retrospective.sse-protocol.ts +92 -92
  62. package/src/server-sent-events/server-sent-events.manager.ts +73 -73
  63. package/src/types/draw.type.ts +173 -173
  64. package/src/types/enum/api-error.enum.ts +23 -23
  65. package/src/types/enum/board-activity.enum.ts +189 -189
  66. package/src/types/enum/board-column-type.enum.ts +6 -6
  67. package/src/types/enum/pdf-operation.enum.ts +98 -98
  68. package/src/types/enum/rcb-bank.enum.ts +137 -137
  69. package/src/types/index.ts +5 -5
  70. package/src/types/interface/api/index.ts +5 -5
  71. package/src/types/interface/api/requests/abyss.admin.request.ts +20 -20
  72. package/src/types/interface/api/requests/atlas-document.request.ts +32 -32
  73. package/src/types/interface/api/requests/atlas-group.request.ts +45 -45
  74. package/src/types/interface/api/requests/atlas-page.request.ts +84 -84
  75. package/src/types/interface/api/requests/atlas.public.request.ts +21 -21
  76. package/src/types/interface/api/requests/atlas.request.ts +52 -52
  77. package/src/types/interface/api/requests/board-card-checklist.request.ts +61 -61
  78. package/src/types/interface/api/requests/board-card-comment.request.ts +28 -28
  79. package/src/types/interface/api/requests/board-card-document.request.ts +29 -29
  80. package/src/types/interface/api/requests/board-card.request.ts +86 -86
  81. package/src/types/interface/api/requests/board-column.request.ts +30 -30
  82. package/src/types/interface/api/requests/board-label.request.ts +42 -42
  83. package/src/types/interface/api/requests/board.request.ts +61 -61
  84. package/src/types/interface/api/requests/draw.public.request.ts +20 -20
  85. package/src/types/interface/api/requests/draw.request.ts +49 -49
  86. package/src/types/interface/api/requests/memo.request.ts +49 -49
  87. package/src/types/interface/api/requests/metrics.request.ts +7 -7
  88. package/src/types/interface/api/requests/retrospective-card.request.ts +38 -38
  89. package/src/types/interface/api/requests/retrospective-member.request.ts +20 -20
  90. package/src/types/interface/api/requests/retrospective-section.request.ts +43 -43
  91. package/src/types/interface/api/requests/retrospective.public.request.ts +84 -84
  92. package/src/types/interface/api/requests/retrospective.request.ts +59 -59
  93. package/src/types/interface/api/requests/short-link.admin.request.ts +35 -35
  94. package/src/types/interface/api/requests/short-link.public.request.ts +40 -40
  95. package/src/types/interface/api/requests/short-link.request.ts +71 -71
  96. package/src/types/interface/api/requests/tag.request.ts +54 -54
  97. package/src/types/interface/api/requests/transfer.request.ts +3 -3
  98. package/src/types/interface/api/responses/abyss.admin.response.ts +28 -28
  99. package/src/types/interface/api/responses/atlas-document.response.ts +24 -24
  100. package/src/types/interface/api/responses/atlas-group.response.ts +23 -23
  101. package/src/types/interface/api/responses/atlas-page.response.ts +53 -53
  102. package/src/types/interface/api/responses/atlas.public.response.ts +21 -21
  103. package/src/types/interface/api/responses/atlas.response.ts +32 -32
  104. package/src/types/interface/api/responses/board-card-checklist.response.ts +31 -31
  105. package/src/types/interface/api/responses/board-card-comment.response.ts +20 -20
  106. package/src/types/interface/api/responses/board-card-document.response.ts +21 -21
  107. package/src/types/interface/api/responses/board-card.response.ts +55 -55
  108. package/src/types/interface/api/responses/board-column.response.ts +20 -20
  109. package/src/types/interface/api/responses/board-label.response.ts +31 -31
  110. package/src/types/interface/api/responses/board.response.ts +81 -81
  111. package/src/types/interface/api/responses/count.response.ts +9 -9
  112. package/src/types/interface/api/responses/draw.public.response.ts +22 -22
  113. package/src/types/interface/api/responses/draw.response.ts +32 -32
  114. package/src/types/interface/api/responses/enriched-paginate.response.ts +11 -11
  115. package/src/types/interface/api/responses/memo.response.ts +32 -32
  116. package/src/types/interface/api/responses/metrics.response.ts +22 -22
  117. package/src/types/interface/api/responses/monitor.response.ts +8 -8
  118. package/src/types/interface/api/responses/recent.response.ts +18 -18
  119. package/src/types/interface/api/responses/retrospective-card.response.ts +23 -23
  120. package/src/types/interface/api/responses/retrospective-member.response.ts +22 -22
  121. package/src/types/interface/api/responses/retrospective-section.response.ts +23 -23
  122. package/src/types/interface/api/responses/retrospective.public.response.ts +57 -57
  123. package/src/types/interface/api/responses/retrospective.response.ts +32 -32
  124. package/src/types/interface/api/responses/short-link.admin.response.ts +21 -21
  125. package/src/types/interface/api/responses/short-link.public.response.ts +26 -26
  126. package/src/types/interface/api/responses/short-link.response.ts +38 -38
  127. package/src/types/interface/api/responses/tag.response.ts +38 -38
  128. package/src/types/interface/api/responses/transfer.response.ts +14 -14
  129. package/src/types/interface/api/type-message/api-error.ts +7 -7
  130. package/src/types/interface/api/type-message/base-paginate.ts +11 -11
  131. package/src/types/interface/api/type-message/response.ts +6 -6
  132. package/src/types/interface/index.ts +2 -2
  133. package/src/types/interface/models/atlas-document.dto.ts +22 -22
  134. package/src/types/interface/models/atlas-group.dto.ts +21 -21
  135. package/src/types/interface/models/atlas-page-content.dto.ts +17 -17
  136. package/src/types/interface/models/atlas-page.dto.ts +26 -26
  137. package/src/types/interface/models/atlas.dto.ts +34 -34
  138. package/src/types/interface/models/board-activity.dto.ts +20 -20
  139. package/src/types/interface/models/board-card-checklist-row.dto.ts +14 -14
  140. package/src/types/interface/models/board-card-checklist.dto.ts +16 -16
  141. package/src/types/interface/models/board-card-comment.dto.ts +15 -15
  142. package/src/types/interface/models/board-card-document.dto.ts +22 -22
  143. package/src/types/interface/models/board-card-label.dto.ts +14 -14
  144. package/src/types/interface/models/board-card-member.dto.ts +14 -14
  145. package/src/types/interface/models/board-card.dto.ts +37 -37
  146. package/src/types/interface/models/board-column.dto.ts +17 -17
  147. package/src/types/interface/models/board-label.dto.ts +13 -13
  148. package/src/types/interface/models/board.dto.ts +33 -33
  149. package/src/types/interface/models/content-share.dto.ts +16 -16
  150. package/src/types/interface/models/draw.dto.ts +30 -30
  151. package/src/types/interface/models/memo.dto.ts +23 -23
  152. package/src/types/interface/models/project.dto.ts +25 -25
  153. package/src/types/interface/models/retrospective-card.dto.ts +17 -17
  154. package/src/types/interface/models/retrospective-member.dto.ts +15 -15
  155. package/src/types/interface/models/retrospective-section.dto.ts +16 -16
  156. package/src/types/interface/models/retrospective.dto.ts +32 -32
  157. package/src/types/interface/models/short-link-click.dto.ts +33 -33
  158. package/src/types/interface/models/short-link.dto.ts +49 -49
  159. package/src/types/interface/models/tag.dto.ts +26 -26
  160. package/src/types/interface/models/team.dto.ts +12 -12
  161. package/src/types/interface/models/user.dto.ts +26 -26
  162. package/src/utils/board.utils.ts +57 -57
  163. package/src/utils/enum.utils.ts +5 -5
  164. package/src/utils/error.utils.ts +30 -30
  165. package/src/utils/icons.utils.ts +96 -96
  166. package/src/utils/shape.utils.ts +292 -292
@@ -1,292 +1,292 @@
1
- import { ICON_LIBRARY } from './icons.utils';
2
- import {
3
- Id,
4
- Point,
5
- DrawSize,
6
- DrawStyle,
7
- DrawShapeType,
8
- DrawShapeToJsonResult,
9
- } from '../types/draw.type';
10
-
11
- export type Endpoint = {
12
- style: DrawArrowEndpointStyle;
13
- } & (
14
- | { kind: 'free'; x: number; y: number }
15
- | { kind: 'anchor'; shapeId: Id; relativeX: number; relativeY: number }
16
- );
17
-
18
- export type DrawArrowEndpointStyle = 'arrow' | 'circle' | 'square' | 'diamond' | 'none';
19
-
20
- export type CurvePoint = Point & {
21
- type: 'straight' | 'curved'; // type de courbure: angle droit ou arrondi
22
- };
23
-
24
- export const rectangleToSvg = (position: Point, size: DrawSize, style: DrawStyle): string => {
25
- const x = position.x - size.width / 2;
26
- const y = position.y - size.height / 2;
27
- const width = size.width;
28
- const height = size.height;
29
- const fillColor = style.fillColor === 'none' ? 'none' : style.fillColor;
30
- const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
31
- const centerX = position.x;
32
- const centerY = position.y;
33
-
34
- return `<rect x="${x}" y="${y}" width="${width}" height="${height}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${
35
- style.strokeWidth
36
- }" opacity="${style.opacity}" rx="${style.cornerRadius}" ry="${
37
- style.cornerRadius
38
- }" stroke-dasharray="${style.lineDash || 'none'}" transform="rotate(${
39
- style.rotation
40
- } ${centerX} ${centerY})" />`;
41
- };
42
-
43
- export const diamondToSvg = (position: Point, size: DrawSize, style: DrawStyle): string => {
44
- const cx = position.x;
45
- const cy = position.y;
46
- const halfWidth = size.width / 2;
47
- const halfHeight = size.height / 2;
48
- const fillColor = style.fillColor === 'none' ? 'none' : style.fillColor;
49
- const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
50
-
51
- const points = [
52
- `${cx},${cy - halfHeight}`, // Top
53
- `${cx + halfWidth},${cy}`, // Right
54
- `${cx},${cy + halfHeight}`, // Bottom
55
- `${cx - halfWidth},${cy}`, // Left
56
- ].join(' ');
57
-
58
- return `<polygon points="${points}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${
59
- style.strokeWidth
60
- }" stroke-dasharray="${style.lineDash || 'none'}" opacity="${style.opacity}" transform="rotate(${
61
- style.rotation
62
- } ${cx} ${cy})" />`;
63
- };
64
-
65
- export const ellipseToSvg = (position: Point, size: DrawSize, style: DrawStyle): string => {
66
- const cx = position.x;
67
- const cy = position.y;
68
- const radiusX = size.width / 2;
69
- const radiusY = size.height / 2;
70
- const fillColor = style.fillColor === 'none' ? 'none' : style.fillColor;
71
- const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
72
-
73
- return `<ellipse cx="${cx}" cy="${cy}" rx="${radiusX}" ry="${radiusY}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${
74
- style.strokeWidth
75
- }" opacity="${style.opacity}" stroke-dasharray="${style.lineDash || 'none'}" transform="rotate(${
76
- style.rotation
77
- } ${cx} ${cy})" />`;
78
- };
79
-
80
- export const textToSvg = (position: Point, style: DrawStyle, text: string): string => {
81
- const x = position.x;
82
- const y = position.y;
83
- const fillColor = style.fillColor === 'none' ? 'none' : style.fillColor;
84
- const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
85
-
86
- return `<text x="${x}" y="${y}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${
87
- style.strokeWidth
88
- }" opacity="${style.opacity}" font-size="${style.fontSize}" font-family="${style.fontFamily}"
89
- stroke-dasharray="${
90
- style.lineDash || 'none'
91
- }" text-anchor="middle" dominant-baseline="middle" transform="rotate(${
92
- style.rotation
93
- } ${x} ${y})">${text}</text>`;
94
- };
95
-
96
- export const iconToSvg = (
97
- position: Point,
98
- size: DrawSize,
99
- style: DrawStyle,
100
- iconSymbol: string,
101
- ): string => {
102
- const x = position.x;
103
- const y = position.y;
104
- const fillColor = style.fillColor === 'none' ? 'none' : style.fillColor;
105
- const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
106
- const fontSize = Math.min(size.width, size.height) * 0.8;
107
-
108
- return `<text x="${x}" y="${y}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${style.strokeWidth}" opacity="${style.opacity}" font-size="${fontSize}" font-family="Arial" text-anchor="middle" dominant-baseline="middle" transform="rotate(${style.rotation} ${x} ${y})">${iconSymbol}</text>`;
109
- };
110
-
111
- export const imageToSvg = (
112
- position: Point,
113
- size: DrawSize,
114
- style: DrawStyle,
115
- src: string,
116
- ): string => {
117
- const x = position.x - size.width / 2;
118
- const y = position.y - size.height / 2;
119
- const width = size.width;
120
- const height = size.height;
121
- const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
122
- const centerX = position.x;
123
- const centerY = position.y;
124
-
125
- return `<image x="${x}" y="${y}" width="${width}" height="${height}" href="${src}" opacity="${style.opacity}" stroke="${strokeColor}" stroke-width="${style.strokeWidth}" rx="${style.cornerRadius}" ry="${style.cornerRadius}" transform="rotate(${style.rotation} ${centerX} ${centerY})" />`;
126
- };
127
-
128
- export const commentToSvg = (
129
- position: Point,
130
- size: DrawSize,
131
- style: DrawStyle,
132
- id: string,
133
- ): string => {
134
- const cx = position.x;
135
- const cy = position.y;
136
- const radius = size.width / 2;
137
- const fillColor = style.fillColor === 'none' ? 'transparent' : style.fillColor;
138
- const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
139
- const fontSize = size.width * 0.6;
140
-
141
- // Calculate text position to center the "!" character
142
- const textX = cx;
143
- const textY = cy + fontSize * 0.35; // Adjust for vertical centering
144
-
145
- return `
146
- <g opacity="${style.opacity}" transform="rotate(${style.rotation} ${cx} ${cy})">
147
- <defs>
148
- <filter id="comment-shadow-${id}" x="-50%" y="-50%" width="200%" height="200%">
149
- <feDropShadow dx="2" dy="2" stdDeviation="5" flood-color="black" flood-opacity="0.3"/>
150
- </filter>
151
- </defs>
152
- <circle cx="${cx}" cy="${cy}" r="${radius}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${style.strokeWidth}" filter="url(#comment-shadow-${id})" />
153
- <text x="${textX}" y="${textY}" fill="white" font-size="${fontSize}" font-family="Arial" text-anchor="middle" dominant-baseline="middle" font-weight="bold">!</text>
154
- </g>`;
155
- };
156
-
157
- const renderEndpointStyleSvg = (
158
- x: number,
159
- y: number,
160
- style: DrawArrowEndpointStyle,
161
- angle: number,
162
- strokeColor: string,
163
- fillColor: string,
164
- strokeWidth: number,
165
- ): string => {
166
- switch (style) {
167
- case 'circle':
168
- return `<circle cx="${x}" cy="${y}" r="6" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${strokeWidth}" />`;
169
-
170
- case 'square':
171
- const squareX = x - 6;
172
- const squareY = y - 6;
173
- return `<rect x="${squareX}" y="${squareY}" width="12" height="12" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${strokeWidth}" transform="rotate(${
174
- angle * (180 / Math.PI)
175
- } ${x} ${y})" />`;
176
-
177
- case 'diamond':
178
- return `<polygon points="${x},${y - 6} ${x + 6},${y} ${x},${y + 6} ${
179
- x - 6
180
- },${y}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${strokeWidth}" transform="rotate(${
181
- angle * (180 / Math.PI)
182
- } ${x} ${y})" />`;
183
-
184
- case 'arrow':
185
- const arrowSize = 8;
186
- const x1 = x - arrowSize * Math.cos(angle - Math.PI / 6);
187
- const y1 = y - arrowSize * Math.sin(angle - Math.PI / 6);
188
- const x2 = x - arrowSize * Math.cos(angle + Math.PI / 6);
189
- const y2 = y - arrowSize * Math.sin(angle + Math.PI / 6);
190
- return `<polygon points="${x},${y} ${x1},${y1} ${x2},${y2}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${strokeWidth}" />`;
191
-
192
- case 'none':
193
- default:
194
- return '';
195
- }
196
- };
197
-
198
- export const arrowToSvg = (
199
- style: DrawStyle,
200
- startEndpoint: Endpoint,
201
- endEndpoint: Endpoint,
202
- fromPos: Point,
203
- toPos: Point,
204
- ): string => {
205
- const angle = Math.atan2(toPos.y - fromPos.y, toPos.x - fromPos.x);
206
-
207
- let svg = `<g opacity="${style.opacity}">`;
208
-
209
- svg += `<line x1="${fromPos.x}" y1="${fromPos.y}" x2="${toPos.x}" y2="${toPos.y}" stroke="${style.strokeColor}" stroke-width="${style.strokeWidth}" />`;
210
-
211
- svg += renderEndpointStyleSvg(
212
- fromPos.x,
213
- fromPos.y,
214
- startEndpoint.style as DrawArrowEndpointStyle,
215
- angle + Math.PI,
216
- style.strokeColor,
217
- style.fillColor,
218
- style.strokeWidth,
219
- );
220
-
221
- svg += renderEndpointStyleSvg(
222
- toPos.x,
223
- toPos.y,
224
- endEndpoint.style as DrawArrowEndpointStyle,
225
- angle,
226
- style.strokeColor,
227
- style.fillColor,
228
- style.strokeWidth,
229
- );
230
-
231
- svg += '</g>';
232
-
233
- return svg;
234
- };
235
-
236
- export const sceneToSVG = (
237
- shapes: DrawShapeToJsonResult[],
238
- width: number,
239
- height: number,
240
- ): string => {
241
- const shapeEls = shapes
242
- .sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0))
243
- .map((s) => {
244
- switch (s.type) {
245
- case DrawShapeType.RECTANGLE:
246
- return rectangleToSvg(s.position, s.size, s.style);
247
- case DrawShapeType.DIAMOND:
248
- return diamondToSvg(s.position, s.size, s.style);
249
- case DrawShapeType.ELLIPSE:
250
- return ellipseToSvg(s.position, s.size, s.style);
251
- case DrawShapeType.TEXT:
252
- return textToSvg(s.position, s.style, s.text || '');
253
- case DrawShapeType.ICON:
254
- const iconSymbol = ICON_LIBRARY[s.iconType] || '';
255
- return iconToSvg(s.position, s.size, s.style, iconSymbol);
256
- case DrawShapeType.IMAGE:
257
- return imageToSvg(s.position, s.size, s.style, s.src);
258
- case DrawShapeType.COMMENT:
259
- return commentToSvg(s.position, s.size, s.style, s.id);
260
- case DrawShapeType.ARROW:
261
- if (s.startEndpoint && s.endEndpoint) {
262
- const startEp = s.startEndpoint;
263
- const endEp = s.endEndpoint;
264
- const fromPos =
265
- startEp.kind === 'anchor'
266
- ? shapes.find((shape) => shape.id === startEp.shapeId)?.position
267
- : { x: startEp.x, y: startEp.y };
268
- const toPos =
269
- endEp.kind === 'anchor'
270
- ? shapes.find((shape) => shape.id === endEp.shapeId)?.position
271
- : { x: endEp.x, y: endEp.y };
272
- if (!fromPos || !toPos) return '';
273
- return arrowToSvg(s.style, s.startEndpoint, s.endEndpoint, fromPos, toPos);
274
- }
275
- return '';
276
- default:
277
- return '';
278
- }
279
- });
280
-
281
- const defs = `
282
- <defs>
283
- <marker id="arrow" markerWidth="10" markerHeight="10" refX="10" refY="5" orient="auto-start-reverse">
284
- <path d="M0,0 L10,5 L0,10 z" fill="currentColor"/>
285
- </marker>
286
- </defs>`;
287
-
288
- return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">
289
- ${defs}
290
- ${shapeEls.join('\n')}
291
- </svg>`;
292
- };
1
+ import { ICON_LIBRARY } from './icons.utils';
2
+ import {
3
+ Id,
4
+ Point,
5
+ DrawSize,
6
+ DrawStyle,
7
+ DrawShapeType,
8
+ DrawShapeToJsonResult,
9
+ } from '../types/draw.type';
10
+
11
+ export type Endpoint = {
12
+ style: DrawArrowEndpointStyle;
13
+ } & (
14
+ | { kind: 'free'; x: number; y: number }
15
+ | { kind: 'anchor'; shapeId: Id; relativeX: number; relativeY: number }
16
+ );
17
+
18
+ export type DrawArrowEndpointStyle = 'arrow' | 'circle' | 'square' | 'diamond' | 'none';
19
+
20
+ export type CurvePoint = Point & {
21
+ type: 'straight' | 'curved'; // type de courbure: angle droit ou arrondi
22
+ };
23
+
24
+ export const rectangleToSvg = (position: Point, size: DrawSize, style: DrawStyle): string => {
25
+ const x = position.x - size.width / 2;
26
+ const y = position.y - size.height / 2;
27
+ const width = size.width;
28
+ const height = size.height;
29
+ const fillColor = style.fillColor === 'none' ? 'none' : style.fillColor;
30
+ const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
31
+ const centerX = position.x;
32
+ const centerY = position.y;
33
+
34
+ return `<rect x="${x}" y="${y}" width="${width}" height="${height}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${
35
+ style.strokeWidth
36
+ }" opacity="${style.opacity}" rx="${style.cornerRadius}" ry="${
37
+ style.cornerRadius
38
+ }" stroke-dasharray="${style.lineDash || 'none'}" transform="rotate(${
39
+ style.rotation
40
+ } ${centerX} ${centerY})" />`;
41
+ };
42
+
43
+ export const diamondToSvg = (position: Point, size: DrawSize, style: DrawStyle): string => {
44
+ const cx = position.x;
45
+ const cy = position.y;
46
+ const halfWidth = size.width / 2;
47
+ const halfHeight = size.height / 2;
48
+ const fillColor = style.fillColor === 'none' ? 'none' : style.fillColor;
49
+ const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
50
+
51
+ const points = [
52
+ `${cx},${cy - halfHeight}`, // Top
53
+ `${cx + halfWidth},${cy}`, // Right
54
+ `${cx},${cy + halfHeight}`, // Bottom
55
+ `${cx - halfWidth},${cy}`, // Left
56
+ ].join(' ');
57
+
58
+ return `<polygon points="${points}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${
59
+ style.strokeWidth
60
+ }" stroke-dasharray="${style.lineDash || 'none'}" opacity="${style.opacity}" transform="rotate(${
61
+ style.rotation
62
+ } ${cx} ${cy})" />`;
63
+ };
64
+
65
+ export const ellipseToSvg = (position: Point, size: DrawSize, style: DrawStyle): string => {
66
+ const cx = position.x;
67
+ const cy = position.y;
68
+ const radiusX = size.width / 2;
69
+ const radiusY = size.height / 2;
70
+ const fillColor = style.fillColor === 'none' ? 'none' : style.fillColor;
71
+ const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
72
+
73
+ return `<ellipse cx="${cx}" cy="${cy}" rx="${radiusX}" ry="${radiusY}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${
74
+ style.strokeWidth
75
+ }" opacity="${style.opacity}" stroke-dasharray="${style.lineDash || 'none'}" transform="rotate(${
76
+ style.rotation
77
+ } ${cx} ${cy})" />`;
78
+ };
79
+
80
+ export const textToSvg = (position: Point, style: DrawStyle, text: string): string => {
81
+ const x = position.x;
82
+ const y = position.y;
83
+ const fillColor = style.fillColor === 'none' ? 'none' : style.fillColor;
84
+ const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
85
+
86
+ return `<text x="${x}" y="${y}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${
87
+ style.strokeWidth
88
+ }" opacity="${style.opacity}" font-size="${style.fontSize}" font-family="${style.fontFamily}"
89
+ stroke-dasharray="${
90
+ style.lineDash || 'none'
91
+ }" text-anchor="middle" dominant-baseline="middle" transform="rotate(${
92
+ style.rotation
93
+ } ${x} ${y})">${text}</text>`;
94
+ };
95
+
96
+ export const iconToSvg = (
97
+ position: Point,
98
+ size: DrawSize,
99
+ style: DrawStyle,
100
+ iconSymbol: string,
101
+ ): string => {
102
+ const x = position.x;
103
+ const y = position.y;
104
+ const fillColor = style.fillColor === 'none' ? 'none' : style.fillColor;
105
+ const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
106
+ const fontSize = Math.min(size.width, size.height) * 0.8;
107
+
108
+ return `<text x="${x}" y="${y}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${style.strokeWidth}" opacity="${style.opacity}" font-size="${fontSize}" font-family="Arial" text-anchor="middle" dominant-baseline="middle" transform="rotate(${style.rotation} ${x} ${y})">${iconSymbol}</text>`;
109
+ };
110
+
111
+ export const imageToSvg = (
112
+ position: Point,
113
+ size: DrawSize,
114
+ style: DrawStyle,
115
+ src: string,
116
+ ): string => {
117
+ const x = position.x - size.width / 2;
118
+ const y = position.y - size.height / 2;
119
+ const width = size.width;
120
+ const height = size.height;
121
+ const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
122
+ const centerX = position.x;
123
+ const centerY = position.y;
124
+
125
+ return `<image x="${x}" y="${y}" width="${width}" height="${height}" href="${src}" opacity="${style.opacity}" stroke="${strokeColor}" stroke-width="${style.strokeWidth}" rx="${style.cornerRadius}" ry="${style.cornerRadius}" transform="rotate(${style.rotation} ${centerX} ${centerY})" />`;
126
+ };
127
+
128
+ export const commentToSvg = (
129
+ position: Point,
130
+ size: DrawSize,
131
+ style: DrawStyle,
132
+ id: string,
133
+ ): string => {
134
+ const cx = position.x;
135
+ const cy = position.y;
136
+ const radius = size.width / 2;
137
+ const fillColor = style.fillColor === 'none' ? 'transparent' : style.fillColor;
138
+ const strokeColor = style.strokeColor === 'none' ? 'none' : style.strokeColor;
139
+ const fontSize = size.width * 0.6;
140
+
141
+ // Calculate text position to center the "!" character
142
+ const textX = cx;
143
+ const textY = cy + fontSize * 0.35; // Adjust for vertical centering
144
+
145
+ return `
146
+ <g opacity="${style.opacity}" transform="rotate(${style.rotation} ${cx} ${cy})">
147
+ <defs>
148
+ <filter id="comment-shadow-${id}" x="-50%" y="-50%" width="200%" height="200%">
149
+ <feDropShadow dx="2" dy="2" stdDeviation="5" flood-color="black" flood-opacity="0.3"/>
150
+ </filter>
151
+ </defs>
152
+ <circle cx="${cx}" cy="${cy}" r="${radius}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${style.strokeWidth}" filter="url(#comment-shadow-${id})" />
153
+ <text x="${textX}" y="${textY}" fill="white" font-size="${fontSize}" font-family="Arial" text-anchor="middle" dominant-baseline="middle" font-weight="bold">!</text>
154
+ </g>`;
155
+ };
156
+
157
+ const renderEndpointStyleSvg = (
158
+ x: number,
159
+ y: number,
160
+ style: DrawArrowEndpointStyle,
161
+ angle: number,
162
+ strokeColor: string,
163
+ fillColor: string,
164
+ strokeWidth: number,
165
+ ): string => {
166
+ switch (style) {
167
+ case 'circle':
168
+ return `<circle cx="${x}" cy="${y}" r="6" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${strokeWidth}" />`;
169
+
170
+ case 'square':
171
+ const squareX = x - 6;
172
+ const squareY = y - 6;
173
+ return `<rect x="${squareX}" y="${squareY}" width="12" height="12" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${strokeWidth}" transform="rotate(${
174
+ angle * (180 / Math.PI)
175
+ } ${x} ${y})" />`;
176
+
177
+ case 'diamond':
178
+ return `<polygon points="${x},${y - 6} ${x + 6},${y} ${x},${y + 6} ${
179
+ x - 6
180
+ },${y}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${strokeWidth}" transform="rotate(${
181
+ angle * (180 / Math.PI)
182
+ } ${x} ${y})" />`;
183
+
184
+ case 'arrow':
185
+ const arrowSize = 8;
186
+ const x1 = x - arrowSize * Math.cos(angle - Math.PI / 6);
187
+ const y1 = y - arrowSize * Math.sin(angle - Math.PI / 6);
188
+ const x2 = x - arrowSize * Math.cos(angle + Math.PI / 6);
189
+ const y2 = y - arrowSize * Math.sin(angle + Math.PI / 6);
190
+ return `<polygon points="${x},${y} ${x1},${y1} ${x2},${y2}" fill="${fillColor}" stroke="${strokeColor}" stroke-width="${strokeWidth}" />`;
191
+
192
+ case 'none':
193
+ default:
194
+ return '';
195
+ }
196
+ };
197
+
198
+ export const arrowToSvg = (
199
+ style: DrawStyle,
200
+ startEndpoint: Endpoint,
201
+ endEndpoint: Endpoint,
202
+ fromPos: Point,
203
+ toPos: Point,
204
+ ): string => {
205
+ const angle = Math.atan2(toPos.y - fromPos.y, toPos.x - fromPos.x);
206
+
207
+ let svg = `<g opacity="${style.opacity}">`;
208
+
209
+ svg += `<line x1="${fromPos.x}" y1="${fromPos.y}" x2="${toPos.x}" y2="${toPos.y}" stroke="${style.strokeColor}" stroke-width="${style.strokeWidth}" />`;
210
+
211
+ svg += renderEndpointStyleSvg(
212
+ fromPos.x,
213
+ fromPos.y,
214
+ startEndpoint.style as DrawArrowEndpointStyle,
215
+ angle + Math.PI,
216
+ style.strokeColor,
217
+ style.fillColor,
218
+ style.strokeWidth,
219
+ );
220
+
221
+ svg += renderEndpointStyleSvg(
222
+ toPos.x,
223
+ toPos.y,
224
+ endEndpoint.style as DrawArrowEndpointStyle,
225
+ angle,
226
+ style.strokeColor,
227
+ style.fillColor,
228
+ style.strokeWidth,
229
+ );
230
+
231
+ svg += '</g>';
232
+
233
+ return svg;
234
+ };
235
+
236
+ export const sceneToSVG = (
237
+ shapes: DrawShapeToJsonResult[],
238
+ width: number,
239
+ height: number,
240
+ ): string => {
241
+ const shapeEls = shapes
242
+ .sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0))
243
+ .map((s) => {
244
+ switch (s.type) {
245
+ case DrawShapeType.RECTANGLE:
246
+ return rectangleToSvg(s.position, s.size, s.style);
247
+ case DrawShapeType.DIAMOND:
248
+ return diamondToSvg(s.position, s.size, s.style);
249
+ case DrawShapeType.ELLIPSE:
250
+ return ellipseToSvg(s.position, s.size, s.style);
251
+ case DrawShapeType.TEXT:
252
+ return textToSvg(s.position, s.style, s.text || '');
253
+ case DrawShapeType.ICON:
254
+ const iconSymbol = ICON_LIBRARY[s.iconType] || '';
255
+ return iconToSvg(s.position, s.size, s.style, iconSymbol);
256
+ case DrawShapeType.IMAGE:
257
+ return imageToSvg(s.position, s.size, s.style, s.src);
258
+ case DrawShapeType.COMMENT:
259
+ return commentToSvg(s.position, s.size, s.style, s.id);
260
+ case DrawShapeType.ARROW:
261
+ if (s.startEndpoint && s.endEndpoint) {
262
+ const startEp = s.startEndpoint;
263
+ const endEp = s.endEndpoint;
264
+ const fromPos =
265
+ startEp.kind === 'anchor'
266
+ ? shapes.find((shape) => shape.id === startEp.shapeId)?.position
267
+ : { x: startEp.x, y: startEp.y };
268
+ const toPos =
269
+ endEp.kind === 'anchor'
270
+ ? shapes.find((shape) => shape.id === endEp.shapeId)?.position
271
+ : { x: endEp.x, y: endEp.y };
272
+ if (!fromPos || !toPos) return '';
273
+ return arrowToSvg(s.style, s.startEndpoint, s.endEndpoint, fromPos, toPos);
274
+ }
275
+ return '';
276
+ default:
277
+ return '';
278
+ }
279
+ });
280
+
281
+ const defs = `
282
+ <defs>
283
+ <marker id="arrow" markerWidth="10" markerHeight="10" refX="10" refY="5" orient="auto-start-reverse">
284
+ <path d="M0,0 L10,5 L0,10 z" fill="currentColor"/>
285
+ </marker>
286
+ </defs>`;
287
+
288
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}">
289
+ ${defs}
290
+ ${shapeEls.join('\n')}
291
+ </svg>`;
292
+ };