plotboilerplate 1.18.0 → 1.20.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 (155) hide show
  1. package/README.md +1 -1
  2. package/dist/index.esm.js +244 -63
  3. package/dist/index.esm.js.map +1 -1
  4. package/dist/index.esm.min.js +1 -1
  5. package/dist/index.esm.min.js.map +1 -1
  6. package/dist/plotboilerplate.browser.min.js +1 -1
  7. package/dist/plotboilerplate.browser.min.js.map +1 -1
  8. package/dist/plotboilerplate.js +243 -74
  9. package/dist/plotboilerplate.min.js +1 -1
  10. package/package.json +1 -1
  11. package/src/cjs/Bounds.d.ts +14 -5
  12. package/src/cjs/Bounds.js +18 -8
  13. package/src/cjs/Bounds.js.map +1 -1
  14. package/src/cjs/CubicBezierCurve.d.ts +20 -3
  15. package/src/cjs/CubicBezierCurve.js +25 -2
  16. package/src/cjs/CubicBezierCurve.js.map +1 -1
  17. package/src/cjs/Line.d.ts +46 -4
  18. package/src/cjs/Line.js +60 -3
  19. package/src/cjs/Line.js.map +1 -1
  20. package/src/cjs/PlotBoilerplate.d.ts +5 -2
  21. package/src/cjs/PlotBoilerplate.js +52 -30
  22. package/src/cjs/PlotBoilerplate.js.map +1 -1
  23. package/src/cjs/Polygon.js +1 -1
  24. package/src/cjs/Polygon.js.map +1 -1
  25. package/src/cjs/VEllipseSector.d.ts +4 -3
  26. package/src/cjs/VEllipseSector.js +15 -8
  27. package/src/cjs/VEllipseSector.js.map +1 -1
  28. package/src/cjs/Vector.d.ts +14 -3
  29. package/src/cjs/Vector.js +21 -2
  30. package/src/cjs/Vector.js.map +1 -1
  31. package/src/cjs/Vertex.d.ts +33 -1
  32. package/src/cjs/Vertex.js +43 -1
  33. package/src/cjs/Vertex.js.map +1 -1
  34. package/src/cjs/drawutilssvg.d.ts +2 -1
  35. package/src/cjs/drawutilssvg.js +7 -19
  36. package/src/cjs/drawutilssvg.js.map +1 -1
  37. package/src/cjs/entry.js +1 -0
  38. package/src/cjs/interfaces/additionals.d.ts +95 -0
  39. package/src/cjs/interfaces/additionals.js +3 -0
  40. package/src/cjs/interfaces/additionals.js.map +1 -0
  41. package/src/cjs/interfaces/core.d.ts +7 -0
  42. package/src/cjs/interfaces/core.js +2 -0
  43. package/src/cjs/interfaces/core.js.map +1 -1
  44. package/src/cjs/interfaces/index.d.ts +1 -0
  45. package/src/cjs/interfaces/index.js +1 -0
  46. package/src/cjs/interfaces/index.js.map +1 -1
  47. package/src/cjs/utils/algorithms/arrayShuffle.d.ts +8 -0
  48. package/src/cjs/utils/algorithms/arrayShuffle.js +15 -0
  49. package/src/cjs/utils/algorithms/arrayShuffle.js.map +1 -0
  50. package/src/cjs/utils/algorithms/detectPaths.d.ts +21 -0
  51. package/src/cjs/utils/algorithms/detectPaths.js +169 -0
  52. package/src/cjs/utils/algorithms/detectPaths.js.map +1 -0
  53. package/src/cjs/utils/creategui.js +7 -0
  54. package/src/cjs/utils/datastructures/Color.d.ts +1 -1
  55. package/src/cjs/utils/datastructures/Color.js +4 -2
  56. package/src/cjs/utils/datastructures/Color.js.map +1 -1
  57. package/src/cjs/utils/datastructures/GenericPath.d.ts +75 -0
  58. package/src/cjs/utils/datastructures/GenericPath.js +105 -0
  59. package/src/cjs/utils/datastructures/GenericPath.js.map +1 -0
  60. package/src/cjs/utils/datastructures/GirihTile.d.ts +1 -1
  61. package/src/cjs/utils/io/FileDrop.d.ts +11 -1
  62. package/src/cjs/utils/io/FileDrop.js +41 -10
  63. package/src/cjs/utils/io/FileDrop.js.map +1 -1
  64. package/src/cjs/utils/parsers/svg/parseSVGPathData.d.ts +26 -0
  65. package/src/cjs/utils/parsers/svg/parseSVGPathData.js +463 -0
  66. package/src/cjs/utils/parsers/svg/parseSVGPathData.js.map +1 -0
  67. package/src/cjs/utils/parsers/svg/splitSVGPathData.d.ts +20 -0
  68. package/src/cjs/utils/parsers/svg/splitSVGPathData.js +49 -0
  69. package/src/cjs/utils/parsers/svg/splitSVGPathData.js.map +1 -0
  70. package/src/cjs/utils/parsers/svg/types.d.ts +43 -0
  71. package/src/cjs/utils/parsers/svg/types.js +16 -0
  72. package/src/cjs/utils/parsers/svg/types.js.map +1 -0
  73. package/src/esm/Bounds.d.ts +14 -5
  74. package/src/esm/Bounds.js +18 -8
  75. package/src/esm/Bounds.js.map +1 -1
  76. package/src/esm/CubicBezierCurve.d.ts +20 -3
  77. package/src/esm/CubicBezierCurve.js +25 -2
  78. package/src/esm/CubicBezierCurve.js.map +1 -1
  79. package/src/esm/Line.d.ts +46 -4
  80. package/src/esm/Line.js +60 -3
  81. package/src/esm/Line.js.map +1 -1
  82. package/src/esm/PlotBoilerplate.d.ts +5 -2
  83. package/src/esm/PlotBoilerplate.js +52 -30
  84. package/src/esm/PlotBoilerplate.js.map +1 -1
  85. package/src/esm/Polygon.js +1 -1
  86. package/src/esm/Polygon.js.map +1 -1
  87. package/src/esm/VEllipseSector.d.ts +4 -3
  88. package/src/esm/VEllipseSector.js +15 -8
  89. package/src/esm/VEllipseSector.js.map +1 -1
  90. package/src/esm/Vector.d.ts +13 -2
  91. package/src/esm/Vector.js +23 -4
  92. package/src/esm/Vector.js.map +1 -1
  93. package/src/esm/Vertex.d.ts +33 -1
  94. package/src/esm/Vertex.js +43 -1
  95. package/src/esm/Vertex.js.map +1 -1
  96. package/src/esm/drawutilssvg.d.ts +2 -1
  97. package/src/esm/drawutilssvg.js +7 -19
  98. package/src/esm/drawutilssvg.js.map +1 -1
  99. package/src/esm/entry.js +1 -0
  100. package/src/esm/interfaces/additionals.d.ts +95 -0
  101. package/src/esm/interfaces/additionals.js +2 -0
  102. package/src/esm/interfaces/additionals.js.map +1 -0
  103. package/src/esm/interfaces/core.d.ts +7 -0
  104. package/src/esm/interfaces/core.js +2 -0
  105. package/src/esm/interfaces/core.js.map +1 -1
  106. package/src/esm/interfaces/index.d.ts +1 -0
  107. package/src/esm/interfaces/index.js +1 -0
  108. package/src/esm/interfaces/index.js.map +1 -1
  109. package/src/esm/utils/algorithms/arrayShuffle.d.ts +8 -0
  110. package/src/esm/utils/algorithms/arrayShuffle.js +11 -0
  111. package/src/esm/utils/algorithms/arrayShuffle.js.map +1 -0
  112. package/src/esm/utils/algorithms/detectPaths.d.ts +21 -0
  113. package/src/esm/utils/algorithms/detectPaths.js +165 -0
  114. package/src/esm/utils/algorithms/detectPaths.js.map +1 -0
  115. package/src/esm/utils/datastructures/Color.d.ts +1 -1
  116. package/src/esm/utils/datastructures/Color.js +4 -2
  117. package/src/esm/utils/datastructures/Color.js.map +1 -1
  118. package/src/esm/utils/datastructures/GenericPath.d.ts +75 -0
  119. package/src/esm/utils/datastructures/GenericPath.js +100 -0
  120. package/src/esm/utils/datastructures/GenericPath.js.map +1 -0
  121. package/src/esm/utils/datastructures/GirihTile.d.ts +1 -1
  122. package/src/esm/utils/io/FileDrop.d.ts +11 -1
  123. package/src/esm/utils/io/FileDrop.js +41 -10
  124. package/src/esm/utils/io/FileDrop.js.map +1 -1
  125. package/src/esm/utils/parsers/svg/parseSVGPathData.d.ts +26 -0
  126. package/src/esm/utils/parsers/svg/parseSVGPathData.js +459 -0
  127. package/src/esm/utils/parsers/svg/parseSVGPathData.js.map +1 -0
  128. package/src/esm/utils/parsers/svg/splitSVGPathData.d.ts +20 -0
  129. package/src/esm/utils/parsers/svg/splitSVGPathData.js +45 -0
  130. package/src/esm/utils/parsers/svg/splitSVGPathData.js.map +1 -0
  131. package/src/esm/utils/parsers/svg/types.d.ts +43 -0
  132. package/src/esm/utils/parsers/svg/types.js +15 -0
  133. package/src/esm/utils/parsers/svg/types.js.map +1 -0
  134. package/src/ts/Bounds.ts +19 -8
  135. package/src/ts/CubicBezierCurve.ts +29 -4
  136. package/src/ts/Line.ts +70 -6
  137. package/src/ts/PlotBoilerplate.ts +57 -35
  138. package/src/ts/Polygon.ts +1 -1
  139. package/src/ts/VEllipseSector.ts +22 -15
  140. package/src/ts/Vector.ts +24 -4
  141. package/src/ts/Vertex.ts +46 -1
  142. package/src/ts/drawutilssvg.ts +8 -19
  143. package/src/ts/interfaces/additionals.ts +105 -0
  144. package/src/ts/interfaces/core.ts +5 -0
  145. package/src/ts/interfaces/index.ts +1 -0
  146. package/src/ts/utils/algorithms/arrayShuffle.ts +11 -0
  147. package/src/ts/utils/algorithms/detectPaths.ts +195 -0
  148. package/src/ts/utils/datastructures/Color.ts +8 -4
  149. package/src/ts/utils/datastructures/GenericPath.ts +113 -0
  150. package/src/ts/utils/datastructures/GirihTile.ts +1 -1
  151. package/src/ts/utils/io/FileDrop.ts +51 -10
  152. package/src/ts/utils/parsers/svg/parseSVGPathData.ts +572 -0
  153. package/src/ts/utils/parsers/svg/splitSVGPathData.ts +50 -0
  154. package/src/ts/utils/parsers/svg/types.ts +70 -0
  155. package/changelog.md +0 -731
