plotboilerplate 1.14.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/changelog.md +57 -0
- package/dist/index.esm.js +856 -694
- 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 +858 -598
- package/dist/plotboilerplate.min.js +1 -1
- package/package.json +1 -1
- package/src/cjs/BezierPath.d.ts +32 -14
- package/src/cjs/BezierPath.js +65 -24
- package/src/cjs/BezierPath.js.map +1 -1
- package/src/cjs/Bounds.d.ts +22 -1
- package/src/cjs/Bounds.js +24 -1
- package/src/cjs/Bounds.js.map +1 -1
- package/src/cjs/Circle.d.ts +15 -13
- package/src/cjs/Circle.js +16 -34
- package/src/cjs/Circle.js.map +1 -1
- package/src/cjs/CircleSector.d.ts +17 -16
- package/src/cjs/CircleSector.js +12 -24
- package/src/cjs/CircleSector.js.map +1 -1
- package/src/cjs/CubicBezierCurve.d.ts +16 -15
- package/src/cjs/CubicBezierCurve.js +57 -94
- package/src/cjs/CubicBezierCurve.js.map +1 -1
- package/src/cjs/KeyHandler.d.ts +10 -3
- package/src/cjs/KeyHandler.js +28 -23
- package/src/cjs/KeyHandler.js.map +1 -1
- package/src/cjs/Line.d.ts +2 -15
- package/src/cjs/Line.js +6 -31
- package/src/cjs/Line.js.map +1 -1
- package/src/cjs/MouseHandler.js +43 -53
- package/src/cjs/MouseHandler.js.map +1 -1
- package/src/cjs/PBImage.d.ts +15 -13
- package/src/cjs/PBImage.js +11 -15
- package/src/cjs/PBImage.js.map +1 -1
- package/src/cjs/PBText.d.ts +13 -12
- package/src/cjs/PBText.js +8 -12
- package/src/cjs/PBText.js.map +1 -1
- package/src/cjs/PlotBoilerplate.js +3 -2
- package/src/cjs/PlotBoilerplate.js.map +1 -1
- package/src/cjs/Polygon.d.ts +44 -14
- package/src/cjs/Polygon.js +116 -66
- package/src/cjs/Polygon.js.map +1 -1
- package/src/cjs/Triangle.d.ts +15 -13
- package/src/cjs/Triangle.js +23 -64
- package/src/cjs/Triangle.js.map +1 -1
- package/src/cjs/VEllipse.d.ts +14 -9
- package/src/cjs/VEllipse.js +10 -18
- package/src/cjs/VEllipse.js.map +1 -1
- package/src/cjs/VEllipseSector.d.ts +15 -1
- package/src/cjs/VEllipseSector.js +11 -1
- package/src/cjs/VEllipseSector.js.map +1 -1
- package/src/cjs/Vector.d.ts +3 -15
- package/src/cjs/Vector.js +9 -49
- package/src/cjs/Vector.js.map +1 -1
- package/src/cjs/VertTuple.d.ts +15 -1
- package/src/cjs/VertTuple.js +14 -19
- package/src/cjs/VertTuple.js.map +1 -1
- package/src/cjs/Vertex.d.ts +47 -13
- package/src/cjs/Vertex.js +62 -22
- package/src/cjs/Vertex.js.map +1 -1
- package/src/cjs/VertexListeners.d.ts +12 -8
- package/src/cjs/VertexListeners.js +18 -25
- package/src/cjs/VertexListeners.js.map +1 -1
- package/src/cjs/draw.d.ts +41 -2
- package/src/cjs/draw.js +140 -3
- package/src/cjs/draw.js.map +1 -1
- package/src/cjs/drawgl.d.ts +38 -2
- package/src/cjs/drawgl.js +41 -2
- package/src/cjs/drawgl.js.map +1 -1
- package/src/cjs/drawutilssvg.d.ts +66 -3
- package/src/cjs/drawutilssvg.js +140 -15
- package/src/cjs/drawutilssvg.js.map +1 -1
- package/src/cjs/index.d.ts +0 -1
- package/src/cjs/index.js +0 -1
- package/src/cjs/index.js.map +1 -1
- package/src/cjs/interfaces/DrawLib.d.ts +61 -26
- package/src/cjs/interfaces/DrawLib.js +2 -0
- package/src/cjs/interfaces/DrawLib.js.map +1 -1
- package/src/cjs/interfaces/core.d.ts +0 -12
- package/src/cjs/module.d.ts +1 -3
- package/src/cjs/module.js +2 -5
- package/src/cjs/module.js.map +1 -1
- package/src/cjs/utils/creategui.js +16 -2
- package/src/cjs/utils/datastructures/Girih.d.ts +5 -0
- package/src/cjs/utils/datastructures/Girih.js +18 -14
- package/src/cjs/utils/datastructures/Girih.js.map +1 -1
- package/src/cjs/utils/datastructures/GirihPenroseRhombus.js +42 -25
- package/src/cjs/utils/datastructures/GirihPenroseRhombus.js.map +1 -1
- package/src/cjs/utils/datastructures/GirihTile.js +2 -13
- package/src/cjs/utils/datastructures/GirihTile.js.map +1 -1
- package/src/cjs/utils/findInVertexArray.d.ts +19 -0
- package/src/cjs/utils/findInVertexArray.js +29 -0
- package/src/cjs/utils/findInVertexArray.js.map +1 -0
- package/src/cjs/utils/helpers/BezierPathInteractionHelper.d.ts +17 -1
- package/src/cjs/utils/helpers/BezierPathInteractionHelper.js +50 -32
- package/src/cjs/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
- package/src/cjs/utils/io/DndFileHandler.d.ts +63 -0
- package/src/cjs/utils/io/DndFileHandler.js +112 -0
- package/src/cjs/utils/io/DndFileHandler.js.map +1 -0
- package/src/cjs/utils/io/FileDrop.d.ts +98 -0
- package/src/cjs/utils/io/FileDrop.js +142 -0
- package/src/cjs/utils/io/FileDrop.js.map +1 -0
- package/src/esm/BezierPath.d.ts +32 -14
- package/src/esm/BezierPath.js +65 -24
- package/src/esm/BezierPath.js.map +1 -1
- package/src/esm/Bounds.d.ts +22 -1
- package/src/esm/Bounds.js +24 -1
- package/src/esm/Bounds.js.map +1 -1
- package/src/esm/Circle.d.ts +15 -13
- package/src/esm/Circle.js +16 -34
- package/src/esm/Circle.js.map +1 -1
- package/src/esm/CircleSector.d.ts +17 -16
- package/src/esm/CircleSector.js +12 -24
- package/src/esm/CircleSector.js.map +1 -1
- package/src/esm/CubicBezierCurve.d.ts +16 -15
- package/src/esm/CubicBezierCurve.js +57 -94
- package/src/esm/CubicBezierCurve.js.map +1 -1
- package/src/esm/KeyHandler.d.ts +10 -3
- package/src/esm/KeyHandler.js +28 -23
- package/src/esm/KeyHandler.js.map +1 -1
- package/src/esm/Line.d.ts +2 -15
- package/src/esm/Line.js +6 -31
- package/src/esm/Line.js.map +1 -1
- package/src/esm/MouseHandler.js +43 -53
- package/src/esm/MouseHandler.js.map +1 -1
- package/src/esm/PBImage.d.ts +15 -13
- package/src/esm/PBImage.js +11 -15
- package/src/esm/PBImage.js.map +1 -1
- package/src/esm/PBText.d.ts +13 -12
- package/src/esm/PBText.js +8 -12
- package/src/esm/PBText.js.map +1 -1
- package/src/esm/PlotBoilerplate.js +3 -2
- package/src/esm/PlotBoilerplate.js.map +1 -1
- package/src/esm/Polygon.d.ts +44 -14
- package/src/esm/Polygon.js +116 -66
- package/src/esm/Polygon.js.map +1 -1
- package/src/esm/Triangle.d.ts +15 -13
- package/src/esm/Triangle.js +23 -64
- package/src/esm/Triangle.js.map +1 -1
- package/src/esm/VEllipse.d.ts +14 -9
- package/src/esm/VEllipse.js +10 -18
- package/src/esm/VEllipse.js.map +1 -1
- package/src/esm/VEllipseSector.d.ts +15 -1
- package/src/esm/VEllipseSector.js +11 -1
- package/src/esm/VEllipseSector.js.map +1 -1
- package/src/esm/Vector.d.ts +3 -15
- package/src/esm/Vector.js +9 -49
- package/src/esm/Vector.js.map +1 -1
- package/src/esm/VertTuple.d.ts +15 -1
- package/src/esm/VertTuple.js +14 -19
- package/src/esm/VertTuple.js.map +1 -1
- package/src/esm/Vertex.d.ts +47 -13
- package/src/esm/Vertex.js +62 -22
- package/src/esm/Vertex.js.map +1 -1
- package/src/esm/VertexListeners.d.ts +12 -8
- package/src/esm/VertexListeners.js +18 -25
- package/src/esm/VertexListeners.js.map +1 -1
- package/src/esm/draw.d.ts +41 -2
- package/src/esm/draw.js +139 -3
- package/src/esm/draw.js.map +1 -1
- package/src/esm/drawgl.d.ts +38 -2
- package/src/esm/drawgl.js +41 -2
- package/src/esm/drawgl.js.map +1 -1
- package/src/esm/drawutilssvg.d.ts +66 -3
- package/src/esm/drawutilssvg.js +140 -15
- package/src/esm/drawutilssvg.js.map +1 -1
- package/src/esm/index.d.ts +0 -1
- package/src/esm/index.js +0 -1
- package/src/esm/index.js.map +1 -1
- package/src/esm/interfaces/DrawLib.d.ts +61 -26
- package/src/esm/interfaces/DrawLib.js +2 -0
- package/src/esm/interfaces/DrawLib.js.map +1 -1
- package/src/esm/interfaces/core.d.ts +0 -12
- package/src/esm/module.d.ts +1 -3
- package/src/esm/module.js +5 -4
- package/src/esm/module.js.map +1 -1
- package/src/esm/utils/datastructures/Girih.d.ts +5 -0
- package/src/esm/utils/datastructures/Girih.js +18 -14
- package/src/esm/utils/datastructures/Girih.js.map +1 -1
- package/src/esm/utils/datastructures/GirihPenroseRhombus.js +42 -25
- package/src/esm/utils/datastructures/GirihPenroseRhombus.js.map +1 -1
- package/src/esm/utils/datastructures/GirihTile.js +2 -13
- package/src/esm/utils/datastructures/GirihTile.js.map +1 -1
- package/src/esm/utils/findInVertexArray.d.ts +19 -0
- package/src/esm/utils/findInVertexArray.js +25 -0
- package/src/esm/utils/findInVertexArray.js.map +1 -0
- package/src/esm/utils/helpers/BezierPathInteractionHelper.d.ts +17 -1
- package/src/esm/utils/helpers/BezierPathInteractionHelper.js +49 -32
- package/src/esm/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
- package/src/esm/utils/io/DndFileHandler.d.ts +63 -0
- package/src/esm/utils/io/DndFileHandler.js +106 -0
- package/src/esm/utils/io/DndFileHandler.js.map +1 -0
- package/src/esm/utils/io/FileDrop.d.ts +98 -0
- package/src/esm/utils/io/FileDrop.js +136 -0
- package/src/esm/utils/io/FileDrop.js.map +1 -0
- package/src/ts/BezierPath.ts +78 -22
- package/src/ts/Bounds.ts +25 -1
- package/src/ts/Circle.ts +187 -200
- package/src/ts/CircleSector.ts +141 -141
- package/src/ts/CubicBezierCurve.ts +738 -810
- package/src/ts/KeyHandler.ts +221 -212
- package/src/ts/Line.ts +48 -80
- package/src/ts/MouseHandler.ts +356 -368
- package/src/ts/PBImage.ts +67 -69
- package/src/ts/PBText.ts +16 -14
- package/src/ts/PlotBoilerplate.ts +4 -2
- package/src/ts/Polygon.ts +493 -451
- package/src/ts/Triangle.ts +444 -489
- package/src/ts/VEllipse.ts +18 -17
- package/src/ts/VEllipseSector.ts +20 -1
- package/src/ts/Vector.ts +124 -160
- package/src/ts/VertTuple.ts +333 -338
- package/src/ts/Vertex.ts +75 -21
- package/src/ts/VertexListeners.ts +248 -266
- package/src/ts/draw.ts +192 -3
- package/src/ts/drawgl.ts +44 -2
- package/src/ts/drawutilssvg.ts +181 -15
- package/src/ts/index.ts +0 -1
- package/src/ts/interfaces/DrawLib.ts +69 -26
- package/src/ts/interfaces/core.ts +0 -11
- package/src/ts/module.ts +2 -4
- package/src/ts/utils/datastructures/Girih.ts +204 -209
- package/src/ts/utils/datastructures/GirihPenroseRhombus.ts +170 -152
- package/src/ts/utils/datastructures/GirihTile.ts +394 -419
- package/src/ts/utils/findInVertexArray.ts +28 -0
- package/src/ts/utils/helpers/BezierPathInteractionHelper.ts +56 -34
- package/src/ts/utils/io/FileDrop.ts +178 -0
- package/src/ts/SVGBuilder.ts +0 -109
- package/src/ts/utils/algorithms/sh-tmp.ts~ +0 -59
package/dist/index.esm.js
CHANGED
|
@@ -99,7 +99,6 @@ class VertexListeners {
|
|
|
99
99
|
this.dragEnd = [];
|
|
100
100
|
this.vertex = vertex;
|
|
101
101
|
}
|
|
102
|
-
;
|
|
103
102
|
/**
|
|
104
103
|
* Add a click listener.
|
|
105
104
|
*
|
|
@@ -113,7 +112,6 @@ class VertexListeners {
|
|
|
113
112
|
VertexListeners._addListener(this.click, listener);
|
|
114
113
|
return this;
|
|
115
114
|
}
|
|
116
|
-
;
|
|
117
115
|
/**
|
|
118
116
|
* The click listener is a function with a single drag event param.
|
|
119
117
|
* @callback VertexListeners~clickListener
|
|
@@ -132,7 +130,6 @@ class VertexListeners {
|
|
|
132
130
|
this.click = VertexListeners._removeListener(this.click, listener);
|
|
133
131
|
return this;
|
|
134
132
|
}
|
|
135
|
-
;
|
|
136
133
|
/**
|
|
137
134
|
* The click listener is a function with a single drag event param.
|
|
138
135
|
* @callback VertexListeners~clickListener
|
|
@@ -151,7 +148,6 @@ class VertexListeners {
|
|
|
151
148
|
VertexListeners._addListener(this.drag, listener);
|
|
152
149
|
return this;
|
|
153
150
|
}
|
|
154
|
-
;
|
|
155
151
|
/**
|
|
156
152
|
* The drag listener is a function with a single drag event param.
|
|
157
153
|
* @callback VertexListeners~dragListener
|
|
@@ -170,7 +166,6 @@ class VertexListeners {
|
|
|
170
166
|
this.drag = VertexListeners._removeListener(this.drag, listener);
|
|
171
167
|
return this;
|
|
172
168
|
}
|
|
173
|
-
;
|
|
174
169
|
/**
|
|
175
170
|
* Add a dragStart listener.
|
|
176
171
|
*
|
|
@@ -184,7 +179,6 @@ class VertexListeners {
|
|
|
184
179
|
VertexListeners._addListener(this.dragStart, listener);
|
|
185
180
|
return this;
|
|
186
181
|
}
|
|
187
|
-
;
|
|
188
182
|
/**
|
|
189
183
|
* The drag-start listener is a function with a single drag event param.
|
|
190
184
|
* @callback VertexListeners~dragStartListener
|
|
@@ -203,7 +197,6 @@ class VertexListeners {
|
|
|
203
197
|
this.dragStart = VertexListeners._removeListener(this.dragStart, listener);
|
|
204
198
|
return this;
|
|
205
199
|
}
|
|
206
|
-
;
|
|
207
200
|
/**
|
|
208
201
|
* Add a dragEnd listener.
|
|
209
202
|
*
|
|
@@ -218,27 +211,25 @@ class VertexListeners {
|
|
|
218
211
|
VertexListeners._addListener(this.dragEnd, listener);
|
|
219
212
|
return this;
|
|
220
213
|
}
|
|
221
|
-
;
|
|
222
214
|
/**
|
|
223
215
|
* The drag-end listener is a function with a single drag event param.
|
|
224
216
|
* @callback VertexListeners~dragEndListener
|
|
225
217
|
* @param {Event} e - The (extended) drag event.
|
|
226
218
|
*/
|
|
227
219
|
/**
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
220
|
+
* Remove a drag listener.
|
|
221
|
+
*
|
|
222
|
+
* @method removeDragEndListener
|
|
223
|
+
* @param {VertexListeners~clickListener} listener - The drag listener to remove (a callback).
|
|
224
|
+
* @return {VertexListeners} this (for chaining)
|
|
225
|
+
* @instance
|
|
226
|
+
* @memberof VertexListeners
|
|
227
|
+
**/
|
|
236
228
|
removeDragEndListener(listener) {
|
|
237
229
|
// this.drag.push( listener );
|
|
238
230
|
this.dragEnd = VertexListeners._removeListener(this.dragEnd, listener);
|
|
239
231
|
return this;
|
|
240
232
|
}
|
|
241
|
-
;
|
|
242
233
|
/**
|
|
243
234
|
* Fire a click event with the given event instance to all
|
|
244
235
|
* installed click listeners.
|
|
@@ -252,7 +243,6 @@ class VertexListeners {
|
|
|
252
243
|
fireClickEvent(e) {
|
|
253
244
|
VertexListeners._fireEvent(this, this.click, e);
|
|
254
245
|
}
|
|
255
|
-
;
|
|
256
246
|
/**
|
|
257
247
|
* Fire a drag event with the given event instance to all
|
|
258
248
|
* installed drag listeners.
|
|
@@ -266,7 +256,6 @@ class VertexListeners {
|
|
|
266
256
|
fireDragEvent(e) {
|
|
267
257
|
VertexListeners._fireEvent(this, this.drag, e);
|
|
268
258
|
}
|
|
269
|
-
;
|
|
270
259
|
/**
|
|
271
260
|
* Fire a dragStart event with the given event instance to all
|
|
272
261
|
* installed drag-start listeners.
|
|
@@ -280,7 +269,6 @@ class VertexListeners {
|
|
|
280
269
|
fireDragStartEvent(e) {
|
|
281
270
|
VertexListeners._fireEvent(this, this.dragStart, e);
|
|
282
271
|
}
|
|
283
|
-
;
|
|
284
272
|
/**
|
|
285
273
|
* Fire a dragEnd event with the given event instance to all
|
|
286
274
|
* installed drag-end listeners.
|
|
@@ -294,13 +282,21 @@ class VertexListeners {
|
|
|
294
282
|
fireDragEndEvent(e) {
|
|
295
283
|
VertexListeners._fireEvent(this, this.dragEnd, e);
|
|
296
284
|
}
|
|
297
|
-
|
|
285
|
+
/**
|
|
286
|
+
* Removes all listeners from this listeners object.
|
|
287
|
+
*/
|
|
288
|
+
removeAllListeners() {
|
|
289
|
+
this.click = [];
|
|
290
|
+
this.drag = [];
|
|
291
|
+
this.dragStart = [];
|
|
292
|
+
this.dragEnd = [];
|
|
293
|
+
}
|
|
298
294
|
/**
|
|
299
295
|
* @private
|
|
300
296
|
**/
|
|
301
297
|
static _fireEvent(_self, listeners, e) {
|
|
302
298
|
const ve = e;
|
|
303
|
-
if (typeof ve.params ==
|
|
299
|
+
if (typeof ve.params == "undefined")
|
|
304
300
|
ve.params = { vertex: _self.vertex };
|
|
305
301
|
else
|
|
306
302
|
ve.params.vertex = _self.vertex;
|
|
@@ -308,7 +304,6 @@ class VertexListeners {
|
|
|
308
304
|
listeners[i](ve);
|
|
309
305
|
}
|
|
310
306
|
}
|
|
311
|
-
;
|
|
312
307
|
/**
|
|
313
308
|
* @private
|
|
314
309
|
*/
|
|
@@ -320,7 +315,6 @@ class VertexListeners {
|
|
|
320
315
|
listeners.push(newListener);
|
|
321
316
|
return true;
|
|
322
317
|
}
|
|
323
|
-
;
|
|
324
318
|
/**
|
|
325
319
|
* @private
|
|
326
320
|
*/
|
|
@@ -331,7 +325,6 @@ class VertexListeners {
|
|
|
331
325
|
}
|
|
332
326
|
return listeners;
|
|
333
327
|
}
|
|
334
|
-
;
|
|
335
328
|
}
|
|
336
329
|
|
|
337
330
|
/**
|
|
@@ -360,7 +353,11 @@ class VertexListeners {
|
|
|
360
353
|
* @modified 2021-03-01 Changed the second param `center` in the `rotate` function from Vertex to XYCoords.
|
|
361
354
|
* @modified 2021-12-01 Changed the type of param of `scale` to XYCoords.
|
|
362
355
|
* @modified 2021-12-01 Added function `scaleXY` for non uniform scaling.
|
|
363
|
-
* @
|
|
356
|
+
* @modified 2021-12-17 Added the functions `lerp` and `lerpAbs` for linear interpolations.
|
|
357
|
+
* @modified 2022-01-31 Added `Vertex.utils.arrayToJSON`.
|
|
358
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
359
|
+
* @modified 2022-02-02 Cleared the `Vertex.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
360
|
+
* @version 2.7.0
|
|
364
361
|
*
|
|
365
362
|
* @file Vertex
|
|
366
363
|
* @public
|
|
@@ -713,6 +710,43 @@ class Vertex {
|
|
|
713
710
|
scale(factor, center) {
|
|
714
711
|
return this.scaleXY({ x: factor, y: factor }, center);
|
|
715
712
|
}
|
|
713
|
+
/**
|
|
714
|
+
* Perform a linear interpolation towards the given target vertex.
|
|
715
|
+
* The amount value `t` is relative, `t=0.0` means no change, `t=1.0`
|
|
716
|
+
* means this point will be moved to the exact target position.
|
|
717
|
+
*
|
|
718
|
+
* `t=0.5` will move this point to the middle of the connecting
|
|
719
|
+
* linear segment.
|
|
720
|
+
*
|
|
721
|
+
* @param {XYCoords} target - The target position to lerp this vertex to.
|
|
722
|
+
* @param {number} t - The relative amount, usually in [0..1], but other values will work, too.
|
|
723
|
+
* @returns
|
|
724
|
+
*/
|
|
725
|
+
lerp(target, t) {
|
|
726
|
+
var diff = this.difference(target);
|
|
727
|
+
// return new Vertex(this.x + diff.x * t, this.y + diff.y * t);
|
|
728
|
+
this.x += diff.x * t;
|
|
729
|
+
this.y += diff.y * t;
|
|
730
|
+
return this;
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* Perform a linear interpolation towards the given target vertex (absolute variant).
|
|
734
|
+
* The amount value `t` is absolute, which means the lerp amount is a direct distance
|
|
735
|
+
* value. This point will have move the amount of the passed distance `u`.
|
|
736
|
+
*
|
|
737
|
+
* @param {XYCoords} target - The target position to lerp this vertex to.
|
|
738
|
+
* @param {number} t - The absolute move amount to use to lerping.
|
|
739
|
+
* @returns
|
|
740
|
+
*/
|
|
741
|
+
lerpAbs(target, u) {
|
|
742
|
+
var dist = this.distance(target);
|
|
743
|
+
var diff = this.difference(target);
|
|
744
|
+
var step = { x: diff.x / dist, y: diff.y / dist };
|
|
745
|
+
// return new Vertex(this.x + step.x * u, this.y + step.y * u);
|
|
746
|
+
this.x += step.x * u;
|
|
747
|
+
this.y += step.y * u;
|
|
748
|
+
return this;
|
|
749
|
+
}
|
|
716
750
|
/**
|
|
717
751
|
* This is a vector-like behavior and 'scales' this vertex
|
|
718
752
|
* towards/from a given center by two independent x- and y- scale factors.
|
|
@@ -810,28 +844,14 @@ class Vertex {
|
|
|
810
844
|
return "(" + this.x + "," + this.y + ")";
|
|
811
845
|
}
|
|
812
846
|
/**
|
|
813
|
-
*
|
|
814
|
-
*
|
|
815
|
-
*
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
* @memberof Vertex
|
|
821
|
-
**/
|
|
822
|
-
toSVGString(options) {
|
|
823
|
-
options = options || {};
|
|
824
|
-
var buffer = [];
|
|
825
|
-
buffer.push("<circle");
|
|
826
|
-
if (options.className)
|
|
827
|
-
buffer.push(' class="' + options.className + '"');
|
|
828
|
-
buffer.push(' cx="' + this.x + '"');
|
|
829
|
-
buffer.push(' cy="' + this.y + '"');
|
|
830
|
-
buffer.push(' r="2"');
|
|
831
|
-
buffer.push(" />");
|
|
832
|
-
return buffer.join("");
|
|
847
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
848
|
+
* After calling this function the object might not hold valid data any more and
|
|
849
|
+
* should not be used.
|
|
850
|
+
*/
|
|
851
|
+
destroy() {
|
|
852
|
+
this.listeners.removeAllListeners();
|
|
853
|
+
this.isDestroyed = true;
|
|
833
854
|
}
|
|
834
|
-
// END Vertex
|
|
835
855
|
/**
|
|
836
856
|
* Create a new random vertex inside the given viewport.
|
|
837
857
|
*
|
|
@@ -886,6 +906,19 @@ Vertex.utils = {
|
|
|
886
906
|
vertices.push(new Vertex(zB.x * scaleX, zB.y * scaleY));
|
|
887
907
|
vertices.push(new Vertex(zB.x * scaleX - headlen * 1.35 * Math.cos(angle + Math.PI / 8), zB.y * scaleY - headlen * 1.35 * Math.sin(angle + Math.PI / 8)));
|
|
888
908
|
return vertices;
|
|
909
|
+
},
|
|
910
|
+
/**
|
|
911
|
+
* Convert the given vertices (array) to a JSON string.
|
|
912
|
+
*
|
|
913
|
+
* @param {number?} precision - (optional) The numeric precision to be used (number of precision digits).
|
|
914
|
+
* @returns {string}
|
|
915
|
+
*/
|
|
916
|
+
arrayToJSON(vertices, precision) {
|
|
917
|
+
return JSON.stringify(vertices.map(function (vert) {
|
|
918
|
+
return typeof precision === undefined
|
|
919
|
+
? { x: vert.x, y: vert.y }
|
|
920
|
+
: { x: Number(vert.x.toFixed(precision)), y: Number(vert.y.toFixed(precision)) };
|
|
921
|
+
}));
|
|
889
922
|
}
|
|
890
923
|
};
|
|
891
924
|
|
|
@@ -910,7 +943,12 @@ Vertex.utils = {
|
|
|
910
943
|
* @modified 2021-01-29 Added the `isClockwise` function.
|
|
911
944
|
* @modified 2021-01-29 Added the `area` function.
|
|
912
945
|
* @modified 2021-01-29 Changed the param type for `containsVert` from Vertex to XYCoords.
|
|
913
|
-
* @
|
|
946
|
+
* @modified 2021-12-14 Added the `perimeter()` function.
|
|
947
|
+
* @modified 2021-12-16 Added the `getEvenDistributionPolygon()` function.
|
|
948
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
949
|
+
* @modified 2022-02-02 Cleared the `Polygon.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
950
|
+
* @modified 2022-03-08 Added the `Polygon.clone()` function.
|
|
951
|
+
* @version 1.10.0
|
|
914
952
|
*
|
|
915
953
|
* @file Polygon
|
|
916
954
|
* @public
|
|
@@ -941,12 +979,11 @@ class Polygon {
|
|
|
941
979
|
**/
|
|
942
980
|
this.className = "Polygon";
|
|
943
981
|
this.uid = UIDGenerator.next();
|
|
944
|
-
if (typeof vertices ==
|
|
982
|
+
if (typeof vertices == "undefined")
|
|
945
983
|
vertices = [];
|
|
946
984
|
this.vertices = vertices;
|
|
947
985
|
this.isOpen = isOpen;
|
|
948
986
|
}
|
|
949
|
-
;
|
|
950
987
|
/**
|
|
951
988
|
* Add a vertex to the end of the `vertices` array.
|
|
952
989
|
*
|
|
@@ -958,7 +995,6 @@ class Polygon {
|
|
|
958
995
|
addVertex(vert) {
|
|
959
996
|
this.vertices.push(vert);
|
|
960
997
|
}
|
|
961
|
-
;
|
|
962
998
|
/**
|
|
963
999
|
* Get the polygon vertex at the given position (index).
|
|
964
1000
|
*
|
|
@@ -981,7 +1017,6 @@ class Polygon {
|
|
|
981
1017
|
else
|
|
982
1018
|
return this.vertices[index % this.vertices.length];
|
|
983
1019
|
}
|
|
984
|
-
;
|
|
985
1020
|
/**
|
|
986
1021
|
* Move the polygon's vertices by the given amount.
|
|
987
1022
|
*
|
|
@@ -991,13 +1026,12 @@ class Polygon {
|
|
|
991
1026
|
* @memberof Polygon
|
|
992
1027
|
* @return {Polygon} this for chaining
|
|
993
1028
|
**/
|
|
994
|
-
move(
|
|
1029
|
+
move(amount) {
|
|
995
1030
|
for (var i in this.vertices) {
|
|
996
|
-
this.vertices[i].add(
|
|
1031
|
+
this.vertices[i].add(amount);
|
|
997
1032
|
}
|
|
998
1033
|
return this;
|
|
999
1034
|
}
|
|
1000
|
-
;
|
|
1001
1035
|
/**
|
|
1002
1036
|
* Check if the given vertex is inside this polygon.<br>
|
|
1003
1037
|
* <br>
|
|
@@ -1017,14 +1051,12 @@ class Polygon {
|
|
|
1017
1051
|
for (var i = 0, j = this.vertices.length - 1; i < this.vertices.length; j = i++) {
|
|
1018
1052
|
let xi = this.vertices[i].x, yi = this.vertices[i].y;
|
|
1019
1053
|
let xj = this.vertices[j].x, yj = this.vertices[j].y;
|
|
1020
|
-
var intersect =
|
|
1021
|
-
&& (vert.x < (xj - xi) * (vert.y - yi) / (yj - yi) + xi);
|
|
1054
|
+
var intersect = yi > vert.y != yj > vert.y && vert.x < ((xj - xi) * (vert.y - yi)) / (yj - yi) + xi;
|
|
1022
1055
|
if (intersect)
|
|
1023
1056
|
inside = !inside;
|
|
1024
1057
|
}
|
|
1025
1058
|
return inside;
|
|
1026
1059
|
}
|
|
1027
|
-
;
|
|
1028
1060
|
/**
|
|
1029
1061
|
* Calculate the area of the given polygon (unsigned).
|
|
1030
1062
|
*
|
|
@@ -1038,7 +1070,6 @@ class Polygon {
|
|
|
1038
1070
|
area() {
|
|
1039
1071
|
return Polygon.utils.area(this.vertices);
|
|
1040
1072
|
}
|
|
1041
|
-
;
|
|
1042
1073
|
/**
|
|
1043
1074
|
* Calulate the signed polyon area by interpreting the polygon as a matrix
|
|
1044
1075
|
* and calculating its determinant.
|
|
@@ -1051,7 +1082,6 @@ class Polygon {
|
|
|
1051
1082
|
signedArea() {
|
|
1052
1083
|
return Polygon.utils.signedArea(this.vertices);
|
|
1053
1084
|
}
|
|
1054
|
-
;
|
|
1055
1085
|
/**
|
|
1056
1086
|
* Get the winding order of this polgon: clockwise or counterclockwise.
|
|
1057
1087
|
*
|
|
@@ -1063,7 +1093,28 @@ class Polygon {
|
|
|
1063
1093
|
isClockwise() {
|
|
1064
1094
|
return Polygon.utils.signedArea(this.vertices) < 0;
|
|
1065
1095
|
}
|
|
1066
|
-
|
|
1096
|
+
/**
|
|
1097
|
+
* Get the perimeter of this polygon.
|
|
1098
|
+
* The perimeter is the absolute length of the outline.
|
|
1099
|
+
*
|
|
1100
|
+
* If this polygon is open then the last segment (connecting the first and the
|
|
1101
|
+
* last vertex) will be skipped.
|
|
1102
|
+
*
|
|
1103
|
+
* @method perimeter
|
|
1104
|
+
* @instance
|
|
1105
|
+
* @memberof Polygon
|
|
1106
|
+
* @return {number}
|
|
1107
|
+
*/
|
|
1108
|
+
perimeter() {
|
|
1109
|
+
let length = 0;
|
|
1110
|
+
for (var i = 1; i < this.vertices.length; i++) {
|
|
1111
|
+
length += this.vertices[i - 1].distance(this.vertices[i]);
|
|
1112
|
+
}
|
|
1113
|
+
if (!this.isOpen && this.vertices.length > 1) {
|
|
1114
|
+
length += this.vertices[0].distance(this.vertices[this.vertices.length - 1]);
|
|
1115
|
+
}
|
|
1116
|
+
return length;
|
|
1117
|
+
}
|
|
1067
1118
|
/**
|
|
1068
1119
|
* Scale the polygon relative to the given center.
|
|
1069
1120
|
*
|
|
@@ -1076,14 +1127,13 @@ class Polygon {
|
|
|
1076
1127
|
**/
|
|
1077
1128
|
scale(factor, center) {
|
|
1078
1129
|
for (var i in this.vertices) {
|
|
1079
|
-
if (typeof this.vertices[i].scale ==
|
|
1130
|
+
if (typeof this.vertices[i].scale == "function")
|
|
1080
1131
|
this.vertices[i].scale(factor, center);
|
|
1081
1132
|
else
|
|
1082
|
-
console.log(
|
|
1133
|
+
console.log("There seems to be a null vertex!", this.vertices[i]);
|
|
1083
1134
|
}
|
|
1084
1135
|
return this;
|
|
1085
1136
|
}
|
|
1086
|
-
;
|
|
1087
1137
|
/**
|
|
1088
1138
|
* Rotate the polygon around the given center.
|
|
1089
1139
|
*
|
|
@@ -1100,7 +1150,52 @@ class Polygon {
|
|
|
1100
1150
|
}
|
|
1101
1151
|
return this;
|
|
1102
1152
|
}
|
|
1103
|
-
|
|
1153
|
+
/**
|
|
1154
|
+
* Convert this polygon into a new polygon with n evenly distributed vertices.
|
|
1155
|
+
*
|
|
1156
|
+
* @param {number} pointCount - Must not be negative.
|
|
1157
|
+
*/
|
|
1158
|
+
getEvenDistributionPolygon(pointCount) {
|
|
1159
|
+
if (pointCount <= 0) {
|
|
1160
|
+
throw new Error("pointCount must be larger than zero; is " + pointCount + ".");
|
|
1161
|
+
}
|
|
1162
|
+
const result = new Polygon([], this.isOpen);
|
|
1163
|
+
if (this.vertices.length === 0) {
|
|
1164
|
+
return result;
|
|
1165
|
+
}
|
|
1166
|
+
// Fetch and add the start point from the source polygon
|
|
1167
|
+
let polygonPoint = new Vertex(this.vertices[0]);
|
|
1168
|
+
result.vertices.push(polygonPoint);
|
|
1169
|
+
if (this.vertices.length === 1) {
|
|
1170
|
+
return result;
|
|
1171
|
+
}
|
|
1172
|
+
const perimeter = this.perimeter();
|
|
1173
|
+
const stepSize = perimeter / pointCount;
|
|
1174
|
+
const n = this.vertices.length;
|
|
1175
|
+
let polygonIndex = 1;
|
|
1176
|
+
let nextPolygonPoint = new Vertex(this.vertices[1]);
|
|
1177
|
+
let segmentLength = polygonPoint.distance(nextPolygonPoint);
|
|
1178
|
+
let loopMax = this.isOpen ? n : n + 1;
|
|
1179
|
+
let curSegmentU = stepSize;
|
|
1180
|
+
var i = 1;
|
|
1181
|
+
while (i < pointCount && polygonIndex < loopMax) {
|
|
1182
|
+
// Check if next eq point is inside this segment
|
|
1183
|
+
if (curSegmentU < segmentLength) {
|
|
1184
|
+
let newPoint = polygonPoint.clone().lerpAbs(nextPolygonPoint, curSegmentU);
|
|
1185
|
+
result.vertices.push(newPoint);
|
|
1186
|
+
curSegmentU += stepSize;
|
|
1187
|
+
i++;
|
|
1188
|
+
}
|
|
1189
|
+
else {
|
|
1190
|
+
polygonIndex++;
|
|
1191
|
+
polygonPoint = nextPolygonPoint;
|
|
1192
|
+
nextPolygonPoint = new Vertex(this.vertices[polygonIndex % n]);
|
|
1193
|
+
curSegmentU = curSegmentU - segmentLength;
|
|
1194
|
+
segmentLength = polygonPoint.distance(nextPolygonPoint);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
return result;
|
|
1198
|
+
}
|
|
1104
1199
|
/**
|
|
1105
1200
|
* Get the bounding box (bounds) of this polygon.
|
|
1106
1201
|
*
|
|
@@ -1112,7 +1207,14 @@ class Polygon {
|
|
|
1112
1207
|
getBounds() {
|
|
1113
1208
|
return Bounds.computeFromVertices(this.vertices);
|
|
1114
1209
|
}
|
|
1115
|
-
|
|
1210
|
+
/**
|
|
1211
|
+
* Create a deep copy of this polygon.
|
|
1212
|
+
*
|
|
1213
|
+
* @return {Polygon} The cloned polygon.
|
|
1214
|
+
*/
|
|
1215
|
+
clone() {
|
|
1216
|
+
return new Polygon(this.vertices.map(vert => vert.clone()), this.isOpen);
|
|
1217
|
+
}
|
|
1116
1218
|
/**
|
|
1117
1219
|
* Convert this polygon to a sequence of quadratic Bézier curves.<br>
|
|
1118
1220
|
* <br>
|
|
@@ -1144,7 +1246,6 @@ class Polygon {
|
|
|
1144
1246
|
}
|
|
1145
1247
|
return qbezier;
|
|
1146
1248
|
}
|
|
1147
|
-
;
|
|
1148
1249
|
/**
|
|
1149
1250
|
* Convert this polygon to a quadratic bezier curve, represented as an SVG data string.
|
|
1150
1251
|
*
|
|
@@ -1157,13 +1258,12 @@ class Polygon {
|
|
|
1157
1258
|
var qdata = this.toQuadraticBezierData();
|
|
1158
1259
|
if (qdata.length == 0)
|
|
1159
1260
|
return "";
|
|
1160
|
-
var buffer = [
|
|
1261
|
+
var buffer = ["M " + qdata[0].x + " " + qdata[0].y];
|
|
1161
1262
|
for (var i = 1; i < qdata.length; i += 2) {
|
|
1162
|
-
buffer.push(
|
|
1263
|
+
buffer.push("Q " + qdata[i].x + " " + qdata[i].y + ", " + qdata[i + 1].x + " " + qdata[i + 1].y);
|
|
1163
1264
|
}
|
|
1164
|
-
return buffer.join(
|
|
1265
|
+
return buffer.join(" ");
|
|
1165
1266
|
}
|
|
1166
|
-
;
|
|
1167
1267
|
/**
|
|
1168
1268
|
* Convert this polygon to a sequence of cubic Bézier curves.<br>
|
|
1169
1269
|
* <br>
|
|
@@ -1180,7 +1280,7 @@ class Polygon {
|
|
|
1180
1280
|
* @memberof Polygon
|
|
1181
1281
|
**/
|
|
1182
1282
|
toCubicBezierData(threshold) {
|
|
1183
|
-
if (typeof threshold ==
|
|
1283
|
+
if (typeof threshold == "undefined")
|
|
1184
1284
|
threshold = 1.0;
|
|
1185
1285
|
if (this.vertices.length < 3)
|
|
1186
1286
|
return [];
|
|
@@ -1204,7 +1304,6 @@ class Polygon {
|
|
|
1204
1304
|
}
|
|
1205
1305
|
return cbezier;
|
|
1206
1306
|
}
|
|
1207
|
-
;
|
|
1208
1307
|
/**
|
|
1209
1308
|
* Convert this polygon to a cubic bezier curve, represented as an SVG data string.
|
|
1210
1309
|
*
|
|
@@ -1217,13 +1316,23 @@ class Polygon {
|
|
|
1217
1316
|
var qdata = this.toCubicBezierData(threshold);
|
|
1218
1317
|
if (qdata.length == 0)
|
|
1219
1318
|
return "";
|
|
1220
|
-
var buffer = [
|
|
1319
|
+
var buffer = ["M " + qdata[0].x + " " + qdata[0].y];
|
|
1221
1320
|
for (var i = 1; i < qdata.length; i += 3) {
|
|
1222
|
-
buffer.push(
|
|
1223
|
-
|
|
1224
|
-
|
|
1321
|
+
buffer.push("C " +
|
|
1322
|
+
qdata[i].x +
|
|
1323
|
+
" " +
|
|
1324
|
+
qdata[i].y +
|
|
1325
|
+
", " +
|
|
1326
|
+
qdata[i + 1].x +
|
|
1327
|
+
" " +
|
|
1328
|
+
qdata[i + 1].y +
|
|
1329
|
+
", " +
|
|
1330
|
+
qdata[i + 2].x +
|
|
1331
|
+
" " +
|
|
1332
|
+
qdata[i + 2].y);
|
|
1333
|
+
}
|
|
1334
|
+
return buffer.join(" ");
|
|
1225
1335
|
}
|
|
1226
|
-
;
|
|
1227
1336
|
/**
|
|
1228
1337
|
* Convert this polygon to a cubic bezier path instance.
|
|
1229
1338
|
*
|
|
@@ -1242,43 +1351,17 @@ class Polygon {
|
|
|
1242
1351
|
}
|
|
1243
1352
|
return BezierPath.fromArray(pathdata);
|
|
1244
1353
|
}
|
|
1245
|
-
;
|
|
1246
1354
|
/**
|
|
1247
|
-
*
|
|
1248
|
-
*
|
|
1249
|
-
*
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
* @memberof Polygon
|
|
1255
|
-
**/
|
|
1256
|
-
toSVGString(options) {
|
|
1257
|
-
options = options || {};
|
|
1258
|
-
var buffer = [];
|
|
1259
|
-
buffer.push('<path');
|
|
1260
|
-
if (options.className)
|
|
1261
|
-
buffer.push(' class="' + options.className + '"');
|
|
1262
|
-
buffer.push(' d="');
|
|
1263
|
-
if (this.vertices.length > 0) {
|
|
1264
|
-
buffer.push('M ');
|
|
1265
|
-
buffer.push(this.vertices[0].x.toString());
|
|
1266
|
-
buffer.push(' ');
|
|
1267
|
-
buffer.push(this.vertices[0].y.toString());
|
|
1268
|
-
for (var i = 1; i < this.vertices.length; i++) {
|
|
1269
|
-
buffer.push(' L ');
|
|
1270
|
-
buffer.push(this.vertices[i].x.toString());
|
|
1271
|
-
buffer.push(' ');
|
|
1272
|
-
buffer.push(this.vertices[i].y.toString());
|
|
1273
|
-
}
|
|
1274
|
-
if (!this.isOpen) {
|
|
1275
|
-
buffer.push(' Z');
|
|
1276
|
-
}
|
|
1355
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
1356
|
+
* After calling this function the object might not hold valid data any more and
|
|
1357
|
+
* should not be used.
|
|
1358
|
+
*/
|
|
1359
|
+
destroy() {
|
|
1360
|
+
for (var i = 0; i < this.vertices.length; i++) {
|
|
1361
|
+
this.vertices[i].destroy();
|
|
1277
1362
|
}
|
|
1278
|
-
|
|
1279
|
-
return buffer.join('');
|
|
1363
|
+
this.isDestroyed = true;
|
|
1280
1364
|
}
|
|
1281
|
-
;
|
|
1282
1365
|
}
|
|
1283
1366
|
Polygon.utils = {
|
|
1284
1367
|
/**
|
|
@@ -1298,8 +1381,8 @@ Polygon.utils = {
|
|
|
1298
1381
|
const addY = vertices[(i + 1) % l].y;
|
|
1299
1382
|
const subX = vertices[(i + 1) % l].x;
|
|
1300
1383
|
const subY = vertices[i].y;
|
|
1301
|
-
total +=
|
|
1302
|
-
total -=
|
|
1384
|
+
total += addX * addY * 0.5;
|
|
1385
|
+
total -= subX * subY * 0.5;
|
|
1303
1386
|
}
|
|
1304
1387
|
return Math.abs(total);
|
|
1305
1388
|
},
|
|
@@ -1328,7 +1411,8 @@ Polygon.utils = {
|
|
|
1328
1411
|
* @modified 2020-11-19 Set min, max, width and height to private.
|
|
1329
1412
|
* @modified 2021-02-02 Added the `toPolygon` method.
|
|
1330
1413
|
* @modified 2021-06-21 (mid-summer) Added `getCenter` method.
|
|
1331
|
-
* @
|
|
1414
|
+
* @modified 2022-02-01 Added the `toString` function.
|
|
1415
|
+
* @version 1.4.0
|
|
1332
1416
|
**/
|
|
1333
1417
|
/**
|
|
1334
1418
|
* @classdesc A bounds class with min and max values. Implementing IBounds.
|
|
@@ -1363,9 +1447,31 @@ class Bounds {
|
|
|
1363
1447
|
toPolygon() {
|
|
1364
1448
|
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);
|
|
1365
1449
|
}
|
|
1450
|
+
/**
|
|
1451
|
+
* Get the center of this boinding box.
|
|
1452
|
+
*
|
|
1453
|
+
* @method getCenter
|
|
1454
|
+
* @instance
|
|
1455
|
+
* @memberof Bounds
|
|
1456
|
+
* @returns {Vertex} The center of these bounds.
|
|
1457
|
+
*/
|
|
1366
1458
|
getCenter() {
|
|
1367
1459
|
return new Vertex(this.min.x + (this.max.x - this.min.x) / 2.0, this.min.y + (this.max.y - this.min.y) / 2);
|
|
1368
1460
|
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Convert these bounds to a human readable form.
|
|
1463
|
+
*
|
|
1464
|
+
* Note: the returned format might change in the future, so please do not
|
|
1465
|
+
* rely on the returned string format.
|
|
1466
|
+
*
|
|
1467
|
+
* @method toString
|
|
1468
|
+
* @instance
|
|
1469
|
+
* @memberof Bounds
|
|
1470
|
+
* @returns {string} Get these bounds in a human readable form.
|
|
1471
|
+
*/
|
|
1472
|
+
toString() {
|
|
1473
|
+
return `{ min: ${this.min.toString()}, max : ${this.max.toString()}, width: ${this.width}, height : ${this.height} }`;
|
|
1474
|
+
}
|
|
1369
1475
|
/**
|
|
1370
1476
|
* Compute the minimal bounding box for a given set of vertices.
|
|
1371
1477
|
*
|
|
@@ -1406,7 +1512,8 @@ class Bounds {
|
|
|
1406
1512
|
* @modified 2020-12-04 Changed `getClosestT` param from `Vertex` to `XYCoords` (generalized).
|
|
1407
1513
|
* @modified 2020-12-04 Added the `hasPoint(XYCoords)` function.
|
|
1408
1514
|
* @modified 2021-01-20 Added UID.
|
|
1409
|
-
* @
|
|
1515
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
1516
|
+
* @version 1.2.0
|
|
1410
1517
|
*/
|
|
1411
1518
|
/**
|
|
1412
1519
|
* @classdesc An abstract base classes for vertex tuple constructs, like Lines or Vectors.
|
|
@@ -1440,7 +1547,6 @@ class VertTuple {
|
|
|
1440
1547
|
length() {
|
|
1441
1548
|
return Math.sqrt(Math.pow(this.b.x - this.a.x, 2) + Math.pow(this.b.y - this.a.y, 2));
|
|
1442
1549
|
}
|
|
1443
|
-
;
|
|
1444
1550
|
/**
|
|
1445
1551
|
* Set the length of this vector to the given amount. This only works if this
|
|
1446
1552
|
* vector is not a null vector.
|
|
@@ -1453,7 +1559,6 @@ class VertTuple {
|
|
|
1453
1559
|
setLength(length) {
|
|
1454
1560
|
return this.scale(length / this.length());
|
|
1455
1561
|
}
|
|
1456
|
-
;
|
|
1457
1562
|
/**
|
|
1458
1563
|
* Substract the given vertex from this line's end points.
|
|
1459
1564
|
*
|
|
@@ -1468,7 +1573,6 @@ class VertTuple {
|
|
|
1468
1573
|
this.b.sub(amount);
|
|
1469
1574
|
return this;
|
|
1470
1575
|
}
|
|
1471
|
-
;
|
|
1472
1576
|
/**
|
|
1473
1577
|
* Add the given vertex to this line's end points.
|
|
1474
1578
|
*
|
|
@@ -1483,7 +1587,6 @@ class VertTuple {
|
|
|
1483
1587
|
this.b.add(amount);
|
|
1484
1588
|
return this;
|
|
1485
1589
|
}
|
|
1486
|
-
;
|
|
1487
1590
|
/**
|
|
1488
1591
|
* Normalize this line (set to length 1).
|
|
1489
1592
|
*
|
|
@@ -1496,7 +1599,6 @@ class VertTuple {
|
|
|
1496
1599
|
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());
|
|
1497
1600
|
return this;
|
|
1498
1601
|
}
|
|
1499
|
-
;
|
|
1500
1602
|
/**
|
|
1501
1603
|
* Scale this line by the given factor.
|
|
1502
1604
|
*
|
|
@@ -1510,7 +1612,6 @@ class VertTuple {
|
|
|
1510
1612
|
this.b.set(this.a.x + (this.b.x - this.a.x) * factor, this.a.y + (this.b.y - this.a.y) * factor);
|
|
1511
1613
|
return this;
|
|
1512
1614
|
}
|
|
1513
|
-
;
|
|
1514
1615
|
/**
|
|
1515
1616
|
* Move this line to a new location.
|
|
1516
1617
|
*
|
|
@@ -1526,7 +1627,6 @@ class VertTuple {
|
|
|
1526
1627
|
this.b.add(diff);
|
|
1527
1628
|
return this;
|
|
1528
1629
|
}
|
|
1529
|
-
;
|
|
1530
1630
|
/**
|
|
1531
1631
|
* Get the angle between this and the passed line (in radians).
|
|
1532
1632
|
*
|
|
@@ -1537,7 +1637,7 @@ class VertTuple {
|
|
|
1537
1637
|
* @memberof VertTuple
|
|
1538
1638
|
**/
|
|
1539
1639
|
angle(line) {
|
|
1540
|
-
if (line == null || typeof line ==
|
|
1640
|
+
if (line == null || typeof line == "undefined") {
|
|
1541
1641
|
line = this.factory(new Vertex(0, 0), new Vertex(100, 0));
|
|
1542
1642
|
}
|
|
1543
1643
|
// Compute the angle from x axis and the return the difference :)
|
|
@@ -1547,7 +1647,6 @@ class VertTuple {
|
|
|
1547
1647
|
// The result might be negative, but isn't it usually nicer to determine angles in positive values only?
|
|
1548
1648
|
return Math.atan2(v1.x, v1.y) - Math.atan2(v0.x, v0.y);
|
|
1549
1649
|
}
|
|
1550
|
-
;
|
|
1551
1650
|
/**
|
|
1552
1651
|
* Get line point at position t in [0 ... 1]:<br>
|
|
1553
1652
|
* <pre>[P(0)]=[A]--------------------[P(t)]------[B]=[P(1)]</pre><br>
|
|
@@ -1563,7 +1662,6 @@ class VertTuple {
|
|
|
1563
1662
|
vertAt(t) {
|
|
1564
1663
|
return new Vertex(this.a.x + (this.b.x - this.a.x) * t, this.a.y + (this.b.y - this.a.y) * t);
|
|
1565
1664
|
}
|
|
1566
|
-
;
|
|
1567
1665
|
/**
|
|
1568
1666
|
* Get the denominator of this and the given line.
|
|
1569
1667
|
*
|
|
@@ -1577,9 +1675,8 @@ class VertTuple {
|
|
|
1577
1675
|
**/
|
|
1578
1676
|
denominator(line) {
|
|
1579
1677
|
// http://jsfiddle.net/justin_c_rounds/Gd2S2/
|
|
1580
|
-
return (
|
|
1678
|
+
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);
|
|
1581
1679
|
}
|
|
1582
|
-
;
|
|
1583
1680
|
/**
|
|
1584
1681
|
* Checks if this and the given line are co-linear.
|
|
1585
1682
|
*
|
|
@@ -1594,7 +1691,6 @@ class VertTuple {
|
|
|
1594
1691
|
colinear(line) {
|
|
1595
1692
|
return Math.abs(this.denominator(line)) < Vertex.EPSILON;
|
|
1596
1693
|
}
|
|
1597
|
-
;
|
|
1598
1694
|
/**
|
|
1599
1695
|
* Get the closest position T from this line to the specified point.
|
|
1600
1696
|
*
|
|
@@ -1617,7 +1713,6 @@ class VertTuple {
|
|
|
1617
1713
|
// t = Math.max(0, Math.min(1, t));
|
|
1618
1714
|
return t;
|
|
1619
1715
|
}
|
|
1620
|
-
;
|
|
1621
1716
|
/**
|
|
1622
1717
|
* Check if the given point is located on this line. Optionally also check if
|
|
1623
1718
|
* that point is located between point `a` and `b`.
|
|
@@ -1653,7 +1748,6 @@ class VertTuple {
|
|
|
1653
1748
|
var t = this.getClosestT(p);
|
|
1654
1749
|
return this.vertAt(t);
|
|
1655
1750
|
}
|
|
1656
|
-
;
|
|
1657
1751
|
/**
|
|
1658
1752
|
* The the minimal distance between this line and the specified point.
|
|
1659
1753
|
*
|
|
@@ -1668,7 +1762,6 @@ class VertTuple {
|
|
|
1668
1762
|
// https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
|
|
1669
1763
|
return Math.sqrt(VertTuple.vtutils.dist2(p, this.vertAt(this.getClosestT(p))));
|
|
1670
1764
|
}
|
|
1671
|
-
;
|
|
1672
1765
|
/**
|
|
1673
1766
|
* Create a deep clone of this instance.
|
|
1674
1767
|
*
|
|
@@ -1680,7 +1773,6 @@ class VertTuple {
|
|
|
1680
1773
|
clone() {
|
|
1681
1774
|
return this.factory(this.a.clone(), this.b.clone());
|
|
1682
1775
|
}
|
|
1683
|
-
;
|
|
1684
1776
|
/**
|
|
1685
1777
|
* Create a string representation of this line.
|
|
1686
1778
|
*
|
|
@@ -1692,7 +1784,16 @@ class VertTuple {
|
|
|
1692
1784
|
toString() {
|
|
1693
1785
|
return "{ a : " + this.a.toString() + ", b : " + this.b.toString() + " }";
|
|
1694
1786
|
}
|
|
1695
|
-
|
|
1787
|
+
/**
|
|
1788
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
1789
|
+
* After calling this function the object might not hold valid data any more and
|
|
1790
|
+
* should not be used.
|
|
1791
|
+
*/
|
|
1792
|
+
destroy() {
|
|
1793
|
+
this.a.destroy();
|
|
1794
|
+
this.b.destroy();
|
|
1795
|
+
this.isDestroyed = true;
|
|
1796
|
+
}
|
|
1696
1797
|
}
|
|
1697
1798
|
/**
|
|
1698
1799
|
* @private
|
|
@@ -1714,7 +1815,9 @@ VertTuple.vtutils = {
|
|
|
1714
1815
|
* @modified 2019-12-04 Added the Vector.inv() function.
|
|
1715
1816
|
* @modified 2020-03-23 Ported to Typescript from JS.
|
|
1716
1817
|
* @modified 2021-01-20 Added UID.
|
|
1717
|
-
* @
|
|
1818
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
1819
|
+
* @modified 2022-02-02 Cleared the `Vector.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
1820
|
+
* @version 1.4.0
|
|
1718
1821
|
*
|
|
1719
1822
|
* @file Vector
|
|
1720
1823
|
* @public
|
|
@@ -1745,7 +1848,6 @@ class Vector extends VertTuple {
|
|
|
1745
1848
|
**/
|
|
1746
1849
|
this.className = "Vector";
|
|
1747
1850
|
}
|
|
1748
|
-
;
|
|
1749
1851
|
/**
|
|
1750
1852
|
* Get the perpendicular of this vector which is located at a.
|
|
1751
1853
|
*
|
|
@@ -1760,7 +1862,6 @@ class Vector extends VertTuple {
|
|
|
1760
1862
|
v.b.add(this.a);
|
|
1761
1863
|
return v;
|
|
1762
1864
|
}
|
|
1763
|
-
;
|
|
1764
1865
|
/**
|
|
1765
1866
|
* The inverse of a vector is a vector witht the same magnitude but oppose direction.
|
|
1766
1867
|
*
|
|
@@ -1774,7 +1875,6 @@ class Vector extends VertTuple {
|
|
|
1774
1875
|
this.b = tmp;
|
|
1775
1876
|
return this;
|
|
1776
1877
|
}
|
|
1777
|
-
;
|
|
1778
1878
|
/**
|
|
1779
1879
|
* This function computes the inverse of the vector, which means 'a' stays untouched.
|
|
1780
1880
|
*
|
|
@@ -1785,7 +1885,6 @@ class Vector extends VertTuple {
|
|
|
1785
1885
|
this.b.y = this.a.y - (this.b.y - this.a.y);
|
|
1786
1886
|
return this;
|
|
1787
1887
|
}
|
|
1788
|
-
;
|
|
1789
1888
|
/**
|
|
1790
1889
|
* Get the intersection if this vector and the specified vector.
|
|
1791
1890
|
*
|
|
@@ -1801,53 +1900,15 @@ class Vector extends VertTuple {
|
|
|
1801
1900
|
return null;
|
|
1802
1901
|
var a = this.a.y - line.a.y;
|
|
1803
1902
|
var b = this.a.x - line.a.x;
|
|
1804
|
-
var numerator1 = (
|
|
1805
|
-
var numerator2 = (
|
|
1903
|
+
var numerator1 = (line.b.x - line.a.x) * a - (line.b.y - line.a.y) * b;
|
|
1904
|
+
var numerator2 = (this.b.x - this.a.x) * a - (this.b.y - this.a.y) * b;
|
|
1806
1905
|
a = numerator1 / denominator; // NaN if parallel lines
|
|
1807
1906
|
b = numerator2 / denominator;
|
|
1808
1907
|
// TODO:
|
|
1809
1908
|
// FOR A VECTOR THE LINE-INTERSECTION MUST BE ON BOTH VECTORS
|
|
1810
1909
|
// if we cast these lines infinitely in both directions, they intersect here:
|
|
1811
|
-
return new Vertex(this.a.x +
|
|
1910
|
+
return new Vertex(this.a.x + a * (this.b.x - this.a.x), this.a.y + a * (this.b.y - this.a.y));
|
|
1812
1911
|
}
|
|
1813
|
-
;
|
|
1814
|
-
/**
|
|
1815
|
-
* Create an SVG representation of this line.
|
|
1816
|
-
*
|
|
1817
|
-
* @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
|
|
1818
|
-
* @method toSVGString
|
|
1819
|
-
* @override
|
|
1820
|
-
* @param {object=} options - A set of options, like 'className'.
|
|
1821
|
-
* @return {string} The SVG string representation.
|
|
1822
|
-
* @instance
|
|
1823
|
-
* @memberof Vector
|
|
1824
|
-
**/
|
|
1825
|
-
toSVGString(options) {
|
|
1826
|
-
options = options || {};
|
|
1827
|
-
var buffer = [];
|
|
1828
|
-
var vertices = Vector.utils.buildArrowHead(this.a, this.b, 8, 1.0, 1.0);
|
|
1829
|
-
buffer.push('<g');
|
|
1830
|
-
if (options.className)
|
|
1831
|
-
buffer.push(' class="' + options.className + '"');
|
|
1832
|
-
buffer.push('>');
|
|
1833
|
-
buffer.push(' <line');
|
|
1834
|
-
buffer.push(' x1="' + this.a.x + '"');
|
|
1835
|
-
buffer.push(' y1="' + this.a.y + '"');
|
|
1836
|
-
buffer.push(' x2="' + vertices[0].x + '"');
|
|
1837
|
-
buffer.push(' y2="' + vertices[0].y + '"');
|
|
1838
|
-
buffer.push(' />');
|
|
1839
|
-
// Add arrow head
|
|
1840
|
-
buffer.push(' <polygon points="');
|
|
1841
|
-
for (var i = 0; i < vertices.length; i++) {
|
|
1842
|
-
if (i > 0)
|
|
1843
|
-
buffer.push(' ');
|
|
1844
|
-
buffer.push('' + vertices[i].x + ',' + vertices[i].y);
|
|
1845
|
-
}
|
|
1846
|
-
buffer.push('"/>');
|
|
1847
|
-
buffer.push('</g>');
|
|
1848
|
-
return buffer.join('');
|
|
1849
|
-
}
|
|
1850
|
-
;
|
|
1851
1912
|
}
|
|
1852
1913
|
Vector.utils = {
|
|
1853
1914
|
/**
|
|
@@ -1878,10 +1939,10 @@ Vector.utils = {
|
|
|
1878
1939
|
buildArrowHead: (zA, zB, headlen, scaleX, scaleY) => {
|
|
1879
1940
|
var angle = Math.atan2((zB.y - zA.y) * scaleY, (zB.x - zA.x) * scaleX);
|
|
1880
1941
|
var vertices = [];
|
|
1881
|
-
vertices.push(new Vertex(zB.x * scaleX -
|
|
1882
|
-
vertices.push(new Vertex(zB.x * scaleX -
|
|
1942
|
+
vertices.push(new Vertex(zB.x * scaleX - headlen * Math.cos(angle), zB.y * scaleY - headlen * Math.sin(angle)));
|
|
1943
|
+
vertices.push(new Vertex(zB.x * scaleX - headlen * 1.35 * Math.cos(angle - Math.PI / 8), zB.y * scaleY - headlen * 1.35 * Math.sin(angle - Math.PI / 8)));
|
|
1883
1944
|
vertices.push(new Vertex(zB.x * scaleX, zB.y * scaleY));
|
|
1884
|
-
vertices.push(new Vertex(zB.x * scaleX -
|
|
1945
|
+
vertices.push(new Vertex(zB.x * scaleX - headlen * 1.35 * Math.cos(angle + Math.PI / 8), zB.y * scaleY - headlen * 1.35 * Math.sin(angle + Math.PI / 8)));
|
|
1885
1946
|
return vertices;
|
|
1886
1947
|
}
|
|
1887
1948
|
};
|
|
@@ -1906,7 +1967,9 @@ Vector.utils = {
|
|
|
1906
1967
|
* @modified 2020-07-14 Changed the moveCurvePoint(...,Vertex) to moveCurvePoint(...,XYCoords), which is more generic.
|
|
1907
1968
|
* @modified 2020-07-24 Added the getClosestT function and the helper function locateIntervalByDistance(...).
|
|
1908
1969
|
* @modified 2021-01-20 Added UID.
|
|
1909
|
-
* @
|
|
1970
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
1971
|
+
* @modified 2022-02-02 Cleared the `toSVGPathData` function (deprecated). Use `drawutilssvg` instead.
|
|
1972
|
+
* @version 2.6.0
|
|
1910
1973
|
*
|
|
1911
1974
|
* @file CubicBezierCurve
|
|
1912
1975
|
* @public
|
|
@@ -1955,7 +2018,6 @@ class CubicBezierCurve {
|
|
|
1955
2018
|
this.arcLength = null;
|
|
1956
2019
|
this.updateArcLengths();
|
|
1957
2020
|
}
|
|
1958
|
-
;
|
|
1959
2021
|
/**
|
|
1960
2022
|
* Move the given curve point (the start point, end point or one of the two
|
|
1961
2023
|
* control points).
|
|
@@ -1992,7 +2054,6 @@ class CubicBezierCurve {
|
|
|
1992
2054
|
if (updateArcLengths)
|
|
1993
2055
|
this.updateArcLengths();
|
|
1994
2056
|
}
|
|
1995
|
-
;
|
|
1996
2057
|
/**
|
|
1997
2058
|
* Translate the whole curve by the given {x,y} amount: moves all four points.
|
|
1998
2059
|
*
|
|
@@ -2009,7 +2070,6 @@ class CubicBezierCurve {
|
|
|
2009
2070
|
this.endPoint.add(amount);
|
|
2010
2071
|
return this;
|
|
2011
2072
|
}
|
|
2012
|
-
;
|
|
2013
2073
|
/**
|
|
2014
2074
|
* Reverse this curve, means swapping start- and end-point and swapping
|
|
2015
2075
|
* start-control- and end-control-point.
|
|
@@ -2028,7 +2088,6 @@ class CubicBezierCurve {
|
|
|
2028
2088
|
this.endControlPoint = tmp;
|
|
2029
2089
|
return this;
|
|
2030
2090
|
}
|
|
2031
|
-
;
|
|
2032
2091
|
/**
|
|
2033
2092
|
* Get the total curve length.<br>
|
|
2034
2093
|
* <br>
|
|
@@ -2047,7 +2106,6 @@ class CubicBezierCurve {
|
|
|
2047
2106
|
getLength() {
|
|
2048
2107
|
return this.arcLength;
|
|
2049
2108
|
}
|
|
2050
|
-
;
|
|
2051
2109
|
/**
|
|
2052
2110
|
* Uptate the internal arc segment buffer and their lengths.<br>
|
|
2053
2111
|
* <br>
|
|
@@ -2085,7 +2143,6 @@ class CubicBezierCurve {
|
|
|
2085
2143
|
}
|
|
2086
2144
|
this.arcLength = newLength;
|
|
2087
2145
|
}
|
|
2088
|
-
;
|
|
2089
2146
|
/**
|
|
2090
2147
|
* Get a 't' (relative position on curve) with the closest distance to point 'p'.
|
|
2091
2148
|
*
|
|
@@ -2108,7 +2165,6 @@ class CubicBezierCurve {
|
|
|
2108
2165
|
} while (iteration < 4 && this.getPointAt(result.tPrev).distance(this.getPointAt(result.tNext)) > desiredEpsilon);
|
|
2109
2166
|
return result.t;
|
|
2110
2167
|
}
|
|
2111
|
-
;
|
|
2112
2168
|
/**
|
|
2113
2169
|
* This helper function locates the 't' on a fixed step interval with the minimal distance
|
|
2114
2170
|
* between the curve (at 't') and the given point.
|
|
@@ -2137,12 +2193,12 @@ class CubicBezierCurve {
|
|
|
2137
2193
|
minDist = dist;
|
|
2138
2194
|
}
|
|
2139
2195
|
}
|
|
2140
|
-
return {
|
|
2196
|
+
return {
|
|
2197
|
+
t: tStart + tDiff * (minIndex / stepCount),
|
|
2141
2198
|
tPrev: tStart + tDiff * (Math.max(0, minIndex - 1) / stepCount),
|
|
2142
2199
|
tNext: tStart + tDiff * (Math.min(stepCount, minIndex + 1) / stepCount)
|
|
2143
2200
|
};
|
|
2144
2201
|
}
|
|
2145
|
-
;
|
|
2146
2202
|
/**
|
|
2147
2203
|
* Get the bounds of this bezier curve.
|
|
2148
2204
|
*
|
|
@@ -2164,7 +2220,6 @@ class CubicBezierCurve {
|
|
|
2164
2220
|
}
|
|
2165
2221
|
return new Bounds(min, max);
|
|
2166
2222
|
}
|
|
2167
|
-
;
|
|
2168
2223
|
/**
|
|
2169
2224
|
* Get the start point of the curve.<br>
|
|
2170
2225
|
* <br>
|
|
@@ -2178,7 +2233,6 @@ class CubicBezierCurve {
|
|
|
2178
2233
|
getStartPoint() {
|
|
2179
2234
|
return this.startPoint;
|
|
2180
2235
|
}
|
|
2181
|
-
;
|
|
2182
2236
|
/**
|
|
2183
2237
|
* Get the end point of the curve.<br>
|
|
2184
2238
|
* <br>
|
|
@@ -2192,7 +2246,6 @@ class CubicBezierCurve {
|
|
|
2192
2246
|
getEndPoint() {
|
|
2193
2247
|
return this.endPoint;
|
|
2194
2248
|
}
|
|
2195
|
-
;
|
|
2196
2249
|
/**
|
|
2197
2250
|
* Get the start control point of the curve.<br>
|
|
2198
2251
|
* <br>
|
|
@@ -2206,7 +2259,6 @@ class CubicBezierCurve {
|
|
|
2206
2259
|
getStartControlPoint() {
|
|
2207
2260
|
return this.startControlPoint;
|
|
2208
2261
|
}
|
|
2209
|
-
;
|
|
2210
2262
|
/**
|
|
2211
2263
|
* Get the end control point of the curve.<br>
|
|
2212
2264
|
* <br>
|
|
@@ -2220,7 +2272,6 @@ class CubicBezierCurve {
|
|
|
2220
2272
|
getEndControlPoint() {
|
|
2221
2273
|
return this.endControlPoint;
|
|
2222
2274
|
}
|
|
2223
|
-
;
|
|
2224
2275
|
/**
|
|
2225
2276
|
* Get one of the four curve points specified by the passt point ID.
|
|
2226
2277
|
*
|
|
@@ -2241,7 +2292,6 @@ class CubicBezierCurve {
|
|
|
2241
2292
|
return this.endControlPoint;
|
|
2242
2293
|
throw new Error(`Invalid point ID '${id}'.`);
|
|
2243
2294
|
}
|
|
2244
|
-
;
|
|
2245
2295
|
/**
|
|
2246
2296
|
* Get the curve point at a given position t, where t is in [0,1].<br>
|
|
2247
2297
|
* <br>
|
|
@@ -2256,13 +2306,16 @@ class CubicBezierCurve {
|
|
|
2256
2306
|
**/
|
|
2257
2307
|
getPointAt(t) {
|
|
2258
2308
|
// Perform some powerful math magic
|
|
2259
|
-
const x = this.startPoint.x * Math.pow(1.0 - t, 3) +
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2309
|
+
const x = this.startPoint.x * Math.pow(1.0 - t, 3) +
|
|
2310
|
+
this.startControlPoint.x * 3 * t * Math.pow(1.0 - t, 2) +
|
|
2311
|
+
this.endControlPoint.x * 3 * Math.pow(t, 2) * (1.0 - t) +
|
|
2312
|
+
this.endPoint.x * Math.pow(t, 3);
|
|
2313
|
+
const y = this.startPoint.y * Math.pow(1.0 - t, 3) +
|
|
2314
|
+
this.startControlPoint.y * 3 * t * Math.pow(1.0 - t, 2) +
|
|
2315
|
+
this.endControlPoint.y * 3 * Math.pow(t, 2) * (1.0 - t) +
|
|
2316
|
+
this.endPoint.y * Math.pow(t, 3);
|
|
2263
2317
|
return new Vertex(x, y);
|
|
2264
2318
|
}
|
|
2265
|
-
;
|
|
2266
2319
|
/**
|
|
2267
2320
|
* Get the curve point at a given position u, where u is in [0,arcLength].<br>
|
|
2268
2321
|
* <br>
|
|
@@ -2278,7 +2331,6 @@ class CubicBezierCurve {
|
|
|
2278
2331
|
getPoint(u) {
|
|
2279
2332
|
return this.getPointAt(u / this.arcLength);
|
|
2280
2333
|
}
|
|
2281
|
-
;
|
|
2282
2334
|
/**
|
|
2283
2335
|
* Get the curve tangent vector at a given absolute curve position t in [0,1].<br>
|
|
2284
2336
|
* <br>
|
|
@@ -2299,18 +2351,11 @@ class CubicBezierCurve {
|
|
|
2299
2351
|
const t2 = t * t;
|
|
2300
2352
|
// (1 - t)^2 = (1-t)*(1-t) = 1 - t - t + t^2 = 1 - 2*t + t^2
|
|
2301
2353
|
const nt2 = 1 - 2 * t + t2;
|
|
2302
|
-
const tX = -3 * a.x * nt2 +
|
|
2303
|
-
|
|
2304
|
-
c.x * (6 * (t - t2) - 3 * t2) +
|
|
2305
|
-
3 * d.x * t2;
|
|
2306
|
-
const tY = -3 * a.y * nt2 +
|
|
2307
|
-
b.y * (3 * nt2 - 6 * (t - t2)) +
|
|
2308
|
-
c.y * (6 * (t - t2) - 3 * t2) +
|
|
2309
|
-
3 * d.y * t2;
|
|
2354
|
+
const tX = -3 * a.x * nt2 + b.x * (3 * nt2 - 6 * (t - t2)) + c.x * (6 * (t - t2) - 3 * t2) + 3 * d.x * t2;
|
|
2355
|
+
const tY = -3 * a.y * nt2 + b.y * (3 * nt2 - 6 * (t - t2)) + c.y * (6 * (t - t2) - 3 * t2) + 3 * d.y * t2;
|
|
2310
2356
|
// Note: my implementation does NOT normalize tangent vectors!
|
|
2311
2357
|
return new Vertex(tX, tY);
|
|
2312
2358
|
}
|
|
2313
|
-
;
|
|
2314
2359
|
/**
|
|
2315
2360
|
* Get a sub curve at the given start end end offsets (values between 0.0 and 1.0).
|
|
2316
2361
|
*
|
|
@@ -2336,7 +2381,6 @@ class CubicBezierCurve {
|
|
|
2336
2381
|
// pb.draw.cubicBezier( startVec.a, endVec.a, startVec.b, endVec.b, '#8800ff', 2 );
|
|
2337
2382
|
return new CubicBezierCurve(startVec.a, endVec.a, startVec.b, endVec.b);
|
|
2338
2383
|
}
|
|
2339
|
-
;
|
|
2340
2384
|
/**
|
|
2341
2385
|
* Convert a relative curve position u to the absolute curve position t.
|
|
2342
2386
|
*
|
|
@@ -2347,9 +2391,8 @@ class CubicBezierCurve {
|
|
|
2347
2391
|
* @return {number}
|
|
2348
2392
|
**/
|
|
2349
2393
|
convertU2T(u) {
|
|
2350
|
-
return Math.max(0.0, Math.min(1.0,
|
|
2394
|
+
return Math.max(0.0, Math.min(1.0, u / this.arcLength));
|
|
2351
2395
|
}
|
|
2352
|
-
;
|
|
2353
2396
|
/**
|
|
2354
2397
|
* Get the curve tangent vector at a given relative position u in [0,arcLength].<br>
|
|
2355
2398
|
* <br>
|
|
@@ -2364,7 +2407,6 @@ class CubicBezierCurve {
|
|
|
2364
2407
|
getTangent(u) {
|
|
2365
2408
|
return this.getTangentAt(this.convertU2T(u));
|
|
2366
2409
|
}
|
|
2367
|
-
;
|
|
2368
2410
|
/**
|
|
2369
2411
|
* Get the curve perpendicular at a given relative position u in [0,arcLength] as a vector.<br>
|
|
2370
2412
|
* <br>
|
|
@@ -2379,7 +2421,6 @@ class CubicBezierCurve {
|
|
|
2379
2421
|
getPerpendicular(u) {
|
|
2380
2422
|
return this.getPerpendicularAt(this.convertU2T(u));
|
|
2381
2423
|
}
|
|
2382
|
-
;
|
|
2383
2424
|
/**
|
|
2384
2425
|
* Get the curve perpendicular at a given absolute position t in [0,1] as a vector.<br>
|
|
2385
2426
|
* <br>
|
|
@@ -2395,7 +2436,6 @@ class CubicBezierCurve {
|
|
|
2395
2436
|
const tangentVector = this.getTangentAt(t);
|
|
2396
2437
|
return new Vertex(tangentVector.y, -tangentVector.x);
|
|
2397
2438
|
}
|
|
2398
|
-
;
|
|
2399
2439
|
/**
|
|
2400
2440
|
* Clone this Bézier curve (deep clone).
|
|
2401
2441
|
*
|
|
@@ -2407,7 +2447,6 @@ class CubicBezierCurve {
|
|
|
2407
2447
|
clone() {
|
|
2408
2448
|
return new CubicBezierCurve(this.getStartPoint().clone(), this.getEndPoint().clone(), this.getStartControlPoint().clone(), this.getEndControlPoint().clone());
|
|
2409
2449
|
}
|
|
2410
|
-
;
|
|
2411
2450
|
/**
|
|
2412
2451
|
* Check if this and the specified curve are equal.<br>
|
|
2413
2452
|
* <br>
|
|
@@ -2426,17 +2465,25 @@ class CubicBezierCurve {
|
|
|
2426
2465
|
// Let's see if this restricted version works out.
|
|
2427
2466
|
if (!curve)
|
|
2428
2467
|
return false;
|
|
2429
|
-
if (!curve.startPoint ||
|
|
2430
|
-
!curve.endPoint ||
|
|
2431
|
-
!curve.startControlPoint ||
|
|
2432
|
-
!curve.endControlPoint)
|
|
2468
|
+
if (!curve.startPoint || !curve.endPoint || !curve.startControlPoint || !curve.endControlPoint)
|
|
2433
2469
|
return false;
|
|
2434
|
-
return this.startPoint.equals(curve.startPoint)
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2470
|
+
return (this.startPoint.equals(curve.startPoint) &&
|
|
2471
|
+
this.endPoint.equals(curve.endPoint) &&
|
|
2472
|
+
this.startControlPoint.equals(curve.startControlPoint) &&
|
|
2473
|
+
this.endControlPoint.equals(curve.endControlPoint));
|
|
2474
|
+
}
|
|
2475
|
+
/**
|
|
2476
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
2477
|
+
* After calling this function the object might not hold valid data any more and
|
|
2478
|
+
* should not be used.
|
|
2479
|
+
*/
|
|
2480
|
+
destroy() {
|
|
2481
|
+
this.startPoint.destroy();
|
|
2482
|
+
this.endPoint.destroy();
|
|
2483
|
+
this.startControlPoint.destroy();
|
|
2484
|
+
this.endControlPoint.destroy();
|
|
2485
|
+
this.isDestroyed = true;
|
|
2438
2486
|
}
|
|
2439
|
-
;
|
|
2440
2487
|
/**
|
|
2441
2488
|
* Quick check for class instance.
|
|
2442
2489
|
* Is there a better way?
|
|
@@ -2462,41 +2509,6 @@ class CubicBezierCurve {
|
|
|
2462
2509
|
*/
|
|
2463
2510
|
return obj instanceof CubicBezierCurve;
|
|
2464
2511
|
}
|
|
2465
|
-
;
|
|
2466
|
-
/**
|
|
2467
|
-
* Create an SVG path data representation of this bézier curve.
|
|
2468
|
-
*
|
|
2469
|
-
* Path data string format is:<br>
|
|
2470
|
-
* <pre>'M x0 y1 C dx0 dy1 dx1 dy1 x1 x2'</pre><br>
|
|
2471
|
-
* or in other words<br>
|
|
2472
|
-
* <pre>'M startoint.x startPoint.y C startControlPoint.x startControlPoint.y endControlPoint.x endControlPoint.y endPoint.x endPoint.y'</pre>
|
|
2473
|
-
*
|
|
2474
|
-
* @method toSVGPathData
|
|
2475
|
-
* @instance
|
|
2476
|
-
* @memberof CubicBezierCurve
|
|
2477
|
-
* @return {string} The SVG path data string.
|
|
2478
|
-
**/
|
|
2479
|
-
toSVGPathData() {
|
|
2480
|
-
var buffer = [];
|
|
2481
|
-
buffer.push('M ');
|
|
2482
|
-
buffer.push(this.startPoint.x.toString());
|
|
2483
|
-
buffer.push(' ');
|
|
2484
|
-
buffer.push(this.startPoint.y.toString());
|
|
2485
|
-
buffer.push(' C ');
|
|
2486
|
-
buffer.push(this.startControlPoint.x.toString());
|
|
2487
|
-
buffer.push(' ');
|
|
2488
|
-
buffer.push(this.startControlPoint.y.toString());
|
|
2489
|
-
buffer.push(' ');
|
|
2490
|
-
buffer.push(this.endControlPoint.x.toString());
|
|
2491
|
-
buffer.push(' ');
|
|
2492
|
-
buffer.push(this.endControlPoint.y.toString());
|
|
2493
|
-
buffer.push(' ');
|
|
2494
|
-
buffer.push(this.endPoint.x.toString());
|
|
2495
|
-
buffer.push(' ');
|
|
2496
|
-
buffer.push(this.endPoint.y.toString());
|
|
2497
|
-
return buffer.join('');
|
|
2498
|
-
}
|
|
2499
|
-
;
|
|
2500
2512
|
/**
|
|
2501
2513
|
* Convert this curve to a JSON string.
|
|
2502
2514
|
*
|
|
@@ -2509,18 +2521,33 @@ class CubicBezierCurve {
|
|
|
2509
2521
|
toJSON(prettyFormat) {
|
|
2510
2522
|
var jsonString = "{ " + // begin object
|
|
2511
2523
|
(prettyFormat ? "\n\t" : "") +
|
|
2512
|
-
"
|
|
2524
|
+
'"startPoint" : [' +
|
|
2525
|
+
this.getStartPoint().x +
|
|
2526
|
+
"," +
|
|
2527
|
+
this.getStartPoint().y +
|
|
2528
|
+
"], " +
|
|
2513
2529
|
(prettyFormat ? "\n\t" : "") +
|
|
2514
|
-
"
|
|
2530
|
+
'"endPoint" : [' +
|
|
2531
|
+
this.getEndPoint().x +
|
|
2532
|
+
"," +
|
|
2533
|
+
this.getEndPoint().y +
|
|
2534
|
+
"], " +
|
|
2515
2535
|
(prettyFormat ? "\n\t" : "") +
|
|
2516
|
-
"
|
|
2536
|
+
'"startControlPoint": [' +
|
|
2537
|
+
this.getStartControlPoint().x +
|
|
2538
|
+
"," +
|
|
2539
|
+
this.getStartControlPoint().y +
|
|
2540
|
+
"], " +
|
|
2517
2541
|
(prettyFormat ? "\n\t" : "") +
|
|
2518
|
-
"
|
|
2542
|
+
'"endControlPoint" : [' +
|
|
2543
|
+
this.getEndControlPoint().x +
|
|
2544
|
+
"," +
|
|
2545
|
+
this.getEndControlPoint().y +
|
|
2546
|
+
"]" +
|
|
2519
2547
|
(prettyFormat ? "\n\t" : "") +
|
|
2520
2548
|
" }"; // end object
|
|
2521
2549
|
return jsonString;
|
|
2522
2550
|
}
|
|
2523
|
-
;
|
|
2524
2551
|
/**
|
|
2525
2552
|
* Parse a Bézier curve from the given JSON string.
|
|
2526
2553
|
*
|
|
@@ -2535,7 +2562,6 @@ class CubicBezierCurve {
|
|
|
2535
2562
|
var obj = JSON.parse(jsonString);
|
|
2536
2563
|
return CubicBezierCurve.fromObject(obj);
|
|
2537
2564
|
}
|
|
2538
|
-
;
|
|
2539
2565
|
/**
|
|
2540
2566
|
* Try to convert the passed object to a CubicBezierCurve.
|
|
2541
2567
|
*
|
|
@@ -2550,16 +2576,15 @@ class CubicBezierCurve {
|
|
|
2550
2576
|
if (typeof obj !== "object")
|
|
2551
2577
|
throw "Can only build from object.";
|
|
2552
2578
|
if (!obj.startPoint)
|
|
2553
|
-
throw
|
|
2579
|
+
throw 'Object member "startPoint" missing.';
|
|
2554
2580
|
if (!obj.endPoint)
|
|
2555
|
-
throw
|
|
2581
|
+
throw 'Object member "endPoint" missing.';
|
|
2556
2582
|
if (!obj.startControlPoint)
|
|
2557
|
-
throw
|
|
2583
|
+
throw 'Object member "startControlPoint" missing.';
|
|
2558
2584
|
if (!obj.endControlPoint)
|
|
2559
|
-
throw
|
|
2585
|
+
throw 'Object member "endControlPoint" missing.';
|
|
2560
2586
|
return new CubicBezierCurve(new Vertex(obj.startPoint[0], obj.startPoint[1]), new Vertex(obj.endPoint[0], obj.endPoint[1]), new Vertex(obj.startControlPoint[0], obj.startControlPoint[1]), new Vertex(obj.endControlPoint[0], obj.endControlPoint[1]));
|
|
2561
2587
|
}
|
|
2562
|
-
;
|
|
2563
2588
|
/**
|
|
2564
2589
|
* Convert a 4-element array of vertices to a cubic bézier curve.
|
|
2565
2590
|
*
|
|
@@ -2576,7 +2601,6 @@ class CubicBezierCurve {
|
|
|
2576
2601
|
throw "Can only build from array with four elements.";
|
|
2577
2602
|
return new CubicBezierCurve(arr[0], arr[1], arr[2], arr[3]);
|
|
2578
2603
|
}
|
|
2579
|
-
;
|
|
2580
2604
|
}
|
|
2581
2605
|
/** @constant {number} */
|
|
2582
2606
|
CubicBezierCurve.START_POINT = 0;
|
|
@@ -2609,7 +2633,10 @@ CubicBezierCurve.END_POINT = 3;
|
|
|
2609
2633
|
* @modified 2020-07-24 Added the getClosestT(Vertex) function.
|
|
2610
2634
|
* @modified 2020-12-29 Constructor is now private (no explicit use intended).
|
|
2611
2635
|
* @modified 2021-05-25 Added BezierPath.fromReducedList( Array<number> ).
|
|
2612
|
-
* @
|
|
2636
|
+
* @modified 2022-01-31 Added `BezierPath.getEvenDistributionVertices(number)`.
|
|
2637
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
2638
|
+
* @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
2639
|
+
* @version 2.5.0
|
|
2613
2640
|
*
|
|
2614
2641
|
* @file BezierPath
|
|
2615
2642
|
* @public
|
|
@@ -3498,6 +3525,59 @@ class BezierPath {
|
|
|
3498
3525
|
}
|
|
3499
3526
|
return new Bounds(min, max);
|
|
3500
3527
|
}
|
|
3528
|
+
/**
|
|
3529
|
+
* Get n 'equally' distributed vertices along this Bézier path.
|
|
3530
|
+
*
|
|
3531
|
+
* As the changing curvature of the B slines makes prediction of distances difficult, the
|
|
3532
|
+
* returned vertices' distances are only relatively equal:
|
|
3533
|
+
* - the distance grows where curvature is large.
|
|
3534
|
+
* - the distance shrinks where curvature is small.
|
|
3535
|
+
*
|
|
3536
|
+
* Only the distance mean of all consecutive is 1/n-th of the total arc length.
|
|
3537
|
+
*
|
|
3538
|
+
* Usually this approximation is good enough for most use cases.
|
|
3539
|
+
*
|
|
3540
|
+
* @param {number} pointCount - (must be at least 2) The number of desired points (start and end point included).
|
|
3541
|
+
* @return {Array<Vertex>}
|
|
3542
|
+
*/
|
|
3543
|
+
getEvenDistributionVertices(pointCount) {
|
|
3544
|
+
if (pointCount < 2) {
|
|
3545
|
+
throw new Error("pointCount must be larger than one; is " + pointCount + ".");
|
|
3546
|
+
}
|
|
3547
|
+
const result = [];
|
|
3548
|
+
if (this.bezierCurves.length === 0) {
|
|
3549
|
+
return result;
|
|
3550
|
+
}
|
|
3551
|
+
// Fetch and add the start point from the source polygon
|
|
3552
|
+
var polygonPoint = new Vertex(this.bezierCurves[0].startPoint);
|
|
3553
|
+
result.push(polygonPoint);
|
|
3554
|
+
// if (this.bezierCurves.length === 1) {
|
|
3555
|
+
// return result;
|
|
3556
|
+
// }
|
|
3557
|
+
const perimeter = this.totalArcLength;
|
|
3558
|
+
const stepSize = perimeter / (pointCount - 1);
|
|
3559
|
+
const n = this.bezierCurves.length;
|
|
3560
|
+
let curveIndex = 0;
|
|
3561
|
+
let segmentLength = this.bezierCurves[0].arcLength;
|
|
3562
|
+
let curSegmentU = stepSize;
|
|
3563
|
+
let i = 1;
|
|
3564
|
+
while (i < pointCount && curveIndex < n) {
|
|
3565
|
+
// Check if next eq point is inside this segment
|
|
3566
|
+
if (curSegmentU < segmentLength) {
|
|
3567
|
+
var newPoint = this.bezierCurves[curveIndex].getPoint(curSegmentU);
|
|
3568
|
+
result.push(newPoint);
|
|
3569
|
+
curSegmentU += stepSize;
|
|
3570
|
+
i++;
|
|
3571
|
+
}
|
|
3572
|
+
else {
|
|
3573
|
+
curveIndex++;
|
|
3574
|
+
curSegmentU = curSegmentU - segmentLength;
|
|
3575
|
+
segmentLength = curveIndex < n ? this.bezierCurves[curveIndex].arcLength : 0;
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
result.push(new Vertex(this.bezierCurves[n - 1].endPoint));
|
|
3579
|
+
return result;
|
|
3580
|
+
}
|
|
3501
3581
|
/**
|
|
3502
3582
|
* Clone this BezierPath (deep clone).
|
|
3503
3583
|
*
|
|
@@ -3544,30 +3624,15 @@ class BezierPath {
|
|
|
3544
3624
|
return true;
|
|
3545
3625
|
}
|
|
3546
3626
|
/**
|
|
3547
|
-
*
|
|
3548
|
-
*
|
|
3549
|
-
*
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
* @memberof BezierPath
|
|
3555
|
-
* @return {string} The SVG string.
|
|
3556
|
-
**/
|
|
3557
|
-
toSVGString(options) {
|
|
3558
|
-
options = options || {};
|
|
3559
|
-
var buffer = [];
|
|
3560
|
-
buffer.push("<path");
|
|
3561
|
-
if (options.className)
|
|
3562
|
-
buffer.push(' class="' + options.className + '"');
|
|
3563
|
-
buffer.push(' d="');
|
|
3564
|
-
for (var c = 0; c < this.bezierCurves.length; c++) {
|
|
3565
|
-
if (c > 0)
|
|
3566
|
-
buffer.push(" ");
|
|
3567
|
-
buffer.push(this.bezierCurves[c].toSVGPathData());
|
|
3627
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
3628
|
+
* After calling this function the object might not hold valid data any more and
|
|
3629
|
+
* should not be used.
|
|
3630
|
+
*/
|
|
3631
|
+
destroy() {
|
|
3632
|
+
for (var i = 0; i < this.bezierCurves.length; i++) {
|
|
3633
|
+
this.bezierCurves[i].destroy();
|
|
3568
3634
|
}
|
|
3569
|
-
|
|
3570
|
-
return buffer.join("");
|
|
3635
|
+
this.isDestroyed = true;
|
|
3571
3636
|
}
|
|
3572
3637
|
/**
|
|
3573
3638
|
* Create a JSON string representation of this bézier curve.
|
|
@@ -3794,7 +3859,8 @@ BezierPath.END_POINT = 3;
|
|
|
3794
3859
|
* @modified 2020-03-16 The Line.angle(Line) parameter is now optional. The baseline (x-axis) will be used if not defined.
|
|
3795
3860
|
* @modified 2020-03-23 Ported to Typescript from JS.
|
|
3796
3861
|
* @modified 2020-12-04 The `intersection` function returns undefined if both lines are parallel.
|
|
3797
|
-
* @
|
|
3862
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
3863
|
+
* @version 2.2.0
|
|
3798
3864
|
*
|
|
3799
3865
|
* @file Line
|
|
3800
3866
|
* @public
|
|
@@ -3839,45 +3905,19 @@ class Line extends VertTuple {
|
|
|
3839
3905
|
return null;
|
|
3840
3906
|
let a = this.a.y - line.a.y;
|
|
3841
3907
|
let b = this.a.x - line.a.x;
|
|
3842
|
-
const numerator1 = (
|
|
3843
|
-
const numerator2 = (
|
|
3908
|
+
const numerator1 = (line.b.x - line.a.x) * a - (line.b.y - line.a.y) * b;
|
|
3909
|
+
const numerator2 = (this.b.x - this.a.x) * a - (this.b.y - this.a.y) * b;
|
|
3844
3910
|
a = numerator1 / denominator; // NaN if parallel lines
|
|
3845
3911
|
b = numerator2 / denominator;
|
|
3846
3912
|
// Catch NaN?
|
|
3847
|
-
const x = this.a.x +
|
|
3848
|
-
const y = this.a.y +
|
|
3913
|
+
const x = this.a.x + a * (this.b.x - this.a.x);
|
|
3914
|
+
const y = this.a.y + a * (this.b.y - this.a.y);
|
|
3849
3915
|
if (isNaN(a) || isNaN(x) || isNaN(y)) {
|
|
3850
3916
|
return undefined;
|
|
3851
3917
|
}
|
|
3852
3918
|
// if we cast these lines infinitely in both directions, they intersect here:
|
|
3853
3919
|
return new Vertex(x, y);
|
|
3854
3920
|
}
|
|
3855
|
-
;
|
|
3856
|
-
/**
|
|
3857
|
-
* Create an SVG representation of this line.
|
|
3858
|
-
*
|
|
3859
|
-
* @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
|
|
3860
|
-
* @method toSVGString
|
|
3861
|
-
* @param {options} p - A set of options, like the 'classname' to use
|
|
3862
|
-
* for the line object.
|
|
3863
|
-
* @return {string} The SVG string representing this line.
|
|
3864
|
-
* @instance
|
|
3865
|
-
* @memberof Line
|
|
3866
|
-
**/
|
|
3867
|
-
toSVGString(options) {
|
|
3868
|
-
options = options || {};
|
|
3869
|
-
var buffer = [];
|
|
3870
|
-
buffer.push('<line');
|
|
3871
|
-
if (options.className)
|
|
3872
|
-
buffer.push(' class="' + options.className + '"');
|
|
3873
|
-
buffer.push(' x1="' + this.a.x + '"');
|
|
3874
|
-
buffer.push(' y1="' + this.a.y + '"');
|
|
3875
|
-
buffer.push(' x2="' + this.b.x + '"');
|
|
3876
|
-
buffer.push(' y2="' + this.b.y + '"');
|
|
3877
|
-
buffer.push(' />');
|
|
3878
|
-
return buffer.join('');
|
|
3879
|
-
}
|
|
3880
|
-
;
|
|
3881
3921
|
}
|
|
3882
3922
|
|
|
3883
3923
|
/**
|
|
@@ -3889,7 +3929,9 @@ class Line extends VertTuple {
|
|
|
3889
3929
|
* @modified 2020-09-07 Changed the vertAt function by switching sin and cos! The old version did not return the correct vertex (by angle) accoring to the assumed circle math.
|
|
3890
3930
|
* @modified 2020-10-16 Added the containsCircle(...) function.
|
|
3891
3931
|
* @modified 2021-01-20 Added UID.
|
|
3892
|
-
* @
|
|
3932
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
3933
|
+
* @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
3934
|
+
* @version 1.3.0
|
|
3893
3935
|
**/
|
|
3894
3936
|
/**
|
|
3895
3937
|
* @classdesc A simple circle: center point and radius.
|
|
@@ -3920,7 +3962,6 @@ class Circle {
|
|
|
3920
3962
|
this.center = center;
|
|
3921
3963
|
this.radius = radius;
|
|
3922
3964
|
}
|
|
3923
|
-
;
|
|
3924
3965
|
/**
|
|
3925
3966
|
* Check if the given circle is fully contained inside this circle.
|
|
3926
3967
|
*
|
|
@@ -3933,7 +3974,6 @@ class Circle {
|
|
|
3933
3974
|
containsCircle(circle) {
|
|
3934
3975
|
return this.center.distance(circle.center) + circle.radius < this.radius;
|
|
3935
3976
|
}
|
|
3936
|
-
;
|
|
3937
3977
|
/**
|
|
3938
3978
|
* Calculate the distance from this circle to the given line.
|
|
3939
3979
|
*
|
|
@@ -3952,7 +3992,6 @@ class Circle {
|
|
|
3952
3992
|
const closestPointOnLine = line.getClosestPoint(this.center);
|
|
3953
3993
|
return closestPointOnLine.distance(this.center) - this.radius;
|
|
3954
3994
|
}
|
|
3955
|
-
;
|
|
3956
3995
|
/**
|
|
3957
3996
|
* Get the vertex on the this circle for the given angle.
|
|
3958
3997
|
*
|
|
@@ -3966,7 +4005,6 @@ class Circle {
|
|
|
3966
4005
|
// Find the point on the circle respective the angle. Then move relative to center.
|
|
3967
4006
|
return Circle.circleUtils.vertAt(angle, this.radius).add(this.center);
|
|
3968
4007
|
}
|
|
3969
|
-
;
|
|
3970
4008
|
/**
|
|
3971
4009
|
* Get a tangent line of this circle for a given angle.
|
|
3972
4010
|
*
|
|
@@ -3983,7 +4021,6 @@ class Circle {
|
|
|
3983
4021
|
// Construct the perpendicular of the line in point a. Then move relative to center.
|
|
3984
4022
|
return new Vector(pointA, new Vertex(0, 0)).add(this.center).perp();
|
|
3985
4023
|
}
|
|
3986
|
-
;
|
|
3987
4024
|
/**
|
|
3988
4025
|
* Calculate the intersection points (if exists) with the given circle.
|
|
3989
4026
|
*
|
|
@@ -4023,48 +4060,33 @@ class Circle {
|
|
|
4023
4060
|
// x4 = P2.x - h*(P1.y - P0.y)/d;
|
|
4024
4061
|
// y4 = P2.y + h*(P1.x - P0.x)/d;
|
|
4025
4062
|
// return pair<Point, Point>(Point(x3, y3), Point(x4, y4));
|
|
4026
|
-
// }
|
|
4063
|
+
// }
|
|
4027
4064
|
var p0 = this.center;
|
|
4028
4065
|
var p1 = circle.center;
|
|
4029
4066
|
var d = p0.distance(p1);
|
|
4030
4067
|
var a = (this.radius * this.radius - circle.radius * circle.radius + d * d) / (2 * d);
|
|
4031
4068
|
var h = Math.sqrt(this.radius * this.radius - a * a);
|
|
4032
4069
|
var p2 = p1.clone().scale(a / d, p0);
|
|
4033
|
-
var x3 = p2.x + h * (p1.y - p0.y) / d;
|
|
4034
|
-
var y3 = p2.y - h * (p1.x - p0.x) / d;
|
|
4035
|
-
var x4 = p2.x - h * (p1.y - p0.y) / d;
|
|
4036
|
-
var y4 = p2.y + h * (p1.x - p0.x) / d;
|
|
4070
|
+
var x3 = p2.x + (h * (p1.y - p0.y)) / d;
|
|
4071
|
+
var y3 = p2.y - (h * (p1.x - p0.x)) / d;
|
|
4072
|
+
var x4 = p2.x - (h * (p1.y - p0.y)) / d;
|
|
4073
|
+
var y4 = p2.y + (h * (p1.x - p0.x)) / d;
|
|
4037
4074
|
return new Line(new Vertex(x3, y3), new Vertex(x4, y4));
|
|
4038
4075
|
}
|
|
4039
|
-
;
|
|
4040
4076
|
/**
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4048
|
-
* @memberof Circle
|
|
4049
|
-
*/
|
|
4050
|
-
toSVGString(options) {
|
|
4051
|
-
options = options || {};
|
|
4052
|
-
var buffer = [];
|
|
4053
|
-
buffer.push('<circle');
|
|
4054
|
-
if (options.className)
|
|
4055
|
-
buffer.push(' class="' + options.className + '"');
|
|
4056
|
-
buffer.push(' cx="' + this.center.x + '"');
|
|
4057
|
-
buffer.push(' cy="' + this.center.y + '"');
|
|
4058
|
-
buffer.push(' r="' + this.radius + '"');
|
|
4059
|
-
buffer.push(' />');
|
|
4060
|
-
return buffer.join('');
|
|
4077
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
4078
|
+
* After calling this function the object might not hold valid data any more and
|
|
4079
|
+
* should not be used.
|
|
4080
|
+
*/
|
|
4081
|
+
destroy() {
|
|
4082
|
+
this.center.destroy();
|
|
4083
|
+
this.isDestroyed = true;
|
|
4061
4084
|
}
|
|
4062
|
-
;
|
|
4063
4085
|
} // END class
|
|
4064
4086
|
Circle.circleUtils = {
|
|
4065
4087
|
vertAt: (angle, radius) => {
|
|
4066
4088
|
/* return new Vertex( Math.sin(angle) * radius,
|
|
4067
|
-
|
|
4089
|
+
Math.cos(angle) * radius ); */
|
|
4068
4090
|
return new Vertex(Math.cos(angle) * radius, Math.sin(angle) * radius);
|
|
4069
4091
|
}
|
|
4070
4092
|
};
|
|
@@ -4105,27 +4127,15 @@ class CircleSector {
|
|
|
4105
4127
|
this.startAngle = startAngle;
|
|
4106
4128
|
this.endAngle = endAngle;
|
|
4107
4129
|
}
|
|
4108
|
-
;
|
|
4109
4130
|
/**
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
*/
|
|
4118
|
-
toSVGString(options) {
|
|
4119
|
-
options = options || {};
|
|
4120
|
-
var buffer = [];
|
|
4121
|
-
buffer.push('<path ');
|
|
4122
|
-
if (options.className)
|
|
4123
|
-
buffer.push(' class="' + options.className + '"');
|
|
4124
|
-
const data = CircleSector.circleSectorUtils.describeSVGArc(this.circle.center.x, this.circle.center.y, this.circle.radius, this.startAngle, this.endAngle);
|
|
4125
|
-
buffer.push(' d="' + data.join(" ") + '" />');
|
|
4126
|
-
return buffer.join('');
|
|
4131
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
4132
|
+
* After calling this function the object might not hold valid data any more and
|
|
4133
|
+
* should not be used.
|
|
4134
|
+
*/
|
|
4135
|
+
destroy() {
|
|
4136
|
+
this.circle.destroy();
|
|
4137
|
+
this.isDestroyed = true;
|
|
4127
4138
|
}
|
|
4128
|
-
;
|
|
4129
4139
|
} // END class
|
|
4130
4140
|
CircleSector.circleSectorUtils = {
|
|
4131
4141
|
/**
|
|
@@ -4134,11 +4144,11 @@ CircleSector.circleSectorUtils = {
|
|
|
4134
4144
|
* TODO: generalize for ellipses (two radii).
|
|
4135
4145
|
*
|
|
4136
4146
|
* @param {number} angle - The angle in radians.
|
|
4137
|
-
|
|
4147
|
+
*/
|
|
4138
4148
|
polarToCartesian: (centerX, centerY, radius, angle) => {
|
|
4139
4149
|
return {
|
|
4140
|
-
x: centerX +
|
|
4141
|
-
y: centerY +
|
|
4150
|
+
x: centerX + radius * Math.cos(angle),
|
|
4151
|
+
y: centerY + radius * Math.sin(angle)
|
|
4142
4152
|
};
|
|
4143
4153
|
},
|
|
4144
4154
|
/**
|
|
@@ -4151,7 +4161,7 @@ CircleSector.circleSectorUtils = {
|
|
|
4151
4161
|
* @return [ 'A', radiusx, radiusy, rotation=0, largeArcFlag=1|0, sweepFlag=0, endx, endy ]
|
|
4152
4162
|
*/
|
|
4153
4163
|
describeSVGArc: (x, y, radius, startAngle, endAngle, options) => {
|
|
4154
|
-
if (typeof options ===
|
|
4164
|
+
if (typeof options === "undefined")
|
|
4155
4165
|
options = { moveToStart: true };
|
|
4156
4166
|
const end = CircleSector.circleSectorUtils.polarToCartesian(x, y, radius, endAngle);
|
|
4157
4167
|
const start = CircleSector.circleSectorUtils.polarToCartesian(x, y, radius, startAngle);
|
|
@@ -4176,7 +4186,7 @@ CircleSector.circleSectorUtils = {
|
|
|
4176
4186
|
}
|
|
4177
4187
|
const pathData = [];
|
|
4178
4188
|
if (options.moveToStart) {
|
|
4179
|
-
pathData.push(
|
|
4189
|
+
pathData.push("M", start.x, start.y);
|
|
4180
4190
|
}
|
|
4181
4191
|
pathData.push("A", radius, radius, 0, largeArcFlag, sweepFlag, end.x, end.y);
|
|
4182
4192
|
return pathData;
|
|
@@ -4214,7 +4224,11 @@ CircleSector.circleSectorUtils = {
|
|
|
4214
4224
|
* @modified 2021-11-15 Adding more parameters tot the `text()` function: fontSize, textAlign, fontFamily, lineHeight.
|
|
4215
4225
|
* @modified 2021-11-19 Fixing the `label(text,x,y)` position.
|
|
4216
4226
|
* @modified 2021-11-19 Added the `color` param to the `label(...)` function.
|
|
4217
|
-
* @
|
|
4227
|
+
* @modified 2022-02-03 Added the `lineWidth` param to the `crosshair` function.
|
|
4228
|
+
* @modified 2022-02-03 Added the `cross(...)` function.
|
|
4229
|
+
* @modified 2022-03-26 Added the private `nodeDefs` and `bufferedNodeDefs` attributes.
|
|
4230
|
+
* @modified 2022-03-26 Added the `texturedPoly` function to draw textures polygons.
|
|
4231
|
+
* @version 1.6.0
|
|
4218
4232
|
**/
|
|
4219
4233
|
const RAD_TO_DEG = 180 / Math.PI;
|
|
4220
4234
|
/**
|
|
@@ -4241,7 +4255,7 @@ class drawutilssvg {
|
|
|
4241
4255
|
* @param {boolean=} isSecondary - (optional) Indicates if this is the primary or secondary instance. Only primary instances manage child nodes.
|
|
4242
4256
|
* @param {SVGGElement=} gNode - (optional) Primary and seconday instances share the same <g> node.
|
|
4243
4257
|
**/
|
|
4244
|
-
constructor(svgNode, offset, scale, canvasSize, fillShapes, drawConfig, isSecondary, gNode, bufferGNode) {
|
|
4258
|
+
constructor(svgNode, offset, scale, canvasSize, fillShapes, drawConfig, isSecondary, gNode, bufferGNode, nodeDefs, bufferNodeDefs) {
|
|
4245
4259
|
this.svgNode = svgNode;
|
|
4246
4260
|
this.offset = new Vertex(0, 0).set(offset);
|
|
4247
4261
|
this.scale = new Vertex(1, 1).set(scale);
|
|
@@ -4253,14 +4267,23 @@ class drawutilssvg {
|
|
|
4253
4267
|
if (isSecondary) {
|
|
4254
4268
|
this.gNode = gNode;
|
|
4255
4269
|
this.bufferGNode = bufferGNode;
|
|
4270
|
+
this.nodeDefs = nodeDefs;
|
|
4271
|
+
this.bufferedNodeDefs = bufferNodeDefs;
|
|
4256
4272
|
}
|
|
4257
4273
|
else {
|
|
4258
4274
|
this.addStyleDefs(drawConfig);
|
|
4275
|
+
this.addDefsNode();
|
|
4259
4276
|
this.gNode = this.createSVGNode("g");
|
|
4260
4277
|
this.bufferGNode = this.createSVGNode("g");
|
|
4261
4278
|
this.svgNode.appendChild(this.gNode);
|
|
4262
4279
|
}
|
|
4263
4280
|
}
|
|
4281
|
+
/**
|
|
4282
|
+
* Adds a default style defintion based on the passed DrawConfig.
|
|
4283
|
+
* Twaek the draw config to change default colors or line thicknesses.
|
|
4284
|
+
*
|
|
4285
|
+
* @param {DrawConfig} drawConfig
|
|
4286
|
+
*/
|
|
4264
4287
|
addStyleDefs(drawConfig) {
|
|
4265
4288
|
this.nodeStyle = this.createSVGNode("style");
|
|
4266
4289
|
this.svgNode.appendChild(this.nodeStyle);
|
|
@@ -4293,6 +4316,15 @@ class drawutilssvg {
|
|
|
4293
4316
|
}
|
|
4294
4317
|
this.nodeStyle.innerHTML = rules.join("\n");
|
|
4295
4318
|
}
|
|
4319
|
+
/**
|
|
4320
|
+
* Adds the internal <defs> node.
|
|
4321
|
+
*/
|
|
4322
|
+
addDefsNode() {
|
|
4323
|
+
this.nodeDefs = this.createSVGNode("defs");
|
|
4324
|
+
// this.svgNode.appendChild(this.nodeDefs);
|
|
4325
|
+
this.bufferedNodeDefs = this.createSVGNode("defs");
|
|
4326
|
+
this.svgNode.appendChild(this.nodeDefs);
|
|
4327
|
+
}
|
|
4296
4328
|
/**
|
|
4297
4329
|
* This is a simple way to include custom CSS class mappings to the style defs of the generated SVG.
|
|
4298
4330
|
*
|
|
@@ -4430,7 +4462,7 @@ class drawutilssvg {
|
|
|
4430
4462
|
copyInstance(fillShapes) {
|
|
4431
4463
|
var copy = new drawutilssvg(this.svgNode, this.offset, this.scale, this.canvasSize, fillShapes, null, // no DrawConfig
|
|
4432
4464
|
true, // isSecondary
|
|
4433
|
-
this.gNode, this.bufferGNode);
|
|
4465
|
+
this.gNode, this.bufferGNode, this.nodeDefs, this.bufferedNodeDefs);
|
|
4434
4466
|
return copy;
|
|
4435
4467
|
}
|
|
4436
4468
|
/**
|
|
@@ -4507,11 +4539,15 @@ class drawutilssvg {
|
|
|
4507
4539
|
// layout updates.
|
|
4508
4540
|
// Replace the old <g>-node with the buffer node.
|
|
4509
4541
|
// https://stackoverflow.com/questions/27442464/how-to-update-a-svg-image-without-seeing-a-blinking
|
|
4542
|
+
this.svgNode.replaceChild(this.bufferedNodeDefs, this.nodeDefs);
|
|
4510
4543
|
this.svgNode.replaceChild(this.bufferGNode, this.gNode);
|
|
4511
4544
|
}
|
|
4512
|
-
|
|
4545
|
+
const tmpGNode = this.gNode;
|
|
4513
4546
|
this.gNode = this.bufferGNode;
|
|
4514
|
-
this.bufferGNode =
|
|
4547
|
+
this.bufferGNode = tmpGNode;
|
|
4548
|
+
const tmpDefsNode = this.nodeDefs;
|
|
4549
|
+
this.nodeDefs = this.bufferedNodeDefs;
|
|
4550
|
+
this.bufferedNodeDefs = tmpDefsNode;
|
|
4515
4551
|
}
|
|
4516
4552
|
_x(x) {
|
|
4517
4553
|
return this.offset.x + this.scale.x * x;
|
|
@@ -4603,6 +4639,74 @@ class drawutilssvg {
|
|
|
4603
4639
|
node.setAttribute("href", image.src);
|
|
4604
4640
|
return this._bindFillDraw(node, "image", null, null);
|
|
4605
4641
|
}
|
|
4642
|
+
/**
|
|
4643
|
+
* Draw an image at the given position with the given size.<br>
|
|
4644
|
+
* <br>
|
|
4645
|
+
* Note: SVG images may have resizing issues at the moment.Draw a line and an arrow at the end (zB) of the given line with the specified (CSS-) color.
|
|
4646
|
+
*
|
|
4647
|
+
* @method texturedPoly
|
|
4648
|
+
* @param {Image} textureImage - The image object to draw.
|
|
4649
|
+
* @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
|
|
4650
|
+
* @param {Polygon} polygon - The polygon to use as clip path.
|
|
4651
|
+
* @param {Vertex} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
|
|
4652
|
+
* @param {number} rotation - The rotation to use for the polygon (and for the texture).
|
|
4653
|
+
* @return {void}
|
|
4654
|
+
* @instance
|
|
4655
|
+
* @memberof drawutilssvg
|
|
4656
|
+
**/
|
|
4657
|
+
texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
|
|
4658
|
+
polygon.getBounds();
|
|
4659
|
+
const rotatedScalingOrigin = new Vertex(textureSize.min).clone().rotate(rotation, polygonPosition);
|
|
4660
|
+
polygonPosition.clone().add(rotatedScalingOrigin.difference(textureSize.min).inv());
|
|
4661
|
+
// Create something like this
|
|
4662
|
+
// ...
|
|
4663
|
+
// <defs>
|
|
4664
|
+
// <clipPath id="shape">
|
|
4665
|
+
// <path fill="none" d="..."/>
|
|
4666
|
+
// </clipPath>
|
|
4667
|
+
// </defs>
|
|
4668
|
+
// ...
|
|
4669
|
+
// <g clip-path="url(#shape)">
|
|
4670
|
+
// <g transform="scale(...)">
|
|
4671
|
+
// <image width="643" height="643" transform="rotate(...)" xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/beagle400.jpg" >
|
|
4672
|
+
// </g>
|
|
4673
|
+
// </g>
|
|
4674
|
+
// </image>
|
|
4675
|
+
// ...
|
|
4676
|
+
const clipPathNode = this.makeNode("clipPath");
|
|
4677
|
+
const clipPathId = `clippath_${UIDGenerator.next()}`; // TODO: use a better UUID generator here?
|
|
4678
|
+
clipPathNode.setAttribute("id", clipPathId);
|
|
4679
|
+
const gNode = this.makeNode("g");
|
|
4680
|
+
const imageNode = this.makeNode("image");
|
|
4681
|
+
imageNode.setAttribute("x", `${this._x(rotatedScalingOrigin.x)}`);
|
|
4682
|
+
imageNode.setAttribute("y", `${this._y(rotatedScalingOrigin.y)}`);
|
|
4683
|
+
imageNode.setAttribute("width", `${textureSize.width}`);
|
|
4684
|
+
imageNode.setAttribute("height", `${textureSize.height}`);
|
|
4685
|
+
imageNode.setAttribute("href", textureImage.src);
|
|
4686
|
+
// imageNode.setAttribute("opacity", "0.5");
|
|
4687
|
+
// SVG rotations in degrees
|
|
4688
|
+
imageNode.setAttribute("transform", `rotate(${rotation * RAD_TO_DEG}, ${this._x(rotatedScalingOrigin.x)}, ${this._y(rotatedScalingOrigin.y)})`);
|
|
4689
|
+
const pathNode = this.makeNode("path");
|
|
4690
|
+
const pathData = [];
|
|
4691
|
+
if (polygon.vertices.length > 0) {
|
|
4692
|
+
pathData.push("M", `${this._x(polygon.vertices[0].x)}`, `${this._y(polygon.vertices[0].y)}`);
|
|
4693
|
+
for (var i = 1; i < polygon.vertices.length; i++) {
|
|
4694
|
+
pathData.push("L", `${this._x(polygon.vertices[i].x)}`, `${this._y(polygon.vertices[i].y)}`);
|
|
4695
|
+
}
|
|
4696
|
+
}
|
|
4697
|
+
pathNode.setAttribute("d", pathData.join(" "));
|
|
4698
|
+
clipPathNode.appendChild(pathNode);
|
|
4699
|
+
this.bufferedNodeDefs.appendChild(clipPathNode);
|
|
4700
|
+
gNode.appendChild(imageNode);
|
|
4701
|
+
gNode.setAttribute("transform-origin", `${this._x(rotatedScalingOrigin.x)} ${this._y(rotatedScalingOrigin.y)}`);
|
|
4702
|
+
gNode.setAttribute("transform", `scale(${this.scale.x}, ${this.scale.y})`);
|
|
4703
|
+
const clipNode = this.makeNode("g");
|
|
4704
|
+
clipNode.appendChild(gNode);
|
|
4705
|
+
clipNode.setAttribute("clip-path", `url(#${clipPathId})`);
|
|
4706
|
+
// TODO: check if the image class is correct here or if we should use a 'clippedImage' class here
|
|
4707
|
+
this._bindFillDraw(clipNode, "image", null, null); // No color, no lineWidth
|
|
4708
|
+
return clipNode;
|
|
4709
|
+
}
|
|
4606
4710
|
/**
|
|
4607
4711
|
* Draw the given (cubic) bézier curve.
|
|
4608
4712
|
*
|
|
@@ -4995,11 +5099,12 @@ class drawutilssvg {
|
|
|
4995
5099
|
* @param {XYCoords} center - The center of the crosshair.
|
|
4996
5100
|
* @param {number} radius - The radius of the crosshair.
|
|
4997
5101
|
* @param {string} color - The CSS color to draw the crosshair with.
|
|
5102
|
+
* @param {number=0.5} lineWidth - (optional, default=0.5) The line width to use.
|
|
4998
5103
|
* @return {void}
|
|
4999
5104
|
* @instance
|
|
5000
5105
|
* @memberof drawutilssvg
|
|
5001
5106
|
*/
|
|
5002
|
-
crosshair(center, radius, color) {
|
|
5107
|
+
crosshair(center, radius, color, lineWidth) {
|
|
5003
5108
|
const node = this.makeNode("path");
|
|
5004
5109
|
const d = [
|
|
5005
5110
|
"M",
|
|
@@ -5016,7 +5121,40 @@ class drawutilssvg {
|
|
|
5016
5121
|
this._y(center.y) + radius
|
|
5017
5122
|
];
|
|
5018
5123
|
node.setAttribute("d", d.join(" "));
|
|
5019
|
-
return this._bindFillDraw(node, "crosshair", color, 0.5);
|
|
5124
|
+
return this._bindFillDraw(node, "crosshair", color, lineWidth || 0.5);
|
|
5125
|
+
}
|
|
5126
|
+
/**
|
|
5127
|
+
* Draw a cross with diagonal axes with given radius, color and lineWidth at the given position.<br>
|
|
5128
|
+
* <br>
|
|
5129
|
+
* Note that the x's radius will not be affected by scaling.
|
|
5130
|
+
*
|
|
5131
|
+
* @method crosshair
|
|
5132
|
+
* @param {XYCoords} center - The center of the crosshair.
|
|
5133
|
+
* @param {number} radius - The radius of the crosshair.
|
|
5134
|
+
* @param {string} color - The CSS color to draw the crosshair with.
|
|
5135
|
+
* @param {number=1} lineWidth - (optional, default=1.0) The line width to use.
|
|
5136
|
+
* @return {void}
|
|
5137
|
+
* @instance
|
|
5138
|
+
* @memberof drawutils
|
|
5139
|
+
*/
|
|
5140
|
+
cross(center, radius, color, lineWidth) {
|
|
5141
|
+
const node = this.makeNode("path");
|
|
5142
|
+
const d = [
|
|
5143
|
+
"M",
|
|
5144
|
+
this._x(center.x) - radius,
|
|
5145
|
+
this._y(center.y) - radius,
|
|
5146
|
+
"L",
|
|
5147
|
+
this._x(center.x) + radius,
|
|
5148
|
+
this._y(center.y) + radius,
|
|
5149
|
+
"M",
|
|
5150
|
+
this._x(center.x) - radius,
|
|
5151
|
+
this._y(center.y) + radius,
|
|
5152
|
+
"L",
|
|
5153
|
+
this._x(center.x) + radius,
|
|
5154
|
+
this._y(center.y) - radius
|
|
5155
|
+
];
|
|
5156
|
+
node.setAttribute("d", d.join(" "));
|
|
5157
|
+
return this._bindFillDraw(node, "cross", color, lineWidth || 1.0);
|
|
5020
5158
|
}
|
|
5021
5159
|
/**
|
|
5022
5160
|
* Draw a polygon.
|
|
@@ -5179,14 +5317,6 @@ class drawutilssvg {
|
|
|
5179
5317
|
if (this.isSecondary) {
|
|
5180
5318
|
return;
|
|
5181
5319
|
}
|
|
5182
|
-
// // Clearing an SVG is equivalent to removing all its child elements.
|
|
5183
|
-
// for (var i = 0; i < this.gNode.childNodes.length; i++) {
|
|
5184
|
-
// // Hide all nodes here. Don't throw them away.
|
|
5185
|
-
// // We can probably re-use them in the next draw cycle.
|
|
5186
|
-
// var child: SVGElement = this.gNode.childNodes[i] as SVGElement;
|
|
5187
|
-
// this.cache.set(child.getAttribute("id"), child);
|
|
5188
|
-
// }
|
|
5189
|
-
// this.removeAllChildNodes();
|
|
5190
5320
|
// Add a covering rect with the given background color
|
|
5191
5321
|
this.curId = "background";
|
|
5192
5322
|
this.curClassName = undefined;
|
|
@@ -5212,6 +5342,9 @@ class drawutilssvg {
|
|
|
5212
5342
|
while (this.bufferGNode.lastChild) {
|
|
5213
5343
|
this.bufferGNode.removeChild(this.bufferGNode.lastChild);
|
|
5214
5344
|
}
|
|
5345
|
+
while (this.bufferedNodeDefs.lastChild) {
|
|
5346
|
+
this.bufferedNodeDefs.removeChild(this.bufferedNodeDefs.lastChild);
|
|
5347
|
+
}
|
|
5215
5348
|
}
|
|
5216
5349
|
/**
|
|
5217
5350
|
* Create a new and empty `SVGElement` <svg> in the svg-namespace.
|
|
@@ -5451,7 +5584,10 @@ drawutilssvg.HEAD_XML = [
|
|
|
5451
5584
|
* @modified 2021-05-31 Added the `setConfiguration` function from `DrawLib`.
|
|
5452
5585
|
* @modified 2021-11-12 Adding more parameters tot the `text()` function: fontSize, textAlign, fontFamily, lineHeight.
|
|
5453
5586
|
* @modified 2021-11-19 Added the `color` param to the `label(...)` function.
|
|
5454
|
-
* @
|
|
5587
|
+
* @modified 2022-02-03 Added the `lineWidth` param to the `crosshair` function.
|
|
5588
|
+
* @modified 2022-02-03 Added the `cross(...)` function.
|
|
5589
|
+
* @modified 2022-03-27 Added the `texturedPoly` function.
|
|
5590
|
+
* @version 1.12.0
|
|
5455
5591
|
**/
|
|
5456
5592
|
// Todo: rename this class to Drawutils?
|
|
5457
5593
|
/**
|
|
@@ -5605,6 +5741,96 @@ class drawutils {
|
|
|
5605
5741
|
this.offset.x + position.x * this.scale.x, this.offset.y + position.y * this.scale.y, size.x * this.scale.x, size.y * this.scale.y);
|
|
5606
5742
|
this.ctx.restore();
|
|
5607
5743
|
}
|
|
5744
|
+
/**
|
|
5745
|
+
* Draw an image at the given position with the given size.<br>
|
|
5746
|
+
* <br>
|
|
5747
|
+
* Note: SVG images may have resizing issues at the moment.Draw a line and an arrow at the end (zB) of the given line with the specified (CSS-) color.
|
|
5748
|
+
*
|
|
5749
|
+
* @method texturedPoly
|
|
5750
|
+
* @param {Image} textureImage - The image object to draw.
|
|
5751
|
+
* @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
|
|
5752
|
+
* @param {Polygon} polygon - The polygon to use as clip path.
|
|
5753
|
+
* @param {Vertex} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
|
|
5754
|
+
* @param {number} rotation - The rotation to use for the polygon (and for the texture).
|
|
5755
|
+
* @param {XYCoords={x:0,y:0}} rotationCenter - (optional) The rotational center; default is center of bounding box.
|
|
5756
|
+
* @return {void}
|
|
5757
|
+
* @instance
|
|
5758
|
+
* @memberof drawutils
|
|
5759
|
+
**/
|
|
5760
|
+
texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
|
|
5761
|
+
var basePolygonBounds = polygon.getBounds();
|
|
5762
|
+
var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
|
|
5763
|
+
// var rotationalOffset = rotationCenter ? polygonPosition.difference(rotationCenter) : { x: 0, y: 0 };
|
|
5764
|
+
// var rotationalOffset = { x: 0, y: 0 };
|
|
5765
|
+
basePolygonBounds.getCenter().sub(targetCenterDifference);
|
|
5766
|
+
// Get the position offset of the polygon
|
|
5767
|
+
var targetTextureSize = new Vertex(textureSize.width, textureSize.height);
|
|
5768
|
+
// var targetTextureOffset = new Vertex(-textureSize.width / 2, -textureSize.height / 2).sub(targetCenterDifference);
|
|
5769
|
+
var targetTextureOffset = new Vertex(textureSize.min.x, textureSize.min.y).sub(polygonPosition);
|
|
5770
|
+
this.ctx.save();
|
|
5771
|
+
// this.ctx.translate(this.offset.x + rotationCenter.x * this.scale.x, this.offset.y + rotationCenter.y * this.scale.y);
|
|
5772
|
+
this.ctx.translate(this.offset.x + polygonPosition.x * this.scale.x, this.offset.y + polygonPosition.y * this.scale.y);
|
|
5773
|
+
drawutils.helpers.clipPoly(this.ctx, {
|
|
5774
|
+
x: -polygonPosition.x * this.scale.x,
|
|
5775
|
+
y: -polygonPosition.y * this.scale.y
|
|
5776
|
+
}, this.scale, polygon.vertices);
|
|
5777
|
+
this.ctx.scale(this.scale.x, this.scale.y);
|
|
5778
|
+
this.ctx.rotate(rotation);
|
|
5779
|
+
this.ctx.drawImage(textureImage, 0, 0, textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
|
|
5780
|
+
textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
|
|
5781
|
+
targetTextureOffset.x, // * this.scale.x,
|
|
5782
|
+
targetTextureOffset.y, // * this.scale.y,
|
|
5783
|
+
targetTextureSize.x, // * this.scale.x,
|
|
5784
|
+
targetTextureSize.y // * this.scale.y
|
|
5785
|
+
);
|
|
5786
|
+
this.ctx.restore();
|
|
5787
|
+
}
|
|
5788
|
+
_texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation, rotationCenter = { x: 0, y: 0 }) {
|
|
5789
|
+
var basePolygonBounds = polygon.getBounds();
|
|
5790
|
+
var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
|
|
5791
|
+
var rotationalOffset = rotationCenter ? polygonPosition.difference(rotationCenter) : { x: 0, y: 0 };
|
|
5792
|
+
// var rotationalOffset = { x: 0, y: 0 };
|
|
5793
|
+
var tileCenter = basePolygonBounds.getCenter().sub(targetCenterDifference);
|
|
5794
|
+
// Get the position offset of the polygon
|
|
5795
|
+
var targetTextureSize = new Vertex(textureSize.width, textureSize.height);
|
|
5796
|
+
var targetTextureOffset = new Vertex(-textureSize.width / 2, -textureSize.height / 2).sub(targetCenterDifference);
|
|
5797
|
+
this.ctx.save();
|
|
5798
|
+
// this.ctx.translate(
|
|
5799
|
+
// this.offset.x + (tileCenter.x - rotationalOffset.x * 0 + targetTextureOffset.x * 0.0) * this.scale.x,
|
|
5800
|
+
// this.offset.y + (tileCenter.y - rotationalOffset.y * 0 + targetTextureOffset.y * 0.0) * this.scale.y
|
|
5801
|
+
// );
|
|
5802
|
+
this.ctx.translate(this.offset.x + (tileCenter.x - rotationalOffset.x * 0 + targetTextureOffset.x * 0.0) * this.scale.x, this.offset.y + (tileCenter.y - rotationalOffset.y * 0 + targetTextureOffset.y * 0.0) * this.scale.y);
|
|
5803
|
+
this.ctx.rotate(rotation);
|
|
5804
|
+
drawutils.helpers.clipPoly(this.ctx, {
|
|
5805
|
+
x: (-targetCenterDifference.x * 1 - tileCenter.x - rotationalOffset.x) * this.scale.x,
|
|
5806
|
+
y: (-targetCenterDifference.y * 1 - tileCenter.y - rotationalOffset.y) * this.scale.y
|
|
5807
|
+
}, this.scale, polygon.vertices);
|
|
5808
|
+
this.ctx.drawImage(textureImage, 0, 0, textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
|
|
5809
|
+
textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
|
|
5810
|
+
(-polygonPosition.x + targetTextureOffset.x * 1 - rotationalOffset.x * 1) * this.scale.x, (-polygonPosition.y + targetTextureOffset.y * 1 - rotationalOffset.y * 1) * this.scale.y, targetTextureSize.x * this.scale.x, targetTextureSize.y * this.scale.y);
|
|
5811
|
+
// const scaledTextureSize = new Bounds(
|
|
5812
|
+
// new Vertex(
|
|
5813
|
+
// -polygonPosition.x + targetTextureOffset.x - rotationalOffset.x,
|
|
5814
|
+
// -polygonPosition.y + targetTextureOffset.y - rotationalOffset.y
|
|
5815
|
+
// ).scaleXY(this.scale, rotationCenter),
|
|
5816
|
+
// new Vertex(
|
|
5817
|
+
// -polygonPosition.x + targetTextureOffset.x - rotationalOffset.x + targetTextureSize.x,
|
|
5818
|
+
// -polygonPosition.y + targetTextureOffset.y - rotationalOffset.y + targetTextureSize.y
|
|
5819
|
+
// ).scaleXY(this.scale, rotationCenter)
|
|
5820
|
+
// );
|
|
5821
|
+
// this.ctx.drawImage(
|
|
5822
|
+
// textureImage,
|
|
5823
|
+
// 0,
|
|
5824
|
+
// 0,
|
|
5825
|
+
// textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
|
|
5826
|
+
// textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
|
|
5827
|
+
// scaledTextureSize.min.x,
|
|
5828
|
+
// scaledTextureSize.min.y,
|
|
5829
|
+
// scaledTextureSize.width,
|
|
5830
|
+
// scaledTextureSize.height
|
|
5831
|
+
// );
|
|
5832
|
+
this.ctx.restore();
|
|
5833
|
+
}
|
|
5608
5834
|
/**
|
|
5609
5835
|
* Draw a rectangle.
|
|
5610
5836
|
*
|
|
@@ -6045,11 +6271,12 @@ class drawutils {
|
|
|
6045
6271
|
* @param {XYCoords} center - The center of the crosshair.
|
|
6046
6272
|
* @param {number} radius - The radius of the crosshair.
|
|
6047
6273
|
* @param {string} color - The CSS color to draw the crosshair with.
|
|
6274
|
+
* @param {number=0.5} lineWidth - (optional, default=0.5) The line width to use.
|
|
6048
6275
|
* @return {void}
|
|
6049
6276
|
* @instance
|
|
6050
6277
|
* @memberof drawutils
|
|
6051
6278
|
*/
|
|
6052
|
-
crosshair(center, radius, color) {
|
|
6279
|
+
crosshair(center, radius, color, lineWidth) {
|
|
6053
6280
|
this.ctx.save();
|
|
6054
6281
|
this.ctx.beginPath();
|
|
6055
6282
|
this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y);
|
|
@@ -6057,7 +6284,34 @@ class drawutils {
|
|
|
6057
6284
|
this.ctx.moveTo(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y - radius);
|
|
6058
6285
|
this.ctx.lineTo(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y + radius);
|
|
6059
6286
|
this.ctx.strokeStyle = color;
|
|
6060
|
-
this.ctx.lineWidth = 0.5;
|
|
6287
|
+
this.ctx.lineWidth = lineWidth || 0.5;
|
|
6288
|
+
this.ctx.stroke();
|
|
6289
|
+
this.ctx.closePath();
|
|
6290
|
+
this.ctx.restore();
|
|
6291
|
+
}
|
|
6292
|
+
/**
|
|
6293
|
+
* Draw a cross with diagonal axes with given radius, color and lineWidth at the given position.<br>
|
|
6294
|
+
* <br>
|
|
6295
|
+
* Note that the x's radius will not be affected by scaling.
|
|
6296
|
+
*
|
|
6297
|
+
* @method crosshair
|
|
6298
|
+
* @param {XYCoords} center - The center of the crosshair.
|
|
6299
|
+
* @param {number} radius - The radius of the crosshair.
|
|
6300
|
+
* @param {string} color - The CSS color to draw the crosshair with.
|
|
6301
|
+
* @param {number=1} lineWidth - (optional, default=1.0) The line width to use.
|
|
6302
|
+
* @return {void}
|
|
6303
|
+
* @instance
|
|
6304
|
+
* @memberof drawutils
|
|
6305
|
+
*/
|
|
6306
|
+
cross(center, radius, color, lineWidth) {
|
|
6307
|
+
this.ctx.save();
|
|
6308
|
+
this.ctx.beginPath();
|
|
6309
|
+
this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y - radius);
|
|
6310
|
+
this.ctx.lineTo(this.offset.x + center.x * this.scale.x + radius, this.offset.y + center.y * this.scale.y + radius);
|
|
6311
|
+
this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y + radius);
|
|
6312
|
+
this.ctx.lineTo(this.offset.x + center.x * this.scale.x + radius, this.offset.y + center.y * this.scale.y - radius);
|
|
6313
|
+
this.ctx.strokeStyle = color;
|
|
6314
|
+
this.ctx.lineWidth = lineWidth || 1.0;
|
|
6061
6315
|
this.ctx.stroke();
|
|
6062
6316
|
this.ctx.closePath();
|
|
6063
6317
|
this.ctx.restore();
|
|
@@ -6235,6 +6489,21 @@ class drawutils {
|
|
|
6235
6489
|
this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
|
|
6236
6490
|
}
|
|
6237
6491
|
}
|
|
6492
|
+
drawutils.helpers = {
|
|
6493
|
+
// A helper function to define the clipping path.
|
|
6494
|
+
// This could be a candidate for the draw library.
|
|
6495
|
+
clipPoly: (ctx, offset, scale, vertices) => {
|
|
6496
|
+
ctx.beginPath();
|
|
6497
|
+
// Set clip mask
|
|
6498
|
+
ctx.moveTo(offset.x + vertices[0].x * scale.x, offset.y + vertices[0].y * scale.y);
|
|
6499
|
+
for (var i = 1; i < vertices.length; i++) {
|
|
6500
|
+
const vert = vertices[i];
|
|
6501
|
+
ctx.lineTo(offset.x + vert.x * scale.x, offset.y + vert.y * scale.y);
|
|
6502
|
+
}
|
|
6503
|
+
ctx.closePath();
|
|
6504
|
+
ctx.clip();
|
|
6505
|
+
}
|
|
6506
|
+
};
|
|
6238
6507
|
|
|
6239
6508
|
/**
|
|
6240
6509
|
* @author Ikaros Kappler
|
|
@@ -6244,7 +6513,10 @@ class drawutils {
|
|
|
6244
6513
|
* @modified 2020-10-15 Re-added the text() function.
|
|
6245
6514
|
* @modified 2021-01-24 Added the `setCurrentId` function.
|
|
6246
6515
|
* @modified 2021-05-31 Added the `setConfiguration` function from `DrawLib`.
|
|
6247
|
-
* @
|
|
6516
|
+
* @modified 2022-02-03 Added the `lineWidth` param to the `crosshair` function.
|
|
6517
|
+
* @modified 2022-02-03 Added the `cross(...)` function.
|
|
6518
|
+
* @modified 2022-03-27 Added the `texturedPoly` function.
|
|
6519
|
+
* @version 0.0.7
|
|
6248
6520
|
**/
|
|
6249
6521
|
/**
|
|
6250
6522
|
* @classdesc A wrapper class for basic drawing operations. This is the WebGL
|
|
@@ -6441,6 +6713,24 @@ class drawutilsgl {
|
|
|
6441
6713
|
image(image, position, size) {
|
|
6442
6714
|
// NOT YET IMPLEMENTED
|
|
6443
6715
|
}
|
|
6716
|
+
/**
|
|
6717
|
+
* Draw an image at the given position with the given size.<br>
|
|
6718
|
+
* <br>
|
|
6719
|
+
* Note: SVG images may have resizing issues at the moment.Draw a line and an arrow at the end (zB) of the given line with the specified (CSS-) color.
|
|
6720
|
+
*
|
|
6721
|
+
* @method texturedPoly
|
|
6722
|
+
* @param {Image} textureImage - The image object to draw.
|
|
6723
|
+
* @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
|
|
6724
|
+
* @param {Polygon} polygon - The polygon to use as clip path.
|
|
6725
|
+
* @param {Vertex} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
|
|
6726
|
+
* @param {number} rotation - The rotation to use for the polygon (and for the texture).
|
|
6727
|
+
* @return {void}
|
|
6728
|
+
* @instance
|
|
6729
|
+
* @memberof drawutilsgl
|
|
6730
|
+
**/
|
|
6731
|
+
texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
|
|
6732
|
+
// NOT YET IMPLEMENTED
|
|
6733
|
+
}
|
|
6444
6734
|
// +---------------------------------------------------------------------------------
|
|
6445
6735
|
// | This is the final helper function for drawing and filling stuff. It is not
|
|
6446
6736
|
// | intended to be used from the outside.
|
|
@@ -6722,11 +7012,29 @@ class drawutilsgl {
|
|
|
6722
7012
|
* @param {XYCoords} center - The center of the crosshair.
|
|
6723
7013
|
* @param {number} radius - The radius of the crosshair.
|
|
6724
7014
|
* @param {string} color - The CSS color to draw the crosshair with.
|
|
7015
|
+
* @param {number=0.5} lineWidth - (optional, default=0.5) The line width to use.
|
|
7016
|
+
* @return {void}
|
|
7017
|
+
* @instance
|
|
7018
|
+
* @memberof drawutils
|
|
7019
|
+
*/
|
|
7020
|
+
crosshair(center, radius, color, lineWidth) {
|
|
7021
|
+
// NOT YET IMPLEMENTED
|
|
7022
|
+
}
|
|
7023
|
+
/**
|
|
7024
|
+
* Draw a cross with diagonal axes with given radius, color and lineWidth at the given position.<br>
|
|
7025
|
+
* <br>
|
|
7026
|
+
* Note that the x's radius will not be affected by scaling.
|
|
7027
|
+
*
|
|
7028
|
+
* @method crosshair
|
|
7029
|
+
* @param {XYCoords} center - The center of the crosshair.
|
|
7030
|
+
* @param {number} radius - The radius of the crosshair.
|
|
7031
|
+
* @param {string} color - The CSS color to draw the crosshair with.
|
|
7032
|
+
* @param {number=1} lineWidth - (optional, default=1.0) The line width to use.
|
|
6725
7033
|
* @return {void}
|
|
6726
7034
|
* @instance
|
|
6727
7035
|
* @memberof drawutils
|
|
6728
7036
|
*/
|
|
6729
|
-
|
|
7037
|
+
cross(center, radius, color, lineWidth) {
|
|
6730
7038
|
// NOT YET IMPLEMENTED
|
|
6731
7039
|
}
|
|
6732
7040
|
/**
|
|
@@ -6966,7 +7274,9 @@ class GLU {
|
|
|
6966
7274
|
* @modified 2020-12-28 Added the `getArea` function.
|
|
6967
7275
|
* @modified 2021-01-20 Added UID.
|
|
6968
7276
|
* @modified 2021-01-22 Always updating circumcircle when retieving it.
|
|
6969
|
-
* @
|
|
7277
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
7278
|
+
* @modified 2022-02-02 Cleared the `Triangle.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
7279
|
+
* @version 2.6.0
|
|
6970
7280
|
*
|
|
6971
7281
|
* @file Triangle
|
|
6972
7282
|
* @fileoverview A simple triangle class: three vertices.
|
|
@@ -7027,7 +7337,6 @@ class Triangle {
|
|
|
7027
7337
|
throw `Cannot create triangle from array with less than three vertices (${arr.length})`;
|
|
7028
7338
|
return new Triangle(arr[0], arr[1], arr[2]);
|
|
7029
7339
|
}
|
|
7030
|
-
;
|
|
7031
7340
|
/**
|
|
7032
7341
|
* Get the area of this triangle. The returned area is never negative.
|
|
7033
7342
|
*
|
|
@@ -7043,7 +7352,6 @@ class Triangle {
|
|
|
7043
7352
|
getArea() {
|
|
7044
7353
|
return Math.abs(Triangle.utils.signedArea(this.a.x, this.a.y, this.b.x, this.b.y, this.c.x, this.c.y));
|
|
7045
7354
|
}
|
|
7046
|
-
;
|
|
7047
7355
|
/**
|
|
7048
7356
|
* Get the centroid of this triangle.
|
|
7049
7357
|
*
|
|
@@ -7057,7 +7365,6 @@ class Triangle {
|
|
|
7057
7365
|
getCentroid() {
|
|
7058
7366
|
return new Vertex((this.a.x + this.b.x + this.c.x) / 3, (this.a.y + this.b.y + this.c.y) / 3);
|
|
7059
7367
|
}
|
|
7060
|
-
;
|
|
7061
7368
|
/**
|
|
7062
7369
|
* Scale the triangle towards its centroid.
|
|
7063
7370
|
*
|
|
@@ -7074,7 +7381,6 @@ class Triangle {
|
|
|
7074
7381
|
this.c.scale(factor, centroid);
|
|
7075
7382
|
return this;
|
|
7076
7383
|
}
|
|
7077
|
-
;
|
|
7078
7384
|
/**
|
|
7079
7385
|
* Get the circumcircle of this triangle.
|
|
7080
7386
|
*
|
|
@@ -7091,11 +7397,10 @@ class Triangle {
|
|
|
7091
7397
|
* @memberof Triangle
|
|
7092
7398
|
*/
|
|
7093
7399
|
getCircumcircle() {
|
|
7094
|
-
// if( !this.center || !this.radius )
|
|
7400
|
+
// if( !this.center || !this.radius )
|
|
7095
7401
|
this.calcCircumcircle();
|
|
7096
7402
|
return new Circle(this.center.clone(), this.radius);
|
|
7097
7403
|
}
|
|
7098
|
-
;
|
|
7099
7404
|
/**
|
|
7100
7405
|
* Check if this triangle and the passed triangle share an
|
|
7101
7406
|
* adjacent edge.
|
|
@@ -7115,7 +7420,6 @@ class Triangle {
|
|
|
7115
7420
|
var c = this.c.equals(tri.a) || this.c.equals(tri.b) || this.c.equals(tri.c);
|
|
7116
7421
|
return (a && b) || (a && c) || (b && c);
|
|
7117
7422
|
}
|
|
7118
|
-
;
|
|
7119
7423
|
/**
|
|
7120
7424
|
* Get that vertex of this triangle (a,b,c) that is not vert1 nor vert2 of
|
|
7121
7425
|
* the passed two.
|
|
@@ -7128,14 +7432,13 @@ class Triangle {
|
|
|
7128
7432
|
* @memberof Triangle
|
|
7129
7433
|
*/
|
|
7130
7434
|
getThirdVertex(vert1, vert2) {
|
|
7131
|
-
if (this.a.equals(vert1) && this.b.equals(vert2) || this.a.equals(vert2) && this.b.equals(vert1))
|
|
7435
|
+
if ((this.a.equals(vert1) && this.b.equals(vert2)) || (this.a.equals(vert2) && this.b.equals(vert1)))
|
|
7132
7436
|
return this.c;
|
|
7133
|
-
if (this.b.equals(vert1) && this.c.equals(vert2) || this.b.equals(vert2) && this.c.equals(vert1))
|
|
7437
|
+
if ((this.b.equals(vert1) && this.c.equals(vert2)) || (this.b.equals(vert2) && this.c.equals(vert1)))
|
|
7134
7438
|
return this.a;
|
|
7135
7439
|
//if( this.c.equals(vert1) && this.a.equals(vert2) || this.c.equals(vert2) && this.a.equals(vert1) )
|
|
7136
7440
|
return this.b;
|
|
7137
7441
|
}
|
|
7138
|
-
;
|
|
7139
7442
|
/**
|
|
7140
7443
|
* Re-compute the circumcircle of this triangle (if the vertices
|
|
7141
7444
|
* have changed).
|
|
@@ -7175,8 +7478,7 @@ class Triangle {
|
|
|
7175
7478
|
}
|
|
7176
7479
|
this.radius_squared = dx * dx + dy * dy;
|
|
7177
7480
|
this.radius = Math.sqrt(this.radius_squared);
|
|
7178
|
-
}
|
|
7179
|
-
; // END calcCircumcircle
|
|
7481
|
+
} // END calcCircumcircle
|
|
7180
7482
|
/**
|
|
7181
7483
|
* Check if the passed vertex is inside this triangle's
|
|
7182
7484
|
* circumcircle.
|
|
@@ -7191,9 +7493,8 @@ class Triangle {
|
|
|
7191
7493
|
const dx = this.center.x - v.x;
|
|
7192
7494
|
const dy = this.center.y - v.y;
|
|
7193
7495
|
const dist_squared = dx * dx + dy * dy;
|
|
7194
|
-
return
|
|
7496
|
+
return dist_squared <= this.radius_squared;
|
|
7195
7497
|
}
|
|
7196
|
-
;
|
|
7197
7498
|
/**
|
|
7198
7499
|
* Get the rectangular bounds for this triangle.
|
|
7199
7500
|
*
|
|
@@ -7205,7 +7506,6 @@ class Triangle {
|
|
|
7205
7506
|
bounds() {
|
|
7206
7507
|
return new Bounds(new Vertex(Triangle.utils.min3(this.a.x, this.b.x, this.c.x), Triangle.utils.min3(this.a.y, this.b.y, this.c.y)), new Vertex(Triangle.utils.max3(this.a.x, this.b.x, this.c.x), Triangle.utils.max3(this.a.y, this.b.y, this.c.y)));
|
|
7207
7508
|
}
|
|
7208
|
-
;
|
|
7209
7509
|
/**
|
|
7210
7510
|
* Convert this triangle to a polygon instance.
|
|
7211
7511
|
*
|
|
@@ -7219,7 +7519,6 @@ class Triangle {
|
|
|
7219
7519
|
toPolygon() {
|
|
7220
7520
|
return new Polygon([this.a, this.b, this.c]);
|
|
7221
7521
|
}
|
|
7222
|
-
;
|
|
7223
7522
|
/**
|
|
7224
7523
|
* Get the determinant of this triangle.
|
|
7225
7524
|
*
|
|
@@ -7232,7 +7531,6 @@ class Triangle {
|
|
|
7232
7531
|
// (b.y - a.y)*(c.x - b.x) - (c.y - b.y)*(b.x - a.x);
|
|
7233
7532
|
return (this.b.y - this.a.y) * (this.c.x - this.b.x) - (this.c.y - this.b.y) * (this.b.x - this.a.x);
|
|
7234
7533
|
}
|
|
7235
|
-
;
|
|
7236
7534
|
/**
|
|
7237
7535
|
* Checks if the passed vertex (p) is inside this triangle.
|
|
7238
7536
|
*
|
|
@@ -7247,7 +7545,6 @@ class Triangle {
|
|
|
7247
7545
|
containsPoint(p) {
|
|
7248
7546
|
return Triangle.utils.pointIsInTriangle(p.x, p.y, this.a.x, this.a.y, this.b.x, this.b.y, this.c.x, this.c.y);
|
|
7249
7547
|
}
|
|
7250
|
-
;
|
|
7251
7548
|
/**
|
|
7252
7549
|
* Get that inner triangle which defines the maximal incircle.
|
|
7253
7550
|
*
|
|
@@ -7266,7 +7563,6 @@ class Triangle {
|
|
|
7266
7563
|
const circleIntersC = lineC.getClosestPoint(intersection);
|
|
7267
7564
|
return new Triangle(circleIntersA, circleIntersB, circleIntersC);
|
|
7268
7565
|
}
|
|
7269
|
-
;
|
|
7270
7566
|
/**
|
|
7271
7567
|
* Get the incircle of this triangle. That is the circle that touches each side
|
|
7272
7568
|
* of this triangle in exactly one point.
|
|
@@ -7278,7 +7574,6 @@ class Triangle {
|
|
|
7278
7574
|
getIncircle() {
|
|
7279
7575
|
return this.getIncircularTriangle().getCircumcircle();
|
|
7280
7576
|
}
|
|
7281
|
-
;
|
|
7282
7577
|
/**
|
|
7283
7578
|
* Get the incenter of this triangle (which is the center of the circumcircle).
|
|
7284
7579
|
*
|
|
@@ -7292,7 +7587,6 @@ class Triangle {
|
|
|
7292
7587
|
this.calcCircumcircle();
|
|
7293
7588
|
return this.center.clone();
|
|
7294
7589
|
}
|
|
7295
|
-
;
|
|
7296
7590
|
/**
|
|
7297
7591
|
* Converts this triangle into a human-readable string.
|
|
7298
7592
|
*
|
|
@@ -7302,46 +7596,19 @@ class Triangle {
|
|
|
7302
7596
|
* @memberof Triangle
|
|
7303
7597
|
*/
|
|
7304
7598
|
toString() {
|
|
7305
|
-
return
|
|
7599
|
+
return "{ a : " + this.a.toString() + ", b : " + this.b.toString() + ", c : " + this.c.toString() + "}";
|
|
7306
7600
|
}
|
|
7307
|
-
;
|
|
7308
7601
|
/**
|
|
7309
|
-
*
|
|
7310
|
-
*
|
|
7311
|
-
*
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
|
|
7317
|
-
|
|
7318
|
-
toSVGString(options) {
|
|
7319
|
-
options = options || {};
|
|
7320
|
-
var buffer = [];
|
|
7321
|
-
buffer.push('<path');
|
|
7322
|
-
if (options.className)
|
|
7323
|
-
buffer.push(' class="' + options.className + '"');
|
|
7324
|
-
buffer.push(' d="');
|
|
7325
|
-
var vertices = [this.a, this.b, this.c];
|
|
7326
|
-
if (vertices.length > 0) {
|
|
7327
|
-
buffer.push('M ');
|
|
7328
|
-
buffer.push(vertices[0].x);
|
|
7329
|
-
buffer.push(' ');
|
|
7330
|
-
buffer.push(vertices[0].y);
|
|
7331
|
-
for (var i = 1; i < vertices.length; i++) {
|
|
7332
|
-
buffer.push(' L ');
|
|
7333
|
-
buffer.push(vertices[i].x);
|
|
7334
|
-
buffer.push(' ');
|
|
7335
|
-
buffer.push(vertices[i].y);
|
|
7336
|
-
}
|
|
7337
|
-
//if( !this.isOpen ) {
|
|
7338
|
-
buffer.push(' Z');
|
|
7339
|
-
//}
|
|
7340
|
-
}
|
|
7341
|
-
buffer.push('" />');
|
|
7342
|
-
return buffer.join('');
|
|
7602
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
7603
|
+
* After calling this function the object might not hold valid data any more and
|
|
7604
|
+
* should not be used.
|
|
7605
|
+
*/
|
|
7606
|
+
destroy() {
|
|
7607
|
+
this.a.destroy();
|
|
7608
|
+
this.b.destroy();
|
|
7609
|
+
this.c.destroy();
|
|
7610
|
+
this.isDestroyed = true;
|
|
7343
7611
|
}
|
|
7344
|
-
;
|
|
7345
7612
|
}
|
|
7346
7613
|
/**
|
|
7347
7614
|
* An epsilon for comparison.
|
|
@@ -7353,10 +7620,10 @@ Triangle.EPSILON = 1.0e-6;
|
|
|
7353
7620
|
Triangle.utils = {
|
|
7354
7621
|
// Used in the bounds() function.
|
|
7355
7622
|
max3(a, b, c) {
|
|
7356
|
-
return
|
|
7623
|
+
return a >= b && a >= c ? a : b >= a && b >= c ? b : c;
|
|
7357
7624
|
},
|
|
7358
7625
|
min3(a, b, c) {
|
|
7359
|
-
return
|
|
7626
|
+
return a <= b && a <= c ? a : b <= a && b <= c ? b : c;
|
|
7360
7627
|
},
|
|
7361
7628
|
signedArea(p0x, p0y, p1x, p1y, p2x, p2y) {
|
|
7362
7629
|
return 0.5 * (-p1y * p2x + p0y * (-p1x + p2x) + p0x * (p1y - p2y) + p1x * p2y);
|
|
@@ -7372,9 +7639,9 @@ Triangle.utils = {
|
|
|
7372
7639
|
// http://stackoverflow.com/questions/2049582/how-to-determine-a-point-in-a-2d-triangle
|
|
7373
7640
|
// var area : number = 1/2*(-p1y*p2x + p0y*(-p1x + p2x) + p0x*(p1y - p2y) + p1x*p2y);
|
|
7374
7641
|
var area = Triangle.utils.signedArea(p0x, p0y, p1x, p1y, p2x, p2y);
|
|
7375
|
-
var s = 1 / (2 * area) * (p0y * p2x - p0x * p2y + (p2y - p0y) * px + (p0x - p2x) * py);
|
|
7376
|
-
var t = 1 / (2 * area) * (p0x * p1y - p0y * p1x + (p0y - p1y) * px + (p1x - p0x) * py);
|
|
7377
|
-
return s > 0 && t > 0 &&
|
|
7642
|
+
var s = (1 / (2 * area)) * (p0y * p2x - p0x * p2y + (p2y - p0y) * px + (p0x - p2x) * py);
|
|
7643
|
+
var t = (1 / (2 * area)) * (p0x * p1y - p0y * p1x + (p0y - p1y) * px + (p1x - p0x) * py);
|
|
7644
|
+
return s > 0 && t > 0 && 1 - s - t > 0;
|
|
7378
7645
|
}
|
|
7379
7646
|
};
|
|
7380
7647
|
|
|
@@ -7545,7 +7812,8 @@ Grid.utils = {
|
|
|
7545
7812
|
* @modified 2020-07-28 Changed the `delete` key code from 8 to 46.
|
|
7546
7813
|
* @modified 2020-10-04 Changed `window` to `globalThis`.
|
|
7547
7814
|
* @modified 2020-10-04 Added extended JSDoc.
|
|
7548
|
-
* @
|
|
7815
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
7816
|
+
* @version 1.1.0
|
|
7549
7817
|
*
|
|
7550
7818
|
* @file KeyHandler
|
|
7551
7819
|
* @public
|
|
@@ -7576,7 +7844,7 @@ class KeyHandler {
|
|
|
7576
7844
|
* @memberof KeyHandler
|
|
7577
7845
|
* @param {HTMLElement} options.element (optional) The HTML element to listen on; if null then 'window' will be used.
|
|
7578
7846
|
* @param {boolean} options.trackAll (optional) Set to true if you want to keep track of _all_ keys (keyStatus).
|
|
7579
|
-
|
|
7847
|
+
**/
|
|
7580
7848
|
constructor(options) {
|
|
7581
7849
|
this.downListeners = [];
|
|
7582
7850
|
this.pressListeners = [];
|
|
@@ -7595,7 +7863,6 @@ class KeyHandler {
|
|
|
7595
7863
|
// Install the listeners
|
|
7596
7864
|
this.installListeners();
|
|
7597
7865
|
}
|
|
7598
|
-
;
|
|
7599
7866
|
/**
|
|
7600
7867
|
* A helper function to fire key events from this KeyHandler.
|
|
7601
7868
|
*
|
|
@@ -7613,7 +7880,6 @@ class KeyHandler {
|
|
|
7613
7880
|
}
|
|
7614
7881
|
return hasListener;
|
|
7615
7882
|
}
|
|
7616
|
-
;
|
|
7617
7883
|
/**
|
|
7618
7884
|
* Internal function to fire a new keydown event to all listeners.
|
|
7619
7885
|
* You should not call this function on your own unless you know what you do.
|
|
@@ -7629,10 +7895,9 @@ class KeyHandler {
|
|
|
7629
7895
|
fireDownEvent(e, handler) {
|
|
7630
7896
|
if (handler.fireEvent(e, handler.downListeners) || handler.trackAllKeys) {
|
|
7631
7897
|
// Down event has listeners. Update key state.
|
|
7632
|
-
handler.keyStates[e.keyCode] =
|
|
7898
|
+
handler.keyStates[e.keyCode] = "down";
|
|
7633
7899
|
}
|
|
7634
7900
|
}
|
|
7635
|
-
;
|
|
7636
7901
|
/**
|
|
7637
7902
|
* Internal function to fire a new keypress event to all listeners.
|
|
7638
7903
|
* You should not call this function on your own unless you know what you do.
|
|
@@ -7648,7 +7913,6 @@ class KeyHandler {
|
|
|
7648
7913
|
firePressEvent(e, handler) {
|
|
7649
7914
|
handler.fireEvent(e, handler.pressListeners);
|
|
7650
7915
|
}
|
|
7651
|
-
;
|
|
7652
7916
|
/**
|
|
7653
7917
|
* Internal function to fire a new keyup event to all listeners.
|
|
7654
7918
|
* You should not call this function on your own unless you know what you do.
|
|
@@ -7667,20 +7931,18 @@ class KeyHandler {
|
|
|
7667
7931
|
delete handler.keyStates[e.keyCode];
|
|
7668
7932
|
}
|
|
7669
7933
|
}
|
|
7670
|
-
;
|
|
7671
7934
|
/**
|
|
7672
7935
|
* Resolve the key/name code.
|
|
7673
7936
|
*/
|
|
7674
7937
|
static key2code(key) {
|
|
7675
|
-
if (typeof key ==
|
|
7938
|
+
if (typeof key == "number")
|
|
7676
7939
|
return key;
|
|
7677
|
-
if (typeof key !=
|
|
7940
|
+
if (typeof key != "string")
|
|
7678
7941
|
throw "Unknown key name or key type (should be a string or integer): " + key;
|
|
7679
7942
|
if (KeyHandler.KEY_CODES[key])
|
|
7680
7943
|
return KeyHandler.KEY_CODES[key];
|
|
7681
7944
|
throw "Unknown key (cannot resolve key code): " + key;
|
|
7682
7945
|
}
|
|
7683
|
-
;
|
|
7684
7946
|
/**
|
|
7685
7947
|
* Install the required listeners into the initially passed element.
|
|
7686
7948
|
*
|
|
@@ -7689,20 +7951,24 @@ class KeyHandler {
|
|
|
7689
7951
|
*/
|
|
7690
7952
|
installListeners() {
|
|
7691
7953
|
var _self = this;
|
|
7692
|
-
this.element.addEventListener(
|
|
7693
|
-
|
|
7694
|
-
|
|
7954
|
+
this.element.addEventListener("keydown", (this._keyDownListener = (e) => {
|
|
7955
|
+
_self.fireDownEvent(e, _self);
|
|
7956
|
+
}));
|
|
7957
|
+
this.element.addEventListener("keypress", (this._keyPressListener = (e) => {
|
|
7958
|
+
_self.firePressEvent(e, _self);
|
|
7959
|
+
}));
|
|
7960
|
+
this.element.addEventListener("keyup", (this._keyUpListener = (e) => {
|
|
7961
|
+
_self.fireUpEvent(e, _self);
|
|
7962
|
+
}));
|
|
7695
7963
|
}
|
|
7696
|
-
;
|
|
7697
7964
|
/**
|
|
7698
7965
|
* Remove all installed event listeners from the underlying element.
|
|
7699
7966
|
*/
|
|
7700
7967
|
releaseListeners() {
|
|
7701
|
-
this.element.removeEventListener(
|
|
7702
|
-
this.element.removeEventListener(
|
|
7703
|
-
this.element.removeEventListener(
|
|
7968
|
+
this.element.removeEventListener("keydown", this._keyDownListener);
|
|
7969
|
+
this.element.removeEventListener("keypress", this._keyPressListener);
|
|
7970
|
+
this.element.removeEventListener("keyup", this._keyUpListener);
|
|
7704
7971
|
}
|
|
7705
|
-
;
|
|
7706
7972
|
/**
|
|
7707
7973
|
* Listen for key down. This function allows chaining.
|
|
7708
7974
|
*
|
|
@@ -7719,7 +7985,6 @@ class KeyHandler {
|
|
|
7719
7985
|
this.downListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
|
|
7720
7986
|
return this;
|
|
7721
7987
|
}
|
|
7722
|
-
;
|
|
7723
7988
|
/**
|
|
7724
7989
|
* Listen for key press.
|
|
7725
7990
|
*
|
|
@@ -7736,7 +8001,6 @@ class KeyHandler {
|
|
|
7736
8001
|
this.pressListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
|
|
7737
8002
|
return this;
|
|
7738
8003
|
}
|
|
7739
|
-
;
|
|
7740
8004
|
/**
|
|
7741
8005
|
* Listen for key up.
|
|
7742
8006
|
*
|
|
@@ -7753,23 +8017,31 @@ class KeyHandler {
|
|
|
7753
8017
|
this.upListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
|
|
7754
8018
|
return this;
|
|
7755
8019
|
}
|
|
7756
|
-
;
|
|
7757
8020
|
/**
|
|
7758
8021
|
* Check if a specific key is currently held pressed.
|
|
7759
8022
|
*
|
|
7760
8023
|
* @param {string|number} key - Any key identifier, key code or one from the KEY_CODES list.
|
|
7761
8024
|
*/
|
|
7762
8025
|
isDown(key) {
|
|
7763
|
-
if (typeof key ==
|
|
8026
|
+
if (typeof key == "number")
|
|
7764
8027
|
return this.keyStates[key] ? true : false;
|
|
7765
8028
|
else
|
|
7766
8029
|
return this.keyStates[KeyHandler.key2code(key)] ? true : false;
|
|
7767
8030
|
}
|
|
8031
|
+
/**
|
|
8032
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
8033
|
+
* After calling this function the object might not hold valid data any more and
|
|
8034
|
+
* should not be used any more.
|
|
8035
|
+
*/
|
|
8036
|
+
destroy() {
|
|
8037
|
+
this.releaseListeners();
|
|
8038
|
+
}
|
|
7768
8039
|
}
|
|
7769
8040
|
/**
|
|
7770
8041
|
* Source:
|
|
7771
8042
|
* https://keycode.info/
|
|
7772
8043
|
*/
|
|
8044
|
+
// prettier-ignore
|
|
7773
8045
|
KeyHandler.KEY_CODES = {
|
|
7774
8046
|
'break': 3,
|
|
7775
8047
|
'backspace': 8,
|
|
@@ -8086,41 +8358,41 @@ class MouseHandler {
|
|
|
8086
8358
|
// | drag offset, ...) to the callbacks.
|
|
8087
8359
|
// +-------------------------------------------------
|
|
8088
8360
|
const _self = this;
|
|
8089
|
-
this.handlers[
|
|
8361
|
+
this.handlers["mousemove"] = (e) => {
|
|
8090
8362
|
if (_self.listeners.mousemove)
|
|
8091
|
-
_self.listeners.mousemove(_self.mkParams(e,
|
|
8363
|
+
_self.listeners.mousemove(_self.mkParams(e, "mousemove"));
|
|
8092
8364
|
if (_self.mouseDragPos && _self.listeners.drag)
|
|
8093
|
-
_self.listeners.drag(_self.mkParams(e,
|
|
8365
|
+
_self.listeners.drag(_self.mkParams(e, "drag"));
|
|
8094
8366
|
if (_self.mouseDownPos)
|
|
8095
8367
|
_self.mouseDragPos = _self.relPos(e);
|
|
8096
8368
|
};
|
|
8097
|
-
this.handlers[
|
|
8369
|
+
this.handlers["mouseup"] = (e) => {
|
|
8098
8370
|
if (_self.listeners.mouseup)
|
|
8099
|
-
_self.listeners.mouseup(_self.mkParams(e,
|
|
8371
|
+
_self.listeners.mouseup(_self.mkParams(e, "mouseup"));
|
|
8100
8372
|
_self.mouseDragPos = undefined;
|
|
8101
8373
|
_self.mouseDownPos = undefined;
|
|
8102
8374
|
_self.mouseButton = -1;
|
|
8103
8375
|
};
|
|
8104
|
-
this.handlers[
|
|
8376
|
+
this.handlers["mousedown"] = (e) => {
|
|
8105
8377
|
_self.mouseDragPos = _self.relPos(e);
|
|
8106
8378
|
_self.mouseDownPos = _self.relPos(e);
|
|
8107
8379
|
_self.mouseButton = e.button;
|
|
8108
8380
|
if (_self.listeners.mousedown)
|
|
8109
|
-
_self.listeners.mousedown(_self.mkParams(e,
|
|
8381
|
+
_self.listeners.mousedown(_self.mkParams(e, "mousedown"));
|
|
8110
8382
|
};
|
|
8111
|
-
this.handlers[
|
|
8383
|
+
this.handlers["click"] = (e) => {
|
|
8112
8384
|
if (_self.listeners.click)
|
|
8113
|
-
_self.listeners.click(_self.mkParams(e,
|
|
8385
|
+
_self.listeners.click(_self.mkParams(e, "click"));
|
|
8114
8386
|
};
|
|
8115
|
-
this.handlers[
|
|
8387
|
+
this.handlers["wheel"] = (e) => {
|
|
8116
8388
|
if (_self.listeners.wheel)
|
|
8117
|
-
_self.listeners.wheel(_self.mkParams(e,
|
|
8389
|
+
_self.listeners.wheel(_self.mkParams(e, "wheel"));
|
|
8118
8390
|
};
|
|
8119
|
-
this.element.addEventListener(
|
|
8120
|
-
this.element.addEventListener(
|
|
8121
|
-
this.element.addEventListener(
|
|
8122
|
-
this.element.addEventListener(
|
|
8123
|
-
this.element.addEventListener(
|
|
8391
|
+
this.element.addEventListener("mousemove", this.handlers["mousemove"]);
|
|
8392
|
+
this.element.addEventListener("mouseup", this.handlers["mouseup"]);
|
|
8393
|
+
this.element.addEventListener("mousedown", this.handlers["mousedown"]);
|
|
8394
|
+
this.element.addEventListener("click", this.handlers["click"]);
|
|
8395
|
+
this.element.addEventListener("wheel", this.handlers["wheel"]);
|
|
8124
8396
|
}
|
|
8125
8397
|
/**
|
|
8126
8398
|
* Get relative position from the given MouseEvent.
|
|
@@ -8133,11 +8405,8 @@ class MouseHandler {
|
|
|
8133
8405
|
* @return {XYCoords} The relative mouse coordinates.
|
|
8134
8406
|
*/
|
|
8135
8407
|
relPos(e) {
|
|
8136
|
-
return { x: e.offsetX,
|
|
8137
|
-
y: e.offsetY
|
|
8138
|
-
};
|
|
8408
|
+
return { x: e.offsetX, y: e.offsetY };
|
|
8139
8409
|
}
|
|
8140
|
-
;
|
|
8141
8410
|
/**
|
|
8142
8411
|
* Build the extended event params.
|
|
8143
8412
|
*
|
|
@@ -8163,8 +8432,8 @@ class MouseHandler {
|
|
|
8163
8432
|
rightButton: this.mouseButton == 2,
|
|
8164
8433
|
mouseDownPos: this.mouseDownPos,
|
|
8165
8434
|
draggedFrom: this.mouseDragPos,
|
|
8166
|
-
wasDragged:
|
|
8167
|
-
dragAmount:
|
|
8435
|
+
wasDragged: this.mouseDownPos != null && (this.mouseDownPos.x != rel.x || this.mouseDownPos.y != rel.y),
|
|
8436
|
+
dragAmount: this.mouseDownPos != null ? { x: rel.x - this.mouseDragPos.x, y: rel.y - this.mouseDragPos.y } : { x: 0, y: 0 }
|
|
8168
8437
|
};
|
|
8169
8438
|
return xEvent;
|
|
8170
8439
|
}
|
|
@@ -8215,14 +8484,13 @@ class MouseHandler {
|
|
|
8215
8484
|
*/
|
|
8216
8485
|
drag(callback) {
|
|
8217
8486
|
if (this.listeners.drag)
|
|
8218
|
-
this.throwAlreadyInstalled(
|
|
8487
|
+
this.throwAlreadyInstalled("drag");
|
|
8219
8488
|
this.listeners.drag = callback;
|
|
8220
|
-
this.listenFor(
|
|
8221
|
-
this.listenFor(
|
|
8222
|
-
this.listenFor(
|
|
8489
|
+
this.listenFor("mousedown");
|
|
8490
|
+
this.listenFor("mousemove");
|
|
8491
|
+
this.listenFor("mouseup");
|
|
8223
8492
|
return this;
|
|
8224
8493
|
}
|
|
8225
|
-
;
|
|
8226
8494
|
/**
|
|
8227
8495
|
* Installer function to listen for a specific event: mouse-move.
|
|
8228
8496
|
* Pass your callbacks here.
|
|
@@ -8237,12 +8505,11 @@ class MouseHandler {
|
|
|
8237
8505
|
*/
|
|
8238
8506
|
move(callback) {
|
|
8239
8507
|
if (this.listeners.mousemove)
|
|
8240
|
-
this.throwAlreadyInstalled(
|
|
8241
|
-
this.listenFor(
|
|
8508
|
+
this.throwAlreadyInstalled("mousemove");
|
|
8509
|
+
this.listenFor("mousemove");
|
|
8242
8510
|
this.listeners.mousemove = callback;
|
|
8243
8511
|
return this;
|
|
8244
8512
|
}
|
|
8245
|
-
;
|
|
8246
8513
|
/**
|
|
8247
8514
|
* Installer function to listen for a specific event: mouse-up.
|
|
8248
8515
|
* Pass your callbacks here.
|
|
@@ -8257,12 +8524,11 @@ class MouseHandler {
|
|
|
8257
8524
|
*/
|
|
8258
8525
|
up(callback) {
|
|
8259
8526
|
if (this.listeners.mouseup)
|
|
8260
|
-
this.throwAlreadyInstalled(
|
|
8261
|
-
this.listenFor(
|
|
8527
|
+
this.throwAlreadyInstalled("mouseup");
|
|
8528
|
+
this.listenFor("mouseup");
|
|
8262
8529
|
this.listeners.mouseup = callback;
|
|
8263
8530
|
return this;
|
|
8264
8531
|
}
|
|
8265
|
-
;
|
|
8266
8532
|
/**
|
|
8267
8533
|
* Installer function to listen for a specific event: mouse-down.
|
|
8268
8534
|
* Pass your callbacks here.
|
|
@@ -8277,12 +8543,11 @@ class MouseHandler {
|
|
|
8277
8543
|
*/
|
|
8278
8544
|
down(callback) {
|
|
8279
8545
|
if (this.listeners.mousedown)
|
|
8280
|
-
this.throwAlreadyInstalled(
|
|
8281
|
-
this.listenFor(
|
|
8546
|
+
this.throwAlreadyInstalled("mousedown");
|
|
8547
|
+
this.listenFor("mousedown");
|
|
8282
8548
|
this.listeners.mousedown = callback;
|
|
8283
8549
|
return this;
|
|
8284
8550
|
}
|
|
8285
|
-
;
|
|
8286
8551
|
/**
|
|
8287
8552
|
* Installer function to listen for a specific event: mouse-click.
|
|
8288
8553
|
* Pass your callbacks here.
|
|
@@ -8297,12 +8562,11 @@ class MouseHandler {
|
|
|
8297
8562
|
*/
|
|
8298
8563
|
click(callback) {
|
|
8299
8564
|
if (this.listeners.click)
|
|
8300
|
-
this.throwAlreadyInstalled(
|
|
8301
|
-
this.listenFor(
|
|
8565
|
+
this.throwAlreadyInstalled("click");
|
|
8566
|
+
this.listenFor("click");
|
|
8302
8567
|
this.listeners.click = callback;
|
|
8303
8568
|
return this;
|
|
8304
8569
|
}
|
|
8305
|
-
;
|
|
8306
8570
|
/**
|
|
8307
8571
|
* Installer function to listen for a specific event: mouse-wheel.
|
|
8308
8572
|
* Pass your callbacks here.
|
|
@@ -8317,12 +8581,11 @@ class MouseHandler {
|
|
|
8317
8581
|
*/
|
|
8318
8582
|
wheel(callback) {
|
|
8319
8583
|
if (this.listeners.wheel)
|
|
8320
|
-
this.throwAlreadyInstalled(
|
|
8321
|
-
this.listenFor(
|
|
8584
|
+
this.throwAlreadyInstalled("wheel");
|
|
8585
|
+
this.listenFor("wheel");
|
|
8322
8586
|
this.listeners.wheel = callback;
|
|
8323
8587
|
return this;
|
|
8324
8588
|
}
|
|
8325
|
-
;
|
|
8326
8589
|
/**
|
|
8327
8590
|
* An internal function to throw events.
|
|
8328
8591
|
*
|
|
@@ -8336,7 +8599,6 @@ class MouseHandler {
|
|
|
8336
8599
|
throwAlreadyInstalled(name) {
|
|
8337
8600
|
throw `This MouseHandler already has a '${name}' callback. To keep the code simple there is only room for one.`;
|
|
8338
8601
|
}
|
|
8339
|
-
;
|
|
8340
8602
|
/**
|
|
8341
8603
|
* Call this when your work is done.
|
|
8342
8604
|
*
|
|
@@ -8349,16 +8611,16 @@ class MouseHandler {
|
|
|
8349
8611
|
* @return {void}
|
|
8350
8612
|
*/
|
|
8351
8613
|
destroy() {
|
|
8352
|
-
this.unlistenFor(
|
|
8353
|
-
this.unlistenFor(
|
|
8354
|
-
this.unlistenFor(
|
|
8355
|
-
this.unlistenFor(
|
|
8356
|
-
this.unlistenFor(
|
|
8357
|
-
this.element.removeEventListener(
|
|
8358
|
-
this.element.removeEventListener(
|
|
8359
|
-
this.element.removeEventListener(
|
|
8360
|
-
this.element.removeEventListener(
|
|
8361
|
-
this.element.removeEventListener(
|
|
8614
|
+
this.unlistenFor("mousedown");
|
|
8615
|
+
this.unlistenFor("mousemove");
|
|
8616
|
+
this.unlistenFor("moseup");
|
|
8617
|
+
this.unlistenFor("click");
|
|
8618
|
+
this.unlistenFor("wheel");
|
|
8619
|
+
this.element.removeEventListener("mousemove", this.handlers["mousemove"]);
|
|
8620
|
+
this.element.removeEventListener("mouseup", this.handlers["mousedown"]);
|
|
8621
|
+
this.element.removeEventListener("mousedown", this.handlers["mousedown"]);
|
|
8622
|
+
this.element.removeEventListener("click", this.handlers["click"]);
|
|
8623
|
+
this.element.removeEventListener("wheel", this.handlers["wheel"]);
|
|
8362
8624
|
}
|
|
8363
8625
|
}
|
|
8364
8626
|
|
|
@@ -8368,7 +8630,9 @@ class MouseHandler {
|
|
|
8368
8630
|
* @modified 2019-03-23 Added JSDoc tags.
|
|
8369
8631
|
* @modified 2020-03-25 Ported this class from vanilla-JS to Typescript.
|
|
8370
8632
|
* @modified 2021-01-20 Added UID.
|
|
8371
|
-
* @
|
|
8633
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
8634
|
+
* @modified 2022-02-02 Cleared the `PBImage.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
8635
|
+
* @version 1.2.0
|
|
8372
8636
|
*
|
|
8373
8637
|
* @file PBImage
|
|
8374
8638
|
* @fileoverview As native Image objects have only a position and with
|
|
@@ -8403,28 +8667,23 @@ class PBImage {
|
|
|
8403
8667
|
this.upperLeft = upperLeft;
|
|
8404
8668
|
this.lowerRight = lowerRight;
|
|
8405
8669
|
}
|
|
8406
|
-
;
|
|
8407
8670
|
/**
|
|
8408
|
-
*
|
|
8409
|
-
*
|
|
8410
|
-
*
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
**/
|
|
8417
|
-
toSVGString(options) {
|
|
8418
|
-
console.warn("PBImage is not yet SVG serializable. Returning empty SVG string.");
|
|
8419
|
-
return "";
|
|
8671
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
8672
|
+
* After calling this function the object might not hold valid data any more and
|
|
8673
|
+
* should not be used.
|
|
8674
|
+
*/
|
|
8675
|
+
destroy() {
|
|
8676
|
+
this.upperLeft.destroy();
|
|
8677
|
+
this.lowerRight.destroy();
|
|
8678
|
+
this.isDestroyed = true;
|
|
8420
8679
|
}
|
|
8421
|
-
;
|
|
8422
8680
|
}
|
|
8423
8681
|
|
|
8424
8682
|
/**
|
|
8425
8683
|
* @author Ikaros Kappler
|
|
8426
8684
|
* @date 2021-11-16
|
|
8427
|
-
* @
|
|
8685
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
8686
|
+
* @version 1.1.0
|
|
8428
8687
|
**/
|
|
8429
8688
|
/**
|
|
8430
8689
|
* @classdesc A simple text element: position, fontSize, fontFamily, color, textAlign, lineHeight and rotation.
|
|
@@ -8465,18 +8724,13 @@ class PBText {
|
|
|
8465
8724
|
this.rotation = options.rotation;
|
|
8466
8725
|
}
|
|
8467
8726
|
/**
|
|
8468
|
-
*
|
|
8469
|
-
*
|
|
8470
|
-
*
|
|
8471
|
-
* @method toSVGString
|
|
8472
|
-
* @param {object=} options - An optional set of options, like 'className'.
|
|
8473
|
-
* @return {string} A string representing the SVG code for this vertex.
|
|
8474
|
-
* @instance
|
|
8475
|
-
* @memberof Circle
|
|
8727
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
8728
|
+
* After calling this function the object might not hold valid data any more and
|
|
8729
|
+
* should not be used.
|
|
8476
8730
|
*/
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8731
|
+
destroy() {
|
|
8732
|
+
this.anchor.destroy();
|
|
8733
|
+
this.isDestroyed = true;
|
|
8480
8734
|
}
|
|
8481
8735
|
} // END class
|
|
8482
8736
|
|
|
@@ -8881,7 +9135,9 @@ class AlloyFinger {
|
|
|
8881
9135
|
* @modified 2021-03-10 Added the `toCubicBezier` method.
|
|
8882
9136
|
* @modified 2021-03-15 Added `VEllipse.quarterSegmentCount` and `VEllipse.scale` functions.
|
|
8883
9137
|
* @modified 2021-03-19 Added the `VEllipse.rotate` function.
|
|
8884
|
-
* @
|
|
9138
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
9139
|
+
* @modified 2022-02-02 Cleared the `VEllipse.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
9140
|
+
* @version 1.3.0
|
|
8885
9141
|
*
|
|
8886
9142
|
* @file VEllipse
|
|
8887
9143
|
* @fileoverview Ellipses with a center and an x- and a y-axis (stored as a vertex).
|
|
@@ -9200,24 +9456,14 @@ class VEllipse {
|
|
|
9200
9456
|
return curves;
|
|
9201
9457
|
}
|
|
9202
9458
|
/**
|
|
9203
|
-
*
|
|
9204
|
-
*
|
|
9205
|
-
*
|
|
9206
|
-
* @param {object} options { className?:string }
|
|
9207
|
-
* @return string The SVG string
|
|
9459
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
9460
|
+
* After calling this function the object might not hold valid data any more and
|
|
9461
|
+
* should not be used.
|
|
9208
9462
|
*/
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9212
|
-
|
|
9213
|
-
if (options.className)
|
|
9214
|
-
buffer.push(' class="' + options.className + '"');
|
|
9215
|
-
buffer.push(' cx="' + this.center.x + '"');
|
|
9216
|
-
buffer.push(' cy="' + this.center.y + '"');
|
|
9217
|
-
buffer.push(' rx="' + this.axis.x + '"');
|
|
9218
|
-
buffer.push(' ry="' + this.axis.y + '"');
|
|
9219
|
-
buffer.push(" />");
|
|
9220
|
-
return buffer.join("");
|
|
9463
|
+
destroy() {
|
|
9464
|
+
this.center.destroy();
|
|
9465
|
+
this.axis.destroy();
|
|
9466
|
+
this.isDestroyed = true;
|
|
9221
9467
|
}
|
|
9222
9468
|
}
|
|
9223
9469
|
/**
|
|
@@ -9284,7 +9530,8 @@ VEllipse.utils = {
|
|
|
9284
9530
|
*
|
|
9285
9531
|
* @author Ikaros Kappler
|
|
9286
9532
|
* @date 2021-02-26
|
|
9287
|
-
* @
|
|
9533
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
9534
|
+
* @version 1.1.0
|
|
9288
9535
|
*/
|
|
9289
9536
|
/**
|
|
9290
9537
|
* @classdesc A class for elliptic sectors.
|
|
@@ -9370,6 +9617,15 @@ class VEllipseSector {
|
|
|
9370
9617
|
}
|
|
9371
9618
|
return curves;
|
|
9372
9619
|
}
|
|
9620
|
+
/**
|
|
9621
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
9622
|
+
* After calling this function the object might not hold valid data any more and
|
|
9623
|
+
* should not be used.
|
|
9624
|
+
*/
|
|
9625
|
+
destroy() {
|
|
9626
|
+
this.ellipse.destroy();
|
|
9627
|
+
this.isDestroyed = true;
|
|
9628
|
+
}
|
|
9373
9629
|
}
|
|
9374
9630
|
VEllipseSector.ellipseSectorUtils = {
|
|
9375
9631
|
/**
|
|
@@ -10220,7 +10476,7 @@ class PlotBoilerplate {
|
|
|
10220
10476
|
}
|
|
10221
10477
|
}
|
|
10222
10478
|
for (var i = 0; i < this.drawables.length; i++) {
|
|
10223
|
-
if (this.drawables[i] === drawable) {
|
|
10479
|
+
if (this.drawables[i] === drawable || this.drawables[i].uid === drawable.uid) {
|
|
10224
10480
|
this.drawables.splice(i, 1);
|
|
10225
10481
|
if (removeWithVertices) {
|
|
10226
10482
|
// Check if some listeners need to be removed
|
|
@@ -10332,8 +10588,9 @@ class PlotBoilerplate {
|
|
|
10332
10588
|
**/
|
|
10333
10589
|
getVertexNear(pixelPosition, pixelTolerance) {
|
|
10334
10590
|
var p = this.locatePointNear(this.transformMousePosition(pixelPosition.x, pixelPosition.y), pixelTolerance / Math.min(this.config.cssScaleX, this.config.cssScaleY));
|
|
10335
|
-
if (p && p.typeName == "vertex")
|
|
10591
|
+
if (p && p.typeName == "vertex") {
|
|
10336
10592
|
return this.vertices[p.vindex];
|
|
10593
|
+
}
|
|
10337
10594
|
return undefined;
|
|
10338
10595
|
}
|
|
10339
10596
|
/**
|
|
@@ -11599,100 +11856,5 @@ PlotBoilerplate.utils = {
|
|
|
11599
11856
|
}
|
|
11600
11857
|
}; // END utils
|
|
11601
11858
|
|
|
11602
|
-
|
|
11603
|
-
* Todos:
|
|
11604
|
-
* + use a Drawable interface
|
|
11605
|
-
* + use a SVGSerializable interface
|
|
11606
|
-
*
|
|
11607
|
-
* @require Vertex
|
|
11608
|
-
*
|
|
11609
|
-
* @deprecated THIS CLASS IS DEPRECATED. Please use the new `drawutilssvg` instead.
|
|
11610
|
-
*
|
|
11611
|
-
* @author Ikaros Kappler
|
|
11612
|
-
* @date 2018-12-04
|
|
11613
|
-
* @modified 2019-11-07 Added the 'Triangle' style class.
|
|
11614
|
-
* @modified 2019-11-13 Added the <?xml ...?> tag.
|
|
11615
|
-
* @modified 2020-03-25 Ported this class from vanilla-JS to Typescript.
|
|
11616
|
-
* @modified 2020-12-17 Added Circle and CircleSection style classes.
|
|
11617
|
-
* @modified 2021-01-26 DEPRECATION
|
|
11618
|
-
* @version 1.0.5
|
|
11619
|
-
**/
|
|
11620
|
-
/**
|
|
11621
|
-
* @classdesc A default SVG builder.
|
|
11622
|
-
*
|
|
11623
|
-
* @requires SVGSerializable
|
|
11624
|
-
* @requires Vertex
|
|
11625
|
-
*/
|
|
11626
|
-
class SVGBuilder {
|
|
11627
|
-
/**
|
|
11628
|
-
* @constructor
|
|
11629
|
-
**/
|
|
11630
|
-
constructor() {
|
|
11631
|
-
console.warn("THIS CLASS IS DEPRECATED. Please use the new 'drawutilssvg' instead.");
|
|
11632
|
-
}
|
|
11633
|
-
;
|
|
11634
|
-
/**
|
|
11635
|
-
* Builds the SVG code from the given list of drawables.
|
|
11636
|
-
*
|
|
11637
|
-
* @param {object[]} drawables - The drawable elements (should implement Drawable) to be converted (each must have a toSVGString-function).
|
|
11638
|
-
* @param {object} options - { canvasSize, zoom, offset }
|
|
11639
|
-
* @return {string}
|
|
11640
|
-
**/
|
|
11641
|
-
build(drawables, options) {
|
|
11642
|
-
var nl = '\n';
|
|
11643
|
-
var indent = ' ';
|
|
11644
|
-
var buffer = [];
|
|
11645
|
-
buffer.push('<?xml version="1.0" encoding="UTF-8"?>' + nl);
|
|
11646
|
-
buffer.push('<svg width="' + options.canvasSize.width + '" height="' + options.canvasSize.height + '"');
|
|
11647
|
-
buffer.push(' viewBox="');
|
|
11648
|
-
buffer.push('0');
|
|
11649
|
-
buffer.push(' ');
|
|
11650
|
-
buffer.push('0');
|
|
11651
|
-
buffer.push(' ');
|
|
11652
|
-
buffer.push(options.canvasSize.width.toString());
|
|
11653
|
-
buffer.push(' ');
|
|
11654
|
-
buffer.push(options.canvasSize.height.toString());
|
|
11655
|
-
buffer.push('"');
|
|
11656
|
-
buffer.push(' xmlns="http://www.w3.org/2000/svg">' + nl);
|
|
11657
|
-
buffer.push(indent + '<defs>' + nl);
|
|
11658
|
-
buffer.push(indent + '<style>' + nl);
|
|
11659
|
-
buffer.push(indent + indent + ' .Vertex { fill : blue; stroke : none; } ' + nl);
|
|
11660
|
-
buffer.push(indent + indent + ' .Triangle { fill : none; stroke : turquoise; stroke-width : 1px; } ' + nl);
|
|
11661
|
-
buffer.push(indent + indent + ' .Polygon { fill : none; stroke : green; stroke-width : 2px; } ' + nl);
|
|
11662
|
-
buffer.push(indent + indent + ' .BezierPath { fill : none; stroke : blue; stroke-width : 2px; } ' + nl);
|
|
11663
|
-
buffer.push(indent + indent + ' .VEllipse { fill : none; stroke : black; stroke-width : 1px; } ' + nl);
|
|
11664
|
-
buffer.push(indent + indent + ' .Line { fill : none; stroke : purple; stroke-width : 1px; } ' + nl);
|
|
11665
|
-
buffer.push(indent + indent + ' .Circle { fill : none; stroke : purple; stroke-width : 1px; } ' + nl);
|
|
11666
|
-
buffer.push(indent + indent + ' .CircleSector { fill : none; stroke : purple; stroke-width : 1px; } ' + nl);
|
|
11667
|
-
buffer.push(indent + '</style>' + nl);
|
|
11668
|
-
buffer.push(indent + '</defs>' + nl);
|
|
11669
|
-
buffer.push(indent + '<g class="main-g"');
|
|
11670
|
-
if (options.zoom || options.offset) {
|
|
11671
|
-
buffer.push(' transform="');
|
|
11672
|
-
if (options.zoom)
|
|
11673
|
-
buffer.push('scale(' + options.zoom.x + ',' + options.zoom.y + ')');
|
|
11674
|
-
if (options.offset)
|
|
11675
|
-
buffer.push(' translate(' + options.offset.x + ',' + options.offset.y + ')');
|
|
11676
|
-
buffer.push('"');
|
|
11677
|
-
}
|
|
11678
|
-
buffer.push('>' + nl);
|
|
11679
|
-
for (var i in drawables) {
|
|
11680
|
-
var d = drawables[i];
|
|
11681
|
-
if (typeof d.toSVGString == 'function') {
|
|
11682
|
-
buffer.push(indent + indent);
|
|
11683
|
-
buffer.push(d.toSVGString({ 'className': d.className }));
|
|
11684
|
-
buffer.push(nl);
|
|
11685
|
-
}
|
|
11686
|
-
else {
|
|
11687
|
-
console.warn('Unrecognized drawable type has no toSVGString()-function. Ignoring: ' + d.className);
|
|
11688
|
-
}
|
|
11689
|
-
}
|
|
11690
|
-
buffer.push(indent + '</g>' + nl);
|
|
11691
|
-
buffer.push('</svg>' + nl);
|
|
11692
|
-
return buffer.join('');
|
|
11693
|
-
}
|
|
11694
|
-
;
|
|
11695
|
-
}
|
|
11696
|
-
|
|
11697
|
-
export { BezierPath, Bounds, Circle, CircleSector, CubicBezierCurve, Grid, KeyHandler, Line, MouseHandler, PBImage, PBText, PlotBoilerplate, Polygon, SVGBuilder, Triangle, UIDGenerator, VEllipse, VEllipseSector, Vector, VertTuple, Vertex, VertexAttr, VertexListeners, XMouseEvent, XWheelEvent, drawutils, drawutilsgl, drawutilssvg, geomutils };
|
|
11859
|
+
export { BezierPath, Bounds, Circle, CircleSector, CubicBezierCurve, Grid, KeyHandler, Line, MouseHandler, PBImage, PBText, PlotBoilerplate, Polygon, Triangle, UIDGenerator, VEllipse, VEllipseSector, Vector, VertTuple, Vertex, VertexAttr, VertexListeners, XMouseEvent, XWheelEvent, drawutils, drawutilsgl, drawutilssvg, geomutils };
|
|
11698
11860
|
//# sourceMappingURL=index.esm.js.map
|