plotboilerplate 1.20.2 → 1.21.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/dist/index.esm.js +1985 -1368
- 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 +1170 -541
- package/dist/plotboilerplate.min.js +1 -1
- package/package.json +1 -1
- package/src/cjs/BezierPath.d.ts +27 -49
- package/src/cjs/BezierPath.js +67 -234
- package/src/cjs/BezierPath.js.map +1 -1
- package/src/cjs/Bounds.d.ts +14 -1
- package/src/cjs/Bounds.js +21 -1
- package/src/cjs/Bounds.js.map +1 -1
- package/src/cjs/CubicBezierCurve.d.ts +70 -1
- package/src/cjs/CubicBezierCurve.js +130 -12
- package/src/cjs/CubicBezierCurve.js.map +1 -1
- package/src/cjs/Line.d.ts +2 -1
- package/src/cjs/Line.js +1 -0
- package/src/cjs/Line.js.map +1 -1
- package/src/cjs/PBText.d.ts +2 -1
- package/src/cjs/PBText.js +10 -9
- package/src/cjs/PBText.js.map +1 -1
- package/src/cjs/PlotBoilerplate.d.ts +4 -13
- package/src/cjs/PlotBoilerplate.js +61 -15
- package/src/cjs/PlotBoilerplate.js.map +1 -1
- package/src/cjs/Polygon.d.ts +35 -1
- package/src/cjs/Polygon.js +87 -1
- package/src/cjs/Polygon.js.map +1 -1
- package/src/cjs/VEllipse.js +1 -1
- package/src/cjs/VEllipse.js.map +1 -1
- package/src/cjs/Vector.d.ts +4 -4
- package/src/cjs/Vector.js +2 -2
- package/src/cjs/Vector.js.map +1 -1
- package/src/cjs/VertTuple.d.ts +2 -1
- package/src/cjs/VertTuple.js +4 -3
- package/src/cjs/VertTuple.js.map +1 -1
- package/src/cjs/Vertex.d.ts +14 -3
- package/src/cjs/Vertex.js +18 -3
- package/src/cjs/Vertex.js.map +1 -1
- package/src/cjs/draw.d.ts +154 -75
- package/src/cjs/draw.js +308 -137
- package/src/cjs/draw.js.map +1 -1
- package/src/cjs/drawgl.d.ts +87 -50
- package/src/cjs/drawgl.js +86 -31
- package/src/cjs/drawgl.js.map +1 -1
- package/src/cjs/drawutilssvg.d.ts +226 -53
- package/src/cjs/drawutilssvg.js +374 -92
- package/src/cjs/drawutilssvg.js.map +1 -1
- package/src/cjs/interfaces/DrawLib.d.ts +157 -79
- package/src/cjs/interfaces/DrawLib.js +6 -0
- package/src/cjs/interfaces/DrawLib.js.map +1 -1
- package/src/cjs/interfaces/core.d.ts +13 -2
- package/src/cjs/interfaces/core.js +1 -0
- package/src/cjs/interfaces/core.js.map +1 -1
- package/src/cjs/utils/creategui.js +16 -10
- package/src/cjs/utils/detectDarkMode.d.ts +10 -0
- package/src/cjs/utils/detectDarkMode.js +32 -0
- package/src/cjs/utils/detectDarkMode.js.map +1 -0
- package/src/esm/BezierPath.d.ts +27 -49
- package/src/esm/BezierPath.js +67 -234
- package/src/esm/BezierPath.js.map +1 -1
- package/src/esm/Bounds.d.ts +14 -1
- package/src/esm/Bounds.js +19 -1
- package/src/esm/Bounds.js.map +1 -1
- package/src/esm/CubicBezierCurve.d.ts +70 -1
- package/src/esm/CubicBezierCurve.js +130 -12
- package/src/esm/CubicBezierCurve.js.map +1 -1
- package/src/esm/Line.d.ts +2 -1
- package/src/esm/Line.js +1 -0
- package/src/esm/Line.js.map +1 -1
- package/src/esm/PBText.d.ts +2 -1
- package/src/esm/PBText.js +10 -9
- package/src/esm/PBText.js.map +1 -1
- package/src/esm/PlotBoilerplate.d.ts +4 -13
- package/src/esm/PlotBoilerplate.js +62 -16
- package/src/esm/PlotBoilerplate.js.map +1 -1
- package/src/esm/Polygon.d.ts +35 -1
- package/src/esm/Polygon.js +85 -1
- package/src/esm/Polygon.js.map +1 -1
- package/src/esm/VEllipse.js +1 -1
- package/src/esm/VEllipse.js.map +1 -1
- package/src/esm/Vector.d.ts +4 -4
- package/src/esm/Vector.js +2 -2
- package/src/esm/Vector.js.map +1 -1
- package/src/esm/VertTuple.d.ts +2 -1
- package/src/esm/VertTuple.js +4 -3
- package/src/esm/VertTuple.js.map +1 -1
- package/src/esm/Vertex.d.ts +14 -3
- package/src/esm/Vertex.js +18 -3
- package/src/esm/Vertex.js.map +1 -1
- package/src/esm/draw.d.ts +154 -75
- package/src/esm/draw.js +304 -135
- package/src/esm/draw.js.map +1 -1
- package/src/esm/drawgl.d.ts +87 -50
- package/src/esm/drawgl.js +86 -31
- package/src/esm/drawgl.js.map +1 -1
- package/src/esm/drawutilssvg.d.ts +226 -53
- package/src/esm/drawutilssvg.js +369 -92
- package/src/esm/drawutilssvg.js.map +1 -1
- package/src/esm/interfaces/DrawLib.d.ts +157 -79
- package/src/esm/interfaces/DrawLib.js +6 -0
- package/src/esm/interfaces/DrawLib.js.map +1 -1
- package/src/esm/interfaces/core.d.ts +13 -2
- package/src/esm/interfaces/core.js +1 -0
- package/src/esm/interfaces/core.js.map +1 -1
- package/src/esm/utils/detectDarkMode.d.ts +10 -0
- package/src/esm/utils/detectDarkMode.js +28 -0
- package/src/esm/utils/detectDarkMode.js.map +1 -0
- package/src/ts/BezierPath.ts +72 -241
- package/src/ts/Bounds.ts +25 -1
- package/src/ts/CubicBezierCurve.ts +139 -12
- package/src/ts/Line.ts +2 -1
- package/src/ts/PBText.ts +10 -9
- package/src/ts/PlotBoilerplate.ts +56 -19
- package/src/ts/Polygon.ts +91 -1
- package/src/ts/VEllipse.ts +2 -2
- package/src/ts/Vector.ts +4 -4
- package/src/ts/VertTuple.ts +4 -3
- package/src/ts/Vertex.ts +20 -4
- package/src/ts/draw.ts +311 -115
- package/src/ts/drawgl.ts +133 -71
- package/src/ts/drawutilssvg.ts +543 -121
- package/src/ts/interfaces/DrawLib.ts +219 -83
- package/src/ts/interfaces/core.ts +14 -2
- package/src/ts/utils/detectDarkMode.ts +30 -0
package/dist/index.esm.js
CHANGED
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @classdesc A static UIDGenerator.
|
|
3
|
-
*
|
|
4
|
-
* @author Ikaros Kappler
|
|
5
|
-
* @date 2021-01-20
|
|
6
|
-
* @version 1.0.0
|
|
7
|
-
*/
|
|
8
|
-
class UIDGenerator {
|
|
9
|
-
static next() {
|
|
10
|
-
return `${UIDGenerator.current++}`;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
UIDGenerator.current = 0;
|
|
14
|
-
|
|
15
1
|
/**
|
|
16
2
|
* @author Ikaros Kappler
|
|
17
3
|
* @date 2018-08-26
|
|
@@ -65,6 +51,20 @@ VertexAttr.model = {
|
|
|
65
51
|
visible: true
|
|
66
52
|
};
|
|
67
53
|
|
|
54
|
+
/**
|
|
55
|
+
* @classdesc A static UIDGenerator.
|
|
56
|
+
*
|
|
57
|
+
* @author Ikaros Kappler
|
|
58
|
+
* @date 2021-01-20
|
|
59
|
+
* @version 1.0.0
|
|
60
|
+
*/
|
|
61
|
+
class UIDGenerator {
|
|
62
|
+
static next() {
|
|
63
|
+
return `${UIDGenerator.current++}`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
UIDGenerator.current = 0;
|
|
67
|
+
|
|
68
68
|
/**
|
|
69
69
|
* @author Ikaros Kappler
|
|
70
70
|
* @date 2018-08-27
|
|
@@ -358,6 +358,8 @@ class VertexListeners {
|
|
|
358
358
|
* @modified 2022-02-02 Added the `destroy` method.
|
|
359
359
|
* @modified 2022-02-02 Cleared the `Vertex.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
360
360
|
* @modified 2022-11-28 Added the `subXY`, `subX` and `subY` methods to the `Vertex` class.
|
|
361
|
+
* @modified 2023-09-29 Downgraded types for the `Vertex.utils.buildArrowHead` function (replacing Vertex params by more generic XYCoords type).
|
|
362
|
+
* @modified 2023-09-29 Added the `Vertex.abs()` method as it seems useful.
|
|
361
363
|
* @version 2.8.0
|
|
362
364
|
*
|
|
363
365
|
* @file Vertex
|
|
@@ -874,6 +876,19 @@ class Vertex {
|
|
|
874
876
|
this.y = -this.y;
|
|
875
877
|
return this;
|
|
876
878
|
}
|
|
879
|
+
/**
|
|
880
|
+
* Set both coordinates of this vertex to their absolute value (abs(x), abs(y)).
|
|
881
|
+
*
|
|
882
|
+
* @method abs
|
|
883
|
+
* @return {Vertex} this
|
|
884
|
+
* @instance
|
|
885
|
+
* @memberof Vertex
|
|
886
|
+
*/
|
|
887
|
+
abs() {
|
|
888
|
+
this.x = Math.abs(this.x);
|
|
889
|
+
this.y = Math.abs(this.y);
|
|
890
|
+
return this;
|
|
891
|
+
}
|
|
877
892
|
/**
|
|
878
893
|
* Get a string representation of this vertex.
|
|
879
894
|
*
|
|
@@ -932,15 +947,15 @@ Vertex.utils = {
|
|
|
932
947
|
* Example:
|
|
933
948
|
* buildArrowHead( new Vertex(0,0), new Vertex(50,100), 8, 1.0, 1.0 )
|
|
934
949
|
*
|
|
935
|
-
* @param {
|
|
936
|
-
* @param {
|
|
950
|
+
* @param {XYCoords} zA - The start vertex of the vector to calculate the arrow head for.
|
|
951
|
+
* @param {XYCoords} zB - The end vertex of the vector.
|
|
937
952
|
* @param {number} headlen - The length of the arrow head (along the vector direction. A good value is 12).
|
|
938
953
|
* @param {number} scaleX - The horizontal scaling during draw.
|
|
939
954
|
* @param {number} scaleY - the vertical scaling during draw.
|
|
940
955
|
**/
|
|
941
956
|
// @DEPRECATED: use Vector.utils.buildArrowHead instead!!!
|
|
942
957
|
buildArrowHead: (zA, zB, headlen, scaleX, scaleY) => {
|
|
943
|
-
|
|
958
|
+
console.warn("[DEPRECATION] Vertex.utils.buildArrowHead is deprecated. Please use Vector.utils.buildArrowHead instead.");
|
|
944
959
|
var angle = Math.atan2((zB.y - zA.y) * scaleY, (zB.x - zA.x) * scaleX);
|
|
945
960
|
var vertices = [];
|
|
946
961
|
vertices.push(new Vertex(zB.x * scaleX - headlen * Math.cos(angle), zB.y * scaleY - headlen * Math.sin(angle)));
|
|
@@ -965,433 +980,287 @@ Vertex.utils = {
|
|
|
965
980
|
};
|
|
966
981
|
|
|
967
982
|
/**
|
|
968
|
-
* @author
|
|
969
|
-
* @date
|
|
970
|
-
* @modified
|
|
971
|
-
* @modified
|
|
972
|
-
* @modified
|
|
973
|
-
* @modified
|
|
974
|
-
* @modified
|
|
975
|
-
* @modified
|
|
976
|
-
* @modified 2019-11-22 Added the rotate(number,Vertex) function.
|
|
977
|
-
* @modified 2020-03-24 Ported this class from vanilla-JS to Typescript.
|
|
978
|
-
* @modified 2020-10-30 Added the `addVertex` function.
|
|
979
|
-
* @modified 2020-10-31 Added the `getVertexAt` function.
|
|
980
|
-
* @modified 2020-11-06 Added the `move` function.
|
|
981
|
-
* @modified 2020-11-10 Added the `getBounds` function.
|
|
982
|
-
* @modified 2020-11-11 Generalized `move(Vertex)` to `move(XYCoords)`.
|
|
983
|
+
* @author Ikaros Kappler
|
|
984
|
+
* @date 2020-03-24
|
|
985
|
+
* @modified 2020-05-04 Fixed a serious bug in the pointDistance function.
|
|
986
|
+
* @modified 2020-05-12 The angle(line) param was still not optional. Changed that.
|
|
987
|
+
* @modified 2020-11-11 Generalized the `add` and `sub` param from `Vertex` to `XYCoords`.
|
|
988
|
+
* @modified 2020-12-04 Changed`vtutils.dist2` params from `Vertex` to `XYCoords` (generalized).
|
|
989
|
+
* @modified 2020-12-04 Changed `getClosestT` param from `Vertex` to `XYCoords` (generalized).
|
|
990
|
+
* @modified 2020-12-04 Added the `hasPoint(XYCoords)` function.
|
|
983
991
|
* @modified 2021-01-20 Added UID.
|
|
984
|
-
* @modified 2021-01-29 Added the `signedArea` function (was global function in the demos before).
|
|
985
|
-
* @modified 2021-01-29 Added the `isClockwise` function.
|
|
986
|
-
* @modified 2021-01-29 Added the `area` function.
|
|
987
|
-
* @modified 2021-01-29 Changed the param type for `containsVert` from Vertex to XYCoords.
|
|
988
|
-
* @modified 2021-12-14 Added the `perimeter()` function.
|
|
989
|
-
* @modified 2021-12-16 Added the `getEvenDistributionPolygon()` function.
|
|
990
992
|
* @modified 2022-02-02 Added the `destroy` method.
|
|
991
|
-
* @modified
|
|
992
|
-
* @
|
|
993
|
-
|
|
994
|
-
*
|
|
995
|
-
* @file Polygon
|
|
996
|
-
* @public
|
|
997
|
-
**/
|
|
993
|
+
* @modified 2023-09-29 Fixed a calculation error in the VertTuple.hasPoint() function; distance measure was broken!
|
|
994
|
+
* @version 1.2.1
|
|
995
|
+
*/
|
|
998
996
|
/**
|
|
999
|
-
* @classdesc
|
|
1000
|
-
*
|
|
1001
|
-
* @requires BezierPath
|
|
1002
|
-
* @requires Bounds
|
|
1003
|
-
* @requires SVGSerializabe
|
|
997
|
+
* @classdesc An abstract base classes for vertex tuple constructs, like Lines or Vectors.
|
|
998
|
+
* @abstract
|
|
1004
999
|
* @requires UID
|
|
1005
|
-
* @requires UIDGenerator
|
|
1006
1000
|
* @requires Vertex
|
|
1007
1001
|
* @requires XYCoords
|
|
1008
1002
|
*/
|
|
1009
|
-
class
|
|
1003
|
+
class VertTuple {
|
|
1010
1004
|
/**
|
|
1011
|
-
*
|
|
1005
|
+
* Creates an instance.
|
|
1012
1006
|
*
|
|
1013
1007
|
* @constructor
|
|
1014
|
-
* @name
|
|
1015
|
-
* @param {Vertex
|
|
1016
|
-
* @param {
|
|
1008
|
+
* @name VertTuple
|
|
1009
|
+
* @param {Vertex} a The tuple's first point.
|
|
1010
|
+
* @param {Vertex} b The tuple's second point.
|
|
1017
1011
|
**/
|
|
1018
|
-
constructor(
|
|
1019
|
-
/**
|
|
1020
|
-
* Required to generate proper CSS classes and other class related IDs.
|
|
1021
|
-
**/
|
|
1022
|
-
this.className = "Polygon";
|
|
1012
|
+
constructor(a, b, factory) {
|
|
1023
1013
|
this.uid = UIDGenerator.next();
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
this.
|
|
1027
|
-
this.isOpen = isOpen || false;
|
|
1014
|
+
this.a = a;
|
|
1015
|
+
this.b = b;
|
|
1016
|
+
this.factory = factory;
|
|
1028
1017
|
}
|
|
1029
1018
|
/**
|
|
1030
|
-
*
|
|
1019
|
+
* Get the length of this line.
|
|
1031
1020
|
*
|
|
1032
|
-
* @method
|
|
1033
|
-
* @param {Vertex} vert - The vertex to add.
|
|
1021
|
+
* @method length
|
|
1034
1022
|
* @instance
|
|
1035
|
-
* @memberof
|
|
1023
|
+
* @memberof VertTuple
|
|
1036
1024
|
**/
|
|
1037
|
-
|
|
1038
|
-
this.
|
|
1025
|
+
length() {
|
|
1026
|
+
return Math.sqrt(Math.pow(this.b.x - this.a.x, 2) + Math.pow(this.b.y - this.a.y, 2));
|
|
1039
1027
|
}
|
|
1040
1028
|
/**
|
|
1041
|
-
*
|
|
1042
|
-
*
|
|
1043
|
-
* The index may exceed the total vertex count, and will be wrapped around then (modulo).
|
|
1044
|
-
*
|
|
1045
|
-
* For k >= 0:
|
|
1046
|
-
* - getVertexAt( vertices.length ) == getVertexAt( 0 )
|
|
1047
|
-
* - getVertexAt( vertices.length + k ) == getVertexAt( k )
|
|
1048
|
-
* - getVertexAt( -k ) == getVertexAt( vertices.length -k )
|
|
1029
|
+
* Set the length of this vector to the given amount. This only works if this
|
|
1030
|
+
* vector is not a null vector.
|
|
1049
1031
|
*
|
|
1050
|
-
* @
|
|
1051
|
-
* @param {number}
|
|
1052
|
-
* @
|
|
1053
|
-
* @
|
|
1054
|
-
* @return {Vertex} At the given index.
|
|
1032
|
+
* @method setLength
|
|
1033
|
+
* @param {number} length - The desired length.
|
|
1034
|
+
* @memberof VertTuple
|
|
1035
|
+
* @return {T} this (for chaining)
|
|
1055
1036
|
**/
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
return this.vertices[this.vertices.length - (Math.abs(index) % this.vertices.length)];
|
|
1059
|
-
else
|
|
1060
|
-
return this.vertices[index % this.vertices.length];
|
|
1037
|
+
setLength(length) {
|
|
1038
|
+
return this.scale(length / this.length());
|
|
1061
1039
|
}
|
|
1062
1040
|
/**
|
|
1063
|
-
*
|
|
1041
|
+
* Substract the given vertex from this line's end points.
|
|
1064
1042
|
*
|
|
1065
|
-
* @method
|
|
1066
|
-
* @param {XYCoords} amount
|
|
1043
|
+
* @method sub
|
|
1044
|
+
* @param {XYCoords} amount The amount (x,y) to substract.
|
|
1045
|
+
* @return {VertTuple} this
|
|
1067
1046
|
* @instance
|
|
1068
|
-
* @memberof
|
|
1069
|
-
* @return {Polygon} this for chaining
|
|
1047
|
+
* @memberof VertTuple
|
|
1070
1048
|
**/
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
}
|
|
1049
|
+
sub(amount) {
|
|
1050
|
+
this.a.sub(amount);
|
|
1051
|
+
this.b.sub(amount);
|
|
1075
1052
|
return this;
|
|
1076
1053
|
}
|
|
1077
1054
|
/**
|
|
1078
|
-
*
|
|
1079
|
-
* <br>
|
|
1080
|
-
* Ray-casting algorithm found at<br>
|
|
1081
|
-
* https://stackoverflow.com/questions/22521982/check-if-point-inside-a-polygon
|
|
1055
|
+
* Add the given vertex to this line's end points.
|
|
1082
1056
|
*
|
|
1083
|
-
* @method
|
|
1084
|
-
* @param {XYCoords}
|
|
1085
|
-
* @return {
|
|
1057
|
+
* @method add
|
|
1058
|
+
* @param {XYCoords} amount The amount (x,y) to add.
|
|
1059
|
+
* @return {Line} this
|
|
1086
1060
|
* @instance
|
|
1087
|
-
* @memberof
|
|
1061
|
+
* @memberof VertTuple
|
|
1088
1062
|
**/
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
for (var i = 0, j = this.vertices.length - 1; i < this.vertices.length; j = i++) {
|
|
1094
|
-
let xi = this.vertices[i].x, yi = this.vertices[i].y;
|
|
1095
|
-
let xj = this.vertices[j].x, yj = this.vertices[j].y;
|
|
1096
|
-
var intersect = yi > vert.y != yj > vert.y && vert.x < ((xj - xi) * (vert.y - yi)) / (yj - yi) + xi;
|
|
1097
|
-
if (intersect)
|
|
1098
|
-
inside = !inside;
|
|
1099
|
-
}
|
|
1100
|
-
return inside;
|
|
1063
|
+
add(amount) {
|
|
1064
|
+
this.a.add(amount);
|
|
1065
|
+
this.b.add(amount);
|
|
1066
|
+
return this;
|
|
1101
1067
|
}
|
|
1102
1068
|
/**
|
|
1103
|
-
*
|
|
1104
|
-
*
|
|
1105
|
-
* Note that this does not work for self-intersecting polygons.
|
|
1069
|
+
* Normalize this line (set to length 1).
|
|
1106
1070
|
*
|
|
1107
|
-
* @method
|
|
1071
|
+
* @method normalize
|
|
1072
|
+
* @return {VertTuple} this
|
|
1108
1073
|
* @instance
|
|
1109
|
-
* @memberof
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
return
|
|
1074
|
+
* @memberof VertTuple
|
|
1075
|
+
**/
|
|
1076
|
+
normalize() {
|
|
1077
|
+
this.b.set(this.a.x + (this.b.x - this.a.x) / this.length(), this.a.y + (this.b.y - this.a.y) / this.length());
|
|
1078
|
+
return this;
|
|
1114
1079
|
}
|
|
1115
1080
|
/**
|
|
1116
|
-
*
|
|
1117
|
-
* and calculating its determinant.
|
|
1081
|
+
* Scale this line by the given factor.
|
|
1118
1082
|
*
|
|
1119
|
-
* @method
|
|
1083
|
+
* @method scale
|
|
1084
|
+
* @param {number} factor The factor for scaling (1.0 means no scale).
|
|
1085
|
+
* @return {VertTuple} this
|
|
1120
1086
|
* @instance
|
|
1121
|
-
* @memberof
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
return
|
|
1087
|
+
* @memberof VertTuple
|
|
1088
|
+
**/
|
|
1089
|
+
scale(factor) {
|
|
1090
|
+
this.b.set(this.a.x + (this.b.x - this.a.x) * factor, this.a.y + (this.b.y - this.a.y) * factor);
|
|
1091
|
+
return this;
|
|
1126
1092
|
}
|
|
1127
1093
|
/**
|
|
1128
|
-
*
|
|
1094
|
+
* Move this line to a new location.
|
|
1129
1095
|
*
|
|
1130
|
-
* @method
|
|
1096
|
+
* @method moveTo
|
|
1097
|
+
* @param {Vertex} newA - The new desired location of 'a'. Vertex 'b' will be moved, too.
|
|
1098
|
+
* @return {VertTuple} this
|
|
1131
1099
|
* @instance
|
|
1132
|
-
* @memberof
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1100
|
+
* @memberof VertTuple
|
|
1101
|
+
**/
|
|
1102
|
+
moveTo(newA) {
|
|
1103
|
+
let diff = this.a.difference(newA);
|
|
1104
|
+
this.a.add(diff);
|
|
1105
|
+
this.b.add(diff);
|
|
1106
|
+
return this;
|
|
1137
1107
|
}
|
|
1138
1108
|
/**
|
|
1139
|
-
* Get the
|
|
1140
|
-
* The perimeter is the absolute length of the outline.
|
|
1141
|
-
*
|
|
1142
|
-
* If this polygon is open then the last segment (connecting the first and the
|
|
1143
|
-
* last vertex) will be skipped.
|
|
1109
|
+
* Get the angle between this and the passed line (in radians).
|
|
1144
1110
|
*
|
|
1145
|
-
* @method
|
|
1111
|
+
* @method angle
|
|
1112
|
+
* @param {VertTuple} line - (optional) The line to calculate the angle to. If null the baseline (x-axis) will be used.
|
|
1113
|
+
* @return {number} this
|
|
1146
1114
|
* @instance
|
|
1147
|
-
* @memberof
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
for (var i = 1; i < this.vertices.length; i++) {
|
|
1153
|
-
length += this.vertices[i - 1].distance(this.vertices[i]);
|
|
1154
|
-
}
|
|
1155
|
-
if (!this.isOpen && this.vertices.length > 1) {
|
|
1156
|
-
length += this.vertices[0].distance(this.vertices[this.vertices.length - 1]);
|
|
1115
|
+
* @memberof VertTuple
|
|
1116
|
+
**/
|
|
1117
|
+
angle(line) {
|
|
1118
|
+
if (line == null || typeof line == "undefined") {
|
|
1119
|
+
line = this.factory(new Vertex(0, 0), new Vertex(100, 0));
|
|
1157
1120
|
}
|
|
1158
|
-
return
|
|
1121
|
+
// Compute the angle from x axis and the return the difference :)
|
|
1122
|
+
const v0 = this.b.clone().sub(this.a);
|
|
1123
|
+
const v1 = line.b.clone().sub(line.a);
|
|
1124
|
+
// Thank you, Javascript, for this second atan function. No additional math is needed here!
|
|
1125
|
+
// The result might be negative, but isn't it usually nicer to determine angles in positive values only?
|
|
1126
|
+
return Math.atan2(v1.x, v1.y) - Math.atan2(v0.x, v0.y);
|
|
1159
1127
|
}
|
|
1160
1128
|
/**
|
|
1161
|
-
*
|
|
1129
|
+
* Get line point at position t in [0 ... 1]:<br>
|
|
1130
|
+
* <pre>[P(0)]=[A]--------------------[P(t)]------[B]=[P(1)]</pre><br>
|
|
1131
|
+
* <br>
|
|
1132
|
+
* The counterpart of this function is Line.getClosestT(Vertex).
|
|
1162
1133
|
*
|
|
1163
|
-
* @method
|
|
1164
|
-
* @param {number}
|
|
1165
|
-
* @
|
|
1166
|
-
* @return {Polygon} this, for chaining.
|
|
1134
|
+
* @method vertAt
|
|
1135
|
+
* @param {number} t The position scalar.
|
|
1136
|
+
* @return {Vertex} The vertex a position t.
|
|
1167
1137
|
* @instance
|
|
1168
|
-
* @memberof
|
|
1138
|
+
* @memberof VertTuple
|
|
1169
1139
|
**/
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
if (typeof this.vertices[i].scale == "function")
|
|
1173
|
-
this.vertices[i].scale(factor, center);
|
|
1174
|
-
else
|
|
1175
|
-
console.log("There seems to be a null vertex!", this.vertices[i]);
|
|
1176
|
-
}
|
|
1177
|
-
return this;
|
|
1140
|
+
vertAt(t) {
|
|
1141
|
+
return new Vertex(this.a.x + (this.b.x - this.a.x) * t, this.a.y + (this.b.y - this.a.y) * t);
|
|
1178
1142
|
}
|
|
1179
1143
|
/**
|
|
1180
|
-
*
|
|
1144
|
+
* Get the denominator of this and the given line.
|
|
1181
1145
|
*
|
|
1182
|
-
*
|
|
1183
|
-
*
|
|
1184
|
-
* @
|
|
1146
|
+
* If the denominator is zero (or close to zero) both line are co-linear.
|
|
1147
|
+
*
|
|
1148
|
+
* @method denominator
|
|
1149
|
+
* @param {VertTuple} line
|
|
1185
1150
|
* @instance
|
|
1186
|
-
* @memberof
|
|
1187
|
-
* @return {
|
|
1151
|
+
* @memberof VertTuple
|
|
1152
|
+
* @return {Number}
|
|
1188
1153
|
**/
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
}
|
|
1193
|
-
return this;
|
|
1154
|
+
denominator(line) {
|
|
1155
|
+
// http://jsfiddle.net/justin_c_rounds/Gd2S2/
|
|
1156
|
+
return (line.b.y - line.a.y) * (this.b.x - this.a.x) - (line.b.x - line.a.x) * (this.b.y - this.a.y);
|
|
1194
1157
|
}
|
|
1195
1158
|
/**
|
|
1196
|
-
*
|
|
1159
|
+
* Checks if this and the given line are co-linear.
|
|
1197
1160
|
*
|
|
1198
|
-
*
|
|
1161
|
+
* The constant Vertex.EPSILON is used for tolerance.
|
|
1162
|
+
*
|
|
1163
|
+
* @method colinear
|
|
1164
|
+
* @param {VertTuple} line
|
|
1165
|
+
* @instance
|
|
1166
|
+
* @memberof VertTuple
|
|
1167
|
+
* @return true if both lines are co-linear.
|
|
1199
1168
|
*/
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
throw new Error("pointCount must be larger than zero; is " + pointCount + ".");
|
|
1203
|
-
}
|
|
1204
|
-
const result = new Polygon([], this.isOpen);
|
|
1205
|
-
if (this.vertices.length === 0) {
|
|
1206
|
-
return result;
|
|
1207
|
-
}
|
|
1208
|
-
// Fetch and add the start point from the source polygon
|
|
1209
|
-
let polygonPoint = new Vertex(this.vertices[0]);
|
|
1210
|
-
result.vertices.push(polygonPoint);
|
|
1211
|
-
if (this.vertices.length === 1) {
|
|
1212
|
-
return result;
|
|
1213
|
-
}
|
|
1214
|
-
const perimeter = this.perimeter();
|
|
1215
|
-
const stepSize = perimeter / pointCount;
|
|
1216
|
-
const n = this.vertices.length;
|
|
1217
|
-
let polygonIndex = 1;
|
|
1218
|
-
let nextPolygonPoint = new Vertex(this.vertices[1]);
|
|
1219
|
-
let segmentLength = polygonPoint.distance(nextPolygonPoint);
|
|
1220
|
-
let loopMax = this.isOpen ? n : n + 1;
|
|
1221
|
-
let curSegmentU = stepSize;
|
|
1222
|
-
var i = 1;
|
|
1223
|
-
while (i < pointCount && polygonIndex < loopMax) {
|
|
1224
|
-
// Check if next eq point is inside this segment
|
|
1225
|
-
if (curSegmentU < segmentLength) {
|
|
1226
|
-
let newPoint = polygonPoint.clone().lerpAbs(nextPolygonPoint, curSegmentU);
|
|
1227
|
-
result.vertices.push(newPoint);
|
|
1228
|
-
curSegmentU += stepSize;
|
|
1229
|
-
i++;
|
|
1230
|
-
}
|
|
1231
|
-
else {
|
|
1232
|
-
polygonIndex++;
|
|
1233
|
-
polygonPoint = nextPolygonPoint;
|
|
1234
|
-
nextPolygonPoint = new Vertex(this.vertices[polygonIndex % n]);
|
|
1235
|
-
curSegmentU = curSegmentU - segmentLength;
|
|
1236
|
-
segmentLength = polygonPoint.distance(nextPolygonPoint);
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
|
-
return result;
|
|
1169
|
+
colinear(line) {
|
|
1170
|
+
return Math.abs(this.denominator(line)) < Vertex.EPSILON;
|
|
1240
1171
|
}
|
|
1241
1172
|
/**
|
|
1242
|
-
* Get the
|
|
1173
|
+
* Get the closest position T from this line to the specified point.
|
|
1243
1174
|
*
|
|
1244
|
-
*
|
|
1175
|
+
* The counterpart for this function is Line.vertAt(Number).
|
|
1176
|
+
*
|
|
1177
|
+
* @name getClosetT
|
|
1178
|
+
* @method getClosestT
|
|
1179
|
+
* @param {XYCoords} p The point (vertex) to measure the distance to.
|
|
1180
|
+
* @return {number} The line position t of minimal distance to p.
|
|
1245
1181
|
* @instance
|
|
1246
|
-
* @memberof
|
|
1247
|
-
* @return {Bounds} The rectangular bounds of this polygon.
|
|
1182
|
+
* @memberof VertTuple
|
|
1248
1183
|
**/
|
|
1249
|
-
|
|
1250
|
-
|
|
1184
|
+
getClosestT(p) {
|
|
1185
|
+
var l2 = VertTuple.vtutils.dist2(this.a, this.b);
|
|
1186
|
+
if (l2 === 0)
|
|
1187
|
+
return 0;
|
|
1188
|
+
var t = ((p.x - this.a.x) * (this.b.x - this.a.x) + (p.y - this.a.y) * (this.b.y - this.a.y)) / l2;
|
|
1189
|
+
// Do not wrap to [0,1] here.
|
|
1190
|
+
// Other results are of interest, too.
|
|
1191
|
+
// t = Math.max(0, Math.min(1, t));
|
|
1192
|
+
return t;
|
|
1251
1193
|
}
|
|
1252
1194
|
/**
|
|
1253
|
-
*
|
|
1195
|
+
* Check if the given point is located on this line. Optionally also check if
|
|
1196
|
+
* that point is located between point `a` and `b`.
|
|
1254
1197
|
*
|
|
1255
|
-
* @
|
|
1198
|
+
* @method hasPoint
|
|
1199
|
+
* @param {Vertex} point The point to check.
|
|
1200
|
+
* @param {boolean=} insideBoundsOnly If set to to true (default=false) the point must be between start and end point of the line.
|
|
1201
|
+
* @return {boolean} True if the given point is on this line.
|
|
1202
|
+
* @instance
|
|
1203
|
+
* @memberof VertTuple
|
|
1256
1204
|
*/
|
|
1257
|
-
|
|
1258
|
-
|
|
1205
|
+
hasPoint(point, insideBoundsOnly) {
|
|
1206
|
+
const t = this.getClosestT(point);
|
|
1207
|
+
// Compare to pointDistance?
|
|
1208
|
+
const distance = Math.sqrt(VertTuple.vtutils.dist2(point, this.vertAt(t)));
|
|
1209
|
+
if (typeof insideBoundsOnly !== "undefined" && insideBoundsOnly) {
|
|
1210
|
+
return distance < Vertex.EPSILON && t >= 0 && t <= 1;
|
|
1211
|
+
}
|
|
1212
|
+
else {
|
|
1213
|
+
return distance < Vertex.EPSILON; // t >= 0 && t <= 1;
|
|
1214
|
+
}
|
|
1259
1215
|
}
|
|
1260
1216
|
/**
|
|
1261
|
-
*
|
|
1262
|
-
* <br>
|
|
1263
|
-
* The first vertex in the returned array is the start point.<br>
|
|
1264
|
-
* The following sequence are pairs of control-point-and-end-point:
|
|
1265
|
-
* <pre>startPoint, controlPoint0, pathPoint1, controlPoint1, pathPoint2, controlPoint2, ..., endPoint</pre>
|
|
1217
|
+
* Get the closest point on this line to the specified point.
|
|
1266
1218
|
*
|
|
1267
|
-
* @method
|
|
1268
|
-
* @
|
|
1219
|
+
* @method getClosestPoint
|
|
1220
|
+
* @param {Vertex} p The point (vertex) to measre the distance to.
|
|
1221
|
+
* @return {Vertex} The point on the line that is closest to p.
|
|
1269
1222
|
* @instance
|
|
1270
|
-
* @memberof
|
|
1223
|
+
* @memberof VertTuple
|
|
1271
1224
|
**/
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
var qbezier = [];
|
|
1276
|
-
var cc0 = this.vertices[0];
|
|
1277
|
-
var cc1 = this.vertices[1];
|
|
1278
|
-
var edgeCenter = new Vertex(cc0.x + (cc1.x - cc0.x) / 2, cc0.y + (cc1.y - cc0.y) / 2);
|
|
1279
|
-
qbezier.push(edgeCenter);
|
|
1280
|
-
var limit = this.isOpen ? this.vertices.length : this.vertices.length + 1;
|
|
1281
|
-
for (var t = 1; t < limit; t++) {
|
|
1282
|
-
cc0 = this.vertices[t % this.vertices.length];
|
|
1283
|
-
cc1 = this.vertices[(t + 1) % this.vertices.length];
|
|
1284
|
-
var edgeCenter = new Vertex(cc0.x + (cc1.x - cc0.x) / 2, cc0.y + (cc1.y - cc0.y) / 2);
|
|
1285
|
-
qbezier.push(cc0);
|
|
1286
|
-
qbezier.push(edgeCenter);
|
|
1287
|
-
cc0 = cc1;
|
|
1288
|
-
}
|
|
1289
|
-
return qbezier;
|
|
1225
|
+
getClosestPoint(p) {
|
|
1226
|
+
var t = this.getClosestT(p);
|
|
1227
|
+
return this.vertAt(t);
|
|
1290
1228
|
}
|
|
1291
1229
|
/**
|
|
1292
|
-
*
|
|
1230
|
+
* The the minimal distance between this line and the specified point.
|
|
1293
1231
|
*
|
|
1294
|
-
* @method
|
|
1295
|
-
* @
|
|
1232
|
+
* @method pointDistance
|
|
1233
|
+
* @param {Vertex} p The point (vertex) to measre the distance to.
|
|
1234
|
+
* @return {number} The absolute minimal distance.
|
|
1296
1235
|
* @instance
|
|
1297
|
-
* @memberof
|
|
1236
|
+
* @memberof VertTuple
|
|
1298
1237
|
**/
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
var buffer = ["M " + qdata[0].x + " " + qdata[0].y];
|
|
1304
|
-
for (var i = 1; i < qdata.length; i += 2) {
|
|
1305
|
-
buffer.push("Q " + qdata[i].x + " " + qdata[i].y + ", " + qdata[i + 1].x + " " + qdata[i + 1].y);
|
|
1306
|
-
}
|
|
1307
|
-
return buffer.join(" ");
|
|
1238
|
+
pointDistance(p) {
|
|
1239
|
+
// Taken From:
|
|
1240
|
+
// https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
|
|
1241
|
+
return Math.sqrt(VertTuple.vtutils.dist2(p, this.vertAt(this.getClosestT(p))));
|
|
1308
1242
|
}
|
|
1309
1243
|
/**
|
|
1310
|
-
*
|
|
1311
|
-
* <br>
|
|
1312
|
-
* The first vertex in the returned array is the start point.<br>
|
|
1313
|
-
* The following sequence are triplets of (first-control-point, secnond-control-point, end-point):<br>
|
|
1314
|
-
* <pre>startPoint, controlPoint0_0, controlPoint1_1, pathPoint1, controlPoint1_0, controlPoint1_1, ..., endPoint</pre>
|
|
1244
|
+
* Create a deep clone of this instance.
|
|
1315
1245
|
*
|
|
1316
|
-
* @method
|
|
1317
|
-
* @
|
|
1318
|
-
* should over-/under-drive. Should be between 0.0 and 1.0 for best
|
|
1319
|
-
* results but other values are allowed.
|
|
1320
|
-
* @return {Vertex[]} An array of 2d vertices that shape the cubic Bézier curve.
|
|
1246
|
+
* @method cloneLine
|
|
1247
|
+
* @return {T} A type safe clone if this instance.
|
|
1321
1248
|
* @instance
|
|
1322
|
-
* @memberof
|
|
1249
|
+
* @memberof VertTuple
|
|
1323
1250
|
**/
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
threshold = 1.0;
|
|
1327
|
-
if (this.vertices.length < 3)
|
|
1328
|
-
return [];
|
|
1329
|
-
var cbezier = [];
|
|
1330
|
-
var a = this.vertices[0];
|
|
1331
|
-
var b = this.vertices[1];
|
|
1332
|
-
var edgeCenter = new Vertex(a.x + (b.x - a.x) / 2, a.y + (b.y - a.y) / 2);
|
|
1333
|
-
cbezier.push(edgeCenter);
|
|
1334
|
-
var limit = this.isOpen ? this.vertices.length - 1 : this.vertices.length;
|
|
1335
|
-
for (var t = 0; t < limit; t++) {
|
|
1336
|
-
var a = this.vertices[t % this.vertices.length];
|
|
1337
|
-
var b = this.vertices[(t + 1) % this.vertices.length];
|
|
1338
|
-
var c = this.vertices[(t + 2) % this.vertices.length];
|
|
1339
|
-
var aCenter = new Vertex(a.x + (b.x - a.x) / 2, a.y + (b.y - a.y) / 2);
|
|
1340
|
-
var bCenter = new Vertex(b.x + (c.x - b.x) / 2, b.y + (c.y - b.y) / 2);
|
|
1341
|
-
var a2 = new Vertex(aCenter.x + (b.x - aCenter.x) * threshold, aCenter.y + (b.y - aCenter.y) * threshold);
|
|
1342
|
-
var b0 = new Vertex(bCenter.x + (b.x - bCenter.x) * threshold, bCenter.y + (b.y - bCenter.y) * threshold);
|
|
1343
|
-
cbezier.push(a2);
|
|
1344
|
-
cbezier.push(b0);
|
|
1345
|
-
cbezier.push(bCenter);
|
|
1346
|
-
}
|
|
1347
|
-
return cbezier;
|
|
1251
|
+
clone() {
|
|
1252
|
+
return this.factory(this.a.clone(), this.b.clone());
|
|
1348
1253
|
}
|
|
1349
1254
|
/**
|
|
1350
|
-
*
|
|
1255
|
+
* Create a string representation of this line.
|
|
1351
1256
|
*
|
|
1352
|
-
* @method
|
|
1353
|
-
* @return {string} The
|
|
1354
|
-
* @instance
|
|
1355
|
-
* @memberof Polygon
|
|
1356
|
-
**/
|
|
1357
|
-
toCubicBezierSVGString(threshold) {
|
|
1358
|
-
var qdata = this.toCubicBezierData(threshold);
|
|
1359
|
-
if (qdata.length == 0)
|
|
1360
|
-
return "";
|
|
1361
|
-
var buffer = ["M " + qdata[0].x + " " + qdata[0].y];
|
|
1362
|
-
for (var i = 1; i < qdata.length; i += 3) {
|
|
1363
|
-
buffer.push("C " +
|
|
1364
|
-
qdata[i].x +
|
|
1365
|
-
" " +
|
|
1366
|
-
qdata[i].y +
|
|
1367
|
-
", " +
|
|
1368
|
-
qdata[i + 1].x +
|
|
1369
|
-
" " +
|
|
1370
|
-
qdata[i + 1].y +
|
|
1371
|
-
", " +
|
|
1372
|
-
qdata[i + 2].x +
|
|
1373
|
-
" " +
|
|
1374
|
-
qdata[i + 2].y);
|
|
1375
|
-
}
|
|
1376
|
-
return buffer.join(" ");
|
|
1377
|
-
}
|
|
1378
|
-
/**
|
|
1379
|
-
* Convert this polygon to a cubic bezier path instance.
|
|
1380
|
-
*
|
|
1381
|
-
* @method toCubicBezierPath
|
|
1382
|
-
* @param {number} threshold - The threshold, usually from 0.0 to 1.0.
|
|
1383
|
-
* @return {BezierPath} - A bezier path instance.
|
|
1257
|
+
* @method totring
|
|
1258
|
+
* @return {string} The string representing this line.
|
|
1384
1259
|
* @instance
|
|
1385
|
-
* @memberof
|
|
1260
|
+
* @memberof VertTuple
|
|
1386
1261
|
**/
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
// Conver the linear path vertices to a two-dimensional path array
|
|
1390
|
-
var pathdata = [];
|
|
1391
|
-
for (var i = 0; i + 3 < qdata.length; i += 3) {
|
|
1392
|
-
pathdata.push([qdata[i], qdata[i + 3], qdata[i + 1], qdata[i + 2]]);
|
|
1393
|
-
}
|
|
1394
|
-
return BezierPath.fromArray(pathdata);
|
|
1262
|
+
toString() {
|
|
1263
|
+
return "{ a : " + this.a.toString() + ", b : " + this.b.toString() + " }";
|
|
1395
1264
|
}
|
|
1396
1265
|
/**
|
|
1397
1266
|
* This function should invalidate any installed listeners and invalidate this object.
|
|
@@ -1399,476 +1268,857 @@ class Polygon {
|
|
|
1399
1268
|
* should not be used.
|
|
1400
1269
|
*/
|
|
1401
1270
|
destroy() {
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
}
|
|
1271
|
+
this.a.destroy();
|
|
1272
|
+
this.b.destroy();
|
|
1405
1273
|
this.isDestroyed = true;
|
|
1406
1274
|
}
|
|
1407
1275
|
}
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
* @name area
|
|
1415
|
-
* @return {number}
|
|
1416
|
-
*/
|
|
1417
|
-
area(vertices) {
|
|
1418
|
-
// Found at:
|
|
1419
|
-
// https://stackoverflow.com/questions/16285134/calculating-polygon-area
|
|
1420
|
-
let total = 0.0;
|
|
1421
|
-
for (var i = 0, l = vertices.length; i < l; i++) {
|
|
1422
|
-
const addX = vertices[i].x;
|
|
1423
|
-
const addY = vertices[(i + 1) % l].y;
|
|
1424
|
-
const subX = vertices[(i + 1) % l].x;
|
|
1425
|
-
const subY = vertices[i].y;
|
|
1426
|
-
total += addX * addY * 0.5;
|
|
1427
|
-
total -= subX * subY * 0.5;
|
|
1428
|
-
}
|
|
1429
|
-
return Math.abs(total);
|
|
1430
|
-
},
|
|
1431
|
-
/**
|
|
1432
|
-
* Calulate the signed polyon area by interpreting the polygon as a matrix
|
|
1433
|
-
* and calculating its determinant.
|
|
1434
|
-
*
|
|
1435
|
-
* @name signedArea
|
|
1436
|
-
* @return {number}
|
|
1437
|
-
*/
|
|
1438
|
-
signedArea(vertices) {
|
|
1439
|
-
let sum = 0;
|
|
1440
|
-
const n = vertices.length;
|
|
1441
|
-
for (var i = 0; i < n; i++) {
|
|
1442
|
-
const j = (i + 1) % n;
|
|
1443
|
-
sum += (vertices[j].x - vertices[i].x) * (vertices[i].y + vertices[j].y);
|
|
1444
|
-
}
|
|
1445
|
-
return sum;
|
|
1276
|
+
/**
|
|
1277
|
+
* @private
|
|
1278
|
+
**/
|
|
1279
|
+
VertTuple.vtutils = {
|
|
1280
|
+
dist2: (v, w) => {
|
|
1281
|
+
return (v.x - w.x) * (v.x - w.x) + (v.y - w.y) * (v.y - w.y);
|
|
1446
1282
|
}
|
|
1447
1283
|
};
|
|
1448
1284
|
|
|
1449
1285
|
/**
|
|
1450
1286
|
* @author Ikaros Kappler
|
|
1451
|
-
* @date
|
|
1452
|
-
* @modified
|
|
1453
|
-
* @modified
|
|
1454
|
-
* @modified
|
|
1455
|
-
* @modified
|
|
1456
|
-
* @modified
|
|
1457
|
-
* @modified
|
|
1458
|
-
* @modified
|
|
1459
|
-
* @
|
|
1287
|
+
* @date 2016-03-12
|
|
1288
|
+
* @modified 2018-12-05 Refactored the code from the morley-triangle script.
|
|
1289
|
+
* @modified 2019-03-20 Added JSDoc tags.
|
|
1290
|
+
* @modified 2019-04-28 Fixed a bug in the Line.sub( Vertex ) function (was not working).
|
|
1291
|
+
* @modified 2019-09-02 Added the Line.add( Vertex ) function.
|
|
1292
|
+
* @modified 2019-09-02 Added the Line.denominator( Line ) function.
|
|
1293
|
+
* @modified 2019-09-02 Added the Line.colinear( Line ) function.
|
|
1294
|
+
* @modified 2019-09-02 Fixed an error in the Line.intersection( Line ) function (class Point was renamed to Vertex).
|
|
1295
|
+
* @modified 2019-12-15 Added the Line.moveTo(Vertex) function.
|
|
1296
|
+
* @modified 2020-03-16 The Line.angle(Line) parameter is now optional. The baseline (x-axis) will be used if not defined.
|
|
1297
|
+
* @modified 2020-03-23 Ported to Typescript from JS.
|
|
1298
|
+
* @modified 2020-12-04 The `intersection` function returns undefined if both lines are parallel.
|
|
1299
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
1300
|
+
* @modified 2022-10-09 Changed the actual return value of the `intersection` function to null (was undefined before).
|
|
1301
|
+
* @modified 2022-10-17 Adding these methods from the `PathSegment` interface: getStartPoint, getEndPoint, revert.
|
|
1302
|
+
* @modified 2023-09-25 Changed param type of `intersection()` from Line to VertTuple.
|
|
1303
|
+
* @version 2.3.0
|
|
1304
|
+
*
|
|
1305
|
+
* @file Line
|
|
1306
|
+
* @public
|
|
1460
1307
|
**/
|
|
1461
1308
|
/**
|
|
1462
|
-
* @classdesc A
|
|
1309
|
+
* @classdesc A line consists of two vertices a and b.<br>
|
|
1310
|
+
* <br>
|
|
1311
|
+
* This is some refactored code from my 'Morley Triangle' test<br>
|
|
1312
|
+
* https://github.com/IkarosKappler/morleys-trisector-theorem
|
|
1463
1313
|
*
|
|
1464
|
-
* @requires XYCoords
|
|
1465
1314
|
* @requires Vertex
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
class Bounds {
|
|
1315
|
+
*/
|
|
1316
|
+
class Line extends VertTuple {
|
|
1469
1317
|
/**
|
|
1470
|
-
*
|
|
1318
|
+
* Creates an instance of Line.
|
|
1471
1319
|
*
|
|
1472
1320
|
* @constructor
|
|
1473
|
-
* @name
|
|
1474
|
-
* @param {
|
|
1475
|
-
* @param {
|
|
1321
|
+
* @name Line
|
|
1322
|
+
* @param {Vertex} a The line's first point.
|
|
1323
|
+
* @param {Vertex} b The line's second point.
|
|
1476
1324
|
**/
|
|
1477
|
-
constructor(
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1325
|
+
constructor(a, b) {
|
|
1326
|
+
super(a, b, (a, b) => new Line(a, b));
|
|
1327
|
+
/**
|
|
1328
|
+
* Required to generate proper CSS classes and other class related IDs.
|
|
1329
|
+
**/
|
|
1330
|
+
this.className = "Line";
|
|
1482
1331
|
}
|
|
1483
1332
|
/**
|
|
1484
|
-
*
|
|
1333
|
+
* Get the intersection if this line and the specified line.
|
|
1485
1334
|
*
|
|
1486
|
-
* @method
|
|
1335
|
+
* @method intersection
|
|
1336
|
+
* @param {Line} line The second line.
|
|
1337
|
+
* @return {Vertex|undefined} The intersection (may lie outside the end-points) or `undefined` if both lines are parallel.
|
|
1487
1338
|
* @instance
|
|
1488
|
-
* @memberof
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1339
|
+
* @memberof Line
|
|
1340
|
+
**/
|
|
1341
|
+
// !!! DO NOT MOVE TO VertTuple
|
|
1342
|
+
intersection(line) {
|
|
1343
|
+
const denominator = this.denominator(line);
|
|
1344
|
+
if (denominator == 0) {
|
|
1345
|
+
return null;
|
|
1346
|
+
}
|
|
1347
|
+
let a = this.a.y - line.a.y;
|
|
1348
|
+
let b = this.a.x - line.a.x;
|
|
1349
|
+
const numerator1 = (line.b.x - line.a.x) * a - (line.b.y - line.a.y) * b;
|
|
1350
|
+
const numerator2 = (this.b.x - this.a.x) * a - (this.b.y - this.a.y) * b;
|
|
1351
|
+
a = numerator1 / denominator; // NaN if parallel lines
|
|
1352
|
+
b = numerator2 / denominator;
|
|
1353
|
+
// Catch NaN?
|
|
1354
|
+
const x = this.a.x + a * (this.b.x - this.a.x);
|
|
1355
|
+
const y = this.a.y + a * (this.b.y - this.a.y);
|
|
1356
|
+
if (isNaN(a) || isNaN(x) || isNaN(y)) {
|
|
1357
|
+
return null;
|
|
1358
|
+
}
|
|
1359
|
+
// if we cast these lines infinitely in both directions, they intersect here:
|
|
1360
|
+
return new Vertex(x, y);
|
|
1493
1361
|
}
|
|
1362
|
+
//--- Implement PathSegment ---
|
|
1494
1363
|
/**
|
|
1495
|
-
* Get the
|
|
1364
|
+
* Get the start point of this path segment.
|
|
1496
1365
|
*
|
|
1497
|
-
* @method
|
|
1498
|
-
* @
|
|
1499
|
-
* @
|
|
1500
|
-
* @returns {Vertex} The center of these bounds.
|
|
1366
|
+
* @method getStartPoint
|
|
1367
|
+
* @memberof PathSegment
|
|
1368
|
+
* @return {Vertex} The start point of this path segment.
|
|
1501
1369
|
*/
|
|
1502
|
-
|
|
1503
|
-
return
|
|
1370
|
+
getStartPoint() {
|
|
1371
|
+
return this.a;
|
|
1504
1372
|
}
|
|
1505
1373
|
/**
|
|
1506
|
-
*
|
|
1507
|
-
*
|
|
1508
|
-
* Note: the returned format might change in the future, so please do not
|
|
1509
|
-
* rely on the returned string format.
|
|
1374
|
+
* Get the end point of this path segment.
|
|
1510
1375
|
*
|
|
1511
|
-
* @method
|
|
1512
|
-
* @
|
|
1513
|
-
* @
|
|
1514
|
-
* @returns {string} Get these bounds in a human readable form.
|
|
1376
|
+
* @method getEndPoint
|
|
1377
|
+
* @memberof PathSegment
|
|
1378
|
+
* @return {Vertex} The end point of this path segment.
|
|
1515
1379
|
*/
|
|
1516
|
-
|
|
1517
|
-
return
|
|
1380
|
+
getEndPoint() {
|
|
1381
|
+
return this.b;
|
|
1518
1382
|
}
|
|
1519
1383
|
/**
|
|
1520
|
-
*
|
|
1384
|
+
* Get the tangent's end point at the start point of this segment.
|
|
1521
1385
|
*
|
|
1522
|
-
* @method
|
|
1523
|
-
* @
|
|
1524
|
-
* @
|
|
1525
|
-
* @returns {Bounds} Creates a deep clone of this bounds object.
|
|
1386
|
+
* @method getStartTangent
|
|
1387
|
+
* @memberof PathSegment
|
|
1388
|
+
* @return {Vertex} The end point of the starting point's tangent.
|
|
1526
1389
|
*/
|
|
1527
|
-
|
|
1528
|
-
return
|
|
1390
|
+
getStartTangent() {
|
|
1391
|
+
return this.b;
|
|
1529
1392
|
}
|
|
1530
1393
|
/**
|
|
1531
|
-
*
|
|
1394
|
+
* Get the tangent's end point at the end point of this segment.
|
|
1532
1395
|
*
|
|
1533
|
-
*
|
|
1396
|
+
* @method getEndTangent
|
|
1397
|
+
* @memberof PathSegment
|
|
1398
|
+
* @return {Vertex} The end point of the ending point's tangent.
|
|
1399
|
+
*/
|
|
1400
|
+
getEndTangent() {
|
|
1401
|
+
return this.a;
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* Inverse this path segment (in-place) and return this same instance (useful for chaining).
|
|
1534
1405
|
*
|
|
1535
|
-
* @
|
|
1536
|
-
* @
|
|
1537
|
-
* @
|
|
1538
|
-
* @param {Array<Vertex>} vertices - The set of vertices you want to get the bounding box for.
|
|
1539
|
-
* @return The minimal Bounds for the given vertices.
|
|
1540
|
-
**/
|
|
1541
|
-
static computeFromVertices(vertices) {
|
|
1542
|
-
if (vertices.length == 0)
|
|
1543
|
-
return new Bounds(new Vertex(0, 0), new Vertex(0, 0));
|
|
1544
|
-
let xMin = vertices[0].x;
|
|
1545
|
-
let xMax = vertices[0].x;
|
|
1546
|
-
let yMin = vertices[0].y;
|
|
1547
|
-
let yMax = vertices[0].y;
|
|
1548
|
-
let vert;
|
|
1549
|
-
for (var i in vertices) {
|
|
1550
|
-
vert = vertices[i];
|
|
1551
|
-
xMin = Math.min(xMin, vert.x);
|
|
1552
|
-
xMax = Math.max(xMax, vert.x);
|
|
1553
|
-
yMin = Math.min(yMin, vert.y);
|
|
1554
|
-
yMax = Math.max(yMax, vert.y);
|
|
1555
|
-
}
|
|
1556
|
-
return new Bounds(new Vertex(xMin, yMin), new Vertex(xMax, yMax));
|
|
1557
|
-
}
|
|
1558
|
-
/**
|
|
1559
|
-
* Create a new `Bounds` instance just from `width` and `height`, located at (0,0) or the optionally given origin.
|
|
1560
|
-
*
|
|
1561
|
-
* @param {number} width - The width of the bounds
|
|
1562
|
-
* @param {number} height - The height of the bounds
|
|
1563
|
-
* @param {XYCoords={x:0,y:0}} origin - [optional] A origin to locate the new Bounds object at.
|
|
1564
|
-
* @returns {Bounds} A new `Bounds` instance width given width and height, located at (0,0) or the given origin..
|
|
1406
|
+
* @method reverse
|
|
1407
|
+
* @memberof PathSegment
|
|
1408
|
+
* @return {PathSegment} This path segment instance (for chaining).
|
|
1565
1409
|
*/
|
|
1566
|
-
|
|
1567
|
-
|
|
1410
|
+
reverse() {
|
|
1411
|
+
var tmp = this.a;
|
|
1412
|
+
this.a = this.b;
|
|
1413
|
+
this.b = tmp;
|
|
1414
|
+
return this;
|
|
1568
1415
|
}
|
|
1569
|
-
}
|
|
1416
|
+
}
|
|
1570
1417
|
|
|
1571
1418
|
/**
|
|
1572
|
-
* @author
|
|
1573
|
-
* @date
|
|
1574
|
-
* @modified
|
|
1575
|
-
* @modified
|
|
1576
|
-
* @modified
|
|
1577
|
-
* @modified
|
|
1578
|
-
* @modified
|
|
1579
|
-
* @modified
|
|
1419
|
+
* @author Ikaros Kappler
|
|
1420
|
+
* @date 2018-04-14
|
|
1421
|
+
* @modified 2018-11-17 Added the containsVert function.
|
|
1422
|
+
* @modified 2018-12-04 Added the toSVGString function.
|
|
1423
|
+
* @modified 2019-03-20 Added JSDoc tags.
|
|
1424
|
+
* @modified 2019-10-25 Added the scale function.
|
|
1425
|
+
* @modified 2019-11-06 JSDoc update.
|
|
1426
|
+
* @modified 2019-11-07 Added toCubicBezierPath(number) function.
|
|
1427
|
+
* @modified 2019-11-22 Added the rotate(number,Vertex) function.
|
|
1428
|
+
* @modified 2020-03-24 Ported this class from vanilla-JS to Typescript.
|
|
1429
|
+
* @modified 2020-10-30 Added the `addVertex` function.
|
|
1430
|
+
* @modified 2020-10-31 Added the `getVertexAt` function.
|
|
1431
|
+
* @modified 2020-11-06 Added the `move` function.
|
|
1432
|
+
* @modified 2020-11-10 Added the `getBounds` function.
|
|
1433
|
+
* @modified 2020-11-11 Generalized `move(Vertex)` to `move(XYCoords)`.
|
|
1580
1434
|
* @modified 2021-01-20 Added UID.
|
|
1435
|
+
* @modified 2021-01-29 Added the `signedArea` function (was global function in the demos before).
|
|
1436
|
+
* @modified 2021-01-29 Added the `isClockwise` function.
|
|
1437
|
+
* @modified 2021-01-29 Added the `area` function.
|
|
1438
|
+
* @modified 2021-01-29 Changed the param type for `containsVert` from Vertex to XYCoords.
|
|
1439
|
+
* @modified 2021-12-14 Added the `perimeter()` function.
|
|
1440
|
+
* @modified 2021-12-16 Added the `getEvenDistributionPolygon()` function.
|
|
1581
1441
|
* @modified 2022-02-02 Added the `destroy` method.
|
|
1582
|
-
* @
|
|
1583
|
-
|
|
1442
|
+
* @modified 2022-02-02 Cleared the `Polygon.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
1443
|
+
* @modified 2022-03-08 Added the `Polygon.clone()` function.
|
|
1444
|
+
* @modified 2023-09-25 Added the `Polygon.getInterpolationPolygon(number)` function.
|
|
1445
|
+
* @modified 2023-09-25 Added the `Polygon.lineIntersections(Line,boolean)` function.
|
|
1446
|
+
* @modified 2023-09-29 Added the `Polygon.closestLineIntersection(Line,boolean)` function.
|
|
1447
|
+
* @version 1.11.0
|
|
1448
|
+
*
|
|
1449
|
+
* @file Polygon
|
|
1450
|
+
* @public
|
|
1451
|
+
**/
|
|
1584
1452
|
/**
|
|
1585
|
-
* @classdesc
|
|
1586
|
-
*
|
|
1453
|
+
* @classdesc A polygon class. Any polygon consists of an array of vertices; polygons can be open or closed.
|
|
1454
|
+
*
|
|
1455
|
+
* @requires BezierPath
|
|
1456
|
+
* @requires Bounds
|
|
1457
|
+
* @requires SVGSerializabe
|
|
1587
1458
|
* @requires UID
|
|
1459
|
+
* @requires UIDGenerator
|
|
1588
1460
|
* @requires Vertex
|
|
1589
1461
|
* @requires XYCoords
|
|
1590
1462
|
*/
|
|
1591
|
-
class
|
|
1463
|
+
class Polygon {
|
|
1592
1464
|
/**
|
|
1593
|
-
*
|
|
1465
|
+
* The constructor.
|
|
1594
1466
|
*
|
|
1595
1467
|
* @constructor
|
|
1596
|
-
* @name
|
|
1597
|
-
* @param {Vertex}
|
|
1598
|
-
* @param {
|
|
1468
|
+
* @name Polygon
|
|
1469
|
+
* @param {Vertex[]} vertices - An array of 2d vertices that shape the polygon.
|
|
1470
|
+
* @param {boolean} isOpen - Indicates if the polygon should be rendered as an open or closed shape.
|
|
1599
1471
|
**/
|
|
1600
|
-
constructor(
|
|
1472
|
+
constructor(vertices, isOpen) {
|
|
1473
|
+
/**
|
|
1474
|
+
* Required to generate proper CSS classes and other class related IDs.
|
|
1475
|
+
**/
|
|
1476
|
+
this.className = "Polygon";
|
|
1601
1477
|
this.uid = UIDGenerator.next();
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
this.
|
|
1478
|
+
if (typeof vertices == "undefined")
|
|
1479
|
+
vertices = [];
|
|
1480
|
+
this.vertices = vertices;
|
|
1481
|
+
this.isOpen = isOpen || false;
|
|
1605
1482
|
}
|
|
1606
1483
|
/**
|
|
1607
|
-
*
|
|
1484
|
+
* Add a vertex to the end of the `vertices` array.
|
|
1608
1485
|
*
|
|
1609
|
-
* @method
|
|
1486
|
+
* @method addVert
|
|
1487
|
+
* @param {Vertex} vert - The vertex to add.
|
|
1610
1488
|
* @instance
|
|
1611
|
-
* @memberof
|
|
1489
|
+
* @memberof Polygon
|
|
1612
1490
|
**/
|
|
1613
|
-
|
|
1614
|
-
|
|
1491
|
+
addVertex(vert) {
|
|
1492
|
+
this.vertices.push(vert);
|
|
1615
1493
|
}
|
|
1616
1494
|
/**
|
|
1617
|
-
*
|
|
1618
|
-
* vector is not a null vector.
|
|
1495
|
+
* Get the polygon vertex at the given position (index).
|
|
1619
1496
|
*
|
|
1620
|
-
*
|
|
1621
|
-
* @param {number} length - The desired length.
|
|
1622
|
-
* @memberof VertTuple
|
|
1623
|
-
* @return {T} this (for chaining)
|
|
1624
|
-
**/
|
|
1625
|
-
setLength(length) {
|
|
1626
|
-
return this.scale(length / this.length());
|
|
1627
|
-
}
|
|
1628
|
-
/**
|
|
1629
|
-
* Substract the given vertex from this line's end points.
|
|
1497
|
+
* The index may exceed the total vertex count, and will be wrapped around then (modulo).
|
|
1630
1498
|
*
|
|
1631
|
-
*
|
|
1632
|
-
*
|
|
1633
|
-
*
|
|
1499
|
+
* For k >= 0:
|
|
1500
|
+
* - getVertexAt( vertices.length ) == getVertexAt( 0 )
|
|
1501
|
+
* - getVertexAt( vertices.length + k ) == getVertexAt( k )
|
|
1502
|
+
* - getVertexAt( -k ) == getVertexAt( vertices.length -k )
|
|
1503
|
+
*
|
|
1504
|
+
* @metho getVertexAt
|
|
1505
|
+
* @param {number} index - The index of the desired vertex.
|
|
1634
1506
|
* @instance
|
|
1635
|
-
* @memberof
|
|
1507
|
+
* @memberof Polygon
|
|
1508
|
+
* @return {Vertex} At the given index.
|
|
1636
1509
|
**/
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1510
|
+
getVertexAt(index) {
|
|
1511
|
+
if (index < 0)
|
|
1512
|
+
return this.vertices[this.vertices.length - (Math.abs(index) % this.vertices.length)];
|
|
1513
|
+
else
|
|
1514
|
+
return this.vertices[index % this.vertices.length];
|
|
1641
1515
|
}
|
|
1642
1516
|
/**
|
|
1643
|
-
*
|
|
1517
|
+
* Move the polygon's vertices by the given amount.
|
|
1644
1518
|
*
|
|
1645
|
-
* @method
|
|
1646
|
-
* @param {XYCoords} amount The amount
|
|
1647
|
-
* @return {Line} this
|
|
1519
|
+
* @method move
|
|
1520
|
+
* @param {XYCoords} amount - The amount to move.
|
|
1648
1521
|
* @instance
|
|
1649
|
-
* @memberof
|
|
1522
|
+
* @memberof Polygon
|
|
1523
|
+
* @return {Polygon} this for chaining
|
|
1650
1524
|
**/
|
|
1651
|
-
|
|
1652
|
-
this.
|
|
1653
|
-
|
|
1525
|
+
move(amount) {
|
|
1526
|
+
for (var i in this.vertices) {
|
|
1527
|
+
this.vertices[i].add(amount);
|
|
1528
|
+
}
|
|
1654
1529
|
return this;
|
|
1655
1530
|
}
|
|
1656
1531
|
/**
|
|
1657
|
-
*
|
|
1532
|
+
* Check if the given vertex is inside this polygon.<br>
|
|
1533
|
+
* <br>
|
|
1534
|
+
* Ray-casting algorithm found at<br>
|
|
1535
|
+
* https://stackoverflow.com/questions/22521982/check-if-point-inside-a-polygon
|
|
1658
1536
|
*
|
|
1659
|
-
* @method
|
|
1660
|
-
* @
|
|
1537
|
+
* @method containsVert
|
|
1538
|
+
* @param {XYCoords} vert - The vertex to check. The new x-component.
|
|
1539
|
+
* @return {boolean} True if the passed vertex is inside this polygon. The polygon is considered closed.
|
|
1661
1540
|
* @instance
|
|
1662
|
-
* @memberof
|
|
1541
|
+
* @memberof Polygon
|
|
1663
1542
|
**/
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1543
|
+
containsVert(vert) {
|
|
1544
|
+
// ray-casting algorithm based on
|
|
1545
|
+
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
|
1546
|
+
var inside = false;
|
|
1547
|
+
for (var i = 0, j = this.vertices.length - 1; i < this.vertices.length; j = i++) {
|
|
1548
|
+
let xi = this.vertices[i].x, yi = this.vertices[i].y;
|
|
1549
|
+
let xj = this.vertices[j].x, yj = this.vertices[j].y;
|
|
1550
|
+
var intersect = yi > vert.y != yj > vert.y && vert.x < ((xj - xi) * (vert.y - yi)) / (yj - yi) + xi;
|
|
1551
|
+
if (intersect)
|
|
1552
|
+
inside = !inside;
|
|
1553
|
+
}
|
|
1554
|
+
return inside;
|
|
1667
1555
|
}
|
|
1668
1556
|
/**
|
|
1669
|
-
*
|
|
1557
|
+
* Calculate the area of the given polygon (unsigned).
|
|
1670
1558
|
*
|
|
1671
|
-
*
|
|
1672
|
-
*
|
|
1673
|
-
* @
|
|
1559
|
+
* Note that this does not work for self-intersecting polygons.
|
|
1560
|
+
*
|
|
1561
|
+
* @method area
|
|
1674
1562
|
* @instance
|
|
1675
|
-
* @memberof
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
return this;
|
|
1563
|
+
* @memberof Polygon
|
|
1564
|
+
* @return {number}
|
|
1565
|
+
*/
|
|
1566
|
+
area() {
|
|
1567
|
+
return Polygon.utils.area(this.vertices);
|
|
1680
1568
|
}
|
|
1681
1569
|
/**
|
|
1682
|
-
*
|
|
1570
|
+
* Calulate the signed polyon area by interpreting the polygon as a matrix
|
|
1571
|
+
* and calculating its determinant.
|
|
1683
1572
|
*
|
|
1684
|
-
* @method
|
|
1685
|
-
* @param {Vertex} newA - The new desired location of 'a'. Vertex 'b' will be moved, too.
|
|
1686
|
-
* @return {VertTuple} this
|
|
1573
|
+
* @method signedArea
|
|
1687
1574
|
* @instance
|
|
1688
|
-
* @memberof
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
this.b.add(diff);
|
|
1694
|
-
return this;
|
|
1575
|
+
* @memberof Polygon
|
|
1576
|
+
* @return {number}
|
|
1577
|
+
*/
|
|
1578
|
+
signedArea() {
|
|
1579
|
+
return Polygon.utils.signedArea(this.vertices);
|
|
1695
1580
|
}
|
|
1696
1581
|
/**
|
|
1697
|
-
* Get the
|
|
1582
|
+
* Get the winding order of this polgon: clockwise or counterclockwise.
|
|
1698
1583
|
*
|
|
1699
|
-
* @method
|
|
1700
|
-
* @param {VertTuple} line - (optional) The line to calculate the angle to. If null the baseline (x-axis) will be used.
|
|
1701
|
-
* @return {number} this
|
|
1584
|
+
* @method isClockwise
|
|
1702
1585
|
* @instance
|
|
1703
|
-
* @memberof
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
}
|
|
1709
|
-
// Compute the angle from x axis and the return the difference :)
|
|
1710
|
-
const v0 = this.b.clone().sub(this.a);
|
|
1711
|
-
const v1 = line.b.clone().sub(line.a);
|
|
1712
|
-
// Thank you, Javascript, for this second atan function. No additional math is needed here!
|
|
1713
|
-
// The result might be negative, but isn't it usually nicer to determine angles in positive values only?
|
|
1714
|
-
return Math.atan2(v1.x, v1.y) - Math.atan2(v0.x, v0.y);
|
|
1586
|
+
* @memberof Polygon
|
|
1587
|
+
* @return {boolean}
|
|
1588
|
+
*/
|
|
1589
|
+
isClockwise() {
|
|
1590
|
+
return Polygon.utils.signedArea(this.vertices) < 0;
|
|
1715
1591
|
}
|
|
1716
1592
|
/**
|
|
1717
|
-
* Get
|
|
1718
|
-
*
|
|
1719
|
-
* <br>
|
|
1720
|
-
* The counterpart of this function is Line.getClosestT(Vertex).
|
|
1593
|
+
* Get the perimeter of this polygon.
|
|
1594
|
+
* The perimeter is the absolute length of the outline.
|
|
1721
1595
|
*
|
|
1722
|
-
*
|
|
1723
|
-
*
|
|
1724
|
-
*
|
|
1596
|
+
* If this polygon is open then the last segment (connecting the first and the
|
|
1597
|
+
* last vertex) will be skipped.
|
|
1598
|
+
*
|
|
1599
|
+
* @method perimeter
|
|
1725
1600
|
* @instance
|
|
1726
|
-
* @memberof
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1601
|
+
* @memberof Polygon
|
|
1602
|
+
* @return {number}
|
|
1603
|
+
*/
|
|
1604
|
+
perimeter() {
|
|
1605
|
+
let length = 0;
|
|
1606
|
+
for (var i = 1; i < this.vertices.length; i++) {
|
|
1607
|
+
length += this.vertices[i - 1].distance(this.vertices[i]);
|
|
1608
|
+
}
|
|
1609
|
+
if (!this.isOpen && this.vertices.length > 1) {
|
|
1610
|
+
length += this.vertices[0].distance(this.vertices[this.vertices.length - 1]);
|
|
1611
|
+
}
|
|
1612
|
+
return length;
|
|
1730
1613
|
}
|
|
1731
1614
|
/**
|
|
1732
|
-
*
|
|
1615
|
+
* Scale the polygon relative to the given center.
|
|
1733
1616
|
*
|
|
1734
|
-
*
|
|
1617
|
+
* @method scale
|
|
1618
|
+
* @param {number} factor - The scale factor.
|
|
1619
|
+
* @param {Vertex} center - The center of scaling.
|
|
1620
|
+
* @return {Polygon} this, for chaining.
|
|
1621
|
+
* @instance
|
|
1622
|
+
* @memberof Polygon
|
|
1623
|
+
**/
|
|
1624
|
+
scale(factor, center) {
|
|
1625
|
+
for (var i in this.vertices) {
|
|
1626
|
+
if (typeof this.vertices[i].scale == "function")
|
|
1627
|
+
this.vertices[i].scale(factor, center);
|
|
1628
|
+
else
|
|
1629
|
+
console.log("There seems to be a null vertex!", this.vertices[i]);
|
|
1630
|
+
}
|
|
1631
|
+
return this;
|
|
1632
|
+
}
|
|
1633
|
+
/**
|
|
1634
|
+
* Rotate the polygon around the given center.
|
|
1735
1635
|
*
|
|
1736
|
-
* @method
|
|
1737
|
-
* @param {
|
|
1636
|
+
* @method rotate
|
|
1637
|
+
* @param {number} angle - The rotation angle.
|
|
1638
|
+
* @param {Vertex} center - The center of rotation.
|
|
1738
1639
|
* @instance
|
|
1739
|
-
* @memberof
|
|
1740
|
-
* @return {
|
|
1640
|
+
* @memberof Polygon
|
|
1641
|
+
* @return {Polygon} this, for chaining.
|
|
1741
1642
|
**/
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1643
|
+
rotate(angle, center) {
|
|
1644
|
+
for (var i in this.vertices) {
|
|
1645
|
+
this.vertices[i].rotate(angle, center);
|
|
1646
|
+
}
|
|
1647
|
+
return this;
|
|
1745
1648
|
}
|
|
1746
1649
|
/**
|
|
1747
|
-
*
|
|
1650
|
+
* Get all line intersections with this polygon.
|
|
1748
1651
|
*
|
|
1749
|
-
*
|
|
1652
|
+
* See demo `47-closest-vector-projection-on-polygon` for how it works.
|
|
1750
1653
|
*
|
|
1751
|
-
* @
|
|
1752
|
-
* @param {
|
|
1654
|
+
* @param {VertTuple} line - The line to find intersections with.
|
|
1655
|
+
* @param {boolean} inVectorBoundsOnly - If set to true only intersecion points on the passed vector are returned (located strictly between start and end vertex).
|
|
1656
|
+
* @returns {Array<Vertex>} - An array of all intersections within the polygon bounds.
|
|
1657
|
+
*/
|
|
1658
|
+
lineIntersections(line, inVectorBoundsOnly = false) {
|
|
1659
|
+
// Find the intersections of all lines inside the edge bounds
|
|
1660
|
+
const intersectionPoints = [];
|
|
1661
|
+
for (var i = 0; i < this.vertices.length; i++) {
|
|
1662
|
+
const polyLine = new Line(this.vertices[i], this.vertices[(i + 1) % this.vertices.length]);
|
|
1663
|
+
const intersection = polyLine.intersection(line);
|
|
1664
|
+
// true => only inside bounds
|
|
1665
|
+
// ignore last edge if open
|
|
1666
|
+
if ((!this.isOpen || i + 1 !== this.vertices.length) &&
|
|
1667
|
+
intersection !== null &&
|
|
1668
|
+
polyLine.hasPoint(intersection, true) &&
|
|
1669
|
+
(!inVectorBoundsOnly || line.hasPoint(intersection, inVectorBoundsOnly))) {
|
|
1670
|
+
intersectionPoints.push(intersection);
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
return intersectionPoints;
|
|
1674
|
+
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Get the closest line-polygon-intersection point (closest the line point A).
|
|
1677
|
+
*
|
|
1678
|
+
* See demo `47-closest-vector-projection-on-polygon` for how it works.
|
|
1679
|
+
*
|
|
1680
|
+
* @param {VertTuple} line - The line to find intersections with.
|
|
1681
|
+
* @param {boolean} inVectorBoundsOnly - If set to true only intersecion points on the passed vector are considered (located strictly between start and end vertex).
|
|
1682
|
+
* @returns {Array<Vertex>} - An array of all intersections within the polygon bounds.
|
|
1683
|
+
*/
|
|
1684
|
+
closestLineIntersection(line, inVectorBoundsOnly = false) {
|
|
1685
|
+
const allIntersections = this.lineIntersections(line, inVectorBoundsOnly);
|
|
1686
|
+
if (allIntersections.length <= 0) {
|
|
1687
|
+
// Empty polygon -> no intersections
|
|
1688
|
+
return null;
|
|
1689
|
+
}
|
|
1690
|
+
// Find the closest intersection
|
|
1691
|
+
let closestIntersection = new Vertex(Number.MAX_VALUE, Number.MAX_VALUE);
|
|
1692
|
+
let curDist = Number.MAX_VALUE;
|
|
1693
|
+
for (var i in allIntersections) {
|
|
1694
|
+
const curVert = allIntersections[i];
|
|
1695
|
+
const dist = curVert.distance(line.a);
|
|
1696
|
+
if (dist < curDist) {
|
|
1697
|
+
// && line.hasPoint(curVert)) {
|
|
1698
|
+
curDist = dist;
|
|
1699
|
+
closestIntersection = curVert;
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
return closestIntersection;
|
|
1703
|
+
}
|
|
1704
|
+
/**
|
|
1705
|
+
* Construct a new polygon from this polygon with more vertices on each edge. The
|
|
1706
|
+
* interpolation count determines the number of additional vertices on each edge.
|
|
1707
|
+
* An interpolation count of `0` will return a polygon that equals the source
|
|
1708
|
+
* polygon.
|
|
1709
|
+
*
|
|
1710
|
+
* @param {number} interpolationCount
|
|
1711
|
+
* @returns {Polygon} A polygon with `interpolationCount` more vertices (as as factor).
|
|
1712
|
+
*/
|
|
1713
|
+
getInterpolationPolygon(interpolationCount) {
|
|
1714
|
+
const verts = [];
|
|
1715
|
+
for (var i = 0; i < this.vertices.length; i++) {
|
|
1716
|
+
const curVert = this.vertices[i];
|
|
1717
|
+
const nextVert = this.vertices[(i + 1) % this.vertices.length];
|
|
1718
|
+
verts.push(curVert.clone());
|
|
1719
|
+
// Add interpolation points
|
|
1720
|
+
if (!this.isOpen || i + 1 !== this.vertices.length) {
|
|
1721
|
+
const lerpAmount = 1.0 / (interpolationCount + 1);
|
|
1722
|
+
for (var j = 1; j <= interpolationCount; j++) {
|
|
1723
|
+
verts.push(curVert.clone().lerp(nextVert, lerpAmount * j));
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
return new Polygon(verts, this.isOpen);
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Convert this polygon into a new polygon with n evenly distributed vertices.
|
|
1731
|
+
*
|
|
1732
|
+
* @param {number} pointCount - Must not be negative.
|
|
1733
|
+
*/
|
|
1734
|
+
getEvenDistributionPolygon(pointCount) {
|
|
1735
|
+
if (pointCount <= 0) {
|
|
1736
|
+
throw new Error("pointCount must be larger than zero; is " + pointCount + ".");
|
|
1737
|
+
}
|
|
1738
|
+
const result = new Polygon([], this.isOpen);
|
|
1739
|
+
if (this.vertices.length === 0) {
|
|
1740
|
+
return result;
|
|
1741
|
+
}
|
|
1742
|
+
// Fetch and add the start point from the source polygon
|
|
1743
|
+
let polygonPoint = new Vertex(this.vertices[0]);
|
|
1744
|
+
result.vertices.push(polygonPoint);
|
|
1745
|
+
if (this.vertices.length === 1) {
|
|
1746
|
+
return result;
|
|
1747
|
+
}
|
|
1748
|
+
const perimeter = this.perimeter();
|
|
1749
|
+
const stepSize = perimeter / pointCount;
|
|
1750
|
+
const n = this.vertices.length;
|
|
1751
|
+
let polygonIndex = 1;
|
|
1752
|
+
let nextPolygonPoint = new Vertex(this.vertices[1]);
|
|
1753
|
+
let segmentLength = polygonPoint.distance(nextPolygonPoint);
|
|
1754
|
+
let loopMax = this.isOpen ? n : n + 1;
|
|
1755
|
+
let curSegmentU = stepSize;
|
|
1756
|
+
var i = 1;
|
|
1757
|
+
while (i < pointCount && polygonIndex < loopMax) {
|
|
1758
|
+
// Check if next eq point is inside this segment
|
|
1759
|
+
if (curSegmentU < segmentLength) {
|
|
1760
|
+
let newPoint = polygonPoint.clone().lerpAbs(nextPolygonPoint, curSegmentU);
|
|
1761
|
+
result.vertices.push(newPoint);
|
|
1762
|
+
curSegmentU += stepSize;
|
|
1763
|
+
i++;
|
|
1764
|
+
}
|
|
1765
|
+
else {
|
|
1766
|
+
polygonIndex++;
|
|
1767
|
+
polygonPoint = nextPolygonPoint;
|
|
1768
|
+
nextPolygonPoint = new Vertex(this.vertices[polygonIndex % n]);
|
|
1769
|
+
curSegmentU = curSegmentU - segmentLength;
|
|
1770
|
+
segmentLength = polygonPoint.distance(nextPolygonPoint);
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
return result;
|
|
1774
|
+
}
|
|
1775
|
+
/**
|
|
1776
|
+
* Get the bounding box (bounds) of this polygon.
|
|
1777
|
+
*
|
|
1778
|
+
* @method getBounds
|
|
1753
1779
|
* @instance
|
|
1754
|
-
* @memberof
|
|
1755
|
-
* @return
|
|
1780
|
+
* @memberof Polygon
|
|
1781
|
+
* @return {Bounds} The rectangular bounds of this polygon.
|
|
1782
|
+
**/
|
|
1783
|
+
getBounds() {
|
|
1784
|
+
return Bounds.computeFromVertices(this.vertices);
|
|
1785
|
+
}
|
|
1786
|
+
/**
|
|
1787
|
+
* Create a deep copy of this polygon.
|
|
1788
|
+
*
|
|
1789
|
+
* @return {Polygon} The cloned polygon.
|
|
1756
1790
|
*/
|
|
1757
|
-
|
|
1758
|
-
return
|
|
1791
|
+
clone() {
|
|
1792
|
+
return new Polygon(this.vertices.map(vert => vert.clone()), this.isOpen);
|
|
1759
1793
|
}
|
|
1760
1794
|
/**
|
|
1761
|
-
*
|
|
1795
|
+
* Convert this polygon to a sequence of quadratic Bézier curves.<br>
|
|
1796
|
+
* <br>
|
|
1797
|
+
* The first vertex in the returned array is the start point.<br>
|
|
1798
|
+
* The following sequence are pairs of control-point-and-end-point:
|
|
1799
|
+
* <pre>startPoint, controlPoint0, pathPoint1, controlPoint1, pathPoint2, controlPoint2, ..., endPoint</pre>
|
|
1762
1800
|
*
|
|
1763
|
-
*
|
|
1801
|
+
* @method toQuadraticBezierData
|
|
1802
|
+
* @return {Vertex[]} An array of 2d vertices that shape the quadratic Bézier curve.
|
|
1803
|
+
* @instance
|
|
1804
|
+
* @memberof Polygon
|
|
1805
|
+
**/
|
|
1806
|
+
toQuadraticBezierData() {
|
|
1807
|
+
if (this.vertices.length < 3)
|
|
1808
|
+
return [];
|
|
1809
|
+
var qbezier = [];
|
|
1810
|
+
var cc0 = this.vertices[0];
|
|
1811
|
+
var cc1 = this.vertices[1];
|
|
1812
|
+
var edgeCenter = new Vertex(cc0.x + (cc1.x - cc0.x) / 2, cc0.y + (cc1.y - cc0.y) / 2);
|
|
1813
|
+
qbezier.push(edgeCenter);
|
|
1814
|
+
var limit = this.isOpen ? this.vertices.length : this.vertices.length + 1;
|
|
1815
|
+
for (var t = 1; t < limit; t++) {
|
|
1816
|
+
cc0 = this.vertices[t % this.vertices.length];
|
|
1817
|
+
cc1 = this.vertices[(t + 1) % this.vertices.length];
|
|
1818
|
+
var edgeCenter = new Vertex(cc0.x + (cc1.x - cc0.x) / 2, cc0.y + (cc1.y - cc0.y) / 2);
|
|
1819
|
+
qbezier.push(cc0);
|
|
1820
|
+
qbezier.push(edgeCenter);
|
|
1821
|
+
cc0 = cc1;
|
|
1822
|
+
}
|
|
1823
|
+
return qbezier;
|
|
1824
|
+
}
|
|
1825
|
+
/**
|
|
1826
|
+
* Convert this polygon to a quadratic bezier curve, represented as an SVG data string.
|
|
1764
1827
|
*
|
|
1765
|
-
* @
|
|
1766
|
-
* @
|
|
1767
|
-
* @param {XYCoords} p The point (vertex) to measure the distance to.
|
|
1768
|
-
* @return {number} The line position t of minimal distance to p.
|
|
1828
|
+
* @method toQuadraticBezierSVGString
|
|
1829
|
+
* @return {string} The 'd' part for an SVG 'path' element.
|
|
1769
1830
|
* @instance
|
|
1770
|
-
* @memberof
|
|
1831
|
+
* @memberof Polygon
|
|
1771
1832
|
**/
|
|
1772
|
-
|
|
1773
|
-
var
|
|
1774
|
-
if (
|
|
1775
|
-
return
|
|
1776
|
-
var
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
return
|
|
1833
|
+
toQuadraticBezierSVGString() {
|
|
1834
|
+
var qdata = this.toQuadraticBezierData();
|
|
1835
|
+
if (qdata.length == 0)
|
|
1836
|
+
return "";
|
|
1837
|
+
var buffer = ["M " + qdata[0].x + " " + qdata[0].y];
|
|
1838
|
+
for (var i = 1; i < qdata.length; i += 2) {
|
|
1839
|
+
buffer.push("Q " + qdata[i].x + " " + qdata[i].y + ", " + qdata[i + 1].x + " " + qdata[i + 1].y);
|
|
1840
|
+
}
|
|
1841
|
+
return buffer.join(" ");
|
|
1842
|
+
}
|
|
1843
|
+
/**
|
|
1844
|
+
* Convert this polygon to a sequence of cubic Bézier curves.<br>
|
|
1845
|
+
* <br>
|
|
1846
|
+
* The first vertex in the returned array is the start point.<br>
|
|
1847
|
+
* The following sequence are triplets of (first-control-point, secnond-control-point, end-point):<br>
|
|
1848
|
+
* <pre>startPoint, controlPoint0_0, controlPoint1_1, pathPoint1, controlPoint1_0, controlPoint1_1, ..., endPoint</pre>
|
|
1849
|
+
*
|
|
1850
|
+
* @method toCubicBezierData
|
|
1851
|
+
* @param {number=} threshold - An optional threshold (default=1.0) how strong the curve segments
|
|
1852
|
+
* should over-/under-drive. Should be between 0.0 and 1.0 for best
|
|
1853
|
+
* results but other values are allowed.
|
|
1854
|
+
* @return {Vertex[]} An array of 2d vertices that shape the cubic Bézier curve.
|
|
1855
|
+
* @instance
|
|
1856
|
+
* @memberof Polygon
|
|
1857
|
+
**/
|
|
1858
|
+
toCubicBezierData(threshold) {
|
|
1859
|
+
if (typeof threshold == "undefined")
|
|
1860
|
+
threshold = 1.0;
|
|
1861
|
+
if (this.vertices.length < 3)
|
|
1862
|
+
return [];
|
|
1863
|
+
var cbezier = [];
|
|
1864
|
+
var a = this.vertices[0];
|
|
1865
|
+
var b = this.vertices[1];
|
|
1866
|
+
var edgeCenter = new Vertex(a.x + (b.x - a.x) / 2, a.y + (b.y - a.y) / 2);
|
|
1867
|
+
cbezier.push(edgeCenter);
|
|
1868
|
+
var limit = this.isOpen ? this.vertices.length - 1 : this.vertices.length;
|
|
1869
|
+
for (var t = 0; t < limit; t++) {
|
|
1870
|
+
var a = this.vertices[t % this.vertices.length];
|
|
1871
|
+
var b = this.vertices[(t + 1) % this.vertices.length];
|
|
1872
|
+
var c = this.vertices[(t + 2) % this.vertices.length];
|
|
1873
|
+
var aCenter = new Vertex(a.x + (b.x - a.x) / 2, a.y + (b.y - a.y) / 2);
|
|
1874
|
+
var bCenter = new Vertex(b.x + (c.x - b.x) / 2, b.y + (c.y - b.y) / 2);
|
|
1875
|
+
var a2 = new Vertex(aCenter.x + (b.x - aCenter.x) * threshold, aCenter.y + (b.y - aCenter.y) * threshold);
|
|
1876
|
+
var b0 = new Vertex(bCenter.x + (b.x - bCenter.x) * threshold, bCenter.y + (b.y - bCenter.y) * threshold);
|
|
1877
|
+
cbezier.push(a2);
|
|
1878
|
+
cbezier.push(b0);
|
|
1879
|
+
cbezier.push(bCenter);
|
|
1880
|
+
}
|
|
1881
|
+
return cbezier;
|
|
1882
|
+
}
|
|
1883
|
+
/**
|
|
1884
|
+
* Convert this polygon to a cubic bezier curve, represented as an SVG data string.
|
|
1885
|
+
*
|
|
1886
|
+
* @method toCubicBezierSVGString
|
|
1887
|
+
* @return {string} The 'd' part for an SVG 'path' element.
|
|
1888
|
+
* @instance
|
|
1889
|
+
* @memberof Polygon
|
|
1890
|
+
**/
|
|
1891
|
+
toCubicBezierSVGString(threshold) {
|
|
1892
|
+
var qdata = this.toCubicBezierData(threshold);
|
|
1893
|
+
if (qdata.length == 0)
|
|
1894
|
+
return "";
|
|
1895
|
+
var buffer = ["M " + qdata[0].x + " " + qdata[0].y];
|
|
1896
|
+
for (var i = 1; i < qdata.length; i += 3) {
|
|
1897
|
+
buffer.push("C " +
|
|
1898
|
+
qdata[i].x +
|
|
1899
|
+
" " +
|
|
1900
|
+
qdata[i].y +
|
|
1901
|
+
", " +
|
|
1902
|
+
qdata[i + 1].x +
|
|
1903
|
+
" " +
|
|
1904
|
+
qdata[i + 1].y +
|
|
1905
|
+
", " +
|
|
1906
|
+
qdata[i + 2].x +
|
|
1907
|
+
" " +
|
|
1908
|
+
qdata[i + 2].y);
|
|
1909
|
+
}
|
|
1910
|
+
return buffer.join(" ");
|
|
1911
|
+
}
|
|
1912
|
+
/**
|
|
1913
|
+
* Convert this polygon to a cubic bezier path instance.
|
|
1914
|
+
*
|
|
1915
|
+
* @method toCubicBezierPath
|
|
1916
|
+
* @param {number} threshold - The threshold, usually from 0.0 to 1.0.
|
|
1917
|
+
* @return {BezierPath} - A bezier path instance.
|
|
1918
|
+
* @instance
|
|
1919
|
+
* @memberof Polygon
|
|
1920
|
+
**/
|
|
1921
|
+
toCubicBezierPath(threshold) {
|
|
1922
|
+
var qdata = this.toCubicBezierData(threshold);
|
|
1923
|
+
// Conver the linear path vertices to a two-dimensional path array
|
|
1924
|
+
var pathdata = [];
|
|
1925
|
+
for (var i = 0; i + 3 < qdata.length; i += 3) {
|
|
1926
|
+
pathdata.push([qdata[i], qdata[i + 3], qdata[i + 1], qdata[i + 2]]);
|
|
1927
|
+
}
|
|
1928
|
+
return BezierPath.fromArray(pathdata);
|
|
1929
|
+
}
|
|
1930
|
+
/**
|
|
1931
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
1932
|
+
* After calling this function the object might not hold valid data any more and
|
|
1933
|
+
* should not be used.
|
|
1934
|
+
*/
|
|
1935
|
+
destroy() {
|
|
1936
|
+
for (var i = 0; i < this.vertices.length; i++) {
|
|
1937
|
+
this.vertices[i].destroy();
|
|
1938
|
+
}
|
|
1939
|
+
this.isDestroyed = true;
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
Polygon.utils = {
|
|
1943
|
+
/**
|
|
1944
|
+
* Calculate the area of the given polygon (unsigned).
|
|
1945
|
+
*
|
|
1946
|
+
* Note that this does not work for self-intersecting polygons.
|
|
1947
|
+
*
|
|
1948
|
+
* @name area
|
|
1949
|
+
* @return {number}
|
|
1950
|
+
*/
|
|
1951
|
+
area(vertices) {
|
|
1952
|
+
// Found at:
|
|
1953
|
+
// https://stackoverflow.com/questions/16285134/calculating-polygon-area
|
|
1954
|
+
let total = 0.0;
|
|
1955
|
+
for (var i = 0, l = vertices.length; i < l; i++) {
|
|
1956
|
+
const addX = vertices[i].x;
|
|
1957
|
+
const addY = vertices[(i + 1) % l].y;
|
|
1958
|
+
const subX = vertices[(i + 1) % l].x;
|
|
1959
|
+
const subY = vertices[i].y;
|
|
1960
|
+
total += addX * addY * 0.5;
|
|
1961
|
+
total -= subX * subY * 0.5;
|
|
1962
|
+
}
|
|
1963
|
+
return Math.abs(total);
|
|
1964
|
+
},
|
|
1965
|
+
/**
|
|
1966
|
+
* Calulate the signed polyon area by interpreting the polygon as a matrix
|
|
1967
|
+
* and calculating its determinant.
|
|
1968
|
+
*
|
|
1969
|
+
* @name signedArea
|
|
1970
|
+
* @return {number}
|
|
1971
|
+
*/
|
|
1972
|
+
signedArea(vertices) {
|
|
1973
|
+
let sum = 0;
|
|
1974
|
+
const n = vertices.length;
|
|
1975
|
+
for (var i = 0; i < n; i++) {
|
|
1976
|
+
const j = (i + 1) % n;
|
|
1977
|
+
sum += (vertices[j].x - vertices[i].x) * (vertices[i].y + vertices[j].y);
|
|
1978
|
+
}
|
|
1979
|
+
return sum;
|
|
1980
|
+
}
|
|
1981
|
+
};
|
|
1982
|
+
|
|
1983
|
+
/**
|
|
1984
|
+
* @author Ikaros Kappler
|
|
1985
|
+
* @date 2020-05-11
|
|
1986
|
+
* @modified 2020-10-30 Added the static computeFromVertices function.
|
|
1987
|
+
* @modified 2020-11-19 Set min, max, width and height to private.
|
|
1988
|
+
* @modified 2021-02-02 Added the `toPolygon` method.
|
|
1989
|
+
* @modified 2021-06-21 (mid-summer) Added `getCenter` method.
|
|
1990
|
+
* @modified 2022-02-01 Added the `toString` function.
|
|
1991
|
+
* @modified 2022-10-09 Added the `fromDimension` function.
|
|
1992
|
+
* @modified 2022-11-28 Added the `clone` method.
|
|
1993
|
+
* @modified 2023-09-29 Added the `randomPoint` method.
|
|
1994
|
+
* @version 1.7.0
|
|
1995
|
+
**/
|
|
1996
|
+
/**
|
|
1997
|
+
* @classdesc A bounds class with min and max values. Implementing IBounds.
|
|
1998
|
+
*
|
|
1999
|
+
* @requires XYCoords
|
|
2000
|
+
* @requires Vertex
|
|
2001
|
+
* @requires IBounds
|
|
2002
|
+
**/
|
|
2003
|
+
class Bounds {
|
|
2004
|
+
/**
|
|
2005
|
+
* The constructor.
|
|
2006
|
+
*
|
|
2007
|
+
* @constructor
|
|
2008
|
+
* @name Bounds
|
|
2009
|
+
* @param {XYCoords} min - The min values (x,y) as a XYCoords tuple.
|
|
2010
|
+
* @param {XYCoords} max - The max values (x,y) as a XYCoords tuple.
|
|
2011
|
+
**/
|
|
2012
|
+
constructor(min, max) {
|
|
2013
|
+
this.min = min;
|
|
2014
|
+
this.max = max;
|
|
2015
|
+
this.width = max.x - min.x;
|
|
2016
|
+
this.height = max.y - min.y;
|
|
2017
|
+
}
|
|
2018
|
+
/**
|
|
2019
|
+
* Convert this rectangular bounding box to a polygon with four vertices.
|
|
2020
|
+
*
|
|
2021
|
+
* @method toPolygon
|
|
2022
|
+
* @instance
|
|
2023
|
+
* @memberof Bounds
|
|
2024
|
+
* @return {Polygon} This bound rectangle as a polygon.
|
|
2025
|
+
*/
|
|
2026
|
+
toPolygon() {
|
|
2027
|
+
return new Polygon([new Vertex(this.min), new Vertex(this.max.x, this.min.y), new Vertex(this.max), new Vertex(this.min.x, this.max.y)], false);
|
|
1781
2028
|
}
|
|
1782
2029
|
/**
|
|
1783
|
-
*
|
|
1784
|
-
* that point is located between point `a` and `b`.
|
|
2030
|
+
* Get the center of this boinding box.
|
|
1785
2031
|
*
|
|
1786
|
-
* @method
|
|
1787
|
-
* @param {Vertex} point The point to check.
|
|
1788
|
-
* @param {boolean=} insideBoundsOnly If set to to true (default=false) the point must be between start and end point of the line.
|
|
1789
|
-
* @return {boolean} True if the given point is on this line.
|
|
2032
|
+
* @method getCenter
|
|
1790
2033
|
* @instance
|
|
1791
|
-
* @memberof
|
|
2034
|
+
* @memberof Bounds
|
|
2035
|
+
* @returns {Vertex} The center of these bounds.
|
|
1792
2036
|
*/
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
// Compare to pointDistance?
|
|
1796
|
-
if (typeof insideBoundsOnly !== "undefined" && insideBoundsOnly) {
|
|
1797
|
-
const distance = Math.sqrt(VertTuple.vtutils.dist2(point, this.vertAt(t)));
|
|
1798
|
-
return distance < Vertex.EPSILON && t >= 0 && t <= 1;
|
|
1799
|
-
}
|
|
1800
|
-
else {
|
|
1801
|
-
return t >= 0 && t <= 1;
|
|
1802
|
-
}
|
|
2037
|
+
getCenter() {
|
|
2038
|
+
return new Vertex(this.min.x + (this.max.x - this.min.x) / 2.0, this.min.y + (this.max.y - this.min.y) / 2);
|
|
1803
2039
|
}
|
|
1804
2040
|
/**
|
|
1805
|
-
*
|
|
2041
|
+
* Generate a random point inside this bounds object. Safe areas at the border to avoid
|
|
2042
|
+
* included.
|
|
1806
2043
|
*
|
|
1807
|
-
* @method
|
|
1808
|
-
* @param {Vertex} p The point (vertex) to measre the distance to.
|
|
1809
|
-
* @return {Vertex} The point on the line that is closest to p.
|
|
2044
|
+
* @method randomPoint
|
|
1810
2045
|
* @instance
|
|
1811
|
-
* @memberof
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
2046
|
+
* @memberof Bounds
|
|
2047
|
+
* @param {horizontalSafeArea} - (optional) The horizonal (left and right) safe area. No vertex will be created here. Can be used as percent in (0.0 ... 0.1) interval.
|
|
2048
|
+
* @param {verticalSafeArea} - (optional) The vertical (top and bottom) safe area. No vertex will be created here. Can be used as percent in (0.0 ... 0.1) interval
|
|
2049
|
+
* @returns {Vertex} A pseudo random point inside these bounds.
|
|
2050
|
+
*/
|
|
2051
|
+
randomPoint(horizontalSafeArea = 0, verticalSafeArea = 0) {
|
|
2052
|
+
// Check if the safe areas are meant as percent
|
|
2053
|
+
const absHorizontalSafeArea = horizontalSafeArea > 0 && horizontalSafeArea < 1 ? this.width * horizontalSafeArea : horizontalSafeArea;
|
|
2054
|
+
const absVerticalSafeArea = verticalSafeArea > 0 && verticalSafeArea < 1 ? this.height * verticalSafeArea : verticalSafeArea;
|
|
2055
|
+
return new Vertex(this.min.x + absHorizontalSafeArea + Math.random() * (this.width - 2 * absHorizontalSafeArea), this.min.y + absVerticalSafeArea + Math.random() * (this.height - 2 * absVerticalSafeArea));
|
|
1816
2056
|
}
|
|
1817
2057
|
/**
|
|
1818
|
-
*
|
|
2058
|
+
* Convert these bounds to a human readable form.
|
|
1819
2059
|
*
|
|
1820
|
-
*
|
|
1821
|
-
*
|
|
1822
|
-
*
|
|
2060
|
+
* Note: the returned format might change in the future, so please do not
|
|
2061
|
+
* rely on the returned string format.
|
|
2062
|
+
*
|
|
2063
|
+
* @method toString
|
|
1823
2064
|
* @instance
|
|
1824
|
-
* @memberof
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
return Math.sqrt(VertTuple.vtutils.dist2(p, this.vertAt(this.getClosestT(p))));
|
|
2065
|
+
* @memberof Bounds
|
|
2066
|
+
* @returns {string} Get these bounds in a human readable form.
|
|
2067
|
+
*/
|
|
2068
|
+
toString() {
|
|
2069
|
+
return `{ min: ${this.min.toString()}, max : ${this.max.toString()}, width: ${this.width}, height : ${this.height} }`;
|
|
1830
2070
|
}
|
|
1831
2071
|
/**
|
|
1832
|
-
*
|
|
2072
|
+
* Clone this bounds object (create a deep clone).
|
|
1833
2073
|
*
|
|
1834
|
-
* @method
|
|
1835
|
-
* @return {T} A type safe clone if this instance.
|
|
2074
|
+
* @method clone
|
|
1836
2075
|
* @instance
|
|
1837
|
-
* @memberof
|
|
1838
|
-
|
|
2076
|
+
* @memberof Bounds
|
|
2077
|
+
* @returns {Bounds} Creates a deep clone of this bounds object.
|
|
2078
|
+
*/
|
|
1839
2079
|
clone() {
|
|
1840
|
-
return this.
|
|
2080
|
+
return new Bounds({ x: this.min.x, y: this.min.y }, { x: this.max.x, y: this.max.y });
|
|
1841
2081
|
}
|
|
1842
2082
|
/**
|
|
1843
|
-
*
|
|
2083
|
+
* Compute the minimal bounding box for a given set of vertices.
|
|
1844
2084
|
*
|
|
1845
|
-
*
|
|
1846
|
-
*
|
|
1847
|
-
* @
|
|
1848
|
-
* @
|
|
2085
|
+
* An empty vertex array will return an empty bounding box located at (0,0).
|
|
2086
|
+
*
|
|
2087
|
+
* @static
|
|
2088
|
+
* @method computeFromVertices
|
|
2089
|
+
* @memberof Bounds
|
|
2090
|
+
* @param {Array<Vertex>} vertices - The set of vertices you want to get the bounding box for.
|
|
2091
|
+
* @return The minimal Bounds for the given vertices.
|
|
1849
2092
|
**/
|
|
1850
|
-
|
|
1851
|
-
|
|
2093
|
+
static computeFromVertices(vertices) {
|
|
2094
|
+
if (vertices.length == 0)
|
|
2095
|
+
return new Bounds(new Vertex(0, 0), new Vertex(0, 0));
|
|
2096
|
+
let xMin = vertices[0].x;
|
|
2097
|
+
let xMax = vertices[0].x;
|
|
2098
|
+
let yMin = vertices[0].y;
|
|
2099
|
+
let yMax = vertices[0].y;
|
|
2100
|
+
let vert;
|
|
2101
|
+
for (var i in vertices) {
|
|
2102
|
+
vert = vertices[i];
|
|
2103
|
+
xMin = Math.min(xMin, vert.x);
|
|
2104
|
+
xMax = Math.max(xMax, vert.x);
|
|
2105
|
+
yMin = Math.min(yMin, vert.y);
|
|
2106
|
+
yMax = Math.max(yMax, vert.y);
|
|
2107
|
+
}
|
|
2108
|
+
return new Bounds(new Vertex(xMin, yMin), new Vertex(xMax, yMax));
|
|
1852
2109
|
}
|
|
1853
2110
|
/**
|
|
1854
|
-
*
|
|
1855
|
-
*
|
|
1856
|
-
*
|
|
2111
|
+
* Create a new `Bounds` instance just from `width` and `height`, located at (0,0) or the optionally given origin.
|
|
2112
|
+
*
|
|
2113
|
+
* @param {number} width - The width of the bounds
|
|
2114
|
+
* @param {number} height - The height of the bounds
|
|
2115
|
+
* @param {XYCoords={x:0,y:0}} origin - [optional] A origin to locate the new Bounds object at.
|
|
2116
|
+
* @returns {Bounds} A new `Bounds` instance width given width and height, located at (0,0) or the given origin..
|
|
1857
2117
|
*/
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
this.b.destroy();
|
|
1861
|
-
this.isDestroyed = true;
|
|
1862
|
-
}
|
|
1863
|
-
}
|
|
1864
|
-
/**
|
|
1865
|
-
* @private
|
|
1866
|
-
**/
|
|
1867
|
-
VertTuple.vtutils = {
|
|
1868
|
-
dist2: (v, w) => {
|
|
1869
|
-
return (v.x - w.x) * (v.x - w.x) + (v.y - w.y) * (v.y - w.y);
|
|
2118
|
+
static fromDimension(width, height, origin) {
|
|
2119
|
+
return new Bounds(origin !== null && origin !== void 0 ? origin : { x: 0, y: 0 }, { x: (origin ? origin.x : 0) + width, y: (origin ? origin.y : 0) + height });
|
|
1870
2120
|
}
|
|
1871
|
-
}
|
|
2121
|
+
} // END class bounds
|
|
1872
2122
|
|
|
1873
2123
|
/**
|
|
1874
2124
|
* @author Ikaros Kappler
|
|
@@ -2015,8 +2265,8 @@ Vector.utils = {
|
|
|
2015
2265
|
* Example:
|
|
2016
2266
|
* buildArrowHead( new Vertex(0,0), new Vertex(50,100), 8, 1.0, 1.0 )
|
|
2017
2267
|
*
|
|
2018
|
-
* @param {
|
|
2019
|
-
* @param {
|
|
2268
|
+
* @param {XYCoords} zA - The start vertex of the vector to calculate the arrow head for.
|
|
2269
|
+
* @param {XYCoords} zB - The end vertex of the vector.
|
|
2020
2270
|
* @param {number} headlen - The length of the arrow head (along the vector direction. A good value is 12).
|
|
2021
2271
|
* @param {number} scaleX - The horizontal scaling during draw.
|
|
2022
2272
|
* @param {number} scaleY - the vertical scaling during draw.
|
|
@@ -2055,7 +2305,9 @@ Vector.utils = {
|
|
|
2055
2305
|
* @modified 2022-02-02 Added the `destroy` method.
|
|
2056
2306
|
* @modified 2022-02-02 Cleared the `toSVGPathData` function (deprecated). Use `drawutilssvg` instead.
|
|
2057
2307
|
* @modified 2022-10-17 The `CubicBezierCurve` class now implements the new `PathSegment` interface.
|
|
2058
|
-
* @
|
|
2308
|
+
* @modified 2023-09-30 Added the function `CubicbezierCurve.getSubCurve(number,number)` – similar to `getSubCurveAt(...)` but with absolute position parameters.
|
|
2309
|
+
* @modified 2023-10-07 Added the `trimEnd`, `trimEndAt`, `trimStart`, `trimStartAt` methods.
|
|
2310
|
+
* @version 2.8.0
|
|
2059
2311
|
*
|
|
2060
2312
|
* @file CubicBezierCurve
|
|
2061
2313
|
* @public
|
|
@@ -2442,6 +2694,91 @@ class CubicBezierCurve {
|
|
|
2442
2694
|
// Note: my implementation does NOT normalize tangent vectors!
|
|
2443
2695
|
return new Vertex(tX, tY);
|
|
2444
2696
|
}
|
|
2697
|
+
/**
|
|
2698
|
+
* Trim off a start section of this curve. The position parameter `uValue` is the absolute position on the
|
|
2699
|
+
* curve in `[0...arcLength]`.
|
|
2700
|
+
* The remaining curve will be the one in the bounds `[uValue,1]` (so `[0.0,uValue]` is cut off).
|
|
2701
|
+
*
|
|
2702
|
+
* Note this function just converts the absolute parameter to a relative one and call `trimStartAt`.
|
|
2703
|
+
*
|
|
2704
|
+
* @method trimStart
|
|
2705
|
+
* @instance
|
|
2706
|
+
* @memberof CubicBezierCurve
|
|
2707
|
+
* @param {number} uValue - The absolute position parameter where to cut off the head curve.
|
|
2708
|
+
* @returns {CubicBezierCurve} `this` for chanining.
|
|
2709
|
+
*/
|
|
2710
|
+
trimStart(uValue) {
|
|
2711
|
+
return this.trimStartAt(this.convertU2T(uValue));
|
|
2712
|
+
}
|
|
2713
|
+
/**
|
|
2714
|
+
* Trim off a start section of this curve. The position parameter `t` is the relative position in [0..1].
|
|
2715
|
+
* The remaining curve will be the one in the bounds `[uValue,1]` (so `[0.0,uValue]` is cut off).
|
|
2716
|
+
*
|
|
2717
|
+
* @method trimStartAt
|
|
2718
|
+
* @instance
|
|
2719
|
+
* @memberof CubicBezierCurve
|
|
2720
|
+
* @param {number} t - The relative position parameter where to cut off the head curve.
|
|
2721
|
+
* @returns {CubicBezierCurve} `this` for chanining.
|
|
2722
|
+
*/
|
|
2723
|
+
trimStartAt(t) {
|
|
2724
|
+
const subCurbePoints = CubicBezierCurve.utils.getSubCurvePointsAt(this, t, 1.0);
|
|
2725
|
+
this.startPoint.set(subCurbePoints[0]);
|
|
2726
|
+
this.startControlPoint.set(subCurbePoints[2]);
|
|
2727
|
+
this.endPoint.set(subCurbePoints[1]);
|
|
2728
|
+
this.endControlPoint.set(subCurbePoints[3]);
|
|
2729
|
+
this.updateArcLengths();
|
|
2730
|
+
return this;
|
|
2731
|
+
}
|
|
2732
|
+
/**
|
|
2733
|
+
* Trim off the end of this curve. The position parameter `uValue` is the absolute position on the
|
|
2734
|
+
* curve in `[0...arcLength]`.
|
|
2735
|
+
* The remaining curve will be the one in the bounds `[0,uValue]` (so `[1.0-uValue,1.0]` is cut off).
|
|
2736
|
+
*
|
|
2737
|
+
* Note this function just converts the absolute parameter to a relative one and call `trimEndAt`.
|
|
2738
|
+
*
|
|
2739
|
+
* @method trimEnd
|
|
2740
|
+
* @instance
|
|
2741
|
+
* @memberof CubicBezierCurve
|
|
2742
|
+
* @param {number} uValue - The absolute position parameter where to cut off the tail curve.
|
|
2743
|
+
* @returns {CubicBezierCurve} `this` for chanining.
|
|
2744
|
+
*/
|
|
2745
|
+
trimEnd(uValue) {
|
|
2746
|
+
return this.trimEndAt(this.convertU2T(uValue));
|
|
2747
|
+
}
|
|
2748
|
+
/**
|
|
2749
|
+
* Trim off the end of this curve. The position parameter `t` is the relative position in [0..1].
|
|
2750
|
+
* The remaining curve will be the one in the bounds `[0,t]` (so `[1.0-t,1.0]` is cut off).
|
|
2751
|
+
*
|
|
2752
|
+
* @method trimEndAt
|
|
2753
|
+
* @instance
|
|
2754
|
+
* @memberof CubicBezierCurve
|
|
2755
|
+
* @param {number} t - The relative position parameter where to cut off the tail curve.
|
|
2756
|
+
* @returns {CubicBezierCurve} `this` for chanining.
|
|
2757
|
+
*/
|
|
2758
|
+
trimEndAt(t) {
|
|
2759
|
+
const subCurbePoints = CubicBezierCurve.utils.getSubCurvePointsAt(this, 0.0, t);
|
|
2760
|
+
this.startPoint.set(subCurbePoints[0]);
|
|
2761
|
+
this.startControlPoint.set(subCurbePoints[2]);
|
|
2762
|
+
this.endPoint.set(subCurbePoints[1]);
|
|
2763
|
+
this.endControlPoint.set(subCurbePoints[3]);
|
|
2764
|
+
this.updateArcLengths();
|
|
2765
|
+
return this;
|
|
2766
|
+
}
|
|
2767
|
+
/**
|
|
2768
|
+
* Get a sub curve at the given start end end positions (values on the curve's length, between 0 and curve.arcLength).
|
|
2769
|
+
*
|
|
2770
|
+
* tStart >= tEnd is allowed, you will get a reversed sub curve then.
|
|
2771
|
+
*
|
|
2772
|
+
* @method getSubCurve
|
|
2773
|
+
* @param {number} tStart – The start position of the desired sub curve (must be in [0..arcLength]).
|
|
2774
|
+
* @param {number} tEnd – The end position if the desired cub curve (must be in [0..arcLength]).
|
|
2775
|
+
* @instance
|
|
2776
|
+
* @memberof CubicBezierCurve
|
|
2777
|
+
* @return {CubicBezierCurve} The sub curve as a new curve.
|
|
2778
|
+
**/
|
|
2779
|
+
getSubCurve(uStart, uEnd) {
|
|
2780
|
+
return this.getSubCurveAt(this.convertU2T(uStart), this.convertU2T(uEnd));
|
|
2781
|
+
}
|
|
2445
2782
|
/**
|
|
2446
2783
|
* Get a sub curve at the given start end end offsets (values between 0.0 and 1.0).
|
|
2447
2784
|
*
|
|
@@ -2455,17 +2792,19 @@ class CubicBezierCurve {
|
|
|
2455
2792
|
* @return {CubicBezierCurve} The sub curve as a new curve.
|
|
2456
2793
|
**/
|
|
2457
2794
|
getSubCurveAt(tStart, tEnd) {
|
|
2458
|
-
const startVec = new Vector(this.getPointAt(tStart), this.getTangentAt(tStart));
|
|
2459
|
-
const endVec = new Vector(this.getPointAt(tEnd), this.getTangentAt(tEnd).inv());
|
|
2460
|
-
// Tangents are relative. Make absolute.
|
|
2461
|
-
startVec.b.add(startVec.a);
|
|
2462
|
-
endVec.b.add(endVec.a);
|
|
2463
|
-
// This 'splits' the curve at the given point at t.
|
|
2464
|
-
startVec.scale(0.33333333 * (tEnd - tStart));
|
|
2465
|
-
endVec.scale(0.33333333 * (tEnd - tStart));
|
|
2466
|
-
// Draw the bezier curve
|
|
2467
|
-
// pb.draw.cubicBezier( startVec.a, endVec.a, startVec.b, endVec.b, '#8800ff', 2 );
|
|
2468
|
-
return new CubicBezierCurve(startVec.a, endVec.a, startVec.b, endVec.b);
|
|
2795
|
+
// const startVec: Vector = new Vector(this.getPointAt(tStart), this.getTangentAt(tStart));
|
|
2796
|
+
// const endVec: Vector = new Vector(this.getPointAt(tEnd), this.getTangentAt(tEnd).inv());
|
|
2797
|
+
// // Tangents are relative. Make absolute.
|
|
2798
|
+
// startVec.b.add(startVec.a);
|
|
2799
|
+
// endVec.b.add(endVec.a);
|
|
2800
|
+
// // This 'splits' the curve at the given point at t.
|
|
2801
|
+
// startVec.scale(0.33333333 * (tEnd - tStart));
|
|
2802
|
+
// endVec.scale(0.33333333 * (tEnd - tStart));
|
|
2803
|
+
// // Draw the bezier curve
|
|
2804
|
+
// // pb.draw.cubicBezier( startVec.a, endVec.a, startVec.b, endVec.b, '#8800ff', 2 );
|
|
2805
|
+
// return new CubicBezierCurve(startVec.a, endVec.a, startVec.b, endVec.b);
|
|
2806
|
+
const subCurbePoints = CubicBezierCurve.utils.getSubCurvePointsAt(this, tStart, tEnd);
|
|
2807
|
+
return new CubicBezierCurve(subCurbePoints[0], subCurbePoints[1], subCurbePoints[2], subCurbePoints[3]);
|
|
2469
2808
|
}
|
|
2470
2809
|
/**
|
|
2471
2810
|
* Convert a relative curve position u to the absolute curve position t.
|
|
@@ -2718,6 +3057,35 @@ CubicBezierCurve.START_CONTROL_POINT = 1;
|
|
|
2718
3057
|
CubicBezierCurve.END_CONTROL_POINT = 2;
|
|
2719
3058
|
/** @constant {number} */
|
|
2720
3059
|
CubicBezierCurve.END_POINT = 3;
|
|
3060
|
+
/**
|
|
3061
|
+
* Helper utils.
|
|
3062
|
+
*/
|
|
3063
|
+
CubicBezierCurve.utils = {
|
|
3064
|
+
/**
|
|
3065
|
+
* Get the points of a sub curve at the given start end end offsets (values between 0.0 and 1.0).
|
|
3066
|
+
*
|
|
3067
|
+
* tStart >= tEnd is allowed, you will get a reversed sub curve then.
|
|
3068
|
+
*
|
|
3069
|
+
* @method getSubCurvePointsAt
|
|
3070
|
+
* @param {CubicBezierCurve} curve – The curve to get the sub curve points from.
|
|
3071
|
+
* @param {number} tStart – The start offset of the desired sub curve (must be in [0..1]).
|
|
3072
|
+
* @param {number} tEnd – The end offset if the desired cub curve (must be in [0..1]).
|
|
3073
|
+
* @instance
|
|
3074
|
+
* @memberof CubicBezierCurve
|
|
3075
|
+
* @return {CubicBezierCurve} The sub curve as a new curve.
|
|
3076
|
+
**/
|
|
3077
|
+
getSubCurvePointsAt: (curve, tStart, tEnd) => {
|
|
3078
|
+
const startVec = new Vector(curve.getPointAt(tStart), curve.getTangentAt(tStart));
|
|
3079
|
+
const endVec = new Vector(curve.getPointAt(tEnd), curve.getTangentAt(tEnd).inv());
|
|
3080
|
+
// Tangents are relative. Make absolute.
|
|
3081
|
+
startVec.b.add(startVec.a);
|
|
3082
|
+
endVec.b.add(endVec.a);
|
|
3083
|
+
// This 'splits' the curve at the given point at t.
|
|
3084
|
+
startVec.scale(0.33333333 * (tEnd - tStart));
|
|
3085
|
+
endVec.scale(0.33333333 * (tEnd - tStart));
|
|
3086
|
+
return [startVec.a, endVec.a, startVec.b, endVec.b];
|
|
3087
|
+
}
|
|
3088
|
+
};
|
|
2721
3089
|
|
|
2722
3090
|
/**
|
|
2723
3091
|
* @author Ikaros Kappler
|
|
@@ -2744,7 +3112,9 @@ CubicBezierCurve.END_POINT = 3;
|
|
|
2744
3112
|
* @modified 2022-01-31 Added `BezierPath.getEvenDistributionVertices(number)`.
|
|
2745
3113
|
* @modified 2022-02-02 Added the `destroy` method.
|
|
2746
3114
|
* @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
2747
|
-
* @
|
|
3115
|
+
* @modified 2023-10-06 Adding the `BezierPath.toPathPoints()` method.
|
|
3116
|
+
* @modified 2023-10-07 Adding the `BezierPath.fromCurve(CubicBezierCurve)` static function.
|
|
3117
|
+
* @version 2.6.0
|
|
2748
3118
|
*
|
|
2749
3119
|
* @file BezierPath
|
|
2750
3120
|
* @public
|
|
@@ -2775,7 +3145,7 @@ class BezierPath {
|
|
|
2775
3145
|
* @name BezierPath
|
|
2776
3146
|
* @param {Vertex[]} pathPoints - An array of path vertices (no control points).
|
|
2777
3147
|
**/
|
|
2778
|
-
constructor(
|
|
3148
|
+
constructor() {
|
|
2779
3149
|
/**
|
|
2780
3150
|
* Required to generate proper CSS classes and other class related IDs.
|
|
2781
3151
|
**/
|
|
@@ -2788,7 +3158,11 @@ class BezierPath {
|
|
|
2788
3158
|
this.END_CONTROL_POINT = 2;
|
|
2789
3159
|
/** @constant {number} */
|
|
2790
3160
|
this.END_POINT = 3;
|
|
3161
|
+
// pathPoints: Array<Vertex> | undefined | null) {
|
|
2791
3162
|
this.uid = UIDGenerator.next();
|
|
3163
|
+
// if (!pathPoints) {
|
|
3164
|
+
// pathPoints = [];
|
|
3165
|
+
// }
|
|
2792
3166
|
this.totalArcLength = 0.0;
|
|
2793
3167
|
// Set this flag to true if you want the first point and
|
|
2794
3168
|
// last point of the path to be auto adjusted, too.
|
|
@@ -2927,229 +3301,20 @@ class BezierPath {
|
|
|
2927
3301
|
* @return {number} The number of curves in this path.
|
|
2928
3302
|
**/
|
|
2929
3303
|
getCurveCount() {
|
|
2930
|
-
return this.bezierCurves.length;
|
|
2931
|
-
}
|
|
2932
|
-
/**
|
|
2933
|
-
* Get the cubic bezier curve at the given index.
|
|
2934
|
-
*
|
|
2935
|
-
* @method getCurveAt
|
|
2936
|
-
* @param {number} index - The curve index from 0 to getCurveCount()-1.
|
|
2937
|
-
* @instance
|
|
2938
|
-
* @memberof BezierPath
|
|
2939
|
-
* @return {CubicBezierCurve} The curve at the specified index.
|
|
2940
|
-
**/
|
|
2941
|
-
getCurveAt(curveIndex) {
|
|
2942
|
-
return this.bezierCurves[curveIndex];
|
|
2943
|
-
}
|
|
2944
|
-
/**
|
|
2945
|
-
* Remove the end point of this path (which removes the last curve from this path).<br>
|
|
2946
|
-
* <br>
|
|
2947
|
-
* Please note that this function does never remove the first curve, thus the path
|
|
2948
|
-
* cannot be empty after this call.
|
|
2949
|
-
*
|
|
2950
|
-
* @method removeEndPoint
|
|
2951
|
-
* @instance
|
|
2952
|
-
* @memberof BezierPath
|
|
2953
|
-
* @return {boolean} Indicating if the last curve was removed.
|
|
2954
|
-
**/
|
|
2955
|
-
/*
|
|
2956
|
-
BezierPath.prototype.removeEndPoint = function() {
|
|
2957
|
-
if( this.bezierCurves.length <= 1 )
|
|
2958
|
-
return false;
|
|
2959
|
-
|
|
2960
|
-
var newArray = [ this.bezierCurves.length-1 ];
|
|
2961
|
-
for( var i = 0; i < this.bezierCurves.length-1; i++ ) {
|
|
2962
|
-
newArray[i] = this.bezierCurves[i];
|
|
2963
|
-
}
|
|
2964
|
-
|
|
2965
|
-
// Update arc length
|
|
2966
|
-
this.totalArcLength -= this.bezierCurves[ this.bezierCurves.length-1 ].getLength();
|
|
2967
|
-
this.bezierCurves = newArray;
|
|
2968
|
-
return true;
|
|
2969
|
-
}
|
|
2970
|
-
*/
|
|
2971
|
-
/**
|
|
2972
|
-
* Remove the start point of this path (which removes the first curve from this path).<br>
|
|
2973
|
-
* <br>
|
|
2974
|
-
* Please note that this function does never remove the last curve, thus the path
|
|
2975
|
-
* cannot be empty after this call.<br>
|
|
2976
|
-
*
|
|
2977
|
-
* @method removeStartPoint
|
|
2978
|
-
* @instance
|
|
2979
|
-
* @memberof BezierPath
|
|
2980
|
-
* @return {boolean} Indicating if the first curve was removed.
|
|
2981
|
-
**/
|
|
2982
|
-
/*
|
|
2983
|
-
BezierPath.prototype.removeStartPoint = function() {
|
|
2984
|
-
|
|
2985
|
-
if( this.bezierCurves.length <= 1 )
|
|
2986
|
-
return false;
|
|
2987
|
-
|
|
2988
|
-
var newArray = [ this.bezierCurves.length-1 ];
|
|
2989
|
-
for( var i = 1; i < this.bezierCurves.length; i++ ) {
|
|
2990
|
-
|
|
2991
|
-
newArray[i-1] = this.bezierCurves[i];
|
|
2992
|
-
|
|
2993
|
-
}
|
|
2994
|
-
|
|
2995
|
-
// Update arc length
|
|
2996
|
-
this.totalArcLength -= this.bezierCurves[ 0 ].getLength();
|
|
2997
|
-
this.bezierCurves = newArray;
|
|
2998
|
-
|
|
2999
|
-
return true;
|
|
3000
|
-
}
|
|
3001
|
-
*/
|
|
3002
|
-
/**
|
|
3003
|
-
* Removes a path point inside the path.
|
|
3004
|
-
*
|
|
3005
|
-
* This function joins the bezier curve at the given index with
|
|
3006
|
-
* its predecessor, which means that the start point at the given
|
|
3007
|
-
* curve index will be removed.
|
|
3008
|
-
*
|
|
3009
|
-
* @method joinAt
|
|
3010
|
-
* @param {number} curveIndex - The index of the curve to be joined with its predecessor.
|
|
3011
|
-
* @instance
|
|
3012
|
-
* @memberof BezierPath
|
|
3013
|
-
* @return {boolean} True if the passed index indicated an inner vertex and the two curves were joined.
|
|
3014
|
-
**/
|
|
3015
|
-
/*
|
|
3016
|
-
BezierPath.prototype.joinAt = function( curveIndex ) {
|
|
3017
|
-
|
|
3018
|
-
if( curveIndex < 0 || curveIndex >= this.bezierCurves.length )
|
|
3019
|
-
return false;
|
|
3020
|
-
|
|
3021
|
-
var leftCurve = this.bezierCurves[ curveIndex-1 ];
|
|
3022
|
-
var rightCurve = this.bezierCurves[ curveIndex ];
|
|
3023
|
-
|
|
3024
|
-
// Make the length of the new handle double that long
|
|
3025
|
-
var leftControlPoint = leftCurve.getStartControlPoint().clone();
|
|
3026
|
-
leftControlPoint.sub( leftCurve.getStartPoint() );
|
|
3027
|
-
leftControlPoint.multiplyScalar( 2.0 );
|
|
3028
|
-
leftControlPoint.add( leftCurve.getStartPoint() );
|
|
3029
|
-
|
|
3030
|
-
var rightControlPoint = rightCurve.getEndControlPoint().clone();
|
|
3031
|
-
rightControlPoint.sub( rightCurve.getEndPoint() );
|
|
3032
|
-
rightControlPoint.multiplyScalar( 2.0 );
|
|
3033
|
-
rightControlPoint.add( rightCurve.getEndPoint() );
|
|
3034
|
-
|
|
3035
|
-
var newCurve = new IKRS.CubicBezierCurve( leftCurve.getStartPoint(),
|
|
3036
|
-
rightCurve.getEndPoint(),
|
|
3037
|
-
leftControlPoint,
|
|
3038
|
-
rightControlPoint
|
|
3039
|
-
);
|
|
3040
|
-
// Place into array
|
|
3041
|
-
var newArray = [ this.bezierCurves.length - 1 ];
|
|
3042
|
-
|
|
3043
|
-
for( var i = 0; i < curveIndex-1; i++ )
|
|
3044
|
-
newArray[ i ] = this.bezierCurves[i];
|
|
3045
|
-
|
|
3046
|
-
newArray[ curveIndex-1 ] = newCurve;
|
|
3047
|
-
|
|
3048
|
-
// Shift trailing curves left
|
|
3049
|
-
for( var i = curveIndex; i+1 < this.bezierCurves.length; i++ )
|
|
3050
|
-
newArray[ i ] = this.bezierCurves[ i+1 ];
|
|
3051
|
-
|
|
3052
|
-
this.bezierCurves = newArray;
|
|
3053
|
-
this.updateArcLengths();
|
|
3054
|
-
|
|
3055
|
-
return true;
|
|
3056
|
-
}
|
|
3057
|
-
*/
|
|
3058
|
-
/**
|
|
3059
|
-
* Add a new inner curve point to the path.<br>
|
|
3060
|
-
* <br>
|
|
3061
|
-
* This function splits the bezier curve at the given index and given
|
|
3062
|
-
* curve segment index.
|
|
3063
|
-
*
|
|
3064
|
-
* @method splitAt
|
|
3065
|
-
* @param {number} curveIndex - The index of the curve to split.
|
|
3066
|
-
* @param {nunber} segmentIndex - The index of the curve segment where the split should be performed.
|
|
3067
|
-
* @instance
|
|
3068
|
-
* @memberof BezierPath
|
|
3069
|
-
* @return {boolean} True if the passed indices were valid and the path was split.
|
|
3070
|
-
**/
|
|
3071
|
-
/*
|
|
3072
|
-
BezierPath.prototype.splitAt = function( curveIndex,
|
|
3073
|
-
segmentIndex
|
|
3074
|
-
) {
|
|
3075
|
-
// Must be a valid curve index
|
|
3076
|
-
if( curveIndex < 0 || curveIndex >= this.bezierCurves.length )
|
|
3077
|
-
return false;
|
|
3078
|
-
|
|
3079
|
-
var oldCurve = this.bezierCurves[ curveIndex ];
|
|
3080
|
-
|
|
3081
|
-
// Segment must be an INNER point!
|
|
3082
|
-
// (the outer points are already bezier end/start points!)
|
|
3083
|
-
if( segmentIndex < 1 || segmentIndex-1 >= oldCurve.segmentCache.length )
|
|
3084
|
-
return false;
|
|
3085
|
-
|
|
3086
|
-
// Make room for a new curve
|
|
3087
|
-
for( var c = this.bezierCurves.length; c > curveIndex; c-- ) {
|
|
3088
|
-
// Move one position to the right
|
|
3089
|
-
this.bezierCurves[ c ] = this.bezierCurves[ c-1 ];
|
|
3090
|
-
}
|
|
3091
|
-
|
|
3092
|
-
// Accumulate segment lengths
|
|
3093
|
-
var u = 0;
|
|
3094
|
-
for( var i = 0; i < segmentIndex; i++ )
|
|
3095
|
-
u += oldCurve.segmentLengths[i];
|
|
3096
|
-
//var tangent = oldCurve.getTangentAt( u );
|
|
3097
|
-
var tangent = oldCurve.getTangent( u );
|
|
3098
|
-
tangent = tangent.multiplyScalar( 0.25 );
|
|
3099
|
-
|
|
3100
|
-
var leftEndControlPoint = oldCurve.segmentCache[ segmentIndex ].clone();
|
|
3101
|
-
leftEndControlPoint.sub( tangent );
|
|
3102
|
-
|
|
3103
|
-
var rightStartControlPoint = oldCurve.segmentCache[ segmentIndex ].clone();
|
|
3104
|
-
rightStartControlPoint.add( tangent );
|
|
3105
|
-
|
|
3106
|
-
// Make the old existing handles a quarter that long
|
|
3107
|
-
var leftStartControlPoint = oldCurve.getStartControlPoint().clone();
|
|
3108
|
-
// move to (0,0)
|
|
3109
|
-
leftStartControlPoint.sub( oldCurve.getStartPoint() );
|
|
3110
|
-
leftStartControlPoint.multiplyScalar( 0.25 );
|
|
3111
|
-
leftStartControlPoint.add( oldCurve.getStartPoint() );
|
|
3112
|
-
|
|
3113
|
-
var rightEndControlPoint = oldCurve.getEndControlPoint().clone();
|
|
3114
|
-
// move to (0,0)
|
|
3115
|
-
rightEndControlPoint.sub( oldCurve.getEndPoint() );
|
|
3116
|
-
rightEndControlPoint.multiplyScalar( 0.25 );
|
|
3117
|
-
rightEndControlPoint.add( oldCurve.getEndPoint() );
|
|
3118
|
-
|
|
3119
|
-
var newLeft = new CubicBezierCurve( oldCurve.getStartPoint(), // old start point
|
|
3120
|
-
oldCurve.segmentCache[ segmentIndex ], // new end point
|
|
3121
|
-
leftStartControlPoint, // old start control point
|
|
3122
|
-
leftEndControlPoint // new end control point
|
|
3123
|
-
);
|
|
3124
|
-
var newRight = new CubicBezierCurve( oldCurve.segmentCache[ segmentIndex ], // new start point
|
|
3125
|
-
oldCurve.getEndPoint(), // old end point
|
|
3126
|
-
rightStartControlPoint, // new start control point
|
|
3127
|
-
rightEndControlPoint // old end control point
|
|
3128
|
-
);
|
|
3129
|
-
|
|
3130
|
-
// Insert split curve(s) at free index
|
|
3131
|
-
this.bezierCurves[ curveIndex ] = newLeft;
|
|
3132
|
-
this.bezierCurves[ curveIndex + 1 ] = newRight;
|
|
3133
|
-
|
|
3134
|
-
// Update total arc length, even if there is only a very little change!
|
|
3135
|
-
this.totalArcLength -= oldCurve.getLength();
|
|
3136
|
-
this.totalArcLength += newLeft.getLength();
|
|
3137
|
-
this.totalArcLength += newRight.getLength();
|
|
3138
|
-
|
|
3139
|
-
return true;
|
|
3140
|
-
};
|
|
3141
|
-
*/
|
|
3142
|
-
/*
|
|
3143
|
-
insertVertexAt( t:number ) : void {
|
|
3144
|
-
console.log('Inserting vertex at', t );
|
|
3145
|
-
// Find the curve index
|
|
3146
|
-
var u : number = 0;
|
|
3147
|
-
var curveIndex : number = -1;
|
|
3148
|
-
var localT : number = 0.0;
|
|
3149
|
-
for( var i = 0; curveIndex == -1 && i < this.bezierCurves.length; i++ ) {
|
|
3150
|
-
|
|
3151
|
-
}
|
|
3152
|
-
}; */
|
|
3304
|
+
return this.bezierCurves.length;
|
|
3305
|
+
}
|
|
3306
|
+
/**
|
|
3307
|
+
* Get the cubic bezier curve at the given index.
|
|
3308
|
+
*
|
|
3309
|
+
* @method getCurveAt
|
|
3310
|
+
* @param {number} index - The curve index from 0 to getCurveCount()-1.
|
|
3311
|
+
* @instance
|
|
3312
|
+
* @memberof BezierPath
|
|
3313
|
+
* @return {CubicBezierCurve} The curve at the specified index.
|
|
3314
|
+
**/
|
|
3315
|
+
getCurveAt(curveIndex) {
|
|
3316
|
+
return this.bezierCurves[curveIndex];
|
|
3317
|
+
}
|
|
3153
3318
|
/**
|
|
3154
3319
|
* Move the whole bezier path by the given (x,y)-amount.
|
|
3155
3320
|
*
|
|
@@ -3184,22 +3349,6 @@ class BezierPath {
|
|
|
3184
3349
|
* @return {BezierPath} this for chaining.
|
|
3185
3350
|
**/
|
|
3186
3351
|
scale(anchor, scaleFactor) {
|
|
3187
|
-
// var scaleFactors : XYCoords = { x : scaleFactor, y : scaleFactor };
|
|
3188
|
-
// for (var i = 0; i < this.bezierCurves.length; i++) {
|
|
3189
|
-
// var curve = this.bezierCurves[i];
|
|
3190
|
-
// curve.getStartPoint().scale(scaleFactor, anchor);
|
|
3191
|
-
// curve.getStartControlPoint().scale(scaleFactor, anchor);
|
|
3192
|
-
// curve.getEndControlPoint().scale(scaleFactor, anchor);
|
|
3193
|
-
// // Do NOT scale the end point here!
|
|
3194
|
-
// // Don't forget that the curves are connected and on curve's end point
|
|
3195
|
-
// // the the successor's start point (same instance)!
|
|
3196
|
-
// }
|
|
3197
|
-
// // Finally move the last end point (was not scaled yet)
|
|
3198
|
-
// if (this.bezierCurves.length > 0 && !this.adjustCircular) {
|
|
3199
|
-
// this.bezierCurves[this.bezierCurves.length - 1].getEndPoint().scale(scaleFactor, anchor);
|
|
3200
|
-
// }
|
|
3201
|
-
// this.updateArcLengths();
|
|
3202
|
-
// return this;
|
|
3203
3352
|
return this.scaleXY({ x: scaleFactor, y: scaleFactor }, anchor);
|
|
3204
3353
|
}
|
|
3205
3354
|
/**
|
|
@@ -3695,7 +3844,7 @@ class BezierPath {
|
|
|
3695
3844
|
* @return {BezierPath}
|
|
3696
3845
|
**/
|
|
3697
3846
|
clone() {
|
|
3698
|
-
var path = new BezierPath(undefined);
|
|
3847
|
+
var path = new BezierPath(); // undefined);
|
|
3699
3848
|
for (var i = 0; i < this.bezierCurves.length; i++) {
|
|
3700
3849
|
path.bezierCurves.push(this.bezierCurves[i].clone());
|
|
3701
3850
|
// Connect splines
|
|
@@ -3735,6 +3884,10 @@ class BezierPath {
|
|
|
3735
3884
|
* This function should invalidate any installed listeners and invalidate this object.
|
|
3736
3885
|
* After calling this function the object might not hold valid data any more and
|
|
3737
3886
|
* should not be used.
|
|
3887
|
+
*
|
|
3888
|
+
* @method destroy
|
|
3889
|
+
* @instance
|
|
3890
|
+
* @memberof BezierPath
|
|
3738
3891
|
*/
|
|
3739
3892
|
destroy() {
|
|
3740
3893
|
for (var i = 0; i < this.bezierCurves.length; i++) {
|
|
@@ -3742,6 +3895,40 @@ class BezierPath {
|
|
|
3742
3895
|
}
|
|
3743
3896
|
this.isDestroyed = true;
|
|
3744
3897
|
}
|
|
3898
|
+
/**
|
|
3899
|
+
* Convert this path to an array of path points that can be drawn by the default DrawLib
|
|
3900
|
+
* implementations.
|
|
3901
|
+
*
|
|
3902
|
+
* @method toPathPoints
|
|
3903
|
+
* @instance
|
|
3904
|
+
* @memberof BezierPath
|
|
3905
|
+
* @return {Array<XYCoords>}
|
|
3906
|
+
*/
|
|
3907
|
+
toPathPoints() {
|
|
3908
|
+
if (this.bezierCurves.length === 0) {
|
|
3909
|
+
return [];
|
|
3910
|
+
}
|
|
3911
|
+
if (this.bezierCurves.length === 1) {
|
|
3912
|
+
return [
|
|
3913
|
+
this.bezierCurves[0].startPoint,
|
|
3914
|
+
this.bezierCurves[0].startControlPoint,
|
|
3915
|
+
this.bezierCurves[0].endControlPoint,
|
|
3916
|
+
this.bezierCurves[0].endPoint
|
|
3917
|
+
];
|
|
3918
|
+
}
|
|
3919
|
+
const arr = [];
|
|
3920
|
+
arr.push(this.bezierCurves[0].startPoint);
|
|
3921
|
+
arr.push(this.bezierCurves[0].startControlPoint);
|
|
3922
|
+
for (var i = 1; i < this.bezierCurves.length; i++) {
|
|
3923
|
+
arr.push(this.bezierCurves[i - 1].endControlPoint);
|
|
3924
|
+
arr.push(this.bezierCurves[i - 1].endPoint);
|
|
3925
|
+
arr.push(this.bezierCurves[i].startPoint);
|
|
3926
|
+
arr.push(this.bezierCurves[i].startControlPoint);
|
|
3927
|
+
}
|
|
3928
|
+
arr.push(this.bezierCurves[0].endControlPoint);
|
|
3929
|
+
arr.push(this.bezierCurves[0].endPoint);
|
|
3930
|
+
return arr;
|
|
3931
|
+
}
|
|
3745
3932
|
/**
|
|
3746
3933
|
* Create a JSON string representation of this bézier curve.
|
|
3747
3934
|
*
|
|
@@ -3782,6 +3969,20 @@ class BezierPath {
|
|
|
3782
3969
|
var obj = JSON.parse(jsonString);
|
|
3783
3970
|
return BezierPath.fromArray(obj);
|
|
3784
3971
|
}
|
|
3972
|
+
/**
|
|
3973
|
+
* Construct a new path with a single curve. Adding more curves is always possible.
|
|
3974
|
+
*
|
|
3975
|
+
* @method fromCurve
|
|
3976
|
+
* @param {CubicBezierCurve} curve - The curve to construct a new path from.
|
|
3977
|
+
* @static
|
|
3978
|
+
* @memberof BezierPath
|
|
3979
|
+
* @return {BezierPath} The constructed bezier path instance.
|
|
3980
|
+
*/
|
|
3981
|
+
static fromCurve(curve) {
|
|
3982
|
+
const path = new BezierPath(); // []);
|
|
3983
|
+
path.addCurve(curve);
|
|
3984
|
+
return path;
|
|
3985
|
+
}
|
|
3785
3986
|
/**
|
|
3786
3987
|
* Create a BezierPath instance from the given array.
|
|
3787
3988
|
*
|
|
@@ -3793,13 +3994,15 @@ class BezierPath {
|
|
|
3793
3994
|
* @return {BezierPath} The bezier path instance retrieved from the array data.
|
|
3794
3995
|
**/
|
|
3795
3996
|
static fromArray(obj) {
|
|
3796
|
-
if (!Array.isArray(obj))
|
|
3997
|
+
if (!Array.isArray(obj)) {
|
|
3797
3998
|
throw "[BezierPath.fromArray] Passed object must be an array.";
|
|
3999
|
+
}
|
|
3798
4000
|
const arr = obj; // FORCE?
|
|
3799
|
-
if (arr.length < 1)
|
|
4001
|
+
if (arr.length < 1) {
|
|
3800
4002
|
throw "[BezierPath.fromArray] Passed array must contain at least one bezier curve (has " + arr.length + ").";
|
|
4003
|
+
}
|
|
3801
4004
|
// Create an empty bezier path
|
|
3802
|
-
var bPath = new BezierPath(undefined);
|
|
4005
|
+
var bPath = new BezierPath(); // undefined);
|
|
3803
4006
|
var lastCurve = null;
|
|
3804
4007
|
for (var i = 0; i < arr.length; i++) {
|
|
3805
4008
|
// Convert object (or array?) to bezier curve
|
|
@@ -3909,7 +4112,7 @@ class BezierPath {
|
|
|
3909
4112
|
*/
|
|
3910
4113
|
static fromReducedList(pointArray, adjustCircular) {
|
|
3911
4114
|
// Convert to object
|
|
3912
|
-
var bezierPath = new BezierPath(null); // No points yet
|
|
4115
|
+
var bezierPath = new BezierPath(); // null); // No points yet
|
|
3913
4116
|
var startPoint = new Vertex();
|
|
3914
4117
|
var startControlPoint;
|
|
3915
4118
|
var endControlPoint;
|
|
@@ -3952,138 +4155,6 @@ BezierPath.END_CONTROL_POINT = 2;
|
|
|
3952
4155
|
/** @constant {number} */
|
|
3953
4156
|
BezierPath.END_POINT = 3;
|
|
3954
4157
|
|
|
3955
|
-
/**
|
|
3956
|
-
* @author Ikaros Kappler
|
|
3957
|
-
* @date 2016-03-12
|
|
3958
|
-
* @modified 2018-12-05 Refactored the code from the morley-triangle script.
|
|
3959
|
-
* @modified 2019-03-20 Added JSDoc tags.
|
|
3960
|
-
* @modified 2019-04-28 Fixed a bug in the Line.sub( Vertex ) function (was not working).
|
|
3961
|
-
* @modified 2019-09-02 Added the Line.add( Vertex ) function.
|
|
3962
|
-
* @modified 2019-09-02 Added the Line.denominator( Line ) function.
|
|
3963
|
-
* @modified 2019-09-02 Added the Line.colinear( Line ) function.
|
|
3964
|
-
* @modified 2019-09-02 Fixed an error in the Line.intersection( Line ) function (class Point was renamed to Vertex).
|
|
3965
|
-
* @modified 2019-12-15 Added the Line.moveTo(Vertex) function.
|
|
3966
|
-
* @modified 2020-03-16 The Line.angle(Line) parameter is now optional. The baseline (x-axis) will be used if not defined.
|
|
3967
|
-
* @modified 2020-03-23 Ported to Typescript from JS.
|
|
3968
|
-
* @modified 2020-12-04 The `intersection` function returns undefined if both lines are parallel.
|
|
3969
|
-
* @modified 2022-02-02 Added the `destroy` method.
|
|
3970
|
-
* @modified 2022-10-09 Changed the actual return value of the `intersection` function to null (was undefined before).
|
|
3971
|
-
* @modified 2022-10-17 Adding these methods from the `PathSegment` interface: getStartPoint, getEndPoint, revert.
|
|
3972
|
-
* @version 2.3.0
|
|
3973
|
-
*
|
|
3974
|
-
* @file Line
|
|
3975
|
-
* @public
|
|
3976
|
-
**/
|
|
3977
|
-
/**
|
|
3978
|
-
* @classdesc A line consists of two vertices a and b.<br>
|
|
3979
|
-
* <br>
|
|
3980
|
-
* This is some refactored code from my 'Morley Triangle' test<br>
|
|
3981
|
-
* https://github.com/IkarosKappler/morleys-trisector-theorem
|
|
3982
|
-
*
|
|
3983
|
-
* @requires Vertex
|
|
3984
|
-
*/
|
|
3985
|
-
class Line extends VertTuple {
|
|
3986
|
-
/**
|
|
3987
|
-
* Creates an instance of Line.
|
|
3988
|
-
*
|
|
3989
|
-
* @constructor
|
|
3990
|
-
* @name Line
|
|
3991
|
-
* @param {Vertex} a The line's first point.
|
|
3992
|
-
* @param {Vertex} b The line's second point.
|
|
3993
|
-
**/
|
|
3994
|
-
constructor(a, b) {
|
|
3995
|
-
super(a, b, (a, b) => new Line(a, b));
|
|
3996
|
-
/**
|
|
3997
|
-
* Required to generate proper CSS classes and other class related IDs.
|
|
3998
|
-
**/
|
|
3999
|
-
this.className = "Line";
|
|
4000
|
-
}
|
|
4001
|
-
/**
|
|
4002
|
-
* Get the intersection if this line and the specified line.
|
|
4003
|
-
*
|
|
4004
|
-
* @method intersection
|
|
4005
|
-
* @param {Line} line The second line.
|
|
4006
|
-
* @return {Vertex|undefined} The intersection (may lie outside the end-points) or `undefined` if both lines are parallel.
|
|
4007
|
-
* @instance
|
|
4008
|
-
* @memberof Line
|
|
4009
|
-
**/
|
|
4010
|
-
// !!! DO NOT MOVE TO VertTuple
|
|
4011
|
-
intersection(line) {
|
|
4012
|
-
const denominator = this.denominator(line);
|
|
4013
|
-
if (denominator == 0) {
|
|
4014
|
-
return null;
|
|
4015
|
-
}
|
|
4016
|
-
let a = this.a.y - line.a.y;
|
|
4017
|
-
let b = this.a.x - line.a.x;
|
|
4018
|
-
const numerator1 = (line.b.x - line.a.x) * a - (line.b.y - line.a.y) * b;
|
|
4019
|
-
const numerator2 = (this.b.x - this.a.x) * a - (this.b.y - this.a.y) * b;
|
|
4020
|
-
a = numerator1 / denominator; // NaN if parallel lines
|
|
4021
|
-
b = numerator2 / denominator;
|
|
4022
|
-
// Catch NaN?
|
|
4023
|
-
const x = this.a.x + a * (this.b.x - this.a.x);
|
|
4024
|
-
const y = this.a.y + a * (this.b.y - this.a.y);
|
|
4025
|
-
if (isNaN(a) || isNaN(x) || isNaN(y)) {
|
|
4026
|
-
return null;
|
|
4027
|
-
}
|
|
4028
|
-
// if we cast these lines infinitely in both directions, they intersect here:
|
|
4029
|
-
return new Vertex(x, y);
|
|
4030
|
-
}
|
|
4031
|
-
//--- Implement PathSegment ---
|
|
4032
|
-
/**
|
|
4033
|
-
* Get the start point of this path segment.
|
|
4034
|
-
*
|
|
4035
|
-
* @method getStartPoint
|
|
4036
|
-
* @memberof PathSegment
|
|
4037
|
-
* @return {Vertex} The start point of this path segment.
|
|
4038
|
-
*/
|
|
4039
|
-
getStartPoint() {
|
|
4040
|
-
return this.a;
|
|
4041
|
-
}
|
|
4042
|
-
/**
|
|
4043
|
-
* Get the end point of this path segment.
|
|
4044
|
-
*
|
|
4045
|
-
* @method getEndPoint
|
|
4046
|
-
* @memberof PathSegment
|
|
4047
|
-
* @return {Vertex} The end point of this path segment.
|
|
4048
|
-
*/
|
|
4049
|
-
getEndPoint() {
|
|
4050
|
-
return this.b;
|
|
4051
|
-
}
|
|
4052
|
-
/**
|
|
4053
|
-
* Get the tangent's end point at the start point of this segment.
|
|
4054
|
-
*
|
|
4055
|
-
* @method getStartTangent
|
|
4056
|
-
* @memberof PathSegment
|
|
4057
|
-
* @return {Vertex} The end point of the starting point's tangent.
|
|
4058
|
-
*/
|
|
4059
|
-
getStartTangent() {
|
|
4060
|
-
return this.b;
|
|
4061
|
-
}
|
|
4062
|
-
/**
|
|
4063
|
-
* Get the tangent's end point at the end point of this segment.
|
|
4064
|
-
*
|
|
4065
|
-
* @method getEndTangent
|
|
4066
|
-
* @memberof PathSegment
|
|
4067
|
-
* @return {Vertex} The end point of the ending point's tangent.
|
|
4068
|
-
*/
|
|
4069
|
-
getEndTangent() {
|
|
4070
|
-
return this.a;
|
|
4071
|
-
}
|
|
4072
|
-
/**
|
|
4073
|
-
* Inverse this path segment (in-place) and return this same instance (useful for chaining).
|
|
4074
|
-
*
|
|
4075
|
-
* @method reverse
|
|
4076
|
-
* @memberof PathSegment
|
|
4077
|
-
* @return {PathSegment} This path segment instance (for chaining).
|
|
4078
|
-
*/
|
|
4079
|
-
reverse() {
|
|
4080
|
-
var tmp = this.a;
|
|
4081
|
-
this.a = this.b;
|
|
4082
|
-
this.b = tmp;
|
|
4083
|
-
return this;
|
|
4084
|
-
}
|
|
4085
|
-
}
|
|
4086
|
-
|
|
4087
4158
|
/**
|
|
4088
4159
|
* @author Ikaros Kappler
|
|
4089
4160
|
* @date 2020-05-04
|
|
@@ -4476,7 +4547,15 @@ CircleSector.circleSectorUtils = {
|
|
|
4476
4547
|
* @modified 2022-11-10 Tweaking some type issues.
|
|
4477
4548
|
* @modified 2023-02-04 Fixed a typo in the CSS classname for cubic Bézier paths: cubicBezier (was cubierBezier).
|
|
4478
4549
|
* @modified 2023-02-10 The methods `setCurrentClassName` and `setCurrentId` also accept `null` now.
|
|
4479
|
-
* @
|
|
4550
|
+
* @modified 2023-09-29 Added initialization checks for null parameters.
|
|
4551
|
+
* @modified 2023-09-29 Added a missing implementation to the `drawurilssvg.do(XYCoords,string)` function. Didn't draw anything.
|
|
4552
|
+
* @modified 2023-09-29 Downgrading all `Vertex` param type to the more generic `XYCoords` type in these render functions: line, arrow, texturedPoly, cubicBezier, cubicBezierPath, handle, handleLine, dot, point, circle, circleArc, ellipse, grid, raster.
|
|
4553
|
+
* @modified 2023-09-29 Added the `headLength` parameter to the 'DrawLib.arrow()` function.
|
|
4554
|
+
* @modified 2023-09-29 Added the `arrowHead(...)` function to the 'DrawLib.arrow()` interface.
|
|
4555
|
+
* @modified 2023-09-29 Added the `cubicBezierArrow(...)` function to the 'DrawLib.arrow()` interface.
|
|
4556
|
+
* @modified 2023-10-04 Adding `strokeOptions` param to these draw function: line, arrow, cubicBezierArrow, cubicBezier, cubicBezierPath, circle, circleArc, ellipse, square, rect, polygon, polyline.
|
|
4557
|
+
*
|
|
4558
|
+
* @version 1.6.7
|
|
4480
4559
|
**/
|
|
4481
4560
|
const RAD_TO_DEG = 180 / Math.PI;
|
|
4482
4561
|
/**
|
|
@@ -4513,6 +4592,9 @@ class drawutilssvg {
|
|
|
4513
4592
|
this.cache = new Map();
|
|
4514
4593
|
this.setSize(canvasSize);
|
|
4515
4594
|
if (isSecondary) {
|
|
4595
|
+
if (!gNode || !bufferGNode || !nodeDefs || !bufferNodeDefs) {
|
|
4596
|
+
throw "Cannot create secondary svg draw lib with undefinde gNode|bufferGNode|nodeDefs|bufferNodeDefs.";
|
|
4597
|
+
}
|
|
4516
4598
|
this.gNode = gNode;
|
|
4517
4599
|
this.bufferGNode = bufferGNode;
|
|
4518
4600
|
this.nodeDefs = nodeDefs;
|
|
@@ -4653,6 +4735,9 @@ class drawutilssvg {
|
|
|
4653
4735
|
if (this.drawlibConfiguration.blendMode) {
|
|
4654
4736
|
node.style["mix-blend-mode"] = this.drawlibConfiguration.blendMode;
|
|
4655
4737
|
}
|
|
4738
|
+
// if (this.lineDashEnabled && this.lineDash && this.lineDash.length > 0 && drawutilssvg.nodeSupportsLineDash(nodeName)) {
|
|
4739
|
+
// node.setAttribute("stroke-dasharray", this.lineDash.join(" "));
|
|
4740
|
+
// }
|
|
4656
4741
|
return node;
|
|
4657
4742
|
}
|
|
4658
4743
|
/**
|
|
@@ -4675,23 +4760,58 @@ class drawutilssvg {
|
|
|
4675
4760
|
* @param {number=1} lineWidth - (optional) A line width to use for drawing (default is 1).
|
|
4676
4761
|
* @return {SVGElement} The node itself (for chaining).
|
|
4677
4762
|
*/
|
|
4678
|
-
_bindFillDraw(node, className, color, lineWidth) {
|
|
4763
|
+
_bindFillDraw(node, className, color, lineWidth, strokeOptions) {
|
|
4764
|
+
this._configureNode(node, className, this.fillShapes, color, lineWidth, strokeOptions);
|
|
4765
|
+
return this._bindNode(node, undefined);
|
|
4766
|
+
}
|
|
4767
|
+
/**
|
|
4768
|
+
* Bind this given node to a parent. If no parent is passed then the global
|
|
4769
|
+
* node buffer will be used.
|
|
4770
|
+
*
|
|
4771
|
+
* @method _bindNode
|
|
4772
|
+
* @private
|
|
4773
|
+
* @instance
|
|
4774
|
+
* @memberof drawutilssvg
|
|
4775
|
+
* @param {SVGElement} node - The SVG node to bind.
|
|
4776
|
+
* @param {SVGElement=} bindingParent - (optional) You may pass node other than the glober buffer node.
|
|
4777
|
+
* @returns {SVGElement} The passed node itself.
|
|
4778
|
+
*/
|
|
4779
|
+
_bindNode(node, bindingParent) {
|
|
4780
|
+
if (!node.parentNode) {
|
|
4781
|
+
// Attach to DOM only if not already attached
|
|
4782
|
+
(bindingParent !== null && bindingParent !== void 0 ? bindingParent : this.bufferGNode).appendChild(node);
|
|
4783
|
+
}
|
|
4784
|
+
return node;
|
|
4785
|
+
}
|
|
4786
|
+
/**
|
|
4787
|
+
* Add custom CSS class names and the globally defined CSS classname to the
|
|
4788
|
+
* given node.
|
|
4789
|
+
*
|
|
4790
|
+
* @method addCSSClasses
|
|
4791
|
+
* @private
|
|
4792
|
+
* @instance
|
|
4793
|
+
* @memberof drawutilssvg
|
|
4794
|
+
* @param {SVGElement} node - The SVG node to bind.
|
|
4795
|
+
* @param {string} className - The additional custom classname to add.
|
|
4796
|
+
* @returns {void}
|
|
4797
|
+
*/
|
|
4798
|
+
_addCSSClasses(node, className) {
|
|
4679
4799
|
if (this.curClassName) {
|
|
4680
4800
|
node.setAttribute("class", `${className} ${this.curClassName}`);
|
|
4681
4801
|
}
|
|
4682
4802
|
else {
|
|
4683
4803
|
node.setAttribute("class", className);
|
|
4684
4804
|
}
|
|
4685
|
-
|
|
4686
|
-
|
|
4805
|
+
}
|
|
4806
|
+
_configureNode(node, className, fillMode, color, lineWidth, strokeOptions) {
|
|
4807
|
+
this._addCSSClasses(node, className);
|
|
4808
|
+
node.setAttribute("fill", fillMode && color ? color : "none");
|
|
4809
|
+
node.setAttribute("stroke", fillMode ? "none" : color || "none");
|
|
4687
4810
|
node.setAttribute("stroke-width", `${lineWidth || 1}`);
|
|
4688
4811
|
if (this.curId) {
|
|
4689
4812
|
node.setAttribute("id", `${this.curId}`); // Maybe React-style 'key' would be better?
|
|
4690
4813
|
}
|
|
4691
|
-
|
|
4692
|
-
// Attach to DOM only if not already attached
|
|
4693
|
-
this.bufferGNode.appendChild(node);
|
|
4694
|
-
}
|
|
4814
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
4695
4815
|
return node;
|
|
4696
4816
|
}
|
|
4697
4817
|
/**
|
|
@@ -4713,7 +4833,7 @@ class drawutilssvg {
|
|
|
4713
4833
|
* that under the hood the same gl context and gl program will be used.
|
|
4714
4834
|
*/
|
|
4715
4835
|
copyInstance(fillShapes) {
|
|
4716
|
-
var copy = new drawutilssvg(this.svgNode, this.offset, this.scale, this.canvasSize, fillShapes, null, // no DrawConfig
|
|
4836
|
+
var copy = new drawutilssvg(this.svgNode, this.offset, this.scale, this.canvasSize, fillShapes, null, // no DrawConfig – this will work as long as `isSecondary===true`
|
|
4717
4837
|
true, // isSecondary
|
|
4718
4838
|
this.gNode, this.bufferGNode, this.nodeDefs, this.bufferedNodeDefs);
|
|
4719
4839
|
return copy;
|
|
@@ -4728,6 +4848,20 @@ class drawutilssvg {
|
|
|
4728
4848
|
setConfiguration(configuration) {
|
|
4729
4849
|
this.drawlibConfiguration = configuration;
|
|
4730
4850
|
}
|
|
4851
|
+
// /**
|
|
4852
|
+
// * Set or clear the line-dash configuration. Pass `null` for un-dashed lines.
|
|
4853
|
+
// *
|
|
4854
|
+
// * See https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray
|
|
4855
|
+
// * and https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
|
|
4856
|
+
// * for how line dashes work.
|
|
4857
|
+
// *
|
|
4858
|
+
// * @method
|
|
4859
|
+
// * @param {Array<number> lineDashes - The line-dash array configuration.
|
|
4860
|
+
// * @returns {void}
|
|
4861
|
+
// */
|
|
4862
|
+
// setLineDash(lineDashes: Array<number>) {
|
|
4863
|
+
// this.lineDash = lineDashes;
|
|
4864
|
+
// }
|
|
4731
4865
|
/**
|
|
4732
4866
|
* This method shouled be called each time the currently drawn `Drawable` changes.
|
|
4733
4867
|
* It is used by some libraries for identifying elemente on re-renders.
|
|
@@ -4802,6 +4936,26 @@ class drawutilssvg {
|
|
|
4802
4936
|
this.nodeDefs = this.bufferedNodeDefs;
|
|
4803
4937
|
this.bufferedNodeDefs = tmpDefsNode;
|
|
4804
4938
|
}
|
|
4939
|
+
/**
|
|
4940
|
+
* A private helper method to apply stroke options to the current
|
|
4941
|
+
* context.
|
|
4942
|
+
* @param {StrokeOptions=} strokeOptions -
|
|
4943
|
+
*/
|
|
4944
|
+
applyStrokeOpts(node, strokeOptions) {
|
|
4945
|
+
if (strokeOptions &&
|
|
4946
|
+
strokeOptions.dashArray &&
|
|
4947
|
+
strokeOptions.dashArray.length > 0 &&
|
|
4948
|
+
drawutilssvg.nodeSupportsLineDash(node.tagName)) {
|
|
4949
|
+
node.setAttribute("stroke-dasharray", strokeOptions.dashArray
|
|
4950
|
+
.map((dashArayElem) => {
|
|
4951
|
+
return dashArayElem * this.scale.x;
|
|
4952
|
+
})
|
|
4953
|
+
.join(" "));
|
|
4954
|
+
if (strokeOptions.dashOffset) {
|
|
4955
|
+
node.setAttribute("stroke-dashoffset", `${strokeOptions.dashOffset * this.scale.x}`);
|
|
4956
|
+
}
|
|
4957
|
+
}
|
|
4958
|
+
}
|
|
4805
4959
|
_x(x) {
|
|
4806
4960
|
return this.offset.x + this.scale.x * x;
|
|
4807
4961
|
}
|
|
@@ -4812,47 +4966,101 @@ class drawutilssvg {
|
|
|
4812
4966
|
* Draw the line between the given two points with the specified (CSS-) color.
|
|
4813
4967
|
*
|
|
4814
4968
|
* @method line
|
|
4815
|
-
* @param {
|
|
4816
|
-
* @param {
|
|
4969
|
+
* @param {XYCoords} zA - The start point of the line.
|
|
4970
|
+
* @param {XYCoords} zB - The end point of the line.
|
|
4817
4971
|
* @param {string} color - Any valid CSS color string.
|
|
4818
4972
|
* @param {number=1} lineWidth? - [optional] The line's width.
|
|
4973
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
4974
|
+
*
|
|
4819
4975
|
* @return {void}
|
|
4820
4976
|
* @instance
|
|
4821
4977
|
* @memberof drawutilssvg
|
|
4822
4978
|
**/
|
|
4823
|
-
line(zA, zB, color, lineWidth) {
|
|
4824
|
-
const line = this.makeNode("line");
|
|
4825
|
-
|
|
4826
|
-
line.setAttribute("
|
|
4827
|
-
line.setAttribute("
|
|
4828
|
-
line.setAttribute("
|
|
4829
|
-
|
|
4979
|
+
line(zA, zB, color, lineWidth, strokeOptions) {
|
|
4980
|
+
// const line: SVGElement = this.makeNode("line");
|
|
4981
|
+
// this.applyStrokeOpts(line, strokeOptions);
|
|
4982
|
+
// line.setAttribute("x1", `${this._x(zA.x)}`);
|
|
4983
|
+
// line.setAttribute("y1", `${this._y(zA.y)}`);
|
|
4984
|
+
// line.setAttribute("x2", `${this._x(zB.x)}`);
|
|
4985
|
+
// line.setAttribute("y2", `${this._y(zB.y)}`);
|
|
4986
|
+
const line = this.makeLineNode(zA, zB, color, lineWidth, strokeOptions);
|
|
4987
|
+
return this._bindFillDraw(line, "line", color, lineWidth || 1, strokeOptions);
|
|
4830
4988
|
}
|
|
4831
4989
|
/**
|
|
4832
4990
|
* Draw a line and an arrow at the end (zB) of the given line with the specified (CSS-) color.
|
|
4833
4991
|
*
|
|
4834
4992
|
* @method arrow
|
|
4835
|
-
* @param {
|
|
4836
|
-
* @param {
|
|
4993
|
+
* @param {XYCoords} zA - The start point of the arrow-line.
|
|
4994
|
+
* @param {XYCoords} zB - The end point of the arrow-line.
|
|
4837
4995
|
* @param {string} color - Any valid CSS color string.
|
|
4838
4996
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
4997
|
+
* @param {headLength=8} headLength - (optional) The length of the arrow head (default is 8 units).
|
|
4998
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
4999
|
+
*
|
|
4839
5000
|
* @return {void}
|
|
4840
5001
|
* @instance
|
|
4841
5002
|
* @memberof drawutilssvg
|
|
4842
5003
|
**/
|
|
4843
|
-
arrow(zA, zB, color, lineWidth) {
|
|
4844
|
-
const
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
const
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
5004
|
+
arrow(zA, zB, color, lineWidth, headLength = 8, strokeOptions) {
|
|
5005
|
+
const group = this.makeNode("g");
|
|
5006
|
+
const arrowHeadBasePosition = { x: 0, y: 0 };
|
|
5007
|
+
// Just create the child nodes, don't bind them to the root node.
|
|
5008
|
+
const arrowHead = this.makeArrowHeadNode(zA, zB, color, lineWidth, headLength, undefined, arrowHeadBasePosition);
|
|
5009
|
+
const line = this.makeLineNode(zA, arrowHeadBasePosition, color, lineWidth, strokeOptions);
|
|
5010
|
+
group.appendChild(line);
|
|
5011
|
+
group.appendChild(arrowHead);
|
|
5012
|
+
this._addCSSClasses(group, "linear-arrow");
|
|
5013
|
+
this._bindNode(group, undefined);
|
|
5014
|
+
return group;
|
|
5015
|
+
}
|
|
5016
|
+
/**
|
|
5017
|
+
* Draw a cubic Bézier curve and and an arrow at the end (endControlPoint) of the given line width the specified (CSS-) color and arrow size.
|
|
5018
|
+
*
|
|
5019
|
+
* @method cubicBezierArrow
|
|
5020
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
5021
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
5022
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
5023
|
+
* @param {XYCoords} endControlPoint - The end control point the cubic Bézier curve.
|
|
5024
|
+
* @param {string} color - The CSS color to draw the curve with.
|
|
5025
|
+
* @param {number} lineWidth - (optional) The line width to use.
|
|
5026
|
+
* @param {headLength=8} headLength - (optional) The length of the arrow head (default is 8 units).
|
|
5027
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5028
|
+
*
|
|
5029
|
+
* @return {void}
|
|
5030
|
+
* @instance
|
|
5031
|
+
* @memberof DrawLib
|
|
5032
|
+
*/
|
|
5033
|
+
cubicBezierArrow(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, headLength = 8, strokeOptions) {
|
|
5034
|
+
const group = this.makeNode("g");
|
|
5035
|
+
// Just create the child nodes, don't bind them to the root node.
|
|
5036
|
+
const arrowHeadBasePosition = new Vertex(0, 0);
|
|
5037
|
+
const arrowHead = this.makeArrowHeadNode(endControlPoint, endPoint, color, lineWidth, headLength, undefined, arrowHeadBasePosition);
|
|
5038
|
+
const diff = arrowHeadBasePosition.difference(endPoint);
|
|
5039
|
+
const bezier = this.makeCubicBezierNode(startPoint, { x: endPoint.x - diff.x, y: endPoint.y - diff.y }, startControlPoint, { x: endControlPoint.x - diff.x, y: endControlPoint.y - diff.y }, color, lineWidth, strokeOptions);
|
|
5040
|
+
group.appendChild(bezier);
|
|
5041
|
+
group.appendChild(arrowHead);
|
|
5042
|
+
this._addCSSClasses(group, "cubicbezier-arrow");
|
|
5043
|
+
this._bindNode(group, undefined);
|
|
5044
|
+
return group;
|
|
5045
|
+
}
|
|
5046
|
+
/**
|
|
5047
|
+
* Draw just an arrow head a the end of an imaginary line (zB) of the given line width the specified (CSS-) color and size.
|
|
5048
|
+
*
|
|
5049
|
+
* @method arrow
|
|
5050
|
+
* @param {XYCoords} zA - The start point of the arrow-line.
|
|
5051
|
+
* @param {XYCoords} zB - The end point of the arrow-line.
|
|
5052
|
+
* @param {string} color - Any valid CSS color string.
|
|
5053
|
+
* @param {number=1} lineWidth - (optional) The line width to use; default is 1.
|
|
5054
|
+
* @param {number=8} headLength - (optional) The length of the arrow head (default is 8 pixels).
|
|
5055
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5056
|
+
*
|
|
5057
|
+
* @return {void}
|
|
5058
|
+
* @instance
|
|
5059
|
+
* @memberof DrawLib
|
|
5060
|
+
**/
|
|
5061
|
+
arrowHead(zA, zB, color, lineWidth, headLength = 8, strokeOptions) {
|
|
5062
|
+
const node = this.makeArrowHeadNode(zA, zB, color, lineWidth, headLength, strokeOptions);
|
|
5063
|
+
return this._bindFillDraw(node, "arrowhead", color, lineWidth || 1, strokeOptions);
|
|
4856
5064
|
}
|
|
4857
5065
|
/**
|
|
4858
5066
|
* Draw an image at the given position with the given size.<br>
|
|
@@ -4861,8 +5069,8 @@ class drawutilssvg {
|
|
|
4861
5069
|
*
|
|
4862
5070
|
* @method image
|
|
4863
5071
|
* @param {Image} image - The image object to draw.
|
|
4864
|
-
* @param {
|
|
4865
|
-
* @param {
|
|
5072
|
+
* @param {XYCoords} position - The position to draw the the upper left corner at.
|
|
5073
|
+
* @param {XYCoords} size - The x/y-size to draw the image with.
|
|
4866
5074
|
* @param {number=0.0} alpha - (optional, default=0.0) The transparency (1.0=opaque, 0.0=transparent).
|
|
4867
5075
|
* @return {void}
|
|
4868
5076
|
* @instance
|
|
@@ -4905,16 +5113,16 @@ class drawutilssvg {
|
|
|
4905
5113
|
* @param {Image} textureImage - The image object to draw.
|
|
4906
5114
|
* @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
|
|
4907
5115
|
* @param {Polygon} polygon - The polygon to use as clip path.
|
|
4908
|
-
* @param {
|
|
5116
|
+
* @param {XYCoords} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
|
|
4909
5117
|
* @param {number} rotation - The rotation to use for the polygon (and for the texture).
|
|
4910
5118
|
* @return {void}
|
|
4911
5119
|
* @instance
|
|
4912
5120
|
* @memberof drawutilssvg
|
|
4913
5121
|
**/
|
|
4914
5122
|
texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
|
|
4915
|
-
polygon.getBounds();
|
|
5123
|
+
// const basePolygonBounds: Bounds = polygon.getBounds();
|
|
4916
5124
|
const rotatedScalingOrigin = new Vertex(textureSize.min).clone().rotate(rotation, polygonPosition);
|
|
4917
|
-
polygonPosition.clone().add(rotatedScalingOrigin.difference(textureSize.min).inv());
|
|
5125
|
+
// const rotationCenter = polygonPosition.clone().add(rotatedScalingOrigin.difference(textureSize.min).inv());
|
|
4918
5126
|
// Create something like this
|
|
4919
5127
|
// ...
|
|
4920
5128
|
// <defs>
|
|
@@ -4968,36 +5176,21 @@ class drawutilssvg {
|
|
|
4968
5176
|
* Draw the given (cubic) bézier curve.
|
|
4969
5177
|
*
|
|
4970
5178
|
* @method cubicBezier
|
|
4971
|
-
* @param {
|
|
4972
|
-
* @param {
|
|
4973
|
-
* @param {
|
|
4974
|
-
* @param {
|
|
5179
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
5180
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
5181
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
5182
|
+
* @param {XYCoords} endControlPoint - The end control point the cubic Bézier curve.
|
|
4975
5183
|
* @param {string} color - The CSS color to draw the curve with.
|
|
4976
5184
|
* @param {number} lineWidth - (optional) The line width to use.
|
|
4977
|
-
* @
|
|
4978
|
-
*
|
|
4979
|
-
* @
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
// Draw curve
|
|
4987
|
-
const d = [
|
|
4988
|
-
"M",
|
|
4989
|
-
this._x(startPoint.x),
|
|
4990
|
-
this._y(startPoint.y),
|
|
4991
|
-
"C",
|
|
4992
|
-
this._x(startControlPoint.x),
|
|
4993
|
-
this._y(startControlPoint.y),
|
|
4994
|
-
this._x(endControlPoint.x),
|
|
4995
|
-
this._y(endControlPoint.y),
|
|
4996
|
-
this._x(endPoint.x),
|
|
4997
|
-
this._y(endPoint.y)
|
|
4998
|
-
];
|
|
4999
|
-
node.setAttribute("d", d.join(" "));
|
|
5000
|
-
return this._bindFillDraw(node, "cubicBezier", color, lineWidth);
|
|
5185
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5186
|
+
*
|
|
5187
|
+
* @return {void}
|
|
5188
|
+
* @instance
|
|
5189
|
+
* @memberof drawutilssvg
|
|
5190
|
+
*/
|
|
5191
|
+
cubicBezier(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, strokeOptions) {
|
|
5192
|
+
const node = this.makeCubicBezierNode(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, strokeOptions);
|
|
5193
|
+
return this._bindNode(node, undefined);
|
|
5001
5194
|
}
|
|
5002
5195
|
/**
|
|
5003
5196
|
* Draw the given (cubic) Bézier path.
|
|
@@ -5007,17 +5200,21 @@ class drawutilssvg {
|
|
|
5007
5200
|
* <pre> [ point1, point1_startControl, point2_endControl, point2, point2_startControl, point3_endControl, point3, ... pointN_endControl, pointN ]</pre>
|
|
5008
5201
|
*
|
|
5009
5202
|
* @method cubicBezierPath
|
|
5010
|
-
* @param {
|
|
5203
|
+
* @param {XYCoords[]} path - The cubic bezier path as described above.
|
|
5011
5204
|
* @param {string} color - The CSS colot to draw the path with.
|
|
5012
5205
|
* @param {number=1} lineWidth - (optional) The line width to use.
|
|
5206
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5207
|
+
*
|
|
5013
5208
|
* @return {void}
|
|
5014
5209
|
* @instance
|
|
5015
5210
|
* @memberof drawutilssvg
|
|
5016
5211
|
*/
|
|
5017
|
-
cubicBezierPath(path, color, lineWidth) {
|
|
5212
|
+
cubicBezierPath(path, color, lineWidth, strokeOptions) {
|
|
5018
5213
|
const node = this.makeNode("path");
|
|
5019
|
-
|
|
5214
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5215
|
+
if (!path || path.length == 0) {
|
|
5020
5216
|
return node;
|
|
5217
|
+
}
|
|
5021
5218
|
// Draw curve
|
|
5022
5219
|
const d = ["M", this._x(path[0].x), this._y(path[0].y)];
|
|
5023
5220
|
// Draw curve path
|
|
@@ -5054,20 +5251,20 @@ class drawutilssvg {
|
|
|
5054
5251
|
* Draw a handle line (with a light grey).
|
|
5055
5252
|
*
|
|
5056
5253
|
* @method handleLine
|
|
5057
|
-
* @param {
|
|
5058
|
-
* @param {
|
|
5254
|
+
* @param {XYCoords} startPoint - The start point to draw the handle at.
|
|
5255
|
+
* @param {XYCoords} endPoint - The end point to draw the handle at.
|
|
5059
5256
|
* @return {void}
|
|
5060
5257
|
* @instance
|
|
5061
5258
|
* @memberof drawutilssvg
|
|
5062
5259
|
*/
|
|
5063
5260
|
handleLine(startPoint, endPoint) {
|
|
5064
|
-
this.line(startPoint, endPoint, "rgb(
|
|
5261
|
+
this.line(startPoint, endPoint, "rgb(128,128,128,0.5)");
|
|
5065
5262
|
}
|
|
5066
5263
|
/**
|
|
5067
5264
|
* Draw a 1x1 dot with the specified (CSS-) color.
|
|
5068
5265
|
*
|
|
5069
5266
|
* @method dot
|
|
5070
|
-
* @param {
|
|
5267
|
+
* @param {XYCoords} p - The position to draw the dot at.
|
|
5071
5268
|
* @param {string} color - The CSS color to draw the dot with.
|
|
5072
5269
|
* @return {void}
|
|
5073
5270
|
* @instance
|
|
@@ -5075,13 +5272,17 @@ class drawutilssvg {
|
|
|
5075
5272
|
*/
|
|
5076
5273
|
dot(p, color) {
|
|
5077
5274
|
const node = this.makeNode("line");
|
|
5275
|
+
node.setAttribute("x1", `${this._x(p.x)}`);
|
|
5276
|
+
node.setAttribute("y1", `${this._y(p.y)}`);
|
|
5277
|
+
node.setAttribute("x2", `${this._x(p.x)}`);
|
|
5278
|
+
node.setAttribute("y2", `${this._y(p.y)}`);
|
|
5078
5279
|
return this._bindFillDraw(node, "dot", color, 1);
|
|
5079
5280
|
}
|
|
5080
5281
|
/**
|
|
5081
5282
|
* Draw the given point with the specified (CSS-) color and radius 3.
|
|
5082
5283
|
*
|
|
5083
5284
|
* @method point
|
|
5084
|
-
* @param {
|
|
5285
|
+
* @param {XYCoords} p - The position to draw the point at.
|
|
5085
5286
|
* @param {string} color - The CSS color to draw the point with.
|
|
5086
5287
|
* @return {void}
|
|
5087
5288
|
* @instance
|
|
@@ -5101,17 +5302,20 @@ class drawutilssvg {
|
|
|
5101
5302
|
* Note that if the x- and y- scales are different the result will be an ellipse rather than a circle.
|
|
5102
5303
|
*
|
|
5103
5304
|
* @method circle
|
|
5104
|
-
* @param {
|
|
5305
|
+
* @param {XYCoords} center - The center of the circle.
|
|
5105
5306
|
* @param {number} radius - The radius of the circle.
|
|
5106
5307
|
* @param {string} color - The CSS color to draw the circle with.
|
|
5107
5308
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
5309
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5310
|
+
*
|
|
5108
5311
|
* @return {void}
|
|
5109
5312
|
* @instance
|
|
5110
5313
|
* @memberof drawutilssvg
|
|
5111
5314
|
*/
|
|
5112
|
-
circle(center, radius, color, lineWidth) {
|
|
5315
|
+
circle(center, radius, color, lineWidth, strokeOptions) {
|
|
5113
5316
|
// Todo: draw ellipse when scalex!=scaley
|
|
5114
5317
|
const node = this.makeNode("circle");
|
|
5318
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5115
5319
|
node.setAttribute("cx", `${this._x(center.x)}`);
|
|
5116
5320
|
node.setAttribute("cy", `${this._y(center.y)}`);
|
|
5117
5321
|
node.setAttribute("r", `${radius * this.scale.x}`); // y?
|
|
@@ -5121,17 +5325,20 @@ class drawutilssvg {
|
|
|
5121
5325
|
* Draw a circular arc (section of a circle) with the given CSS color.
|
|
5122
5326
|
*
|
|
5123
5327
|
* @method circleArc
|
|
5124
|
-
* @param {
|
|
5328
|
+
* @param {XYCoords} center - The center of the circle.
|
|
5125
5329
|
* @param {number} radius - The radius of the circle.
|
|
5126
5330
|
* @param {number} startAngle - The angle to start at.
|
|
5127
5331
|
* @param {number} endAngle - The angle to end at.
|
|
5128
5332
|
* @param {string} color - The CSS color to draw the circle with.
|
|
5333
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5334
|
+
*
|
|
5129
5335
|
* @return {void}
|
|
5130
5336
|
* @instance
|
|
5131
5337
|
* @memberof drawutilssvg
|
|
5132
5338
|
*/
|
|
5133
|
-
circleArc(center, radius, startAngle, endAngle, color, lineWidth) {
|
|
5339
|
+
circleArc(center, radius, startAngle, endAngle, color, lineWidth, strokeOptions) {
|
|
5134
5340
|
const node = this.makeNode("path");
|
|
5341
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5135
5342
|
const arcData = CircleSector.circleSectorUtils.describeSVGArc(this._x(center.x), this._y(center.y), radius * this.scale.x, // y?
|
|
5136
5343
|
startAngle, endAngle);
|
|
5137
5344
|
node.setAttribute("d", arcData.join(" "));
|
|
@@ -5141,21 +5348,24 @@ class drawutilssvg {
|
|
|
5141
5348
|
* Draw an ellipse with the specified (CSS-) color and thw two radii.
|
|
5142
5349
|
*
|
|
5143
5350
|
* @method ellipse
|
|
5144
|
-
* @param {
|
|
5351
|
+
* @param {XYCoords} center - The center of the ellipse.
|
|
5145
5352
|
* @param {number} radiusX - The radius of the ellipse.
|
|
5146
5353
|
* @param {number} radiusY - The radius of the ellipse.
|
|
5147
5354
|
* @param {string} color - The CSS color to draw the ellipse with.
|
|
5148
5355
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
5149
5356
|
* @param {number=} rotation - (optional, default=0) The rotation of the ellipse.
|
|
5357
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5358
|
+
*
|
|
5150
5359
|
* @return {void}
|
|
5151
5360
|
* @instance
|
|
5152
5361
|
* @memberof drawutilssvg
|
|
5153
5362
|
*/
|
|
5154
|
-
ellipse(center, radiusX, radiusY, color, lineWidth, rotation) {
|
|
5363
|
+
ellipse(center, radiusX, radiusY, color, lineWidth, rotation, strokeOptions) {
|
|
5155
5364
|
if (typeof rotation === "undefined") {
|
|
5156
5365
|
rotation = 0.0;
|
|
5157
5366
|
}
|
|
5158
5367
|
const node = this.makeNode("ellipse");
|
|
5368
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5159
5369
|
node.setAttribute("cx", `${this._x(center.x)}`);
|
|
5160
5370
|
node.setAttribute("cy", `${this._y(center.y)}`);
|
|
5161
5371
|
node.setAttribute("rx", `${radiusX * this.scale.x}`);
|
|
@@ -5171,15 +5381,18 @@ class drawutilssvg {
|
|
|
5171
5381
|
*
|
|
5172
5382
|
* @method square
|
|
5173
5383
|
* @param {XYCoords} center - The center of the square.
|
|
5174
|
-
* @param {
|
|
5384
|
+
* @param {number} size - The size of the square.
|
|
5175
5385
|
* @param {string} color - The CSS color to draw the square with.
|
|
5176
5386
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
5177
|
-
* @
|
|
5387
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5388
|
+
*
|
|
5389
|
+
* @return {SVGElement}
|
|
5178
5390
|
* @instance
|
|
5179
5391
|
* @memberof drawutilssvg
|
|
5180
5392
|
*/
|
|
5181
|
-
square(center, size, color, lineWidth) {
|
|
5393
|
+
square(center, size, color, lineWidth, strokeOptions) {
|
|
5182
5394
|
const node = this.makeNode("rectangle");
|
|
5395
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5183
5396
|
node.setAttribute("x", `${this._x(center.x - size / 2.0)}`);
|
|
5184
5397
|
node.setAttribute("y", `${this._y(center.y - size / 2.0)}`);
|
|
5185
5398
|
node.setAttribute("width", `${size * this.scale.x}`);
|
|
@@ -5194,9 +5407,15 @@ class drawutilssvg {
|
|
|
5194
5407
|
* @param {number} height - The height of the rectangle.
|
|
5195
5408
|
* @param {string} color - The color to use.
|
|
5196
5409
|
* @param {number=1} lineWidth - (optional) The line with to use (default is 1).
|
|
5410
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5411
|
+
*
|
|
5412
|
+
* @return {SVGElement}
|
|
5413
|
+
* @instance
|
|
5414
|
+
* @memberof drawutilssvg
|
|
5197
5415
|
**/
|
|
5198
|
-
rect(position, width, height, color, lineWidth) {
|
|
5416
|
+
rect(position, width, height, color, lineWidth, strokeOptions) {
|
|
5199
5417
|
const node = this.makeNode("rect");
|
|
5418
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5200
5419
|
node.setAttribute("x", `${this._x(position.x)}`);
|
|
5201
5420
|
node.setAttribute("y", `${this._y(position.y)}`);
|
|
5202
5421
|
node.setAttribute("width", `${width * this.scale.x}`);
|
|
@@ -5207,7 +5426,7 @@ class drawutilssvg {
|
|
|
5207
5426
|
* Draw a grid of horizontal and vertical lines with the given (CSS-) color.
|
|
5208
5427
|
*
|
|
5209
5428
|
* @method grid
|
|
5210
|
-
* @param {
|
|
5429
|
+
* @param {XYCoords} center - The center of the grid.
|
|
5211
5430
|
* @param {number} width - The total width of the grid (width/2 each to the left and to the right).
|
|
5212
5431
|
* @param {number} height - The total height of the grid (height/2 each to the top and to the bottom).
|
|
5213
5432
|
* @param {number} sizeX - The horizontal grid size.
|
|
@@ -5241,7 +5460,7 @@ class drawutilssvg {
|
|
|
5241
5460
|
* This works analogue to the grid() function
|
|
5242
5461
|
*
|
|
5243
5462
|
* @method raster
|
|
5244
|
-
* @param {
|
|
5463
|
+
* @param {XYCoords} center - The center of the raster.
|
|
5245
5464
|
* @param {number} width - The total width of the raster (width/2 each to the left and to the right).
|
|
5246
5465
|
* @param {number} height - The total height of the raster (height/2 each to the top and to the bottom).
|
|
5247
5466
|
* @param {number} sizeX - The horizontal raster size.
|
|
@@ -5274,8 +5493,8 @@ class drawutilssvg {
|
|
|
5274
5493
|
* as even shaped diamonds.
|
|
5275
5494
|
*
|
|
5276
5495
|
* @method diamondHandle
|
|
5277
|
-
* @param {
|
|
5278
|
-
* @param {
|
|
5496
|
+
* @param {XYCoords} center - The center of the diamond.
|
|
5497
|
+
* @param {number} size - The x/y-size of the diamond.
|
|
5279
5498
|
* @param {string} color - The CSS color to draw the diamond with.
|
|
5280
5499
|
* @return {void}
|
|
5281
5500
|
* @instance
|
|
@@ -5309,8 +5528,8 @@ class drawutilssvg {
|
|
|
5309
5528
|
* as even shaped squares.
|
|
5310
5529
|
*
|
|
5311
5530
|
* @method squareHandle
|
|
5312
|
-
* @param {
|
|
5313
|
-
* @param {
|
|
5531
|
+
* @param {XYCoords} center - The center of the square.
|
|
5532
|
+
* @param {XYCoords} size - The x/y-size of the square.
|
|
5314
5533
|
* @param {string} color - The CSS color to draw the square with.
|
|
5315
5534
|
* @return {void}
|
|
5316
5535
|
* @instance
|
|
@@ -5332,7 +5551,7 @@ class drawutilssvg {
|
|
|
5332
5551
|
* as even shaped circles.
|
|
5333
5552
|
*
|
|
5334
5553
|
* @method circleHandle
|
|
5335
|
-
* @param {
|
|
5554
|
+
* @param {XYCoords} center - The center of the circle.
|
|
5336
5555
|
* @param {number} radius - The radius of the circle.
|
|
5337
5556
|
* @param {string} color - The CSS color to draw the circle with.
|
|
5338
5557
|
* @return {void}
|
|
@@ -5431,18 +5650,22 @@ class drawutilssvg {
|
|
|
5431
5650
|
* Draw a polygon line (alternative function to the polygon).
|
|
5432
5651
|
*
|
|
5433
5652
|
* @method polyline
|
|
5434
|
-
* @param {
|
|
5653
|
+
* @param {XYCoords[]} vertices - The polygon vertices to draw.
|
|
5435
5654
|
* @param {boolan} isOpen - If true the polyline will not be closed at its end.
|
|
5436
5655
|
* @param {string} color - The CSS color to draw the polygon with.
|
|
5437
5656
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
5657
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5658
|
+
*
|
|
5438
5659
|
* @return {void}
|
|
5439
5660
|
* @instance
|
|
5440
5661
|
* @memberof drawutilssvg
|
|
5441
5662
|
*/
|
|
5442
|
-
polyline(vertices, isOpen, color, lineWidth) {
|
|
5663
|
+
polyline(vertices, isOpen, color, lineWidth, strokeOptions) {
|
|
5443
5664
|
const node = this.makeNode("path");
|
|
5444
|
-
|
|
5665
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5666
|
+
if (vertices.length == 0) {
|
|
5445
5667
|
return node;
|
|
5668
|
+
}
|
|
5446
5669
|
// Draw curve
|
|
5447
5670
|
const d = ["M", this._x(vertices[0].x), this._y(vertices[0].y)];
|
|
5448
5671
|
var n = vertices.length;
|
|
@@ -5545,12 +5768,16 @@ class drawutilssvg {
|
|
|
5545
5768
|
* @param {string=null} color - (optional) The color to draw this path with (default is null).
|
|
5546
5769
|
* @param {number=1} lineWidth - (optional) the line width to use (default is 1).
|
|
5547
5770
|
* @param {boolean=false} options.inplace - (optional) If set to true then path transforamtions (scale and translate) will be done in-place in the array. This can boost the performance.
|
|
5771
|
+
* @param {number=} options.dashOffset - (optional) `See StrokeOptions`.
|
|
5772
|
+
* @param {number=[]} options.dashArray - (optional) `See StrokeOptions`.
|
|
5773
|
+
*
|
|
5548
5774
|
* @instance
|
|
5549
5775
|
* @memberof drawutils
|
|
5550
5776
|
* @return {R} An instance representing the drawn path.
|
|
5551
5777
|
*/
|
|
5552
5778
|
path(pathData, color, lineWidth, options) {
|
|
5553
5779
|
const node = this.makeNode("path");
|
|
5780
|
+
this.applyStrokeOpts(node, options);
|
|
5554
5781
|
// Transform the path: in-place (fast) or copy (slower)
|
|
5555
5782
|
const d = options && options.inplace ? pathData : drawutilssvg.copyPathData(pathData);
|
|
5556
5783
|
drawutilssvg.transformPathData(d, this.offset, this.scale);
|
|
@@ -5576,7 +5803,7 @@ class drawutilssvg {
|
|
|
5576
5803
|
}
|
|
5577
5804
|
// Add a covering rect with the given background color
|
|
5578
5805
|
this.curId = "background";
|
|
5579
|
-
this.curClassName = undefined;
|
|
5806
|
+
this.curClassName = null; // undefined;
|
|
5580
5807
|
const node = this.makeNode("rect");
|
|
5581
5808
|
// For some strange reason SVG rotation transforms use degrees instead of radians
|
|
5582
5809
|
// Note that the background does not scale with the zoom level (always covers full element)
|
|
@@ -5588,7 +5815,7 @@ class drawutilssvg {
|
|
|
5588
5815
|
this._bindFillDraw(node, this.curId, null, null);
|
|
5589
5816
|
node.setAttribute("fill", typeof color === "undefined" ? "none" : color);
|
|
5590
5817
|
// Clear the current ID again
|
|
5591
|
-
this.curId = undefined;
|
|
5818
|
+
this.curId = null; // undefined;
|
|
5592
5819
|
}
|
|
5593
5820
|
/**
|
|
5594
5821
|
* A private helper function to clear all SVG nodes from the >g> node.
|
|
@@ -5792,6 +6019,126 @@ class drawutilssvg {
|
|
|
5792
6019
|
}
|
|
5793
6020
|
} // END while
|
|
5794
6021
|
} // END transformPathData
|
|
6022
|
+
static nodeSupportsLineDash(nodeName) {
|
|
6023
|
+
return ["line", "path", "circle", "ellipse", "rectangle", "rect"].includes(nodeName);
|
|
6024
|
+
}
|
|
6025
|
+
/**
|
|
6026
|
+
* Creates a basic <line> node with start and end coordinates. The created node will not
|
|
6027
|
+
* be bound to any root node.
|
|
6028
|
+
*
|
|
6029
|
+
* @private
|
|
6030
|
+
* @method makeLineNode
|
|
6031
|
+
* @param {XYCoords} zA - The line's start position.
|
|
6032
|
+
* @param {XYCoords} zB - The line's start position.
|
|
6033
|
+
* @param {string} color - The CSS color to draw the point with.
|
|
6034
|
+
* @param {number=1} lineWidth - (optional) The line width to use.
|
|
6035
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Additional stroke options to use.
|
|
6036
|
+
* @param {string=} classNameOverride - (optional) If nothing is passed the default classname 'path' will be used.
|
|
6037
|
+
* @return {SVGLineElement}
|
|
6038
|
+
* @instance
|
|
6039
|
+
* @memberof drawutilssvg
|
|
6040
|
+
*/
|
|
6041
|
+
makeLineNode(zA, zB, color, lineWidth, strokeOptions, classNameOverride) {
|
|
6042
|
+
const line = this.makeNode("line");
|
|
6043
|
+
line.setAttribute("x1", `${this._x(zA.x)}`);
|
|
6044
|
+
line.setAttribute("y1", `${this._y(zA.y)}`);
|
|
6045
|
+
line.setAttribute("x2", `${this._x(zB.x)}`);
|
|
6046
|
+
line.setAttribute("y2", `${this._y(zB.y)}`);
|
|
6047
|
+
this._configureNode(line, classNameOverride !== null && classNameOverride !== void 0 ? classNameOverride : "line", this.fillShapes, color, lineWidth || 1, strokeOptions);
|
|
6048
|
+
return line;
|
|
6049
|
+
}
|
|
6050
|
+
/**
|
|
6051
|
+
* Creates a basic <path> node with given path string data. The created node will not
|
|
6052
|
+
* be bound to any root node.
|
|
6053
|
+
*
|
|
6054
|
+
* @private
|
|
6055
|
+
* @method makePathNode
|
|
6056
|
+
* @param {string} pathString - The path data (must be a valid path data string).
|
|
6057
|
+
* @param {string} color - The CSS color to draw the point with.
|
|
6058
|
+
* @param {number=1} lineWidth - (optional) The line width to use.
|
|
6059
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Additional stroke options to use.
|
|
6060
|
+
* @param {string=} classNameOverride - (optional) If nothing is passed the default classname 'path' will be used.
|
|
6061
|
+
* @return {SVGPathElement}
|
|
6062
|
+
* @instance
|
|
6063
|
+
* @memberof drawutilssvg
|
|
6064
|
+
*/
|
|
6065
|
+
makePathNode(pathString, color, lineWidth, strokeOptions, classNameOverride) {
|
|
6066
|
+
const path = this.makeNode("path");
|
|
6067
|
+
path.setAttribute("d", pathString);
|
|
6068
|
+
this._configureNode(path, classNameOverride !== null && classNameOverride !== void 0 ? classNameOverride : "path", this.fillShapes, color, lineWidth || 1, strokeOptions);
|
|
6069
|
+
return path;
|
|
6070
|
+
}
|
|
6071
|
+
/**
|
|
6072
|
+
* Creates a basic arrow head node (<path> node) at the end of the given line coordinates. The created node will not
|
|
6073
|
+
* be bound to any root node.
|
|
6074
|
+
*
|
|
6075
|
+
* @private
|
|
6076
|
+
* @method makeArrowHeadNode
|
|
6077
|
+
* @param {string} pathString - The path data (must be a valid path data string).
|
|
6078
|
+
* @param {string} color - The CSS color to draw the point with.
|
|
6079
|
+
* @param {number=1} lineWidth - (optional) The line width to use.
|
|
6080
|
+
* @param {number=8} headLength - (optional) The length of the arrow head; if none is specified then the head will be 8 absolute units long.
|
|
6081
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Additional stroke options to use.
|
|
6082
|
+
* @param {XYCoords=} arrowHeadBasePositionBuffer - (optional) If not null, then this position will contain the arrow head's start point (after execution). Some sort of OUT variable.
|
|
6083
|
+
* @return {SVGPathElement}
|
|
6084
|
+
* @instance
|
|
6085
|
+
* @memberof drawutilssvg
|
|
6086
|
+
*/
|
|
6087
|
+
makeArrowHeadNode(zA, zB, color, lineWidth, headLength = 8, strokeOptions, arrowHeadBasePositionBuffer) {
|
|
6088
|
+
var vertices = Vector.utils.buildArrowHead(zA, zB, headLength, this.scale.x, this.scale.y);
|
|
6089
|
+
const d = ["M", this.offset.x + vertices[0].x, this.offset.y + vertices[0].y];
|
|
6090
|
+
if (arrowHeadBasePositionBuffer) {
|
|
6091
|
+
arrowHeadBasePositionBuffer.x = vertices[0].x / this.scale.x;
|
|
6092
|
+
arrowHeadBasePositionBuffer.y = vertices[0].y / this.scale.y;
|
|
6093
|
+
}
|
|
6094
|
+
for (var i = 1; i <= vertices.length; i++) {
|
|
6095
|
+
d.push("L");
|
|
6096
|
+
// Note: only use offset here (the vertices are already scaled)
|
|
6097
|
+
d.push(this.offset.x + vertices[i % vertices.length].x);
|
|
6098
|
+
d.push(this.offset.y + vertices[i % vertices.length].y);
|
|
6099
|
+
}
|
|
6100
|
+
const node = this.makePathNode(d.join(" "), color, lineWidth, strokeOptions, "arrowhead");
|
|
6101
|
+
return node;
|
|
6102
|
+
}
|
|
6103
|
+
/**
|
|
6104
|
+
* Creates a basic cubic Bézier path node (<path> node) with the given cubic Bézier data. The created node will not
|
|
6105
|
+
* be bound to any root node.
|
|
6106
|
+
*
|
|
6107
|
+
* @private
|
|
6108
|
+
* @method makeCubicBezierNode
|
|
6109
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
6110
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
6111
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
6112
|
+
* @param {XYCoords} endControlPoint - The end control point the cubic Bézier curve.
|
|
6113
|
+
* @param {string} color - The CSS color to draw the point with.
|
|
6114
|
+
* @param {number=1} lineWidth - (optional) The line width to use.
|
|
6115
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Additional stroke options to use.
|
|
6116
|
+
* @param {string=} classNameOverride - (optional) If nothing is passed the default classname 'path' will be used.
|
|
6117
|
+
* @param {XYCoords=} arrowHeadBasePositionBuffer - (optional) If not null, then this position will contain the arrow head's start point (after execution). Some sort of OUT variable.
|
|
6118
|
+
* @return {SVGPathElement}
|
|
6119
|
+
* @instance
|
|
6120
|
+
* @memberof drawutilssvg
|
|
6121
|
+
*/
|
|
6122
|
+
makeCubicBezierNode(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, strokeOptions) {
|
|
6123
|
+
if (startPoint instanceof CubicBezierCurve) {
|
|
6124
|
+
return this.cubicBezier(startPoint.startPoint, startPoint.endPoint, startPoint.startControlPoint, startPoint.endControlPoint, color, lineWidth);
|
|
6125
|
+
}
|
|
6126
|
+
// Draw curve
|
|
6127
|
+
const d = [
|
|
6128
|
+
"M",
|
|
6129
|
+
this._x(startPoint.x),
|
|
6130
|
+
this._y(startPoint.y),
|
|
6131
|
+
"C",
|
|
6132
|
+
this._x(startControlPoint.x),
|
|
6133
|
+
this._y(startControlPoint.y),
|
|
6134
|
+
this._x(endControlPoint.x),
|
|
6135
|
+
this._y(endControlPoint.y),
|
|
6136
|
+
this._x(endPoint.x),
|
|
6137
|
+
this._y(endPoint.y)
|
|
6138
|
+
];
|
|
6139
|
+
const node = this.makePathNode(d.join(" "), color, lineWidth, strokeOptions, "cubicBezier");
|
|
6140
|
+
return node;
|
|
6141
|
+
}
|
|
5795
6142
|
}
|
|
5796
6143
|
drawutilssvg.HEAD_XML = [
|
|
5797
6144
|
'<?xml version="1.0" encoding="UTF-8" standalone="no"?>',
|
|
@@ -5850,7 +6197,15 @@ drawutilssvg.HEAD_XML = [
|
|
|
5850
6197
|
* @modified 2022-08-23 Fixed a type issue in the `setConfiguration` function.
|
|
5851
6198
|
* @modified 2022-08-23 Fixed a type issue in the `path` function.
|
|
5852
6199
|
* @modified 2023-02-10 The methods `setCurrentClassName` and `setCurrentId` also accept `null` now.
|
|
5853
|
-
* @
|
|
6200
|
+
* @modified 2023-09-29 Removed unused method stub for texturedPoly helper function (cleanup).
|
|
6201
|
+
* @modified 2023-09-29 Downgrading all `Vertex` param type to the more generic `XYCoords` type in these render functions: line, arrow, texturedPoly, cubicBezier, cubicBezierPath, handle, handleLine, dot, point, circle, circleArc, ellipse, grid, raster.
|
|
6202
|
+
* @modified 2023-09-29 Added the `headLength` parameter to the 'DrawLib.arrow()` function.
|
|
6203
|
+
* @modified 2023-09-29 Added the `arrowHead(...)` function to the 'DrawLib.arrow()` interface.
|
|
6204
|
+
* @modified 2023-09-29 Added the `cubicBezierArrow(...)` function to the 'DrawLib.arrow()` interface.
|
|
6205
|
+
* @modified 2023-09-29 Added the `lineDashes` attribute.
|
|
6206
|
+
* @modified 2023-09-30 Adding `strokeOptions` param to these draw function: line, arrow, cubicBezierArrow, cubicBezier, cubicBezierPath, circle, circleArc, ellipse, square, rect, polygon, polyline.
|
|
6207
|
+
* @modified 2023-10-07 Adding the optional `arrowHeadBasePositionBuffer` param to the arrowHead(...) method.
|
|
6208
|
+
* @version 1.13.0
|
|
5854
6209
|
**/
|
|
5855
6210
|
// Todo: rename this class to Drawutils?
|
|
5856
6211
|
/**
|
|
@@ -5872,10 +6227,47 @@ class drawutils {
|
|
|
5872
6227
|
**/
|
|
5873
6228
|
constructor(context, fillShapes) {
|
|
5874
6229
|
this.ctx = context;
|
|
6230
|
+
// this.lineDash = [];
|
|
5875
6231
|
this.offset = new Vertex(0, 0);
|
|
5876
6232
|
this.scale = new Vertex(1, 1);
|
|
5877
6233
|
this.fillShapes = fillShapes;
|
|
5878
6234
|
}
|
|
6235
|
+
/**
|
|
6236
|
+
* A private helper method to apply stroke options to the current
|
|
6237
|
+
* context.
|
|
6238
|
+
* @param {StrokeOptions=} strokeOptions -
|
|
6239
|
+
*/
|
|
6240
|
+
applyStrokeOpts(strokeOptions) {
|
|
6241
|
+
var _a, _b;
|
|
6242
|
+
this.ctx.setLineDash(((_a = strokeOptions === null || strokeOptions === void 0 ? void 0 : strokeOptions.dashArray) !== null && _a !== void 0 ? _a : []).map((dashArrayElem) => {
|
|
6243
|
+
// Note assume scale.x === scale.y
|
|
6244
|
+
// Invariant scale makes funny stuff anyway.
|
|
6245
|
+
return dashArrayElem * this.scale.x;
|
|
6246
|
+
}));
|
|
6247
|
+
this.ctx.lineDashOffset = ((_b = strokeOptions === null || strokeOptions === void 0 ? void 0 : strokeOptions.dashOffset) !== null && _b !== void 0 ? _b : 0) * this.scale.x;
|
|
6248
|
+
}
|
|
6249
|
+
// +---------------------------------------------------------------------------------
|
|
6250
|
+
// | This is the final helper function for drawing and filling stuff. It is not
|
|
6251
|
+
// | intended to be used from the outside.
|
|
6252
|
+
// |
|
|
6253
|
+
// | When in draw mode it draws the current shape.
|
|
6254
|
+
// | When in fill mode it fills the current shape.
|
|
6255
|
+
// |
|
|
6256
|
+
// | This function is usually only called internally.
|
|
6257
|
+
// |
|
|
6258
|
+
// | @param color A stroke/fill color to use.
|
|
6259
|
+
// +-------------------------------
|
|
6260
|
+
// TODO: convert this to a STATIC function.
|
|
6261
|
+
_fillOrDraw(color) {
|
|
6262
|
+
if (this.fillShapes) {
|
|
6263
|
+
this.ctx.fillStyle = color;
|
|
6264
|
+
this.ctx.fill();
|
|
6265
|
+
}
|
|
6266
|
+
else {
|
|
6267
|
+
this.ctx.strokeStyle = color;
|
|
6268
|
+
this.ctx.stroke();
|
|
6269
|
+
}
|
|
6270
|
+
}
|
|
5879
6271
|
/**
|
|
5880
6272
|
* Called before each draw cycle.
|
|
5881
6273
|
* @param {UID=} uid - (optional) A UID identifying the currently drawn element(s).
|
|
@@ -5906,6 +6298,20 @@ class drawutils {
|
|
|
5906
6298
|
setConfiguration(configuration) {
|
|
5907
6299
|
this.ctx.globalCompositeOperation = configuration.blendMode || "source-over";
|
|
5908
6300
|
}
|
|
6301
|
+
// /**
|
|
6302
|
+
// * Set or clear the line-dash configuration. Pass `null` for un-dashed lines.
|
|
6303
|
+
// *
|
|
6304
|
+
// * See https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray
|
|
6305
|
+
// * and https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
|
|
6306
|
+
// * for how line dashes work.
|
|
6307
|
+
// *
|
|
6308
|
+
// * @method
|
|
6309
|
+
// * @param {Array<number> lineDashes - The line-dash array configuration.
|
|
6310
|
+
// * @returns {void}
|
|
6311
|
+
// */
|
|
6312
|
+
// setLineDash(lineDash: Array<number>) {
|
|
6313
|
+
// this.lineDash = lineDash;
|
|
6314
|
+
// }
|
|
5909
6315
|
/**
|
|
5910
6316
|
* This method shouled be called each time the currently drawn `Drawable` changes.
|
|
5911
6317
|
* It is used by some libraries for identifying elemente on re-renders.
|
|
@@ -5932,17 +6338,20 @@ class drawutils {
|
|
|
5932
6338
|
* Draw the line between the given two points with the specified (CSS-) color.
|
|
5933
6339
|
*
|
|
5934
6340
|
* @method line
|
|
5935
|
-
* @param {
|
|
5936
|
-
* @param {
|
|
6341
|
+
* @param {XYCoords} zA - The start point of the line.
|
|
6342
|
+
* @param {XYCoords} zB - The end point of the line.
|
|
5937
6343
|
* @param {string} color - Any valid CSS color string.
|
|
5938
6344
|
* @param {number} lineWidth? - [optional] The line's width.
|
|
6345
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6346
|
+
*
|
|
5939
6347
|
* @return {void}
|
|
5940
6348
|
* @instance
|
|
5941
6349
|
* @memberof drawutils
|
|
5942
6350
|
**/
|
|
5943
|
-
line(zA, zB, color, lineWidth) {
|
|
6351
|
+
line(zA, zB, color, lineWidth, strokeOptions) {
|
|
5944
6352
|
this.ctx.save();
|
|
5945
6353
|
this.ctx.beginPath();
|
|
6354
|
+
this.applyStrokeOpts(strokeOptions);
|
|
5946
6355
|
this.ctx.moveTo(this.offset.x + zA.x * this.scale.x, this.offset.y + zA.y * this.scale.y);
|
|
5947
6356
|
this.ctx.lineTo(this.offset.x + zB.x * this.scale.x, this.offset.y + zB.y * this.scale.y);
|
|
5948
6357
|
this.ctx.strokeStyle = color;
|
|
@@ -5954,22 +6363,74 @@ class drawutils {
|
|
|
5954
6363
|
* Draw a line and an arrow at the end (zB) of the given line with the specified (CSS-) color.
|
|
5955
6364
|
*
|
|
5956
6365
|
* @method arrow
|
|
5957
|
-
* @param {
|
|
5958
|
-
* @param {
|
|
6366
|
+
* @param {XYCoords} zA - The start point of the arrow-line.
|
|
6367
|
+
* @param {XYCoords} zB - The end point of the arrow-line.
|
|
5959
6368
|
* @param {string} color - Any valid CSS color string.
|
|
5960
6369
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
6370
|
+
* @param {headLength=8} headLength - (optional) The length of the arrow head (default is 8 units).
|
|
6371
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6372
|
+
*
|
|
5961
6373
|
* @return {void}
|
|
5962
6374
|
* @instance
|
|
5963
6375
|
* @memberof drawutils
|
|
5964
6376
|
**/
|
|
5965
|
-
arrow(zA, zB, color, lineWidth) {
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
6377
|
+
arrow(zA, zB, color, lineWidth, headLength = 8, strokeOptions) {
|
|
6378
|
+
const arrowHeadBasePosition = new Vertex(0, 0);
|
|
6379
|
+
this.arrowHead(zA, zB, color, lineWidth, headLength, undefined, arrowHeadBasePosition); // Will NOT use dash configuration
|
|
6380
|
+
this.line(zA, arrowHeadBasePosition, color, lineWidth, strokeOptions); // Will use dash configuration
|
|
6381
|
+
}
|
|
6382
|
+
/**
|
|
6383
|
+
* Draw a cubic Bézier curve and and an arrow at the end (endControlPoint) of the given line width the specified (CSS-) color and arrow size.
|
|
6384
|
+
*
|
|
6385
|
+
* @method cubicBezierArrow
|
|
6386
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
6387
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
6388
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
6389
|
+
* @param {XYCoords} endControlPoint - The end control point the cubic Bézier curve.
|
|
6390
|
+
* @param {string} color - The CSS color to draw the curve with.
|
|
6391
|
+
* @param {number} lineWidth - (optional) The line width to use.
|
|
6392
|
+
* @param {headLength=8} headLength - (optional) The length of the arrow head (default is 8 units).
|
|
6393
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6394
|
+
*
|
|
6395
|
+
* @return {void}
|
|
6396
|
+
* @instance
|
|
6397
|
+
* @memberof DrawLib
|
|
6398
|
+
*/
|
|
6399
|
+
cubicBezierArrow(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, headLength, strokeOptions) {
|
|
6400
|
+
const arrowHeadBasePosition = new Vertex(0, 0);
|
|
6401
|
+
// Will NOT use dash configuration
|
|
6402
|
+
this.arrowHead(endControlPoint, endPoint, color, lineWidth, headLength, undefined, arrowHeadBasePosition);
|
|
6403
|
+
const diff = arrowHeadBasePosition.difference(endPoint);
|
|
6404
|
+
// Will use dash configuration
|
|
6405
|
+
this.cubicBezier(startPoint, { x: endPoint.x - diff.x, y: endPoint.y - diff.y }, startControlPoint, { x: endControlPoint.x - diff.x, y: endControlPoint.y - diff.y }, color, lineWidth, strokeOptions);
|
|
6406
|
+
}
|
|
6407
|
+
/**
|
|
6408
|
+
* Draw just an arrow head a the end of an imaginary line (zB) of the given line width the specified (CSS-) color and size.
|
|
6409
|
+
*
|
|
6410
|
+
* @method arrow
|
|
6411
|
+
* @param {XYCoords} zA - The start point of the arrow-line.
|
|
6412
|
+
* @param {XYCoords} zB - The end point of the arrow-line.
|
|
6413
|
+
* @param {string} color - Any valid CSS color string.
|
|
6414
|
+
* @param {number=1} lineWidth - (optional) The line width to use; default is 1.
|
|
6415
|
+
* @param {number=8} headLength - (optional) The length of the arrow head (default is 8 pixels).
|
|
6416
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6417
|
+
* @param {XYCoords=} arrowHeadBasePositionBuffer - (optional) If not null, then this position will contain the arrow head's start point (after execution). Some sort of OUT variable.
|
|
6418
|
+
*
|
|
6419
|
+
* @return {void}
|
|
6420
|
+
* @instance
|
|
6421
|
+
* @memberof DrawLib
|
|
6422
|
+
**/
|
|
6423
|
+
arrowHead(zA, zB, color, lineWidth, headLength = 8, strokeOptions, arrowHeadBasePositionBuffer) {
|
|
6424
|
+
// var headLength: number = 8; // length of head in pixels
|
|
5969
6425
|
this.ctx.save();
|
|
5970
6426
|
this.ctx.beginPath();
|
|
5971
|
-
|
|
5972
|
-
|
|
6427
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6428
|
+
var vertices = Vector.utils.buildArrowHead(zA, zB, headLength, this.scale.x, this.scale.y);
|
|
6429
|
+
if (arrowHeadBasePositionBuffer) {
|
|
6430
|
+
arrowHeadBasePositionBuffer.x = vertices[0].x / this.scale.x;
|
|
6431
|
+
arrowHeadBasePositionBuffer.y = vertices[0].y / this.scale.y;
|
|
6432
|
+
}
|
|
6433
|
+
this.ctx.moveTo(this.offset.x + vertices[0].x, this.offset.y + vertices[0].y);
|
|
5973
6434
|
for (var i = 0; i < vertices.length; i++) {
|
|
5974
6435
|
this.ctx.lineTo(this.offset.x + vertices[i].x, this.offset.y + vertices[i].y);
|
|
5975
6436
|
}
|
|
@@ -5985,8 +6446,8 @@ class drawutils {
|
|
|
5985
6446
|
*
|
|
5986
6447
|
* @method image
|
|
5987
6448
|
* @param {Image} image - The image object to draw.
|
|
5988
|
-
* @param {
|
|
5989
|
-
* @param {
|
|
6449
|
+
* @param {XYCoords} position - The position to draw the the upper left corner at.
|
|
6450
|
+
* @param {XYCoords} size - The x/y-size to draw the image with.
|
|
5990
6451
|
* @param {number=0.0} alpha - (optional, default=0.0) The transparency (1.0=opaque, 0.0=transparent).
|
|
5991
6452
|
* @return {void}
|
|
5992
6453
|
* @instance
|
|
@@ -6015,7 +6476,7 @@ class drawutils {
|
|
|
6015
6476
|
* @param {Image} textureImage - The image object to draw.
|
|
6016
6477
|
* @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
|
|
6017
6478
|
* @param {Polygon} polygon - The polygon to use as clip path.
|
|
6018
|
-
* @param {
|
|
6479
|
+
* @param {XYCoords} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
|
|
6019
6480
|
* @param {number} rotation - The rotation to use for the polygon (and for the texture).
|
|
6020
6481
|
* @param {XYCoords={x:0,y:0}} rotationCenter - (optional) The rotational center; default is center of bounding box.
|
|
6021
6482
|
* @return {void}
|
|
@@ -6024,10 +6485,9 @@ class drawutils {
|
|
|
6024
6485
|
**/
|
|
6025
6486
|
texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
|
|
6026
6487
|
var basePolygonBounds = polygon.getBounds();
|
|
6027
|
-
var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
|
|
6028
|
-
|
|
6029
|
-
// var
|
|
6030
|
-
basePolygonBounds.getCenter().sub(targetCenterDifference);
|
|
6488
|
+
// var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
|
|
6489
|
+
new Vertex(polygonPosition.x, polygonPosition.y).difference(basePolygonBounds.getCenter());
|
|
6490
|
+
// var tileCenter = basePolygonBounds.getCenter().sub(targetCenterDifference);
|
|
6031
6491
|
// Get the position offset of the polygon
|
|
6032
6492
|
var targetTextureSize = new Vertex(textureSize.width, textureSize.height);
|
|
6033
6493
|
// var targetTextureOffset = new Vertex(-textureSize.width / 2, -textureSize.height / 2).sub(targetCenterDifference);
|
|
@@ -6050,52 +6510,83 @@ class drawutils {
|
|
|
6050
6510
|
);
|
|
6051
6511
|
this.ctx.restore();
|
|
6052
6512
|
}
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6513
|
+
/*
|
|
6514
|
+
_texturedPoly(
|
|
6515
|
+
textureImage: HTMLImageElement,
|
|
6516
|
+
textureSize: Bounds,
|
|
6517
|
+
polygon: Polygon,
|
|
6518
|
+
polygonPosition: XYCoords,
|
|
6519
|
+
rotation: number,
|
|
6520
|
+
rotationCenter: XYCoords = { x: 0, y: 0 }
|
|
6521
|
+
): void {
|
|
6522
|
+
var basePolygonBounds = polygon.getBounds();
|
|
6523
|
+
var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
|
|
6524
|
+
var rotationalOffset = rotationCenter ? polygonPosition.difference(rotationCenter) : { x: 0, y: 0 };
|
|
6525
|
+
// var rotationalOffset = { x: 0, y: 0 };
|
|
6526
|
+
var tileCenter = basePolygonBounds.getCenter().sub(targetCenterDifference);
|
|
6527
|
+
|
|
6528
|
+
// Get the position offset of the polygon
|
|
6529
|
+
var targetTextureSize = new Vertex(textureSize.width, textureSize.height);
|
|
6530
|
+
var targetTextureOffset = new Vertex(-textureSize.width / 2, -textureSize.height / 2).sub(targetCenterDifference);
|
|
6531
|
+
|
|
6532
|
+
this.ctx.save();
|
|
6533
|
+
|
|
6534
|
+
// this.ctx.translate(
|
|
6535
|
+
// this.offset.x + (tileCenter.x - rotationalOffset.x * 0 + targetTextureOffset.x * 0.0) * this.scale.x,
|
|
6536
|
+
// this.offset.y + (tileCenter.y - rotationalOffset.y * 0 + targetTextureOffset.y * 0.0) * this.scale.y
|
|
6537
|
+
// );
|
|
6538
|
+
this.ctx.translate(
|
|
6539
|
+
this.offset.x + (tileCenter.x - rotationalOffset.x * 0 + targetTextureOffset.x * 0.0) * this.scale.x,
|
|
6540
|
+
this.offset.y + (tileCenter.y - rotationalOffset.y * 0 + targetTextureOffset.y * 0.0) * this.scale.y
|
|
6541
|
+
);
|
|
6542
|
+
this.ctx.rotate(rotation);
|
|
6543
|
+
|
|
6544
|
+
drawutils.helpers.clipPoly(
|
|
6545
|
+
this.ctx,
|
|
6546
|
+
{
|
|
6547
|
+
x: (-targetCenterDifference.x * 1 - tileCenter.x - rotationalOffset.x) * this.scale.x,
|
|
6548
|
+
y: (-targetCenterDifference.y * 1 - tileCenter.y - rotationalOffset.y) * this.scale.y
|
|
6549
|
+
},
|
|
6550
|
+
this.scale,
|
|
6551
|
+
polygon.vertices
|
|
6552
|
+
);
|
|
6553
|
+
this.ctx.drawImage(
|
|
6554
|
+
textureImage,
|
|
6555
|
+
0,
|
|
6556
|
+
0,
|
|
6557
|
+
textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
|
|
6074
6558
|
textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
|
|
6075
|
-
(-polygonPosition.x + targetTextureOffset.x * 1 - rotationalOffset.x * 1) * this.scale.x,
|
|
6076
|
-
|
|
6077
|
-
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
|
|
6083
|
-
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
|
|
6088
|
-
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
|
|
6097
|
-
|
|
6559
|
+
(-polygonPosition.x + targetTextureOffset.x * 1 - rotationalOffset.x * 1) * this.scale.x,
|
|
6560
|
+
(-polygonPosition.y + targetTextureOffset.y * 1 - rotationalOffset.y * 1) * this.scale.y,
|
|
6561
|
+
targetTextureSize.x * this.scale.x,
|
|
6562
|
+
targetTextureSize.y * this.scale.y
|
|
6563
|
+
);
|
|
6564
|
+
|
|
6565
|
+
// const scaledTextureSize = new Bounds(
|
|
6566
|
+
// new Vertex(
|
|
6567
|
+
// -polygonPosition.x + targetTextureOffset.x - rotationalOffset.x,
|
|
6568
|
+
// -polygonPosition.y + targetTextureOffset.y - rotationalOffset.y
|
|
6569
|
+
// ).scaleXY(this.scale, rotationCenter),
|
|
6570
|
+
// new Vertex(
|
|
6571
|
+
// -polygonPosition.x + targetTextureOffset.x - rotationalOffset.x + targetTextureSize.x,
|
|
6572
|
+
// -polygonPosition.y + targetTextureOffset.y - rotationalOffset.y + targetTextureSize.y
|
|
6573
|
+
// ).scaleXY(this.scale, rotationCenter)
|
|
6574
|
+
// );
|
|
6575
|
+
// this.ctx.drawImage(
|
|
6576
|
+
// textureImage,
|
|
6577
|
+
// 0,
|
|
6578
|
+
// 0,
|
|
6579
|
+
// textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
|
|
6580
|
+
// textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
|
|
6581
|
+
// scaledTextureSize.min.x,
|
|
6582
|
+
// scaledTextureSize.min.y,
|
|
6583
|
+
// scaledTextureSize.width,
|
|
6584
|
+
// scaledTextureSize.height
|
|
6585
|
+
// );
|
|
6586
|
+
|
|
6587
|
+
this.ctx.restore();
|
|
6098
6588
|
}
|
|
6589
|
+
*/
|
|
6099
6590
|
/**
|
|
6100
6591
|
* Draw a rectangle.
|
|
6101
6592
|
*
|
|
@@ -6104,10 +6595,16 @@ class drawutils {
|
|
|
6104
6595
|
* @param {number} height - The height of the rectangle.
|
|
6105
6596
|
* @param {string} color - The color to use.
|
|
6106
6597
|
* @param {number=1} lineWidth - (optional) The line with to use (default is 1).
|
|
6598
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6599
|
+
*
|
|
6600
|
+
* @return {void}
|
|
6601
|
+
* @instance
|
|
6602
|
+
* @memberof drawutils
|
|
6107
6603
|
**/
|
|
6108
|
-
rect(position, width, height, color, lineWidth) {
|
|
6604
|
+
rect(position, width, height, color, lineWidth, strokeOptions) {
|
|
6109
6605
|
this.ctx.save();
|
|
6110
6606
|
this.ctx.beginPath();
|
|
6607
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6111
6608
|
this.ctx.moveTo(this.offset.x + position.x * this.scale.x, this.offset.y + position.y * this.scale.y);
|
|
6112
6609
|
this.ctx.lineTo(this.offset.x + (position.x + width) * this.scale.x, this.offset.y + position.y * this.scale.y);
|
|
6113
6610
|
this.ctx.lineTo(this.offset.x + (position.x + width) * this.scale.x, this.offset.y + (position.y + height) * this.scale.y);
|
|
@@ -6118,43 +6615,23 @@ class drawutils {
|
|
|
6118
6615
|
this._fillOrDraw(color);
|
|
6119
6616
|
this.ctx.restore();
|
|
6120
6617
|
}
|
|
6121
|
-
// +---------------------------------------------------------------------------------
|
|
6122
|
-
// | This is the final helper function for drawing and filling stuff. It is not
|
|
6123
|
-
// | intended to be used from the outside.
|
|
6124
|
-
// |
|
|
6125
|
-
// | When in draw mode it draws the current shape.
|
|
6126
|
-
// | When in fill mode it fills the current shape.
|
|
6127
|
-
// |
|
|
6128
|
-
// | This function is usually only called internally.
|
|
6129
|
-
// |
|
|
6130
|
-
// | @param color A stroke/fill color to use.
|
|
6131
|
-
// +-------------------------------
|
|
6132
|
-
// TODO: convert this to a STATIC function.
|
|
6133
|
-
_fillOrDraw(color) {
|
|
6134
|
-
if (this.fillShapes) {
|
|
6135
|
-
this.ctx.fillStyle = color;
|
|
6136
|
-
this.ctx.fill();
|
|
6137
|
-
}
|
|
6138
|
-
else {
|
|
6139
|
-
this.ctx.strokeStyle = color;
|
|
6140
|
-
this.ctx.stroke();
|
|
6141
|
-
}
|
|
6142
|
-
}
|
|
6143
6618
|
/**
|
|
6144
6619
|
* Draw the given (cubic) bézier curve.
|
|
6145
6620
|
*
|
|
6146
6621
|
* @method cubicBezier
|
|
6147
|
-
* @param {
|
|
6148
|
-
* @param {
|
|
6149
|
-
* @param {
|
|
6150
|
-
* @param {
|
|
6622
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
6623
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
6624
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
6625
|
+
* @param {XYCoords} endControlPoint - The end control point the cubic Bézier curve.
|
|
6151
6626
|
* @param {string} color - The CSS color to draw the curve with.
|
|
6152
6627
|
* @param {number} lineWidth - (optional) The line width to use.
|
|
6628
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6629
|
+
*
|
|
6153
6630
|
* @return {void}
|
|
6154
6631
|
* @instance
|
|
6155
6632
|
* @memberof drawutils
|
|
6156
6633
|
*/
|
|
6157
|
-
cubicBezier(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth) {
|
|
6634
|
+
cubicBezier(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, strokeOptions) {
|
|
6158
6635
|
if (startPoint instanceof CubicBezierCurve) {
|
|
6159
6636
|
this.cubicBezier(startPoint.startPoint, startPoint.endPoint, startPoint.startControlPoint, startPoint.endControlPoint, color, lineWidth);
|
|
6160
6637
|
return;
|
|
@@ -6162,6 +6639,7 @@ class drawutils {
|
|
|
6162
6639
|
// Draw curve
|
|
6163
6640
|
this.ctx.save();
|
|
6164
6641
|
this.ctx.beginPath();
|
|
6642
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6165
6643
|
this.ctx.moveTo(this.offset.x + startPoint.x * this.scale.x, this.offset.y + startPoint.y * this.scale.y);
|
|
6166
6644
|
this.ctx.bezierCurveTo(this.offset.x + startControlPoint.x * this.scale.x, this.offset.y + startControlPoint.y * this.scale.y, this.offset.x + endControlPoint.x * this.scale.x, this.offset.y + endControlPoint.y * this.scale.y, this.offset.x + endPoint.x * this.scale.x, this.offset.y + endPoint.y * this.scale.y);
|
|
6167
6645
|
//this.ctx.closePath();
|
|
@@ -6173,19 +6651,22 @@ class drawutils {
|
|
|
6173
6651
|
* Draw the given (quadratic) bézier curve.
|
|
6174
6652
|
*
|
|
6175
6653
|
* @method quadraticBezier
|
|
6176
|
-
* @param {
|
|
6177
|
-
* @param {
|
|
6178
|
-
* @param {
|
|
6654
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
6655
|
+
* @param {XYCoords} controlPoint - The control point the cubic Bézier curve.
|
|
6656
|
+
* @param {XYCoords} endPoint - The end control point the cubic Bézier curve.
|
|
6179
6657
|
* @param {string} color - The CSS color to draw the curve with.
|
|
6180
6658
|
* @param {number|string} lineWidth - (optional) The line width to use.
|
|
6659
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6660
|
+
*
|
|
6181
6661
|
* @return {void}
|
|
6182
6662
|
* @instance
|
|
6183
6663
|
* @memberof drawutils
|
|
6184
6664
|
*/
|
|
6185
|
-
quadraticBezier(startPoint, controlPoint, endPoint, color, lineWidth) {
|
|
6665
|
+
quadraticBezier(startPoint, controlPoint, endPoint, color, lineWidth, strokeOptions) {
|
|
6186
6666
|
// Draw curve
|
|
6187
6667
|
this.ctx.save();
|
|
6188
6668
|
this.ctx.beginPath();
|
|
6669
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6189
6670
|
this.ctx.moveTo(this.offset.x + startPoint.x * this.scale.x, this.offset.y + startPoint.y * this.scale.y);
|
|
6190
6671
|
this.ctx.quadraticCurveTo(this.offset.x + controlPoint.x * this.scale.x, this.offset.y + controlPoint.y * this.scale.y, this.offset.x + endPoint.x * this.scale.x, this.offset.y + endPoint.y * this.scale.y);
|
|
6191
6672
|
this.ctx.lineWidth = lineWidth || 2;
|
|
@@ -6200,22 +6681,26 @@ class drawutils {
|
|
|
6200
6681
|
* <pre> [ point1, point1_startControl, point2_endControl, point2, point2_startControl, point3_endControl, point3, ... pointN_endControl, pointN ]</pre>
|
|
6201
6682
|
*
|
|
6202
6683
|
* @method cubicBezierPath
|
|
6203
|
-
* @param {
|
|
6684
|
+
* @param {XYCoords[]} path - The cubic bezier path as described above.
|
|
6204
6685
|
* @param {string} color - The CSS colot to draw the path with.
|
|
6205
6686
|
* @param {number=1} lineWidth - (optional) The line width to use.
|
|
6687
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6688
|
+
*
|
|
6206
6689
|
* @return {void}
|
|
6207
6690
|
* @instance
|
|
6208
6691
|
* @memberof drawutils
|
|
6209
6692
|
*/
|
|
6210
|
-
cubicBezierPath(path, color, lineWidth) {
|
|
6211
|
-
if (!path || path.length == 0)
|
|
6693
|
+
cubicBezierPath(path, color, lineWidth, strokeOptions) {
|
|
6694
|
+
if (!path || path.length == 0) {
|
|
6212
6695
|
return;
|
|
6696
|
+
}
|
|
6213
6697
|
// Draw curve
|
|
6214
6698
|
this.ctx.save();
|
|
6215
6699
|
this.ctx.beginPath();
|
|
6216
6700
|
var endPoint;
|
|
6217
6701
|
var startControlPoint;
|
|
6218
6702
|
var endControlPoint;
|
|
6703
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6219
6704
|
this.ctx.moveTo(this.offset.x + path[0].x * this.scale.x, this.offset.y + path[0].y * this.scale.y);
|
|
6220
6705
|
for (var i = 1; i < path.length; i += 3) {
|
|
6221
6706
|
startControlPoint = path[i];
|
|
@@ -6234,8 +6719,8 @@ class drawutils {
|
|
|
6234
6719
|
* The colors for this are fixed and cannot be specified.
|
|
6235
6720
|
*
|
|
6236
6721
|
* @method handle
|
|
6237
|
-
* @param {
|
|
6238
|
-
* @param {
|
|
6722
|
+
* @param {XYCoords} startPoint - The start of the handle.
|
|
6723
|
+
* @param {XYCoords} endPoint - The end point of the handle.
|
|
6239
6724
|
* @return {void}
|
|
6240
6725
|
* @instance
|
|
6241
6726
|
* @memberof drawutils
|
|
@@ -6250,21 +6735,21 @@ class drawutils {
|
|
|
6250
6735
|
* Draw a handle line (with a light grey).
|
|
6251
6736
|
*
|
|
6252
6737
|
* @method handleLine
|
|
6253
|
-
* @param {
|
|
6254
|
-
* @param {
|
|
6738
|
+
* @param {XYCoords} startPoint - The start point to draw the handle at.
|
|
6739
|
+
* @param {XYCoords} endPoint - The end point to draw the handle at.
|
|
6255
6740
|
* @return {void}
|
|
6256
6741
|
* @instance
|
|
6257
6742
|
* @memberof drawutils
|
|
6258
6743
|
*/
|
|
6259
6744
|
handleLine(startPoint, endPoint) {
|
|
6260
6745
|
// Draw handle lines
|
|
6261
|
-
this.line(startPoint, endPoint, "
|
|
6746
|
+
this.line(startPoint, endPoint, "rgba(128,128,128, 0.5)", undefined);
|
|
6262
6747
|
}
|
|
6263
6748
|
/**
|
|
6264
6749
|
* Draw a 1x1 dot with the specified (CSS-) color.
|
|
6265
6750
|
*
|
|
6266
6751
|
* @method dot
|
|
6267
|
-
* @param {
|
|
6752
|
+
* @param {XYCoords} p - The position to draw the dot at.
|
|
6268
6753
|
* @param {string} color - The CSS color to draw the dot with.
|
|
6269
6754
|
* @return {void}
|
|
6270
6755
|
* @instance
|
|
@@ -6273,6 +6758,7 @@ class drawutils {
|
|
|
6273
6758
|
dot(p, color) {
|
|
6274
6759
|
this.ctx.save();
|
|
6275
6760
|
this.ctx.beginPath();
|
|
6761
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6276
6762
|
this.ctx.moveTo(Math.round(this.offset.x + this.scale.x * p.x), Math.round(this.offset.y + this.scale.y * p.y));
|
|
6277
6763
|
this.ctx.lineTo(Math.round(this.offset.x + this.scale.x * p.x + 1), Math.round(this.offset.y + this.scale.y * p.y + 1));
|
|
6278
6764
|
this.ctx.closePath();
|
|
@@ -6284,7 +6770,7 @@ class drawutils {
|
|
|
6284
6770
|
* Draw the given point with the specified (CSS-) color and radius 3.
|
|
6285
6771
|
*
|
|
6286
6772
|
* @method point
|
|
6287
|
-
* @param {
|
|
6773
|
+
* @param {XYCoords} p - The position to draw the point at.
|
|
6288
6774
|
* @param {string} color - The CSS color to draw the point with.
|
|
6289
6775
|
* @return {void}
|
|
6290
6776
|
* @instance
|
|
@@ -6292,6 +6778,7 @@ class drawutils {
|
|
|
6292
6778
|
*/
|
|
6293
6779
|
point(p, color) {
|
|
6294
6780
|
var radius = 3;
|
|
6781
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6295
6782
|
this.ctx.beginPath();
|
|
6296
6783
|
this.ctx.arc(this.offset.x + p.x * this.scale.x, this.offset.y + p.y * this.scale.y, radius, 0, 2 * Math.PI, false);
|
|
6297
6784
|
this.ctx.closePath();
|
|
@@ -6304,15 +6791,18 @@ class drawutils {
|
|
|
6304
6791
|
* Note that if the x- and y- scales are different the result will be an ellipse rather than a circle.
|
|
6305
6792
|
*
|
|
6306
6793
|
* @method circle
|
|
6307
|
-
* @param {
|
|
6794
|
+
* @param {XYCoords} center - The center of the circle.
|
|
6308
6795
|
* @param {number} radius - The radius of the circle.
|
|
6309
6796
|
* @param {string} color - The CSS color to draw the circle with.
|
|
6310
6797
|
* @param {number} lineWidth - The line width (optional, default=1).
|
|
6798
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6799
|
+
*
|
|
6311
6800
|
* @return {void}
|
|
6312
6801
|
* @instance
|
|
6313
6802
|
* @memberof drawutils
|
|
6314
6803
|
*/
|
|
6315
|
-
circle(center, radius, color, lineWidth) {
|
|
6804
|
+
circle(center, radius, color, lineWidth, strokeOptions) {
|
|
6805
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6316
6806
|
this.ctx.beginPath();
|
|
6317
6807
|
this.ctx.ellipse(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y, radius * this.scale.x, radius * this.scale.y, 0.0, 0.0, Math.PI * 2);
|
|
6318
6808
|
this.ctx.closePath();
|
|
@@ -6320,24 +6810,28 @@ class drawutils {
|
|
|
6320
6810
|
this._fillOrDraw(color);
|
|
6321
6811
|
}
|
|
6322
6812
|
/**
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6813
|
+
* Draw a circular arc (section of a circle) with the given CSS color.
|
|
6814
|
+
*
|
|
6815
|
+
* @method circleArc
|
|
6816
|
+
* @param {XYCoords} center - The center of the circle.
|
|
6817
|
+
* @param {number} radius - The radius of the circle.
|
|
6818
|
+
* @param {number} startAngle - The angle to start at.
|
|
6819
|
+
* @param {number} endAngle - The angle to end at.
|
|
6820
|
+
* @param {string=#000000} color - The CSS color to draw the circle with.
|
|
6821
|
+
* @param {number=1} lineWidth - The line width to use
|
|
6822
|
+
* @param {boolean=false} options.asSegment - If `true` then no beginPath and no draw will be applied (as part of larger path).
|
|
6823
|
+
* @param {number=} options.dashOffset - (optional) `See StrokeOptions`.
|
|
6824
|
+
* @param {number=[]} options.dashArray - (optional) `See StrokeOptions`.
|
|
6825
|
+
*
|
|
6826
|
+
* @return {void}
|
|
6827
|
+
* @instance
|
|
6828
|
+
* @memberof drawutils
|
|
6829
|
+
*/
|
|
6337
6830
|
circleArc(center, radius, startAngle, endAngle, color, lineWidth, options) {
|
|
6338
6831
|
if (!options || !options.asSegment) {
|
|
6339
6832
|
this.ctx.beginPath();
|
|
6340
6833
|
}
|
|
6834
|
+
this.applyStrokeOpts(options);
|
|
6341
6835
|
this.ctx.ellipse(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y, radius * this.scale.x, radius * this.scale.y, 0.0, startAngle, endAngle, false);
|
|
6342
6836
|
if (!options || !options.asSegment) {
|
|
6343
6837
|
// this.ctx.closePath();
|
|
@@ -6349,20 +6843,23 @@ class drawutils {
|
|
|
6349
6843
|
* Draw an ellipse with the specified (CSS-) color and thw two radii.
|
|
6350
6844
|
*
|
|
6351
6845
|
* @method ellipse
|
|
6352
|
-
* @param {
|
|
6846
|
+
* @param {XYCoords} center - The center of the ellipse.
|
|
6353
6847
|
* @param {number} radiusX - The radius of the ellipse.
|
|
6354
6848
|
* @param {number} radiusY - The radius of the ellipse.
|
|
6355
6849
|
* @param {string} color - The CSS color to draw the ellipse with.
|
|
6356
6850
|
* @param {number} lineWidth=1 - An optional line width param (default is 1).
|
|
6357
6851
|
* @param {number=} rotation - (optional, default=0) The rotation of the ellipse.
|
|
6852
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6853
|
+
*
|
|
6358
6854
|
* @return {void}
|
|
6359
6855
|
* @instance
|
|
6360
6856
|
* @memberof drawutils
|
|
6361
6857
|
*/
|
|
6362
|
-
ellipse(center, radiusX, radiusY, color, lineWidth, rotation) {
|
|
6858
|
+
ellipse(center, radiusX, radiusY, color, lineWidth, rotation, strokeOptions) {
|
|
6363
6859
|
if (typeof rotation === "undefined") {
|
|
6364
6860
|
rotation = 0.0;
|
|
6365
6861
|
}
|
|
6862
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6366
6863
|
this.ctx.beginPath();
|
|
6367
6864
|
this.ctx.ellipse(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y, radiusX * this.scale.x, radiusY * this.scale.y, rotation, 0.0, Math.PI * 2);
|
|
6368
6865
|
this.ctx.closePath();
|
|
@@ -6379,11 +6876,14 @@ class drawutils {
|
|
|
6379
6876
|
* @param {number} size - The size of the square.
|
|
6380
6877
|
* @param {string} color - The CSS color to draw the square with.
|
|
6381
6878
|
* @param {number} lineWidth - The line with to use (optional, default is 1).
|
|
6879
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6880
|
+
*
|
|
6382
6881
|
* @return {void}
|
|
6383
6882
|
* @instance
|
|
6384
6883
|
* @memberof drawutils
|
|
6385
6884
|
*/
|
|
6386
|
-
square(center, size, color, lineWidth) {
|
|
6885
|
+
square(center, size, color, lineWidth, strokeOptions) {
|
|
6886
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6387
6887
|
this.ctx.beginPath();
|
|
6388
6888
|
this.ctx.rect(this.offset.x + (center.x - size / 2.0) * this.scale.x, this.offset.y + (center.y - size / 2.0) * this.scale.y, size * this.scale.x, size * this.scale.y);
|
|
6389
6889
|
this.ctx.closePath();
|
|
@@ -6394,7 +6894,7 @@ class drawutils {
|
|
|
6394
6894
|
* Draw a grid of horizontal and vertical lines with the given (CSS-) color.
|
|
6395
6895
|
*
|
|
6396
6896
|
* @method grid
|
|
6397
|
-
* @param {
|
|
6897
|
+
* @param {XYCoords} center - The center of the grid.
|
|
6398
6898
|
* @param {number} width - The total width of the grid (width/2 each to the left and to the right).
|
|
6399
6899
|
* @param {number} height - The total height of the grid (height/2 each to the top and to the bottom).
|
|
6400
6900
|
* @param {number} sizeX - The horizontal grid size.
|
|
@@ -6405,6 +6905,7 @@ class drawutils {
|
|
|
6405
6905
|
* @memberof drawutils
|
|
6406
6906
|
*/
|
|
6407
6907
|
grid(center, width, height, sizeX, sizeY, color) {
|
|
6908
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6408
6909
|
this.ctx.beginPath();
|
|
6409
6910
|
var yMin = -Math.ceil((height * 0.5) / sizeY) * sizeY;
|
|
6410
6911
|
var yMax = height / 2;
|
|
@@ -6429,7 +6930,7 @@ class drawutils {
|
|
|
6429
6930
|
* This works analogue to the grid() function
|
|
6430
6931
|
*
|
|
6431
6932
|
* @method raster
|
|
6432
|
-
* @param {
|
|
6933
|
+
* @param {XYCoords} center - The center of the raster.
|
|
6433
6934
|
* @param {number} width - The total width of the raster (width/2 each to the left and to the right).
|
|
6434
6935
|
* @param {number} height - The total height of the raster (height/2 each to the top and to the bottom).
|
|
6435
6936
|
* @param {number} sizeX - The horizontal raster size.
|
|
@@ -6441,6 +6942,7 @@ class drawutils {
|
|
|
6441
6942
|
*/
|
|
6442
6943
|
raster(center, width, height, sizeX, sizeY, color) {
|
|
6443
6944
|
this.ctx.save();
|
|
6945
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6444
6946
|
this.ctx.beginPath();
|
|
6445
6947
|
for (var x = -Math.ceil((width * 0.5) / sizeX) * sizeX; x < width / 2; x += sizeX) {
|
|
6446
6948
|
for (var y = -Math.ceil((height * 0.5) / sizeY) * sizeY; y < height / 2; y += sizeY) {
|
|
@@ -6465,14 +6967,15 @@ class drawutils {
|
|
|
6465
6967
|
* as even shaped diamonds.
|
|
6466
6968
|
*
|
|
6467
6969
|
* @method diamondHandle
|
|
6468
|
-
* @param {
|
|
6469
|
-
* @param {
|
|
6970
|
+
* @param {XYCoords} center - The center of the diamond.
|
|
6971
|
+
* @param {number} size - The x/y-size of the diamond.
|
|
6470
6972
|
* @param {string} color - The CSS color to draw the diamond with.
|
|
6471
6973
|
* @return {void}
|
|
6472
6974
|
* @instance
|
|
6473
6975
|
* @memberof drawutils
|
|
6474
6976
|
*/
|
|
6475
6977
|
diamondHandle(center, size, color) {
|
|
6978
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6476
6979
|
this.ctx.beginPath();
|
|
6477
6980
|
this.ctx.moveTo(this.offset.x + center.x * this.scale.x - size / 2.0, this.offset.y + center.y * this.scale.y);
|
|
6478
6981
|
this.ctx.lineTo(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y - size / 2.0);
|
|
@@ -6490,14 +6993,15 @@ class drawutils {
|
|
|
6490
6993
|
* as even shaped squares.
|
|
6491
6994
|
*
|
|
6492
6995
|
* @method squareHandle
|
|
6493
|
-
* @param {
|
|
6494
|
-
* @param {
|
|
6996
|
+
* @param {XYCoords} center - The center of the square.
|
|
6997
|
+
* @param {number} size - The x/y-size of the square.
|
|
6495
6998
|
* @param {string} color - The CSS color to draw the square with.
|
|
6496
6999
|
* @return {void}
|
|
6497
7000
|
* @instance
|
|
6498
7001
|
* @memberof drawutils
|
|
6499
7002
|
*/
|
|
6500
7003
|
squareHandle(center, size, color) {
|
|
7004
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6501
7005
|
this.ctx.beginPath();
|
|
6502
7006
|
this.ctx.rect(this.offset.x + center.x * this.scale.x - size / 2.0, this.offset.y + center.y * this.scale.y - size / 2.0, size, size);
|
|
6503
7007
|
this.ctx.closePath();
|
|
@@ -6512,7 +7016,7 @@ class drawutils {
|
|
|
6512
7016
|
* as even shaped circles.
|
|
6513
7017
|
*
|
|
6514
7018
|
* @method circleHandle
|
|
6515
|
-
* @param {
|
|
7019
|
+
* @param {XYCoords} center - The center of the circle.
|
|
6516
7020
|
* @param {number} radius - The radius of the circle.
|
|
6517
7021
|
* @param {string} color - The CSS color to draw the circle with.
|
|
6518
7022
|
* @return {void}
|
|
@@ -6521,6 +7025,7 @@ class drawutils {
|
|
|
6521
7025
|
*/
|
|
6522
7026
|
circleHandle(center, radius, color) {
|
|
6523
7027
|
radius = radius || 3;
|
|
7028
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6524
7029
|
this.ctx.beginPath();
|
|
6525
7030
|
this.ctx.arc(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y, radius, 0, 2 * Math.PI, false);
|
|
6526
7031
|
this.ctx.closePath();
|
|
@@ -6543,6 +7048,7 @@ class drawutils {
|
|
|
6543
7048
|
*/
|
|
6544
7049
|
crosshair(center, radius, color, lineWidth) {
|
|
6545
7050
|
this.ctx.save();
|
|
7051
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6546
7052
|
this.ctx.beginPath();
|
|
6547
7053
|
this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y);
|
|
6548
7054
|
this.ctx.lineTo(this.offset.x + center.x * this.scale.x + radius, this.offset.y + center.y * this.scale.y);
|
|
@@ -6570,6 +7076,7 @@ class drawutils {
|
|
|
6570
7076
|
*/
|
|
6571
7077
|
cross(center, radius, color, lineWidth) {
|
|
6572
7078
|
this.ctx.save();
|
|
7079
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6573
7080
|
this.ctx.beginPath();
|
|
6574
7081
|
this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y - radius);
|
|
6575
7082
|
this.ctx.lineTo(this.offset.x + center.x * this.scale.x + radius, this.offset.y + center.y * this.scale.y + radius);
|
|
@@ -6588,30 +7095,35 @@ class drawutils {
|
|
|
6588
7095
|
* @param {Polygon} polygon - The polygon to draw.
|
|
6589
7096
|
* @param {string} color - The CSS color to draw the polygon with.
|
|
6590
7097
|
* @param {string} lineWidth - The line width to use.
|
|
7098
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
7099
|
+
*
|
|
6591
7100
|
* @return {void}
|
|
6592
7101
|
* @instance
|
|
6593
7102
|
* @memberof drawutils
|
|
6594
7103
|
*/
|
|
6595
|
-
polygon(polygon, color, lineWidth) {
|
|
6596
|
-
this.polyline(polygon.vertices, polygon.isOpen, color, lineWidth);
|
|
7104
|
+
polygon(polygon, color, lineWidth, strokeOptions) {
|
|
7105
|
+
this.polyline(polygon.vertices, polygon.isOpen, color, lineWidth, strokeOptions);
|
|
6597
7106
|
}
|
|
6598
7107
|
/**
|
|
6599
7108
|
* Draw a polygon line (alternative function to the polygon).
|
|
6600
7109
|
*
|
|
6601
7110
|
* @method polyline
|
|
6602
|
-
* @param {
|
|
7111
|
+
* @param {XYCoords[]} vertices - The polygon vertices to draw.
|
|
6603
7112
|
* @param {boolan} isOpen - If true the polyline will not be closed at its end.
|
|
6604
7113
|
* @param {string} color - The CSS color to draw the polygon with.
|
|
6605
7114
|
* @param {number} lineWidth - The line width (default is 1.0);
|
|
7115
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
7116
|
+
*
|
|
6606
7117
|
* @return {void}
|
|
6607
7118
|
* @instance
|
|
6608
7119
|
* @memberof drawutils
|
|
6609
7120
|
*/
|
|
6610
|
-
polyline(vertices, isOpen, color, lineWidth) {
|
|
7121
|
+
polyline(vertices, isOpen, color, lineWidth, strokeOptions) {
|
|
6611
7122
|
if (vertices.length <= 1) {
|
|
6612
7123
|
return;
|
|
6613
7124
|
}
|
|
6614
7125
|
this.ctx.save();
|
|
7126
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6615
7127
|
this.ctx.beginPath();
|
|
6616
7128
|
this.ctx.lineWidth = (lineWidth || 1.0) * this.scale.x;
|
|
6617
7129
|
this.ctx.moveTo(this.offset.x + vertices[0].x * this.scale.x, this.offset.y + vertices[0].y * this.scale.y);
|
|
@@ -6723,6 +7235,8 @@ class drawutils {
|
|
|
6723
7235
|
* @param {string=null} color - (optional) The color to draw this path with (default is null).
|
|
6724
7236
|
* @param {number=1} lineWidth - (optional) the line width to use (default is 1).
|
|
6725
7237
|
* @param {boolean=false} options.inplace - (optional) If set to true then path transforamtions (scale and translate) will be done in-place in the array. This can boost the performance.
|
|
7238
|
+
* @param {number=} options.dashOffset - (optional) `See StrokeOptions`.
|
|
7239
|
+
* @param {number=[]} options.dashArray - (optional) `See StrokeOptions`.
|
|
6726
7240
|
* @instance
|
|
6727
7241
|
* @memberof drawutils
|
|
6728
7242
|
* @return {R} An instance representing the drawn path.
|
|
@@ -6734,6 +7248,7 @@ class drawutils {
|
|
|
6734
7248
|
this.ctx.strokeStyle = color;
|
|
6735
7249
|
}
|
|
6736
7250
|
this.ctx.lineWidth = lineWidth || 1;
|
|
7251
|
+
this.applyStrokeOpts(options);
|
|
6737
7252
|
if (this.fillShapes) {
|
|
6738
7253
|
if (color) {
|
|
6739
7254
|
this.ctx.fillStyle = color;
|
|
@@ -6790,7 +7305,12 @@ drawutils.helpers = {
|
|
|
6790
7305
|
* @modified 2022-03-27 Added the `texturedPoly` function.
|
|
6791
7306
|
* @modified 2022-07-26 Adding `alpha` to the `image(...)` function.
|
|
6792
7307
|
* @modified 2023-02-10 The methods `setCurrentClassName` and `setCurrentId` also accept `null` now.
|
|
6793
|
-
* @
|
|
7308
|
+
* @modified 2023-09-29 Downgrading all `Vertex` param type to the more generic `XYCoords` type in these render functions: line, arrow, texturedPoly, cubicBezier, cubicBezierPath, handle, handleLine, dot, point, circle, circleArc, ellipse, grid, raster.
|
|
7309
|
+
* @modified 2023-09-29 Added the `headLength` parameter to the 'DrawLib.arrow()` function.
|
|
7310
|
+
* @modified 2023-09-29 Added the `arrowHead(...)` function to the 'DrawLib.arrow()` interface.
|
|
7311
|
+
* @modified 2023-09-29 Added the `cubicBezierArrow(...)` function to the 'DrawLib.arrow()` interface.
|
|
7312
|
+
* @modified 2023-09-29 Added the `lineDashes` attribute.
|
|
7313
|
+
* @version 0.0.10
|
|
6794
7314
|
**/
|
|
6795
7315
|
/**
|
|
6796
7316
|
* @classdesc A wrapper class for basic drawing operations. This is the WebGL
|
|
@@ -6884,6 +7404,20 @@ class drawutilsgl {
|
|
|
6884
7404
|
setConfiguration(configuration) {
|
|
6885
7405
|
// TODO
|
|
6886
7406
|
}
|
|
7407
|
+
// /**
|
|
7408
|
+
// * Set or clear the line-dash configuration. Pass `null` for un-dashed lines.
|
|
7409
|
+
// *
|
|
7410
|
+
// * See https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray
|
|
7411
|
+
// * and https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
|
|
7412
|
+
// * for how line dashes work.
|
|
7413
|
+
// *
|
|
7414
|
+
// * @method
|
|
7415
|
+
// * @param {Array<number> lineDashes - The line-dash array configuration.
|
|
7416
|
+
// * @returns {void}
|
|
7417
|
+
// */
|
|
7418
|
+
// setLineDash(lineDashes: Array<number>) {
|
|
7419
|
+
// // TODO
|
|
7420
|
+
// }
|
|
6887
7421
|
/**
|
|
6888
7422
|
* This method shouled be called each time the currently drawn `Drawable` changes.
|
|
6889
7423
|
* It is used by some libraries for identifying elemente on re-renders.
|
|
@@ -6911,8 +7445,8 @@ class drawutilsgl {
|
|
|
6911
7445
|
* Draw the line between the given two points with the specified (CSS-) color.
|
|
6912
7446
|
*
|
|
6913
7447
|
* @method line
|
|
6914
|
-
* @param {
|
|
6915
|
-
* @param {
|
|
7448
|
+
* @param {XYCoords} zA - The start point of the line.
|
|
7449
|
+
* @param {XYCoords} zB - The end point of the line.
|
|
6916
7450
|
* @param {string} color - Any valid CSS color string.
|
|
6917
7451
|
* @return {void}
|
|
6918
7452
|
* @instance
|
|
@@ -6961,9 +7495,10 @@ class drawutilsgl {
|
|
|
6961
7495
|
* Draw a line and an arrow at the end (zB) of the given line with the specified (CSS-) color.
|
|
6962
7496
|
*
|
|
6963
7497
|
* @method arrow
|
|
6964
|
-
* @param {
|
|
6965
|
-
* @param {
|
|
7498
|
+
* @param {XYCoords} zA - The start point of the arrow-line.
|
|
7499
|
+
* @param {XYCoords} zB - The end point of the arrow-line.
|
|
6966
7500
|
* @param {string} color - Any valid CSS color string.
|
|
7501
|
+
* @param {headLength=8} headLength - (optional) The length of the arrow head (default is 8 units).
|
|
6967
7502
|
* @return {void}
|
|
6968
7503
|
* @instance
|
|
6969
7504
|
* @memberof drawutils
|
|
@@ -6971,6 +7506,41 @@ class drawutilsgl {
|
|
|
6971
7506
|
arrow(zA, zB, color) {
|
|
6972
7507
|
// NOT YET IMPLEMENTED
|
|
6973
7508
|
}
|
|
7509
|
+
/**
|
|
7510
|
+
* Draw a cubic Bézier curve and and an arrow at the end (endControlPoint) of the given line width the specified (CSS-) color and arrow size.
|
|
7511
|
+
*
|
|
7512
|
+
* @method cubicBezierArrow
|
|
7513
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
7514
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
7515
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
7516
|
+
* @param {XYCoords} endControlPoint - The end control point the cubic Bézier curve.
|
|
7517
|
+
* @param {string} color - The CSS color to draw the curve with.
|
|
7518
|
+
* @param {number} lineWidth - (optional) The line width to use.
|
|
7519
|
+
* @param {headLength=8} headLength - (optional) The length of the arrow head (default is 8 units).
|
|
7520
|
+
*
|
|
7521
|
+
* @return {void}
|
|
7522
|
+
* @instance
|
|
7523
|
+
* @memberof DrawLib
|
|
7524
|
+
*/
|
|
7525
|
+
cubicBezierArrow(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, headLength) {
|
|
7526
|
+
// NOT YET IMPLEMENTED
|
|
7527
|
+
}
|
|
7528
|
+
/**
|
|
7529
|
+
* Draw just an arrow head a the end of an imaginary line (zB) of the given line width the specified (CSS-) color and size.
|
|
7530
|
+
*
|
|
7531
|
+
* @method arrow
|
|
7532
|
+
* @param {XYCoords} zA - The start point of the arrow-line.
|
|
7533
|
+
* @param {XYCoords} zB - The end point of the arrow-line.
|
|
7534
|
+
* @param {string} color - Any valid CSS color string.
|
|
7535
|
+
* @param {number=1} lineWidth - (optional) The line width to use; default is 1.
|
|
7536
|
+
* @param {number=8} headLength - (optional) The length of the arrow head (default is 8 pixels).
|
|
7537
|
+
* @return {void}
|
|
7538
|
+
* @instance
|
|
7539
|
+
* @memberof DrawLib
|
|
7540
|
+
**/
|
|
7541
|
+
arrowHead(zA, zB, color, lineWidth, headLength) {
|
|
7542
|
+
// NOT YET IMPLEMENTED
|
|
7543
|
+
}
|
|
6974
7544
|
/**
|
|
6975
7545
|
* Draw an image at the given position with the given size.<br>
|
|
6976
7546
|
* <br>
|
|
@@ -6978,8 +7548,8 @@ class drawutilsgl {
|
|
|
6978
7548
|
*
|
|
6979
7549
|
* @method image
|
|
6980
7550
|
* @param {Image} image - The image object to draw.
|
|
6981
|
-
* @param {
|
|
6982
|
-
* @param {
|
|
7551
|
+
* @param {XYCoords} position - The position to draw the the upper left corner at.
|
|
7552
|
+
* @param {XYCoords} size - The x/y-size to draw the image with.
|
|
6983
7553
|
* @param {number=0.0} alpha - (optional, default=0.0) The transparency (0.0=opaque, 1.0=transparent).
|
|
6984
7554
|
* @return {void}
|
|
6985
7555
|
* @instance
|
|
@@ -6997,7 +7567,7 @@ class drawutilsgl {
|
|
|
6997
7567
|
* @param {Image} textureImage - The image object to draw.
|
|
6998
7568
|
* @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
|
|
6999
7569
|
* @param {Polygon} polygon - The polygon to use as clip path.
|
|
7000
|
-
* @param {
|
|
7570
|
+
* @param {XYCoords} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
|
|
7001
7571
|
* @param {number} rotation - The rotation to use for the polygon (and for the texture).
|
|
7002
7572
|
* @return {void}
|
|
7003
7573
|
* @instance
|
|
@@ -7024,10 +7594,10 @@ class drawutilsgl {
|
|
|
7024
7594
|
* Draw the given (cubic) bézier curve.
|
|
7025
7595
|
*
|
|
7026
7596
|
* @method cubicBezier
|
|
7027
|
-
* @param {
|
|
7028
|
-
* @param {
|
|
7029
|
-
* @param {
|
|
7030
|
-
* @param {
|
|
7597
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
7598
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
7599
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
7600
|
+
* @param {VertXYCoordsex} endControlPoint - The end control point the cubic Bézier curve.
|
|
7031
7601
|
* @param {string} color - The CSS color to draw the curve with.
|
|
7032
7602
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
7033
7603
|
* @return {void}
|
|
@@ -7045,7 +7615,7 @@ class drawutilsgl {
|
|
|
7045
7615
|
* <pre> [ point1, point1_startControl, point2_endControl, point2, point2_startControl, point3_endControl, point3, ... pointN_endControl, pointN ]</pre>
|
|
7046
7616
|
*
|
|
7047
7617
|
* @method cubicBezierPath
|
|
7048
|
-
* @param {
|
|
7618
|
+
* @param {XYCoords[]} path - The cubic bezier path as described above.
|
|
7049
7619
|
* @param {string} color - The CSS colot to draw the path with.
|
|
7050
7620
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
7051
7621
|
* @return {void}
|
|
@@ -7061,8 +7631,8 @@ class drawutilsgl {
|
|
|
7061
7631
|
* The colors for this are fixed and cannot be specified.
|
|
7062
7632
|
*
|
|
7063
7633
|
* @method handle
|
|
7064
|
-
* @param {
|
|
7065
|
-
* @param {
|
|
7634
|
+
* @param {XYCoords} startPoint - The start of the handle.
|
|
7635
|
+
* @param {XYCoords} endPoint - The end point of the handle.
|
|
7066
7636
|
* @return {void}
|
|
7067
7637
|
* @instance
|
|
7068
7638
|
* @memberof drawutils
|
|
@@ -7074,8 +7644,8 @@ class drawutilsgl {
|
|
|
7074
7644
|
* Draw a handle line (with a light grey).
|
|
7075
7645
|
*
|
|
7076
7646
|
* @method handleLine
|
|
7077
|
-
* @param {
|
|
7078
|
-
* @param {
|
|
7647
|
+
* @param {XYCoords} startPoint - The start point to draw the handle at.
|
|
7648
|
+
* @param {XYCoords} endPoint - The end point to draw the handle at.
|
|
7079
7649
|
* @return {void}
|
|
7080
7650
|
* @instance
|
|
7081
7651
|
* @memberof drawutils
|
|
@@ -7087,7 +7657,7 @@ class drawutilsgl {
|
|
|
7087
7657
|
* Draw a 1x1 dot with the specified (CSS-) color.
|
|
7088
7658
|
*
|
|
7089
7659
|
* @method dot
|
|
7090
|
-
* @param {
|
|
7660
|
+
* @param {XYCoords} p - The position to draw the dot at.
|
|
7091
7661
|
* @param {string} color - The CSS color to draw the dot with.
|
|
7092
7662
|
* @return {void}
|
|
7093
7663
|
* @instance
|
|
@@ -7100,7 +7670,7 @@ class drawutilsgl {
|
|
|
7100
7670
|
* Draw the given point with the specified (CSS-) color and radius 3.
|
|
7101
7671
|
*
|
|
7102
7672
|
* @method point
|
|
7103
|
-
* @param {
|
|
7673
|
+
* @param {XYCoords} p - The position to draw the point at.
|
|
7104
7674
|
* @param {string} color - The CSS color to draw the point with.
|
|
7105
7675
|
* @return {void}
|
|
7106
7676
|
* @instance
|
|
@@ -7115,7 +7685,7 @@ class drawutilsgl {
|
|
|
7115
7685
|
* Note that if the x- and y- scales are different the result will be an ellipse rather than a circle.
|
|
7116
7686
|
*
|
|
7117
7687
|
* @method circle
|
|
7118
|
-
* @param {
|
|
7688
|
+
* @param {XYCoords} center - The center of the circle.
|
|
7119
7689
|
* @param {number} radius - The radius of the circle.
|
|
7120
7690
|
* @param {string} color - The CSS color to draw the circle with.
|
|
7121
7691
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
@@ -7130,7 +7700,7 @@ class drawutilsgl {
|
|
|
7130
7700
|
* Draw a circular arc (section of a circle) with the given CSS color.
|
|
7131
7701
|
*
|
|
7132
7702
|
* @method circleArc
|
|
7133
|
-
* @param {
|
|
7703
|
+
* @param {XYCoords} center - The center of the circle.
|
|
7134
7704
|
* @param {number} radius - The radius of the circle.
|
|
7135
7705
|
* @param {number} startAngle - The angle to start at.
|
|
7136
7706
|
* @param {number} endAngle - The angle to end at.
|
|
@@ -7146,7 +7716,7 @@ class drawutilsgl {
|
|
|
7146
7716
|
* Draw an ellipse with the specified (CSS-) color and thw two radii.
|
|
7147
7717
|
*
|
|
7148
7718
|
* @method ellipse
|
|
7149
|
-
* @param {
|
|
7719
|
+
* @param {XYCoords} center - The center of the ellipse.
|
|
7150
7720
|
* @param {number} radiusX - The radius of the ellipse.
|
|
7151
7721
|
* @param {number} radiusY - The radius of the ellipse.
|
|
7152
7722
|
* @param {string} color - The CSS color to draw the ellipse with.
|
|
@@ -7166,7 +7736,7 @@ class drawutilsgl {
|
|
|
7166
7736
|
*
|
|
7167
7737
|
* @method square
|
|
7168
7738
|
* @param {XYCords} center - The center of the square.
|
|
7169
|
-
* @param {
|
|
7739
|
+
* @param {number} size - The size of the square.
|
|
7170
7740
|
* @param {string} color - The CSS color to draw the square with.
|
|
7171
7741
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
7172
7742
|
* @return {void}
|
|
@@ -7192,7 +7762,7 @@ class drawutilsgl {
|
|
|
7192
7762
|
* Draw a grid of horizontal and vertical lines with the given (CSS-) color.
|
|
7193
7763
|
*
|
|
7194
7764
|
* @method grid
|
|
7195
|
-
* @param {
|
|
7765
|
+
* @param {XYCoords} center - The center of the grid.
|
|
7196
7766
|
* @param {number} width - The total width of the grid (width/2 each to the left and to the right).
|
|
7197
7767
|
* @param {number} height - The total height of the grid (height/2 each to the top and to the bottom).
|
|
7198
7768
|
* @param {number} sizeX - The horizontal grid size.
|
|
@@ -7211,7 +7781,7 @@ class drawutilsgl {
|
|
|
7211
7781
|
* This works analogue to the grid() function
|
|
7212
7782
|
*
|
|
7213
7783
|
* @method raster
|
|
7214
|
-
* @param {
|
|
7784
|
+
* @param {XYCoords} center - The center of the raster.
|
|
7215
7785
|
* @param {number} width - The total width of the raster (width/2 each to the left and to the right).
|
|
7216
7786
|
* @param {number} height - The total height of the raster (height/2 each to the top and to the bottom).
|
|
7217
7787
|
* @param {number} sizeX - The horizontal raster size.
|
|
@@ -7232,8 +7802,8 @@ class drawutilsgl {
|
|
|
7232
7802
|
* as even shaped diamonds.
|
|
7233
7803
|
*
|
|
7234
7804
|
* @method diamondHandle
|
|
7235
|
-
* @param {
|
|
7236
|
-
* @param {
|
|
7805
|
+
* @param {XYCoords} center - The center of the diamond.
|
|
7806
|
+
* @param {number} size - The x/y-size of the diamond.
|
|
7237
7807
|
* @param {string} color - The CSS color to draw the diamond with.
|
|
7238
7808
|
* @return {void}
|
|
7239
7809
|
* @instance
|
|
@@ -7250,8 +7820,8 @@ class drawutilsgl {
|
|
|
7250
7820
|
* as even shaped squares.
|
|
7251
7821
|
*
|
|
7252
7822
|
* @method squareHandle
|
|
7253
|
-
* @param {
|
|
7254
|
-
* @param {
|
|
7823
|
+
* @param {XYCoords} center - The center of the square.
|
|
7824
|
+
* @param {number} size - The x/y-size of the square.
|
|
7255
7825
|
* @param {string} color - The CSS color to draw the square with.
|
|
7256
7826
|
* @return {void}
|
|
7257
7827
|
* @instance
|
|
@@ -7268,7 +7838,7 @@ class drawutilsgl {
|
|
|
7268
7838
|
* as even shaped circles.
|
|
7269
7839
|
*
|
|
7270
7840
|
* @method circleHandle
|
|
7271
|
-
* @param {
|
|
7841
|
+
* @param {XYCoords} center - The center of the circle.
|
|
7272
7842
|
* @param {number} radius - The radius of the circle.
|
|
7273
7843
|
* @param {string} color - The CSS color to draw the circle with.
|
|
7274
7844
|
* @return {void}
|
|
@@ -7364,7 +7934,7 @@ class drawutilsgl {
|
|
|
7364
7934
|
* Draw a polygon line (alternative function to the polygon).
|
|
7365
7935
|
*
|
|
7366
7936
|
* @method polyline
|
|
7367
|
-
* @param {
|
|
7937
|
+
* @param {XYCoords[]} vertices - The polygon vertices to draw.
|
|
7368
7938
|
* @param {boolan} isOpen - If true the polyline will not be closed at its end.
|
|
7369
7939
|
* @param {string} color - The CSS color to draw the polygon with.
|
|
7370
7940
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
@@ -8961,7 +9531,8 @@ class PBImage {
|
|
|
8961
9531
|
* @author Ikaros Kappler
|
|
8962
9532
|
* @date 2021-11-16
|
|
8963
9533
|
* @modified 2022-02-02 Added the `destroy` method.
|
|
8964
|
-
* @
|
|
9534
|
+
* @modified 2023-09-25 Fixed a type error in the constructor. Nothing vital.
|
|
9535
|
+
* @version 1.1.1
|
|
8965
9536
|
**/
|
|
8966
9537
|
/**
|
|
8967
9538
|
* @classdesc A simple text element: position, fontSize, fontFamily, color, textAlign, lineHeight and rotation.
|
|
@@ -8992,14 +9563,14 @@ class PBText {
|
|
|
8992
9563
|
this.uid = UIDGenerator.next();
|
|
8993
9564
|
this.text = text;
|
|
8994
9565
|
this.anchor = anchor !== null && anchor !== void 0 ? anchor : new Vertex();
|
|
8995
|
-
this.color = options.color;
|
|
8996
|
-
this.fontFamily = options.fontFamily;
|
|
8997
|
-
this.fontSize = options.fontSize;
|
|
8998
|
-
this.fontStyle = options.fontStyle;
|
|
8999
|
-
this.fontWeight = options.fontWeight;
|
|
9000
|
-
this.lineHeight = options.lineHeight;
|
|
9001
|
-
this.textAlign = options.textAlign;
|
|
9002
|
-
this.rotation = options.rotation;
|
|
9566
|
+
this.color = options === null || options === void 0 ? void 0 : options.color;
|
|
9567
|
+
this.fontFamily = options === null || options === void 0 ? void 0 : options.fontFamily;
|
|
9568
|
+
this.fontSize = options === null || options === void 0 ? void 0 : options.fontSize;
|
|
9569
|
+
this.fontStyle = options === null || options === void 0 ? void 0 : options.fontStyle;
|
|
9570
|
+
this.fontWeight = options === null || options === void 0 ? void 0 : options.fontWeight;
|
|
9571
|
+
this.lineHeight = options === null || options === void 0 ? void 0 : options.lineHeight;
|
|
9572
|
+
this.textAlign = options === null || options === void 0 ? void 0 : options.textAlign;
|
|
9573
|
+
this.rotation = options === null || options === void 0 ? void 0 : options.rotation;
|
|
9003
9574
|
}
|
|
9004
9575
|
/**
|
|
9005
9576
|
* This function should invalidate any installed listeners and invalidate this object.
|
|
@@ -9719,7 +10290,7 @@ class VEllipse {
|
|
|
9719
10290
|
else {
|
|
9720
10291
|
let startTangent = this.tangentAt(curAngle);
|
|
9721
10292
|
let endTangent = this.tangentAt(nextAngle);
|
|
9722
|
-
// Find intersection
|
|
10293
|
+
// Find intersection (ignore that the result might be null in some extreme cases)
|
|
9723
10294
|
let intersection = startTangent.intersection(endTangent);
|
|
9724
10295
|
// What if intersection is undefined?
|
|
9725
10296
|
// --> This *can* not happen if segmentCount > 2 and height and width of the ellipse are not zero.
|
|
@@ -10159,7 +10730,8 @@ VEllipseSector.ellipseSectorUtils = {
|
|
|
10159
10730
|
* @modified 2023-02-10 Fixing an issue of the `style.position` setting when `fitToParent=true` from `absolute` to `static` (default).
|
|
10160
10731
|
* @modified 2023-02-10 Cleaning up most type errors in the main class (mostly null checks).
|
|
10161
10732
|
* @modified 2023-02-10 Adding `enableZoom` and `enablePan` (both default true) to have the option to disable these functions.
|
|
10162
|
-
* @
|
|
10733
|
+
* @modified 2023-09-29 Adding proper dicionary key and value types to the params of `PlotBoilerplate.utils.safeMergeByKeys` (was `object` before).
|
|
10734
|
+
* @version 1.17.3
|
|
10163
10735
|
*
|
|
10164
10736
|
* @file PlotBoilerplate
|
|
10165
10737
|
* @fileoverview The main class.
|
|
@@ -10277,7 +10849,7 @@ class PlotBoilerplate {
|
|
|
10277
10849
|
draggable: true,
|
|
10278
10850
|
visible: true
|
|
10279
10851
|
};
|
|
10280
|
-
if (typeof config.canvas
|
|
10852
|
+
if (typeof config.canvas === "undefined") {
|
|
10281
10853
|
throw "No canvas specified.";
|
|
10282
10854
|
}
|
|
10283
10855
|
/**
|
|
@@ -10369,6 +10941,10 @@ class PlotBoilerplate {
|
|
|
10369
10941
|
fill: true
|
|
10370
10942
|
}
|
|
10371
10943
|
},
|
|
10944
|
+
// bezierPath: {
|
|
10945
|
+
// color: "#0022a8",
|
|
10946
|
+
// lineWidth: 1
|
|
10947
|
+
// },
|
|
10372
10948
|
polygon: {
|
|
10373
10949
|
color: "#0022a8",
|
|
10374
10950
|
lineWidth: 1
|
|
@@ -10428,7 +11004,10 @@ class PlotBoilerplate {
|
|
|
10428
11004
|
// +-------------------------------
|
|
10429
11005
|
this.grid = new Grid(new Vertex(0, 0), new Vertex(50, 50));
|
|
10430
11006
|
this.canvasSize = { width: PlotBoilerplate.DEFAULT_CANVAS_WIDTH, height: PlotBoilerplate.DEFAULT_CANVAS_HEIGHT };
|
|
10431
|
-
const canvasElement = typeof config.canvas
|
|
11007
|
+
const canvasElement = typeof config.canvas === "string" ? document.querySelector(config.canvas) : config.canvas;
|
|
11008
|
+
if (typeof canvasElement === "undefined") {
|
|
11009
|
+
throw `Cannot initialize PlotBoilerplate with a null canvas (element "${config.canvas} not found).`;
|
|
11010
|
+
}
|
|
10432
11011
|
// Which renderer to use: Canvas2D, WebGL (experimental) or SVG?
|
|
10433
11012
|
if (canvasElement.tagName.toLowerCase() === "canvas") {
|
|
10434
11013
|
this.canvas = canvasElement;
|
|
@@ -11076,10 +11655,10 @@ class PlotBoilerplate {
|
|
|
11076
11655
|
if (this.drawConfig.drawBezierHandleLines && this.drawConfig.drawHandleLines) {
|
|
11077
11656
|
draw.setCurrentId(`${d.uid}_l0`);
|
|
11078
11657
|
draw.setCurrentClassName(`${d.className}-start-line`);
|
|
11079
|
-
draw.
|
|
11658
|
+
draw.handleLine(d.bezierCurves[c].startPoint, d.bezierCurves[c].startControlPoint);
|
|
11080
11659
|
draw.setCurrentId(`${d.uid}_l1`);
|
|
11081
11660
|
draw.setCurrentClassName(`${d.className}-end-line`);
|
|
11082
|
-
draw.
|
|
11661
|
+
draw.handleLine(d.bezierCurves[c].endPoint, d.bezierCurves[c].endControlPoint);
|
|
11083
11662
|
}
|
|
11084
11663
|
curveIndex++;
|
|
11085
11664
|
} // END for
|
|
@@ -11102,11 +11681,11 @@ class PlotBoilerplate {
|
|
|
11102
11681
|
draw.setCurrentId(`${d.uid}_e0`);
|
|
11103
11682
|
draw.setCurrentClassName(`${d.className}-v-line`);
|
|
11104
11683
|
// draw.line( d.center.clone().add(0,d.axis.y-d.center.y), d.axis, '#c8c8c8' );
|
|
11105
|
-
draw.
|
|
11684
|
+
draw.handleLine(d.center.clone().add(0, d.signedRadiusV()).rotate(d.rotation, d.center), d.axis); // , "#c8c8c8");
|
|
11106
11685
|
draw.setCurrentId(`${d.uid}_e1`);
|
|
11107
11686
|
draw.setCurrentClassName(`${d.className}-h-line`);
|
|
11108
11687
|
// draw.line( d.center.clone().add(d.axis.x-d.center.x,0), d.axis, '#c8c8c8' );
|
|
11109
|
-
draw.
|
|
11688
|
+
draw.handleLine(d.center.clone().add(d.signedRadiusH(), 0).rotate(d.rotation, d.center), d.axis); // , "#c8c8c8");
|
|
11110
11689
|
}
|
|
11111
11690
|
draw.setCurrentId(d.uid);
|
|
11112
11691
|
draw.setCurrentClassName(`${d.className}`);
|
|
@@ -12042,22 +12621,35 @@ PlotBoilerplate.utils = {
|
|
|
12042
12621
|
**/
|
|
12043
12622
|
safeMergeByKeys: (base, extension) => {
|
|
12044
12623
|
for (var k in extension) {
|
|
12045
|
-
if (!extension.hasOwnProperty(k))
|
|
12624
|
+
if (!extension.hasOwnProperty(k)) {
|
|
12046
12625
|
continue;
|
|
12626
|
+
}
|
|
12047
12627
|
if (base.hasOwnProperty(k)) {
|
|
12048
|
-
|
|
12628
|
+
const typ = typeof base[k];
|
|
12629
|
+
const extVal = extension[k];
|
|
12049
12630
|
try {
|
|
12050
|
-
if (typ == "boolean")
|
|
12051
|
-
|
|
12052
|
-
|
|
12053
|
-
|
|
12054
|
-
|
|
12631
|
+
if (typ == "boolean") {
|
|
12632
|
+
if (typeof extVal === "string")
|
|
12633
|
+
base[k] = Boolean(!!JSON.parse(extVal));
|
|
12634
|
+
else
|
|
12635
|
+
base[k] = extVal;
|
|
12636
|
+
}
|
|
12637
|
+
else if (typ == "number") {
|
|
12638
|
+
if (typeof extVal === "string")
|
|
12639
|
+
base[k] = Number(JSON.parse(extVal) * 1);
|
|
12640
|
+
else
|
|
12641
|
+
base[k] = extension[k];
|
|
12642
|
+
}
|
|
12643
|
+
else if (typ == "function" && typeof extVal == "function") {
|
|
12055
12644
|
base[k] = extension[k];
|
|
12056
|
-
|
|
12645
|
+
}
|
|
12646
|
+
else {
|
|
12647
|
+
// Probably a sting
|
|
12057
12648
|
base[k] = extension[k];
|
|
12649
|
+
}
|
|
12058
12650
|
}
|
|
12059
12651
|
catch (e) {
|
|
12060
|
-
console.error("error in key ", k,
|
|
12652
|
+
console.error("error in key ", k, extVal, e);
|
|
12061
12653
|
}
|
|
12062
12654
|
}
|
|
12063
12655
|
else {
|
|
@@ -12066,6 +12658,31 @@ PlotBoilerplate.utils = {
|
|
|
12066
12658
|
}
|
|
12067
12659
|
return base;
|
|
12068
12660
|
},
|
|
12661
|
+
/*
|
|
12662
|
+
__safeMergeByKeys: <KeyType extends string | number | symbol, ValueType extends boolean | number | string | Function>(
|
|
12663
|
+
base: Record<KeyType, ValueType>,
|
|
12664
|
+
extension: Record<KeyType, string>
|
|
12665
|
+
): Record<KeyType, ValueType> => {
|
|
12666
|
+
for (var k in extension) {
|
|
12667
|
+
if (!extension.hasOwnProperty(k)) continue;
|
|
12668
|
+
if (base.hasOwnProperty(k)) {
|
|
12669
|
+
var typ = typeof base[k];
|
|
12670
|
+
try {
|
|
12671
|
+
if (typ == "boolean") base[k] = !!JSON.parse(extension[k]);
|
|
12672
|
+
else if (typ == "number") base[k] = JSON.parse(extension[k]) * 1;
|
|
12673
|
+
else if (typ == "function" && typeof extension[k] == "function") base[k] = extension[k];
|
|
12674
|
+
else base[k] = extension[k];
|
|
12675
|
+
} catch (e) {
|
|
12676
|
+
console.error("error in key ", k, extension[k], e);
|
|
12677
|
+
}
|
|
12678
|
+
} else {
|
|
12679
|
+
base[k] = extension[k];
|
|
12680
|
+
}
|
|
12681
|
+
}
|
|
12682
|
+
return base;
|
|
12683
|
+
},
|
|
12684
|
+
*()
|
|
12685
|
+
|
|
12069
12686
|
/**
|
|
12070
12687
|
* A helper function to scale elements (usually the canvas) using CSS.
|
|
12071
12688
|
*
|