@@ -34,7 +34,8 @@
34
34
  * @modified 2022-03-26 Added the private `nodeDefs` and `bufferedNodeDefs` attributes.
35
35
  * @modified 2022-03-26 Added the `texturedPoly` function to draw textures polygons.
36
36
  * @modified 2022-07-26 Adding `alpha` to the `image(...)` function.
37
- * @version 1.6.1
37
+ * @modified 2022-11-10 Tweaking some type issues.
38
+ * @version 1.6.2
38
39
  **/
39
40
 
40
41
  import { CircleSector } from "./CircleSector";
@@ -259,7 +260,7 @@ export class drawutilssvg implements DrawLib<void | SVGElement> {
259
260
  "text": "Text"
260
261
  };
261
262
  // Question: why isn't this working if the svgNode is created dynamically? (nodeStyle.sheet is null)
262
- const rules = [];
263
+ const rules: Array<string> = [];
263
264
  for (var k in keys) {
264
265
  const className: string = keys[k];
265
266
  const drawSettings: DrawSettings | undefined = drawConfig[k];
@@ -1321,10 +1322,10 @@ export class drawutilssvg implements DrawLib<void | SVGElement> {
1321
1322
  this.curId = curId + "_text";
1322
1323
  const textNode: SVGElement = this.makeNode("text");
1323
1324
  node.appendChild(textNode);
1324
- textNode.setAttribute("font-family", options.fontFamily); // May be undefined
1325
- textNode.setAttribute("font-size", options.fontSize ? `${options.fontSize * this.scale.x}` : null);
1326
- textNode.setAttribute("font-style", options.fontStyle ? `${options.fontStyle}` : null);
1327
- textNode.setAttribute("font-weight", options.fontWeight ? `${options.fontWeight}` : null);
1325
+ textNode.setAttribute("font-family", options.fontFamily ?? ""); // May be undefined
1326
+ textNode.setAttribute("font-size", options.fontSize ? `${options.fontSize * this.scale.x}` : "");
1327
+ textNode.setAttribute("font-style", options.fontStyle ? `${options.fontStyle}` : "");
1328
+ textNode.setAttribute("font-weight", options.fontWeight ? `${options.fontWeight}` : "");
1328
1329
  textNode.setAttribute("text-anchor", textAlign);
1329
1330
  textNode.setAttribute("transform-origin", "0 0");
1330
1331
  textNode.setAttribute("transform", rotate);
@@ -1488,19 +1489,7 @@ export class drawutilssvg implements DrawLib<void | SVGElement> {
1488
1489
  const _sy = (index: number): void => {
1489
1490
  data[index] = scale.y * Number(data[index]);
1490
1491
  };
1491
- const stx = (value: number): number => {
1492
- return offset.x + scale.x * value;
1493
- };
1494
- const sty = (value: number): number => {
1495
- return offset.y + scale.y * value;
1496
- };
1497
- // scale only {x,y}
1498
- const sx = (value: number): number => {
1499
- return scale.x * value;
1500
- };
1501
- const sy = (value: number): number => {
1502
- return scale.y * value;
1503
- };
1492
+
1504
1493
  var i: number = 0;
1505
1494
  var lastPoint: XYCoords = { x: NaN, y: NaN };
1506
1495
  // "save last point"
@@ -0,0 +1,105 @@
1
+ /**
2
+ * @date 2022-10-17
3
+ */
4
+ import { Vertex } from "../Vertex";
5
+
6
+ /**
7
+ * A common interface for different kinds of path segments.
8
+ */
9
+ export interface PathSegment {
10
+ /**
11
+ * Get the start point of this path segment.
12
+ *
13
+ * @method getStartPoint
14
+ * @memberof PathSegment
15
+ * @return {Vertex} The start point of this path segment.
16
+ */
17
+ getStartPoint(): Vertex;
18
+
19
+ /**
20
+ * Get the end point of this path segment.
21
+ *
22
+ * @method getEndPoint
23
+ * @memberof PathSegment
24
+ * @return {Vertex} The end point of this path segment.
25
+ */
26
+ getEndPoint(): Vertex;
27
+
28
+ /**
29
+ * Get the tangent's end point at the start point of this segment.
30
+ *
31
+ * @method getStartTangent
32
+ * @memberof PathSegment
33
+ * @return {Vertex} The end point of the starting point's tangent.
34
+ */
35
+ getStartTangent(): Vertex;
36
+
37
+ /**
38
+ * Get the tangent's end point at the end point of this segment.
39
+ *
40
+ * @method getEndTangent
41
+ * @memberof PathSegment
42
+ * @return {Vertex} The end point of the ending point's tangent.
43
+ */
44
+ getEndTangent(): Vertex;
45
+
46
+ /**
47
+ * Create a deep clone of this path segment.
48
+ *
49
+ * @method clone
50
+ * @memberof PathSegment
51
+ * @return {PathSegment} A deep clone/copy of this path segment.
52
+ */
53
+ clone: () => PathSegment;
54
+
55
+ /**
56
+ * Revserse this path segment (in-place) and return this same instance (useful for chaining).
57
+ * The new path segment has start and end point swapped.
58
+ *
59
+ * @method reverse
60
+ * @memberof PathSegment
61
+ * @return {PathSegment} This path segment instance (for chaining).
62
+ */
63
+ reverse: () => PathSegment;
64
+ }
65
+
66
+ /**
67
+ * A common interface for general path representations.
68
+ */
69
+ export interface Path extends PathSegment {
70
+ /**
71
+ * Get the number of segments in this path.
72
+ *
73
+ * @method getSegmentCount
74
+ * @memberof Path
75
+ * @return {number} The number (integer) of path segments.
76
+ */
77
+ getSegmentCount: () => number;
78
+
79
+ /**
80
+ * Get the path segment at the given index.
81
+ *
82
+ * @method getSegmentAt
83
+ * @memberof Path
84
+ * @return {PathSegment} The paths segment at the given index.
85
+ */
86
+ getSegmentAt: (index: number) => PathSegment;
87
+
88
+ /**
89
+ * Create a deep clone of this path.
90
+ *
91
+ * @method clone
92
+ * @memberof Path
93
+ * @return {Path} A deep clone/copy of this path.
94
+ */
95
+ clone: () => Path;
96
+
97
+ /**
98
+ * Reverse this path (swap start and end and thus – the direction) in-place.
99
+ *
100
+ * @method revert
101
+ * @memberof Path
102
+ * @return {PathSegment} This path instance.
103
+ */
104
+ reverse: () => Path;
105
+ }
@@ -15,6 +15,8 @@
15
15
  * @modified 2021-06-21 Added `IBounds.getCenter()`.
16
16
  * @modified 2021-11-16 Added `text` options to the `DrawConfig`.
17
17
  * @modified 2022-08-01 Added `title` param to the `PBParams` interface.
18
+ * @modified 2022-10-25 Added `origin` param to the `DrawConfig` interface.
19
+ * @modified 2022-11-23 Added `drawRaster` to the `Config` interface.
18
20
  **/
19
21
 
20
22
  import { Vertex } from "../Vertex";
@@ -107,6 +109,7 @@ export interface Config {
107
109
  offsetX?: number; // The initial x-offset. Default is 0.0. Note that autoAdjustOffset=true overrides these values.
108
110
  offsetY?: number; // The initial y-offset. Default is 0.0. Note that autoAdjustOffset=true overrides these values.
109
111
  rasterGrid?: boolean; // If set to true the background grid will be drawn rastered.
112
+ drawRaster?: boolean; // If set to false, no raster or grid will be drawn at all.
110
113
  rasterScaleX?: number; // Define the default horizontal raster scale (default=1.0).
111
114
  rasterScaleY?: number; // Define the default vertical raster scale (default=1.0).
112
115
  rasterAdjustFactor?: number; // The exponential limit for wrapping down the grid. (2.0 means: halve the grid each 2.0*n zoom step).
@@ -175,6 +178,7 @@ export interface DrawConfig {
175
178
  drawHandleLines: boolean;
176
179
  drawHandlePoints: boolean;
177
180
  drawGrid: boolean;
181
+ drawRaster: boolean; // If set to false, no raster or grid will be drawn at all.
178
182
  bezier: {
179
183
  color: string;
180
184
  lineWidth: number;
@@ -199,6 +203,7 @@ export interface DrawConfig {
199
203
  fill?: boolean;
200
204
  anchor?: boolean;
201
205
  };
206
+ origin: { color: string };
202
207
  }
203
208
 
204
209
  /** This is a fix for the problem, that the constructor's "name" attribute is not
@@ -1,3 +1,4 @@
1
1
  export * from "./core";
2
2
  export * from "./DrawLib";
3
3
  export * from "./externals";
4
+ export * from "./additionals";
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Randomize a given array in-place.
3
+ *
4
+ * @author Ikaros Kappler
5
+ * @date 2022-10-09
6
+ * @version 1.0.0
7
+ **/
8
+
9
+ export const arrayShuffle = (arr: Array<any>): void => {
10
+ arr.sort(() => Math.random() - 0.5);
11
+ };
@@ -0,0 +1,195 @@
1
+ /**
2
+ * A function to detect connected paths on the plane given by a random set of segments.
3
+ *
4
+ * Note that is algorithm operates IN PLACE and will ALTER your INPUT array.
5
+ *
6
+ * @author Ikaros Kappler
7
+ * @version 1.0.0
8
+ * @date 2022-10-17
9
+ */
10
+
11
+ import { Path, PathSegment } from "../../interfaces";
12
+ import { GenericPath } from "../datastructures/GenericPath";
13
+
14
+ /**
15
+ * An interface/datascructure for keeping track of visited path segments.
16
+ */
17
+ interface Visitation {
18
+ visited: boolean;
19
+ hasPredecessor: boolean;
20
+ hasSuccessor: boolean;
21
+ }
22
+
23
+ /**
24
+ * A private helper function that initializes the visitation tracking and reverses
25
+ * dangling path ends to connect them with preceding paths.
26
+ *
27
+ * Note that this function alters those dangling path segments IN PLACE!
28
+ *
29
+ * @param segments
30
+ * @param epsilon
31
+ * @returns
32
+ */
33
+ const initVisitationArray = (segments: Array<PathSegment>, epsilon: number): Array<Visitation> => {
34
+ const result: Array<Visitation> = []; // { visited: false, hasPredecessor: false }
35
+ for (var i = 0; i < segments.length; i++) {
36
+ result.push({ visited: false, hasPredecessor: false, hasSuccessor: false });
37
+ for (var j = 0; j < segments.length; j++) {
38
+ if (i === j) {
39
+ continue;
40
+ }
41
+ if (
42
+ segments[i].getStartPoint().distance(segments[j].getEndPoint()) < epsilon ||
43
+ segments[i].getStartPoint().distance(segments[j].getStartPoint()) < epsilon
44
+ ) {
45
+ result[i].hasPredecessor = true;
46
+ }
47
+ if (
48
+ segments[i].getEndPoint().distance(segments[j].getEndPoint()) < epsilon ||
49
+ segments[i].getEndPoint().distance(segments[j].getStartPoint()) < epsilon
50
+ ) {
51
+ result[i].hasSuccessor = true;
52
+ }
53
+ }
54
+ }
55
+ // After first initialization make sure that no loose path ends are dangling around
56
+ // if the affected path segment has a predecessor (but nu successor).
57
+ //
58
+ // Revert those segments. This makes the actual detection algorithm much easier.
59
+ for (var i = 0; i < segments.length; i++) {
60
+ if (!result[i].hasSuccessor && result[i].hasPredecessor) {
61
+ segments[i] = segments[i].reverse();
62
+ result[i].hasPredecessor = false;
63
+ result[i].hasSuccessor = true;
64
+ }
65
+ }
66
+ return result;
67
+ };
68
+
69
+ /**
70
+ * Find the next unvisited path segment (private helper function).
71
+ *
72
+ * There is a special order: starting path segments (those without any predecessor)
73
+ * will be preferred. If no more open paths are available (no starting path segments),
74
+ * then no more unvisited paths are available or all remaining paths are loops (without
75
+ * determined start/end).
76
+ *
77
+ * Doing this keeps us from the need to run a final loop to connect detected sub paths.
78
+ *
79
+ * @param {Array<PathSegment>} segments - The path segments to search in.
80
+ * @param { Array<Visitation>} isSegmentVisited
81
+ * @returns {number} The index of the next unvisited path segment or -1 if no more are available.
82
+ */
83
+ const locateUnvisitedSegment = (segments: Array<PathSegment>, isSegmentVisited: Array<Visitation>): number => {
84
+ // First run: detect beginnings
85
+ for (var i = 0; i < segments.length; i++) {
86
+ if (!isSegmentVisited[i].hasPredecessor && !isSegmentVisited[i].visited) {
87
+ return i;
88
+ }
89
+ }
90
+ // Second run: if no beginnings exist -> use inner path segment
91
+ for (var i = 0; i < segments.length; i++) {
92
+ if (!isSegmentVisited[i].visited) {
93
+ return i;
94
+ }
95
+ }
96
+ return -1;
97
+ };
98
+
99
+ /**
100
+ * Get the next adjacent path segment to the given (current) segment. This is a private
101
+ * helper function.
102
+ *
103
+ * Note that the function will revert the adjacent path segment if required, so the next
104
+ * starting point 'equals' the current ending point.
105
+ *
106
+ * The visitation tracker will be updated if the adjacent segment was found.
107
+ *
108
+ * @param {Array<PathSegment>} segments - The total set of available path segments (visited and invisited).
109
+ * @param {Array<Visitation>} isSegmentVisited - A tracker of visited path segments so far.
110
+ * @param {PathSegment} currentSegment - The current path segment to find the adjacent segment for.
111
+ * @param {number} epsilon - The epsilon to use to detect 'equal' start/end points. Must be >= 0.
112
+ * @returns {PathSegment | null} The next adjacent path segment of null if no such exists.
113
+ */
114
+ const getAdjacentSegment = (
115
+ segments: Array<PathSegment>,
116
+ isSegmentVisited: Array<Visitation>,
117
+ currentSegment: PathSegment,
118
+ epsilon: number
119
+ ): PathSegment | null => {
120
+ for (var j = 0; j < segments.length; j++) {
121
+ if (isSegmentVisited[j].visited) {
122
+ continue;
123
+ }
124
+ var nextSegment = segments[j];
125
+ // [start]---[end] [start]---[end]
126
+ if (currentSegment.getEndPoint().distance(nextSegment.getStartPoint()) < epsilon) {
127
+ isSegmentVisited[j].visited = true;
128
+ return nextSegment;
129
+ }
130
+ // [start]---[end] [end]---[start]
131
+ else if (currentSegment.getEndPoint().distance(nextSegment.getEndPoint()) < epsilon) {
132
+ isSegmentVisited[j].visited = true;
133
+ return nextSegment.reverse();
134
+ }
135
+ }
136
+ return null;
137
+ };
138
+
139
+ /**
140
+ * A private helper function to find the adjacent full path for the given path segment,
141
+ * considering the current path segment is a starting segment (or one inside a loop).
142
+ *
143
+ * @param {Array<PathSegment>} segments - The total set of available path segments.
144
+ * @param { Array<Visitation>} isSegmentVisited - A tracker to determine which segments have already been visited.
145
+ * @param {number} currentSegmentIndex - The index of the current segments to find the containing path for.
146
+ * @param {number} epsilon - The epsilon to use to determine 'equal' path points. Must be >= 0.
147
+ * @returns {GenericPath} The dected path which consists at least of the current path segment.
148
+ */
149
+ const detectAdjacentPath = (
150
+ segments: Array<PathSegment>,
151
+ isSegmentVisited: Array<Visitation>,
152
+ currentSegmentIndex: number,
153
+ epsilon: number
154
+ ): GenericPath => {
155
+ var currentSegment: PathSegment | null = segments[currentSegmentIndex];
156
+ isSegmentVisited[currentSegmentIndex].visited = true;
157
+ const path = new GenericPath(currentSegment); // { segments: [currentSegment], reverse };
158
+
159
+ var i: number = 0;
160
+ // A safety break if something goes wrong
161
+ while (i < segments.length && currentSegment) {
162
+ currentSegment = getAdjacentSegment(segments, isSegmentVisited, currentSegment, epsilon);
163
+ if (currentSegment) {
164
+ path.segments.push(currentSegment);
165
+ }
166
+ i++;
167
+ }
168
+ return path;
169
+ };
170
+
171
+ /**
172
+ * Run a path detection on the given set of path segments.
173
+ *
174
+ * Note that the array and some path segments may be altered (like reversal) IN PLACE.
175
+ *
176
+ * @param {Array<PathSegment>} segments - The total set (array) of available path segments.
177
+ * @param {number=1.0} epsilon - (optional) An epsilon to use to tell if two plane points should be considered 'equal'.
178
+ * @returns {Array<GenericPath>} An array containing all detected path (consisting of adjacent path segments of the original set).
179
+ */
180
+ export const detectPaths = (segments: Array<PathSegment>, epsilon?: number): Array<GenericPath> => {
181
+ const eps = typeof epsilon === "undefined" || epsilon < 0 ? 1.0 : epsilon;
182
+ const isSegmentVisited: Array<Visitation> = initVisitationArray(segments, eps);
183
+ const resultPaths: Array<GenericPath> = [];
184
+ var nextSegmentIndex: number = -1;
185
+ var i = 0;
186
+ while ((nextSegmentIndex = locateUnvisitedSegment(segments, isSegmentVisited)) !== -1 && i < segments.length) {
187
+ isSegmentVisited[nextSegmentIndex].visited = true;
188
+ // A safety break (to avoid infinited loops during development).
189
+ i++;
190
+ const path = detectAdjacentPath(segments, isSegmentVisited, nextSegmentIndex, eps);
191
+ i += path.getSegmentCount() - 1;
192
+ resultPaths.push(path);
193
+ }
194
+ return resultPaths;
195
+ };
@@ -532,9 +532,13 @@ export class Color {
532
532
  * @param {string} str - The string representation to parse.
533
533
  * @return {Color} The color instance that's represented by the given string.
534
534
  */
535
- static parse(str: string): Color {
536
- if (typeof str == "undefined") return null;
537
- if ((str = str.trim().toLowerCase()).length == 0) return null;
535
+ static parse(str: string): Color | null {
536
+ if (typeof str == "undefined") {
537
+ return null;
538
+ }
539
+ if ((str = str.trim().toLowerCase()).length == 0) {
540
+ return null;
541
+ }
538
542
  if (str.startsWith("#")) return Color.makeHEX(str.substring(1, str.length));
539
543
  if (str.startsWith("rgb")) {
540
544
  var parts = str.match(/^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,?\s*(\d*(?:\.\d+\s*)?)\)$/);
@@ -555,7 +559,7 @@ export class Color {
555
559
 
556
560
  private static Sanitizer = {
557
561
  RGB: function (...args: any[]) {
558
- var o = [];
562
+ var o: number[] = [];
559
563
  if (arguments.length == 0) {
560
564
  return [];
561
565
  }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * @author Ikaros Kappler
3
+ * @version 1.0.0
4
+ * @date 2022-10-17
5
+ */
6
+
7
+ import { Path, PathSegment } from "../../interfaces/additionals";
8
+ import { Vertex } from "../../Vertex";
9
+
10
+ export class GenericPath implements Path {
11
+ segments: Array<PathSegment>;
12
+
13
+ constructor(startSegment: PathSegment) {
14
+ this.segments = [startSegment];
15
+ }
16
+
17
+ /**
18
+ * Get the number of segments in this path.
19
+ *
20
+ * @method getSegmentCount
21
+ * @memberof Path
22
+ * @return {number} The number (integer) of path segments.
23
+ */
24
+ getSegmentCount(): number {
25
+ return this.segments.length;
26
+ }
27
+
28
+ /**
29
+ * Get the path segment at the given index.
30
+ *
31
+ * @method getSegmentAt
32
+ * @memberof Path
33
+ * @return {PathSegment} The paths segment at the given index.
34
+ */
35
+ getSegmentAt(index: number): PathSegment {
36
+ return this.segments[index];
37
+ }
38
+
39
+ /**
40
+ * Create a deep clone of this path.
41
+ *
42
+ * @method clone
43
+ * @memberof Path
44
+ * @return {Path} A deep clone/copy of this path.
45
+ */
46
+ clone(): GenericPath {
47
+ const newPath = new GenericPath(this.segments[this.segments.length - 1].clone().reverse());
48
+ for (var i = this.segments.length - 2; i >= 0; i--) {
49
+ newPath.segments.push(this.segments[i].clone().reverse());
50
+ }
51
+ return newPath;
52
+ }
53
+
54
+ /**
55
+ * Reverse this path (swap start and end and thus – the direction) in-place.
56
+ *
57
+ * @method reverse
58
+ * @memberof Path
59
+ * @return {PathSegment} This path instance.
60
+ */
61
+ reverse() {
62
+ const newSegments: Array<PathSegment> = [];
63
+ for (var i = this.segments.length - 1; i >= 0; i--) {
64
+ newSegments.push(this.segments[i].reverse());
65
+ }
66
+ this.segments = newSegments;
67
+ return this;
68
+ }
69
+
70
+ /**
71
+ * Get the start point of this path segment.
72
+ *
73
+ * @method getStartPoint
74
+ * @memberof PathSegment
75
+ * @return {Vertex} The start point of this path segment.
76
+ */
77
+ getStartPoint(): Vertex {
78
+ return this.segments[0].getStartPoint();
79
+ }
80
+
81
+ /**
82
+ * Get the end point of this path segment.
83
+ *
84
+ * @method getEndPoint
85
+ * @memberof PathSegment
86
+ * @return {Vertex} The end point of this path segment.
87
+ */
88
+ getEndPoint(): Vertex {
89
+ return this.segments[this.segments.length - 1].getEndPoint();
90
+ }
91
+
92
+ /**
93
+ * Get the tangent's end point at the start point of this segment.
94
+ *
95
+ * @method getStartTangent
96
+ * @memberof PathSegment
97
+ * @return {Vertex} The end point of the starting point's tangent.
98
+ */
99
+ getStartTangent(): Vertex {
100
+ return this.segments[0].getStartTangent();
101
+ }
102
+
103
+ /**
104
+ * Get the tangent's end point at the end point of this segment.
105
+ *
106
+ * @method getEndTangent
107
+ * @memberof PathSegment
108
+ * @return {Vertex} The end point of the ending point's tangent.
109
+ */
110
+ getEndTangent(): Vertex {
111
+ return this.segments[this.segments.length - 1].getEndTangent();
112
+ }
113
+ }
@@ -319,7 +319,7 @@ export abstract class GirihTile extends Polygon {
319
319
  * @param {Polygon} neighbourTile - The polygon (or tile) you want to find adjacency for at the specified edge.
320
320
  * @return {Polygon|null} the passed tile itself if adjacency was found, null otherwise.
321
321
  */
322
- transformTilePositionToAdjacency<P extends Polygon>(baseEdgeIndex: number, neighbourTile: P): P {
322
+ transformTilePositionToAdjacency<P extends Polygon>(baseEdgeIndex: number, neighbourTile: P): P | null {
323
323
  // Find the position for that tile to match (might not exist)
324
324
  // { edgeIndex:number, offset:XYCoords }
325
325
  var adjacency = this.findAdjacentTilePosition(baseEdgeIndex, neighbourTile);
@@ -13,11 +13,13 @@
13
13
  * @author Ikaros Kappler
14
14
  * @date 2021-10-13
15
15
  * @modified 2022-01-31 (ported from the ngdg project, then generalized)
16
- * @version 2.0.0
16
+ * @modified 2023-01-03 Fixing some minor type issues and adding SVG reading capabilities.
17
+ * @version 2.1.0
17
18
  */
18
19
 
19
20
  type IDroppedCallbackJSON = (jsonData: object) => void;
20
21
  type IDroppedCallbackText = (textData: string) => void;
22
+ type IDroppedCallbackSVG = (svgDocument: Document) => void;
21
23
  type IDroppedCallbackBinary = (binaryData: Blob, file: File) => void;
22
24
 
23
25
  export class FileDrop {
@@ -53,6 +55,14 @@ export class FileDrop {
53
55
  */
54
56
  private fileDroppedCallbackBinary: IDroppedCallbackBinary | null;
55
57
 
58
+ /**
59
+ * The SVG file drop callback.
60
+ * @private
61
+ * @memberof FileDrop
62
+ * @member {HTMLElement}
63
+ */
64
+ private fileDroppedCallbackSVG: IDroppedCallbackSVG | null;
65
+
56
66
  /**
57
67
  *
58
68
  * @param {HTMLElement} element - The element you wish to operate as the drop zone (like <body/>).
@@ -92,6 +102,10 @@ export class FileDrop {
92
102
  this.fileDroppedCallbackText = callback;
93
103
  }
94
104
 
105
+ onFileSVGDropped(callback: IDroppedCallbackSVG) {
106
+ this.fileDroppedCallbackSVG = callback;
107
+ }
108
+
95
109
  /**
96
110
  * Internally handle a drop event.
97
111
  *
@@ -103,7 +117,7 @@ export class FileDrop {
103
117
  event.stopPropagation();
104
118
  this.element.style.opacity = "1.0";
105
119
 
106
- if (!event.dataTransfer.files || event.dataTransfer.files.length === 0) {
120
+ if (!event.dataTransfer || !event.dataTransfer.files || event.dataTransfer.files.length === 0) {
107
121
  // No files were dropped
108
122
  return;
109
123
  }
@@ -111,36 +125,63 @@ export class FileDrop {
111
125
  // Multiple file drop is not nupported
112
126
  return;
113
127
  }
114
- if (!this.fileDroppedCallbackJSON) {
115
- // No handling callback defined.
116
- return;
117
- }
128
+ // if (!this.fileDroppedCallbackJSON) {
129
+ // // No handling callback defined.
130
+ // return;
131
+ // }
118
132
  if (event.dataTransfer.files[0]) {
119
133
  const file: File = event.dataTransfer.files[0];
120
134
  // console.log("file", file);
121
- if (file.type.match(/json.*/) && this.fileDroppedCallbackJSON) {
135
+ if (file.type.match(/json.*/) && this.fileDroppedCallbackJSON !== null) {
122
136
  var reader = new FileReader();
123
137
  reader.onload = (readEvent: ProgressEvent<FileReader>) => {
138
+ if (!readEvent.target) {
139
+ console.warn("Cannot process JSON ProgressEvent data: target is null.");
140
+ return;
141
+ }
124
142
  // Finished reading file data.
125
143
  const jsonObject: object = JSON.parse(readEvent.target.result as string);
126
144
  // TODO: what happens on fail?
127
- this.fileDroppedCallbackJSON(jsonObject);
145
+ this.fileDroppedCallbackJSON && this.fileDroppedCallbackJSON(jsonObject);
128
146
  };
129
147
  reader.readAsText(file); // start reading the file data.
130
148
  } else if (file.type.match(/text\/plain.*/) && this.fileDroppedCallbackText) {
131
149
  var reader = new FileReader();
132
150
  reader.onload = (readEvent: ProgressEvent<FileReader>) => {
151
+ if (!readEvent.target) {
152
+ console.warn("Cannot process Text ProgressEvent data: target is null.");
153
+ return;
154
+ }
133
155
  // Finished reading file data.
134
- this.fileDroppedCallbackText(readEvent.target.result as string);
156
+ this.fileDroppedCallbackText && this.fileDroppedCallbackText(readEvent.target.result as string);
135
157
  };
136
158
  reader.readAsText(file); // start reading the file data.
137
159
  } else if (this.fileDroppedCallbackBinary) {
138
160
  var reader = new FileReader();
139
161
  reader.onload = (readEvent: ProgressEvent<FileReader>) => {
162
+ if (!readEvent.target) {
163
+ console.warn("Cannot process Binary ProgressEvent data: target is null.");
164
+ return;
165
+ }
140
166
  // Finished reading file data.
141
- this.fileDroppedCallbackBinary(new Blob([readEvent.target.result]), file);
167
+ this.fileDroppedCallbackBinary &&
168
+ this.fileDroppedCallbackBinary(new Blob([readEvent.target.result as ArrayBuffer]), file);
142
169
  };
143
170
  reader.readAsBinaryString(file); // start reading the file data.
171
+ } else if (this.fileDroppedCallbackSVG) {
172
+ var reader = new FileReader();
173
+ reader.onload = (readEvent: ProgressEvent<FileReader>) => {
174
+ if (!readEvent.target) {
175
+ console.warn("Cannot process SVG ProgressEvent data: target is null.");
176
+ return;
177
+ }
178
+ const parser = new DOMParser();
179
+ const doc = parser.parseFromString(readEvent.target.result as string, "image/svg+xml");
180
+
181
+ // Finished reading file data.
182
+ this.fileDroppedCallbackSVG && this.fileDroppedCallbackSVG(doc);
183
+ };
184
+ reader.readAsText(file); // start reading the file data.
144
185
  }
145
186
  }
146
187
  };