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.
- package/README.md +1 -1
- package/dist/index.esm.js +244 -63
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +1 -1
- package/dist/index.esm.min.js.map +1 -1
- package/dist/plotboilerplate.browser.min.js +1 -1
- package/dist/plotboilerplate.browser.min.js.map +1 -1
- package/dist/plotboilerplate.js +243 -74
- package/dist/plotboilerplate.min.js +1 -1
- package/package.json +1 -1
- package/src/cjs/Bounds.d.ts +14 -5
- package/src/cjs/Bounds.js +18 -8
- package/src/cjs/Bounds.js.map +1 -1
- package/src/cjs/CubicBezierCurve.d.ts +20 -3
- package/src/cjs/CubicBezierCurve.js +25 -2
- package/src/cjs/CubicBezierCurve.js.map +1 -1
- package/src/cjs/Line.d.ts +46 -4
- package/src/cjs/Line.js +60 -3
- package/src/cjs/Line.js.map +1 -1
- package/src/cjs/PlotBoilerplate.d.ts +5 -2
- package/src/cjs/PlotBoilerplate.js +52 -30
- package/src/cjs/PlotBoilerplate.js.map +1 -1
- package/src/cjs/Polygon.js +1 -1
- package/src/cjs/Polygon.js.map +1 -1
- package/src/cjs/VEllipseSector.d.ts +4 -3
- package/src/cjs/VEllipseSector.js +15 -8
- package/src/cjs/VEllipseSector.js.map +1 -1
- package/src/cjs/Vector.d.ts +14 -3
- package/src/cjs/Vector.js +21 -2
- package/src/cjs/Vector.js.map +1 -1
- package/src/cjs/Vertex.d.ts +33 -1
- package/src/cjs/Vertex.js +43 -1
- package/src/cjs/Vertex.js.map +1 -1
- package/src/cjs/drawutilssvg.d.ts +2 -1
- package/src/cjs/drawutilssvg.js +7 -19
- package/src/cjs/drawutilssvg.js.map +1 -1
- package/src/cjs/entry.js +1 -0
- package/src/cjs/interfaces/additionals.d.ts +95 -0
- package/src/cjs/interfaces/additionals.js +3 -0
- package/src/cjs/interfaces/additionals.js.map +1 -0
- package/src/cjs/interfaces/core.d.ts +7 -0
- package/src/cjs/interfaces/core.js +2 -0
- package/src/cjs/interfaces/core.js.map +1 -1
- package/src/cjs/interfaces/index.d.ts +1 -0
- package/src/cjs/interfaces/index.js +1 -0
- package/src/cjs/interfaces/index.js.map +1 -1
- package/src/cjs/utils/algorithms/arrayShuffle.d.ts +8 -0
- package/src/cjs/utils/algorithms/arrayShuffle.js +15 -0
- package/src/cjs/utils/algorithms/arrayShuffle.js.map +1 -0
- package/src/cjs/utils/algorithms/detectPaths.d.ts +21 -0
- package/src/cjs/utils/algorithms/detectPaths.js +169 -0
- package/src/cjs/utils/algorithms/detectPaths.js.map +1 -0
- package/src/cjs/utils/creategui.js +7 -0
- package/src/cjs/utils/datastructures/Color.d.ts +1 -1
- package/src/cjs/utils/datastructures/Color.js +4 -2
- package/src/cjs/utils/datastructures/Color.js.map +1 -1
- package/src/cjs/utils/datastructures/GenericPath.d.ts +75 -0
- package/src/cjs/utils/datastructures/GenericPath.js +105 -0
- package/src/cjs/utils/datastructures/GenericPath.js.map +1 -0
- package/src/cjs/utils/datastructures/GirihTile.d.ts +1 -1
- package/src/cjs/utils/io/FileDrop.d.ts +11 -1
- package/src/cjs/utils/io/FileDrop.js +41 -10
- package/src/cjs/utils/io/FileDrop.js.map +1 -1
- package/src/cjs/utils/parsers/svg/parseSVGPathData.d.ts +26 -0
- package/src/cjs/utils/parsers/svg/parseSVGPathData.js +463 -0
- package/src/cjs/utils/parsers/svg/parseSVGPathData.js.map +1 -0
- package/src/cjs/utils/parsers/svg/splitSVGPathData.d.ts +20 -0
- package/src/cjs/utils/parsers/svg/splitSVGPathData.js +49 -0
- package/src/cjs/utils/parsers/svg/splitSVGPathData.js.map +1 -0
- package/src/cjs/utils/parsers/svg/types.d.ts +43 -0
- package/src/cjs/utils/parsers/svg/types.js +16 -0
- package/src/cjs/utils/parsers/svg/types.js.map +1 -0
- package/src/esm/Bounds.d.ts +14 -5
- package/src/esm/Bounds.js +18 -8
- package/src/esm/Bounds.js.map +1 -1
- package/src/esm/CubicBezierCurve.d.ts +20 -3
- package/src/esm/CubicBezierCurve.js +25 -2
- package/src/esm/CubicBezierCurve.js.map +1 -1
- package/src/esm/Line.d.ts +46 -4
- package/src/esm/Line.js +60 -3
- package/src/esm/Line.js.map +1 -1
- package/src/esm/PlotBoilerplate.d.ts +5 -2
- package/src/esm/PlotBoilerplate.js +52 -30
- package/src/esm/PlotBoilerplate.js.map +1 -1
- package/src/esm/Polygon.js +1 -1
- package/src/esm/Polygon.js.map +1 -1
- package/src/esm/VEllipseSector.d.ts +4 -3
- package/src/esm/VEllipseSector.js +15 -8
- package/src/esm/VEllipseSector.js.map +1 -1
- package/src/esm/Vector.d.ts +13 -2
- package/src/esm/Vector.js +23 -4
- package/src/esm/Vector.js.map +1 -1
- package/src/esm/Vertex.d.ts +33 -1
- package/src/esm/Vertex.js +43 -1
- package/src/esm/Vertex.js.map +1 -1
- package/src/esm/drawutilssvg.d.ts +2 -1
- package/src/esm/drawutilssvg.js +7 -19
- package/src/esm/drawutilssvg.js.map +1 -1
- package/src/esm/entry.js +1 -0
- package/src/esm/interfaces/additionals.d.ts +95 -0
- package/src/esm/interfaces/additionals.js +2 -0
- package/src/esm/interfaces/additionals.js.map +1 -0
- package/src/esm/interfaces/core.d.ts +7 -0
- package/src/esm/interfaces/core.js +2 -0
- package/src/esm/interfaces/core.js.map +1 -1
- package/src/esm/interfaces/index.d.ts +1 -0
- package/src/esm/interfaces/index.js +1 -0
- package/src/esm/interfaces/index.js.map +1 -1
- package/src/esm/utils/algorithms/arrayShuffle.d.ts +8 -0
- package/src/esm/utils/algorithms/arrayShuffle.js +11 -0
- package/src/esm/utils/algorithms/arrayShuffle.js.map +1 -0
- package/src/esm/utils/algorithms/detectPaths.d.ts +21 -0
- package/src/esm/utils/algorithms/detectPaths.js +165 -0
- package/src/esm/utils/algorithms/detectPaths.js.map +1 -0
- package/src/esm/utils/datastructures/Color.d.ts +1 -1
- package/src/esm/utils/datastructures/Color.js +4 -2
- package/src/esm/utils/datastructures/Color.js.map +1 -1
- package/src/esm/utils/datastructures/GenericPath.d.ts +75 -0
- package/src/esm/utils/datastructures/GenericPath.js +100 -0
- package/src/esm/utils/datastructures/GenericPath.js.map +1 -0
- package/src/esm/utils/datastructures/GirihTile.d.ts +1 -1
- package/src/esm/utils/io/FileDrop.d.ts +11 -1
- package/src/esm/utils/io/FileDrop.js +41 -10
- package/src/esm/utils/io/FileDrop.js.map +1 -1
- package/src/esm/utils/parsers/svg/parseSVGPathData.d.ts +26 -0
- package/src/esm/utils/parsers/svg/parseSVGPathData.js +459 -0
- package/src/esm/utils/parsers/svg/parseSVGPathData.js.map +1 -0
- package/src/esm/utils/parsers/svg/splitSVGPathData.d.ts +20 -0
- package/src/esm/utils/parsers/svg/splitSVGPathData.js +45 -0
- package/src/esm/utils/parsers/svg/splitSVGPathData.js.map +1 -0
- package/src/esm/utils/parsers/svg/types.d.ts +43 -0
- package/src/esm/utils/parsers/svg/types.js +15 -0
- package/src/esm/utils/parsers/svg/types.js.map +1 -0
- package/src/ts/Bounds.ts +19 -8
- package/src/ts/CubicBezierCurve.ts +29 -4
- package/src/ts/Line.ts +70 -6
- package/src/ts/PlotBoilerplate.ts +57 -35
- package/src/ts/Polygon.ts +1 -1
- package/src/ts/VEllipseSector.ts +22 -15
- package/src/ts/Vector.ts +24 -4
- package/src/ts/Vertex.ts +46 -1
- package/src/ts/drawutilssvg.ts +8 -19
- package/src/ts/interfaces/additionals.ts +105 -0
- package/src/ts/interfaces/core.ts +5 -0
- package/src/ts/interfaces/index.ts +1 -0
- package/src/ts/utils/algorithms/arrayShuffle.ts +11 -0
- package/src/ts/utils/algorithms/detectPaths.ts +195 -0
- package/src/ts/utils/datastructures/Color.ts +8 -4
- package/src/ts/utils/datastructures/GenericPath.ts +113 -0
- package/src/ts/utils/datastructures/GirihTile.ts +1 -1
- package/src/ts/utils/io/FileDrop.ts +51 -10
- package/src/ts/utils/parsers/svg/parseSVGPathData.ts +572 -0
- package/src/ts/utils/parsers/svg/splitSVGPathData.ts +50 -0
- package/src/ts/utils/parsers/svg/types.ts +70 -0
- package/changelog.md +0 -731
package/src/ts/drawutilssvg.ts
CHANGED
|
@@ -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
|
-
* @
|
|
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}` :
|
|
1326
|
-
textNode.setAttribute("font-style", options.fontStyle ? `${options.fontStyle}` :
|
|
1327
|
-
textNode.setAttribute("font-weight", options.fontWeight ? `${options.fontWeight}` :
|
|
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
|
-
|
|
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
|
|
@@ -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")
|
|
537
|
-
|
|
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
|
-
* @
|
|
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
|
-
|
|
116
|
-
|
|
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
|
|
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
|
};
|