plotboilerplate 1.20.2 → 1.22.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 +2012 -1366
- 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 +1199 -541
- package/dist/plotboilerplate.min.js +1 -1
- package/package.json +3 -2
- 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 +47 -1
- package/src/cjs/Polygon.js +116 -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/Params.d.ts +15 -0
- package/src/cjs/utils/Params.js +49 -0
- package/src/cjs/utils/Params.js.map +1 -0
- package/src/cjs/utils/algorithms/ContourLineDetection.d.ts +150 -0
- package/src/cjs/utils/algorithms/ContourLineDetection.js +367 -0
- package/src/cjs/utils/algorithms/ContourLineDetection.js.map +1 -0
- package/src/cjs/utils/algorithms/clearDuplicateVertices.d.ts +21 -0
- package/src/cjs/utils/algorithms/clearDuplicateVertices.js +48 -0
- package/src/cjs/utils/algorithms/clearDuplicateVertices.js.map +1 -0
- package/src/cjs/utils/creategui.js +16 -10
- package/src/cjs/utils/datastructures/DataGrid2d.d.ts +47 -0
- package/src/cjs/utils/datastructures/DataGrid2d.js +20 -0
- package/src/cjs/utils/datastructures/DataGrid2d.js.map +1 -0
- package/src/cjs/utils/datastructures/DataGrid2dListAdapter.d.ts +65 -0
- package/src/cjs/utils/datastructures/DataGrid2dListAdapter.js +84 -0
- package/src/cjs/utils/datastructures/DataGrid2dListAdapter.js.map +1 -0
- package/src/cjs/utils/datastructures/GenericPath.d.ts +14 -3
- package/src/cjs/utils/datastructures/GenericPath.js +20 -3
- package/src/cjs/utils/datastructures/GenericPath.js.map +1 -1
- 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 +47 -1
- package/src/esm/Polygon.js +114 -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/Params.d.ts +15 -0
- package/src/esm/utils/Params.js +44 -0
- package/src/esm/utils/Params.js.map +1 -0
- package/src/esm/utils/algorithms/ContourLineDetection.d.ts +150 -0
- package/src/esm/utils/algorithms/ContourLineDetection.js +362 -0
- package/src/esm/utils/algorithms/ContourLineDetection.js.map +1 -0
- package/src/esm/utils/algorithms/clearDuplicateVertices.d.ts +21 -0
- package/src/esm/utils/algorithms/clearDuplicateVertices.js +44 -0
- package/src/esm/utils/algorithms/clearDuplicateVertices.js.map +1 -0
- package/src/esm/utils/datastructures/DataGrid2d.d.ts +47 -0
- package/src/esm/utils/datastructures/DataGrid2d.js +19 -0
- package/src/esm/utils/datastructures/DataGrid2d.js.map +1 -0
- package/src/esm/utils/datastructures/DataGrid2dListAdapter.d.ts +65 -0
- package/src/esm/utils/datastructures/DataGrid2dListAdapter.js +79 -0
- package/src/esm/utils/datastructures/DataGrid2dListAdapter.js.map +1 -0
- package/src/esm/utils/datastructures/GenericPath.d.ts +14 -3
- package/src/esm/utils/datastructures/GenericPath.js +20 -3
- package/src/esm/utils/datastructures/GenericPath.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 +121 -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/Params.ts +47 -0
- package/src/ts/utils/algorithms/ContourLineDetection.ts +485 -0
- package/src/ts/utils/algorithms/clearDuplicateVertices.ts +49 -0
- package/src/ts/utils/datastructures/DataGrid2d.ts +54 -0
- package/src/ts/utils/datastructures/DataGrid2dListAdapter.ts +121 -0
- package/src/ts/utils/datastructures/GenericPath.ts +21 -3
- 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,886 @@ 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
|
+
* @modified 2023-11-24 Added the `Polygon.containsPolygon(Polygon)' function.
|
|
1448
|
+
* @version 1.12.0
|
|
1449
|
+
*
|
|
1450
|
+
* @file Polygon
|
|
1451
|
+
* @public
|
|
1452
|
+
**/
|
|
1584
1453
|
/**
|
|
1585
|
-
* @classdesc
|
|
1586
|
-
*
|
|
1454
|
+
* @classdesc A polygon class. Any polygon consists of an array of vertices; polygons can be open or closed.
|
|
1455
|
+
*
|
|
1456
|
+
* @requires BezierPath
|
|
1457
|
+
* @requires Bounds
|
|
1458
|
+
* @requires SVGSerializabe
|
|
1587
1459
|
* @requires UID
|
|
1460
|
+
* @requires UIDGenerator
|
|
1588
1461
|
* @requires Vertex
|
|
1589
1462
|
* @requires XYCoords
|
|
1590
1463
|
*/
|
|
1591
|
-
class
|
|
1464
|
+
class Polygon {
|
|
1592
1465
|
/**
|
|
1593
|
-
*
|
|
1466
|
+
* The constructor.
|
|
1594
1467
|
*
|
|
1595
1468
|
* @constructor
|
|
1596
|
-
* @name
|
|
1597
|
-
* @param {Vertex}
|
|
1598
|
-
* @param {
|
|
1469
|
+
* @name Polygon
|
|
1470
|
+
* @param {Vertex[]} vertices - An array of 2d vertices that shape the polygon.
|
|
1471
|
+
* @param {boolean} isOpen - Indicates if the polygon should be rendered as an open or closed shape.
|
|
1599
1472
|
**/
|
|
1600
|
-
constructor(
|
|
1473
|
+
constructor(vertices, isOpen) {
|
|
1474
|
+
/**
|
|
1475
|
+
* Required to generate proper CSS classes and other class related IDs.
|
|
1476
|
+
**/
|
|
1477
|
+
this.className = "Polygon";
|
|
1601
1478
|
this.uid = UIDGenerator.next();
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
this.
|
|
1479
|
+
if (typeof vertices == "undefined")
|
|
1480
|
+
vertices = [];
|
|
1481
|
+
this.vertices = vertices;
|
|
1482
|
+
this.isOpen = isOpen || false;
|
|
1605
1483
|
}
|
|
1606
1484
|
/**
|
|
1607
|
-
*
|
|
1485
|
+
* Add a vertex to the end of the `vertices` array.
|
|
1608
1486
|
*
|
|
1609
|
-
* @method
|
|
1487
|
+
* @method addVert
|
|
1488
|
+
* @param {Vertex} vert - The vertex to add.
|
|
1610
1489
|
* @instance
|
|
1611
|
-
* @memberof
|
|
1490
|
+
* @memberof Polygon
|
|
1612
1491
|
**/
|
|
1613
|
-
|
|
1614
|
-
|
|
1492
|
+
addVertex(vert) {
|
|
1493
|
+
this.vertices.push(vert);
|
|
1615
1494
|
}
|
|
1616
1495
|
/**
|
|
1617
|
-
*
|
|
1618
|
-
* vector is not a null vector.
|
|
1496
|
+
* Get the polygon vertex at the given position (index).
|
|
1619
1497
|
*
|
|
1620
|
-
*
|
|
1621
|
-
*
|
|
1622
|
-
*
|
|
1623
|
-
*
|
|
1498
|
+
* The index may exceed the total vertex count, and will be wrapped around then (modulo).
|
|
1499
|
+
*
|
|
1500
|
+
* For k >= 0:
|
|
1501
|
+
* - getVertexAt( vertices.length ) == getVertexAt( 0 )
|
|
1502
|
+
* - getVertexAt( vertices.length + k ) == getVertexAt( k )
|
|
1503
|
+
* - getVertexAt( -k ) == getVertexAt( vertices.length -k )
|
|
1504
|
+
*
|
|
1505
|
+
* @metho getVertexAt
|
|
1506
|
+
* @param {number} index - The index of the desired vertex.
|
|
1507
|
+
* @instance
|
|
1508
|
+
* @memberof Polygon
|
|
1509
|
+
* @return {Vertex} At the given index.
|
|
1624
1510
|
**/
|
|
1625
|
-
|
|
1626
|
-
|
|
1511
|
+
getVertexAt(index) {
|
|
1512
|
+
if (index < 0)
|
|
1513
|
+
return this.vertices[this.vertices.length - (Math.abs(index) % this.vertices.length)];
|
|
1514
|
+
else
|
|
1515
|
+
return this.vertices[index % this.vertices.length];
|
|
1627
1516
|
}
|
|
1628
1517
|
/**
|
|
1629
|
-
*
|
|
1518
|
+
* Move the polygon's vertices by the given amount.
|
|
1630
1519
|
*
|
|
1631
|
-
* @method
|
|
1632
|
-
* @param {XYCoords} amount The amount
|
|
1633
|
-
* @return {VertTuple} this
|
|
1520
|
+
* @method move
|
|
1521
|
+
* @param {XYCoords} amount - The amount to move.
|
|
1634
1522
|
* @instance
|
|
1635
|
-
* @memberof
|
|
1523
|
+
* @memberof Polygon
|
|
1524
|
+
* @return {Polygon} this for chaining
|
|
1636
1525
|
**/
|
|
1637
|
-
|
|
1638
|
-
this.
|
|
1639
|
-
|
|
1526
|
+
move(amount) {
|
|
1527
|
+
for (var i in this.vertices) {
|
|
1528
|
+
this.vertices[i].add(amount);
|
|
1529
|
+
}
|
|
1640
1530
|
return this;
|
|
1641
1531
|
}
|
|
1642
1532
|
/**
|
|
1643
|
-
*
|
|
1533
|
+
* Check if the given vertex is inside this polygon.<br>
|
|
1534
|
+
* <br>
|
|
1535
|
+
* Ray-casting algorithm found at<br>
|
|
1536
|
+
* https://stackoverflow.com/questions/22521982/check-if-point-inside-a-polygon
|
|
1644
1537
|
*
|
|
1645
|
-
* @method
|
|
1646
|
-
* @param {XYCoords}
|
|
1647
|
-
* @return {
|
|
1538
|
+
* @method containsVert
|
|
1539
|
+
* @param {XYCoords} vert - The vertex to check. The new x-component.
|
|
1540
|
+
* @return {boolean} True if the passed vertex is inside this polygon. The polygon is considered closed.
|
|
1648
1541
|
* @instance
|
|
1649
|
-
* @memberof
|
|
1542
|
+
* @memberof Polygon
|
|
1650
1543
|
**/
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1544
|
+
containsVert(vert) {
|
|
1545
|
+
// ray-casting algorithm based on
|
|
1546
|
+
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
|
|
1547
|
+
var inside = false;
|
|
1548
|
+
for (var i = 0, j = this.vertices.length - 1; i < this.vertices.length; j = i++) {
|
|
1549
|
+
let xi = this.vertices[i].x, yi = this.vertices[i].y;
|
|
1550
|
+
let xj = this.vertices[j].x, yj = this.vertices[j].y;
|
|
1551
|
+
var intersect = yi > vert.y != yj > vert.y && vert.x < ((xj - xi) * (vert.y - yi)) / (yj - yi) + xi;
|
|
1552
|
+
if (intersect)
|
|
1553
|
+
inside = !inside;
|
|
1554
|
+
}
|
|
1555
|
+
return inside;
|
|
1655
1556
|
}
|
|
1656
1557
|
/**
|
|
1657
|
-
*
|
|
1558
|
+
* Check if the passed polygon is completly contained inside this polygon.
|
|
1658
1559
|
*
|
|
1659
|
-
*
|
|
1660
|
-
*
|
|
1661
|
-
*
|
|
1662
|
-
*
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1560
|
+
* This means:
|
|
1561
|
+
* - all polygon's vertices must be inside this polygon.
|
|
1562
|
+
* - the polygon has no edge intersections with this polygon.
|
|
1563
|
+
*
|
|
1564
|
+
* @param {Polygon} polygon - The polygon to check if contained.
|
|
1565
|
+
* @return {boolean}
|
|
1566
|
+
*/
|
|
1567
|
+
containsPolygon(polygon) {
|
|
1568
|
+
for (var i = 0; i < polygon.vertices.length; i++) {
|
|
1569
|
+
if (!this.containsVert(polygon.vertices[i])) {
|
|
1570
|
+
return false;
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
// All vertices are inside; check for intersections
|
|
1574
|
+
const lineSegment = new Line(new Vertex(), new Vertex());
|
|
1575
|
+
for (var i = 0; i < polygon.vertices.length; i++) {
|
|
1576
|
+
lineSegment.a.set(polygon.vertices[i]);
|
|
1577
|
+
lineSegment.b.set(polygon.vertices[(i + 1) % polygon.vertices.length]);
|
|
1578
|
+
if (this.lineIntersections(lineSegment, true).length > 0) {
|
|
1579
|
+
// Current segment has intersection(s) with this polygon.
|
|
1580
|
+
return false;
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
return true;
|
|
1667
1584
|
}
|
|
1668
1585
|
/**
|
|
1669
|
-
*
|
|
1586
|
+
* Calculate the area of the given polygon (unsigned).
|
|
1670
1587
|
*
|
|
1671
|
-
*
|
|
1672
|
-
*
|
|
1673
|
-
* @
|
|
1588
|
+
* Note that this does not work for self-intersecting polygons.
|
|
1589
|
+
*
|
|
1590
|
+
* @method area
|
|
1674
1591
|
* @instance
|
|
1675
|
-
* @memberof
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
return this;
|
|
1592
|
+
* @memberof Polygon
|
|
1593
|
+
* @return {number}
|
|
1594
|
+
*/
|
|
1595
|
+
area() {
|
|
1596
|
+
return Polygon.utils.area(this.vertices);
|
|
1680
1597
|
}
|
|
1681
1598
|
/**
|
|
1682
|
-
*
|
|
1599
|
+
* Calulate the signed polyon area by interpreting the polygon as a matrix
|
|
1600
|
+
* and calculating its determinant.
|
|
1683
1601
|
*
|
|
1684
|
-
* @method
|
|
1685
|
-
* @param {Vertex} newA - The new desired location of 'a'. Vertex 'b' will be moved, too.
|
|
1686
|
-
* @return {VertTuple} this
|
|
1602
|
+
* @method signedArea
|
|
1687
1603
|
* @instance
|
|
1688
|
-
* @memberof
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
this.b.add(diff);
|
|
1694
|
-
return this;
|
|
1604
|
+
* @memberof Polygon
|
|
1605
|
+
* @return {number}
|
|
1606
|
+
*/
|
|
1607
|
+
signedArea() {
|
|
1608
|
+
return Polygon.utils.signedArea(this.vertices);
|
|
1695
1609
|
}
|
|
1696
1610
|
/**
|
|
1697
|
-
* Get the
|
|
1611
|
+
* Get the winding order of this polgon: clockwise or counterclockwise.
|
|
1698
1612
|
*
|
|
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
|
|
1613
|
+
* @method isClockwise
|
|
1702
1614
|
* @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);
|
|
1615
|
+
* @memberof Polygon
|
|
1616
|
+
* @return {boolean}
|
|
1617
|
+
*/
|
|
1618
|
+
isClockwise() {
|
|
1619
|
+
return Polygon.utils.signedArea(this.vertices) < 0;
|
|
1715
1620
|
}
|
|
1716
1621
|
/**
|
|
1717
|
-
* Get
|
|
1718
|
-
*
|
|
1622
|
+
* Get the perimeter of this polygon.
|
|
1623
|
+
* The perimeter is the absolute length of the outline.
|
|
1624
|
+
*
|
|
1625
|
+
* If this polygon is open then the last segment (connecting the first and the
|
|
1626
|
+
* last vertex) will be skipped.
|
|
1627
|
+
*
|
|
1628
|
+
* @method perimeter
|
|
1629
|
+
* @instance
|
|
1630
|
+
* @memberof Polygon
|
|
1631
|
+
* @return {number}
|
|
1632
|
+
*/
|
|
1633
|
+
perimeter() {
|
|
1634
|
+
let length = 0;
|
|
1635
|
+
for (var i = 1; i < this.vertices.length; i++) {
|
|
1636
|
+
length += this.vertices[i - 1].distance(this.vertices[i]);
|
|
1637
|
+
}
|
|
1638
|
+
if (!this.isOpen && this.vertices.length > 1) {
|
|
1639
|
+
length += this.vertices[0].distance(this.vertices[this.vertices.length - 1]);
|
|
1640
|
+
}
|
|
1641
|
+
return length;
|
|
1642
|
+
}
|
|
1643
|
+
/**
|
|
1644
|
+
* Scale the polygon relative to the given center.
|
|
1645
|
+
*
|
|
1646
|
+
* @method scale
|
|
1647
|
+
* @param {number} factor - The scale factor.
|
|
1648
|
+
* @param {Vertex} center - The center of scaling.
|
|
1649
|
+
* @return {Polygon} this, for chaining.
|
|
1650
|
+
* @instance
|
|
1651
|
+
* @memberof Polygon
|
|
1652
|
+
**/
|
|
1653
|
+
scale(factor, center) {
|
|
1654
|
+
for (var i in this.vertices) {
|
|
1655
|
+
if (typeof this.vertices[i].scale == "function")
|
|
1656
|
+
this.vertices[i].scale(factor, center);
|
|
1657
|
+
else
|
|
1658
|
+
console.log("There seems to be a null vertex!", this.vertices[i]);
|
|
1659
|
+
}
|
|
1660
|
+
return this;
|
|
1661
|
+
}
|
|
1662
|
+
/**
|
|
1663
|
+
* Rotate the polygon around the given center.
|
|
1664
|
+
*
|
|
1665
|
+
* @method rotate
|
|
1666
|
+
* @param {number} angle - The rotation angle.
|
|
1667
|
+
* @param {Vertex} center - The center of rotation.
|
|
1668
|
+
* @instance
|
|
1669
|
+
* @memberof Polygon
|
|
1670
|
+
* @return {Polygon} this, for chaining.
|
|
1671
|
+
**/
|
|
1672
|
+
rotate(angle, center) {
|
|
1673
|
+
for (var i in this.vertices) {
|
|
1674
|
+
this.vertices[i].rotate(angle, center);
|
|
1675
|
+
}
|
|
1676
|
+
return this;
|
|
1677
|
+
}
|
|
1678
|
+
/**
|
|
1679
|
+
* Get all line intersections with this polygon.
|
|
1680
|
+
*
|
|
1681
|
+
* See demo `47-closest-vector-projection-on-polygon` for how it works.
|
|
1682
|
+
*
|
|
1683
|
+
* @param {VertTuple} line - The line to find intersections with.
|
|
1684
|
+
* @param {boolean} inVectorBoundsOnly - If set to true only intersecion points on the passed vector are returned (located strictly between start and end vertex).
|
|
1685
|
+
* @returns {Array<Vertex>} - An array of all intersections within the polygon bounds.
|
|
1686
|
+
*/
|
|
1687
|
+
lineIntersections(line, inVectorBoundsOnly = false) {
|
|
1688
|
+
// Find the intersections of all lines inside the edge bounds
|
|
1689
|
+
const intersectionPoints = [];
|
|
1690
|
+
for (var i = 0; i < this.vertices.length; i++) {
|
|
1691
|
+
const polyLine = new Line(this.vertices[i], this.vertices[(i + 1) % this.vertices.length]);
|
|
1692
|
+
const intersection = polyLine.intersection(line);
|
|
1693
|
+
// true => only inside bounds
|
|
1694
|
+
// ignore last edge if open
|
|
1695
|
+
if ((!this.isOpen || i + 1 !== this.vertices.length) &&
|
|
1696
|
+
intersection !== null &&
|
|
1697
|
+
polyLine.hasPoint(intersection, true) &&
|
|
1698
|
+
(!inVectorBoundsOnly || line.hasPoint(intersection, inVectorBoundsOnly))) {
|
|
1699
|
+
intersectionPoints.push(intersection);
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1702
|
+
return intersectionPoints;
|
|
1703
|
+
}
|
|
1704
|
+
/**
|
|
1705
|
+
* Get the closest line-polygon-intersection point (closest the line point A).
|
|
1706
|
+
*
|
|
1707
|
+
* See demo `47-closest-vector-projection-on-polygon` for how it works.
|
|
1708
|
+
*
|
|
1709
|
+
* @param {VertTuple} line - The line to find intersections with.
|
|
1710
|
+
* @param {boolean} inVectorBoundsOnly - If set to true only intersecion points on the passed vector are considered (located strictly between start and end vertex).
|
|
1711
|
+
* @returns {Array<Vertex>} - An array of all intersections within the polygon bounds.
|
|
1712
|
+
*/
|
|
1713
|
+
closestLineIntersection(line, inVectorBoundsOnly = false) {
|
|
1714
|
+
const allIntersections = this.lineIntersections(line, inVectorBoundsOnly);
|
|
1715
|
+
if (allIntersections.length <= 0) {
|
|
1716
|
+
// Empty polygon -> no intersections
|
|
1717
|
+
return null;
|
|
1718
|
+
}
|
|
1719
|
+
// Find the closest intersection
|
|
1720
|
+
let closestIntersection = new Vertex(Number.MAX_VALUE, Number.MAX_VALUE);
|
|
1721
|
+
let curDist = Number.MAX_VALUE;
|
|
1722
|
+
for (var i in allIntersections) {
|
|
1723
|
+
const curVert = allIntersections[i];
|
|
1724
|
+
const dist = curVert.distance(line.a);
|
|
1725
|
+
if (dist < curDist) {
|
|
1726
|
+
// && line.hasPoint(curVert)) {
|
|
1727
|
+
curDist = dist;
|
|
1728
|
+
closestIntersection = curVert;
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
return closestIntersection;
|
|
1732
|
+
}
|
|
1733
|
+
/**
|
|
1734
|
+
* Construct a new polygon from this polygon with more vertices on each edge. The
|
|
1735
|
+
* interpolation count determines the number of additional vertices on each edge.
|
|
1736
|
+
* An interpolation count of `0` will return a polygon that equals the source
|
|
1737
|
+
* polygon.
|
|
1738
|
+
*
|
|
1739
|
+
* @param {number} interpolationCount
|
|
1740
|
+
* @returns {Polygon} A polygon with `interpolationCount` more vertices (as as factor).
|
|
1741
|
+
*/
|
|
1742
|
+
getInterpolationPolygon(interpolationCount) {
|
|
1743
|
+
const verts = [];
|
|
1744
|
+
for (var i = 0; i < this.vertices.length; i++) {
|
|
1745
|
+
const curVert = this.vertices[i];
|
|
1746
|
+
const nextVert = this.vertices[(i + 1) % this.vertices.length];
|
|
1747
|
+
verts.push(curVert.clone());
|
|
1748
|
+
// Add interpolation points
|
|
1749
|
+
if (!this.isOpen || i + 1 !== this.vertices.length) {
|
|
1750
|
+
const lerpAmount = 1.0 / (interpolationCount + 1);
|
|
1751
|
+
for (var j = 1; j <= interpolationCount; j++) {
|
|
1752
|
+
verts.push(curVert.clone().lerp(nextVert, lerpAmount * j));
|
|
1753
|
+
}
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
return new Polygon(verts, this.isOpen);
|
|
1757
|
+
}
|
|
1758
|
+
/**
|
|
1759
|
+
* Convert this polygon into a new polygon with n evenly distributed vertices.
|
|
1760
|
+
*
|
|
1761
|
+
* @param {number} pointCount - Must not be negative.
|
|
1762
|
+
*/
|
|
1763
|
+
getEvenDistributionPolygon(pointCount) {
|
|
1764
|
+
if (pointCount <= 0) {
|
|
1765
|
+
throw new Error("pointCount must be larger than zero; is " + pointCount + ".");
|
|
1766
|
+
}
|
|
1767
|
+
const result = new Polygon([], this.isOpen);
|
|
1768
|
+
if (this.vertices.length === 0) {
|
|
1769
|
+
return result;
|
|
1770
|
+
}
|
|
1771
|
+
// Fetch and add the start point from the source polygon
|
|
1772
|
+
let polygonPoint = new Vertex(this.vertices[0]);
|
|
1773
|
+
result.vertices.push(polygonPoint);
|
|
1774
|
+
if (this.vertices.length === 1) {
|
|
1775
|
+
return result;
|
|
1776
|
+
}
|
|
1777
|
+
const perimeter = this.perimeter();
|
|
1778
|
+
const stepSize = perimeter / pointCount;
|
|
1779
|
+
const n = this.vertices.length;
|
|
1780
|
+
let polygonIndex = 1;
|
|
1781
|
+
let nextPolygonPoint = new Vertex(this.vertices[1]);
|
|
1782
|
+
let segmentLength = polygonPoint.distance(nextPolygonPoint);
|
|
1783
|
+
let loopMax = this.isOpen ? n : n + 1;
|
|
1784
|
+
let curSegmentU = stepSize;
|
|
1785
|
+
var i = 1;
|
|
1786
|
+
while (i < pointCount && polygonIndex < loopMax) {
|
|
1787
|
+
// Check if next eq point is inside this segment
|
|
1788
|
+
if (curSegmentU < segmentLength) {
|
|
1789
|
+
let newPoint = polygonPoint.clone().lerpAbs(nextPolygonPoint, curSegmentU);
|
|
1790
|
+
result.vertices.push(newPoint);
|
|
1791
|
+
curSegmentU += stepSize;
|
|
1792
|
+
i++;
|
|
1793
|
+
}
|
|
1794
|
+
else {
|
|
1795
|
+
polygonIndex++;
|
|
1796
|
+
polygonPoint = nextPolygonPoint;
|
|
1797
|
+
nextPolygonPoint = new Vertex(this.vertices[polygonIndex % n]);
|
|
1798
|
+
curSegmentU = curSegmentU - segmentLength;
|
|
1799
|
+
segmentLength = polygonPoint.distance(nextPolygonPoint);
|
|
1800
|
+
}
|
|
1801
|
+
}
|
|
1802
|
+
return result;
|
|
1803
|
+
}
|
|
1804
|
+
/**
|
|
1805
|
+
* Get the bounding box (bounds) of this polygon.
|
|
1806
|
+
*
|
|
1807
|
+
* @method getBounds
|
|
1808
|
+
* @instance
|
|
1809
|
+
* @memberof Polygon
|
|
1810
|
+
* @return {Bounds} The rectangular bounds of this polygon.
|
|
1811
|
+
**/
|
|
1812
|
+
getBounds() {
|
|
1813
|
+
return Bounds.computeFromVertices(this.vertices);
|
|
1814
|
+
}
|
|
1815
|
+
/**
|
|
1816
|
+
* Create a deep copy of this polygon.
|
|
1817
|
+
*
|
|
1818
|
+
* @return {Polygon} The cloned polygon.
|
|
1819
|
+
*/
|
|
1820
|
+
clone() {
|
|
1821
|
+
return new Polygon(this.vertices.map(vert => vert.clone()), this.isOpen);
|
|
1822
|
+
}
|
|
1823
|
+
/**
|
|
1824
|
+
* Convert this polygon to a sequence of quadratic Bézier curves.<br>
|
|
1719
1825
|
* <br>
|
|
1720
|
-
* The
|
|
1826
|
+
* The first vertex in the returned array is the start point.<br>
|
|
1827
|
+
* The following sequence are pairs of control-point-and-end-point:
|
|
1828
|
+
* <pre>startPoint, controlPoint0, pathPoint1, controlPoint1, pathPoint2, controlPoint2, ..., endPoint</pre>
|
|
1721
1829
|
*
|
|
1722
|
-
* @method
|
|
1723
|
-
* @
|
|
1724
|
-
* @return {Vertex} The vertex a position t.
|
|
1830
|
+
* @method toQuadraticBezierData
|
|
1831
|
+
* @return {Vertex[]} An array of 2d vertices that shape the quadratic Bézier curve.
|
|
1725
1832
|
* @instance
|
|
1726
|
-
* @memberof
|
|
1833
|
+
* @memberof Polygon
|
|
1727
1834
|
**/
|
|
1728
|
-
|
|
1729
|
-
|
|
1835
|
+
toQuadraticBezierData() {
|
|
1836
|
+
if (this.vertices.length < 3)
|
|
1837
|
+
return [];
|
|
1838
|
+
var qbezier = [];
|
|
1839
|
+
var cc0 = this.vertices[0];
|
|
1840
|
+
var cc1 = this.vertices[1];
|
|
1841
|
+
var edgeCenter = new Vertex(cc0.x + (cc1.x - cc0.x) / 2, cc0.y + (cc1.y - cc0.y) / 2);
|
|
1842
|
+
qbezier.push(edgeCenter);
|
|
1843
|
+
var limit = this.isOpen ? this.vertices.length : this.vertices.length + 1;
|
|
1844
|
+
for (var t = 1; t < limit; t++) {
|
|
1845
|
+
cc0 = this.vertices[t % this.vertices.length];
|
|
1846
|
+
cc1 = this.vertices[(t + 1) % this.vertices.length];
|
|
1847
|
+
var edgeCenter = new Vertex(cc0.x + (cc1.x - cc0.x) / 2, cc0.y + (cc1.y - cc0.y) / 2);
|
|
1848
|
+
qbezier.push(cc0);
|
|
1849
|
+
qbezier.push(edgeCenter);
|
|
1850
|
+
cc0 = cc1;
|
|
1851
|
+
}
|
|
1852
|
+
return qbezier;
|
|
1730
1853
|
}
|
|
1731
1854
|
/**
|
|
1732
|
-
*
|
|
1855
|
+
* Convert this polygon to a quadratic bezier curve, represented as an SVG data string.
|
|
1733
1856
|
*
|
|
1734
|
-
*
|
|
1857
|
+
* @method toQuadraticBezierSVGString
|
|
1858
|
+
* @return {string} The 'd' part for an SVG 'path' element.
|
|
1859
|
+
* @instance
|
|
1860
|
+
* @memberof Polygon
|
|
1861
|
+
**/
|
|
1862
|
+
toQuadraticBezierSVGString() {
|
|
1863
|
+
var qdata = this.toQuadraticBezierData();
|
|
1864
|
+
if (qdata.length == 0)
|
|
1865
|
+
return "";
|
|
1866
|
+
var buffer = ["M " + qdata[0].x + " " + qdata[0].y];
|
|
1867
|
+
for (var i = 1; i < qdata.length; i += 2) {
|
|
1868
|
+
buffer.push("Q " + qdata[i].x + " " + qdata[i].y + ", " + qdata[i + 1].x + " " + qdata[i + 1].y);
|
|
1869
|
+
}
|
|
1870
|
+
return buffer.join(" ");
|
|
1871
|
+
}
|
|
1872
|
+
/**
|
|
1873
|
+
* Convert this polygon to a sequence of cubic Bézier curves.<br>
|
|
1874
|
+
* <br>
|
|
1875
|
+
* The first vertex in the returned array is the start point.<br>
|
|
1876
|
+
* The following sequence are triplets of (first-control-point, secnond-control-point, end-point):<br>
|
|
1877
|
+
* <pre>startPoint, controlPoint0_0, controlPoint1_1, pathPoint1, controlPoint1_0, controlPoint1_1, ..., endPoint</pre>
|
|
1735
1878
|
*
|
|
1736
|
-
* @method
|
|
1737
|
-
* @param {
|
|
1879
|
+
* @method toCubicBezierData
|
|
1880
|
+
* @param {number=} threshold - An optional threshold (default=1.0) how strong the curve segments
|
|
1881
|
+
* should over-/under-drive. Should be between 0.0 and 1.0 for best
|
|
1882
|
+
* results but other values are allowed.
|
|
1883
|
+
* @return {Vertex[]} An array of 2d vertices that shape the cubic Bézier curve.
|
|
1738
1884
|
* @instance
|
|
1739
|
-
* @memberof
|
|
1740
|
-
* @return {Number}
|
|
1885
|
+
* @memberof Polygon
|
|
1741
1886
|
**/
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1887
|
+
toCubicBezierData(threshold) {
|
|
1888
|
+
if (typeof threshold == "undefined")
|
|
1889
|
+
threshold = 1.0;
|
|
1890
|
+
if (this.vertices.length < 3)
|
|
1891
|
+
return [];
|
|
1892
|
+
var cbezier = [];
|
|
1893
|
+
var a = this.vertices[0];
|
|
1894
|
+
var b = this.vertices[1];
|
|
1895
|
+
var edgeCenter = new Vertex(a.x + (b.x - a.x) / 2, a.y + (b.y - a.y) / 2);
|
|
1896
|
+
cbezier.push(edgeCenter);
|
|
1897
|
+
var limit = this.isOpen ? this.vertices.length - 1 : this.vertices.length;
|
|
1898
|
+
for (var t = 0; t < limit; t++) {
|
|
1899
|
+
var a = this.vertices[t % this.vertices.length];
|
|
1900
|
+
var b = this.vertices[(t + 1) % this.vertices.length];
|
|
1901
|
+
var c = this.vertices[(t + 2) % this.vertices.length];
|
|
1902
|
+
var aCenter = new Vertex(a.x + (b.x - a.x) / 2, a.y + (b.y - a.y) / 2);
|
|
1903
|
+
var bCenter = new Vertex(b.x + (c.x - b.x) / 2, b.y + (c.y - b.y) / 2);
|
|
1904
|
+
var a2 = new Vertex(aCenter.x + (b.x - aCenter.x) * threshold, aCenter.y + (b.y - aCenter.y) * threshold);
|
|
1905
|
+
var b0 = new Vertex(bCenter.x + (b.x - bCenter.x) * threshold, bCenter.y + (b.y - bCenter.y) * threshold);
|
|
1906
|
+
cbezier.push(a2);
|
|
1907
|
+
cbezier.push(b0);
|
|
1908
|
+
cbezier.push(bCenter);
|
|
1909
|
+
}
|
|
1910
|
+
return cbezier;
|
|
1745
1911
|
}
|
|
1746
1912
|
/**
|
|
1747
|
-
*
|
|
1913
|
+
* Convert this polygon to a cubic bezier curve, represented as an SVG data string.
|
|
1748
1914
|
*
|
|
1749
|
-
*
|
|
1915
|
+
* @method toCubicBezierSVGString
|
|
1916
|
+
* @return {string} The 'd' part for an SVG 'path' element.
|
|
1917
|
+
* @instance
|
|
1918
|
+
* @memberof Polygon
|
|
1919
|
+
**/
|
|
1920
|
+
toCubicBezierSVGString(threshold) {
|
|
1921
|
+
var qdata = this.toCubicBezierData(threshold);
|
|
1922
|
+
if (qdata.length == 0)
|
|
1923
|
+
return "";
|
|
1924
|
+
var buffer = ["M " + qdata[0].x + " " + qdata[0].y];
|
|
1925
|
+
for (var i = 1; i < qdata.length; i += 3) {
|
|
1926
|
+
buffer.push("C " +
|
|
1927
|
+
qdata[i].x +
|
|
1928
|
+
" " +
|
|
1929
|
+
qdata[i].y +
|
|
1930
|
+
", " +
|
|
1931
|
+
qdata[i + 1].x +
|
|
1932
|
+
" " +
|
|
1933
|
+
qdata[i + 1].y +
|
|
1934
|
+
", " +
|
|
1935
|
+
qdata[i + 2].x +
|
|
1936
|
+
" " +
|
|
1937
|
+
qdata[i + 2].y);
|
|
1938
|
+
}
|
|
1939
|
+
return buffer.join(" ");
|
|
1940
|
+
}
|
|
1941
|
+
/**
|
|
1942
|
+
* Convert this polygon to a cubic bezier path instance.
|
|
1750
1943
|
*
|
|
1751
|
-
* @method
|
|
1752
|
-
* @param {
|
|
1944
|
+
* @method toCubicBezierPath
|
|
1945
|
+
* @param {number} threshold - The threshold, usually from 0.0 to 1.0.
|
|
1946
|
+
* @return {BezierPath} - A bezier path instance.
|
|
1753
1947
|
* @instance
|
|
1754
|
-
* @memberof
|
|
1755
|
-
|
|
1948
|
+
* @memberof Polygon
|
|
1949
|
+
**/
|
|
1950
|
+
toCubicBezierPath(threshold) {
|
|
1951
|
+
var qdata = this.toCubicBezierData(threshold);
|
|
1952
|
+
// Conver the linear path vertices to a two-dimensional path array
|
|
1953
|
+
var pathdata = [];
|
|
1954
|
+
for (var i = 0; i + 3 < qdata.length; i += 3) {
|
|
1955
|
+
pathdata.push([qdata[i], qdata[i + 3], qdata[i + 1], qdata[i + 2]]);
|
|
1956
|
+
}
|
|
1957
|
+
return BezierPath.fromArray(pathdata);
|
|
1958
|
+
}
|
|
1959
|
+
/**
|
|
1960
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
1961
|
+
* After calling this function the object might not hold valid data any more and
|
|
1962
|
+
* should not be used.
|
|
1756
1963
|
*/
|
|
1757
|
-
|
|
1758
|
-
|
|
1964
|
+
destroy() {
|
|
1965
|
+
for (var i = 0; i < this.vertices.length; i++) {
|
|
1966
|
+
this.vertices[i].destroy();
|
|
1967
|
+
}
|
|
1968
|
+
this.isDestroyed = true;
|
|
1759
1969
|
}
|
|
1970
|
+
}
|
|
1971
|
+
Polygon.utils = {
|
|
1760
1972
|
/**
|
|
1761
|
-
*
|
|
1973
|
+
* Calculate the area of the given polygon (unsigned).
|
|
1762
1974
|
*
|
|
1763
|
-
*
|
|
1975
|
+
* Note that this does not work for self-intersecting polygons.
|
|
1764
1976
|
*
|
|
1765
|
-
* @name
|
|
1766
|
-
* @
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1977
|
+
* @name area
|
|
1978
|
+
* @return {number}
|
|
1979
|
+
*/
|
|
1980
|
+
area(vertices) {
|
|
1981
|
+
// Found at:
|
|
1982
|
+
// https://stackoverflow.com/questions/16285134/calculating-polygon-area
|
|
1983
|
+
let total = 0.0;
|
|
1984
|
+
for (var i = 0, l = vertices.length; i < l; i++) {
|
|
1985
|
+
const addX = vertices[i].x;
|
|
1986
|
+
const addY = vertices[(i + 1) % l].y;
|
|
1987
|
+
const subX = vertices[(i + 1) % l].x;
|
|
1988
|
+
const subY = vertices[i].y;
|
|
1989
|
+
total += addX * addY * 0.5;
|
|
1990
|
+
total -= subX * subY * 0.5;
|
|
1991
|
+
}
|
|
1992
|
+
return Math.abs(total);
|
|
1993
|
+
},
|
|
1994
|
+
/**
|
|
1995
|
+
* Calulate the signed polyon area by interpreting the polygon as a matrix
|
|
1996
|
+
* and calculating its determinant.
|
|
1997
|
+
*
|
|
1998
|
+
* @name signedArea
|
|
1999
|
+
* @return {number}
|
|
2000
|
+
*/
|
|
2001
|
+
signedArea(vertices) {
|
|
2002
|
+
let sum = 0;
|
|
2003
|
+
const n = vertices.length;
|
|
2004
|
+
for (var i = 0; i < n; i++) {
|
|
2005
|
+
const j = (i + 1) % n;
|
|
2006
|
+
sum += (vertices[j].x - vertices[i].x) * (vertices[i].y + vertices[j].y);
|
|
2007
|
+
}
|
|
2008
|
+
return sum;
|
|
2009
|
+
}
|
|
2010
|
+
};
|
|
2011
|
+
|
|
2012
|
+
/**
|
|
2013
|
+
* @author Ikaros Kappler
|
|
2014
|
+
* @date 2020-05-11
|
|
2015
|
+
* @modified 2020-10-30 Added the static computeFromVertices function.
|
|
2016
|
+
* @modified 2020-11-19 Set min, max, width and height to private.
|
|
2017
|
+
* @modified 2021-02-02 Added the `toPolygon` method.
|
|
2018
|
+
* @modified 2021-06-21 (mid-summer) Added `getCenter` method.
|
|
2019
|
+
* @modified 2022-02-01 Added the `toString` function.
|
|
2020
|
+
* @modified 2022-10-09 Added the `fromDimension` function.
|
|
2021
|
+
* @modified 2022-11-28 Added the `clone` method.
|
|
2022
|
+
* @modified 2023-09-29 Added the `randomPoint` method.
|
|
2023
|
+
* @version 1.7.0
|
|
2024
|
+
**/
|
|
2025
|
+
/**
|
|
2026
|
+
* @classdesc A bounds class with min and max values. Implementing IBounds.
|
|
2027
|
+
*
|
|
2028
|
+
* @requires XYCoords
|
|
2029
|
+
* @requires Vertex
|
|
2030
|
+
* @requires IBounds
|
|
2031
|
+
**/
|
|
2032
|
+
class Bounds {
|
|
2033
|
+
/**
|
|
2034
|
+
* The constructor.
|
|
2035
|
+
*
|
|
2036
|
+
* @constructor
|
|
2037
|
+
* @name Bounds
|
|
2038
|
+
* @param {XYCoords} min - The min values (x,y) as a XYCoords tuple.
|
|
2039
|
+
* @param {XYCoords} max - The max values (x,y) as a XYCoords tuple.
|
|
1771
2040
|
**/
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
2041
|
+
constructor(min, max) {
|
|
2042
|
+
this.min = min;
|
|
2043
|
+
this.max = max;
|
|
2044
|
+
this.width = max.x - min.x;
|
|
2045
|
+
this.height = max.y - min.y;
|
|
2046
|
+
}
|
|
2047
|
+
/**
|
|
2048
|
+
* Convert this rectangular bounding box to a polygon with four vertices.
|
|
2049
|
+
*
|
|
2050
|
+
* @method toPolygon
|
|
2051
|
+
* @instance
|
|
2052
|
+
* @memberof Bounds
|
|
2053
|
+
* @return {Polygon} This bound rectangle as a polygon.
|
|
2054
|
+
*/
|
|
2055
|
+
toPolygon() {
|
|
2056
|
+
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
2057
|
}
|
|
1782
2058
|
/**
|
|
1783
|
-
*
|
|
1784
|
-
* that point is located between point `a` and `b`.
|
|
2059
|
+
* Get the center of this boinding box.
|
|
1785
2060
|
*
|
|
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.
|
|
2061
|
+
* @method getCenter
|
|
1790
2062
|
* @instance
|
|
1791
|
-
* @memberof
|
|
2063
|
+
* @memberof Bounds
|
|
2064
|
+
* @returns {Vertex} The center of these bounds.
|
|
1792
2065
|
*/
|
|
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
|
-
}
|
|
2066
|
+
getCenter() {
|
|
2067
|
+
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
2068
|
}
|
|
1804
2069
|
/**
|
|
1805
|
-
*
|
|
2070
|
+
* Generate a random point inside this bounds object. Safe areas at the border to avoid
|
|
2071
|
+
* included.
|
|
1806
2072
|
*
|
|
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.
|
|
2073
|
+
* @method randomPoint
|
|
1810
2074
|
* @instance
|
|
1811
|
-
* @memberof
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
2075
|
+
* @memberof Bounds
|
|
2076
|
+
* @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.
|
|
2077
|
+
* @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
|
|
2078
|
+
* @returns {Vertex} A pseudo random point inside these bounds.
|
|
2079
|
+
*/
|
|
2080
|
+
randomPoint(horizontalSafeArea = 0, verticalSafeArea = 0) {
|
|
2081
|
+
// Check if the safe areas are meant as percent
|
|
2082
|
+
const absHorizontalSafeArea = horizontalSafeArea > 0 && horizontalSafeArea < 1 ? this.width * horizontalSafeArea : horizontalSafeArea;
|
|
2083
|
+
const absVerticalSafeArea = verticalSafeArea > 0 && verticalSafeArea < 1 ? this.height * verticalSafeArea : verticalSafeArea;
|
|
2084
|
+
return new Vertex(this.min.x + absHorizontalSafeArea + Math.random() * (this.width - 2 * absHorizontalSafeArea), this.min.y + absVerticalSafeArea + Math.random() * (this.height - 2 * absVerticalSafeArea));
|
|
1816
2085
|
}
|
|
1817
2086
|
/**
|
|
1818
|
-
*
|
|
2087
|
+
* Convert these bounds to a human readable form.
|
|
1819
2088
|
*
|
|
1820
|
-
*
|
|
1821
|
-
*
|
|
1822
|
-
*
|
|
2089
|
+
* Note: the returned format might change in the future, so please do not
|
|
2090
|
+
* rely on the returned string format.
|
|
2091
|
+
*
|
|
2092
|
+
* @method toString
|
|
1823
2093
|
* @instance
|
|
1824
|
-
* @memberof
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
return Math.sqrt(VertTuple.vtutils.dist2(p, this.vertAt(this.getClosestT(p))));
|
|
2094
|
+
* @memberof Bounds
|
|
2095
|
+
* @returns {string} Get these bounds in a human readable form.
|
|
2096
|
+
*/
|
|
2097
|
+
toString() {
|
|
2098
|
+
return `{ min: ${this.min.toString()}, max : ${this.max.toString()}, width: ${this.width}, height : ${this.height} }`;
|
|
1830
2099
|
}
|
|
1831
2100
|
/**
|
|
1832
|
-
*
|
|
2101
|
+
* Clone this bounds object (create a deep clone).
|
|
1833
2102
|
*
|
|
1834
|
-
* @method
|
|
1835
|
-
* @return {T} A type safe clone if this instance.
|
|
2103
|
+
* @method clone
|
|
1836
2104
|
* @instance
|
|
1837
|
-
* @memberof
|
|
1838
|
-
|
|
2105
|
+
* @memberof Bounds
|
|
2106
|
+
* @returns {Bounds} Creates a deep clone of this bounds object.
|
|
2107
|
+
*/
|
|
1839
2108
|
clone() {
|
|
1840
|
-
return this.
|
|
2109
|
+
return new Bounds({ x: this.min.x, y: this.min.y }, { x: this.max.x, y: this.max.y });
|
|
1841
2110
|
}
|
|
1842
2111
|
/**
|
|
1843
|
-
*
|
|
2112
|
+
* Compute the minimal bounding box for a given set of vertices.
|
|
1844
2113
|
*
|
|
1845
|
-
*
|
|
1846
|
-
*
|
|
1847
|
-
* @
|
|
1848
|
-
* @
|
|
2114
|
+
* An empty vertex array will return an empty bounding box located at (0,0).
|
|
2115
|
+
*
|
|
2116
|
+
* @static
|
|
2117
|
+
* @method computeFromVertices
|
|
2118
|
+
* @memberof Bounds
|
|
2119
|
+
* @param {Array<Vertex>} vertices - The set of vertices you want to get the bounding box for.
|
|
2120
|
+
* @return The minimal Bounds for the given vertices.
|
|
1849
2121
|
**/
|
|
1850
|
-
|
|
1851
|
-
|
|
2122
|
+
static computeFromVertices(vertices) {
|
|
2123
|
+
if (vertices.length == 0)
|
|
2124
|
+
return new Bounds(new Vertex(0, 0), new Vertex(0, 0));
|
|
2125
|
+
let xMin = vertices[0].x;
|
|
2126
|
+
let xMax = vertices[0].x;
|
|
2127
|
+
let yMin = vertices[0].y;
|
|
2128
|
+
let yMax = vertices[0].y;
|
|
2129
|
+
let vert;
|
|
2130
|
+
for (var i in vertices) {
|
|
2131
|
+
vert = vertices[i];
|
|
2132
|
+
xMin = Math.min(xMin, vert.x);
|
|
2133
|
+
xMax = Math.max(xMax, vert.x);
|
|
2134
|
+
yMin = Math.min(yMin, vert.y);
|
|
2135
|
+
yMax = Math.max(yMax, vert.y);
|
|
2136
|
+
}
|
|
2137
|
+
return new Bounds(new Vertex(xMin, yMin), new Vertex(xMax, yMax));
|
|
1852
2138
|
}
|
|
1853
2139
|
/**
|
|
1854
|
-
*
|
|
1855
|
-
*
|
|
1856
|
-
*
|
|
2140
|
+
* Create a new `Bounds` instance just from `width` and `height`, located at (0,0) or the optionally given origin.
|
|
2141
|
+
*
|
|
2142
|
+
* @param {number} width - The width of the bounds
|
|
2143
|
+
* @param {number} height - The height of the bounds
|
|
2144
|
+
* @param {XYCoords={x:0,y:0}} origin - [optional] A origin to locate the new Bounds object at.
|
|
2145
|
+
* @returns {Bounds} A new `Bounds` instance width given width and height, located at (0,0) or the given origin..
|
|
1857
2146
|
*/
|
|
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);
|
|
2147
|
+
static fromDimension(width, height, origin) {
|
|
2148
|
+
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
2149
|
}
|
|
1871
|
-
}
|
|
2150
|
+
} // END class bounds
|
|
1872
2151
|
|
|
1873
2152
|
/**
|
|
1874
2153
|
* @author Ikaros Kappler
|
|
@@ -2015,8 +2294,8 @@ Vector.utils = {
|
|
|
2015
2294
|
* Example:
|
|
2016
2295
|
* buildArrowHead( new Vertex(0,0), new Vertex(50,100), 8, 1.0, 1.0 )
|
|
2017
2296
|
*
|
|
2018
|
-
* @param {
|
|
2019
|
-
* @param {
|
|
2297
|
+
* @param {XYCoords} zA - The start vertex of the vector to calculate the arrow head for.
|
|
2298
|
+
* @param {XYCoords} zB - The end vertex of the vector.
|
|
2020
2299
|
* @param {number} headlen - The length of the arrow head (along the vector direction. A good value is 12).
|
|
2021
2300
|
* @param {number} scaleX - The horizontal scaling during draw.
|
|
2022
2301
|
* @param {number} scaleY - the vertical scaling during draw.
|
|
@@ -2055,7 +2334,9 @@ Vector.utils = {
|
|
|
2055
2334
|
* @modified 2022-02-02 Added the `destroy` method.
|
|
2056
2335
|
* @modified 2022-02-02 Cleared the `toSVGPathData` function (deprecated). Use `drawutilssvg` instead.
|
|
2057
2336
|
* @modified 2022-10-17 The `CubicBezierCurve` class now implements the new `PathSegment` interface.
|
|
2058
|
-
* @
|
|
2337
|
+
* @modified 2023-09-30 Added the function `CubicbezierCurve.getSubCurve(number,number)` – similar to `getSubCurveAt(...)` but with absolute position parameters.
|
|
2338
|
+
* @modified 2023-10-07 Added the `trimEnd`, `trimEndAt`, `trimStart`, `trimStartAt` methods.
|
|
2339
|
+
* @version 2.8.0
|
|
2059
2340
|
*
|
|
2060
2341
|
* @file CubicBezierCurve
|
|
2061
2342
|
* @public
|
|
@@ -2442,6 +2723,91 @@ class CubicBezierCurve {
|
|
|
2442
2723
|
// Note: my implementation does NOT normalize tangent vectors!
|
|
2443
2724
|
return new Vertex(tX, tY);
|
|
2444
2725
|
}
|
|
2726
|
+
/**
|
|
2727
|
+
* Trim off a start section of this curve. The position parameter `uValue` is the absolute position on the
|
|
2728
|
+
* curve in `[0...arcLength]`.
|
|
2729
|
+
* The remaining curve will be the one in the bounds `[uValue,1]` (so `[0.0,uValue]` is cut off).
|
|
2730
|
+
*
|
|
2731
|
+
* Note this function just converts the absolute parameter to a relative one and call `trimStartAt`.
|
|
2732
|
+
*
|
|
2733
|
+
* @method trimStart
|
|
2734
|
+
* @instance
|
|
2735
|
+
* @memberof CubicBezierCurve
|
|
2736
|
+
* @param {number} uValue - The absolute position parameter where to cut off the head curve.
|
|
2737
|
+
* @returns {CubicBezierCurve} `this` for chanining.
|
|
2738
|
+
*/
|
|
2739
|
+
trimStart(uValue) {
|
|
2740
|
+
return this.trimStartAt(this.convertU2T(uValue));
|
|
2741
|
+
}
|
|
2742
|
+
/**
|
|
2743
|
+
* Trim off a start section of this curve. The position parameter `t` is the relative position in [0..1].
|
|
2744
|
+
* The remaining curve will be the one in the bounds `[uValue,1]` (so `[0.0,uValue]` is cut off).
|
|
2745
|
+
*
|
|
2746
|
+
* @method trimStartAt
|
|
2747
|
+
* @instance
|
|
2748
|
+
* @memberof CubicBezierCurve
|
|
2749
|
+
* @param {number} t - The relative position parameter where to cut off the head curve.
|
|
2750
|
+
* @returns {CubicBezierCurve} `this` for chanining.
|
|
2751
|
+
*/
|
|
2752
|
+
trimStartAt(t) {
|
|
2753
|
+
const subCurbePoints = CubicBezierCurve.utils.getSubCurvePointsAt(this, t, 1.0);
|
|
2754
|
+
this.startPoint.set(subCurbePoints[0]);
|
|
2755
|
+
this.startControlPoint.set(subCurbePoints[2]);
|
|
2756
|
+
this.endPoint.set(subCurbePoints[1]);
|
|
2757
|
+
this.endControlPoint.set(subCurbePoints[3]);
|
|
2758
|
+
this.updateArcLengths();
|
|
2759
|
+
return this;
|
|
2760
|
+
}
|
|
2761
|
+
/**
|
|
2762
|
+
* Trim off the end of this curve. The position parameter `uValue` is the absolute position on the
|
|
2763
|
+
* curve in `[0...arcLength]`.
|
|
2764
|
+
* The remaining curve will be the one in the bounds `[0,uValue]` (so `[1.0-uValue,1.0]` is cut off).
|
|
2765
|
+
*
|
|
2766
|
+
* Note this function just converts the absolute parameter to a relative one and call `trimEndAt`.
|
|
2767
|
+
*
|
|
2768
|
+
* @method trimEnd
|
|
2769
|
+
* @instance
|
|
2770
|
+
* @memberof CubicBezierCurve
|
|
2771
|
+
* @param {number} uValue - The absolute position parameter where to cut off the tail curve.
|
|
2772
|
+
* @returns {CubicBezierCurve} `this` for chanining.
|
|
2773
|
+
*/
|
|
2774
|
+
trimEnd(uValue) {
|
|
2775
|
+
return this.trimEndAt(this.convertU2T(uValue));
|
|
2776
|
+
}
|
|
2777
|
+
/**
|
|
2778
|
+
* Trim off the end of this curve. The position parameter `t` is the relative position in [0..1].
|
|
2779
|
+
* The remaining curve will be the one in the bounds `[0,t]` (so `[1.0-t,1.0]` is cut off).
|
|
2780
|
+
*
|
|
2781
|
+
* @method trimEndAt
|
|
2782
|
+
* @instance
|
|
2783
|
+
* @memberof CubicBezierCurve
|
|
2784
|
+
* @param {number} t - The relative position parameter where to cut off the tail curve.
|
|
2785
|
+
* @returns {CubicBezierCurve} `this` for chanining.
|
|
2786
|
+
*/
|
|
2787
|
+
trimEndAt(t) {
|
|
2788
|
+
const subCurbePoints = CubicBezierCurve.utils.getSubCurvePointsAt(this, 0.0, t);
|
|
2789
|
+
this.startPoint.set(subCurbePoints[0]);
|
|
2790
|
+
this.startControlPoint.set(subCurbePoints[2]);
|
|
2791
|
+
this.endPoint.set(subCurbePoints[1]);
|
|
2792
|
+
this.endControlPoint.set(subCurbePoints[3]);
|
|
2793
|
+
this.updateArcLengths();
|
|
2794
|
+
return this;
|
|
2795
|
+
}
|
|
2796
|
+
/**
|
|
2797
|
+
* Get a sub curve at the given start end end positions (values on the curve's length, between 0 and curve.arcLength).
|
|
2798
|
+
*
|
|
2799
|
+
* tStart >= tEnd is allowed, you will get a reversed sub curve then.
|
|
2800
|
+
*
|
|
2801
|
+
* @method getSubCurve
|
|
2802
|
+
* @param {number} tStart – The start position of the desired sub curve (must be in [0..arcLength]).
|
|
2803
|
+
* @param {number} tEnd – The end position if the desired cub curve (must be in [0..arcLength]).
|
|
2804
|
+
* @instance
|
|
2805
|
+
* @memberof CubicBezierCurve
|
|
2806
|
+
* @return {CubicBezierCurve} The sub curve as a new curve.
|
|
2807
|
+
**/
|
|
2808
|
+
getSubCurve(uStart, uEnd) {
|
|
2809
|
+
return this.getSubCurveAt(this.convertU2T(uStart), this.convertU2T(uEnd));
|
|
2810
|
+
}
|
|
2445
2811
|
/**
|
|
2446
2812
|
* Get a sub curve at the given start end end offsets (values between 0.0 and 1.0).
|
|
2447
2813
|
*
|
|
@@ -2455,17 +2821,19 @@ class CubicBezierCurve {
|
|
|
2455
2821
|
* @return {CubicBezierCurve} The sub curve as a new curve.
|
|
2456
2822
|
**/
|
|
2457
2823
|
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);
|
|
2824
|
+
// const startVec: Vector = new Vector(this.getPointAt(tStart), this.getTangentAt(tStart));
|
|
2825
|
+
// const endVec: Vector = new Vector(this.getPointAt(tEnd), this.getTangentAt(tEnd).inv());
|
|
2826
|
+
// // Tangents are relative. Make absolute.
|
|
2827
|
+
// startVec.b.add(startVec.a);
|
|
2828
|
+
// endVec.b.add(endVec.a);
|
|
2829
|
+
// // This 'splits' the curve at the given point at t.
|
|
2830
|
+
// startVec.scale(0.33333333 * (tEnd - tStart));
|
|
2831
|
+
// endVec.scale(0.33333333 * (tEnd - tStart));
|
|
2832
|
+
// // Draw the bezier curve
|
|
2833
|
+
// // pb.draw.cubicBezier( startVec.a, endVec.a, startVec.b, endVec.b, '#8800ff', 2 );
|
|
2834
|
+
// return new CubicBezierCurve(startVec.a, endVec.a, startVec.b, endVec.b);
|
|
2835
|
+
const subCurbePoints = CubicBezierCurve.utils.getSubCurvePointsAt(this, tStart, tEnd);
|
|
2836
|
+
return new CubicBezierCurve(subCurbePoints[0], subCurbePoints[1], subCurbePoints[2], subCurbePoints[3]);
|
|
2469
2837
|
}
|
|
2470
2838
|
/**
|
|
2471
2839
|
* Convert a relative curve position u to the absolute curve position t.
|
|
@@ -2718,6 +3086,35 @@ CubicBezierCurve.START_CONTROL_POINT = 1;
|
|
|
2718
3086
|
CubicBezierCurve.END_CONTROL_POINT = 2;
|
|
2719
3087
|
/** @constant {number} */
|
|
2720
3088
|
CubicBezierCurve.END_POINT = 3;
|
|
3089
|
+
/**
|
|
3090
|
+
* Helper utils.
|
|
3091
|
+
*/
|
|
3092
|
+
CubicBezierCurve.utils = {
|
|
3093
|
+
/**
|
|
3094
|
+
* Get the points of a sub curve at the given start end end offsets (values between 0.0 and 1.0).
|
|
3095
|
+
*
|
|
3096
|
+
* tStart >= tEnd is allowed, you will get a reversed sub curve then.
|
|
3097
|
+
*
|
|
3098
|
+
* @method getSubCurvePointsAt
|
|
3099
|
+
* @param {CubicBezierCurve} curve – The curve to get the sub curve points from.
|
|
3100
|
+
* @param {number} tStart – The start offset of the desired sub curve (must be in [0..1]).
|
|
3101
|
+
* @param {number} tEnd – The end offset if the desired cub curve (must be in [0..1]).
|
|
3102
|
+
* @instance
|
|
3103
|
+
* @memberof CubicBezierCurve
|
|
3104
|
+
* @return {CubicBezierCurve} The sub curve as a new curve.
|
|
3105
|
+
**/
|
|
3106
|
+
getSubCurvePointsAt: (curve, tStart, tEnd) => {
|
|
3107
|
+
const startVec = new Vector(curve.getPointAt(tStart), curve.getTangentAt(tStart));
|
|
3108
|
+
const endVec = new Vector(curve.getPointAt(tEnd), curve.getTangentAt(tEnd).inv());
|
|
3109
|
+
// Tangents are relative. Make absolute.
|
|
3110
|
+
startVec.b.add(startVec.a);
|
|
3111
|
+
endVec.b.add(endVec.a);
|
|
3112
|
+
// This 'splits' the curve at the given point at t.
|
|
3113
|
+
startVec.scale(0.33333333 * (tEnd - tStart));
|
|
3114
|
+
endVec.scale(0.33333333 * (tEnd - tStart));
|
|
3115
|
+
return [startVec.a, endVec.a, startVec.b, endVec.b];
|
|
3116
|
+
}
|
|
3117
|
+
};
|
|
2721
3118
|
|
|
2722
3119
|
/**
|
|
2723
3120
|
* @author Ikaros Kappler
|
|
@@ -2744,7 +3141,9 @@ CubicBezierCurve.END_POINT = 3;
|
|
|
2744
3141
|
* @modified 2022-01-31 Added `BezierPath.getEvenDistributionVertices(number)`.
|
|
2745
3142
|
* @modified 2022-02-02 Added the `destroy` method.
|
|
2746
3143
|
* @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
2747
|
-
* @
|
|
3144
|
+
* @modified 2023-10-06 Adding the `BezierPath.toPathPoints()` method.
|
|
3145
|
+
* @modified 2023-10-07 Adding the `BezierPath.fromCurve(CubicBezierCurve)` static function.
|
|
3146
|
+
* @version 2.6.0
|
|
2748
3147
|
*
|
|
2749
3148
|
* @file BezierPath
|
|
2750
3149
|
* @public
|
|
@@ -2775,7 +3174,7 @@ class BezierPath {
|
|
|
2775
3174
|
* @name BezierPath
|
|
2776
3175
|
* @param {Vertex[]} pathPoints - An array of path vertices (no control points).
|
|
2777
3176
|
**/
|
|
2778
|
-
constructor(
|
|
3177
|
+
constructor() {
|
|
2779
3178
|
/**
|
|
2780
3179
|
* Required to generate proper CSS classes and other class related IDs.
|
|
2781
3180
|
**/
|
|
@@ -2788,7 +3187,11 @@ class BezierPath {
|
|
|
2788
3187
|
this.END_CONTROL_POINT = 2;
|
|
2789
3188
|
/** @constant {number} */
|
|
2790
3189
|
this.END_POINT = 3;
|
|
3190
|
+
// pathPoints: Array<Vertex> | undefined | null) {
|
|
2791
3191
|
this.uid = UIDGenerator.next();
|
|
3192
|
+
// if (!pathPoints) {
|
|
3193
|
+
// pathPoints = [];
|
|
3194
|
+
// }
|
|
2792
3195
|
this.totalArcLength = 0.0;
|
|
2793
3196
|
// Set this flag to true if you want the first point and
|
|
2794
3197
|
// last point of the path to be auto adjusted, too.
|
|
@@ -2927,229 +3330,20 @@ class BezierPath {
|
|
|
2927
3330
|
* @return {number} The number of curves in this path.
|
|
2928
3331
|
**/
|
|
2929
3332
|
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
|
-
}; */
|
|
3333
|
+
return this.bezierCurves.length;
|
|
3334
|
+
}
|
|
3335
|
+
/**
|
|
3336
|
+
* Get the cubic bezier curve at the given index.
|
|
3337
|
+
*
|
|
3338
|
+
* @method getCurveAt
|
|
3339
|
+
* @param {number} index - The curve index from 0 to getCurveCount()-1.
|
|
3340
|
+
* @instance
|
|
3341
|
+
* @memberof BezierPath
|
|
3342
|
+
* @return {CubicBezierCurve} The curve at the specified index.
|
|
3343
|
+
**/
|
|
3344
|
+
getCurveAt(curveIndex) {
|
|
3345
|
+
return this.bezierCurves[curveIndex];
|
|
3346
|
+
}
|
|
3153
3347
|
/**
|
|
3154
3348
|
* Move the whole bezier path by the given (x,y)-amount.
|
|
3155
3349
|
*
|
|
@@ -3184,22 +3378,6 @@ class BezierPath {
|
|
|
3184
3378
|
* @return {BezierPath} this for chaining.
|
|
3185
3379
|
**/
|
|
3186
3380
|
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
3381
|
return this.scaleXY({ x: scaleFactor, y: scaleFactor }, anchor);
|
|
3204
3382
|
}
|
|
3205
3383
|
/**
|
|
@@ -3695,7 +3873,7 @@ class BezierPath {
|
|
|
3695
3873
|
* @return {BezierPath}
|
|
3696
3874
|
**/
|
|
3697
3875
|
clone() {
|
|
3698
|
-
var path = new BezierPath(undefined);
|
|
3876
|
+
var path = new BezierPath(); // undefined);
|
|
3699
3877
|
for (var i = 0; i < this.bezierCurves.length; i++) {
|
|
3700
3878
|
path.bezierCurves.push(this.bezierCurves[i].clone());
|
|
3701
3879
|
// Connect splines
|
|
@@ -3735,6 +3913,10 @@ class BezierPath {
|
|
|
3735
3913
|
* This function should invalidate any installed listeners and invalidate this object.
|
|
3736
3914
|
* After calling this function the object might not hold valid data any more and
|
|
3737
3915
|
* should not be used.
|
|
3916
|
+
*
|
|
3917
|
+
* @method destroy
|
|
3918
|
+
* @instance
|
|
3919
|
+
* @memberof BezierPath
|
|
3738
3920
|
*/
|
|
3739
3921
|
destroy() {
|
|
3740
3922
|
for (var i = 0; i < this.bezierCurves.length; i++) {
|
|
@@ -3742,6 +3924,40 @@ class BezierPath {
|
|
|
3742
3924
|
}
|
|
3743
3925
|
this.isDestroyed = true;
|
|
3744
3926
|
}
|
|
3927
|
+
/**
|
|
3928
|
+
* Convert this path to an array of path points that can be drawn by the default DrawLib
|
|
3929
|
+
* implementations.
|
|
3930
|
+
*
|
|
3931
|
+
* @method toPathPoints
|
|
3932
|
+
* @instance
|
|
3933
|
+
* @memberof BezierPath
|
|
3934
|
+
* @return {Array<XYCoords>}
|
|
3935
|
+
*/
|
|
3936
|
+
toPathPoints() {
|
|
3937
|
+
if (this.bezierCurves.length === 0) {
|
|
3938
|
+
return [];
|
|
3939
|
+
}
|
|
3940
|
+
if (this.bezierCurves.length === 1) {
|
|
3941
|
+
return [
|
|
3942
|
+
this.bezierCurves[0].startPoint,
|
|
3943
|
+
this.bezierCurves[0].startControlPoint,
|
|
3944
|
+
this.bezierCurves[0].endControlPoint,
|
|
3945
|
+
this.bezierCurves[0].endPoint
|
|
3946
|
+
];
|
|
3947
|
+
}
|
|
3948
|
+
const arr = [];
|
|
3949
|
+
arr.push(this.bezierCurves[0].startPoint);
|
|
3950
|
+
arr.push(this.bezierCurves[0].startControlPoint);
|
|
3951
|
+
for (var i = 1; i < this.bezierCurves.length; i++) {
|
|
3952
|
+
arr.push(this.bezierCurves[i - 1].endControlPoint);
|
|
3953
|
+
arr.push(this.bezierCurves[i - 1].endPoint);
|
|
3954
|
+
arr.push(this.bezierCurves[i].startPoint);
|
|
3955
|
+
arr.push(this.bezierCurves[i].startControlPoint);
|
|
3956
|
+
}
|
|
3957
|
+
arr.push(this.bezierCurves[0].endControlPoint);
|
|
3958
|
+
arr.push(this.bezierCurves[0].endPoint);
|
|
3959
|
+
return arr;
|
|
3960
|
+
}
|
|
3745
3961
|
/**
|
|
3746
3962
|
* Create a JSON string representation of this bézier curve.
|
|
3747
3963
|
*
|
|
@@ -3782,6 +3998,20 @@ class BezierPath {
|
|
|
3782
3998
|
var obj = JSON.parse(jsonString);
|
|
3783
3999
|
return BezierPath.fromArray(obj);
|
|
3784
4000
|
}
|
|
4001
|
+
/**
|
|
4002
|
+
* Construct a new path with a single curve. Adding more curves is always possible.
|
|
4003
|
+
*
|
|
4004
|
+
* @method fromCurve
|
|
4005
|
+
* @param {CubicBezierCurve} curve - The curve to construct a new path from.
|
|
4006
|
+
* @static
|
|
4007
|
+
* @memberof BezierPath
|
|
4008
|
+
* @return {BezierPath} The constructed bezier path instance.
|
|
4009
|
+
*/
|
|
4010
|
+
static fromCurve(curve) {
|
|
4011
|
+
const path = new BezierPath(); // []);
|
|
4012
|
+
path.addCurve(curve);
|
|
4013
|
+
return path;
|
|
4014
|
+
}
|
|
3785
4015
|
/**
|
|
3786
4016
|
* Create a BezierPath instance from the given array.
|
|
3787
4017
|
*
|
|
@@ -3793,13 +4023,15 @@ class BezierPath {
|
|
|
3793
4023
|
* @return {BezierPath} The bezier path instance retrieved from the array data.
|
|
3794
4024
|
**/
|
|
3795
4025
|
static fromArray(obj) {
|
|
3796
|
-
if (!Array.isArray(obj))
|
|
4026
|
+
if (!Array.isArray(obj)) {
|
|
3797
4027
|
throw "[BezierPath.fromArray] Passed object must be an array.";
|
|
4028
|
+
}
|
|
3798
4029
|
const arr = obj; // FORCE?
|
|
3799
|
-
if (arr.length < 1)
|
|
4030
|
+
if (arr.length < 1) {
|
|
3800
4031
|
throw "[BezierPath.fromArray] Passed array must contain at least one bezier curve (has " + arr.length + ").";
|
|
4032
|
+
}
|
|
3801
4033
|
// Create an empty bezier path
|
|
3802
|
-
var bPath = new BezierPath(undefined);
|
|
4034
|
+
var bPath = new BezierPath(); // undefined);
|
|
3803
4035
|
var lastCurve = null;
|
|
3804
4036
|
for (var i = 0; i < arr.length; i++) {
|
|
3805
4037
|
// Convert object (or array?) to bezier curve
|
|
@@ -3909,7 +4141,7 @@ class BezierPath {
|
|
|
3909
4141
|
*/
|
|
3910
4142
|
static fromReducedList(pointArray, adjustCircular) {
|
|
3911
4143
|
// Convert to object
|
|
3912
|
-
var bezierPath = new BezierPath(null); // No points yet
|
|
4144
|
+
var bezierPath = new BezierPath(); // null); // No points yet
|
|
3913
4145
|
var startPoint = new Vertex();
|
|
3914
4146
|
var startControlPoint;
|
|
3915
4147
|
var endControlPoint;
|
|
@@ -3952,138 +4184,6 @@ BezierPath.END_CONTROL_POINT = 2;
|
|
|
3952
4184
|
/** @constant {number} */
|
|
3953
4185
|
BezierPath.END_POINT = 3;
|
|
3954
4186
|
|
|
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
4187
|
/**
|
|
4088
4188
|
* @author Ikaros Kappler
|
|
4089
4189
|
* @date 2020-05-04
|
|
@@ -4476,7 +4576,15 @@ CircleSector.circleSectorUtils = {
|
|
|
4476
4576
|
* @modified 2022-11-10 Tweaking some type issues.
|
|
4477
4577
|
* @modified 2023-02-04 Fixed a typo in the CSS classname for cubic Bézier paths: cubicBezier (was cubierBezier).
|
|
4478
4578
|
* @modified 2023-02-10 The methods `setCurrentClassName` and `setCurrentId` also accept `null` now.
|
|
4479
|
-
* @
|
|
4579
|
+
* @modified 2023-09-29 Added initialization checks for null parameters.
|
|
4580
|
+
* @modified 2023-09-29 Added a missing implementation to the `drawurilssvg.do(XYCoords,string)` function. Didn't draw anything.
|
|
4581
|
+
* @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.
|
|
4582
|
+
* @modified 2023-09-29 Added the `headLength` parameter to the 'DrawLib.arrow()` function.
|
|
4583
|
+
* @modified 2023-09-29 Added the `arrowHead(...)` function to the 'DrawLib.arrow()` interface.
|
|
4584
|
+
* @modified 2023-09-29 Added the `cubicBezierArrow(...)` function to the 'DrawLib.arrow()` interface.
|
|
4585
|
+
* @modified 2023-10-04 Adding `strokeOptions` param to these draw function: line, arrow, cubicBezierArrow, cubicBezier, cubicBezierPath, circle, circleArc, ellipse, square, rect, polygon, polyline.
|
|
4586
|
+
*
|
|
4587
|
+
* @version 1.6.7
|
|
4480
4588
|
**/
|
|
4481
4589
|
const RAD_TO_DEG = 180 / Math.PI;
|
|
4482
4590
|
/**
|
|
@@ -4513,6 +4621,9 @@ class drawutilssvg {
|
|
|
4513
4621
|
this.cache = new Map();
|
|
4514
4622
|
this.setSize(canvasSize);
|
|
4515
4623
|
if (isSecondary) {
|
|
4624
|
+
if (!gNode || !bufferGNode || !nodeDefs || !bufferNodeDefs) {
|
|
4625
|
+
throw "Cannot create secondary svg draw lib with undefinde gNode|bufferGNode|nodeDefs|bufferNodeDefs.";
|
|
4626
|
+
}
|
|
4516
4627
|
this.gNode = gNode;
|
|
4517
4628
|
this.bufferGNode = bufferGNode;
|
|
4518
4629
|
this.nodeDefs = nodeDefs;
|
|
@@ -4653,6 +4764,9 @@ class drawutilssvg {
|
|
|
4653
4764
|
if (this.drawlibConfiguration.blendMode) {
|
|
4654
4765
|
node.style["mix-blend-mode"] = this.drawlibConfiguration.blendMode;
|
|
4655
4766
|
}
|
|
4767
|
+
// if (this.lineDashEnabled && this.lineDash && this.lineDash.length > 0 && drawutilssvg.nodeSupportsLineDash(nodeName)) {
|
|
4768
|
+
// node.setAttribute("stroke-dasharray", this.lineDash.join(" "));
|
|
4769
|
+
// }
|
|
4656
4770
|
return node;
|
|
4657
4771
|
}
|
|
4658
4772
|
/**
|
|
@@ -4675,23 +4789,58 @@ class drawutilssvg {
|
|
|
4675
4789
|
* @param {number=1} lineWidth - (optional) A line width to use for drawing (default is 1).
|
|
4676
4790
|
* @return {SVGElement} The node itself (for chaining).
|
|
4677
4791
|
*/
|
|
4678
|
-
_bindFillDraw(node, className, color, lineWidth) {
|
|
4792
|
+
_bindFillDraw(node, className, color, lineWidth, strokeOptions) {
|
|
4793
|
+
this._configureNode(node, className, this.fillShapes, color, lineWidth, strokeOptions);
|
|
4794
|
+
return this._bindNode(node, undefined);
|
|
4795
|
+
}
|
|
4796
|
+
/**
|
|
4797
|
+
* Bind this given node to a parent. If no parent is passed then the global
|
|
4798
|
+
* node buffer will be used.
|
|
4799
|
+
*
|
|
4800
|
+
* @method _bindNode
|
|
4801
|
+
* @private
|
|
4802
|
+
* @instance
|
|
4803
|
+
* @memberof drawutilssvg
|
|
4804
|
+
* @param {SVGElement} node - The SVG node to bind.
|
|
4805
|
+
* @param {SVGElement=} bindingParent - (optional) You may pass node other than the glober buffer node.
|
|
4806
|
+
* @returns {SVGElement} The passed node itself.
|
|
4807
|
+
*/
|
|
4808
|
+
_bindNode(node, bindingParent) {
|
|
4809
|
+
if (!node.parentNode) {
|
|
4810
|
+
// Attach to DOM only if not already attached
|
|
4811
|
+
(bindingParent !== null && bindingParent !== void 0 ? bindingParent : this.bufferGNode).appendChild(node);
|
|
4812
|
+
}
|
|
4813
|
+
return node;
|
|
4814
|
+
}
|
|
4815
|
+
/**
|
|
4816
|
+
* Add custom CSS class names and the globally defined CSS classname to the
|
|
4817
|
+
* given node.
|
|
4818
|
+
*
|
|
4819
|
+
* @method addCSSClasses
|
|
4820
|
+
* @private
|
|
4821
|
+
* @instance
|
|
4822
|
+
* @memberof drawutilssvg
|
|
4823
|
+
* @param {SVGElement} node - The SVG node to bind.
|
|
4824
|
+
* @param {string} className - The additional custom classname to add.
|
|
4825
|
+
* @returns {void}
|
|
4826
|
+
*/
|
|
4827
|
+
_addCSSClasses(node, className) {
|
|
4679
4828
|
if (this.curClassName) {
|
|
4680
4829
|
node.setAttribute("class", `${className} ${this.curClassName}`);
|
|
4681
4830
|
}
|
|
4682
4831
|
else {
|
|
4683
4832
|
node.setAttribute("class", className);
|
|
4684
4833
|
}
|
|
4685
|
-
|
|
4686
|
-
|
|
4834
|
+
}
|
|
4835
|
+
_configureNode(node, className, fillMode, color, lineWidth, strokeOptions) {
|
|
4836
|
+
this._addCSSClasses(node, className);
|
|
4837
|
+
node.setAttribute("fill", fillMode && color ? color : "none");
|
|
4838
|
+
node.setAttribute("stroke", fillMode ? "none" : color || "none");
|
|
4687
4839
|
node.setAttribute("stroke-width", `${lineWidth || 1}`);
|
|
4688
4840
|
if (this.curId) {
|
|
4689
4841
|
node.setAttribute("id", `${this.curId}`); // Maybe React-style 'key' would be better?
|
|
4690
4842
|
}
|
|
4691
|
-
|
|
4692
|
-
// Attach to DOM only if not already attached
|
|
4693
|
-
this.bufferGNode.appendChild(node);
|
|
4694
|
-
}
|
|
4843
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
4695
4844
|
return node;
|
|
4696
4845
|
}
|
|
4697
4846
|
/**
|
|
@@ -4713,7 +4862,7 @@ class drawutilssvg {
|
|
|
4713
4862
|
* that under the hood the same gl context and gl program will be used.
|
|
4714
4863
|
*/
|
|
4715
4864
|
copyInstance(fillShapes) {
|
|
4716
|
-
var copy = new drawutilssvg(this.svgNode, this.offset, this.scale, this.canvasSize, fillShapes, null, // no DrawConfig
|
|
4865
|
+
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
4866
|
true, // isSecondary
|
|
4718
4867
|
this.gNode, this.bufferGNode, this.nodeDefs, this.bufferedNodeDefs);
|
|
4719
4868
|
return copy;
|
|
@@ -4728,6 +4877,20 @@ class drawutilssvg {
|
|
|
4728
4877
|
setConfiguration(configuration) {
|
|
4729
4878
|
this.drawlibConfiguration = configuration;
|
|
4730
4879
|
}
|
|
4880
|
+
// /**
|
|
4881
|
+
// * Set or clear the line-dash configuration. Pass `null` for un-dashed lines.
|
|
4882
|
+
// *
|
|
4883
|
+
// * See https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray
|
|
4884
|
+
// * and https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
|
|
4885
|
+
// * for how line dashes work.
|
|
4886
|
+
// *
|
|
4887
|
+
// * @method
|
|
4888
|
+
// * @param {Array<number> lineDashes - The line-dash array configuration.
|
|
4889
|
+
// * @returns {void}
|
|
4890
|
+
// */
|
|
4891
|
+
// setLineDash(lineDashes: Array<number>) {
|
|
4892
|
+
// this.lineDash = lineDashes;
|
|
4893
|
+
// }
|
|
4731
4894
|
/**
|
|
4732
4895
|
* This method shouled be called each time the currently drawn `Drawable` changes.
|
|
4733
4896
|
* It is used by some libraries for identifying elemente on re-renders.
|
|
@@ -4802,6 +4965,26 @@ class drawutilssvg {
|
|
|
4802
4965
|
this.nodeDefs = this.bufferedNodeDefs;
|
|
4803
4966
|
this.bufferedNodeDefs = tmpDefsNode;
|
|
4804
4967
|
}
|
|
4968
|
+
/**
|
|
4969
|
+
* A private helper method to apply stroke options to the current
|
|
4970
|
+
* context.
|
|
4971
|
+
* @param {StrokeOptions=} strokeOptions -
|
|
4972
|
+
*/
|
|
4973
|
+
applyStrokeOpts(node, strokeOptions) {
|
|
4974
|
+
if (strokeOptions &&
|
|
4975
|
+
strokeOptions.dashArray &&
|
|
4976
|
+
strokeOptions.dashArray.length > 0 &&
|
|
4977
|
+
drawutilssvg.nodeSupportsLineDash(node.tagName)) {
|
|
4978
|
+
node.setAttribute("stroke-dasharray", strokeOptions.dashArray
|
|
4979
|
+
.map((dashArayElem) => {
|
|
4980
|
+
return dashArayElem * this.scale.x;
|
|
4981
|
+
})
|
|
4982
|
+
.join(" "));
|
|
4983
|
+
if (strokeOptions.dashOffset) {
|
|
4984
|
+
node.setAttribute("stroke-dashoffset", `${strokeOptions.dashOffset * this.scale.x}`);
|
|
4985
|
+
}
|
|
4986
|
+
}
|
|
4987
|
+
}
|
|
4805
4988
|
_x(x) {
|
|
4806
4989
|
return this.offset.x + this.scale.x * x;
|
|
4807
4990
|
}
|
|
@@ -4812,47 +4995,101 @@ class drawutilssvg {
|
|
|
4812
4995
|
* Draw the line between the given two points with the specified (CSS-) color.
|
|
4813
4996
|
*
|
|
4814
4997
|
* @method line
|
|
4815
|
-
* @param {
|
|
4816
|
-
* @param {
|
|
4998
|
+
* @param {XYCoords} zA - The start point of the line.
|
|
4999
|
+
* @param {XYCoords} zB - The end point of the line.
|
|
4817
5000
|
* @param {string} color - Any valid CSS color string.
|
|
4818
5001
|
* @param {number=1} lineWidth? - [optional] The line's width.
|
|
5002
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5003
|
+
*
|
|
4819
5004
|
* @return {void}
|
|
4820
5005
|
* @instance
|
|
4821
5006
|
* @memberof drawutilssvg
|
|
4822
5007
|
**/
|
|
4823
|
-
line(zA, zB, color, lineWidth) {
|
|
4824
|
-
const line = this.makeNode("line");
|
|
4825
|
-
|
|
4826
|
-
line.setAttribute("
|
|
4827
|
-
line.setAttribute("
|
|
4828
|
-
line.setAttribute("
|
|
4829
|
-
|
|
5008
|
+
line(zA, zB, color, lineWidth, strokeOptions) {
|
|
5009
|
+
// const line: SVGElement = this.makeNode("line");
|
|
5010
|
+
// this.applyStrokeOpts(line, strokeOptions);
|
|
5011
|
+
// line.setAttribute("x1", `${this._x(zA.x)}`);
|
|
5012
|
+
// line.setAttribute("y1", `${this._y(zA.y)}`);
|
|
5013
|
+
// line.setAttribute("x2", `${this._x(zB.x)}`);
|
|
5014
|
+
// line.setAttribute("y2", `${this._y(zB.y)}`);
|
|
5015
|
+
const line = this.makeLineNode(zA, zB, color, lineWidth, strokeOptions);
|
|
5016
|
+
return this._bindFillDraw(line, "line", color, lineWidth || 1, strokeOptions);
|
|
4830
5017
|
}
|
|
4831
5018
|
/**
|
|
4832
5019
|
* Draw a line and an arrow at the end (zB) of the given line with the specified (CSS-) color.
|
|
4833
5020
|
*
|
|
4834
5021
|
* @method arrow
|
|
4835
|
-
* @param {
|
|
4836
|
-
* @param {
|
|
5022
|
+
* @param {XYCoords} zA - The start point of the arrow-line.
|
|
5023
|
+
* @param {XYCoords} zB - The end point of the arrow-line.
|
|
4837
5024
|
* @param {string} color - Any valid CSS color string.
|
|
4838
5025
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
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
|
+
*
|
|
4839
5029
|
* @return {void}
|
|
4840
5030
|
* @instance
|
|
4841
5031
|
* @memberof drawutilssvg
|
|
4842
5032
|
**/
|
|
4843
|
-
arrow(zA, zB, color, lineWidth) {
|
|
4844
|
-
const
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
const
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
5033
|
+
arrow(zA, zB, color, lineWidth, headLength = 8, strokeOptions) {
|
|
5034
|
+
const group = this.makeNode("g");
|
|
5035
|
+
const arrowHeadBasePosition = { x: 0, y: 0 };
|
|
5036
|
+
// Just create the child nodes, don't bind them to the root node.
|
|
5037
|
+
const arrowHead = this.makeArrowHeadNode(zA, zB, color, lineWidth, headLength, undefined, arrowHeadBasePosition);
|
|
5038
|
+
const line = this.makeLineNode(zA, arrowHeadBasePosition, color, lineWidth, strokeOptions);
|
|
5039
|
+
group.appendChild(line);
|
|
5040
|
+
group.appendChild(arrowHead);
|
|
5041
|
+
this._addCSSClasses(group, "linear-arrow");
|
|
5042
|
+
this._bindNode(group, undefined);
|
|
5043
|
+
return group;
|
|
5044
|
+
}
|
|
5045
|
+
/**
|
|
5046
|
+
* 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.
|
|
5047
|
+
*
|
|
5048
|
+
* @method cubicBezierArrow
|
|
5049
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
5050
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
5051
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
5052
|
+
* @param {XYCoords} endControlPoint - The end control point the cubic Bézier curve.
|
|
5053
|
+
* @param {string} color - The CSS color to draw the curve with.
|
|
5054
|
+
* @param {number} lineWidth - (optional) The line width to use.
|
|
5055
|
+
* @param {headLength=8} headLength - (optional) The length of the arrow head (default is 8 units).
|
|
5056
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5057
|
+
*
|
|
5058
|
+
* @return {void}
|
|
5059
|
+
* @instance
|
|
5060
|
+
* @memberof DrawLib
|
|
5061
|
+
*/
|
|
5062
|
+
cubicBezierArrow(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, headLength = 8, strokeOptions) {
|
|
5063
|
+
const group = this.makeNode("g");
|
|
5064
|
+
// Just create the child nodes, don't bind them to the root node.
|
|
5065
|
+
const arrowHeadBasePosition = new Vertex(0, 0);
|
|
5066
|
+
const arrowHead = this.makeArrowHeadNode(endControlPoint, endPoint, color, lineWidth, headLength, undefined, arrowHeadBasePosition);
|
|
5067
|
+
const diff = arrowHeadBasePosition.difference(endPoint);
|
|
5068
|
+
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);
|
|
5069
|
+
group.appendChild(bezier);
|
|
5070
|
+
group.appendChild(arrowHead);
|
|
5071
|
+
this._addCSSClasses(group, "cubicbezier-arrow");
|
|
5072
|
+
this._bindNode(group, undefined);
|
|
5073
|
+
return group;
|
|
5074
|
+
}
|
|
5075
|
+
/**
|
|
5076
|
+
* Draw just an arrow head a the end of an imaginary line (zB) of the given line width the specified (CSS-) color and size.
|
|
5077
|
+
*
|
|
5078
|
+
* @method arrow
|
|
5079
|
+
* @param {XYCoords} zA - The start point of the arrow-line.
|
|
5080
|
+
* @param {XYCoords} zB - The end point of the arrow-line.
|
|
5081
|
+
* @param {string} color - Any valid CSS color string.
|
|
5082
|
+
* @param {number=1} lineWidth - (optional) The line width to use; default is 1.
|
|
5083
|
+
* @param {number=8} headLength - (optional) The length of the arrow head (default is 8 pixels).
|
|
5084
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5085
|
+
*
|
|
5086
|
+
* @return {void}
|
|
5087
|
+
* @instance
|
|
5088
|
+
* @memberof DrawLib
|
|
5089
|
+
**/
|
|
5090
|
+
arrowHead(zA, zB, color, lineWidth, headLength = 8, strokeOptions) {
|
|
5091
|
+
const node = this.makeArrowHeadNode(zA, zB, color, lineWidth, headLength, strokeOptions);
|
|
5092
|
+
return this._bindFillDraw(node, "arrowhead", color, lineWidth || 1, strokeOptions);
|
|
4856
5093
|
}
|
|
4857
5094
|
/**
|
|
4858
5095
|
* Draw an image at the given position with the given size.<br>
|
|
@@ -4861,8 +5098,8 @@ class drawutilssvg {
|
|
|
4861
5098
|
*
|
|
4862
5099
|
* @method image
|
|
4863
5100
|
* @param {Image} image - The image object to draw.
|
|
4864
|
-
* @param {
|
|
4865
|
-
* @param {
|
|
5101
|
+
* @param {XYCoords} position - The position to draw the the upper left corner at.
|
|
5102
|
+
* @param {XYCoords} size - The x/y-size to draw the image with.
|
|
4866
5103
|
* @param {number=0.0} alpha - (optional, default=0.0) The transparency (1.0=opaque, 0.0=transparent).
|
|
4867
5104
|
* @return {void}
|
|
4868
5105
|
* @instance
|
|
@@ -4905,16 +5142,16 @@ class drawutilssvg {
|
|
|
4905
5142
|
* @param {Image} textureImage - The image object to draw.
|
|
4906
5143
|
* @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
|
|
4907
5144
|
* @param {Polygon} polygon - The polygon to use as clip path.
|
|
4908
|
-
* @param {
|
|
5145
|
+
* @param {XYCoords} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
|
|
4909
5146
|
* @param {number} rotation - The rotation to use for the polygon (and for the texture).
|
|
4910
5147
|
* @return {void}
|
|
4911
5148
|
* @instance
|
|
4912
5149
|
* @memberof drawutilssvg
|
|
4913
5150
|
**/
|
|
4914
5151
|
texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
|
|
4915
|
-
polygon.getBounds();
|
|
5152
|
+
// const basePolygonBounds: Bounds = polygon.getBounds();
|
|
4916
5153
|
const rotatedScalingOrigin = new Vertex(textureSize.min).clone().rotate(rotation, polygonPosition);
|
|
4917
|
-
polygonPosition.clone().add(rotatedScalingOrigin.difference(textureSize.min).inv());
|
|
5154
|
+
// const rotationCenter = polygonPosition.clone().add(rotatedScalingOrigin.difference(textureSize.min).inv());
|
|
4918
5155
|
// Create something like this
|
|
4919
5156
|
// ...
|
|
4920
5157
|
// <defs>
|
|
@@ -4968,36 +5205,21 @@ class drawutilssvg {
|
|
|
4968
5205
|
* Draw the given (cubic) bézier curve.
|
|
4969
5206
|
*
|
|
4970
5207
|
* @method cubicBezier
|
|
4971
|
-
* @param {
|
|
4972
|
-
* @param {
|
|
4973
|
-
* @param {
|
|
4974
|
-
* @param {
|
|
5208
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
5209
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
5210
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
5211
|
+
* @param {XYCoords} endControlPoint - The end control point the cubic Bézier curve.
|
|
4975
5212
|
* @param {string} color - The CSS color to draw the curve with.
|
|
4976
5213
|
* @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);
|
|
5214
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5215
|
+
*
|
|
5216
|
+
* @return {void}
|
|
5217
|
+
* @instance
|
|
5218
|
+
* @memberof drawutilssvg
|
|
5219
|
+
*/
|
|
5220
|
+
cubicBezier(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, strokeOptions) {
|
|
5221
|
+
const node = this.makeCubicBezierNode(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, strokeOptions);
|
|
5222
|
+
return this._bindNode(node, undefined);
|
|
5001
5223
|
}
|
|
5002
5224
|
/**
|
|
5003
5225
|
* Draw the given (cubic) Bézier path.
|
|
@@ -5007,17 +5229,21 @@ class drawutilssvg {
|
|
|
5007
5229
|
* <pre> [ point1, point1_startControl, point2_endControl, point2, point2_startControl, point3_endControl, point3, ... pointN_endControl, pointN ]</pre>
|
|
5008
5230
|
*
|
|
5009
5231
|
* @method cubicBezierPath
|
|
5010
|
-
* @param {
|
|
5232
|
+
* @param {XYCoords[]} path - The cubic bezier path as described above.
|
|
5011
5233
|
* @param {string} color - The CSS colot to draw the path with.
|
|
5012
5234
|
* @param {number=1} lineWidth - (optional) The line width to use.
|
|
5235
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5236
|
+
*
|
|
5013
5237
|
* @return {void}
|
|
5014
5238
|
* @instance
|
|
5015
5239
|
* @memberof drawutilssvg
|
|
5016
5240
|
*/
|
|
5017
|
-
cubicBezierPath(path, color, lineWidth) {
|
|
5241
|
+
cubicBezierPath(path, color, lineWidth, strokeOptions) {
|
|
5018
5242
|
const node = this.makeNode("path");
|
|
5019
|
-
|
|
5243
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5244
|
+
if (!path || path.length == 0) {
|
|
5020
5245
|
return node;
|
|
5246
|
+
}
|
|
5021
5247
|
// Draw curve
|
|
5022
5248
|
const d = ["M", this._x(path[0].x), this._y(path[0].y)];
|
|
5023
5249
|
// Draw curve path
|
|
@@ -5054,20 +5280,20 @@ class drawutilssvg {
|
|
|
5054
5280
|
* Draw a handle line (with a light grey).
|
|
5055
5281
|
*
|
|
5056
5282
|
* @method handleLine
|
|
5057
|
-
* @param {
|
|
5058
|
-
* @param {
|
|
5283
|
+
* @param {XYCoords} startPoint - The start point to draw the handle at.
|
|
5284
|
+
* @param {XYCoords} endPoint - The end point to draw the handle at.
|
|
5059
5285
|
* @return {void}
|
|
5060
5286
|
* @instance
|
|
5061
5287
|
* @memberof drawutilssvg
|
|
5062
5288
|
*/
|
|
5063
5289
|
handleLine(startPoint, endPoint) {
|
|
5064
|
-
this.line(startPoint, endPoint, "rgb(
|
|
5290
|
+
this.line(startPoint, endPoint, "rgb(128,128,128,0.5)");
|
|
5065
5291
|
}
|
|
5066
5292
|
/**
|
|
5067
5293
|
* Draw a 1x1 dot with the specified (CSS-) color.
|
|
5068
5294
|
*
|
|
5069
5295
|
* @method dot
|
|
5070
|
-
* @param {
|
|
5296
|
+
* @param {XYCoords} p - The position to draw the dot at.
|
|
5071
5297
|
* @param {string} color - The CSS color to draw the dot with.
|
|
5072
5298
|
* @return {void}
|
|
5073
5299
|
* @instance
|
|
@@ -5075,13 +5301,17 @@ class drawutilssvg {
|
|
|
5075
5301
|
*/
|
|
5076
5302
|
dot(p, color) {
|
|
5077
5303
|
const node = this.makeNode("line");
|
|
5304
|
+
node.setAttribute("x1", `${this._x(p.x)}`);
|
|
5305
|
+
node.setAttribute("y1", `${this._y(p.y)}`);
|
|
5306
|
+
node.setAttribute("x2", `${this._x(p.x)}`);
|
|
5307
|
+
node.setAttribute("y2", `${this._y(p.y)}`);
|
|
5078
5308
|
return this._bindFillDraw(node, "dot", color, 1);
|
|
5079
5309
|
}
|
|
5080
5310
|
/**
|
|
5081
5311
|
* Draw the given point with the specified (CSS-) color and radius 3.
|
|
5082
5312
|
*
|
|
5083
5313
|
* @method point
|
|
5084
|
-
* @param {
|
|
5314
|
+
* @param {XYCoords} p - The position to draw the point at.
|
|
5085
5315
|
* @param {string} color - The CSS color to draw the point with.
|
|
5086
5316
|
* @return {void}
|
|
5087
5317
|
* @instance
|
|
@@ -5101,17 +5331,20 @@ class drawutilssvg {
|
|
|
5101
5331
|
* Note that if the x- and y- scales are different the result will be an ellipse rather than a circle.
|
|
5102
5332
|
*
|
|
5103
5333
|
* @method circle
|
|
5104
|
-
* @param {
|
|
5334
|
+
* @param {XYCoords} center - The center of the circle.
|
|
5105
5335
|
* @param {number} radius - The radius of the circle.
|
|
5106
5336
|
* @param {string} color - The CSS color to draw the circle with.
|
|
5107
5337
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
5338
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5339
|
+
*
|
|
5108
5340
|
* @return {void}
|
|
5109
5341
|
* @instance
|
|
5110
5342
|
* @memberof drawutilssvg
|
|
5111
5343
|
*/
|
|
5112
|
-
circle(center, radius, color, lineWidth) {
|
|
5344
|
+
circle(center, radius, color, lineWidth, strokeOptions) {
|
|
5113
5345
|
// Todo: draw ellipse when scalex!=scaley
|
|
5114
5346
|
const node = this.makeNode("circle");
|
|
5347
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5115
5348
|
node.setAttribute("cx", `${this._x(center.x)}`);
|
|
5116
5349
|
node.setAttribute("cy", `${this._y(center.y)}`);
|
|
5117
5350
|
node.setAttribute("r", `${radius * this.scale.x}`); // y?
|
|
@@ -5121,17 +5354,20 @@ class drawutilssvg {
|
|
|
5121
5354
|
* Draw a circular arc (section of a circle) with the given CSS color.
|
|
5122
5355
|
*
|
|
5123
5356
|
* @method circleArc
|
|
5124
|
-
* @param {
|
|
5357
|
+
* @param {XYCoords} center - The center of the circle.
|
|
5125
5358
|
* @param {number} radius - The radius of the circle.
|
|
5126
5359
|
* @param {number} startAngle - The angle to start at.
|
|
5127
5360
|
* @param {number} endAngle - The angle to end at.
|
|
5128
5361
|
* @param {string} color - The CSS color to draw the circle with.
|
|
5362
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5363
|
+
*
|
|
5129
5364
|
* @return {void}
|
|
5130
5365
|
* @instance
|
|
5131
5366
|
* @memberof drawutilssvg
|
|
5132
5367
|
*/
|
|
5133
|
-
circleArc(center, radius, startAngle, endAngle, color, lineWidth) {
|
|
5368
|
+
circleArc(center, radius, startAngle, endAngle, color, lineWidth, strokeOptions) {
|
|
5134
5369
|
const node = this.makeNode("path");
|
|
5370
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5135
5371
|
const arcData = CircleSector.circleSectorUtils.describeSVGArc(this._x(center.x), this._y(center.y), radius * this.scale.x, // y?
|
|
5136
5372
|
startAngle, endAngle);
|
|
5137
5373
|
node.setAttribute("d", arcData.join(" "));
|
|
@@ -5141,21 +5377,24 @@ class drawutilssvg {
|
|
|
5141
5377
|
* Draw an ellipse with the specified (CSS-) color and thw two radii.
|
|
5142
5378
|
*
|
|
5143
5379
|
* @method ellipse
|
|
5144
|
-
* @param {
|
|
5380
|
+
* @param {XYCoords} center - The center of the ellipse.
|
|
5145
5381
|
* @param {number} radiusX - The radius of the ellipse.
|
|
5146
5382
|
* @param {number} radiusY - The radius of the ellipse.
|
|
5147
5383
|
* @param {string} color - The CSS color to draw the ellipse with.
|
|
5148
5384
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
5149
5385
|
* @param {number=} rotation - (optional, default=0) The rotation of the ellipse.
|
|
5386
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5387
|
+
*
|
|
5150
5388
|
* @return {void}
|
|
5151
5389
|
* @instance
|
|
5152
5390
|
* @memberof drawutilssvg
|
|
5153
5391
|
*/
|
|
5154
|
-
ellipse(center, radiusX, radiusY, color, lineWidth, rotation) {
|
|
5392
|
+
ellipse(center, radiusX, radiusY, color, lineWidth, rotation, strokeOptions) {
|
|
5155
5393
|
if (typeof rotation === "undefined") {
|
|
5156
5394
|
rotation = 0.0;
|
|
5157
5395
|
}
|
|
5158
5396
|
const node = this.makeNode("ellipse");
|
|
5397
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5159
5398
|
node.setAttribute("cx", `${this._x(center.x)}`);
|
|
5160
5399
|
node.setAttribute("cy", `${this._y(center.y)}`);
|
|
5161
5400
|
node.setAttribute("rx", `${radiusX * this.scale.x}`);
|
|
@@ -5171,15 +5410,18 @@ class drawutilssvg {
|
|
|
5171
5410
|
*
|
|
5172
5411
|
* @method square
|
|
5173
5412
|
* @param {XYCoords} center - The center of the square.
|
|
5174
|
-
* @param {
|
|
5413
|
+
* @param {number} size - The size of the square.
|
|
5175
5414
|
* @param {string} color - The CSS color to draw the square with.
|
|
5176
5415
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
5177
|
-
* @
|
|
5416
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5417
|
+
*
|
|
5418
|
+
* @return {SVGElement}
|
|
5178
5419
|
* @instance
|
|
5179
5420
|
* @memberof drawutilssvg
|
|
5180
5421
|
*/
|
|
5181
|
-
square(center, size, color, lineWidth) {
|
|
5422
|
+
square(center, size, color, lineWidth, strokeOptions) {
|
|
5182
5423
|
const node = this.makeNode("rectangle");
|
|
5424
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5183
5425
|
node.setAttribute("x", `${this._x(center.x - size / 2.0)}`);
|
|
5184
5426
|
node.setAttribute("y", `${this._y(center.y - size / 2.0)}`);
|
|
5185
5427
|
node.setAttribute("width", `${size * this.scale.x}`);
|
|
@@ -5194,9 +5436,15 @@ class drawutilssvg {
|
|
|
5194
5436
|
* @param {number} height - The height of the rectangle.
|
|
5195
5437
|
* @param {string} color - The color to use.
|
|
5196
5438
|
* @param {number=1} lineWidth - (optional) The line with to use (default is 1).
|
|
5439
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5440
|
+
*
|
|
5441
|
+
* @return {SVGElement}
|
|
5442
|
+
* @instance
|
|
5443
|
+
* @memberof drawutilssvg
|
|
5197
5444
|
**/
|
|
5198
|
-
rect(position, width, height, color, lineWidth) {
|
|
5445
|
+
rect(position, width, height, color, lineWidth, strokeOptions) {
|
|
5199
5446
|
const node = this.makeNode("rect");
|
|
5447
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5200
5448
|
node.setAttribute("x", `${this._x(position.x)}`);
|
|
5201
5449
|
node.setAttribute("y", `${this._y(position.y)}`);
|
|
5202
5450
|
node.setAttribute("width", `${width * this.scale.x}`);
|
|
@@ -5207,7 +5455,7 @@ class drawutilssvg {
|
|
|
5207
5455
|
* Draw a grid of horizontal and vertical lines with the given (CSS-) color.
|
|
5208
5456
|
*
|
|
5209
5457
|
* @method grid
|
|
5210
|
-
* @param {
|
|
5458
|
+
* @param {XYCoords} center - The center of the grid.
|
|
5211
5459
|
* @param {number} width - The total width of the grid (width/2 each to the left and to the right).
|
|
5212
5460
|
* @param {number} height - The total height of the grid (height/2 each to the top and to the bottom).
|
|
5213
5461
|
* @param {number} sizeX - The horizontal grid size.
|
|
@@ -5241,7 +5489,7 @@ class drawutilssvg {
|
|
|
5241
5489
|
* This works analogue to the grid() function
|
|
5242
5490
|
*
|
|
5243
5491
|
* @method raster
|
|
5244
|
-
* @param {
|
|
5492
|
+
* @param {XYCoords} center - The center of the raster.
|
|
5245
5493
|
* @param {number} width - The total width of the raster (width/2 each to the left and to the right).
|
|
5246
5494
|
* @param {number} height - The total height of the raster (height/2 each to the top and to the bottom).
|
|
5247
5495
|
* @param {number} sizeX - The horizontal raster size.
|
|
@@ -5274,8 +5522,8 @@ class drawutilssvg {
|
|
|
5274
5522
|
* as even shaped diamonds.
|
|
5275
5523
|
*
|
|
5276
5524
|
* @method diamondHandle
|
|
5277
|
-
* @param {
|
|
5278
|
-
* @param {
|
|
5525
|
+
* @param {XYCoords} center - The center of the diamond.
|
|
5526
|
+
* @param {number} size - The x/y-size of the diamond.
|
|
5279
5527
|
* @param {string} color - The CSS color to draw the diamond with.
|
|
5280
5528
|
* @return {void}
|
|
5281
5529
|
* @instance
|
|
@@ -5309,8 +5557,8 @@ class drawutilssvg {
|
|
|
5309
5557
|
* as even shaped squares.
|
|
5310
5558
|
*
|
|
5311
5559
|
* @method squareHandle
|
|
5312
|
-
* @param {
|
|
5313
|
-
* @param {
|
|
5560
|
+
* @param {XYCoords} center - The center of the square.
|
|
5561
|
+
* @param {XYCoords} size - The x/y-size of the square.
|
|
5314
5562
|
* @param {string} color - The CSS color to draw the square with.
|
|
5315
5563
|
* @return {void}
|
|
5316
5564
|
* @instance
|
|
@@ -5332,7 +5580,7 @@ class drawutilssvg {
|
|
|
5332
5580
|
* as even shaped circles.
|
|
5333
5581
|
*
|
|
5334
5582
|
* @method circleHandle
|
|
5335
|
-
* @param {
|
|
5583
|
+
* @param {XYCoords} center - The center of the circle.
|
|
5336
5584
|
* @param {number} radius - The radius of the circle.
|
|
5337
5585
|
* @param {string} color - The CSS color to draw the circle with.
|
|
5338
5586
|
* @return {void}
|
|
@@ -5431,18 +5679,22 @@ class drawutilssvg {
|
|
|
5431
5679
|
* Draw a polygon line (alternative function to the polygon).
|
|
5432
5680
|
*
|
|
5433
5681
|
* @method polyline
|
|
5434
|
-
* @param {
|
|
5682
|
+
* @param {XYCoords[]} vertices - The polygon vertices to draw.
|
|
5435
5683
|
* @param {boolan} isOpen - If true the polyline will not be closed at its end.
|
|
5436
5684
|
* @param {string} color - The CSS color to draw the polygon with.
|
|
5437
5685
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
5686
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
5687
|
+
*
|
|
5438
5688
|
* @return {void}
|
|
5439
5689
|
* @instance
|
|
5440
5690
|
* @memberof drawutilssvg
|
|
5441
5691
|
*/
|
|
5442
|
-
polyline(vertices, isOpen, color, lineWidth) {
|
|
5692
|
+
polyline(vertices, isOpen, color, lineWidth, strokeOptions) {
|
|
5443
5693
|
const node = this.makeNode("path");
|
|
5444
|
-
|
|
5694
|
+
this.applyStrokeOpts(node, strokeOptions);
|
|
5695
|
+
if (vertices.length == 0) {
|
|
5445
5696
|
return node;
|
|
5697
|
+
}
|
|
5446
5698
|
// Draw curve
|
|
5447
5699
|
const d = ["M", this._x(vertices[0].x), this._y(vertices[0].y)];
|
|
5448
5700
|
var n = vertices.length;
|
|
@@ -5545,12 +5797,16 @@ class drawutilssvg {
|
|
|
5545
5797
|
* @param {string=null} color - (optional) The color to draw this path with (default is null).
|
|
5546
5798
|
* @param {number=1} lineWidth - (optional) the line width to use (default is 1).
|
|
5547
5799
|
* @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.
|
|
5800
|
+
* @param {number=} options.dashOffset - (optional) `See StrokeOptions`.
|
|
5801
|
+
* @param {number=[]} options.dashArray - (optional) `See StrokeOptions`.
|
|
5802
|
+
*
|
|
5548
5803
|
* @instance
|
|
5549
5804
|
* @memberof drawutils
|
|
5550
5805
|
* @return {R} An instance representing the drawn path.
|
|
5551
5806
|
*/
|
|
5552
5807
|
path(pathData, color, lineWidth, options) {
|
|
5553
5808
|
const node = this.makeNode("path");
|
|
5809
|
+
this.applyStrokeOpts(node, options);
|
|
5554
5810
|
// Transform the path: in-place (fast) or copy (slower)
|
|
5555
5811
|
const d = options && options.inplace ? pathData : drawutilssvg.copyPathData(pathData);
|
|
5556
5812
|
drawutilssvg.transformPathData(d, this.offset, this.scale);
|
|
@@ -5576,7 +5832,7 @@ class drawutilssvg {
|
|
|
5576
5832
|
}
|
|
5577
5833
|
// Add a covering rect with the given background color
|
|
5578
5834
|
this.curId = "background";
|
|
5579
|
-
this.curClassName = undefined;
|
|
5835
|
+
this.curClassName = null; // undefined;
|
|
5580
5836
|
const node = this.makeNode("rect");
|
|
5581
5837
|
// For some strange reason SVG rotation transforms use degrees instead of radians
|
|
5582
5838
|
// Note that the background does not scale with the zoom level (always covers full element)
|
|
@@ -5588,7 +5844,7 @@ class drawutilssvg {
|
|
|
5588
5844
|
this._bindFillDraw(node, this.curId, null, null);
|
|
5589
5845
|
node.setAttribute("fill", typeof color === "undefined" ? "none" : color);
|
|
5590
5846
|
// Clear the current ID again
|
|
5591
|
-
this.curId = undefined;
|
|
5847
|
+
this.curId = null; // undefined;
|
|
5592
5848
|
}
|
|
5593
5849
|
/**
|
|
5594
5850
|
* A private helper function to clear all SVG nodes from the >g> node.
|
|
@@ -5792,6 +6048,126 @@ class drawutilssvg {
|
|
|
5792
6048
|
}
|
|
5793
6049
|
} // END while
|
|
5794
6050
|
} // END transformPathData
|
|
6051
|
+
static nodeSupportsLineDash(nodeName) {
|
|
6052
|
+
return ["line", "path", "circle", "ellipse", "rectangle", "rect"].includes(nodeName);
|
|
6053
|
+
}
|
|
6054
|
+
/**
|
|
6055
|
+
* Creates a basic <line> node with start and end coordinates. The created node will not
|
|
6056
|
+
* be bound to any root node.
|
|
6057
|
+
*
|
|
6058
|
+
* @private
|
|
6059
|
+
* @method makeLineNode
|
|
6060
|
+
* @param {XYCoords} zA - The line's start position.
|
|
6061
|
+
* @param {XYCoords} zB - The line's start position.
|
|
6062
|
+
* @param {string} color - The CSS color to draw the point with.
|
|
6063
|
+
* @param {number=1} lineWidth - (optional) The line width to use.
|
|
6064
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Additional stroke options to use.
|
|
6065
|
+
* @param {string=} classNameOverride - (optional) If nothing is passed the default classname 'path' will be used.
|
|
6066
|
+
* @return {SVGLineElement}
|
|
6067
|
+
* @instance
|
|
6068
|
+
* @memberof drawutilssvg
|
|
6069
|
+
*/
|
|
6070
|
+
makeLineNode(zA, zB, color, lineWidth, strokeOptions, classNameOverride) {
|
|
6071
|
+
const line = this.makeNode("line");
|
|
6072
|
+
line.setAttribute("x1", `${this._x(zA.x)}`);
|
|
6073
|
+
line.setAttribute("y1", `${this._y(zA.y)}`);
|
|
6074
|
+
line.setAttribute("x2", `${this._x(zB.x)}`);
|
|
6075
|
+
line.setAttribute("y2", `${this._y(zB.y)}`);
|
|
6076
|
+
this._configureNode(line, classNameOverride !== null && classNameOverride !== void 0 ? classNameOverride : "line", this.fillShapes, color, lineWidth || 1, strokeOptions);
|
|
6077
|
+
return line;
|
|
6078
|
+
}
|
|
6079
|
+
/**
|
|
6080
|
+
* Creates a basic <path> node with given path string data. The created node will not
|
|
6081
|
+
* be bound to any root node.
|
|
6082
|
+
*
|
|
6083
|
+
* @private
|
|
6084
|
+
* @method makePathNode
|
|
6085
|
+
* @param {string} pathString - The path data (must be a valid path data string).
|
|
6086
|
+
* @param {string} color - The CSS color to draw the point with.
|
|
6087
|
+
* @param {number=1} lineWidth - (optional) The line width to use.
|
|
6088
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Additional stroke options to use.
|
|
6089
|
+
* @param {string=} classNameOverride - (optional) If nothing is passed the default classname 'path' will be used.
|
|
6090
|
+
* @return {SVGPathElement}
|
|
6091
|
+
* @instance
|
|
6092
|
+
* @memberof drawutilssvg
|
|
6093
|
+
*/
|
|
6094
|
+
makePathNode(pathString, color, lineWidth, strokeOptions, classNameOverride) {
|
|
6095
|
+
const path = this.makeNode("path");
|
|
6096
|
+
path.setAttribute("d", pathString);
|
|
6097
|
+
this._configureNode(path, classNameOverride !== null && classNameOverride !== void 0 ? classNameOverride : "path", this.fillShapes, color, lineWidth || 1, strokeOptions);
|
|
6098
|
+
return path;
|
|
6099
|
+
}
|
|
6100
|
+
/**
|
|
6101
|
+
* Creates a basic arrow head node (<path> node) at the end of the given line coordinates. The created node will not
|
|
6102
|
+
* be bound to any root node.
|
|
6103
|
+
*
|
|
6104
|
+
* @private
|
|
6105
|
+
* @method makeArrowHeadNode
|
|
6106
|
+
* @param {string} pathString - The path data (must be a valid path data string).
|
|
6107
|
+
* @param {string} color - The CSS color to draw the point with.
|
|
6108
|
+
* @param {number=1} lineWidth - (optional) The line width to use.
|
|
6109
|
+
* @param {number=8} headLength - (optional) The length of the arrow head; if none is specified then the head will be 8 absolute units long.
|
|
6110
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Additional stroke options to use.
|
|
6111
|
+
* @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.
|
|
6112
|
+
* @return {SVGPathElement}
|
|
6113
|
+
* @instance
|
|
6114
|
+
* @memberof drawutilssvg
|
|
6115
|
+
*/
|
|
6116
|
+
makeArrowHeadNode(zA, zB, color, lineWidth, headLength = 8, strokeOptions, arrowHeadBasePositionBuffer) {
|
|
6117
|
+
var vertices = Vector.utils.buildArrowHead(zA, zB, headLength, this.scale.x, this.scale.y);
|
|
6118
|
+
const d = ["M", this.offset.x + vertices[0].x, this.offset.y + vertices[0].y];
|
|
6119
|
+
if (arrowHeadBasePositionBuffer) {
|
|
6120
|
+
arrowHeadBasePositionBuffer.x = vertices[0].x / this.scale.x;
|
|
6121
|
+
arrowHeadBasePositionBuffer.y = vertices[0].y / this.scale.y;
|
|
6122
|
+
}
|
|
6123
|
+
for (var i = 1; i <= vertices.length; i++) {
|
|
6124
|
+
d.push("L");
|
|
6125
|
+
// Note: only use offset here (the vertices are already scaled)
|
|
6126
|
+
d.push(this.offset.x + vertices[i % vertices.length].x);
|
|
6127
|
+
d.push(this.offset.y + vertices[i % vertices.length].y);
|
|
6128
|
+
}
|
|
6129
|
+
const node = this.makePathNode(d.join(" "), color, lineWidth, strokeOptions, "arrowhead");
|
|
6130
|
+
return node;
|
|
6131
|
+
}
|
|
6132
|
+
/**
|
|
6133
|
+
* Creates a basic cubic Bézier path node (<path> node) with the given cubic Bézier data. The created node will not
|
|
6134
|
+
* be bound to any root node.
|
|
6135
|
+
*
|
|
6136
|
+
* @private
|
|
6137
|
+
* @method makeCubicBezierNode
|
|
6138
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
6139
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
6140
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
6141
|
+
* @param {XYCoords} endControlPoint - The end control point the cubic Bézier curve.
|
|
6142
|
+
* @param {string} color - The CSS color to draw the point with.
|
|
6143
|
+
* @param {number=1} lineWidth - (optional) The line width to use.
|
|
6144
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Additional stroke options to use.
|
|
6145
|
+
* @param {string=} classNameOverride - (optional) If nothing is passed the default classname 'path' will be used.
|
|
6146
|
+
* @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.
|
|
6147
|
+
* @return {SVGPathElement}
|
|
6148
|
+
* @instance
|
|
6149
|
+
* @memberof drawutilssvg
|
|
6150
|
+
*/
|
|
6151
|
+
makeCubicBezierNode(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, strokeOptions) {
|
|
6152
|
+
if (startPoint instanceof CubicBezierCurve) {
|
|
6153
|
+
return this.cubicBezier(startPoint.startPoint, startPoint.endPoint, startPoint.startControlPoint, startPoint.endControlPoint, color, lineWidth);
|
|
6154
|
+
}
|
|
6155
|
+
// Draw curve
|
|
6156
|
+
const d = [
|
|
6157
|
+
"M",
|
|
6158
|
+
this._x(startPoint.x),
|
|
6159
|
+
this._y(startPoint.y),
|
|
6160
|
+
"C",
|
|
6161
|
+
this._x(startControlPoint.x),
|
|
6162
|
+
this._y(startControlPoint.y),
|
|
6163
|
+
this._x(endControlPoint.x),
|
|
6164
|
+
this._y(endControlPoint.y),
|
|
6165
|
+
this._x(endPoint.x),
|
|
6166
|
+
this._y(endPoint.y)
|
|
6167
|
+
];
|
|
6168
|
+
const node = this.makePathNode(d.join(" "), color, lineWidth, strokeOptions, "cubicBezier");
|
|
6169
|
+
return node;
|
|
6170
|
+
}
|
|
5795
6171
|
}
|
|
5796
6172
|
drawutilssvg.HEAD_XML = [
|
|
5797
6173
|
'<?xml version="1.0" encoding="UTF-8" standalone="no"?>',
|
|
@@ -5850,7 +6226,15 @@ drawutilssvg.HEAD_XML = [
|
|
|
5850
6226
|
* @modified 2022-08-23 Fixed a type issue in the `setConfiguration` function.
|
|
5851
6227
|
* @modified 2022-08-23 Fixed a type issue in the `path` function.
|
|
5852
6228
|
* @modified 2023-02-10 The methods `setCurrentClassName` and `setCurrentId` also accept `null` now.
|
|
5853
|
-
* @
|
|
6229
|
+
* @modified 2023-09-29 Removed unused method stub for texturedPoly helper function (cleanup).
|
|
6230
|
+
* @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.
|
|
6231
|
+
* @modified 2023-09-29 Added the `headLength` parameter to the 'DrawLib.arrow()` function.
|
|
6232
|
+
* @modified 2023-09-29 Added the `arrowHead(...)` function to the 'DrawLib.arrow()` interface.
|
|
6233
|
+
* @modified 2023-09-29 Added the `cubicBezierArrow(...)` function to the 'DrawLib.arrow()` interface.
|
|
6234
|
+
* @modified 2023-09-29 Added the `lineDashes` attribute.
|
|
6235
|
+
* @modified 2023-09-30 Adding `strokeOptions` param to these draw function: line, arrow, cubicBezierArrow, cubicBezier, cubicBezierPath, circle, circleArc, ellipse, square, rect, polygon, polyline.
|
|
6236
|
+
* @modified 2023-10-07 Adding the optional `arrowHeadBasePositionBuffer` param to the arrowHead(...) method.
|
|
6237
|
+
* @version 1.13.0
|
|
5854
6238
|
**/
|
|
5855
6239
|
// Todo: rename this class to Drawutils?
|
|
5856
6240
|
/**
|
|
@@ -5872,10 +6256,47 @@ class drawutils {
|
|
|
5872
6256
|
**/
|
|
5873
6257
|
constructor(context, fillShapes) {
|
|
5874
6258
|
this.ctx = context;
|
|
6259
|
+
// this.lineDash = [];
|
|
5875
6260
|
this.offset = new Vertex(0, 0);
|
|
5876
6261
|
this.scale = new Vertex(1, 1);
|
|
5877
6262
|
this.fillShapes = fillShapes;
|
|
5878
6263
|
}
|
|
6264
|
+
/**
|
|
6265
|
+
* A private helper method to apply stroke options to the current
|
|
6266
|
+
* context.
|
|
6267
|
+
* @param {StrokeOptions=} strokeOptions -
|
|
6268
|
+
*/
|
|
6269
|
+
applyStrokeOpts(strokeOptions) {
|
|
6270
|
+
var _a, _b;
|
|
6271
|
+
this.ctx.setLineDash(((_a = strokeOptions === null || strokeOptions === void 0 ? void 0 : strokeOptions.dashArray) !== null && _a !== void 0 ? _a : []).map((dashArrayElem) => {
|
|
6272
|
+
// Note assume scale.x === scale.y
|
|
6273
|
+
// Invariant scale makes funny stuff anyway.
|
|
6274
|
+
return dashArrayElem * this.scale.x;
|
|
6275
|
+
}));
|
|
6276
|
+
this.ctx.lineDashOffset = ((_b = strokeOptions === null || strokeOptions === void 0 ? void 0 : strokeOptions.dashOffset) !== null && _b !== void 0 ? _b : 0) * this.scale.x;
|
|
6277
|
+
}
|
|
6278
|
+
// +---------------------------------------------------------------------------------
|
|
6279
|
+
// | This is the final helper function for drawing and filling stuff. It is not
|
|
6280
|
+
// | intended to be used from the outside.
|
|
6281
|
+
// |
|
|
6282
|
+
// | When in draw mode it draws the current shape.
|
|
6283
|
+
// | When in fill mode it fills the current shape.
|
|
6284
|
+
// |
|
|
6285
|
+
// | This function is usually only called internally.
|
|
6286
|
+
// |
|
|
6287
|
+
// | @param color A stroke/fill color to use.
|
|
6288
|
+
// +-------------------------------
|
|
6289
|
+
// TODO: convert this to a STATIC function.
|
|
6290
|
+
_fillOrDraw(color) {
|
|
6291
|
+
if (this.fillShapes) {
|
|
6292
|
+
this.ctx.fillStyle = color;
|
|
6293
|
+
this.ctx.fill();
|
|
6294
|
+
}
|
|
6295
|
+
else {
|
|
6296
|
+
this.ctx.strokeStyle = color;
|
|
6297
|
+
this.ctx.stroke();
|
|
6298
|
+
}
|
|
6299
|
+
}
|
|
5879
6300
|
/**
|
|
5880
6301
|
* Called before each draw cycle.
|
|
5881
6302
|
* @param {UID=} uid - (optional) A UID identifying the currently drawn element(s).
|
|
@@ -5906,6 +6327,20 @@ class drawutils {
|
|
|
5906
6327
|
setConfiguration(configuration) {
|
|
5907
6328
|
this.ctx.globalCompositeOperation = configuration.blendMode || "source-over";
|
|
5908
6329
|
}
|
|
6330
|
+
// /**
|
|
6331
|
+
// * Set or clear the line-dash configuration. Pass `null` for un-dashed lines.
|
|
6332
|
+
// *
|
|
6333
|
+
// * See https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray
|
|
6334
|
+
// * and https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
|
|
6335
|
+
// * for how line dashes work.
|
|
6336
|
+
// *
|
|
6337
|
+
// * @method
|
|
6338
|
+
// * @param {Array<number> lineDashes - The line-dash array configuration.
|
|
6339
|
+
// * @returns {void}
|
|
6340
|
+
// */
|
|
6341
|
+
// setLineDash(lineDash: Array<number>) {
|
|
6342
|
+
// this.lineDash = lineDash;
|
|
6343
|
+
// }
|
|
5909
6344
|
/**
|
|
5910
6345
|
* This method shouled be called each time the currently drawn `Drawable` changes.
|
|
5911
6346
|
* It is used by some libraries for identifying elemente on re-renders.
|
|
@@ -5932,17 +6367,20 @@ class drawutils {
|
|
|
5932
6367
|
* Draw the line between the given two points with the specified (CSS-) color.
|
|
5933
6368
|
*
|
|
5934
6369
|
* @method line
|
|
5935
|
-
* @param {
|
|
5936
|
-
* @param {
|
|
6370
|
+
* @param {XYCoords} zA - The start point of the line.
|
|
6371
|
+
* @param {XYCoords} zB - The end point of the line.
|
|
5937
6372
|
* @param {string} color - Any valid CSS color string.
|
|
5938
6373
|
* @param {number} lineWidth? - [optional] The line's width.
|
|
6374
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6375
|
+
*
|
|
5939
6376
|
* @return {void}
|
|
5940
6377
|
* @instance
|
|
5941
6378
|
* @memberof drawutils
|
|
5942
6379
|
**/
|
|
5943
|
-
line(zA, zB, color, lineWidth) {
|
|
6380
|
+
line(zA, zB, color, lineWidth, strokeOptions) {
|
|
5944
6381
|
this.ctx.save();
|
|
5945
6382
|
this.ctx.beginPath();
|
|
6383
|
+
this.applyStrokeOpts(strokeOptions);
|
|
5946
6384
|
this.ctx.moveTo(this.offset.x + zA.x * this.scale.x, this.offset.y + zA.y * this.scale.y);
|
|
5947
6385
|
this.ctx.lineTo(this.offset.x + zB.x * this.scale.x, this.offset.y + zB.y * this.scale.y);
|
|
5948
6386
|
this.ctx.strokeStyle = color;
|
|
@@ -5954,22 +6392,74 @@ class drawutils {
|
|
|
5954
6392
|
* Draw a line and an arrow at the end (zB) of the given line with the specified (CSS-) color.
|
|
5955
6393
|
*
|
|
5956
6394
|
* @method arrow
|
|
5957
|
-
* @param {
|
|
5958
|
-
* @param {
|
|
6395
|
+
* @param {XYCoords} zA - The start point of the arrow-line.
|
|
6396
|
+
* @param {XYCoords} zB - The end point of the arrow-line.
|
|
5959
6397
|
* @param {string} color - Any valid CSS color string.
|
|
5960
6398
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
6399
|
+
* @param {headLength=8} headLength - (optional) The length of the arrow head (default is 8 units).
|
|
6400
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6401
|
+
*
|
|
5961
6402
|
* @return {void}
|
|
5962
6403
|
* @instance
|
|
5963
6404
|
* @memberof drawutils
|
|
5964
6405
|
**/
|
|
5965
|
-
arrow(zA, zB, color, lineWidth) {
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
6406
|
+
arrow(zA, zB, color, lineWidth, headLength = 8, strokeOptions) {
|
|
6407
|
+
const arrowHeadBasePosition = new Vertex(0, 0);
|
|
6408
|
+
this.arrowHead(zA, zB, color, lineWidth, headLength, undefined, arrowHeadBasePosition); // Will NOT use dash configuration
|
|
6409
|
+
this.line(zA, arrowHeadBasePosition, color, lineWidth, strokeOptions); // Will use dash configuration
|
|
6410
|
+
}
|
|
6411
|
+
/**
|
|
6412
|
+
* 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.
|
|
6413
|
+
*
|
|
6414
|
+
* @method cubicBezierArrow
|
|
6415
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
6416
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
6417
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
6418
|
+
* @param {XYCoords} endControlPoint - The end control point the cubic Bézier curve.
|
|
6419
|
+
* @param {string} color - The CSS color to draw the curve with.
|
|
6420
|
+
* @param {number} lineWidth - (optional) The line width to use.
|
|
6421
|
+
* @param {headLength=8} headLength - (optional) The length of the arrow head (default is 8 units).
|
|
6422
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6423
|
+
*
|
|
6424
|
+
* @return {void}
|
|
6425
|
+
* @instance
|
|
6426
|
+
* @memberof DrawLib
|
|
6427
|
+
*/
|
|
6428
|
+
cubicBezierArrow(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, headLength, strokeOptions) {
|
|
6429
|
+
const arrowHeadBasePosition = new Vertex(0, 0);
|
|
6430
|
+
// Will NOT use dash configuration
|
|
6431
|
+
this.arrowHead(endControlPoint, endPoint, color, lineWidth, headLength, undefined, arrowHeadBasePosition);
|
|
6432
|
+
const diff = arrowHeadBasePosition.difference(endPoint);
|
|
6433
|
+
// Will use dash configuration
|
|
6434
|
+
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);
|
|
6435
|
+
}
|
|
6436
|
+
/**
|
|
6437
|
+
* Draw just an arrow head a the end of an imaginary line (zB) of the given line width the specified (CSS-) color and size.
|
|
6438
|
+
*
|
|
6439
|
+
* @method arrow
|
|
6440
|
+
* @param {XYCoords} zA - The start point of the arrow-line.
|
|
6441
|
+
* @param {XYCoords} zB - The end point of the arrow-line.
|
|
6442
|
+
* @param {string} color - Any valid CSS color string.
|
|
6443
|
+
* @param {number=1} lineWidth - (optional) The line width to use; default is 1.
|
|
6444
|
+
* @param {number=8} headLength - (optional) The length of the arrow head (default is 8 pixels).
|
|
6445
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6446
|
+
* @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.
|
|
6447
|
+
*
|
|
6448
|
+
* @return {void}
|
|
6449
|
+
* @instance
|
|
6450
|
+
* @memberof DrawLib
|
|
6451
|
+
**/
|
|
6452
|
+
arrowHead(zA, zB, color, lineWidth, headLength = 8, strokeOptions, arrowHeadBasePositionBuffer) {
|
|
6453
|
+
// var headLength: number = 8; // length of head in pixels
|
|
5969
6454
|
this.ctx.save();
|
|
5970
6455
|
this.ctx.beginPath();
|
|
5971
|
-
|
|
5972
|
-
|
|
6456
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6457
|
+
var vertices = Vector.utils.buildArrowHead(zA, zB, headLength, this.scale.x, this.scale.y);
|
|
6458
|
+
if (arrowHeadBasePositionBuffer) {
|
|
6459
|
+
arrowHeadBasePositionBuffer.x = vertices[0].x / this.scale.x;
|
|
6460
|
+
arrowHeadBasePositionBuffer.y = vertices[0].y / this.scale.y;
|
|
6461
|
+
}
|
|
6462
|
+
this.ctx.moveTo(this.offset.x + vertices[0].x, this.offset.y + vertices[0].y);
|
|
5973
6463
|
for (var i = 0; i < vertices.length; i++) {
|
|
5974
6464
|
this.ctx.lineTo(this.offset.x + vertices[i].x, this.offset.y + vertices[i].y);
|
|
5975
6465
|
}
|
|
@@ -5985,8 +6475,8 @@ class drawutils {
|
|
|
5985
6475
|
*
|
|
5986
6476
|
* @method image
|
|
5987
6477
|
* @param {Image} image - The image object to draw.
|
|
5988
|
-
* @param {
|
|
5989
|
-
* @param {
|
|
6478
|
+
* @param {XYCoords} position - The position to draw the the upper left corner at.
|
|
6479
|
+
* @param {XYCoords} size - The x/y-size to draw the image with.
|
|
5990
6480
|
* @param {number=0.0} alpha - (optional, default=0.0) The transparency (1.0=opaque, 0.0=transparent).
|
|
5991
6481
|
* @return {void}
|
|
5992
6482
|
* @instance
|
|
@@ -6015,7 +6505,7 @@ class drawutils {
|
|
|
6015
6505
|
* @param {Image} textureImage - The image object to draw.
|
|
6016
6506
|
* @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
|
|
6017
6507
|
* @param {Polygon} polygon - The polygon to use as clip path.
|
|
6018
|
-
* @param {
|
|
6508
|
+
* @param {XYCoords} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
|
|
6019
6509
|
* @param {number} rotation - The rotation to use for the polygon (and for the texture).
|
|
6020
6510
|
* @param {XYCoords={x:0,y:0}} rotationCenter - (optional) The rotational center; default is center of bounding box.
|
|
6021
6511
|
* @return {void}
|
|
@@ -6024,10 +6514,9 @@ class drawutils {
|
|
|
6024
6514
|
**/
|
|
6025
6515
|
texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
|
|
6026
6516
|
var basePolygonBounds = polygon.getBounds();
|
|
6027
|
-
var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
|
|
6028
|
-
|
|
6029
|
-
// var
|
|
6030
|
-
basePolygonBounds.getCenter().sub(targetCenterDifference);
|
|
6517
|
+
// var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
|
|
6518
|
+
new Vertex(polygonPosition.x, polygonPosition.y).difference(basePolygonBounds.getCenter());
|
|
6519
|
+
// var tileCenter = basePolygonBounds.getCenter().sub(targetCenterDifference);
|
|
6031
6520
|
// Get the position offset of the polygon
|
|
6032
6521
|
var targetTextureSize = new Vertex(textureSize.width, textureSize.height);
|
|
6033
6522
|
// var targetTextureOffset = new Vertex(-textureSize.width / 2, -textureSize.height / 2).sub(targetCenterDifference);
|
|
@@ -6050,52 +6539,83 @@ class drawutils {
|
|
|
6050
6539
|
);
|
|
6051
6540
|
this.ctx.restore();
|
|
6052
6541
|
}
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
|
|
6063
|
-
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
|
|
6073
|
-
|
|
6542
|
+
/*
|
|
6543
|
+
_texturedPoly(
|
|
6544
|
+
textureImage: HTMLImageElement,
|
|
6545
|
+
textureSize: Bounds,
|
|
6546
|
+
polygon: Polygon,
|
|
6547
|
+
polygonPosition: XYCoords,
|
|
6548
|
+
rotation: number,
|
|
6549
|
+
rotationCenter: XYCoords = { x: 0, y: 0 }
|
|
6550
|
+
): void {
|
|
6551
|
+
var basePolygonBounds = polygon.getBounds();
|
|
6552
|
+
var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
|
|
6553
|
+
var rotationalOffset = rotationCenter ? polygonPosition.difference(rotationCenter) : { x: 0, y: 0 };
|
|
6554
|
+
// var rotationalOffset = { x: 0, y: 0 };
|
|
6555
|
+
var tileCenter = basePolygonBounds.getCenter().sub(targetCenterDifference);
|
|
6556
|
+
|
|
6557
|
+
// Get the position offset of the polygon
|
|
6558
|
+
var targetTextureSize = new Vertex(textureSize.width, textureSize.height);
|
|
6559
|
+
var targetTextureOffset = new Vertex(-textureSize.width / 2, -textureSize.height / 2).sub(targetCenterDifference);
|
|
6560
|
+
|
|
6561
|
+
this.ctx.save();
|
|
6562
|
+
|
|
6563
|
+
// this.ctx.translate(
|
|
6564
|
+
// this.offset.x + (tileCenter.x - rotationalOffset.x * 0 + targetTextureOffset.x * 0.0) * this.scale.x,
|
|
6565
|
+
// this.offset.y + (tileCenter.y - rotationalOffset.y * 0 + targetTextureOffset.y * 0.0) * this.scale.y
|
|
6566
|
+
// );
|
|
6567
|
+
this.ctx.translate(
|
|
6568
|
+
this.offset.x + (tileCenter.x - rotationalOffset.x * 0 + targetTextureOffset.x * 0.0) * this.scale.x,
|
|
6569
|
+
this.offset.y + (tileCenter.y - rotationalOffset.y * 0 + targetTextureOffset.y * 0.0) * this.scale.y
|
|
6570
|
+
);
|
|
6571
|
+
this.ctx.rotate(rotation);
|
|
6572
|
+
|
|
6573
|
+
drawutils.helpers.clipPoly(
|
|
6574
|
+
this.ctx,
|
|
6575
|
+
{
|
|
6576
|
+
x: (-targetCenterDifference.x * 1 - tileCenter.x - rotationalOffset.x) * this.scale.x,
|
|
6577
|
+
y: (-targetCenterDifference.y * 1 - tileCenter.y - rotationalOffset.y) * this.scale.y
|
|
6578
|
+
},
|
|
6579
|
+
this.scale,
|
|
6580
|
+
polygon.vertices
|
|
6581
|
+
);
|
|
6582
|
+
this.ctx.drawImage(
|
|
6583
|
+
textureImage,
|
|
6584
|
+
0,
|
|
6585
|
+
0,
|
|
6586
|
+
textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
|
|
6074
6587
|
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
|
-
|
|
6588
|
+
(-polygonPosition.x + targetTextureOffset.x * 1 - rotationalOffset.x * 1) * this.scale.x,
|
|
6589
|
+
(-polygonPosition.y + targetTextureOffset.y * 1 - rotationalOffset.y * 1) * this.scale.y,
|
|
6590
|
+
targetTextureSize.x * this.scale.x,
|
|
6591
|
+
targetTextureSize.y * this.scale.y
|
|
6592
|
+
);
|
|
6593
|
+
|
|
6594
|
+
// const scaledTextureSize = new Bounds(
|
|
6595
|
+
// new Vertex(
|
|
6596
|
+
// -polygonPosition.x + targetTextureOffset.x - rotationalOffset.x,
|
|
6597
|
+
// -polygonPosition.y + targetTextureOffset.y - rotationalOffset.y
|
|
6598
|
+
// ).scaleXY(this.scale, rotationCenter),
|
|
6599
|
+
// new Vertex(
|
|
6600
|
+
// -polygonPosition.x + targetTextureOffset.x - rotationalOffset.x + targetTextureSize.x,
|
|
6601
|
+
// -polygonPosition.y + targetTextureOffset.y - rotationalOffset.y + targetTextureSize.y
|
|
6602
|
+
// ).scaleXY(this.scale, rotationCenter)
|
|
6603
|
+
// );
|
|
6604
|
+
// this.ctx.drawImage(
|
|
6605
|
+
// textureImage,
|
|
6606
|
+
// 0,
|
|
6607
|
+
// 0,
|
|
6608
|
+
// textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
|
|
6609
|
+
// textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
|
|
6610
|
+
// scaledTextureSize.min.x,
|
|
6611
|
+
// scaledTextureSize.min.y,
|
|
6612
|
+
// scaledTextureSize.width,
|
|
6613
|
+
// scaledTextureSize.height
|
|
6614
|
+
// );
|
|
6615
|
+
|
|
6616
|
+
this.ctx.restore();
|
|
6098
6617
|
}
|
|
6618
|
+
*/
|
|
6099
6619
|
/**
|
|
6100
6620
|
* Draw a rectangle.
|
|
6101
6621
|
*
|
|
@@ -6104,10 +6624,16 @@ class drawutils {
|
|
|
6104
6624
|
* @param {number} height - The height of the rectangle.
|
|
6105
6625
|
* @param {string} color - The color to use.
|
|
6106
6626
|
* @param {number=1} lineWidth - (optional) The line with to use (default is 1).
|
|
6627
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6628
|
+
*
|
|
6629
|
+
* @return {void}
|
|
6630
|
+
* @instance
|
|
6631
|
+
* @memberof drawutils
|
|
6107
6632
|
**/
|
|
6108
|
-
rect(position, width, height, color, lineWidth) {
|
|
6633
|
+
rect(position, width, height, color, lineWidth, strokeOptions) {
|
|
6109
6634
|
this.ctx.save();
|
|
6110
6635
|
this.ctx.beginPath();
|
|
6636
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6111
6637
|
this.ctx.moveTo(this.offset.x + position.x * this.scale.x, this.offset.y + position.y * this.scale.y);
|
|
6112
6638
|
this.ctx.lineTo(this.offset.x + (position.x + width) * this.scale.x, this.offset.y + position.y * this.scale.y);
|
|
6113
6639
|
this.ctx.lineTo(this.offset.x + (position.x + width) * this.scale.x, this.offset.y + (position.y + height) * this.scale.y);
|
|
@@ -6118,43 +6644,23 @@ class drawutils {
|
|
|
6118
6644
|
this._fillOrDraw(color);
|
|
6119
6645
|
this.ctx.restore();
|
|
6120
6646
|
}
|
|
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
6647
|
/**
|
|
6144
6648
|
* Draw the given (cubic) bézier curve.
|
|
6145
6649
|
*
|
|
6146
6650
|
* @method cubicBezier
|
|
6147
|
-
* @param {
|
|
6148
|
-
* @param {
|
|
6149
|
-
* @param {
|
|
6150
|
-
* @param {
|
|
6651
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
6652
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
6653
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
6654
|
+
* @param {XYCoords} endControlPoint - The end control point the cubic Bézier curve.
|
|
6151
6655
|
* @param {string} color - The CSS color to draw the curve with.
|
|
6152
6656
|
* @param {number} lineWidth - (optional) The line width to use.
|
|
6657
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6658
|
+
*
|
|
6153
6659
|
* @return {void}
|
|
6154
6660
|
* @instance
|
|
6155
6661
|
* @memberof drawutils
|
|
6156
6662
|
*/
|
|
6157
|
-
cubicBezier(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth) {
|
|
6663
|
+
cubicBezier(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, strokeOptions) {
|
|
6158
6664
|
if (startPoint instanceof CubicBezierCurve) {
|
|
6159
6665
|
this.cubicBezier(startPoint.startPoint, startPoint.endPoint, startPoint.startControlPoint, startPoint.endControlPoint, color, lineWidth);
|
|
6160
6666
|
return;
|
|
@@ -6162,6 +6668,7 @@ class drawutils {
|
|
|
6162
6668
|
// Draw curve
|
|
6163
6669
|
this.ctx.save();
|
|
6164
6670
|
this.ctx.beginPath();
|
|
6671
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6165
6672
|
this.ctx.moveTo(this.offset.x + startPoint.x * this.scale.x, this.offset.y + startPoint.y * this.scale.y);
|
|
6166
6673
|
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
6674
|
//this.ctx.closePath();
|
|
@@ -6173,19 +6680,22 @@ class drawutils {
|
|
|
6173
6680
|
* Draw the given (quadratic) bézier curve.
|
|
6174
6681
|
*
|
|
6175
6682
|
* @method quadraticBezier
|
|
6176
|
-
* @param {
|
|
6177
|
-
* @param {
|
|
6178
|
-
* @param {
|
|
6683
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
6684
|
+
* @param {XYCoords} controlPoint - The control point the cubic Bézier curve.
|
|
6685
|
+
* @param {XYCoords} endPoint - The end control point the cubic Bézier curve.
|
|
6179
6686
|
* @param {string} color - The CSS color to draw the curve with.
|
|
6180
6687
|
* @param {number|string} lineWidth - (optional) The line width to use.
|
|
6688
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6689
|
+
*
|
|
6181
6690
|
* @return {void}
|
|
6182
6691
|
* @instance
|
|
6183
6692
|
* @memberof drawutils
|
|
6184
6693
|
*/
|
|
6185
|
-
quadraticBezier(startPoint, controlPoint, endPoint, color, lineWidth) {
|
|
6694
|
+
quadraticBezier(startPoint, controlPoint, endPoint, color, lineWidth, strokeOptions) {
|
|
6186
6695
|
// Draw curve
|
|
6187
6696
|
this.ctx.save();
|
|
6188
6697
|
this.ctx.beginPath();
|
|
6698
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6189
6699
|
this.ctx.moveTo(this.offset.x + startPoint.x * this.scale.x, this.offset.y + startPoint.y * this.scale.y);
|
|
6190
6700
|
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
6701
|
this.ctx.lineWidth = lineWidth || 2;
|
|
@@ -6200,22 +6710,26 @@ class drawutils {
|
|
|
6200
6710
|
* <pre> [ point1, point1_startControl, point2_endControl, point2, point2_startControl, point3_endControl, point3, ... pointN_endControl, pointN ]</pre>
|
|
6201
6711
|
*
|
|
6202
6712
|
* @method cubicBezierPath
|
|
6203
|
-
* @param {
|
|
6713
|
+
* @param {XYCoords[]} path - The cubic bezier path as described above.
|
|
6204
6714
|
* @param {string} color - The CSS colot to draw the path with.
|
|
6205
6715
|
* @param {number=1} lineWidth - (optional) The line width to use.
|
|
6716
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6717
|
+
*
|
|
6206
6718
|
* @return {void}
|
|
6207
6719
|
* @instance
|
|
6208
6720
|
* @memberof drawutils
|
|
6209
6721
|
*/
|
|
6210
|
-
cubicBezierPath(path, color, lineWidth) {
|
|
6211
|
-
if (!path || path.length == 0)
|
|
6722
|
+
cubicBezierPath(path, color, lineWidth, strokeOptions) {
|
|
6723
|
+
if (!path || path.length == 0) {
|
|
6212
6724
|
return;
|
|
6725
|
+
}
|
|
6213
6726
|
// Draw curve
|
|
6214
6727
|
this.ctx.save();
|
|
6215
6728
|
this.ctx.beginPath();
|
|
6216
6729
|
var endPoint;
|
|
6217
6730
|
var startControlPoint;
|
|
6218
6731
|
var endControlPoint;
|
|
6732
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6219
6733
|
this.ctx.moveTo(this.offset.x + path[0].x * this.scale.x, this.offset.y + path[0].y * this.scale.y);
|
|
6220
6734
|
for (var i = 1; i < path.length; i += 3) {
|
|
6221
6735
|
startControlPoint = path[i];
|
|
@@ -6234,8 +6748,8 @@ class drawutils {
|
|
|
6234
6748
|
* The colors for this are fixed and cannot be specified.
|
|
6235
6749
|
*
|
|
6236
6750
|
* @method handle
|
|
6237
|
-
* @param {
|
|
6238
|
-
* @param {
|
|
6751
|
+
* @param {XYCoords} startPoint - The start of the handle.
|
|
6752
|
+
* @param {XYCoords} endPoint - The end point of the handle.
|
|
6239
6753
|
* @return {void}
|
|
6240
6754
|
* @instance
|
|
6241
6755
|
* @memberof drawutils
|
|
@@ -6250,21 +6764,21 @@ class drawutils {
|
|
|
6250
6764
|
* Draw a handle line (with a light grey).
|
|
6251
6765
|
*
|
|
6252
6766
|
* @method handleLine
|
|
6253
|
-
* @param {
|
|
6254
|
-
* @param {
|
|
6767
|
+
* @param {XYCoords} startPoint - The start point to draw the handle at.
|
|
6768
|
+
* @param {XYCoords} endPoint - The end point to draw the handle at.
|
|
6255
6769
|
* @return {void}
|
|
6256
6770
|
* @instance
|
|
6257
6771
|
* @memberof drawutils
|
|
6258
6772
|
*/
|
|
6259
6773
|
handleLine(startPoint, endPoint) {
|
|
6260
6774
|
// Draw handle lines
|
|
6261
|
-
this.line(startPoint, endPoint, "
|
|
6775
|
+
this.line(startPoint, endPoint, "rgba(128,128,128, 0.5)", undefined);
|
|
6262
6776
|
}
|
|
6263
6777
|
/**
|
|
6264
6778
|
* Draw a 1x1 dot with the specified (CSS-) color.
|
|
6265
6779
|
*
|
|
6266
6780
|
* @method dot
|
|
6267
|
-
* @param {
|
|
6781
|
+
* @param {XYCoords} p - The position to draw the dot at.
|
|
6268
6782
|
* @param {string} color - The CSS color to draw the dot with.
|
|
6269
6783
|
* @return {void}
|
|
6270
6784
|
* @instance
|
|
@@ -6273,6 +6787,7 @@ class drawutils {
|
|
|
6273
6787
|
dot(p, color) {
|
|
6274
6788
|
this.ctx.save();
|
|
6275
6789
|
this.ctx.beginPath();
|
|
6790
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6276
6791
|
this.ctx.moveTo(Math.round(this.offset.x + this.scale.x * p.x), Math.round(this.offset.y + this.scale.y * p.y));
|
|
6277
6792
|
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
6793
|
this.ctx.closePath();
|
|
@@ -6284,7 +6799,7 @@ class drawutils {
|
|
|
6284
6799
|
* Draw the given point with the specified (CSS-) color and radius 3.
|
|
6285
6800
|
*
|
|
6286
6801
|
* @method point
|
|
6287
|
-
* @param {
|
|
6802
|
+
* @param {XYCoords} p - The position to draw the point at.
|
|
6288
6803
|
* @param {string} color - The CSS color to draw the point with.
|
|
6289
6804
|
* @return {void}
|
|
6290
6805
|
* @instance
|
|
@@ -6292,6 +6807,7 @@ class drawutils {
|
|
|
6292
6807
|
*/
|
|
6293
6808
|
point(p, color) {
|
|
6294
6809
|
var radius = 3;
|
|
6810
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6295
6811
|
this.ctx.beginPath();
|
|
6296
6812
|
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
6813
|
this.ctx.closePath();
|
|
@@ -6304,15 +6820,18 @@ class drawutils {
|
|
|
6304
6820
|
* Note that if the x- and y- scales are different the result will be an ellipse rather than a circle.
|
|
6305
6821
|
*
|
|
6306
6822
|
* @method circle
|
|
6307
|
-
* @param {
|
|
6823
|
+
* @param {XYCoords} center - The center of the circle.
|
|
6308
6824
|
* @param {number} radius - The radius of the circle.
|
|
6309
6825
|
* @param {string} color - The CSS color to draw the circle with.
|
|
6310
6826
|
* @param {number} lineWidth - The line width (optional, default=1).
|
|
6827
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6828
|
+
*
|
|
6311
6829
|
* @return {void}
|
|
6312
6830
|
* @instance
|
|
6313
6831
|
* @memberof drawutils
|
|
6314
6832
|
*/
|
|
6315
|
-
circle(center, radius, color, lineWidth) {
|
|
6833
|
+
circle(center, radius, color, lineWidth, strokeOptions) {
|
|
6834
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6316
6835
|
this.ctx.beginPath();
|
|
6317
6836
|
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
6837
|
this.ctx.closePath();
|
|
@@ -6320,24 +6839,28 @@ class drawutils {
|
|
|
6320
6839
|
this._fillOrDraw(color);
|
|
6321
6840
|
}
|
|
6322
6841
|
/**
|
|
6323
|
-
|
|
6324
|
-
|
|
6325
|
-
|
|
6326
|
-
|
|
6327
|
-
|
|
6328
|
-
|
|
6329
|
-
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
|
|
6335
|
-
|
|
6336
|
-
|
|
6842
|
+
* Draw a circular arc (section of a circle) with the given CSS color.
|
|
6843
|
+
*
|
|
6844
|
+
* @method circleArc
|
|
6845
|
+
* @param {XYCoords} center - The center of the circle.
|
|
6846
|
+
* @param {number} radius - The radius of the circle.
|
|
6847
|
+
* @param {number} startAngle - The angle to start at.
|
|
6848
|
+
* @param {number} endAngle - The angle to end at.
|
|
6849
|
+
* @param {string=#000000} color - The CSS color to draw the circle with.
|
|
6850
|
+
* @param {number=1} lineWidth - The line width to use
|
|
6851
|
+
* @param {boolean=false} options.asSegment - If `true` then no beginPath and no draw will be applied (as part of larger path).
|
|
6852
|
+
* @param {number=} options.dashOffset - (optional) `See StrokeOptions`.
|
|
6853
|
+
* @param {number=[]} options.dashArray - (optional) `See StrokeOptions`.
|
|
6854
|
+
*
|
|
6855
|
+
* @return {void}
|
|
6856
|
+
* @instance
|
|
6857
|
+
* @memberof drawutils
|
|
6858
|
+
*/
|
|
6337
6859
|
circleArc(center, radius, startAngle, endAngle, color, lineWidth, options) {
|
|
6338
6860
|
if (!options || !options.asSegment) {
|
|
6339
6861
|
this.ctx.beginPath();
|
|
6340
6862
|
}
|
|
6863
|
+
this.applyStrokeOpts(options);
|
|
6341
6864
|
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
6865
|
if (!options || !options.asSegment) {
|
|
6343
6866
|
// this.ctx.closePath();
|
|
@@ -6349,20 +6872,23 @@ class drawutils {
|
|
|
6349
6872
|
* Draw an ellipse with the specified (CSS-) color and thw two radii.
|
|
6350
6873
|
*
|
|
6351
6874
|
* @method ellipse
|
|
6352
|
-
* @param {
|
|
6875
|
+
* @param {XYCoords} center - The center of the ellipse.
|
|
6353
6876
|
* @param {number} radiusX - The radius of the ellipse.
|
|
6354
6877
|
* @param {number} radiusY - The radius of the ellipse.
|
|
6355
6878
|
* @param {string} color - The CSS color to draw the ellipse with.
|
|
6356
6879
|
* @param {number} lineWidth=1 - An optional line width param (default is 1).
|
|
6357
6880
|
* @param {number=} rotation - (optional, default=0) The rotation of the ellipse.
|
|
6881
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6882
|
+
*
|
|
6358
6883
|
* @return {void}
|
|
6359
6884
|
* @instance
|
|
6360
6885
|
* @memberof drawutils
|
|
6361
6886
|
*/
|
|
6362
|
-
ellipse(center, radiusX, radiusY, color, lineWidth, rotation) {
|
|
6887
|
+
ellipse(center, radiusX, radiusY, color, lineWidth, rotation, strokeOptions) {
|
|
6363
6888
|
if (typeof rotation === "undefined") {
|
|
6364
6889
|
rotation = 0.0;
|
|
6365
6890
|
}
|
|
6891
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6366
6892
|
this.ctx.beginPath();
|
|
6367
6893
|
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
6894
|
this.ctx.closePath();
|
|
@@ -6379,11 +6905,14 @@ class drawutils {
|
|
|
6379
6905
|
* @param {number} size - The size of the square.
|
|
6380
6906
|
* @param {string} color - The CSS color to draw the square with.
|
|
6381
6907
|
* @param {number} lineWidth - The line with to use (optional, default is 1).
|
|
6908
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
6909
|
+
*
|
|
6382
6910
|
* @return {void}
|
|
6383
6911
|
* @instance
|
|
6384
6912
|
* @memberof drawutils
|
|
6385
6913
|
*/
|
|
6386
|
-
square(center, size, color, lineWidth) {
|
|
6914
|
+
square(center, size, color, lineWidth, strokeOptions) {
|
|
6915
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6387
6916
|
this.ctx.beginPath();
|
|
6388
6917
|
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
6918
|
this.ctx.closePath();
|
|
@@ -6394,7 +6923,7 @@ class drawutils {
|
|
|
6394
6923
|
* Draw a grid of horizontal and vertical lines with the given (CSS-) color.
|
|
6395
6924
|
*
|
|
6396
6925
|
* @method grid
|
|
6397
|
-
* @param {
|
|
6926
|
+
* @param {XYCoords} center - The center of the grid.
|
|
6398
6927
|
* @param {number} width - The total width of the grid (width/2 each to the left and to the right).
|
|
6399
6928
|
* @param {number} height - The total height of the grid (height/2 each to the top and to the bottom).
|
|
6400
6929
|
* @param {number} sizeX - The horizontal grid size.
|
|
@@ -6405,6 +6934,7 @@ class drawutils {
|
|
|
6405
6934
|
* @memberof drawutils
|
|
6406
6935
|
*/
|
|
6407
6936
|
grid(center, width, height, sizeX, sizeY, color) {
|
|
6937
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6408
6938
|
this.ctx.beginPath();
|
|
6409
6939
|
var yMin = -Math.ceil((height * 0.5) / sizeY) * sizeY;
|
|
6410
6940
|
var yMax = height / 2;
|
|
@@ -6429,7 +6959,7 @@ class drawutils {
|
|
|
6429
6959
|
* This works analogue to the grid() function
|
|
6430
6960
|
*
|
|
6431
6961
|
* @method raster
|
|
6432
|
-
* @param {
|
|
6962
|
+
* @param {XYCoords} center - The center of the raster.
|
|
6433
6963
|
* @param {number} width - The total width of the raster (width/2 each to the left and to the right).
|
|
6434
6964
|
* @param {number} height - The total height of the raster (height/2 each to the top and to the bottom).
|
|
6435
6965
|
* @param {number} sizeX - The horizontal raster size.
|
|
@@ -6441,6 +6971,7 @@ class drawutils {
|
|
|
6441
6971
|
*/
|
|
6442
6972
|
raster(center, width, height, sizeX, sizeY, color) {
|
|
6443
6973
|
this.ctx.save();
|
|
6974
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6444
6975
|
this.ctx.beginPath();
|
|
6445
6976
|
for (var x = -Math.ceil((width * 0.5) / sizeX) * sizeX; x < width / 2; x += sizeX) {
|
|
6446
6977
|
for (var y = -Math.ceil((height * 0.5) / sizeY) * sizeY; y < height / 2; y += sizeY) {
|
|
@@ -6465,14 +6996,15 @@ class drawutils {
|
|
|
6465
6996
|
* as even shaped diamonds.
|
|
6466
6997
|
*
|
|
6467
6998
|
* @method diamondHandle
|
|
6468
|
-
* @param {
|
|
6469
|
-
* @param {
|
|
6999
|
+
* @param {XYCoords} center - The center of the diamond.
|
|
7000
|
+
* @param {number} size - The x/y-size of the diamond.
|
|
6470
7001
|
* @param {string} color - The CSS color to draw the diamond with.
|
|
6471
7002
|
* @return {void}
|
|
6472
7003
|
* @instance
|
|
6473
7004
|
* @memberof drawutils
|
|
6474
7005
|
*/
|
|
6475
7006
|
diamondHandle(center, size, color) {
|
|
7007
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6476
7008
|
this.ctx.beginPath();
|
|
6477
7009
|
this.ctx.moveTo(this.offset.x + center.x * this.scale.x - size / 2.0, this.offset.y + center.y * this.scale.y);
|
|
6478
7010
|
this.ctx.lineTo(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y - size / 2.0);
|
|
@@ -6490,14 +7022,15 @@ class drawutils {
|
|
|
6490
7022
|
* as even shaped squares.
|
|
6491
7023
|
*
|
|
6492
7024
|
* @method squareHandle
|
|
6493
|
-
* @param {
|
|
6494
|
-
* @param {
|
|
7025
|
+
* @param {XYCoords} center - The center of the square.
|
|
7026
|
+
* @param {number} size - The x/y-size of the square.
|
|
6495
7027
|
* @param {string} color - The CSS color to draw the square with.
|
|
6496
7028
|
* @return {void}
|
|
6497
7029
|
* @instance
|
|
6498
7030
|
* @memberof drawutils
|
|
6499
7031
|
*/
|
|
6500
7032
|
squareHandle(center, size, color) {
|
|
7033
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6501
7034
|
this.ctx.beginPath();
|
|
6502
7035
|
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
7036
|
this.ctx.closePath();
|
|
@@ -6512,7 +7045,7 @@ class drawutils {
|
|
|
6512
7045
|
* as even shaped circles.
|
|
6513
7046
|
*
|
|
6514
7047
|
* @method circleHandle
|
|
6515
|
-
* @param {
|
|
7048
|
+
* @param {XYCoords} center - The center of the circle.
|
|
6516
7049
|
* @param {number} radius - The radius of the circle.
|
|
6517
7050
|
* @param {string} color - The CSS color to draw the circle with.
|
|
6518
7051
|
* @return {void}
|
|
@@ -6521,6 +7054,7 @@ class drawutils {
|
|
|
6521
7054
|
*/
|
|
6522
7055
|
circleHandle(center, radius, color) {
|
|
6523
7056
|
radius = radius || 3;
|
|
7057
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6524
7058
|
this.ctx.beginPath();
|
|
6525
7059
|
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
7060
|
this.ctx.closePath();
|
|
@@ -6543,6 +7077,7 @@ class drawutils {
|
|
|
6543
7077
|
*/
|
|
6544
7078
|
crosshair(center, radius, color, lineWidth) {
|
|
6545
7079
|
this.ctx.save();
|
|
7080
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6546
7081
|
this.ctx.beginPath();
|
|
6547
7082
|
this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y);
|
|
6548
7083
|
this.ctx.lineTo(this.offset.x + center.x * this.scale.x + radius, this.offset.y + center.y * this.scale.y);
|
|
@@ -6570,6 +7105,7 @@ class drawutils {
|
|
|
6570
7105
|
*/
|
|
6571
7106
|
cross(center, radius, color, lineWidth) {
|
|
6572
7107
|
this.ctx.save();
|
|
7108
|
+
this.ctx.setLineDash([]); // Clear line-dash settings
|
|
6573
7109
|
this.ctx.beginPath();
|
|
6574
7110
|
this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y - radius);
|
|
6575
7111
|
this.ctx.lineTo(this.offset.x + center.x * this.scale.x + radius, this.offset.y + center.y * this.scale.y + radius);
|
|
@@ -6588,30 +7124,35 @@ class drawutils {
|
|
|
6588
7124
|
* @param {Polygon} polygon - The polygon to draw.
|
|
6589
7125
|
* @param {string} color - The CSS color to draw the polygon with.
|
|
6590
7126
|
* @param {string} lineWidth - The line width to use.
|
|
7127
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
7128
|
+
*
|
|
6591
7129
|
* @return {void}
|
|
6592
7130
|
* @instance
|
|
6593
7131
|
* @memberof drawutils
|
|
6594
7132
|
*/
|
|
6595
|
-
polygon(polygon, color, lineWidth) {
|
|
6596
|
-
this.polyline(polygon.vertices, polygon.isOpen, color, lineWidth);
|
|
7133
|
+
polygon(polygon, color, lineWidth, strokeOptions) {
|
|
7134
|
+
this.polyline(polygon.vertices, polygon.isOpen, color, lineWidth, strokeOptions);
|
|
6597
7135
|
}
|
|
6598
7136
|
/**
|
|
6599
7137
|
* Draw a polygon line (alternative function to the polygon).
|
|
6600
7138
|
*
|
|
6601
7139
|
* @method polyline
|
|
6602
|
-
* @param {
|
|
7140
|
+
* @param {XYCoords[]} vertices - The polygon vertices to draw.
|
|
6603
7141
|
* @param {boolan} isOpen - If true the polyline will not be closed at its end.
|
|
6604
7142
|
* @param {string} color - The CSS color to draw the polygon with.
|
|
6605
7143
|
* @param {number} lineWidth - The line width (default is 1.0);
|
|
7144
|
+
* @param {StrokeOptions=} strokeOptions - (optional) Stroke settings to use.
|
|
7145
|
+
*
|
|
6606
7146
|
* @return {void}
|
|
6607
7147
|
* @instance
|
|
6608
7148
|
* @memberof drawutils
|
|
6609
7149
|
*/
|
|
6610
|
-
polyline(vertices, isOpen, color, lineWidth) {
|
|
7150
|
+
polyline(vertices, isOpen, color, lineWidth, strokeOptions) {
|
|
6611
7151
|
if (vertices.length <= 1) {
|
|
6612
7152
|
return;
|
|
6613
7153
|
}
|
|
6614
7154
|
this.ctx.save();
|
|
7155
|
+
this.applyStrokeOpts(strokeOptions);
|
|
6615
7156
|
this.ctx.beginPath();
|
|
6616
7157
|
this.ctx.lineWidth = (lineWidth || 1.0) * this.scale.x;
|
|
6617
7158
|
this.ctx.moveTo(this.offset.x + vertices[0].x * this.scale.x, this.offset.y + vertices[0].y * this.scale.y);
|
|
@@ -6723,6 +7264,8 @@ class drawutils {
|
|
|
6723
7264
|
* @param {string=null} color - (optional) The color to draw this path with (default is null).
|
|
6724
7265
|
* @param {number=1} lineWidth - (optional) the line width to use (default is 1).
|
|
6725
7266
|
* @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.
|
|
7267
|
+
* @param {number=} options.dashOffset - (optional) `See StrokeOptions`.
|
|
7268
|
+
* @param {number=[]} options.dashArray - (optional) `See StrokeOptions`.
|
|
6726
7269
|
* @instance
|
|
6727
7270
|
* @memberof drawutils
|
|
6728
7271
|
* @return {R} An instance representing the drawn path.
|
|
@@ -6734,6 +7277,7 @@ class drawutils {
|
|
|
6734
7277
|
this.ctx.strokeStyle = color;
|
|
6735
7278
|
}
|
|
6736
7279
|
this.ctx.lineWidth = lineWidth || 1;
|
|
7280
|
+
this.applyStrokeOpts(options);
|
|
6737
7281
|
if (this.fillShapes) {
|
|
6738
7282
|
if (color) {
|
|
6739
7283
|
this.ctx.fillStyle = color;
|
|
@@ -6790,7 +7334,12 @@ drawutils.helpers = {
|
|
|
6790
7334
|
* @modified 2022-03-27 Added the `texturedPoly` function.
|
|
6791
7335
|
* @modified 2022-07-26 Adding `alpha` to the `image(...)` function.
|
|
6792
7336
|
* @modified 2023-02-10 The methods `setCurrentClassName` and `setCurrentId` also accept `null` now.
|
|
6793
|
-
* @
|
|
7337
|
+
* @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.
|
|
7338
|
+
* @modified 2023-09-29 Added the `headLength` parameter to the 'DrawLib.arrow()` function.
|
|
7339
|
+
* @modified 2023-09-29 Added the `arrowHead(...)` function to the 'DrawLib.arrow()` interface.
|
|
7340
|
+
* @modified 2023-09-29 Added the `cubicBezierArrow(...)` function to the 'DrawLib.arrow()` interface.
|
|
7341
|
+
* @modified 2023-09-29 Added the `lineDashes` attribute.
|
|
7342
|
+
* @version 0.0.10
|
|
6794
7343
|
**/
|
|
6795
7344
|
/**
|
|
6796
7345
|
* @classdesc A wrapper class for basic drawing operations. This is the WebGL
|
|
@@ -6884,6 +7433,20 @@ class drawutilsgl {
|
|
|
6884
7433
|
setConfiguration(configuration) {
|
|
6885
7434
|
// TODO
|
|
6886
7435
|
}
|
|
7436
|
+
// /**
|
|
7437
|
+
// * Set or clear the line-dash configuration. Pass `null` for un-dashed lines.
|
|
7438
|
+
// *
|
|
7439
|
+
// * See https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray
|
|
7440
|
+
// * and https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/setLineDash
|
|
7441
|
+
// * for how line dashes work.
|
|
7442
|
+
// *
|
|
7443
|
+
// * @method
|
|
7444
|
+
// * @param {Array<number> lineDashes - The line-dash array configuration.
|
|
7445
|
+
// * @returns {void}
|
|
7446
|
+
// */
|
|
7447
|
+
// setLineDash(lineDashes: Array<number>) {
|
|
7448
|
+
// // TODO
|
|
7449
|
+
// }
|
|
6887
7450
|
/**
|
|
6888
7451
|
* This method shouled be called each time the currently drawn `Drawable` changes.
|
|
6889
7452
|
* It is used by some libraries for identifying elemente on re-renders.
|
|
@@ -6911,8 +7474,8 @@ class drawutilsgl {
|
|
|
6911
7474
|
* Draw the line between the given two points with the specified (CSS-) color.
|
|
6912
7475
|
*
|
|
6913
7476
|
* @method line
|
|
6914
|
-
* @param {
|
|
6915
|
-
* @param {
|
|
7477
|
+
* @param {XYCoords} zA - The start point of the line.
|
|
7478
|
+
* @param {XYCoords} zB - The end point of the line.
|
|
6916
7479
|
* @param {string} color - Any valid CSS color string.
|
|
6917
7480
|
* @return {void}
|
|
6918
7481
|
* @instance
|
|
@@ -6961,9 +7524,10 @@ class drawutilsgl {
|
|
|
6961
7524
|
* Draw a line and an arrow at the end (zB) of the given line with the specified (CSS-) color.
|
|
6962
7525
|
*
|
|
6963
7526
|
* @method arrow
|
|
6964
|
-
* @param {
|
|
6965
|
-
* @param {
|
|
7527
|
+
* @param {XYCoords} zA - The start point of the arrow-line.
|
|
7528
|
+
* @param {XYCoords} zB - The end point of the arrow-line.
|
|
6966
7529
|
* @param {string} color - Any valid CSS color string.
|
|
7530
|
+
* @param {headLength=8} headLength - (optional) The length of the arrow head (default is 8 units).
|
|
6967
7531
|
* @return {void}
|
|
6968
7532
|
* @instance
|
|
6969
7533
|
* @memberof drawutils
|
|
@@ -6971,6 +7535,41 @@ class drawutilsgl {
|
|
|
6971
7535
|
arrow(zA, zB, color) {
|
|
6972
7536
|
// NOT YET IMPLEMENTED
|
|
6973
7537
|
}
|
|
7538
|
+
/**
|
|
7539
|
+
* 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.
|
|
7540
|
+
*
|
|
7541
|
+
* @method cubicBezierArrow
|
|
7542
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
7543
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
7544
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
7545
|
+
* @param {XYCoords} endControlPoint - The end control point the cubic Bézier curve.
|
|
7546
|
+
* @param {string} color - The CSS color to draw the curve with.
|
|
7547
|
+
* @param {number} lineWidth - (optional) The line width to use.
|
|
7548
|
+
* @param {headLength=8} headLength - (optional) The length of the arrow head (default is 8 units).
|
|
7549
|
+
*
|
|
7550
|
+
* @return {void}
|
|
7551
|
+
* @instance
|
|
7552
|
+
* @memberof DrawLib
|
|
7553
|
+
*/
|
|
7554
|
+
cubicBezierArrow(startPoint, endPoint, startControlPoint, endControlPoint, color, lineWidth, headLength) {
|
|
7555
|
+
// NOT YET IMPLEMENTED
|
|
7556
|
+
}
|
|
7557
|
+
/**
|
|
7558
|
+
* Draw just an arrow head a the end of an imaginary line (zB) of the given line width the specified (CSS-) color and size.
|
|
7559
|
+
*
|
|
7560
|
+
* @method arrow
|
|
7561
|
+
* @param {XYCoords} zA - The start point of the arrow-line.
|
|
7562
|
+
* @param {XYCoords} zB - The end point of the arrow-line.
|
|
7563
|
+
* @param {string} color - Any valid CSS color string.
|
|
7564
|
+
* @param {number=1} lineWidth - (optional) The line width to use; default is 1.
|
|
7565
|
+
* @param {number=8} headLength - (optional) The length of the arrow head (default is 8 pixels).
|
|
7566
|
+
* @return {void}
|
|
7567
|
+
* @instance
|
|
7568
|
+
* @memberof DrawLib
|
|
7569
|
+
**/
|
|
7570
|
+
arrowHead(zA, zB, color, lineWidth, headLength) {
|
|
7571
|
+
// NOT YET IMPLEMENTED
|
|
7572
|
+
}
|
|
6974
7573
|
/**
|
|
6975
7574
|
* Draw an image at the given position with the given size.<br>
|
|
6976
7575
|
* <br>
|
|
@@ -6978,8 +7577,8 @@ class drawutilsgl {
|
|
|
6978
7577
|
*
|
|
6979
7578
|
* @method image
|
|
6980
7579
|
* @param {Image} image - The image object to draw.
|
|
6981
|
-
* @param {
|
|
6982
|
-
* @param {
|
|
7580
|
+
* @param {XYCoords} position - The position to draw the the upper left corner at.
|
|
7581
|
+
* @param {XYCoords} size - The x/y-size to draw the image with.
|
|
6983
7582
|
* @param {number=0.0} alpha - (optional, default=0.0) The transparency (0.0=opaque, 1.0=transparent).
|
|
6984
7583
|
* @return {void}
|
|
6985
7584
|
* @instance
|
|
@@ -6997,7 +7596,7 @@ class drawutilsgl {
|
|
|
6997
7596
|
* @param {Image} textureImage - The image object to draw.
|
|
6998
7597
|
* @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
|
|
6999
7598
|
* @param {Polygon} polygon - The polygon to use as clip path.
|
|
7000
|
-
* @param {
|
|
7599
|
+
* @param {XYCoords} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
|
|
7001
7600
|
* @param {number} rotation - The rotation to use for the polygon (and for the texture).
|
|
7002
7601
|
* @return {void}
|
|
7003
7602
|
* @instance
|
|
@@ -7024,10 +7623,10 @@ class drawutilsgl {
|
|
|
7024
7623
|
* Draw the given (cubic) bézier curve.
|
|
7025
7624
|
*
|
|
7026
7625
|
* @method cubicBezier
|
|
7027
|
-
* @param {
|
|
7028
|
-
* @param {
|
|
7029
|
-
* @param {
|
|
7030
|
-
* @param {
|
|
7626
|
+
* @param {XYCoords} startPoint - The start point of the cubic Bézier curve
|
|
7627
|
+
* @param {XYCoords} endPoint - The end point the cubic Bézier curve.
|
|
7628
|
+
* @param {XYCoords} startControlPoint - The start control point the cubic Bézier curve.
|
|
7629
|
+
* @param {VertXYCoordsex} endControlPoint - The end control point the cubic Bézier curve.
|
|
7031
7630
|
* @param {string} color - The CSS color to draw the curve with.
|
|
7032
7631
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
7033
7632
|
* @return {void}
|
|
@@ -7045,7 +7644,7 @@ class drawutilsgl {
|
|
|
7045
7644
|
* <pre> [ point1, point1_startControl, point2_endControl, point2, point2_startControl, point3_endControl, point3, ... pointN_endControl, pointN ]</pre>
|
|
7046
7645
|
*
|
|
7047
7646
|
* @method cubicBezierPath
|
|
7048
|
-
* @param {
|
|
7647
|
+
* @param {XYCoords[]} path - The cubic bezier path as described above.
|
|
7049
7648
|
* @param {string} color - The CSS colot to draw the path with.
|
|
7050
7649
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
7051
7650
|
* @return {void}
|
|
@@ -7061,8 +7660,8 @@ class drawutilsgl {
|
|
|
7061
7660
|
* The colors for this are fixed and cannot be specified.
|
|
7062
7661
|
*
|
|
7063
7662
|
* @method handle
|
|
7064
|
-
* @param {
|
|
7065
|
-
* @param {
|
|
7663
|
+
* @param {XYCoords} startPoint - The start of the handle.
|
|
7664
|
+
* @param {XYCoords} endPoint - The end point of the handle.
|
|
7066
7665
|
* @return {void}
|
|
7067
7666
|
* @instance
|
|
7068
7667
|
* @memberof drawutils
|
|
@@ -7074,8 +7673,8 @@ class drawutilsgl {
|
|
|
7074
7673
|
* Draw a handle line (with a light grey).
|
|
7075
7674
|
*
|
|
7076
7675
|
* @method handleLine
|
|
7077
|
-
* @param {
|
|
7078
|
-
* @param {
|
|
7676
|
+
* @param {XYCoords} startPoint - The start point to draw the handle at.
|
|
7677
|
+
* @param {XYCoords} endPoint - The end point to draw the handle at.
|
|
7079
7678
|
* @return {void}
|
|
7080
7679
|
* @instance
|
|
7081
7680
|
* @memberof drawutils
|
|
@@ -7087,7 +7686,7 @@ class drawutilsgl {
|
|
|
7087
7686
|
* Draw a 1x1 dot with the specified (CSS-) color.
|
|
7088
7687
|
*
|
|
7089
7688
|
* @method dot
|
|
7090
|
-
* @param {
|
|
7689
|
+
* @param {XYCoords} p - The position to draw the dot at.
|
|
7091
7690
|
* @param {string} color - The CSS color to draw the dot with.
|
|
7092
7691
|
* @return {void}
|
|
7093
7692
|
* @instance
|
|
@@ -7100,7 +7699,7 @@ class drawutilsgl {
|
|
|
7100
7699
|
* Draw the given point with the specified (CSS-) color and radius 3.
|
|
7101
7700
|
*
|
|
7102
7701
|
* @method point
|
|
7103
|
-
* @param {
|
|
7702
|
+
* @param {XYCoords} p - The position to draw the point at.
|
|
7104
7703
|
* @param {string} color - The CSS color to draw the point with.
|
|
7105
7704
|
* @return {void}
|
|
7106
7705
|
* @instance
|
|
@@ -7115,7 +7714,7 @@ class drawutilsgl {
|
|
|
7115
7714
|
* Note that if the x- and y- scales are different the result will be an ellipse rather than a circle.
|
|
7116
7715
|
*
|
|
7117
7716
|
* @method circle
|
|
7118
|
-
* @param {
|
|
7717
|
+
* @param {XYCoords} center - The center of the circle.
|
|
7119
7718
|
* @param {number} radius - The radius of the circle.
|
|
7120
7719
|
* @param {string} color - The CSS color to draw the circle with.
|
|
7121
7720
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
@@ -7130,7 +7729,7 @@ class drawutilsgl {
|
|
|
7130
7729
|
* Draw a circular arc (section of a circle) with the given CSS color.
|
|
7131
7730
|
*
|
|
7132
7731
|
* @method circleArc
|
|
7133
|
-
* @param {
|
|
7732
|
+
* @param {XYCoords} center - The center of the circle.
|
|
7134
7733
|
* @param {number} radius - The radius of the circle.
|
|
7135
7734
|
* @param {number} startAngle - The angle to start at.
|
|
7136
7735
|
* @param {number} endAngle - The angle to end at.
|
|
@@ -7146,7 +7745,7 @@ class drawutilsgl {
|
|
|
7146
7745
|
* Draw an ellipse with the specified (CSS-) color and thw two radii.
|
|
7147
7746
|
*
|
|
7148
7747
|
* @method ellipse
|
|
7149
|
-
* @param {
|
|
7748
|
+
* @param {XYCoords} center - The center of the ellipse.
|
|
7150
7749
|
* @param {number} radiusX - The radius of the ellipse.
|
|
7151
7750
|
* @param {number} radiusY - The radius of the ellipse.
|
|
7152
7751
|
* @param {string} color - The CSS color to draw the ellipse with.
|
|
@@ -7166,7 +7765,7 @@ class drawutilsgl {
|
|
|
7166
7765
|
*
|
|
7167
7766
|
* @method square
|
|
7168
7767
|
* @param {XYCords} center - The center of the square.
|
|
7169
|
-
* @param {
|
|
7768
|
+
* @param {number} size - The size of the square.
|
|
7170
7769
|
* @param {string} color - The CSS color to draw the square with.
|
|
7171
7770
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
7172
7771
|
* @return {void}
|
|
@@ -7192,7 +7791,7 @@ class drawutilsgl {
|
|
|
7192
7791
|
* Draw a grid of horizontal and vertical lines with the given (CSS-) color.
|
|
7193
7792
|
*
|
|
7194
7793
|
* @method grid
|
|
7195
|
-
* @param {
|
|
7794
|
+
* @param {XYCoords} center - The center of the grid.
|
|
7196
7795
|
* @param {number} width - The total width of the grid (width/2 each to the left and to the right).
|
|
7197
7796
|
* @param {number} height - The total height of the grid (height/2 each to the top and to the bottom).
|
|
7198
7797
|
* @param {number} sizeX - The horizontal grid size.
|
|
@@ -7211,7 +7810,7 @@ class drawutilsgl {
|
|
|
7211
7810
|
* This works analogue to the grid() function
|
|
7212
7811
|
*
|
|
7213
7812
|
* @method raster
|
|
7214
|
-
* @param {
|
|
7813
|
+
* @param {XYCoords} center - The center of the raster.
|
|
7215
7814
|
* @param {number} width - The total width of the raster (width/2 each to the left and to the right).
|
|
7216
7815
|
* @param {number} height - The total height of the raster (height/2 each to the top and to the bottom).
|
|
7217
7816
|
* @param {number} sizeX - The horizontal raster size.
|
|
@@ -7232,8 +7831,8 @@ class drawutilsgl {
|
|
|
7232
7831
|
* as even shaped diamonds.
|
|
7233
7832
|
*
|
|
7234
7833
|
* @method diamondHandle
|
|
7235
|
-
* @param {
|
|
7236
|
-
* @param {
|
|
7834
|
+
* @param {XYCoords} center - The center of the diamond.
|
|
7835
|
+
* @param {number} size - The x/y-size of the diamond.
|
|
7237
7836
|
* @param {string} color - The CSS color to draw the diamond with.
|
|
7238
7837
|
* @return {void}
|
|
7239
7838
|
* @instance
|
|
@@ -7250,8 +7849,8 @@ class drawutilsgl {
|
|
|
7250
7849
|
* as even shaped squares.
|
|
7251
7850
|
*
|
|
7252
7851
|
* @method squareHandle
|
|
7253
|
-
* @param {
|
|
7254
|
-
* @param {
|
|
7852
|
+
* @param {XYCoords} center - The center of the square.
|
|
7853
|
+
* @param {number} size - The x/y-size of the square.
|
|
7255
7854
|
* @param {string} color - The CSS color to draw the square with.
|
|
7256
7855
|
* @return {void}
|
|
7257
7856
|
* @instance
|
|
@@ -7268,7 +7867,7 @@ class drawutilsgl {
|
|
|
7268
7867
|
* as even shaped circles.
|
|
7269
7868
|
*
|
|
7270
7869
|
* @method circleHandle
|
|
7271
|
-
* @param {
|
|
7870
|
+
* @param {XYCoords} center - The center of the circle.
|
|
7272
7871
|
* @param {number} radius - The radius of the circle.
|
|
7273
7872
|
* @param {string} color - The CSS color to draw the circle with.
|
|
7274
7873
|
* @return {void}
|
|
@@ -7364,7 +7963,7 @@ class drawutilsgl {
|
|
|
7364
7963
|
* Draw a polygon line (alternative function to the polygon).
|
|
7365
7964
|
*
|
|
7366
7965
|
* @method polyline
|
|
7367
|
-
* @param {
|
|
7966
|
+
* @param {XYCoords[]} vertices - The polygon vertices to draw.
|
|
7368
7967
|
* @param {boolan} isOpen - If true the polyline will not be closed at its end.
|
|
7369
7968
|
* @param {string} color - The CSS color to draw the polygon with.
|
|
7370
7969
|
* @param {number=} lineWidth - (optional) The line width to use; default is 1.
|
|
@@ -8961,7 +9560,8 @@ class PBImage {
|
|
|
8961
9560
|
* @author Ikaros Kappler
|
|
8962
9561
|
* @date 2021-11-16
|
|
8963
9562
|
* @modified 2022-02-02 Added the `destroy` method.
|
|
8964
|
-
* @
|
|
9563
|
+
* @modified 2023-09-25 Fixed a type error in the constructor. Nothing vital.
|
|
9564
|
+
* @version 1.1.1
|
|
8965
9565
|
**/
|
|
8966
9566
|
/**
|
|
8967
9567
|
* @classdesc A simple text element: position, fontSize, fontFamily, color, textAlign, lineHeight and rotation.
|
|
@@ -8992,14 +9592,14 @@ class PBText {
|
|
|
8992
9592
|
this.uid = UIDGenerator.next();
|
|
8993
9593
|
this.text = text;
|
|
8994
9594
|
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;
|
|
9595
|
+
this.color = options === null || options === void 0 ? void 0 : options.color;
|
|
9596
|
+
this.fontFamily = options === null || options === void 0 ? void 0 : options.fontFamily;
|
|
9597
|
+
this.fontSize = options === null || options === void 0 ? void 0 : options.fontSize;
|
|
9598
|
+
this.fontStyle = options === null || options === void 0 ? void 0 : options.fontStyle;
|
|
9599
|
+
this.fontWeight = options === null || options === void 0 ? void 0 : options.fontWeight;
|
|
9600
|
+
this.lineHeight = options === null || options === void 0 ? void 0 : options.lineHeight;
|
|
9601
|
+
this.textAlign = options === null || options === void 0 ? void 0 : options.textAlign;
|
|
9602
|
+
this.rotation = options === null || options === void 0 ? void 0 : options.rotation;
|
|
9003
9603
|
}
|
|
9004
9604
|
/**
|
|
9005
9605
|
* This function should invalidate any installed listeners and invalidate this object.
|
|
@@ -9719,7 +10319,7 @@ class VEllipse {
|
|
|
9719
10319
|
else {
|
|
9720
10320
|
let startTangent = this.tangentAt(curAngle);
|
|
9721
10321
|
let endTangent = this.tangentAt(nextAngle);
|
|
9722
|
-
// Find intersection
|
|
10322
|
+
// Find intersection (ignore that the result might be null in some extreme cases)
|
|
9723
10323
|
let intersection = startTangent.intersection(endTangent);
|
|
9724
10324
|
// What if intersection is undefined?
|
|
9725
10325
|
// --> This *can* not happen if segmentCount > 2 and height and width of the ellipse are not zero.
|
|
@@ -10159,7 +10759,8 @@ VEllipseSector.ellipseSectorUtils = {
|
|
|
10159
10759
|
* @modified 2023-02-10 Fixing an issue of the `style.position` setting when `fitToParent=true` from `absolute` to `static` (default).
|
|
10160
10760
|
* @modified 2023-02-10 Cleaning up most type errors in the main class (mostly null checks).
|
|
10161
10761
|
* @modified 2023-02-10 Adding `enableZoom` and `enablePan` (both default true) to have the option to disable these functions.
|
|
10162
|
-
* @
|
|
10762
|
+
* @modified 2023-09-29 Adding proper dicionary key and value types to the params of `PlotBoilerplate.utils.safeMergeByKeys` (was `object` before).
|
|
10763
|
+
* @version 1.17.3
|
|
10163
10764
|
*
|
|
10164
10765
|
* @file PlotBoilerplate
|
|
10165
10766
|
* @fileoverview The main class.
|
|
@@ -10277,7 +10878,7 @@ class PlotBoilerplate {
|
|
|
10277
10878
|
draggable: true,
|
|
10278
10879
|
visible: true
|
|
10279
10880
|
};
|
|
10280
|
-
if (typeof config.canvas
|
|
10881
|
+
if (typeof config.canvas === "undefined") {
|
|
10281
10882
|
throw "No canvas specified.";
|
|
10282
10883
|
}
|
|
10283
10884
|
/**
|
|
@@ -10369,6 +10970,10 @@ class PlotBoilerplate {
|
|
|
10369
10970
|
fill: true
|
|
10370
10971
|
}
|
|
10371
10972
|
},
|
|
10973
|
+
// bezierPath: {
|
|
10974
|
+
// color: "#0022a8",
|
|
10975
|
+
// lineWidth: 1
|
|
10976
|
+
// },
|
|
10372
10977
|
polygon: {
|
|
10373
10978
|
color: "#0022a8",
|
|
10374
10979
|
lineWidth: 1
|
|
@@ -10428,7 +11033,10 @@ class PlotBoilerplate {
|
|
|
10428
11033
|
// +-------------------------------
|
|
10429
11034
|
this.grid = new Grid(new Vertex(0, 0), new Vertex(50, 50));
|
|
10430
11035
|
this.canvasSize = { width: PlotBoilerplate.DEFAULT_CANVAS_WIDTH, height: PlotBoilerplate.DEFAULT_CANVAS_HEIGHT };
|
|
10431
|
-
const canvasElement = typeof config.canvas
|
|
11036
|
+
const canvasElement = typeof config.canvas === "string" ? document.querySelector(config.canvas) : config.canvas;
|
|
11037
|
+
if (typeof canvasElement === "undefined") {
|
|
11038
|
+
throw `Cannot initialize PlotBoilerplate with a null canvas (element "${config.canvas} not found).`;
|
|
11039
|
+
}
|
|
10432
11040
|
// Which renderer to use: Canvas2D, WebGL (experimental) or SVG?
|
|
10433
11041
|
if (canvasElement.tagName.toLowerCase() === "canvas") {
|
|
10434
11042
|
this.canvas = canvasElement;
|
|
@@ -11076,10 +11684,10 @@ class PlotBoilerplate {
|
|
|
11076
11684
|
if (this.drawConfig.drawBezierHandleLines && this.drawConfig.drawHandleLines) {
|
|
11077
11685
|
draw.setCurrentId(`${d.uid}_l0`);
|
|
11078
11686
|
draw.setCurrentClassName(`${d.className}-start-line`);
|
|
11079
|
-
draw.
|
|
11687
|
+
draw.handleLine(d.bezierCurves[c].startPoint, d.bezierCurves[c].startControlPoint);
|
|
11080
11688
|
draw.setCurrentId(`${d.uid}_l1`);
|
|
11081
11689
|
draw.setCurrentClassName(`${d.className}-end-line`);
|
|
11082
|
-
draw.
|
|
11690
|
+
draw.handleLine(d.bezierCurves[c].endPoint, d.bezierCurves[c].endControlPoint);
|
|
11083
11691
|
}
|
|
11084
11692
|
curveIndex++;
|
|
11085
11693
|
} // END for
|
|
@@ -11102,11 +11710,11 @@ class PlotBoilerplate {
|
|
|
11102
11710
|
draw.setCurrentId(`${d.uid}_e0`);
|
|
11103
11711
|
draw.setCurrentClassName(`${d.className}-v-line`);
|
|
11104
11712
|
// draw.line( d.center.clone().add(0,d.axis.y-d.center.y), d.axis, '#c8c8c8' );
|
|
11105
|
-
draw.
|
|
11713
|
+
draw.handleLine(d.center.clone().add(0, d.signedRadiusV()).rotate(d.rotation, d.center), d.axis); // , "#c8c8c8");
|
|
11106
11714
|
draw.setCurrentId(`${d.uid}_e1`);
|
|
11107
11715
|
draw.setCurrentClassName(`${d.className}-h-line`);
|
|
11108
11716
|
// draw.line( d.center.clone().add(d.axis.x-d.center.x,0), d.axis, '#c8c8c8' );
|
|
11109
|
-
draw.
|
|
11717
|
+
draw.handleLine(d.center.clone().add(d.signedRadiusH(), 0).rotate(d.rotation, d.center), d.axis); // , "#c8c8c8");
|
|
11110
11718
|
}
|
|
11111
11719
|
draw.setCurrentId(d.uid);
|
|
11112
11720
|
draw.setCurrentClassName(`${d.className}`);
|
|
@@ -12042,22 +12650,35 @@ PlotBoilerplate.utils = {
|
|
|
12042
12650
|
**/
|
|
12043
12651
|
safeMergeByKeys: (base, extension) => {
|
|
12044
12652
|
for (var k in extension) {
|
|
12045
|
-
if (!extension.hasOwnProperty(k))
|
|
12653
|
+
if (!extension.hasOwnProperty(k)) {
|
|
12046
12654
|
continue;
|
|
12655
|
+
}
|
|
12047
12656
|
if (base.hasOwnProperty(k)) {
|
|
12048
|
-
|
|
12657
|
+
const typ = typeof base[k];
|
|
12658
|
+
const extVal = extension[k];
|
|
12049
12659
|
try {
|
|
12050
|
-
if (typ == "boolean")
|
|
12051
|
-
|
|
12052
|
-
|
|
12053
|
-
|
|
12054
|
-
|
|
12660
|
+
if (typ == "boolean") {
|
|
12661
|
+
if (typeof extVal === "string")
|
|
12662
|
+
base[k] = Boolean(!!JSON.parse(extVal));
|
|
12663
|
+
else
|
|
12664
|
+
base[k] = extVal;
|
|
12665
|
+
}
|
|
12666
|
+
else if (typ == "number") {
|
|
12667
|
+
if (typeof extVal === "string")
|
|
12668
|
+
base[k] = Number(JSON.parse(extVal) * 1);
|
|
12669
|
+
else
|
|
12670
|
+
base[k] = extension[k];
|
|
12671
|
+
}
|
|
12672
|
+
else if (typ == "function" && typeof extVal == "function") {
|
|
12055
12673
|
base[k] = extension[k];
|
|
12056
|
-
|
|
12674
|
+
}
|
|
12675
|
+
else {
|
|
12676
|
+
// Probably a sting
|
|
12057
12677
|
base[k] = extension[k];
|
|
12678
|
+
}
|
|
12058
12679
|
}
|
|
12059
12680
|
catch (e) {
|
|
12060
|
-
console.error("error in key ", k,
|
|
12681
|
+
console.error("error in key ", k, extVal, e);
|
|
12061
12682
|
}
|
|
12062
12683
|
}
|
|
12063
12684
|
else {
|
|
@@ -12066,6 +12687,31 @@ PlotBoilerplate.utils = {
|
|
|
12066
12687
|
}
|
|
12067
12688
|
return base;
|
|
12068
12689
|
},
|
|
12690
|
+
/*
|
|
12691
|
+
__safeMergeByKeys: <KeyType extends string | number | symbol, ValueType extends boolean | number | string | Function>(
|
|
12692
|
+
base: Record<KeyType, ValueType>,
|
|
12693
|
+
extension: Record<KeyType, string>
|
|
12694
|
+
): Record<KeyType, ValueType> => {
|
|
12695
|
+
for (var k in extension) {
|
|
12696
|
+
if (!extension.hasOwnProperty(k)) continue;
|
|
12697
|
+
if (base.hasOwnProperty(k)) {
|
|
12698
|
+
var typ = typeof base[k];
|
|
12699
|
+
try {
|
|
12700
|
+
if (typ == "boolean") base[k] = !!JSON.parse(extension[k]);
|
|
12701
|
+
else if (typ == "number") base[k] = JSON.parse(extension[k]) * 1;
|
|
12702
|
+
else if (typ == "function" && typeof extension[k] == "function") base[k] = extension[k];
|
|
12703
|
+
else base[k] = extension[k];
|
|
12704
|
+
} catch (e) {
|
|
12705
|
+
console.error("error in key ", k, extension[k], e);
|
|
12706
|
+
}
|
|
12707
|
+
} else {
|
|
12708
|
+
base[k] = extension[k];
|
|
12709
|
+
}
|
|
12710
|
+
}
|
|
12711
|
+
return base;
|
|
12712
|
+
},
|
|
12713
|
+
*()
|
|
12714
|
+
|
|
12069
12715
|
/**
|
|
12070
12716
|
* A helper function to scale elements (usually the canvas) using CSS.
|
|
12071
12717
|
*
|