plotboilerplate 1.15.0 → 1.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/changelog.md +65 -0
- package/dist/index.esm.js +760 -667
- 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 +765 -571
- 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 +33 -1
- package/src/cjs/Bounds.js +38 -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.d.ts +3 -1
- package/src/cjs/PlotBoilerplate.js +9 -2
- package/src/cjs/PlotBoilerplate.js.map +1 -1
- package/src/cjs/Polygon.d.ts +23 -14
- package/src/cjs/Polygon.js +22 -35
- 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 +23 -13
- package/src/cjs/Vertex.js +24 -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 +45 -3
- package/src/cjs/draw.js +149 -6
- package/src/cjs/draw.js.map +1 -1
- package/src/cjs/drawgl.d.ts +41 -3
- package/src/cjs/drawgl.js +45 -3
- package/src/cjs/drawgl.js.map +1 -1
- package/src/cjs/drawutilssvg.d.ts +69 -4
- package/src/cjs/drawutilssvg.js +147 -16
- 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 +64 -27
- package/src/cjs/interfaces/DrawLib.js +3 -0
- package/src/cjs/interfaces/DrawLib.js.map +1 -1
- package/src/cjs/interfaces/core.d.ts +2 -12
- package/src/cjs/interfaces/core.js +1 -0
- package/src/cjs/interfaces/core.js.map +1 -1
- 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/Color.d.ts +3 -1
- package/src/cjs/utils/datastructures/Color.js +17 -6
- package/src/cjs/utils/datastructures/Color.js.map +1 -1
- 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/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 +33 -1
- package/src/esm/Bounds.js +38 -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.d.ts +3 -1
- package/src/esm/PlotBoilerplate.js +9 -2
- package/src/esm/PlotBoilerplate.js.map +1 -1
- package/src/esm/Polygon.d.ts +23 -14
- package/src/esm/Polygon.js +22 -35
- 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 +23 -13
- package/src/esm/Vertex.js +24 -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 +45 -3
- package/src/esm/draw.js +147 -6
- package/src/esm/draw.js.map +1 -1
- package/src/esm/drawgl.d.ts +41 -3
- package/src/esm/drawgl.js +44 -3
- package/src/esm/drawgl.js.map +1 -1
- package/src/esm/drawutilssvg.d.ts +69 -4
- package/src/esm/drawutilssvg.js +146 -16
- 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 +64 -27
- package/src/esm/interfaces/DrawLib.js +3 -0
- package/src/esm/interfaces/DrawLib.js.map +1 -1
- package/src/esm/interfaces/core.d.ts +2 -12
- package/src/esm/interfaces/core.js +1 -0
- package/src/esm/interfaces/core.js.map +1 -1
- 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/Color.d.ts +3 -1
- package/src/esm/utils/datastructures/Color.js +17 -6
- package/src/esm/utils/datastructures/Color.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/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 +40 -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 +9 -2
- package/src/ts/Polygon.ts +34 -34
- 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 +35 -21
- package/src/ts/VertexListeners.ts +248 -266
- package/src/ts/draw.ts +201 -6
- package/src/ts/drawgl.ts +47 -3
- package/src/ts/drawutilssvg.ts +187 -16
- package/src/ts/index.ts +0 -1
- package/src/ts/interfaces/DrawLib.ts +72 -27
- package/src/ts/interfaces/core.ts +3 -13
- package/src/ts/module.ts +2 -4
- package/src/ts/utils/datastructures/Color.ts +17 -6
- 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/helpers/BezierPathInteractionHelper.ts +56 -34
- package/src/ts/utils/io/FileDrop.ts +178 -0
- package/src/ts/SVGBuilder.ts +0 -109
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
|
/**
|
|
@@ -361,7 +354,10 @@ class VertexListeners {
|
|
|
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.
|
|
364
|
-
* @
|
|
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
|
|
365
361
|
*
|
|
366
362
|
* @file Vertex
|
|
367
363
|
* @public
|
|
@@ -848,28 +844,14 @@ class Vertex {
|
|
|
848
844
|
return "(" + this.x + "," + this.y + ")";
|
|
849
845
|
}
|
|
850
846
|
/**
|
|
851
|
-
*
|
|
852
|
-
*
|
|
853
|
-
*
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
* @memberof Vertex
|
|
859
|
-
**/
|
|
860
|
-
toSVGString(options) {
|
|
861
|
-
options = options || {};
|
|
862
|
-
var buffer = [];
|
|
863
|
-
buffer.push("<circle");
|
|
864
|
-
if (options.className)
|
|
865
|
-
buffer.push(' class="' + options.className + '"');
|
|
866
|
-
buffer.push(' cx="' + this.x + '"');
|
|
867
|
-
buffer.push(' cy="' + this.y + '"');
|
|
868
|
-
buffer.push(' r="2"');
|
|
869
|
-
buffer.push(" />");
|
|
870
|
-
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;
|
|
871
854
|
}
|
|
872
|
-
// END Vertex
|
|
873
855
|
/**
|
|
874
856
|
* Create a new random vertex inside the given viewport.
|
|
875
857
|
*
|
|
@@ -924,6 +906,19 @@ Vertex.utils = {
|
|
|
924
906
|
vertices.push(new Vertex(zB.x * scaleX, zB.y * scaleY));
|
|
925
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)));
|
|
926
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
|
+
}));
|
|
927
922
|
}
|
|
928
923
|
};
|
|
929
924
|
|
|
@@ -950,7 +945,10 @@ Vertex.utils = {
|
|
|
950
945
|
* @modified 2021-01-29 Changed the param type for `containsVert` from Vertex to XYCoords.
|
|
951
946
|
* @modified 2021-12-14 Added the `perimeter()` function.
|
|
952
947
|
* @modified 2021-12-16 Added the `getEvenDistributionPolygon()` function.
|
|
953
|
-
* @
|
|
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
|
|
954
952
|
*
|
|
955
953
|
* @file Polygon
|
|
956
954
|
* @public
|
|
@@ -1028,9 +1026,9 @@ class Polygon {
|
|
|
1028
1026
|
* @memberof Polygon
|
|
1029
1027
|
* @return {Polygon} this for chaining
|
|
1030
1028
|
**/
|
|
1031
|
-
move(
|
|
1029
|
+
move(amount) {
|
|
1032
1030
|
for (var i in this.vertices) {
|
|
1033
|
-
this.vertices[i].add(
|
|
1031
|
+
this.vertices[i].add(amount);
|
|
1034
1032
|
}
|
|
1035
1033
|
return this;
|
|
1036
1034
|
}
|
|
@@ -1209,6 +1207,14 @@ class Polygon {
|
|
|
1209
1207
|
getBounds() {
|
|
1210
1208
|
return Bounds.computeFromVertices(this.vertices);
|
|
1211
1209
|
}
|
|
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
|
+
}
|
|
1212
1218
|
/**
|
|
1213
1219
|
* Convert this polygon to a sequence of quadratic Bézier curves.<br>
|
|
1214
1220
|
* <br>
|
|
@@ -1346,39 +1352,15 @@ class Polygon {
|
|
|
1346
1352
|
return BezierPath.fromArray(pathdata);
|
|
1347
1353
|
}
|
|
1348
1354
|
/**
|
|
1349
|
-
*
|
|
1350
|
-
*
|
|
1351
|
-
*
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
* @memberof Polygon
|
|
1357
|
-
**/
|
|
1358
|
-
toSVGString(options) {
|
|
1359
|
-
options = options || {};
|
|
1360
|
-
var buffer = [];
|
|
1361
|
-
buffer.push("<path");
|
|
1362
|
-
if (options.className)
|
|
1363
|
-
buffer.push(' class="' + options.className + '"');
|
|
1364
|
-
buffer.push(' d="');
|
|
1365
|
-
if (this.vertices.length > 0) {
|
|
1366
|
-
buffer.push("M ");
|
|
1367
|
-
buffer.push(this.vertices[0].x.toString());
|
|
1368
|
-
buffer.push(" ");
|
|
1369
|
-
buffer.push(this.vertices[0].y.toString());
|
|
1370
|
-
for (var i = 1; i < this.vertices.length; i++) {
|
|
1371
|
-
buffer.push(" L ");
|
|
1372
|
-
buffer.push(this.vertices[i].x.toString());
|
|
1373
|
-
buffer.push(" ");
|
|
1374
|
-
buffer.push(this.vertices[i].y.toString());
|
|
1375
|
-
}
|
|
1376
|
-
if (!this.isOpen) {
|
|
1377
|
-
buffer.push(" Z");
|
|
1378
|
-
}
|
|
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();
|
|
1379
1362
|
}
|
|
1380
|
-
|
|
1381
|
-
return buffer.join("");
|
|
1363
|
+
this.isDestroyed = true;
|
|
1382
1364
|
}
|
|
1383
1365
|
}
|
|
1384
1366
|
Polygon.utils = {
|
|
@@ -1429,7 +1411,8 @@ Polygon.utils = {
|
|
|
1429
1411
|
* @modified 2020-11-19 Set min, max, width and height to private.
|
|
1430
1412
|
* @modified 2021-02-02 Added the `toPolygon` method.
|
|
1431
1413
|
* @modified 2021-06-21 (mid-summer) Added `getCenter` method.
|
|
1432
|
-
* @
|
|
1414
|
+
* @modified 2022-02-01 Added the `toString` function.
|
|
1415
|
+
* @version 1.4.0
|
|
1433
1416
|
**/
|
|
1434
1417
|
/**
|
|
1435
1418
|
* @classdesc A bounds class with min and max values. Implementing IBounds.
|
|
@@ -1464,9 +1447,45 @@ class Bounds {
|
|
|
1464
1447
|
toPolygon() {
|
|
1465
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);
|
|
1466
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
|
+
*/
|
|
1467
1458
|
getCenter() {
|
|
1468
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);
|
|
1469
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
|
+
}
|
|
1475
|
+
/**
|
|
1476
|
+
* Clone this bounds object (create a deep clone).
|
|
1477
|
+
*
|
|
1478
|
+
* Note: the returned format might change in the future, so please do not
|
|
1479
|
+
* rely on the returned string format.
|
|
1480
|
+
*
|
|
1481
|
+
* @method clone
|
|
1482
|
+
* @instance
|
|
1483
|
+
* @memberof Bounds
|
|
1484
|
+
* @returns {string} Creates a deep clone of this bounds object. The returned object's `min` and `max` instances are `Vertex` instances.
|
|
1485
|
+
*/
|
|
1486
|
+
// clone() {
|
|
1487
|
+
// return new Bounds(new Vertex(this.min.x, this.min.y), new Vertex(this.max.x, this.max.y));
|
|
1488
|
+
// }
|
|
1470
1489
|
/**
|
|
1471
1490
|
* Compute the minimal bounding box for a given set of vertices.
|
|
1472
1491
|
*
|
|
@@ -1507,7 +1526,8 @@ class Bounds {
|
|
|
1507
1526
|
* @modified 2020-12-04 Changed `getClosestT` param from `Vertex` to `XYCoords` (generalized).
|
|
1508
1527
|
* @modified 2020-12-04 Added the `hasPoint(XYCoords)` function.
|
|
1509
1528
|
* @modified 2021-01-20 Added UID.
|
|
1510
|
-
* @
|
|
1529
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
1530
|
+
* @version 1.2.0
|
|
1511
1531
|
*/
|
|
1512
1532
|
/**
|
|
1513
1533
|
* @classdesc An abstract base classes for vertex tuple constructs, like Lines or Vectors.
|
|
@@ -1541,7 +1561,6 @@ class VertTuple {
|
|
|
1541
1561
|
length() {
|
|
1542
1562
|
return Math.sqrt(Math.pow(this.b.x - this.a.x, 2) + Math.pow(this.b.y - this.a.y, 2));
|
|
1543
1563
|
}
|
|
1544
|
-
;
|
|
1545
1564
|
/**
|
|
1546
1565
|
* Set the length of this vector to the given amount. This only works if this
|
|
1547
1566
|
* vector is not a null vector.
|
|
@@ -1554,7 +1573,6 @@ class VertTuple {
|
|
|
1554
1573
|
setLength(length) {
|
|
1555
1574
|
return this.scale(length / this.length());
|
|
1556
1575
|
}
|
|
1557
|
-
;
|
|
1558
1576
|
/**
|
|
1559
1577
|
* Substract the given vertex from this line's end points.
|
|
1560
1578
|
*
|
|
@@ -1569,7 +1587,6 @@ class VertTuple {
|
|
|
1569
1587
|
this.b.sub(amount);
|
|
1570
1588
|
return this;
|
|
1571
1589
|
}
|
|
1572
|
-
;
|
|
1573
1590
|
/**
|
|
1574
1591
|
* Add the given vertex to this line's end points.
|
|
1575
1592
|
*
|
|
@@ -1584,7 +1601,6 @@ class VertTuple {
|
|
|
1584
1601
|
this.b.add(amount);
|
|
1585
1602
|
return this;
|
|
1586
1603
|
}
|
|
1587
|
-
;
|
|
1588
1604
|
/**
|
|
1589
1605
|
* Normalize this line (set to length 1).
|
|
1590
1606
|
*
|
|
@@ -1597,7 +1613,6 @@ class VertTuple {
|
|
|
1597
1613
|
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());
|
|
1598
1614
|
return this;
|
|
1599
1615
|
}
|
|
1600
|
-
;
|
|
1601
1616
|
/**
|
|
1602
1617
|
* Scale this line by the given factor.
|
|
1603
1618
|
*
|
|
@@ -1611,7 +1626,6 @@ class VertTuple {
|
|
|
1611
1626
|
this.b.set(this.a.x + (this.b.x - this.a.x) * factor, this.a.y + (this.b.y - this.a.y) * factor);
|
|
1612
1627
|
return this;
|
|
1613
1628
|
}
|
|
1614
|
-
;
|
|
1615
1629
|
/**
|
|
1616
1630
|
* Move this line to a new location.
|
|
1617
1631
|
*
|
|
@@ -1627,7 +1641,6 @@ class VertTuple {
|
|
|
1627
1641
|
this.b.add(diff);
|
|
1628
1642
|
return this;
|
|
1629
1643
|
}
|
|
1630
|
-
;
|
|
1631
1644
|
/**
|
|
1632
1645
|
* Get the angle between this and the passed line (in radians).
|
|
1633
1646
|
*
|
|
@@ -1638,7 +1651,7 @@ class VertTuple {
|
|
|
1638
1651
|
* @memberof VertTuple
|
|
1639
1652
|
**/
|
|
1640
1653
|
angle(line) {
|
|
1641
|
-
if (line == null || typeof line ==
|
|
1654
|
+
if (line == null || typeof line == "undefined") {
|
|
1642
1655
|
line = this.factory(new Vertex(0, 0), new Vertex(100, 0));
|
|
1643
1656
|
}
|
|
1644
1657
|
// Compute the angle from x axis and the return the difference :)
|
|
@@ -1648,7 +1661,6 @@ class VertTuple {
|
|
|
1648
1661
|
// The result might be negative, but isn't it usually nicer to determine angles in positive values only?
|
|
1649
1662
|
return Math.atan2(v1.x, v1.y) - Math.atan2(v0.x, v0.y);
|
|
1650
1663
|
}
|
|
1651
|
-
;
|
|
1652
1664
|
/**
|
|
1653
1665
|
* Get line point at position t in [0 ... 1]:<br>
|
|
1654
1666
|
* <pre>[P(0)]=[A]--------------------[P(t)]------[B]=[P(1)]</pre><br>
|
|
@@ -1664,7 +1676,6 @@ class VertTuple {
|
|
|
1664
1676
|
vertAt(t) {
|
|
1665
1677
|
return new Vertex(this.a.x + (this.b.x - this.a.x) * t, this.a.y + (this.b.y - this.a.y) * t);
|
|
1666
1678
|
}
|
|
1667
|
-
;
|
|
1668
1679
|
/**
|
|
1669
1680
|
* Get the denominator of this and the given line.
|
|
1670
1681
|
*
|
|
@@ -1678,9 +1689,8 @@ class VertTuple {
|
|
|
1678
1689
|
**/
|
|
1679
1690
|
denominator(line) {
|
|
1680
1691
|
// http://jsfiddle.net/justin_c_rounds/Gd2S2/
|
|
1681
|
-
return (
|
|
1692
|
+
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);
|
|
1682
1693
|
}
|
|
1683
|
-
;
|
|
1684
1694
|
/**
|
|
1685
1695
|
* Checks if this and the given line are co-linear.
|
|
1686
1696
|
*
|
|
@@ -1695,7 +1705,6 @@ class VertTuple {
|
|
|
1695
1705
|
colinear(line) {
|
|
1696
1706
|
return Math.abs(this.denominator(line)) < Vertex.EPSILON;
|
|
1697
1707
|
}
|
|
1698
|
-
;
|
|
1699
1708
|
/**
|
|
1700
1709
|
* Get the closest position T from this line to the specified point.
|
|
1701
1710
|
*
|
|
@@ -1718,7 +1727,6 @@ class VertTuple {
|
|
|
1718
1727
|
// t = Math.max(0, Math.min(1, t));
|
|
1719
1728
|
return t;
|
|
1720
1729
|
}
|
|
1721
|
-
;
|
|
1722
1730
|
/**
|
|
1723
1731
|
* Check if the given point is located on this line. Optionally also check if
|
|
1724
1732
|
* that point is located between point `a` and `b`.
|
|
@@ -1754,7 +1762,6 @@ class VertTuple {
|
|
|
1754
1762
|
var t = this.getClosestT(p);
|
|
1755
1763
|
return this.vertAt(t);
|
|
1756
1764
|
}
|
|
1757
|
-
;
|
|
1758
1765
|
/**
|
|
1759
1766
|
* The the minimal distance between this line and the specified point.
|
|
1760
1767
|
*
|
|
@@ -1769,7 +1776,6 @@ class VertTuple {
|
|
|
1769
1776
|
// https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
|
|
1770
1777
|
return Math.sqrt(VertTuple.vtutils.dist2(p, this.vertAt(this.getClosestT(p))));
|
|
1771
1778
|
}
|
|
1772
|
-
;
|
|
1773
1779
|
/**
|
|
1774
1780
|
* Create a deep clone of this instance.
|
|
1775
1781
|
*
|
|
@@ -1781,7 +1787,6 @@ class VertTuple {
|
|
|
1781
1787
|
clone() {
|
|
1782
1788
|
return this.factory(this.a.clone(), this.b.clone());
|
|
1783
1789
|
}
|
|
1784
|
-
;
|
|
1785
1790
|
/**
|
|
1786
1791
|
* Create a string representation of this line.
|
|
1787
1792
|
*
|
|
@@ -1793,7 +1798,16 @@ class VertTuple {
|
|
|
1793
1798
|
toString() {
|
|
1794
1799
|
return "{ a : " + this.a.toString() + ", b : " + this.b.toString() + " }";
|
|
1795
1800
|
}
|
|
1796
|
-
|
|
1801
|
+
/**
|
|
1802
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
1803
|
+
* After calling this function the object might not hold valid data any more and
|
|
1804
|
+
* should not be used.
|
|
1805
|
+
*/
|
|
1806
|
+
destroy() {
|
|
1807
|
+
this.a.destroy();
|
|
1808
|
+
this.b.destroy();
|
|
1809
|
+
this.isDestroyed = true;
|
|
1810
|
+
}
|
|
1797
1811
|
}
|
|
1798
1812
|
/**
|
|
1799
1813
|
* @private
|
|
@@ -1815,7 +1829,9 @@ VertTuple.vtutils = {
|
|
|
1815
1829
|
* @modified 2019-12-04 Added the Vector.inv() function.
|
|
1816
1830
|
* @modified 2020-03-23 Ported to Typescript from JS.
|
|
1817
1831
|
* @modified 2021-01-20 Added UID.
|
|
1818
|
-
* @
|
|
1832
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
1833
|
+
* @modified 2022-02-02 Cleared the `Vector.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
1834
|
+
* @version 1.4.0
|
|
1819
1835
|
*
|
|
1820
1836
|
* @file Vector
|
|
1821
1837
|
* @public
|
|
@@ -1846,7 +1862,6 @@ class Vector extends VertTuple {
|
|
|
1846
1862
|
**/
|
|
1847
1863
|
this.className = "Vector";
|
|
1848
1864
|
}
|
|
1849
|
-
;
|
|
1850
1865
|
/**
|
|
1851
1866
|
* Get the perpendicular of this vector which is located at a.
|
|
1852
1867
|
*
|
|
@@ -1861,7 +1876,6 @@ class Vector extends VertTuple {
|
|
|
1861
1876
|
v.b.add(this.a);
|
|
1862
1877
|
return v;
|
|
1863
1878
|
}
|
|
1864
|
-
;
|
|
1865
1879
|
/**
|
|
1866
1880
|
* The inverse of a vector is a vector witht the same magnitude but oppose direction.
|
|
1867
1881
|
*
|
|
@@ -1875,7 +1889,6 @@ class Vector extends VertTuple {
|
|
|
1875
1889
|
this.b = tmp;
|
|
1876
1890
|
return this;
|
|
1877
1891
|
}
|
|
1878
|
-
;
|
|
1879
1892
|
/**
|
|
1880
1893
|
* This function computes the inverse of the vector, which means 'a' stays untouched.
|
|
1881
1894
|
*
|
|
@@ -1886,7 +1899,6 @@ class Vector extends VertTuple {
|
|
|
1886
1899
|
this.b.y = this.a.y - (this.b.y - this.a.y);
|
|
1887
1900
|
return this;
|
|
1888
1901
|
}
|
|
1889
|
-
;
|
|
1890
1902
|
/**
|
|
1891
1903
|
* Get the intersection if this vector and the specified vector.
|
|
1892
1904
|
*
|
|
@@ -1902,53 +1914,15 @@ class Vector extends VertTuple {
|
|
|
1902
1914
|
return null;
|
|
1903
1915
|
var a = this.a.y - line.a.y;
|
|
1904
1916
|
var b = this.a.x - line.a.x;
|
|
1905
|
-
var numerator1 = (
|
|
1906
|
-
var numerator2 = (
|
|
1917
|
+
var numerator1 = (line.b.x - line.a.x) * a - (line.b.y - line.a.y) * b;
|
|
1918
|
+
var numerator2 = (this.b.x - this.a.x) * a - (this.b.y - this.a.y) * b;
|
|
1907
1919
|
a = numerator1 / denominator; // NaN if parallel lines
|
|
1908
1920
|
b = numerator2 / denominator;
|
|
1909
1921
|
// TODO:
|
|
1910
1922
|
// FOR A VECTOR THE LINE-INTERSECTION MUST BE ON BOTH VECTORS
|
|
1911
1923
|
// if we cast these lines infinitely in both directions, they intersect here:
|
|
1912
|
-
return new Vertex(this.a.x +
|
|
1913
|
-
}
|
|
1914
|
-
;
|
|
1915
|
-
/**
|
|
1916
|
-
* Create an SVG representation of this line.
|
|
1917
|
-
*
|
|
1918
|
-
* @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
|
|
1919
|
-
* @method toSVGString
|
|
1920
|
-
* @override
|
|
1921
|
-
* @param {object=} options - A set of options, like 'className'.
|
|
1922
|
-
* @return {string} The SVG string representation.
|
|
1923
|
-
* @instance
|
|
1924
|
-
* @memberof Vector
|
|
1925
|
-
**/
|
|
1926
|
-
toSVGString(options) {
|
|
1927
|
-
options = options || {};
|
|
1928
|
-
var buffer = [];
|
|
1929
|
-
var vertices = Vector.utils.buildArrowHead(this.a, this.b, 8, 1.0, 1.0);
|
|
1930
|
-
buffer.push('<g');
|
|
1931
|
-
if (options.className)
|
|
1932
|
-
buffer.push(' class="' + options.className + '"');
|
|
1933
|
-
buffer.push('>');
|
|
1934
|
-
buffer.push(' <line');
|
|
1935
|
-
buffer.push(' x1="' + this.a.x + '"');
|
|
1936
|
-
buffer.push(' y1="' + this.a.y + '"');
|
|
1937
|
-
buffer.push(' x2="' + vertices[0].x + '"');
|
|
1938
|
-
buffer.push(' y2="' + vertices[0].y + '"');
|
|
1939
|
-
buffer.push(' />');
|
|
1940
|
-
// Add arrow head
|
|
1941
|
-
buffer.push(' <polygon points="');
|
|
1942
|
-
for (var i = 0; i < vertices.length; i++) {
|
|
1943
|
-
if (i > 0)
|
|
1944
|
-
buffer.push(' ');
|
|
1945
|
-
buffer.push('' + vertices[i].x + ',' + vertices[i].y);
|
|
1946
|
-
}
|
|
1947
|
-
buffer.push('"/>');
|
|
1948
|
-
buffer.push('</g>');
|
|
1949
|
-
return buffer.join('');
|
|
1924
|
+
return new Vertex(this.a.x + a * (this.b.x - this.a.x), this.a.y + a * (this.b.y - this.a.y));
|
|
1950
1925
|
}
|
|
1951
|
-
;
|
|
1952
1926
|
}
|
|
1953
1927
|
Vector.utils = {
|
|
1954
1928
|
/**
|
|
@@ -1979,10 +1953,10 @@ Vector.utils = {
|
|
|
1979
1953
|
buildArrowHead: (zA, zB, headlen, scaleX, scaleY) => {
|
|
1980
1954
|
var angle = Math.atan2((zB.y - zA.y) * scaleY, (zB.x - zA.x) * scaleX);
|
|
1981
1955
|
var vertices = [];
|
|
1982
|
-
vertices.push(new Vertex(zB.x * scaleX -
|
|
1983
|
-
vertices.push(new Vertex(zB.x * scaleX -
|
|
1956
|
+
vertices.push(new Vertex(zB.x * scaleX - headlen * Math.cos(angle), zB.y * scaleY - headlen * Math.sin(angle)));
|
|
1957
|
+
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)));
|
|
1984
1958
|
vertices.push(new Vertex(zB.x * scaleX, zB.y * scaleY));
|
|
1985
|
-
vertices.push(new Vertex(zB.x * scaleX -
|
|
1959
|
+
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)));
|
|
1986
1960
|
return vertices;
|
|
1987
1961
|
}
|
|
1988
1962
|
};
|
|
@@ -2007,7 +1981,9 @@ Vector.utils = {
|
|
|
2007
1981
|
* @modified 2020-07-14 Changed the moveCurvePoint(...,Vertex) to moveCurvePoint(...,XYCoords), which is more generic.
|
|
2008
1982
|
* @modified 2020-07-24 Added the getClosestT function and the helper function locateIntervalByDistance(...).
|
|
2009
1983
|
* @modified 2021-01-20 Added UID.
|
|
2010
|
-
* @
|
|
1984
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
1985
|
+
* @modified 2022-02-02 Cleared the `toSVGPathData` function (deprecated). Use `drawutilssvg` instead.
|
|
1986
|
+
* @version 2.6.0
|
|
2011
1987
|
*
|
|
2012
1988
|
* @file CubicBezierCurve
|
|
2013
1989
|
* @public
|
|
@@ -2056,7 +2032,6 @@ class CubicBezierCurve {
|
|
|
2056
2032
|
this.arcLength = null;
|
|
2057
2033
|
this.updateArcLengths();
|
|
2058
2034
|
}
|
|
2059
|
-
;
|
|
2060
2035
|
/**
|
|
2061
2036
|
* Move the given curve point (the start point, end point or one of the two
|
|
2062
2037
|
* control points).
|
|
@@ -2093,7 +2068,6 @@ class CubicBezierCurve {
|
|
|
2093
2068
|
if (updateArcLengths)
|
|
2094
2069
|
this.updateArcLengths();
|
|
2095
2070
|
}
|
|
2096
|
-
;
|
|
2097
2071
|
/**
|
|
2098
2072
|
* Translate the whole curve by the given {x,y} amount: moves all four points.
|
|
2099
2073
|
*
|
|
@@ -2110,7 +2084,6 @@ class CubicBezierCurve {
|
|
|
2110
2084
|
this.endPoint.add(amount);
|
|
2111
2085
|
return this;
|
|
2112
2086
|
}
|
|
2113
|
-
;
|
|
2114
2087
|
/**
|
|
2115
2088
|
* Reverse this curve, means swapping start- and end-point and swapping
|
|
2116
2089
|
* start-control- and end-control-point.
|
|
@@ -2129,7 +2102,6 @@ class CubicBezierCurve {
|
|
|
2129
2102
|
this.endControlPoint = tmp;
|
|
2130
2103
|
return this;
|
|
2131
2104
|
}
|
|
2132
|
-
;
|
|
2133
2105
|
/**
|
|
2134
2106
|
* Get the total curve length.<br>
|
|
2135
2107
|
* <br>
|
|
@@ -2148,7 +2120,6 @@ class CubicBezierCurve {
|
|
|
2148
2120
|
getLength() {
|
|
2149
2121
|
return this.arcLength;
|
|
2150
2122
|
}
|
|
2151
|
-
;
|
|
2152
2123
|
/**
|
|
2153
2124
|
* Uptate the internal arc segment buffer and their lengths.<br>
|
|
2154
2125
|
* <br>
|
|
@@ -2186,7 +2157,6 @@ class CubicBezierCurve {
|
|
|
2186
2157
|
}
|
|
2187
2158
|
this.arcLength = newLength;
|
|
2188
2159
|
}
|
|
2189
|
-
;
|
|
2190
2160
|
/**
|
|
2191
2161
|
* Get a 't' (relative position on curve) with the closest distance to point 'p'.
|
|
2192
2162
|
*
|
|
@@ -2209,7 +2179,6 @@ class CubicBezierCurve {
|
|
|
2209
2179
|
} while (iteration < 4 && this.getPointAt(result.tPrev).distance(this.getPointAt(result.tNext)) > desiredEpsilon);
|
|
2210
2180
|
return result.t;
|
|
2211
2181
|
}
|
|
2212
|
-
;
|
|
2213
2182
|
/**
|
|
2214
2183
|
* This helper function locates the 't' on a fixed step interval with the minimal distance
|
|
2215
2184
|
* between the curve (at 't') and the given point.
|
|
@@ -2238,12 +2207,12 @@ class CubicBezierCurve {
|
|
|
2238
2207
|
minDist = dist;
|
|
2239
2208
|
}
|
|
2240
2209
|
}
|
|
2241
|
-
return {
|
|
2210
|
+
return {
|
|
2211
|
+
t: tStart + tDiff * (minIndex / stepCount),
|
|
2242
2212
|
tPrev: tStart + tDiff * (Math.max(0, minIndex - 1) / stepCount),
|
|
2243
2213
|
tNext: tStart + tDiff * (Math.min(stepCount, minIndex + 1) / stepCount)
|
|
2244
2214
|
};
|
|
2245
2215
|
}
|
|
2246
|
-
;
|
|
2247
2216
|
/**
|
|
2248
2217
|
* Get the bounds of this bezier curve.
|
|
2249
2218
|
*
|
|
@@ -2265,7 +2234,6 @@ class CubicBezierCurve {
|
|
|
2265
2234
|
}
|
|
2266
2235
|
return new Bounds(min, max);
|
|
2267
2236
|
}
|
|
2268
|
-
;
|
|
2269
2237
|
/**
|
|
2270
2238
|
* Get the start point of the curve.<br>
|
|
2271
2239
|
* <br>
|
|
@@ -2279,7 +2247,6 @@ class CubicBezierCurve {
|
|
|
2279
2247
|
getStartPoint() {
|
|
2280
2248
|
return this.startPoint;
|
|
2281
2249
|
}
|
|
2282
|
-
;
|
|
2283
2250
|
/**
|
|
2284
2251
|
* Get the end point of the curve.<br>
|
|
2285
2252
|
* <br>
|
|
@@ -2293,7 +2260,6 @@ class CubicBezierCurve {
|
|
|
2293
2260
|
getEndPoint() {
|
|
2294
2261
|
return this.endPoint;
|
|
2295
2262
|
}
|
|
2296
|
-
;
|
|
2297
2263
|
/**
|
|
2298
2264
|
* Get the start control point of the curve.<br>
|
|
2299
2265
|
* <br>
|
|
@@ -2307,7 +2273,6 @@ class CubicBezierCurve {
|
|
|
2307
2273
|
getStartControlPoint() {
|
|
2308
2274
|
return this.startControlPoint;
|
|
2309
2275
|
}
|
|
2310
|
-
;
|
|
2311
2276
|
/**
|
|
2312
2277
|
* Get the end control point of the curve.<br>
|
|
2313
2278
|
* <br>
|
|
@@ -2321,7 +2286,6 @@ class CubicBezierCurve {
|
|
|
2321
2286
|
getEndControlPoint() {
|
|
2322
2287
|
return this.endControlPoint;
|
|
2323
2288
|
}
|
|
2324
|
-
;
|
|
2325
2289
|
/**
|
|
2326
2290
|
* Get one of the four curve points specified by the passt point ID.
|
|
2327
2291
|
*
|
|
@@ -2342,7 +2306,6 @@ class CubicBezierCurve {
|
|
|
2342
2306
|
return this.endControlPoint;
|
|
2343
2307
|
throw new Error(`Invalid point ID '${id}'.`);
|
|
2344
2308
|
}
|
|
2345
|
-
;
|
|
2346
2309
|
/**
|
|
2347
2310
|
* Get the curve point at a given position t, where t is in [0,1].<br>
|
|
2348
2311
|
* <br>
|
|
@@ -2357,13 +2320,16 @@ class CubicBezierCurve {
|
|
|
2357
2320
|
**/
|
|
2358
2321
|
getPointAt(t) {
|
|
2359
2322
|
// Perform some powerful math magic
|
|
2360
|
-
const x = this.startPoint.x * Math.pow(1.0 - t, 3) +
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2323
|
+
const x = this.startPoint.x * Math.pow(1.0 - t, 3) +
|
|
2324
|
+
this.startControlPoint.x * 3 * t * Math.pow(1.0 - t, 2) +
|
|
2325
|
+
this.endControlPoint.x * 3 * Math.pow(t, 2) * (1.0 - t) +
|
|
2326
|
+
this.endPoint.x * Math.pow(t, 3);
|
|
2327
|
+
const y = this.startPoint.y * Math.pow(1.0 - t, 3) +
|
|
2328
|
+
this.startControlPoint.y * 3 * t * Math.pow(1.0 - t, 2) +
|
|
2329
|
+
this.endControlPoint.y * 3 * Math.pow(t, 2) * (1.0 - t) +
|
|
2330
|
+
this.endPoint.y * Math.pow(t, 3);
|
|
2364
2331
|
return new Vertex(x, y);
|
|
2365
2332
|
}
|
|
2366
|
-
;
|
|
2367
2333
|
/**
|
|
2368
2334
|
* Get the curve point at a given position u, where u is in [0,arcLength].<br>
|
|
2369
2335
|
* <br>
|
|
@@ -2379,7 +2345,6 @@ class CubicBezierCurve {
|
|
|
2379
2345
|
getPoint(u) {
|
|
2380
2346
|
return this.getPointAt(u / this.arcLength);
|
|
2381
2347
|
}
|
|
2382
|
-
;
|
|
2383
2348
|
/**
|
|
2384
2349
|
* Get the curve tangent vector at a given absolute curve position t in [0,1].<br>
|
|
2385
2350
|
* <br>
|
|
@@ -2400,18 +2365,11 @@ class CubicBezierCurve {
|
|
|
2400
2365
|
const t2 = t * t;
|
|
2401
2366
|
// (1 - t)^2 = (1-t)*(1-t) = 1 - t - t + t^2 = 1 - 2*t + t^2
|
|
2402
2367
|
const nt2 = 1 - 2 * t + t2;
|
|
2403
|
-
const tX = -3 * a.x * nt2 +
|
|
2404
|
-
|
|
2405
|
-
c.x * (6 * (t - t2) - 3 * t2) +
|
|
2406
|
-
3 * d.x * t2;
|
|
2407
|
-
const tY = -3 * a.y * nt2 +
|
|
2408
|
-
b.y * (3 * nt2 - 6 * (t - t2)) +
|
|
2409
|
-
c.y * (6 * (t - t2) - 3 * t2) +
|
|
2410
|
-
3 * d.y * t2;
|
|
2368
|
+
const tX = -3 * a.x * nt2 + b.x * (3 * nt2 - 6 * (t - t2)) + c.x * (6 * (t - t2) - 3 * t2) + 3 * d.x * t2;
|
|
2369
|
+
const tY = -3 * a.y * nt2 + b.y * (3 * nt2 - 6 * (t - t2)) + c.y * (6 * (t - t2) - 3 * t2) + 3 * d.y * t2;
|
|
2411
2370
|
// Note: my implementation does NOT normalize tangent vectors!
|
|
2412
2371
|
return new Vertex(tX, tY);
|
|
2413
2372
|
}
|
|
2414
|
-
;
|
|
2415
2373
|
/**
|
|
2416
2374
|
* Get a sub curve at the given start end end offsets (values between 0.0 and 1.0).
|
|
2417
2375
|
*
|
|
@@ -2437,7 +2395,6 @@ class CubicBezierCurve {
|
|
|
2437
2395
|
// pb.draw.cubicBezier( startVec.a, endVec.a, startVec.b, endVec.b, '#8800ff', 2 );
|
|
2438
2396
|
return new CubicBezierCurve(startVec.a, endVec.a, startVec.b, endVec.b);
|
|
2439
2397
|
}
|
|
2440
|
-
;
|
|
2441
2398
|
/**
|
|
2442
2399
|
* Convert a relative curve position u to the absolute curve position t.
|
|
2443
2400
|
*
|
|
@@ -2448,9 +2405,8 @@ class CubicBezierCurve {
|
|
|
2448
2405
|
* @return {number}
|
|
2449
2406
|
**/
|
|
2450
2407
|
convertU2T(u) {
|
|
2451
|
-
return Math.max(0.0, Math.min(1.0,
|
|
2408
|
+
return Math.max(0.0, Math.min(1.0, u / this.arcLength));
|
|
2452
2409
|
}
|
|
2453
|
-
;
|
|
2454
2410
|
/**
|
|
2455
2411
|
* Get the curve tangent vector at a given relative position u in [0,arcLength].<br>
|
|
2456
2412
|
* <br>
|
|
@@ -2465,7 +2421,6 @@ class CubicBezierCurve {
|
|
|
2465
2421
|
getTangent(u) {
|
|
2466
2422
|
return this.getTangentAt(this.convertU2T(u));
|
|
2467
2423
|
}
|
|
2468
|
-
;
|
|
2469
2424
|
/**
|
|
2470
2425
|
* Get the curve perpendicular at a given relative position u in [0,arcLength] as a vector.<br>
|
|
2471
2426
|
* <br>
|
|
@@ -2480,7 +2435,6 @@ class CubicBezierCurve {
|
|
|
2480
2435
|
getPerpendicular(u) {
|
|
2481
2436
|
return this.getPerpendicularAt(this.convertU2T(u));
|
|
2482
2437
|
}
|
|
2483
|
-
;
|
|
2484
2438
|
/**
|
|
2485
2439
|
* Get the curve perpendicular at a given absolute position t in [0,1] as a vector.<br>
|
|
2486
2440
|
* <br>
|
|
@@ -2496,7 +2450,6 @@ class CubicBezierCurve {
|
|
|
2496
2450
|
const tangentVector = this.getTangentAt(t);
|
|
2497
2451
|
return new Vertex(tangentVector.y, -tangentVector.x);
|
|
2498
2452
|
}
|
|
2499
|
-
;
|
|
2500
2453
|
/**
|
|
2501
2454
|
* Clone this Bézier curve (deep clone).
|
|
2502
2455
|
*
|
|
@@ -2508,7 +2461,6 @@ class CubicBezierCurve {
|
|
|
2508
2461
|
clone() {
|
|
2509
2462
|
return new CubicBezierCurve(this.getStartPoint().clone(), this.getEndPoint().clone(), this.getStartControlPoint().clone(), this.getEndControlPoint().clone());
|
|
2510
2463
|
}
|
|
2511
|
-
;
|
|
2512
2464
|
/**
|
|
2513
2465
|
* Check if this and the specified curve are equal.<br>
|
|
2514
2466
|
* <br>
|
|
@@ -2527,17 +2479,25 @@ class CubicBezierCurve {
|
|
|
2527
2479
|
// Let's see if this restricted version works out.
|
|
2528
2480
|
if (!curve)
|
|
2529
2481
|
return false;
|
|
2530
|
-
if (!curve.startPoint ||
|
|
2531
|
-
!curve.endPoint ||
|
|
2532
|
-
!curve.startControlPoint ||
|
|
2533
|
-
!curve.endControlPoint)
|
|
2482
|
+
if (!curve.startPoint || !curve.endPoint || !curve.startControlPoint || !curve.endControlPoint)
|
|
2534
2483
|
return false;
|
|
2535
|
-
return this.startPoint.equals(curve.startPoint)
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2484
|
+
return (this.startPoint.equals(curve.startPoint) &&
|
|
2485
|
+
this.endPoint.equals(curve.endPoint) &&
|
|
2486
|
+
this.startControlPoint.equals(curve.startControlPoint) &&
|
|
2487
|
+
this.endControlPoint.equals(curve.endControlPoint));
|
|
2488
|
+
}
|
|
2489
|
+
/**
|
|
2490
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
2491
|
+
* After calling this function the object might not hold valid data any more and
|
|
2492
|
+
* should not be used.
|
|
2493
|
+
*/
|
|
2494
|
+
destroy() {
|
|
2495
|
+
this.startPoint.destroy();
|
|
2496
|
+
this.endPoint.destroy();
|
|
2497
|
+
this.startControlPoint.destroy();
|
|
2498
|
+
this.endControlPoint.destroy();
|
|
2499
|
+
this.isDestroyed = true;
|
|
2539
2500
|
}
|
|
2540
|
-
;
|
|
2541
2501
|
/**
|
|
2542
2502
|
* Quick check for class instance.
|
|
2543
2503
|
* Is there a better way?
|
|
@@ -2563,41 +2523,6 @@ class CubicBezierCurve {
|
|
|
2563
2523
|
*/
|
|
2564
2524
|
return obj instanceof CubicBezierCurve;
|
|
2565
2525
|
}
|
|
2566
|
-
;
|
|
2567
|
-
/**
|
|
2568
|
-
* Create an SVG path data representation of this bézier curve.
|
|
2569
|
-
*
|
|
2570
|
-
* Path data string format is:<br>
|
|
2571
|
-
* <pre>'M x0 y1 C dx0 dy1 dx1 dy1 x1 x2'</pre><br>
|
|
2572
|
-
* or in other words<br>
|
|
2573
|
-
* <pre>'M startoint.x startPoint.y C startControlPoint.x startControlPoint.y endControlPoint.x endControlPoint.y endPoint.x endPoint.y'</pre>
|
|
2574
|
-
*
|
|
2575
|
-
* @method toSVGPathData
|
|
2576
|
-
* @instance
|
|
2577
|
-
* @memberof CubicBezierCurve
|
|
2578
|
-
* @return {string} The SVG path data string.
|
|
2579
|
-
**/
|
|
2580
|
-
toSVGPathData() {
|
|
2581
|
-
var buffer = [];
|
|
2582
|
-
buffer.push('M ');
|
|
2583
|
-
buffer.push(this.startPoint.x.toString());
|
|
2584
|
-
buffer.push(' ');
|
|
2585
|
-
buffer.push(this.startPoint.y.toString());
|
|
2586
|
-
buffer.push(' C ');
|
|
2587
|
-
buffer.push(this.startControlPoint.x.toString());
|
|
2588
|
-
buffer.push(' ');
|
|
2589
|
-
buffer.push(this.startControlPoint.y.toString());
|
|
2590
|
-
buffer.push(' ');
|
|
2591
|
-
buffer.push(this.endControlPoint.x.toString());
|
|
2592
|
-
buffer.push(' ');
|
|
2593
|
-
buffer.push(this.endControlPoint.y.toString());
|
|
2594
|
-
buffer.push(' ');
|
|
2595
|
-
buffer.push(this.endPoint.x.toString());
|
|
2596
|
-
buffer.push(' ');
|
|
2597
|
-
buffer.push(this.endPoint.y.toString());
|
|
2598
|
-
return buffer.join('');
|
|
2599
|
-
}
|
|
2600
|
-
;
|
|
2601
2526
|
/**
|
|
2602
2527
|
* Convert this curve to a JSON string.
|
|
2603
2528
|
*
|
|
@@ -2610,18 +2535,33 @@ class CubicBezierCurve {
|
|
|
2610
2535
|
toJSON(prettyFormat) {
|
|
2611
2536
|
var jsonString = "{ " + // begin object
|
|
2612
2537
|
(prettyFormat ? "\n\t" : "") +
|
|
2613
|
-
"
|
|
2538
|
+
'"startPoint" : [' +
|
|
2539
|
+
this.getStartPoint().x +
|
|
2540
|
+
"," +
|
|
2541
|
+
this.getStartPoint().y +
|
|
2542
|
+
"], " +
|
|
2614
2543
|
(prettyFormat ? "\n\t" : "") +
|
|
2615
|
-
"
|
|
2544
|
+
'"endPoint" : [' +
|
|
2545
|
+
this.getEndPoint().x +
|
|
2546
|
+
"," +
|
|
2547
|
+
this.getEndPoint().y +
|
|
2548
|
+
"], " +
|
|
2616
2549
|
(prettyFormat ? "\n\t" : "") +
|
|
2617
|
-
"
|
|
2550
|
+
'"startControlPoint": [' +
|
|
2551
|
+
this.getStartControlPoint().x +
|
|
2552
|
+
"," +
|
|
2553
|
+
this.getStartControlPoint().y +
|
|
2554
|
+
"], " +
|
|
2618
2555
|
(prettyFormat ? "\n\t" : "") +
|
|
2619
|
-
"
|
|
2556
|
+
'"endControlPoint" : [' +
|
|
2557
|
+
this.getEndControlPoint().x +
|
|
2558
|
+
"," +
|
|
2559
|
+
this.getEndControlPoint().y +
|
|
2560
|
+
"]" +
|
|
2620
2561
|
(prettyFormat ? "\n\t" : "") +
|
|
2621
2562
|
" }"; // end object
|
|
2622
2563
|
return jsonString;
|
|
2623
2564
|
}
|
|
2624
|
-
;
|
|
2625
2565
|
/**
|
|
2626
2566
|
* Parse a Bézier curve from the given JSON string.
|
|
2627
2567
|
*
|
|
@@ -2636,7 +2576,6 @@ class CubicBezierCurve {
|
|
|
2636
2576
|
var obj = JSON.parse(jsonString);
|
|
2637
2577
|
return CubicBezierCurve.fromObject(obj);
|
|
2638
2578
|
}
|
|
2639
|
-
;
|
|
2640
2579
|
/**
|
|
2641
2580
|
* Try to convert the passed object to a CubicBezierCurve.
|
|
2642
2581
|
*
|
|
@@ -2651,16 +2590,15 @@ class CubicBezierCurve {
|
|
|
2651
2590
|
if (typeof obj !== "object")
|
|
2652
2591
|
throw "Can only build from object.";
|
|
2653
2592
|
if (!obj.startPoint)
|
|
2654
|
-
throw
|
|
2593
|
+
throw 'Object member "startPoint" missing.';
|
|
2655
2594
|
if (!obj.endPoint)
|
|
2656
|
-
throw
|
|
2595
|
+
throw 'Object member "endPoint" missing.';
|
|
2657
2596
|
if (!obj.startControlPoint)
|
|
2658
|
-
throw
|
|
2597
|
+
throw 'Object member "startControlPoint" missing.';
|
|
2659
2598
|
if (!obj.endControlPoint)
|
|
2660
|
-
throw
|
|
2599
|
+
throw 'Object member "endControlPoint" missing.';
|
|
2661
2600
|
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]));
|
|
2662
2601
|
}
|
|
2663
|
-
;
|
|
2664
2602
|
/**
|
|
2665
2603
|
* Convert a 4-element array of vertices to a cubic bézier curve.
|
|
2666
2604
|
*
|
|
@@ -2677,7 +2615,6 @@ class CubicBezierCurve {
|
|
|
2677
2615
|
throw "Can only build from array with four elements.";
|
|
2678
2616
|
return new CubicBezierCurve(arr[0], arr[1], arr[2], arr[3]);
|
|
2679
2617
|
}
|
|
2680
|
-
;
|
|
2681
2618
|
}
|
|
2682
2619
|
/** @constant {number} */
|
|
2683
2620
|
CubicBezierCurve.START_POINT = 0;
|
|
@@ -2710,7 +2647,10 @@ CubicBezierCurve.END_POINT = 3;
|
|
|
2710
2647
|
* @modified 2020-07-24 Added the getClosestT(Vertex) function.
|
|
2711
2648
|
* @modified 2020-12-29 Constructor is now private (no explicit use intended).
|
|
2712
2649
|
* @modified 2021-05-25 Added BezierPath.fromReducedList( Array<number> ).
|
|
2713
|
-
* @
|
|
2650
|
+
* @modified 2022-01-31 Added `BezierPath.getEvenDistributionVertices(number)`.
|
|
2651
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
2652
|
+
* @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
2653
|
+
* @version 2.5.0
|
|
2714
2654
|
*
|
|
2715
2655
|
* @file BezierPath
|
|
2716
2656
|
* @public
|
|
@@ -3599,6 +3539,59 @@ class BezierPath {
|
|
|
3599
3539
|
}
|
|
3600
3540
|
return new Bounds(min, max);
|
|
3601
3541
|
}
|
|
3542
|
+
/**
|
|
3543
|
+
* Get n 'equally' distributed vertices along this Bézier path.
|
|
3544
|
+
*
|
|
3545
|
+
* As the changing curvature of the B slines makes prediction of distances difficult, the
|
|
3546
|
+
* returned vertices' distances are only relatively equal:
|
|
3547
|
+
* - the distance grows where curvature is large.
|
|
3548
|
+
* - the distance shrinks where curvature is small.
|
|
3549
|
+
*
|
|
3550
|
+
* Only the distance mean of all consecutive is 1/n-th of the total arc length.
|
|
3551
|
+
*
|
|
3552
|
+
* Usually this approximation is good enough for most use cases.
|
|
3553
|
+
*
|
|
3554
|
+
* @param {number} pointCount - (must be at least 2) The number of desired points (start and end point included).
|
|
3555
|
+
* @return {Array<Vertex>}
|
|
3556
|
+
*/
|
|
3557
|
+
getEvenDistributionVertices(pointCount) {
|
|
3558
|
+
if (pointCount < 2) {
|
|
3559
|
+
throw new Error("pointCount must be larger than one; is " + pointCount + ".");
|
|
3560
|
+
}
|
|
3561
|
+
const result = [];
|
|
3562
|
+
if (this.bezierCurves.length === 0) {
|
|
3563
|
+
return result;
|
|
3564
|
+
}
|
|
3565
|
+
// Fetch and add the start point from the source polygon
|
|
3566
|
+
var polygonPoint = new Vertex(this.bezierCurves[0].startPoint);
|
|
3567
|
+
result.push(polygonPoint);
|
|
3568
|
+
// if (this.bezierCurves.length === 1) {
|
|
3569
|
+
// return result;
|
|
3570
|
+
// }
|
|
3571
|
+
const perimeter = this.totalArcLength;
|
|
3572
|
+
const stepSize = perimeter / (pointCount - 1);
|
|
3573
|
+
const n = this.bezierCurves.length;
|
|
3574
|
+
let curveIndex = 0;
|
|
3575
|
+
let segmentLength = this.bezierCurves[0].arcLength;
|
|
3576
|
+
let curSegmentU = stepSize;
|
|
3577
|
+
let i = 1;
|
|
3578
|
+
while (i < pointCount && curveIndex < n) {
|
|
3579
|
+
// Check if next eq point is inside this segment
|
|
3580
|
+
if (curSegmentU < segmentLength) {
|
|
3581
|
+
var newPoint = this.bezierCurves[curveIndex].getPoint(curSegmentU);
|
|
3582
|
+
result.push(newPoint);
|
|
3583
|
+
curSegmentU += stepSize;
|
|
3584
|
+
i++;
|
|
3585
|
+
}
|
|
3586
|
+
else {
|
|
3587
|
+
curveIndex++;
|
|
3588
|
+
curSegmentU = curSegmentU - segmentLength;
|
|
3589
|
+
segmentLength = curveIndex < n ? this.bezierCurves[curveIndex].arcLength : 0;
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
result.push(new Vertex(this.bezierCurves[n - 1].endPoint));
|
|
3593
|
+
return result;
|
|
3594
|
+
}
|
|
3602
3595
|
/**
|
|
3603
3596
|
* Clone this BezierPath (deep clone).
|
|
3604
3597
|
*
|
|
@@ -3645,30 +3638,15 @@ class BezierPath {
|
|
|
3645
3638
|
return true;
|
|
3646
3639
|
}
|
|
3647
3640
|
/**
|
|
3648
|
-
*
|
|
3649
|
-
*
|
|
3650
|
-
*
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
* @memberof BezierPath
|
|
3656
|
-
* @return {string} The SVG string.
|
|
3657
|
-
**/
|
|
3658
|
-
toSVGString(options) {
|
|
3659
|
-
options = options || {};
|
|
3660
|
-
var buffer = [];
|
|
3661
|
-
buffer.push("<path");
|
|
3662
|
-
if (options.className)
|
|
3663
|
-
buffer.push(' class="' + options.className + '"');
|
|
3664
|
-
buffer.push(' d="');
|
|
3665
|
-
for (var c = 0; c < this.bezierCurves.length; c++) {
|
|
3666
|
-
if (c > 0)
|
|
3667
|
-
buffer.push(" ");
|
|
3668
|
-
buffer.push(this.bezierCurves[c].toSVGPathData());
|
|
3641
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
3642
|
+
* After calling this function the object might not hold valid data any more and
|
|
3643
|
+
* should not be used.
|
|
3644
|
+
*/
|
|
3645
|
+
destroy() {
|
|
3646
|
+
for (var i = 0; i < this.bezierCurves.length; i++) {
|
|
3647
|
+
this.bezierCurves[i].destroy();
|
|
3669
3648
|
}
|
|
3670
|
-
|
|
3671
|
-
return buffer.join("");
|
|
3649
|
+
this.isDestroyed = true;
|
|
3672
3650
|
}
|
|
3673
3651
|
/**
|
|
3674
3652
|
* Create a JSON string representation of this bézier curve.
|
|
@@ -3895,7 +3873,8 @@ BezierPath.END_POINT = 3;
|
|
|
3895
3873
|
* @modified 2020-03-16 The Line.angle(Line) parameter is now optional. The baseline (x-axis) will be used if not defined.
|
|
3896
3874
|
* @modified 2020-03-23 Ported to Typescript from JS.
|
|
3897
3875
|
* @modified 2020-12-04 The `intersection` function returns undefined if both lines are parallel.
|
|
3898
|
-
* @
|
|
3876
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
3877
|
+
* @version 2.2.0
|
|
3899
3878
|
*
|
|
3900
3879
|
* @file Line
|
|
3901
3880
|
* @public
|
|
@@ -3940,45 +3919,19 @@ class Line extends VertTuple {
|
|
|
3940
3919
|
return null;
|
|
3941
3920
|
let a = this.a.y - line.a.y;
|
|
3942
3921
|
let b = this.a.x - line.a.x;
|
|
3943
|
-
const numerator1 = (
|
|
3944
|
-
const numerator2 = (
|
|
3922
|
+
const numerator1 = (line.b.x - line.a.x) * a - (line.b.y - line.a.y) * b;
|
|
3923
|
+
const numerator2 = (this.b.x - this.a.x) * a - (this.b.y - this.a.y) * b;
|
|
3945
3924
|
a = numerator1 / denominator; // NaN if parallel lines
|
|
3946
3925
|
b = numerator2 / denominator;
|
|
3947
3926
|
// Catch NaN?
|
|
3948
|
-
const x = this.a.x +
|
|
3949
|
-
const y = this.a.y +
|
|
3927
|
+
const x = this.a.x + a * (this.b.x - this.a.x);
|
|
3928
|
+
const y = this.a.y + a * (this.b.y - this.a.y);
|
|
3950
3929
|
if (isNaN(a) || isNaN(x) || isNaN(y)) {
|
|
3951
3930
|
return undefined;
|
|
3952
3931
|
}
|
|
3953
3932
|
// if we cast these lines infinitely in both directions, they intersect here:
|
|
3954
3933
|
return new Vertex(x, y);
|
|
3955
3934
|
}
|
|
3956
|
-
;
|
|
3957
|
-
/**
|
|
3958
|
-
* Create an SVG representation of this line.
|
|
3959
|
-
*
|
|
3960
|
-
* @deprecated DEPRECATION Please use the drawutilssvg library and an XMLSerializer instead.
|
|
3961
|
-
* @method toSVGString
|
|
3962
|
-
* @param {options} p - A set of options, like the 'classname' to use
|
|
3963
|
-
* for the line object.
|
|
3964
|
-
* @return {string} The SVG string representing this line.
|
|
3965
|
-
* @instance
|
|
3966
|
-
* @memberof Line
|
|
3967
|
-
**/
|
|
3968
|
-
toSVGString(options) {
|
|
3969
|
-
options = options || {};
|
|
3970
|
-
var buffer = [];
|
|
3971
|
-
buffer.push('<line');
|
|
3972
|
-
if (options.className)
|
|
3973
|
-
buffer.push(' class="' + options.className + '"');
|
|
3974
|
-
buffer.push(' x1="' + this.a.x + '"');
|
|
3975
|
-
buffer.push(' y1="' + this.a.y + '"');
|
|
3976
|
-
buffer.push(' x2="' + this.b.x + '"');
|
|
3977
|
-
buffer.push(' y2="' + this.b.y + '"');
|
|
3978
|
-
buffer.push(' />');
|
|
3979
|
-
return buffer.join('');
|
|
3980
|
-
}
|
|
3981
|
-
;
|
|
3982
3935
|
}
|
|
3983
3936
|
|
|
3984
3937
|
/**
|
|
@@ -3990,7 +3943,9 @@ class Line extends VertTuple {
|
|
|
3990
3943
|
* @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.
|
|
3991
3944
|
* @modified 2020-10-16 Added the containsCircle(...) function.
|
|
3992
3945
|
* @modified 2021-01-20 Added UID.
|
|
3993
|
-
* @
|
|
3946
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
3947
|
+
* @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
3948
|
+
* @version 1.3.0
|
|
3994
3949
|
**/
|
|
3995
3950
|
/**
|
|
3996
3951
|
* @classdesc A simple circle: center point and radius.
|
|
@@ -4021,7 +3976,6 @@ class Circle {
|
|
|
4021
3976
|
this.center = center;
|
|
4022
3977
|
this.radius = radius;
|
|
4023
3978
|
}
|
|
4024
|
-
;
|
|
4025
3979
|
/**
|
|
4026
3980
|
* Check if the given circle is fully contained inside this circle.
|
|
4027
3981
|
*
|
|
@@ -4034,7 +3988,6 @@ class Circle {
|
|
|
4034
3988
|
containsCircle(circle) {
|
|
4035
3989
|
return this.center.distance(circle.center) + circle.radius < this.radius;
|
|
4036
3990
|
}
|
|
4037
|
-
;
|
|
4038
3991
|
/**
|
|
4039
3992
|
* Calculate the distance from this circle to the given line.
|
|
4040
3993
|
*
|
|
@@ -4053,7 +4006,6 @@ class Circle {
|
|
|
4053
4006
|
const closestPointOnLine = line.getClosestPoint(this.center);
|
|
4054
4007
|
return closestPointOnLine.distance(this.center) - this.radius;
|
|
4055
4008
|
}
|
|
4056
|
-
;
|
|
4057
4009
|
/**
|
|
4058
4010
|
* Get the vertex on the this circle for the given angle.
|
|
4059
4011
|
*
|
|
@@ -4067,7 +4019,6 @@ class Circle {
|
|
|
4067
4019
|
// Find the point on the circle respective the angle. Then move relative to center.
|
|
4068
4020
|
return Circle.circleUtils.vertAt(angle, this.radius).add(this.center);
|
|
4069
4021
|
}
|
|
4070
|
-
;
|
|
4071
4022
|
/**
|
|
4072
4023
|
* Get a tangent line of this circle for a given angle.
|
|
4073
4024
|
*
|
|
@@ -4084,7 +4035,6 @@ class Circle {
|
|
|
4084
4035
|
// Construct the perpendicular of the line in point a. Then move relative to center.
|
|
4085
4036
|
return new Vector(pointA, new Vertex(0, 0)).add(this.center).perp();
|
|
4086
4037
|
}
|
|
4087
|
-
;
|
|
4088
4038
|
/**
|
|
4089
4039
|
* Calculate the intersection points (if exists) with the given circle.
|
|
4090
4040
|
*
|
|
@@ -4124,48 +4074,33 @@ class Circle {
|
|
|
4124
4074
|
// x4 = P2.x - h*(P1.y - P0.y)/d;
|
|
4125
4075
|
// y4 = P2.y + h*(P1.x - P0.x)/d;
|
|
4126
4076
|
// return pair<Point, Point>(Point(x3, y3), Point(x4, y4));
|
|
4127
|
-
// }
|
|
4077
|
+
// }
|
|
4128
4078
|
var p0 = this.center;
|
|
4129
4079
|
var p1 = circle.center;
|
|
4130
4080
|
var d = p0.distance(p1);
|
|
4131
4081
|
var a = (this.radius * this.radius - circle.radius * circle.radius + d * d) / (2 * d);
|
|
4132
4082
|
var h = Math.sqrt(this.radius * this.radius - a * a);
|
|
4133
4083
|
var p2 = p1.clone().scale(a / d, p0);
|
|
4134
|
-
var x3 = p2.x + h * (p1.y - p0.y) / d;
|
|
4135
|
-
var y3 = p2.y - h * (p1.x - p0.x) / d;
|
|
4136
|
-
var x4 = p2.x - h * (p1.y - p0.y) / d;
|
|
4137
|
-
var y4 = p2.y + h * (p1.x - p0.x) / d;
|
|
4084
|
+
var x3 = p2.x + (h * (p1.y - p0.y)) / d;
|
|
4085
|
+
var y3 = p2.y - (h * (p1.x - p0.x)) / d;
|
|
4086
|
+
var x4 = p2.x - (h * (p1.y - p0.y)) / d;
|
|
4087
|
+
var y4 = p2.y + (h * (p1.x - p0.x)) / d;
|
|
4138
4088
|
return new Line(new Vertex(x3, y3), new Vertex(x4, y4));
|
|
4139
4089
|
}
|
|
4140
|
-
;
|
|
4141
4090
|
/**
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
* @memberof Circle
|
|
4150
|
-
*/
|
|
4151
|
-
toSVGString(options) {
|
|
4152
|
-
options = options || {};
|
|
4153
|
-
var buffer = [];
|
|
4154
|
-
buffer.push('<circle');
|
|
4155
|
-
if (options.className)
|
|
4156
|
-
buffer.push(' class="' + options.className + '"');
|
|
4157
|
-
buffer.push(' cx="' + this.center.x + '"');
|
|
4158
|
-
buffer.push(' cy="' + this.center.y + '"');
|
|
4159
|
-
buffer.push(' r="' + this.radius + '"');
|
|
4160
|
-
buffer.push(' />');
|
|
4161
|
-
return buffer.join('');
|
|
4091
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
4092
|
+
* After calling this function the object might not hold valid data any more and
|
|
4093
|
+
* should not be used.
|
|
4094
|
+
*/
|
|
4095
|
+
destroy() {
|
|
4096
|
+
this.center.destroy();
|
|
4097
|
+
this.isDestroyed = true;
|
|
4162
4098
|
}
|
|
4163
|
-
;
|
|
4164
4099
|
} // END class
|
|
4165
4100
|
Circle.circleUtils = {
|
|
4166
4101
|
vertAt: (angle, radius) => {
|
|
4167
4102
|
/* return new Vertex( Math.sin(angle) * radius,
|
|
4168
|
-
|
|
4103
|
+
Math.cos(angle) * radius ); */
|
|
4169
4104
|
return new Vertex(Math.cos(angle) * radius, Math.sin(angle) * radius);
|
|
4170
4105
|
}
|
|
4171
4106
|
};
|
|
@@ -4206,27 +4141,15 @@ class CircleSector {
|
|
|
4206
4141
|
this.startAngle = startAngle;
|
|
4207
4142
|
this.endAngle = endAngle;
|
|
4208
4143
|
}
|
|
4209
|
-
;
|
|
4210
4144
|
/**
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
*/
|
|
4219
|
-
toSVGString(options) {
|
|
4220
|
-
options = options || {};
|
|
4221
|
-
var buffer = [];
|
|
4222
|
-
buffer.push('<path ');
|
|
4223
|
-
if (options.className)
|
|
4224
|
-
buffer.push(' class="' + options.className + '"');
|
|
4225
|
-
const data = CircleSector.circleSectorUtils.describeSVGArc(this.circle.center.x, this.circle.center.y, this.circle.radius, this.startAngle, this.endAngle);
|
|
4226
|
-
buffer.push(' d="' + data.join(" ") + '" />');
|
|
4227
|
-
return buffer.join('');
|
|
4145
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
4146
|
+
* After calling this function the object might not hold valid data any more and
|
|
4147
|
+
* should not be used.
|
|
4148
|
+
*/
|
|
4149
|
+
destroy() {
|
|
4150
|
+
this.circle.destroy();
|
|
4151
|
+
this.isDestroyed = true;
|
|
4228
4152
|
}
|
|
4229
|
-
;
|
|
4230
4153
|
} // END class
|
|
4231
4154
|
CircleSector.circleSectorUtils = {
|
|
4232
4155
|
/**
|
|
@@ -4235,11 +4158,11 @@ CircleSector.circleSectorUtils = {
|
|
|
4235
4158
|
* TODO: generalize for ellipses (two radii).
|
|
4236
4159
|
*
|
|
4237
4160
|
* @param {number} angle - The angle in radians.
|
|
4238
|
-
|
|
4161
|
+
*/
|
|
4239
4162
|
polarToCartesian: (centerX, centerY, radius, angle) => {
|
|
4240
4163
|
return {
|
|
4241
|
-
x: centerX +
|
|
4242
|
-
y: centerY +
|
|
4164
|
+
x: centerX + radius * Math.cos(angle),
|
|
4165
|
+
y: centerY + radius * Math.sin(angle)
|
|
4243
4166
|
};
|
|
4244
4167
|
},
|
|
4245
4168
|
/**
|
|
@@ -4252,7 +4175,7 @@ CircleSector.circleSectorUtils = {
|
|
|
4252
4175
|
* @return [ 'A', radiusx, radiusy, rotation=0, largeArcFlag=1|0, sweepFlag=0, endx, endy ]
|
|
4253
4176
|
*/
|
|
4254
4177
|
describeSVGArc: (x, y, radius, startAngle, endAngle, options) => {
|
|
4255
|
-
if (typeof options ===
|
|
4178
|
+
if (typeof options === "undefined")
|
|
4256
4179
|
options = { moveToStart: true };
|
|
4257
4180
|
const end = CircleSector.circleSectorUtils.polarToCartesian(x, y, radius, endAngle);
|
|
4258
4181
|
const start = CircleSector.circleSectorUtils.polarToCartesian(x, y, radius, startAngle);
|
|
@@ -4277,7 +4200,7 @@ CircleSector.circleSectorUtils = {
|
|
|
4277
4200
|
}
|
|
4278
4201
|
const pathData = [];
|
|
4279
4202
|
if (options.moveToStart) {
|
|
4280
|
-
pathData.push(
|
|
4203
|
+
pathData.push("M", start.x, start.y);
|
|
4281
4204
|
}
|
|
4282
4205
|
pathData.push("A", radius, radius, 0, largeArcFlag, sweepFlag, end.x, end.y);
|
|
4283
4206
|
return pathData;
|
|
@@ -4315,7 +4238,12 @@ CircleSector.circleSectorUtils = {
|
|
|
4315
4238
|
* @modified 2021-11-15 Adding more parameters tot the `text()` function: fontSize, textAlign, fontFamily, lineHeight.
|
|
4316
4239
|
* @modified 2021-11-19 Fixing the `label(text,x,y)` position.
|
|
4317
4240
|
* @modified 2021-11-19 Added the `color` param to the `label(...)` function.
|
|
4318
|
-
* @
|
|
4241
|
+
* @modified 2022-02-03 Added the `lineWidth` param to the `crosshair` function.
|
|
4242
|
+
* @modified 2022-02-03 Added the `cross(...)` function.
|
|
4243
|
+
* @modified 2022-03-26 Added the private `nodeDefs` and `bufferedNodeDefs` attributes.
|
|
4244
|
+
* @modified 2022-03-26 Added the `texturedPoly` function to draw textures polygons.
|
|
4245
|
+
* @modified 2022-07-26 Adding `alpha` to the `image(...)` function.
|
|
4246
|
+
* @version 1.6.1
|
|
4319
4247
|
**/
|
|
4320
4248
|
const RAD_TO_DEG = 180 / Math.PI;
|
|
4321
4249
|
/**
|
|
@@ -4342,7 +4270,7 @@ class drawutilssvg {
|
|
|
4342
4270
|
* @param {boolean=} isSecondary - (optional) Indicates if this is the primary or secondary instance. Only primary instances manage child nodes.
|
|
4343
4271
|
* @param {SVGGElement=} gNode - (optional) Primary and seconday instances share the same <g> node.
|
|
4344
4272
|
**/
|
|
4345
|
-
constructor(svgNode, offset, scale, canvasSize, fillShapes, drawConfig, isSecondary, gNode, bufferGNode) {
|
|
4273
|
+
constructor(svgNode, offset, scale, canvasSize, fillShapes, drawConfig, isSecondary, gNode, bufferGNode, nodeDefs, bufferNodeDefs) {
|
|
4346
4274
|
this.svgNode = svgNode;
|
|
4347
4275
|
this.offset = new Vertex(0, 0).set(offset);
|
|
4348
4276
|
this.scale = new Vertex(1, 1).set(scale);
|
|
@@ -4354,14 +4282,23 @@ class drawutilssvg {
|
|
|
4354
4282
|
if (isSecondary) {
|
|
4355
4283
|
this.gNode = gNode;
|
|
4356
4284
|
this.bufferGNode = bufferGNode;
|
|
4285
|
+
this.nodeDefs = nodeDefs;
|
|
4286
|
+
this.bufferedNodeDefs = bufferNodeDefs;
|
|
4357
4287
|
}
|
|
4358
4288
|
else {
|
|
4359
4289
|
this.addStyleDefs(drawConfig);
|
|
4290
|
+
this.addDefsNode();
|
|
4360
4291
|
this.gNode = this.createSVGNode("g");
|
|
4361
4292
|
this.bufferGNode = this.createSVGNode("g");
|
|
4362
4293
|
this.svgNode.appendChild(this.gNode);
|
|
4363
4294
|
}
|
|
4364
4295
|
}
|
|
4296
|
+
/**
|
|
4297
|
+
* Adds a default style defintion based on the passed DrawConfig.
|
|
4298
|
+
* Twaek the draw config to change default colors or line thicknesses.
|
|
4299
|
+
*
|
|
4300
|
+
* @param {DrawConfig} drawConfig
|
|
4301
|
+
*/
|
|
4365
4302
|
addStyleDefs(drawConfig) {
|
|
4366
4303
|
this.nodeStyle = this.createSVGNode("style");
|
|
4367
4304
|
this.svgNode.appendChild(this.nodeStyle);
|
|
@@ -4394,6 +4331,15 @@ class drawutilssvg {
|
|
|
4394
4331
|
}
|
|
4395
4332
|
this.nodeStyle.innerHTML = rules.join("\n");
|
|
4396
4333
|
}
|
|
4334
|
+
/**
|
|
4335
|
+
* Adds the internal <defs> node.
|
|
4336
|
+
*/
|
|
4337
|
+
addDefsNode() {
|
|
4338
|
+
this.nodeDefs = this.createSVGNode("defs");
|
|
4339
|
+
// this.svgNode.appendChild(this.nodeDefs);
|
|
4340
|
+
this.bufferedNodeDefs = this.createSVGNode("defs");
|
|
4341
|
+
this.svgNode.appendChild(this.nodeDefs);
|
|
4342
|
+
}
|
|
4397
4343
|
/**
|
|
4398
4344
|
* This is a simple way to include custom CSS class mappings to the style defs of the generated SVG.
|
|
4399
4345
|
*
|
|
@@ -4531,7 +4477,7 @@ class drawutilssvg {
|
|
|
4531
4477
|
copyInstance(fillShapes) {
|
|
4532
4478
|
var copy = new drawutilssvg(this.svgNode, this.offset, this.scale, this.canvasSize, fillShapes, null, // no DrawConfig
|
|
4533
4479
|
true, // isSecondary
|
|
4534
|
-
this.gNode, this.bufferGNode);
|
|
4480
|
+
this.gNode, this.bufferGNode, this.nodeDefs, this.bufferedNodeDefs);
|
|
4535
4481
|
return copy;
|
|
4536
4482
|
}
|
|
4537
4483
|
/**
|
|
@@ -4608,11 +4554,15 @@ class drawutilssvg {
|
|
|
4608
4554
|
// layout updates.
|
|
4609
4555
|
// Replace the old <g>-node with the buffer node.
|
|
4610
4556
|
// https://stackoverflow.com/questions/27442464/how-to-update-a-svg-image-without-seeing-a-blinking
|
|
4557
|
+
this.svgNode.replaceChild(this.bufferedNodeDefs, this.nodeDefs);
|
|
4611
4558
|
this.svgNode.replaceChild(this.bufferGNode, this.gNode);
|
|
4612
4559
|
}
|
|
4613
|
-
|
|
4560
|
+
const tmpGNode = this.gNode;
|
|
4614
4561
|
this.gNode = this.bufferGNode;
|
|
4615
|
-
this.bufferGNode =
|
|
4562
|
+
this.bufferGNode = tmpGNode;
|
|
4563
|
+
const tmpDefsNode = this.nodeDefs;
|
|
4564
|
+
this.nodeDefs = this.bufferedNodeDefs;
|
|
4565
|
+
this.bufferedNodeDefs = tmpDefsNode;
|
|
4616
4566
|
}
|
|
4617
4567
|
_x(x) {
|
|
4618
4568
|
return this.offset.x + this.scale.x * x;
|
|
@@ -4675,11 +4625,12 @@ class drawutilssvg {
|
|
|
4675
4625
|
* @param {Image} image - The image object to draw.
|
|
4676
4626
|
* @param {Vertex} position - The position to draw the the upper left corner at.
|
|
4677
4627
|
* @param {Vertex} size - The x/y-size to draw the image with.
|
|
4628
|
+
* @param {number=0.0} alpha - (optional, default=0.0) The transparency (1.0=opaque, 0.0=transparent).
|
|
4678
4629
|
* @return {void}
|
|
4679
4630
|
* @instance
|
|
4680
4631
|
* @memberof drawutilssvg
|
|
4681
4632
|
**/
|
|
4682
|
-
image(image, position, size) {
|
|
4633
|
+
image(image, position, size, alpha = 1.0) {
|
|
4683
4634
|
const node = this.makeNode("image");
|
|
4684
4635
|
// We need to re-adjust the image if it was not yet fully loaded before.
|
|
4685
4636
|
const setImageSize = (image) => {
|
|
@@ -4689,6 +4640,9 @@ class drawutilssvg {
|
|
|
4689
4640
|
node.setAttribute("width", `${image.naturalWidth * this.scale.x}`);
|
|
4690
4641
|
node.setAttribute("height", `${image.naturalHeight * this.scale.y}`);
|
|
4691
4642
|
node.setAttribute("display", null); // Dislay when loaded
|
|
4643
|
+
// if (alpha) {
|
|
4644
|
+
node.setAttribute("opacity", `${alpha}`);
|
|
4645
|
+
// }
|
|
4692
4646
|
node.setAttribute("transform", `translate(${this._x(position.x)} ${this._y(position.y)}) scale(${ratioX} ${ratioY})`);
|
|
4693
4647
|
}
|
|
4694
4648
|
};
|
|
@@ -4704,6 +4658,74 @@ class drawutilssvg {
|
|
|
4704
4658
|
node.setAttribute("href", image.src);
|
|
4705
4659
|
return this._bindFillDraw(node, "image", null, null);
|
|
4706
4660
|
}
|
|
4661
|
+
/**
|
|
4662
|
+
* Draw an image at the given position with the given size.<br>
|
|
4663
|
+
* <br>
|
|
4664
|
+
* 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.
|
|
4665
|
+
*
|
|
4666
|
+
* @method texturedPoly
|
|
4667
|
+
* @param {Image} textureImage - The image object to draw.
|
|
4668
|
+
* @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
|
|
4669
|
+
* @param {Polygon} polygon - The polygon to use as clip path.
|
|
4670
|
+
* @param {Vertex} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
|
|
4671
|
+
* @param {number} rotation - The rotation to use for the polygon (and for the texture).
|
|
4672
|
+
* @return {void}
|
|
4673
|
+
* @instance
|
|
4674
|
+
* @memberof drawutilssvg
|
|
4675
|
+
**/
|
|
4676
|
+
texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
|
|
4677
|
+
polygon.getBounds();
|
|
4678
|
+
const rotatedScalingOrigin = new Vertex(textureSize.min).clone().rotate(rotation, polygonPosition);
|
|
4679
|
+
polygonPosition.clone().add(rotatedScalingOrigin.difference(textureSize.min).inv());
|
|
4680
|
+
// Create something like this
|
|
4681
|
+
// ...
|
|
4682
|
+
// <defs>
|
|
4683
|
+
// <clipPath id="shape">
|
|
4684
|
+
// <path fill="none" d="..."/>
|
|
4685
|
+
// </clipPath>
|
|
4686
|
+
// </defs>
|
|
4687
|
+
// ...
|
|
4688
|
+
// <g clip-path="url(#shape)">
|
|
4689
|
+
// <g transform="scale(...)">
|
|
4690
|
+
// <image width="643" height="643" transform="rotate(...)" xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/beagle400.jpg" >
|
|
4691
|
+
// </g>
|
|
4692
|
+
// </g>
|
|
4693
|
+
// </image>
|
|
4694
|
+
// ...
|
|
4695
|
+
const clipPathNode = this.makeNode("clipPath");
|
|
4696
|
+
const clipPathId = `clippath_${UIDGenerator.next()}`; // TODO: use a better UUID generator here?
|
|
4697
|
+
clipPathNode.setAttribute("id", clipPathId);
|
|
4698
|
+
const gNode = this.makeNode("g");
|
|
4699
|
+
const imageNode = this.makeNode("image");
|
|
4700
|
+
imageNode.setAttribute("x", `${this._x(rotatedScalingOrigin.x)}`);
|
|
4701
|
+
imageNode.setAttribute("y", `${this._y(rotatedScalingOrigin.y)}`);
|
|
4702
|
+
imageNode.setAttribute("width", `${textureSize.width}`);
|
|
4703
|
+
imageNode.setAttribute("height", `${textureSize.height}`);
|
|
4704
|
+
imageNode.setAttribute("href", textureImage.src);
|
|
4705
|
+
// imageNode.setAttribute("opacity", "0.5");
|
|
4706
|
+
// SVG rotations in degrees
|
|
4707
|
+
imageNode.setAttribute("transform", `rotate(${rotation * RAD_TO_DEG}, ${this._x(rotatedScalingOrigin.x)}, ${this._y(rotatedScalingOrigin.y)})`);
|
|
4708
|
+
const pathNode = this.makeNode("path");
|
|
4709
|
+
const pathData = [];
|
|
4710
|
+
if (polygon.vertices.length > 0) {
|
|
4711
|
+
pathData.push("M", `${this._x(polygon.vertices[0].x)}`, `${this._y(polygon.vertices[0].y)}`);
|
|
4712
|
+
for (var i = 1; i < polygon.vertices.length; i++) {
|
|
4713
|
+
pathData.push("L", `${this._x(polygon.vertices[i].x)}`, `${this._y(polygon.vertices[i].y)}`);
|
|
4714
|
+
}
|
|
4715
|
+
}
|
|
4716
|
+
pathNode.setAttribute("d", pathData.join(" "));
|
|
4717
|
+
clipPathNode.appendChild(pathNode);
|
|
4718
|
+
this.bufferedNodeDefs.appendChild(clipPathNode);
|
|
4719
|
+
gNode.appendChild(imageNode);
|
|
4720
|
+
gNode.setAttribute("transform-origin", `${this._x(rotatedScalingOrigin.x)} ${this._y(rotatedScalingOrigin.y)}`);
|
|
4721
|
+
gNode.setAttribute("transform", `scale(${this.scale.x}, ${this.scale.y})`);
|
|
4722
|
+
const clipNode = this.makeNode("g");
|
|
4723
|
+
clipNode.appendChild(gNode);
|
|
4724
|
+
clipNode.setAttribute("clip-path", `url(#${clipPathId})`);
|
|
4725
|
+
// TODO: check if the image class is correct here or if we should use a 'clippedImage' class here
|
|
4726
|
+
this._bindFillDraw(clipNode, "image", null, null); // No color, no lineWidth
|
|
4727
|
+
return clipNode;
|
|
4728
|
+
}
|
|
4707
4729
|
/**
|
|
4708
4730
|
* Draw the given (cubic) bézier curve.
|
|
4709
4731
|
*
|
|
@@ -5096,11 +5118,12 @@ class drawutilssvg {
|
|
|
5096
5118
|
* @param {XYCoords} center - The center of the crosshair.
|
|
5097
5119
|
* @param {number} radius - The radius of the crosshair.
|
|
5098
5120
|
* @param {string} color - The CSS color to draw the crosshair with.
|
|
5121
|
+
* @param {number=0.5} lineWidth - (optional, default=0.5) The line width to use.
|
|
5099
5122
|
* @return {void}
|
|
5100
5123
|
* @instance
|
|
5101
5124
|
* @memberof drawutilssvg
|
|
5102
5125
|
*/
|
|
5103
|
-
crosshair(center, radius, color) {
|
|
5126
|
+
crosshair(center, radius, color, lineWidth) {
|
|
5104
5127
|
const node = this.makeNode("path");
|
|
5105
5128
|
const d = [
|
|
5106
5129
|
"M",
|
|
@@ -5117,7 +5140,40 @@ class drawutilssvg {
|
|
|
5117
5140
|
this._y(center.y) + radius
|
|
5118
5141
|
];
|
|
5119
5142
|
node.setAttribute("d", d.join(" "));
|
|
5120
|
-
return this._bindFillDraw(node, "crosshair", color, 0.5);
|
|
5143
|
+
return this._bindFillDraw(node, "crosshair", color, lineWidth || 0.5);
|
|
5144
|
+
}
|
|
5145
|
+
/**
|
|
5146
|
+
* Draw a cross with diagonal axes with given radius, color and lineWidth at the given position.<br>
|
|
5147
|
+
* <br>
|
|
5148
|
+
* Note that the x's radius will not be affected by scaling.
|
|
5149
|
+
*
|
|
5150
|
+
* @method crosshair
|
|
5151
|
+
* @param {XYCoords} center - The center of the crosshair.
|
|
5152
|
+
* @param {number} radius - The radius of the crosshair.
|
|
5153
|
+
* @param {string} color - The CSS color to draw the crosshair with.
|
|
5154
|
+
* @param {number=1} lineWidth - (optional, default=1.0) The line width to use.
|
|
5155
|
+
* @return {void}
|
|
5156
|
+
* @instance
|
|
5157
|
+
* @memberof drawutils
|
|
5158
|
+
*/
|
|
5159
|
+
cross(center, radius, color, lineWidth) {
|
|
5160
|
+
const node = this.makeNode("path");
|
|
5161
|
+
const d = [
|
|
5162
|
+
"M",
|
|
5163
|
+
this._x(center.x) - radius,
|
|
5164
|
+
this._y(center.y) - radius,
|
|
5165
|
+
"L",
|
|
5166
|
+
this._x(center.x) + radius,
|
|
5167
|
+
this._y(center.y) + radius,
|
|
5168
|
+
"M",
|
|
5169
|
+
this._x(center.x) - radius,
|
|
5170
|
+
this._y(center.y) + radius,
|
|
5171
|
+
"L",
|
|
5172
|
+
this._x(center.x) + radius,
|
|
5173
|
+
this._y(center.y) - radius
|
|
5174
|
+
];
|
|
5175
|
+
node.setAttribute("d", d.join(" "));
|
|
5176
|
+
return this._bindFillDraw(node, "cross", color, lineWidth || 1.0);
|
|
5121
5177
|
}
|
|
5122
5178
|
/**
|
|
5123
5179
|
* Draw a polygon.
|
|
@@ -5280,14 +5336,6 @@ class drawutilssvg {
|
|
|
5280
5336
|
if (this.isSecondary) {
|
|
5281
5337
|
return;
|
|
5282
5338
|
}
|
|
5283
|
-
// // Clearing an SVG is equivalent to removing all its child elements.
|
|
5284
|
-
// for (var i = 0; i < this.gNode.childNodes.length; i++) {
|
|
5285
|
-
// // Hide all nodes here. Don't throw them away.
|
|
5286
|
-
// // We can probably re-use them in the next draw cycle.
|
|
5287
|
-
// var child: SVGElement = this.gNode.childNodes[i] as SVGElement;
|
|
5288
|
-
// this.cache.set(child.getAttribute("id"), child);
|
|
5289
|
-
// }
|
|
5290
|
-
// this.removeAllChildNodes();
|
|
5291
5339
|
// Add a covering rect with the given background color
|
|
5292
5340
|
this.curId = "background";
|
|
5293
5341
|
this.curClassName = undefined;
|
|
@@ -5313,6 +5361,9 @@ class drawutilssvg {
|
|
|
5313
5361
|
while (this.bufferGNode.lastChild) {
|
|
5314
5362
|
this.bufferGNode.removeChild(this.bufferGNode.lastChild);
|
|
5315
5363
|
}
|
|
5364
|
+
while (this.bufferedNodeDefs.lastChild) {
|
|
5365
|
+
this.bufferedNodeDefs.removeChild(this.bufferedNodeDefs.lastChild);
|
|
5366
|
+
}
|
|
5316
5367
|
}
|
|
5317
5368
|
/**
|
|
5318
5369
|
* Create a new and empty `SVGElement` <svg> in the svg-namespace.
|
|
@@ -5552,7 +5603,12 @@ drawutilssvg.HEAD_XML = [
|
|
|
5552
5603
|
* @modified 2021-05-31 Added the `setConfiguration` function from `DrawLib`.
|
|
5553
5604
|
* @modified 2021-11-12 Adding more parameters tot the `text()` function: fontSize, textAlign, fontFamily, lineHeight.
|
|
5554
5605
|
* @modified 2021-11-19 Added the `color` param to the `label(...)` function.
|
|
5555
|
-
* @
|
|
5606
|
+
* @modified 2022-02-03 Added the `lineWidth` param to the `crosshair` function.
|
|
5607
|
+
* @modified 2022-02-03 Added the `cross(...)` function.
|
|
5608
|
+
* @modified 2022-03-27 Added the `texturedPoly` function.
|
|
5609
|
+
* @modified 2022-06-01 Tweaked the `polyline` function; lineWidth now scales with scale.x.
|
|
5610
|
+
* @modified 2022-07-26 Adding `alpha` to the `image(...)` function.
|
|
5611
|
+
* @version 1.12.2
|
|
5556
5612
|
**/
|
|
5557
5613
|
// Todo: rename this class to Drawutils?
|
|
5558
5614
|
/**
|
|
@@ -5689,16 +5745,18 @@ class drawutils {
|
|
|
5689
5745
|
* @param {Image} image - The image object to draw.
|
|
5690
5746
|
* @param {Vertex} position - The position to draw the the upper left corner at.
|
|
5691
5747
|
* @param {Vertex} size - The x/y-size to draw the image with.
|
|
5748
|
+
* @param {number=0.0} alpha - (optional, default=0.0) The transparency (1.0=opaque, 0.0=transparent).
|
|
5692
5749
|
* @return {void}
|
|
5693
5750
|
* @instance
|
|
5694
5751
|
* @memberof drawutils
|
|
5695
5752
|
**/
|
|
5696
|
-
image(image, position, size) {
|
|
5753
|
+
image(image, position, size, alpha = 1.0) {
|
|
5697
5754
|
if (!image.complete || !image.naturalWidth) {
|
|
5698
5755
|
// Avoid drawing un-unloaded or broken images
|
|
5699
5756
|
return;
|
|
5700
5757
|
}
|
|
5701
5758
|
this.ctx.save();
|
|
5759
|
+
this.ctx.globalAlpha = alpha;
|
|
5702
5760
|
// Note that there is a Safari bug with the 3 or 5 params variant.
|
|
5703
5761
|
// Only the 9-param varaint works.
|
|
5704
5762
|
this.ctx.drawImage(image, 0, 0, image.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
|
|
@@ -5706,6 +5764,96 @@ class drawutils {
|
|
|
5706
5764
|
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);
|
|
5707
5765
|
this.ctx.restore();
|
|
5708
5766
|
}
|
|
5767
|
+
/**
|
|
5768
|
+
* Draw an image at the given position with the given size.<br>
|
|
5769
|
+
* <br>
|
|
5770
|
+
* 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.
|
|
5771
|
+
*
|
|
5772
|
+
* @method texturedPoly
|
|
5773
|
+
* @param {Image} textureImage - The image object to draw.
|
|
5774
|
+
* @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
|
|
5775
|
+
* @param {Polygon} polygon - The polygon to use as clip path.
|
|
5776
|
+
* @param {Vertex} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
|
|
5777
|
+
* @param {number} rotation - The rotation to use for the polygon (and for the texture).
|
|
5778
|
+
* @param {XYCoords={x:0,y:0}} rotationCenter - (optional) The rotational center; default is center of bounding box.
|
|
5779
|
+
* @return {void}
|
|
5780
|
+
* @instance
|
|
5781
|
+
* @memberof drawutils
|
|
5782
|
+
**/
|
|
5783
|
+
texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
|
|
5784
|
+
var basePolygonBounds = polygon.getBounds();
|
|
5785
|
+
var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
|
|
5786
|
+
// var rotationalOffset = rotationCenter ? polygonPosition.difference(rotationCenter) : { x: 0, y: 0 };
|
|
5787
|
+
// var rotationalOffset = { x: 0, y: 0 };
|
|
5788
|
+
basePolygonBounds.getCenter().sub(targetCenterDifference);
|
|
5789
|
+
// Get the position offset of the polygon
|
|
5790
|
+
var targetTextureSize = new Vertex(textureSize.width, textureSize.height);
|
|
5791
|
+
// var targetTextureOffset = new Vertex(-textureSize.width / 2, -textureSize.height / 2).sub(targetCenterDifference);
|
|
5792
|
+
var targetTextureOffset = new Vertex(textureSize.min.x, textureSize.min.y).sub(polygonPosition);
|
|
5793
|
+
this.ctx.save();
|
|
5794
|
+
// this.ctx.translate(this.offset.x + rotationCenter.x * this.scale.x, this.offset.y + rotationCenter.y * this.scale.y);
|
|
5795
|
+
this.ctx.translate(this.offset.x + polygonPosition.x * this.scale.x, this.offset.y + polygonPosition.y * this.scale.y);
|
|
5796
|
+
drawutils.helpers.clipPoly(this.ctx, {
|
|
5797
|
+
x: -polygonPosition.x * this.scale.x,
|
|
5798
|
+
y: -polygonPosition.y * this.scale.y
|
|
5799
|
+
}, this.scale, polygon.vertices);
|
|
5800
|
+
this.ctx.scale(this.scale.x, this.scale.y);
|
|
5801
|
+
this.ctx.rotate(rotation);
|
|
5802
|
+
this.ctx.drawImage(textureImage, 0, 0, textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
|
|
5803
|
+
textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
|
|
5804
|
+
targetTextureOffset.x, // * this.scale.x,
|
|
5805
|
+
targetTextureOffset.y, // * this.scale.y,
|
|
5806
|
+
targetTextureSize.x, // * this.scale.x,
|
|
5807
|
+
targetTextureSize.y // * this.scale.y
|
|
5808
|
+
);
|
|
5809
|
+
this.ctx.restore();
|
|
5810
|
+
}
|
|
5811
|
+
_texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation, rotationCenter = { x: 0, y: 0 }) {
|
|
5812
|
+
var basePolygonBounds = polygon.getBounds();
|
|
5813
|
+
var targetCenterDifference = polygonPosition.clone().difference(basePolygonBounds.getCenter());
|
|
5814
|
+
var rotationalOffset = rotationCenter ? polygonPosition.difference(rotationCenter) : { x: 0, y: 0 };
|
|
5815
|
+
// var rotationalOffset = { x: 0, y: 0 };
|
|
5816
|
+
var tileCenter = basePolygonBounds.getCenter().sub(targetCenterDifference);
|
|
5817
|
+
// Get the position offset of the polygon
|
|
5818
|
+
var targetTextureSize = new Vertex(textureSize.width, textureSize.height);
|
|
5819
|
+
var targetTextureOffset = new Vertex(-textureSize.width / 2, -textureSize.height / 2).sub(targetCenterDifference);
|
|
5820
|
+
this.ctx.save();
|
|
5821
|
+
// this.ctx.translate(
|
|
5822
|
+
// this.offset.x + (tileCenter.x - rotationalOffset.x * 0 + targetTextureOffset.x * 0.0) * this.scale.x,
|
|
5823
|
+
// this.offset.y + (tileCenter.y - rotationalOffset.y * 0 + targetTextureOffset.y * 0.0) * this.scale.y
|
|
5824
|
+
// );
|
|
5825
|
+
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);
|
|
5826
|
+
this.ctx.rotate(rotation);
|
|
5827
|
+
drawutils.helpers.clipPoly(this.ctx, {
|
|
5828
|
+
x: (-targetCenterDifference.x * 1 - tileCenter.x - rotationalOffset.x) * this.scale.x,
|
|
5829
|
+
y: (-targetCenterDifference.y * 1 - tileCenter.y - rotationalOffset.y) * this.scale.y
|
|
5830
|
+
}, this.scale, polygon.vertices);
|
|
5831
|
+
this.ctx.drawImage(textureImage, 0, 0, textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
|
|
5832
|
+
textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
|
|
5833
|
+
(-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);
|
|
5834
|
+
// const scaledTextureSize = new Bounds(
|
|
5835
|
+
// new Vertex(
|
|
5836
|
+
// -polygonPosition.x + targetTextureOffset.x - rotationalOffset.x,
|
|
5837
|
+
// -polygonPosition.y + targetTextureOffset.y - rotationalOffset.y
|
|
5838
|
+
// ).scaleXY(this.scale, rotationCenter),
|
|
5839
|
+
// new Vertex(
|
|
5840
|
+
// -polygonPosition.x + targetTextureOffset.x - rotationalOffset.x + targetTextureSize.x,
|
|
5841
|
+
// -polygonPosition.y + targetTextureOffset.y - rotationalOffset.y + targetTextureSize.y
|
|
5842
|
+
// ).scaleXY(this.scale, rotationCenter)
|
|
5843
|
+
// );
|
|
5844
|
+
// this.ctx.drawImage(
|
|
5845
|
+
// textureImage,
|
|
5846
|
+
// 0,
|
|
5847
|
+
// 0,
|
|
5848
|
+
// textureImage.naturalWidth - 1, // There is this horrible Safari bug (fixed in newer versions)
|
|
5849
|
+
// textureImage.naturalHeight - 1, // To avoid errors substract 1 here.
|
|
5850
|
+
// scaledTextureSize.min.x,
|
|
5851
|
+
// scaledTextureSize.min.y,
|
|
5852
|
+
// scaledTextureSize.width,
|
|
5853
|
+
// scaledTextureSize.height
|
|
5854
|
+
// );
|
|
5855
|
+
this.ctx.restore();
|
|
5856
|
+
}
|
|
5709
5857
|
/**
|
|
5710
5858
|
* Draw a rectangle.
|
|
5711
5859
|
*
|
|
@@ -6146,11 +6294,12 @@ class drawutils {
|
|
|
6146
6294
|
* @param {XYCoords} center - The center of the crosshair.
|
|
6147
6295
|
* @param {number} radius - The radius of the crosshair.
|
|
6148
6296
|
* @param {string} color - The CSS color to draw the crosshair with.
|
|
6297
|
+
* @param {number=0.5} lineWidth - (optional, default=0.5) The line width to use.
|
|
6149
6298
|
* @return {void}
|
|
6150
6299
|
* @instance
|
|
6151
6300
|
* @memberof drawutils
|
|
6152
6301
|
*/
|
|
6153
|
-
crosshair(center, radius, color) {
|
|
6302
|
+
crosshair(center, radius, color, lineWidth) {
|
|
6154
6303
|
this.ctx.save();
|
|
6155
6304
|
this.ctx.beginPath();
|
|
6156
6305
|
this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y);
|
|
@@ -6158,7 +6307,34 @@ class drawutils {
|
|
|
6158
6307
|
this.ctx.moveTo(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y - radius);
|
|
6159
6308
|
this.ctx.lineTo(this.offset.x + center.x * this.scale.x, this.offset.y + center.y * this.scale.y + radius);
|
|
6160
6309
|
this.ctx.strokeStyle = color;
|
|
6161
|
-
this.ctx.lineWidth = 0.5;
|
|
6310
|
+
this.ctx.lineWidth = lineWidth || 0.5;
|
|
6311
|
+
this.ctx.stroke();
|
|
6312
|
+
this.ctx.closePath();
|
|
6313
|
+
this.ctx.restore();
|
|
6314
|
+
}
|
|
6315
|
+
/**
|
|
6316
|
+
* Draw a cross with diagonal axes with given radius, color and lineWidth at the given position.<br>
|
|
6317
|
+
* <br>
|
|
6318
|
+
* Note that the x's radius will not be affected by scaling.
|
|
6319
|
+
*
|
|
6320
|
+
* @method crosshair
|
|
6321
|
+
* @param {XYCoords} center - The center of the crosshair.
|
|
6322
|
+
* @param {number} radius - The radius of the crosshair.
|
|
6323
|
+
* @param {string} color - The CSS color to draw the crosshair with.
|
|
6324
|
+
* @param {number=1} lineWidth - (optional, default=1.0) The line width to use.
|
|
6325
|
+
* @return {void}
|
|
6326
|
+
* @instance
|
|
6327
|
+
* @memberof drawutils
|
|
6328
|
+
*/
|
|
6329
|
+
cross(center, radius, color, lineWidth) {
|
|
6330
|
+
this.ctx.save();
|
|
6331
|
+
this.ctx.beginPath();
|
|
6332
|
+
this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y - radius);
|
|
6333
|
+
this.ctx.lineTo(this.offset.x + center.x * this.scale.x + radius, this.offset.y + center.y * this.scale.y + radius);
|
|
6334
|
+
this.ctx.moveTo(this.offset.x + center.x * this.scale.x - radius, this.offset.y + center.y * this.scale.y + radius);
|
|
6335
|
+
this.ctx.lineTo(this.offset.x + center.x * this.scale.x + radius, this.offset.y + center.y * this.scale.y - radius);
|
|
6336
|
+
this.ctx.strokeStyle = color;
|
|
6337
|
+
this.ctx.lineWidth = lineWidth || 1.0;
|
|
6162
6338
|
this.ctx.stroke();
|
|
6163
6339
|
this.ctx.closePath();
|
|
6164
6340
|
this.ctx.restore();
|
|
@@ -6190,11 +6366,12 @@ class drawutils {
|
|
|
6190
6366
|
* @memberof drawutils
|
|
6191
6367
|
*/
|
|
6192
6368
|
polyline(vertices, isOpen, color, lineWidth) {
|
|
6193
|
-
if (vertices.length <= 1)
|
|
6369
|
+
if (vertices.length <= 1) {
|
|
6194
6370
|
return;
|
|
6371
|
+
}
|
|
6195
6372
|
this.ctx.save();
|
|
6196
6373
|
this.ctx.beginPath();
|
|
6197
|
-
this.ctx.lineWidth = lineWidth || 1.0;
|
|
6374
|
+
this.ctx.lineWidth = lineWidth * this.scale.x || 1.0;
|
|
6198
6375
|
this.ctx.moveTo(this.offset.x + vertices[0].x * this.scale.x, this.offset.y + vertices[0].y * this.scale.y);
|
|
6199
6376
|
for (var i = 0; i < vertices.length; i++) {
|
|
6200
6377
|
this.ctx.lineTo(this.offset.x + vertices[i].x * this.scale.x, this.offset.y + vertices[i].y * this.scale.y);
|
|
@@ -6336,6 +6513,21 @@ class drawutils {
|
|
|
6336
6513
|
this.ctx.fillRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height);
|
|
6337
6514
|
}
|
|
6338
6515
|
}
|
|
6516
|
+
drawutils.helpers = {
|
|
6517
|
+
// A helper function to define the clipping path.
|
|
6518
|
+
// This could be a candidate for the draw library.
|
|
6519
|
+
clipPoly: (ctx, offset, scale, vertices) => {
|
|
6520
|
+
ctx.beginPath();
|
|
6521
|
+
// Set clip mask
|
|
6522
|
+
ctx.moveTo(offset.x + vertices[0].x * scale.x, offset.y + vertices[0].y * scale.y);
|
|
6523
|
+
for (var i = 1; i < vertices.length; i++) {
|
|
6524
|
+
const vert = vertices[i];
|
|
6525
|
+
ctx.lineTo(offset.x + vert.x * scale.x, offset.y + vert.y * scale.y);
|
|
6526
|
+
}
|
|
6527
|
+
ctx.closePath();
|
|
6528
|
+
ctx.clip();
|
|
6529
|
+
}
|
|
6530
|
+
};
|
|
6339
6531
|
|
|
6340
6532
|
/**
|
|
6341
6533
|
* @author Ikaros Kappler
|
|
@@ -6345,7 +6537,11 @@ class drawutils {
|
|
|
6345
6537
|
* @modified 2020-10-15 Re-added the text() function.
|
|
6346
6538
|
* @modified 2021-01-24 Added the `setCurrentId` function.
|
|
6347
6539
|
* @modified 2021-05-31 Added the `setConfiguration` function from `DrawLib`.
|
|
6348
|
-
* @
|
|
6540
|
+
* @modified 2022-02-03 Added the `lineWidth` param to the `crosshair` function.
|
|
6541
|
+
* @modified 2022-02-03 Added the `cross(...)` function.
|
|
6542
|
+
* @modified 2022-03-27 Added the `texturedPoly` function.
|
|
6543
|
+
* @modified 2022-07-26 Adding `alpha` to the `image(...)` function.
|
|
6544
|
+
* @version 0.0.8
|
|
6349
6545
|
**/
|
|
6350
6546
|
/**
|
|
6351
6547
|
* @classdesc A wrapper class for basic drawing operations. This is the WebGL
|
|
@@ -6535,11 +6731,30 @@ class drawutilsgl {
|
|
|
6535
6731
|
* @param {Image} image - The image object to draw.
|
|
6536
6732
|
* @param {Vertex} position - The position to draw the the upper left corner at.
|
|
6537
6733
|
* @param {Vertex} size - The x/y-size to draw the image with.
|
|
6734
|
+
* @param {number=0.0} alpha - (optional, default=0.0) The transparency (0.0=opaque, 1.0=transparent).
|
|
6538
6735
|
* @return {void}
|
|
6539
6736
|
* @instance
|
|
6540
6737
|
* @memberof drawutils
|
|
6541
6738
|
**/
|
|
6542
|
-
image(image, position, size) {
|
|
6739
|
+
image(image, position, size, alpha = 0.0) {
|
|
6740
|
+
// NOT YET IMPLEMENTED
|
|
6741
|
+
}
|
|
6742
|
+
/**
|
|
6743
|
+
* Draw an image at the given position with the given size.<br>
|
|
6744
|
+
* <br>
|
|
6745
|
+
* 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.
|
|
6746
|
+
*
|
|
6747
|
+
* @method texturedPoly
|
|
6748
|
+
* @param {Image} textureImage - The image object to draw.
|
|
6749
|
+
* @param {Bounds} textureSize - The texture size to use; these are the original bounds to map the polygon vertices to.
|
|
6750
|
+
* @param {Polygon} polygon - The polygon to use as clip path.
|
|
6751
|
+
* @param {Vertex} polygonPosition - The polygon's position (relative), measured at the bounding box's center.
|
|
6752
|
+
* @param {number} rotation - The rotation to use for the polygon (and for the texture).
|
|
6753
|
+
* @return {void}
|
|
6754
|
+
* @instance
|
|
6755
|
+
* @memberof drawutilsgl
|
|
6756
|
+
**/
|
|
6757
|
+
texturedPoly(textureImage, textureSize, polygon, polygonPosition, rotation) {
|
|
6543
6758
|
// NOT YET IMPLEMENTED
|
|
6544
6759
|
}
|
|
6545
6760
|
// +---------------------------------------------------------------------------------
|
|
@@ -6823,11 +7038,29 @@ class drawutilsgl {
|
|
|
6823
7038
|
* @param {XYCoords} center - The center of the crosshair.
|
|
6824
7039
|
* @param {number} radius - The radius of the crosshair.
|
|
6825
7040
|
* @param {string} color - The CSS color to draw the crosshair with.
|
|
7041
|
+
* @param {number=0.5} lineWidth - (optional, default=0.5) The line width to use.
|
|
6826
7042
|
* @return {void}
|
|
6827
7043
|
* @instance
|
|
6828
7044
|
* @memberof drawutils
|
|
6829
7045
|
*/
|
|
6830
|
-
crosshair(center, radius, color) {
|
|
7046
|
+
crosshair(center, radius, color, lineWidth) {
|
|
7047
|
+
// NOT YET IMPLEMENTED
|
|
7048
|
+
}
|
|
7049
|
+
/**
|
|
7050
|
+
* Draw a cross with diagonal axes with given radius, color and lineWidth at the given position.<br>
|
|
7051
|
+
* <br>
|
|
7052
|
+
* Note that the x's radius will not be affected by scaling.
|
|
7053
|
+
*
|
|
7054
|
+
* @method crosshair
|
|
7055
|
+
* @param {XYCoords} center - The center of the crosshair.
|
|
7056
|
+
* @param {number} radius - The radius of the crosshair.
|
|
7057
|
+
* @param {string} color - The CSS color to draw the crosshair with.
|
|
7058
|
+
* @param {number=1} lineWidth - (optional, default=1.0) The line width to use.
|
|
7059
|
+
* @return {void}
|
|
7060
|
+
* @instance
|
|
7061
|
+
* @memberof drawutils
|
|
7062
|
+
*/
|
|
7063
|
+
cross(center, radius, color, lineWidth) {
|
|
6831
7064
|
// NOT YET IMPLEMENTED
|
|
6832
7065
|
}
|
|
6833
7066
|
/**
|
|
@@ -7067,7 +7300,9 @@ class GLU {
|
|
|
7067
7300
|
* @modified 2020-12-28 Added the `getArea` function.
|
|
7068
7301
|
* @modified 2021-01-20 Added UID.
|
|
7069
7302
|
* @modified 2021-01-22 Always updating circumcircle when retieving it.
|
|
7070
|
-
* @
|
|
7303
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
7304
|
+
* @modified 2022-02-02 Cleared the `Triangle.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
7305
|
+
* @version 2.6.0
|
|
7071
7306
|
*
|
|
7072
7307
|
* @file Triangle
|
|
7073
7308
|
* @fileoverview A simple triangle class: three vertices.
|
|
@@ -7128,7 +7363,6 @@ class Triangle {
|
|
|
7128
7363
|
throw `Cannot create triangle from array with less than three vertices (${arr.length})`;
|
|
7129
7364
|
return new Triangle(arr[0], arr[1], arr[2]);
|
|
7130
7365
|
}
|
|
7131
|
-
;
|
|
7132
7366
|
/**
|
|
7133
7367
|
* Get the area of this triangle. The returned area is never negative.
|
|
7134
7368
|
*
|
|
@@ -7144,7 +7378,6 @@ class Triangle {
|
|
|
7144
7378
|
getArea() {
|
|
7145
7379
|
return Math.abs(Triangle.utils.signedArea(this.a.x, this.a.y, this.b.x, this.b.y, this.c.x, this.c.y));
|
|
7146
7380
|
}
|
|
7147
|
-
;
|
|
7148
7381
|
/**
|
|
7149
7382
|
* Get the centroid of this triangle.
|
|
7150
7383
|
*
|
|
@@ -7158,7 +7391,6 @@ class Triangle {
|
|
|
7158
7391
|
getCentroid() {
|
|
7159
7392
|
return new Vertex((this.a.x + this.b.x + this.c.x) / 3, (this.a.y + this.b.y + this.c.y) / 3);
|
|
7160
7393
|
}
|
|
7161
|
-
;
|
|
7162
7394
|
/**
|
|
7163
7395
|
* Scale the triangle towards its centroid.
|
|
7164
7396
|
*
|
|
@@ -7175,7 +7407,6 @@ class Triangle {
|
|
|
7175
7407
|
this.c.scale(factor, centroid);
|
|
7176
7408
|
return this;
|
|
7177
7409
|
}
|
|
7178
|
-
;
|
|
7179
7410
|
/**
|
|
7180
7411
|
* Get the circumcircle of this triangle.
|
|
7181
7412
|
*
|
|
@@ -7192,11 +7423,10 @@ class Triangle {
|
|
|
7192
7423
|
* @memberof Triangle
|
|
7193
7424
|
*/
|
|
7194
7425
|
getCircumcircle() {
|
|
7195
|
-
// if( !this.center || !this.radius )
|
|
7426
|
+
// if( !this.center || !this.radius )
|
|
7196
7427
|
this.calcCircumcircle();
|
|
7197
7428
|
return new Circle(this.center.clone(), this.radius);
|
|
7198
7429
|
}
|
|
7199
|
-
;
|
|
7200
7430
|
/**
|
|
7201
7431
|
* Check if this triangle and the passed triangle share an
|
|
7202
7432
|
* adjacent edge.
|
|
@@ -7216,7 +7446,6 @@ class Triangle {
|
|
|
7216
7446
|
var c = this.c.equals(tri.a) || this.c.equals(tri.b) || this.c.equals(tri.c);
|
|
7217
7447
|
return (a && b) || (a && c) || (b && c);
|
|
7218
7448
|
}
|
|
7219
|
-
;
|
|
7220
7449
|
/**
|
|
7221
7450
|
* Get that vertex of this triangle (a,b,c) that is not vert1 nor vert2 of
|
|
7222
7451
|
* the passed two.
|
|
@@ -7229,14 +7458,13 @@ class Triangle {
|
|
|
7229
7458
|
* @memberof Triangle
|
|
7230
7459
|
*/
|
|
7231
7460
|
getThirdVertex(vert1, vert2) {
|
|
7232
|
-
if (this.a.equals(vert1) && this.b.equals(vert2) || this.a.equals(vert2) && this.b.equals(vert1))
|
|
7461
|
+
if ((this.a.equals(vert1) && this.b.equals(vert2)) || (this.a.equals(vert2) && this.b.equals(vert1)))
|
|
7233
7462
|
return this.c;
|
|
7234
|
-
if (this.b.equals(vert1) && this.c.equals(vert2) || this.b.equals(vert2) && this.c.equals(vert1))
|
|
7463
|
+
if ((this.b.equals(vert1) && this.c.equals(vert2)) || (this.b.equals(vert2) && this.c.equals(vert1)))
|
|
7235
7464
|
return this.a;
|
|
7236
7465
|
//if( this.c.equals(vert1) && this.a.equals(vert2) || this.c.equals(vert2) && this.a.equals(vert1) )
|
|
7237
7466
|
return this.b;
|
|
7238
7467
|
}
|
|
7239
|
-
;
|
|
7240
7468
|
/**
|
|
7241
7469
|
* Re-compute the circumcircle of this triangle (if the vertices
|
|
7242
7470
|
* have changed).
|
|
@@ -7276,8 +7504,7 @@ class Triangle {
|
|
|
7276
7504
|
}
|
|
7277
7505
|
this.radius_squared = dx * dx + dy * dy;
|
|
7278
7506
|
this.radius = Math.sqrt(this.radius_squared);
|
|
7279
|
-
}
|
|
7280
|
-
; // END calcCircumcircle
|
|
7507
|
+
} // END calcCircumcircle
|
|
7281
7508
|
/**
|
|
7282
7509
|
* Check if the passed vertex is inside this triangle's
|
|
7283
7510
|
* circumcircle.
|
|
@@ -7292,9 +7519,8 @@ class Triangle {
|
|
|
7292
7519
|
const dx = this.center.x - v.x;
|
|
7293
7520
|
const dy = this.center.y - v.y;
|
|
7294
7521
|
const dist_squared = dx * dx + dy * dy;
|
|
7295
|
-
return
|
|
7522
|
+
return dist_squared <= this.radius_squared;
|
|
7296
7523
|
}
|
|
7297
|
-
;
|
|
7298
7524
|
/**
|
|
7299
7525
|
* Get the rectangular bounds for this triangle.
|
|
7300
7526
|
*
|
|
@@ -7306,7 +7532,6 @@ class Triangle {
|
|
|
7306
7532
|
bounds() {
|
|
7307
7533
|
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)));
|
|
7308
7534
|
}
|
|
7309
|
-
;
|
|
7310
7535
|
/**
|
|
7311
7536
|
* Convert this triangle to a polygon instance.
|
|
7312
7537
|
*
|
|
@@ -7320,7 +7545,6 @@ class Triangle {
|
|
|
7320
7545
|
toPolygon() {
|
|
7321
7546
|
return new Polygon([this.a, this.b, this.c]);
|
|
7322
7547
|
}
|
|
7323
|
-
;
|
|
7324
7548
|
/**
|
|
7325
7549
|
* Get the determinant of this triangle.
|
|
7326
7550
|
*
|
|
@@ -7333,7 +7557,6 @@ class Triangle {
|
|
|
7333
7557
|
// (b.y - a.y)*(c.x - b.x) - (c.y - b.y)*(b.x - a.x);
|
|
7334
7558
|
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);
|
|
7335
7559
|
}
|
|
7336
|
-
;
|
|
7337
7560
|
/**
|
|
7338
7561
|
* Checks if the passed vertex (p) is inside this triangle.
|
|
7339
7562
|
*
|
|
@@ -7348,7 +7571,6 @@ class Triangle {
|
|
|
7348
7571
|
containsPoint(p) {
|
|
7349
7572
|
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);
|
|
7350
7573
|
}
|
|
7351
|
-
;
|
|
7352
7574
|
/**
|
|
7353
7575
|
* Get that inner triangle which defines the maximal incircle.
|
|
7354
7576
|
*
|
|
@@ -7367,7 +7589,6 @@ class Triangle {
|
|
|
7367
7589
|
const circleIntersC = lineC.getClosestPoint(intersection);
|
|
7368
7590
|
return new Triangle(circleIntersA, circleIntersB, circleIntersC);
|
|
7369
7591
|
}
|
|
7370
|
-
;
|
|
7371
7592
|
/**
|
|
7372
7593
|
* Get the incircle of this triangle. That is the circle that touches each side
|
|
7373
7594
|
* of this triangle in exactly one point.
|
|
@@ -7379,7 +7600,6 @@ class Triangle {
|
|
|
7379
7600
|
getIncircle() {
|
|
7380
7601
|
return this.getIncircularTriangle().getCircumcircle();
|
|
7381
7602
|
}
|
|
7382
|
-
;
|
|
7383
7603
|
/**
|
|
7384
7604
|
* Get the incenter of this triangle (which is the center of the circumcircle).
|
|
7385
7605
|
*
|
|
@@ -7393,7 +7613,6 @@ class Triangle {
|
|
|
7393
7613
|
this.calcCircumcircle();
|
|
7394
7614
|
return this.center.clone();
|
|
7395
7615
|
}
|
|
7396
|
-
;
|
|
7397
7616
|
/**
|
|
7398
7617
|
* Converts this triangle into a human-readable string.
|
|
7399
7618
|
*
|
|
@@ -7403,46 +7622,19 @@ class Triangle {
|
|
|
7403
7622
|
* @memberof Triangle
|
|
7404
7623
|
*/
|
|
7405
7624
|
toString() {
|
|
7406
|
-
return
|
|
7625
|
+
return "{ a : " + this.a.toString() + ", b : " + this.b.toString() + ", c : " + this.c.toString() + "}";
|
|
7407
7626
|
}
|
|
7408
|
-
;
|
|
7409
7627
|
/**
|
|
7410
|
-
*
|
|
7411
|
-
*
|
|
7412
|
-
*
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7418
|
-
|
|
7419
|
-
toSVGString(options) {
|
|
7420
|
-
options = options || {};
|
|
7421
|
-
var buffer = [];
|
|
7422
|
-
buffer.push('<path');
|
|
7423
|
-
if (options.className)
|
|
7424
|
-
buffer.push(' class="' + options.className + '"');
|
|
7425
|
-
buffer.push(' d="');
|
|
7426
|
-
var vertices = [this.a, this.b, this.c];
|
|
7427
|
-
if (vertices.length > 0) {
|
|
7428
|
-
buffer.push('M ');
|
|
7429
|
-
buffer.push(vertices[0].x);
|
|
7430
|
-
buffer.push(' ');
|
|
7431
|
-
buffer.push(vertices[0].y);
|
|
7432
|
-
for (var i = 1; i < vertices.length; i++) {
|
|
7433
|
-
buffer.push(' L ');
|
|
7434
|
-
buffer.push(vertices[i].x);
|
|
7435
|
-
buffer.push(' ');
|
|
7436
|
-
buffer.push(vertices[i].y);
|
|
7437
|
-
}
|
|
7438
|
-
//if( !this.isOpen ) {
|
|
7439
|
-
buffer.push(' Z');
|
|
7440
|
-
//}
|
|
7441
|
-
}
|
|
7442
|
-
buffer.push('" />');
|
|
7443
|
-
return buffer.join('');
|
|
7628
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
7629
|
+
* After calling this function the object might not hold valid data any more and
|
|
7630
|
+
* should not be used.
|
|
7631
|
+
*/
|
|
7632
|
+
destroy() {
|
|
7633
|
+
this.a.destroy();
|
|
7634
|
+
this.b.destroy();
|
|
7635
|
+
this.c.destroy();
|
|
7636
|
+
this.isDestroyed = true;
|
|
7444
7637
|
}
|
|
7445
|
-
;
|
|
7446
7638
|
}
|
|
7447
7639
|
/**
|
|
7448
7640
|
* An epsilon for comparison.
|
|
@@ -7454,10 +7646,10 @@ Triangle.EPSILON = 1.0e-6;
|
|
|
7454
7646
|
Triangle.utils = {
|
|
7455
7647
|
// Used in the bounds() function.
|
|
7456
7648
|
max3(a, b, c) {
|
|
7457
|
-
return
|
|
7649
|
+
return a >= b && a >= c ? a : b >= a && b >= c ? b : c;
|
|
7458
7650
|
},
|
|
7459
7651
|
min3(a, b, c) {
|
|
7460
|
-
return
|
|
7652
|
+
return a <= b && a <= c ? a : b <= a && b <= c ? b : c;
|
|
7461
7653
|
},
|
|
7462
7654
|
signedArea(p0x, p0y, p1x, p1y, p2x, p2y) {
|
|
7463
7655
|
return 0.5 * (-p1y * p2x + p0y * (-p1x + p2x) + p0x * (p1y - p2y) + p1x * p2y);
|
|
@@ -7473,9 +7665,9 @@ Triangle.utils = {
|
|
|
7473
7665
|
// http://stackoverflow.com/questions/2049582/how-to-determine-a-point-in-a-2d-triangle
|
|
7474
7666
|
// var area : number = 1/2*(-p1y*p2x + p0y*(-p1x + p2x) + p0x*(p1y - p2y) + p1x*p2y);
|
|
7475
7667
|
var area = Triangle.utils.signedArea(p0x, p0y, p1x, p1y, p2x, p2y);
|
|
7476
|
-
var s = 1 / (2 * area) * (p0y * p2x - p0x * p2y + (p2y - p0y) * px + (p0x - p2x) * py);
|
|
7477
|
-
var t = 1 / (2 * area) * (p0x * p1y - p0y * p1x + (p0y - p1y) * px + (p1x - p0x) * py);
|
|
7478
|
-
return s > 0 && t > 0 &&
|
|
7668
|
+
var s = (1 / (2 * area)) * (p0y * p2x - p0x * p2y + (p2y - p0y) * px + (p0x - p2x) * py);
|
|
7669
|
+
var t = (1 / (2 * area)) * (p0x * p1y - p0y * p1x + (p0y - p1y) * px + (p1x - p0x) * py);
|
|
7670
|
+
return s > 0 && t > 0 && 1 - s - t > 0;
|
|
7479
7671
|
}
|
|
7480
7672
|
};
|
|
7481
7673
|
|
|
@@ -7646,7 +7838,8 @@ Grid.utils = {
|
|
|
7646
7838
|
* @modified 2020-07-28 Changed the `delete` key code from 8 to 46.
|
|
7647
7839
|
* @modified 2020-10-04 Changed `window` to `globalThis`.
|
|
7648
7840
|
* @modified 2020-10-04 Added extended JSDoc.
|
|
7649
|
-
* @
|
|
7841
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
7842
|
+
* @version 1.1.0
|
|
7650
7843
|
*
|
|
7651
7844
|
* @file KeyHandler
|
|
7652
7845
|
* @public
|
|
@@ -7677,7 +7870,7 @@ class KeyHandler {
|
|
|
7677
7870
|
* @memberof KeyHandler
|
|
7678
7871
|
* @param {HTMLElement} options.element (optional) The HTML element to listen on; if null then 'window' will be used.
|
|
7679
7872
|
* @param {boolean} options.trackAll (optional) Set to true if you want to keep track of _all_ keys (keyStatus).
|
|
7680
|
-
|
|
7873
|
+
**/
|
|
7681
7874
|
constructor(options) {
|
|
7682
7875
|
this.downListeners = [];
|
|
7683
7876
|
this.pressListeners = [];
|
|
@@ -7696,7 +7889,6 @@ class KeyHandler {
|
|
|
7696
7889
|
// Install the listeners
|
|
7697
7890
|
this.installListeners();
|
|
7698
7891
|
}
|
|
7699
|
-
;
|
|
7700
7892
|
/**
|
|
7701
7893
|
* A helper function to fire key events from this KeyHandler.
|
|
7702
7894
|
*
|
|
@@ -7714,7 +7906,6 @@ class KeyHandler {
|
|
|
7714
7906
|
}
|
|
7715
7907
|
return hasListener;
|
|
7716
7908
|
}
|
|
7717
|
-
;
|
|
7718
7909
|
/**
|
|
7719
7910
|
* Internal function to fire a new keydown event to all listeners.
|
|
7720
7911
|
* You should not call this function on your own unless you know what you do.
|
|
@@ -7730,10 +7921,9 @@ class KeyHandler {
|
|
|
7730
7921
|
fireDownEvent(e, handler) {
|
|
7731
7922
|
if (handler.fireEvent(e, handler.downListeners) || handler.trackAllKeys) {
|
|
7732
7923
|
// Down event has listeners. Update key state.
|
|
7733
|
-
handler.keyStates[e.keyCode] =
|
|
7924
|
+
handler.keyStates[e.keyCode] = "down";
|
|
7734
7925
|
}
|
|
7735
7926
|
}
|
|
7736
|
-
;
|
|
7737
7927
|
/**
|
|
7738
7928
|
* Internal function to fire a new keypress event to all listeners.
|
|
7739
7929
|
* You should not call this function on your own unless you know what you do.
|
|
@@ -7749,7 +7939,6 @@ class KeyHandler {
|
|
|
7749
7939
|
firePressEvent(e, handler) {
|
|
7750
7940
|
handler.fireEvent(e, handler.pressListeners);
|
|
7751
7941
|
}
|
|
7752
|
-
;
|
|
7753
7942
|
/**
|
|
7754
7943
|
* Internal function to fire a new keyup event to all listeners.
|
|
7755
7944
|
* You should not call this function on your own unless you know what you do.
|
|
@@ -7768,20 +7957,18 @@ class KeyHandler {
|
|
|
7768
7957
|
delete handler.keyStates[e.keyCode];
|
|
7769
7958
|
}
|
|
7770
7959
|
}
|
|
7771
|
-
;
|
|
7772
7960
|
/**
|
|
7773
7961
|
* Resolve the key/name code.
|
|
7774
7962
|
*/
|
|
7775
7963
|
static key2code(key) {
|
|
7776
|
-
if (typeof key ==
|
|
7964
|
+
if (typeof key == "number")
|
|
7777
7965
|
return key;
|
|
7778
|
-
if (typeof key !=
|
|
7966
|
+
if (typeof key != "string")
|
|
7779
7967
|
throw "Unknown key name or key type (should be a string or integer): " + key;
|
|
7780
7968
|
if (KeyHandler.KEY_CODES[key])
|
|
7781
7969
|
return KeyHandler.KEY_CODES[key];
|
|
7782
7970
|
throw "Unknown key (cannot resolve key code): " + key;
|
|
7783
7971
|
}
|
|
7784
|
-
;
|
|
7785
7972
|
/**
|
|
7786
7973
|
* Install the required listeners into the initially passed element.
|
|
7787
7974
|
*
|
|
@@ -7790,20 +7977,24 @@ class KeyHandler {
|
|
|
7790
7977
|
*/
|
|
7791
7978
|
installListeners() {
|
|
7792
7979
|
var _self = this;
|
|
7793
|
-
this.element.addEventListener(
|
|
7794
|
-
|
|
7795
|
-
|
|
7980
|
+
this.element.addEventListener("keydown", (this._keyDownListener = (e) => {
|
|
7981
|
+
_self.fireDownEvent(e, _self);
|
|
7982
|
+
}));
|
|
7983
|
+
this.element.addEventListener("keypress", (this._keyPressListener = (e) => {
|
|
7984
|
+
_self.firePressEvent(e, _self);
|
|
7985
|
+
}));
|
|
7986
|
+
this.element.addEventListener("keyup", (this._keyUpListener = (e) => {
|
|
7987
|
+
_self.fireUpEvent(e, _self);
|
|
7988
|
+
}));
|
|
7796
7989
|
}
|
|
7797
|
-
;
|
|
7798
7990
|
/**
|
|
7799
7991
|
* Remove all installed event listeners from the underlying element.
|
|
7800
7992
|
*/
|
|
7801
7993
|
releaseListeners() {
|
|
7802
|
-
this.element.removeEventListener(
|
|
7803
|
-
this.element.removeEventListener(
|
|
7804
|
-
this.element.removeEventListener(
|
|
7994
|
+
this.element.removeEventListener("keydown", this._keyDownListener);
|
|
7995
|
+
this.element.removeEventListener("keypress", this._keyPressListener);
|
|
7996
|
+
this.element.removeEventListener("keyup", this._keyUpListener);
|
|
7805
7997
|
}
|
|
7806
|
-
;
|
|
7807
7998
|
/**
|
|
7808
7999
|
* Listen for key down. This function allows chaining.
|
|
7809
8000
|
*
|
|
@@ -7820,7 +8011,6 @@ class KeyHandler {
|
|
|
7820
8011
|
this.downListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
|
|
7821
8012
|
return this;
|
|
7822
8013
|
}
|
|
7823
|
-
;
|
|
7824
8014
|
/**
|
|
7825
8015
|
* Listen for key press.
|
|
7826
8016
|
*
|
|
@@ -7837,7 +8027,6 @@ class KeyHandler {
|
|
|
7837
8027
|
this.pressListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
|
|
7838
8028
|
return this;
|
|
7839
8029
|
}
|
|
7840
|
-
;
|
|
7841
8030
|
/**
|
|
7842
8031
|
* Listen for key up.
|
|
7843
8032
|
*
|
|
@@ -7854,23 +8043,31 @@ class KeyHandler {
|
|
|
7854
8043
|
this.upListeners.push({ key: key, keyCode: KeyHandler.key2code(key), listener: listener });
|
|
7855
8044
|
return this;
|
|
7856
8045
|
}
|
|
7857
|
-
;
|
|
7858
8046
|
/**
|
|
7859
8047
|
* Check if a specific key is currently held pressed.
|
|
7860
8048
|
*
|
|
7861
8049
|
* @param {string|number} key - Any key identifier, key code or one from the KEY_CODES list.
|
|
7862
8050
|
*/
|
|
7863
8051
|
isDown(key) {
|
|
7864
|
-
if (typeof key ==
|
|
8052
|
+
if (typeof key == "number")
|
|
7865
8053
|
return this.keyStates[key] ? true : false;
|
|
7866
8054
|
else
|
|
7867
8055
|
return this.keyStates[KeyHandler.key2code(key)] ? true : false;
|
|
7868
8056
|
}
|
|
8057
|
+
/**
|
|
8058
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
8059
|
+
* After calling this function the object might not hold valid data any more and
|
|
8060
|
+
* should not be used any more.
|
|
8061
|
+
*/
|
|
8062
|
+
destroy() {
|
|
8063
|
+
this.releaseListeners();
|
|
8064
|
+
}
|
|
7869
8065
|
}
|
|
7870
8066
|
/**
|
|
7871
8067
|
* Source:
|
|
7872
8068
|
* https://keycode.info/
|
|
7873
8069
|
*/
|
|
8070
|
+
// prettier-ignore
|
|
7874
8071
|
KeyHandler.KEY_CODES = {
|
|
7875
8072
|
'break': 3,
|
|
7876
8073
|
'backspace': 8,
|
|
@@ -8187,41 +8384,41 @@ class MouseHandler {
|
|
|
8187
8384
|
// | drag offset, ...) to the callbacks.
|
|
8188
8385
|
// +-------------------------------------------------
|
|
8189
8386
|
const _self = this;
|
|
8190
|
-
this.handlers[
|
|
8387
|
+
this.handlers["mousemove"] = (e) => {
|
|
8191
8388
|
if (_self.listeners.mousemove)
|
|
8192
|
-
_self.listeners.mousemove(_self.mkParams(e,
|
|
8389
|
+
_self.listeners.mousemove(_self.mkParams(e, "mousemove"));
|
|
8193
8390
|
if (_self.mouseDragPos && _self.listeners.drag)
|
|
8194
|
-
_self.listeners.drag(_self.mkParams(e,
|
|
8391
|
+
_self.listeners.drag(_self.mkParams(e, "drag"));
|
|
8195
8392
|
if (_self.mouseDownPos)
|
|
8196
8393
|
_self.mouseDragPos = _self.relPos(e);
|
|
8197
8394
|
};
|
|
8198
|
-
this.handlers[
|
|
8395
|
+
this.handlers["mouseup"] = (e) => {
|
|
8199
8396
|
if (_self.listeners.mouseup)
|
|
8200
|
-
_self.listeners.mouseup(_self.mkParams(e,
|
|
8397
|
+
_self.listeners.mouseup(_self.mkParams(e, "mouseup"));
|
|
8201
8398
|
_self.mouseDragPos = undefined;
|
|
8202
8399
|
_self.mouseDownPos = undefined;
|
|
8203
8400
|
_self.mouseButton = -1;
|
|
8204
8401
|
};
|
|
8205
|
-
this.handlers[
|
|
8402
|
+
this.handlers["mousedown"] = (e) => {
|
|
8206
8403
|
_self.mouseDragPos = _self.relPos(e);
|
|
8207
8404
|
_self.mouseDownPos = _self.relPos(e);
|
|
8208
8405
|
_self.mouseButton = e.button;
|
|
8209
8406
|
if (_self.listeners.mousedown)
|
|
8210
|
-
_self.listeners.mousedown(_self.mkParams(e,
|
|
8407
|
+
_self.listeners.mousedown(_self.mkParams(e, "mousedown"));
|
|
8211
8408
|
};
|
|
8212
|
-
this.handlers[
|
|
8409
|
+
this.handlers["click"] = (e) => {
|
|
8213
8410
|
if (_self.listeners.click)
|
|
8214
|
-
_self.listeners.click(_self.mkParams(e,
|
|
8411
|
+
_self.listeners.click(_self.mkParams(e, "click"));
|
|
8215
8412
|
};
|
|
8216
|
-
this.handlers[
|
|
8413
|
+
this.handlers["wheel"] = (e) => {
|
|
8217
8414
|
if (_self.listeners.wheel)
|
|
8218
|
-
_self.listeners.wheel(_self.mkParams(e,
|
|
8415
|
+
_self.listeners.wheel(_self.mkParams(e, "wheel"));
|
|
8219
8416
|
};
|
|
8220
|
-
this.element.addEventListener(
|
|
8221
|
-
this.element.addEventListener(
|
|
8222
|
-
this.element.addEventListener(
|
|
8223
|
-
this.element.addEventListener(
|
|
8224
|
-
this.element.addEventListener(
|
|
8417
|
+
this.element.addEventListener("mousemove", this.handlers["mousemove"]);
|
|
8418
|
+
this.element.addEventListener("mouseup", this.handlers["mouseup"]);
|
|
8419
|
+
this.element.addEventListener("mousedown", this.handlers["mousedown"]);
|
|
8420
|
+
this.element.addEventListener("click", this.handlers["click"]);
|
|
8421
|
+
this.element.addEventListener("wheel", this.handlers["wheel"]);
|
|
8225
8422
|
}
|
|
8226
8423
|
/**
|
|
8227
8424
|
* Get relative position from the given MouseEvent.
|
|
@@ -8234,11 +8431,8 @@ class MouseHandler {
|
|
|
8234
8431
|
* @return {XYCoords} The relative mouse coordinates.
|
|
8235
8432
|
*/
|
|
8236
8433
|
relPos(e) {
|
|
8237
|
-
return { x: e.offsetX,
|
|
8238
|
-
y: e.offsetY
|
|
8239
|
-
};
|
|
8434
|
+
return { x: e.offsetX, y: e.offsetY };
|
|
8240
8435
|
}
|
|
8241
|
-
;
|
|
8242
8436
|
/**
|
|
8243
8437
|
* Build the extended event params.
|
|
8244
8438
|
*
|
|
@@ -8264,8 +8458,8 @@ class MouseHandler {
|
|
|
8264
8458
|
rightButton: this.mouseButton == 2,
|
|
8265
8459
|
mouseDownPos: this.mouseDownPos,
|
|
8266
8460
|
draggedFrom: this.mouseDragPos,
|
|
8267
|
-
wasDragged:
|
|
8268
|
-
dragAmount:
|
|
8461
|
+
wasDragged: this.mouseDownPos != null && (this.mouseDownPos.x != rel.x || this.mouseDownPos.y != rel.y),
|
|
8462
|
+
dragAmount: this.mouseDownPos != null ? { x: rel.x - this.mouseDragPos.x, y: rel.y - this.mouseDragPos.y } : { x: 0, y: 0 }
|
|
8269
8463
|
};
|
|
8270
8464
|
return xEvent;
|
|
8271
8465
|
}
|
|
@@ -8316,14 +8510,13 @@ class MouseHandler {
|
|
|
8316
8510
|
*/
|
|
8317
8511
|
drag(callback) {
|
|
8318
8512
|
if (this.listeners.drag)
|
|
8319
|
-
this.throwAlreadyInstalled(
|
|
8513
|
+
this.throwAlreadyInstalled("drag");
|
|
8320
8514
|
this.listeners.drag = callback;
|
|
8321
|
-
this.listenFor(
|
|
8322
|
-
this.listenFor(
|
|
8323
|
-
this.listenFor(
|
|
8515
|
+
this.listenFor("mousedown");
|
|
8516
|
+
this.listenFor("mousemove");
|
|
8517
|
+
this.listenFor("mouseup");
|
|
8324
8518
|
return this;
|
|
8325
8519
|
}
|
|
8326
|
-
;
|
|
8327
8520
|
/**
|
|
8328
8521
|
* Installer function to listen for a specific event: mouse-move.
|
|
8329
8522
|
* Pass your callbacks here.
|
|
@@ -8338,12 +8531,11 @@ class MouseHandler {
|
|
|
8338
8531
|
*/
|
|
8339
8532
|
move(callback) {
|
|
8340
8533
|
if (this.listeners.mousemove)
|
|
8341
|
-
this.throwAlreadyInstalled(
|
|
8342
|
-
this.listenFor(
|
|
8534
|
+
this.throwAlreadyInstalled("mousemove");
|
|
8535
|
+
this.listenFor("mousemove");
|
|
8343
8536
|
this.listeners.mousemove = callback;
|
|
8344
8537
|
return this;
|
|
8345
8538
|
}
|
|
8346
|
-
;
|
|
8347
8539
|
/**
|
|
8348
8540
|
* Installer function to listen for a specific event: mouse-up.
|
|
8349
8541
|
* Pass your callbacks here.
|
|
@@ -8358,12 +8550,11 @@ class MouseHandler {
|
|
|
8358
8550
|
*/
|
|
8359
8551
|
up(callback) {
|
|
8360
8552
|
if (this.listeners.mouseup)
|
|
8361
|
-
this.throwAlreadyInstalled(
|
|
8362
|
-
this.listenFor(
|
|
8553
|
+
this.throwAlreadyInstalled("mouseup");
|
|
8554
|
+
this.listenFor("mouseup");
|
|
8363
8555
|
this.listeners.mouseup = callback;
|
|
8364
8556
|
return this;
|
|
8365
8557
|
}
|
|
8366
|
-
;
|
|
8367
8558
|
/**
|
|
8368
8559
|
* Installer function to listen for a specific event: mouse-down.
|
|
8369
8560
|
* Pass your callbacks here.
|
|
@@ -8378,12 +8569,11 @@ class MouseHandler {
|
|
|
8378
8569
|
*/
|
|
8379
8570
|
down(callback) {
|
|
8380
8571
|
if (this.listeners.mousedown)
|
|
8381
|
-
this.throwAlreadyInstalled(
|
|
8382
|
-
this.listenFor(
|
|
8572
|
+
this.throwAlreadyInstalled("mousedown");
|
|
8573
|
+
this.listenFor("mousedown");
|
|
8383
8574
|
this.listeners.mousedown = callback;
|
|
8384
8575
|
return this;
|
|
8385
8576
|
}
|
|
8386
|
-
;
|
|
8387
8577
|
/**
|
|
8388
8578
|
* Installer function to listen for a specific event: mouse-click.
|
|
8389
8579
|
* Pass your callbacks here.
|
|
@@ -8398,12 +8588,11 @@ class MouseHandler {
|
|
|
8398
8588
|
*/
|
|
8399
8589
|
click(callback) {
|
|
8400
8590
|
if (this.listeners.click)
|
|
8401
|
-
this.throwAlreadyInstalled(
|
|
8402
|
-
this.listenFor(
|
|
8591
|
+
this.throwAlreadyInstalled("click");
|
|
8592
|
+
this.listenFor("click");
|
|
8403
8593
|
this.listeners.click = callback;
|
|
8404
8594
|
return this;
|
|
8405
8595
|
}
|
|
8406
|
-
;
|
|
8407
8596
|
/**
|
|
8408
8597
|
* Installer function to listen for a specific event: mouse-wheel.
|
|
8409
8598
|
* Pass your callbacks here.
|
|
@@ -8418,12 +8607,11 @@ class MouseHandler {
|
|
|
8418
8607
|
*/
|
|
8419
8608
|
wheel(callback) {
|
|
8420
8609
|
if (this.listeners.wheel)
|
|
8421
|
-
this.throwAlreadyInstalled(
|
|
8422
|
-
this.listenFor(
|
|
8610
|
+
this.throwAlreadyInstalled("wheel");
|
|
8611
|
+
this.listenFor("wheel");
|
|
8423
8612
|
this.listeners.wheel = callback;
|
|
8424
8613
|
return this;
|
|
8425
8614
|
}
|
|
8426
|
-
;
|
|
8427
8615
|
/**
|
|
8428
8616
|
* An internal function to throw events.
|
|
8429
8617
|
*
|
|
@@ -8437,7 +8625,6 @@ class MouseHandler {
|
|
|
8437
8625
|
throwAlreadyInstalled(name) {
|
|
8438
8626
|
throw `This MouseHandler already has a '${name}' callback. To keep the code simple there is only room for one.`;
|
|
8439
8627
|
}
|
|
8440
|
-
;
|
|
8441
8628
|
/**
|
|
8442
8629
|
* Call this when your work is done.
|
|
8443
8630
|
*
|
|
@@ -8450,16 +8637,16 @@ class MouseHandler {
|
|
|
8450
8637
|
* @return {void}
|
|
8451
8638
|
*/
|
|
8452
8639
|
destroy() {
|
|
8453
|
-
this.unlistenFor(
|
|
8454
|
-
this.unlistenFor(
|
|
8455
|
-
this.unlistenFor(
|
|
8456
|
-
this.unlistenFor(
|
|
8457
|
-
this.unlistenFor(
|
|
8458
|
-
this.element.removeEventListener(
|
|
8459
|
-
this.element.removeEventListener(
|
|
8460
|
-
this.element.removeEventListener(
|
|
8461
|
-
this.element.removeEventListener(
|
|
8462
|
-
this.element.removeEventListener(
|
|
8640
|
+
this.unlistenFor("mousedown");
|
|
8641
|
+
this.unlistenFor("mousemove");
|
|
8642
|
+
this.unlistenFor("moseup");
|
|
8643
|
+
this.unlistenFor("click");
|
|
8644
|
+
this.unlistenFor("wheel");
|
|
8645
|
+
this.element.removeEventListener("mousemove", this.handlers["mousemove"]);
|
|
8646
|
+
this.element.removeEventListener("mouseup", this.handlers["mousedown"]);
|
|
8647
|
+
this.element.removeEventListener("mousedown", this.handlers["mousedown"]);
|
|
8648
|
+
this.element.removeEventListener("click", this.handlers["click"]);
|
|
8649
|
+
this.element.removeEventListener("wheel", this.handlers["wheel"]);
|
|
8463
8650
|
}
|
|
8464
8651
|
}
|
|
8465
8652
|
|
|
@@ -8469,7 +8656,9 @@ class MouseHandler {
|
|
|
8469
8656
|
* @modified 2019-03-23 Added JSDoc tags.
|
|
8470
8657
|
* @modified 2020-03-25 Ported this class from vanilla-JS to Typescript.
|
|
8471
8658
|
* @modified 2021-01-20 Added UID.
|
|
8472
|
-
* @
|
|
8659
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
8660
|
+
* @modified 2022-02-02 Cleared the `PBImage.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
8661
|
+
* @version 1.2.0
|
|
8473
8662
|
*
|
|
8474
8663
|
* @file PBImage
|
|
8475
8664
|
* @fileoverview As native Image objects have only a position and with
|
|
@@ -8504,28 +8693,23 @@ class PBImage {
|
|
|
8504
8693
|
this.upperLeft = upperLeft;
|
|
8505
8694
|
this.lowerRight = lowerRight;
|
|
8506
8695
|
}
|
|
8507
|
-
;
|
|
8508
8696
|
/**
|
|
8509
|
-
*
|
|
8510
|
-
*
|
|
8511
|
-
*
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
|
|
8516
|
-
|
|
8517
|
-
**/
|
|
8518
|
-
toSVGString(options) {
|
|
8519
|
-
console.warn("PBImage is not yet SVG serializable. Returning empty SVG string.");
|
|
8520
|
-
return "";
|
|
8697
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
8698
|
+
* After calling this function the object might not hold valid data any more and
|
|
8699
|
+
* should not be used.
|
|
8700
|
+
*/
|
|
8701
|
+
destroy() {
|
|
8702
|
+
this.upperLeft.destroy();
|
|
8703
|
+
this.lowerRight.destroy();
|
|
8704
|
+
this.isDestroyed = true;
|
|
8521
8705
|
}
|
|
8522
|
-
;
|
|
8523
8706
|
}
|
|
8524
8707
|
|
|
8525
8708
|
/**
|
|
8526
8709
|
* @author Ikaros Kappler
|
|
8527
8710
|
* @date 2021-11-16
|
|
8528
|
-
* @
|
|
8711
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
8712
|
+
* @version 1.1.0
|
|
8529
8713
|
**/
|
|
8530
8714
|
/**
|
|
8531
8715
|
* @classdesc A simple text element: position, fontSize, fontFamily, color, textAlign, lineHeight and rotation.
|
|
@@ -8566,18 +8750,13 @@ class PBText {
|
|
|
8566
8750
|
this.rotation = options.rotation;
|
|
8567
8751
|
}
|
|
8568
8752
|
/**
|
|
8569
|
-
*
|
|
8570
|
-
*
|
|
8571
|
-
*
|
|
8572
|
-
* @method toSVGString
|
|
8573
|
-
* @param {object=} options - An optional set of options, like 'className'.
|
|
8574
|
-
* @return {string} A string representing the SVG code for this vertex.
|
|
8575
|
-
* @instance
|
|
8576
|
-
* @memberof Circle
|
|
8753
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
8754
|
+
* After calling this function the object might not hold valid data any more and
|
|
8755
|
+
* should not be used.
|
|
8577
8756
|
*/
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
|
|
8757
|
+
destroy() {
|
|
8758
|
+
this.anchor.destroy();
|
|
8759
|
+
this.isDestroyed = true;
|
|
8581
8760
|
}
|
|
8582
8761
|
} // END class
|
|
8583
8762
|
|
|
@@ -8982,7 +9161,9 @@ class AlloyFinger {
|
|
|
8982
9161
|
* @modified 2021-03-10 Added the `toCubicBezier` method.
|
|
8983
9162
|
* @modified 2021-03-15 Added `VEllipse.quarterSegmentCount` and `VEllipse.scale` functions.
|
|
8984
9163
|
* @modified 2021-03-19 Added the `VEllipse.rotate` function.
|
|
8985
|
-
* @
|
|
9164
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
9165
|
+
* @modified 2022-02-02 Cleared the `VEllipse.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
9166
|
+
* @version 1.3.0
|
|
8986
9167
|
*
|
|
8987
9168
|
* @file VEllipse
|
|
8988
9169
|
* @fileoverview Ellipses with a center and an x- and a y-axis (stored as a vertex).
|
|
@@ -9301,24 +9482,14 @@ class VEllipse {
|
|
|
9301
9482
|
return curves;
|
|
9302
9483
|
}
|
|
9303
9484
|
/**
|
|
9304
|
-
*
|
|
9305
|
-
*
|
|
9306
|
-
*
|
|
9307
|
-
* @param {object} options { className?:string }
|
|
9308
|
-
* @return string The SVG string
|
|
9485
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
9486
|
+
* After calling this function the object might not hold valid data any more and
|
|
9487
|
+
* should not be used.
|
|
9309
9488
|
*/
|
|
9310
|
-
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
|
|
9314
|
-
if (options.className)
|
|
9315
|
-
buffer.push(' class="' + options.className + '"');
|
|
9316
|
-
buffer.push(' cx="' + this.center.x + '"');
|
|
9317
|
-
buffer.push(' cy="' + this.center.y + '"');
|
|
9318
|
-
buffer.push(' rx="' + this.axis.x + '"');
|
|
9319
|
-
buffer.push(' ry="' + this.axis.y + '"');
|
|
9320
|
-
buffer.push(" />");
|
|
9321
|
-
return buffer.join("");
|
|
9489
|
+
destroy() {
|
|
9490
|
+
this.center.destroy();
|
|
9491
|
+
this.axis.destroy();
|
|
9492
|
+
this.isDestroyed = true;
|
|
9322
9493
|
}
|
|
9323
9494
|
}
|
|
9324
9495
|
/**
|
|
@@ -9385,7 +9556,8 @@ VEllipse.utils = {
|
|
|
9385
9556
|
*
|
|
9386
9557
|
* @author Ikaros Kappler
|
|
9387
9558
|
* @date 2021-02-26
|
|
9388
|
-
* @
|
|
9559
|
+
* @modified 2022-02-02 Added the `destroy` method.
|
|
9560
|
+
* @version 1.1.0
|
|
9389
9561
|
*/
|
|
9390
9562
|
/**
|
|
9391
9563
|
* @classdesc A class for elliptic sectors.
|
|
@@ -9471,6 +9643,15 @@ class VEllipseSector {
|
|
|
9471
9643
|
}
|
|
9472
9644
|
return curves;
|
|
9473
9645
|
}
|
|
9646
|
+
/**
|
|
9647
|
+
* This function should invalidate any installed listeners and invalidate this object.
|
|
9648
|
+
* After calling this function the object might not hold valid data any more and
|
|
9649
|
+
* should not be used.
|
|
9650
|
+
*/
|
|
9651
|
+
destroy() {
|
|
9652
|
+
this.ellipse.destroy();
|
|
9653
|
+
this.isDestroyed = true;
|
|
9654
|
+
}
|
|
9474
9655
|
}
|
|
9475
9656
|
VEllipseSector.ellipseSectorUtils = {
|
|
9476
9657
|
/**
|
|
@@ -9711,7 +9892,8 @@ VEllipseSector.ellipseSectorUtils = {
|
|
|
9711
9892
|
* @modified 2021-03-29 Clearing `currentClassName` and `currentId` after drawing each drawable.
|
|
9712
9893
|
* @modified 2021-04-25 Extending `remove` to accept arrays of drawables.
|
|
9713
9894
|
* @modified 2021-11-16 Adding the `PBText` drawable.
|
|
9714
|
-
* @
|
|
9895
|
+
* @modified 2022-08-01 Added `title` to the params.
|
|
9896
|
+
* @version 1.15.1
|
|
9715
9897
|
*
|
|
9716
9898
|
* @file PlotBoilerplate
|
|
9717
9899
|
* @fileoverview The main class.
|
|
@@ -9804,6 +9986,7 @@ class PlotBoilerplate {
|
|
|
9804
9986
|
* @param {boolean=} [config.enableGL=false] - Indicates if the application should use the experimental WebGL features (not recommended).
|
|
9805
9987
|
* @param {boolean=} [config.enableSVGExport=true] - Indicates if the SVG export should be enabled (default is true).
|
|
9806
9988
|
* Note that changes from the postDraw hook might not be visible in the export.
|
|
9989
|
+
* @param {string=} [config.title=null] - Specify any hover tile here. It will be attached as a `title` attribute to the most elevated element.
|
|
9807
9990
|
*/
|
|
9808
9991
|
constructor(config) {
|
|
9809
9992
|
/**
|
|
@@ -10019,6 +10202,11 @@ class PlotBoilerplate {
|
|
|
10019
10202
|
else {
|
|
10020
10203
|
throw "Element is neither a canvas nor an svg element.";
|
|
10021
10204
|
}
|
|
10205
|
+
// At this point the event cacher element is deinfed and located at highest elevation.
|
|
10206
|
+
// Set `title` attribut?
|
|
10207
|
+
if (config.title) {
|
|
10208
|
+
this.eventCatcher.setAttribute("title", config.title);
|
|
10209
|
+
}
|
|
10022
10210
|
this.draw.scale.set(this.config.scaleX, this.config.scaleY);
|
|
10023
10211
|
this.fill.scale.set(this.config.scaleX, this.config.scaleY);
|
|
10024
10212
|
this.vertices = [];
|
|
@@ -10321,7 +10509,7 @@ class PlotBoilerplate {
|
|
|
10321
10509
|
}
|
|
10322
10510
|
}
|
|
10323
10511
|
for (var i = 0; i < this.drawables.length; i++) {
|
|
10324
|
-
if (this.drawables[i] === drawable) {
|
|
10512
|
+
if (this.drawables[i] === drawable || this.drawables[i].uid === drawable.uid) {
|
|
10325
10513
|
this.drawables.splice(i, 1);
|
|
10326
10514
|
if (removeWithVertices) {
|
|
10327
10515
|
// Check if some listeners need to be removed
|
|
@@ -11701,100 +11889,5 @@ PlotBoilerplate.utils = {
|
|
|
11701
11889
|
}
|
|
11702
11890
|
}; // END utils
|
|
11703
11891
|
|
|
11704
|
-
|
|
11705
|
-
* Todos:
|
|
11706
|
-
* + use a Drawable interface
|
|
11707
|
-
* + use a SVGSerializable interface
|
|
11708
|
-
*
|
|
11709
|
-
* @require Vertex
|
|
11710
|
-
*
|
|
11711
|
-
* @deprecated THIS CLASS IS DEPRECATED. Please use the new `drawutilssvg` instead.
|
|
11712
|
-
*
|
|
11713
|
-
* @author Ikaros Kappler
|
|
11714
|
-
* @date 2018-12-04
|
|
11715
|
-
* @modified 2019-11-07 Added the 'Triangle' style class.
|
|
11716
|
-
* @modified 2019-11-13 Added the <?xml ...?> tag.
|
|
11717
|
-
* @modified 2020-03-25 Ported this class from vanilla-JS to Typescript.
|
|
11718
|
-
* @modified 2020-12-17 Added Circle and CircleSection style classes.
|
|
11719
|
-
* @modified 2021-01-26 DEPRECATION
|
|
11720
|
-
* @version 1.0.5
|
|
11721
|
-
**/
|
|
11722
|
-
/**
|
|
11723
|
-
* @classdesc A default SVG builder.
|
|
11724
|
-
*
|
|
11725
|
-
* @requires SVGSerializable
|
|
11726
|
-
* @requires Vertex
|
|
11727
|
-
*/
|
|
11728
|
-
class SVGBuilder {
|
|
11729
|
-
/**
|
|
11730
|
-
* @constructor
|
|
11731
|
-
**/
|
|
11732
|
-
constructor() {
|
|
11733
|
-
console.warn("THIS CLASS IS DEPRECATED. Please use the new 'drawutilssvg' instead.");
|
|
11734
|
-
}
|
|
11735
|
-
;
|
|
11736
|
-
/**
|
|
11737
|
-
* Builds the SVG code from the given list of drawables.
|
|
11738
|
-
*
|
|
11739
|
-
* @param {object[]} drawables - The drawable elements (should implement Drawable) to be converted (each must have a toSVGString-function).
|
|
11740
|
-
* @param {object} options - { canvasSize, zoom, offset }
|
|
11741
|
-
* @return {string}
|
|
11742
|
-
**/
|
|
11743
|
-
build(drawables, options) {
|
|
11744
|
-
var nl = '\n';
|
|
11745
|
-
var indent = ' ';
|
|
11746
|
-
var buffer = [];
|
|
11747
|
-
buffer.push('<?xml version="1.0" encoding="UTF-8"?>' + nl);
|
|
11748
|
-
buffer.push('<svg width="' + options.canvasSize.width + '" height="' + options.canvasSize.height + '"');
|
|
11749
|
-
buffer.push(' viewBox="');
|
|
11750
|
-
buffer.push('0');
|
|
11751
|
-
buffer.push(' ');
|
|
11752
|
-
buffer.push('0');
|
|
11753
|
-
buffer.push(' ');
|
|
11754
|
-
buffer.push(options.canvasSize.width.toString());
|
|
11755
|
-
buffer.push(' ');
|
|
11756
|
-
buffer.push(options.canvasSize.height.toString());
|
|
11757
|
-
buffer.push('"');
|
|
11758
|
-
buffer.push(' xmlns="http://www.w3.org/2000/svg">' + nl);
|
|
11759
|
-
buffer.push(indent + '<defs>' + nl);
|
|
11760
|
-
buffer.push(indent + '<style>' + nl);
|
|
11761
|
-
buffer.push(indent + indent + ' .Vertex { fill : blue; stroke : none; } ' + nl);
|
|
11762
|
-
buffer.push(indent + indent + ' .Triangle { fill : none; stroke : turquoise; stroke-width : 1px; } ' + nl);
|
|
11763
|
-
buffer.push(indent + indent + ' .Polygon { fill : none; stroke : green; stroke-width : 2px; } ' + nl);
|
|
11764
|
-
buffer.push(indent + indent + ' .BezierPath { fill : none; stroke : blue; stroke-width : 2px; } ' + nl);
|
|
11765
|
-
buffer.push(indent + indent + ' .VEllipse { fill : none; stroke : black; stroke-width : 1px; } ' + nl);
|
|
11766
|
-
buffer.push(indent + indent + ' .Line { fill : none; stroke : purple; stroke-width : 1px; } ' + nl);
|
|
11767
|
-
buffer.push(indent + indent + ' .Circle { fill : none; stroke : purple; stroke-width : 1px; } ' + nl);
|
|
11768
|
-
buffer.push(indent + indent + ' .CircleSector { fill : none; stroke : purple; stroke-width : 1px; } ' + nl);
|
|
11769
|
-
buffer.push(indent + '</style>' + nl);
|
|
11770
|
-
buffer.push(indent + '</defs>' + nl);
|
|
11771
|
-
buffer.push(indent + '<g class="main-g"');
|
|
11772
|
-
if (options.zoom || options.offset) {
|
|
11773
|
-
buffer.push(' transform="');
|
|
11774
|
-
if (options.zoom)
|
|
11775
|
-
buffer.push('scale(' + options.zoom.x + ',' + options.zoom.y + ')');
|
|
11776
|
-
if (options.offset)
|
|
11777
|
-
buffer.push(' translate(' + options.offset.x + ',' + options.offset.y + ')');
|
|
11778
|
-
buffer.push('"');
|
|
11779
|
-
}
|
|
11780
|
-
buffer.push('>' + nl);
|
|
11781
|
-
for (var i in drawables) {
|
|
11782
|
-
var d = drawables[i];
|
|
11783
|
-
if (typeof d.toSVGString == 'function') {
|
|
11784
|
-
buffer.push(indent + indent);
|
|
11785
|
-
buffer.push(d.toSVGString({ 'className': d.className }));
|
|
11786
|
-
buffer.push(nl);
|
|
11787
|
-
}
|
|
11788
|
-
else {
|
|
11789
|
-
console.warn('Unrecognized drawable type has no toSVGString()-function. Ignoring: ' + d.className);
|
|
11790
|
-
}
|
|
11791
|
-
}
|
|
11792
|
-
buffer.push(indent + '</g>' + nl);
|
|
11793
|
-
buffer.push('</svg>' + nl);
|
|
11794
|
-
return buffer.join('');
|
|
11795
|
-
}
|
|
11796
|
-
;
|
|
11797
|
-
}
|
|
11798
|
-
|
|
11799
|
-
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 };
|
|
11892
|
+
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 };
|
|
11800
11893
|
//# sourceMappingURL=index.esm.js.map
|