@teachinglab/omd 0.7.29 → 0.7.31
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/canvas/features/resizeHandleManager.js +16 -6
- package/canvas/tools/PointerTool.js +12 -5
- package/package.json +1 -1
- package/src/omdShapes.js +159 -60
|
@@ -20,6 +20,7 @@ export class ResizeHandleManager {
|
|
|
20
20
|
this.selectionBorderColor = '#007bff';
|
|
21
21
|
this.selectionBorderWidth = 2;
|
|
22
22
|
this.selectionBorder = null;
|
|
23
|
+
this.selectionBorderPadding = { top: 8, right: 8, bottom: 8, left: 8 };
|
|
23
24
|
|
|
24
25
|
// Resize constraints
|
|
25
26
|
this.minSize = 20;
|
|
@@ -270,11 +271,19 @@ export class ResizeHandleManager {
|
|
|
270
271
|
* @param {string} [style.dasharray] - SVG stroke-dasharray value (e.g. '4,2' or 'none')
|
|
271
272
|
* @param {number} [style.cornerRadius]- rx/ry corner radius of the border rect
|
|
272
273
|
*/
|
|
273
|
-
setSelectionStyle({ color, width, dasharray, cornerRadius } = {}) {
|
|
274
|
+
setSelectionStyle({ color, width, dasharray, cornerRadius, padding, paddingX, paddingY, paddingTop, paddingRight, paddingBottom, paddingLeft } = {}) {
|
|
274
275
|
if (color !== undefined) this.selectionBorderColor = color;
|
|
275
276
|
if (width !== undefined) this.selectionBorderWidth = width;
|
|
276
277
|
if (dasharray !== undefined) this.selectionBorderDasharray = dasharray;
|
|
277
278
|
if (cornerRadius !== undefined) this.selectionBorderCornerRadius = cornerRadius;
|
|
279
|
+
const basePadding = padding ?? null;
|
|
280
|
+
const nextPadding = {
|
|
281
|
+
top: paddingTop ?? paddingY ?? basePadding ?? this.selectionBorderPadding.top,
|
|
282
|
+
right: paddingRight ?? paddingX ?? basePadding ?? this.selectionBorderPadding.right,
|
|
283
|
+
bottom: paddingBottom ?? paddingY ?? basePadding ?? this.selectionBorderPadding.bottom,
|
|
284
|
+
left: paddingLeft ?? paddingX ?? basePadding ?? this.selectionBorderPadding.left
|
|
285
|
+
};
|
|
286
|
+
this.selectionBorderPadding = nextPadding;
|
|
278
287
|
|
|
279
288
|
// Re-apply to live border if one exists
|
|
280
289
|
if (this.selectionBorder) {
|
|
@@ -286,6 +295,7 @@ export class ResizeHandleManager {
|
|
|
286
295
|
this.selectionBorder.setAttribute('rx', this.selectionBorderCornerRadius);
|
|
287
296
|
this.selectionBorder.setAttribute('ry', this.selectionBorderCornerRadius);
|
|
288
297
|
}
|
|
298
|
+
this._updateSelectionBorder();
|
|
289
299
|
}
|
|
290
300
|
}
|
|
291
301
|
|
|
@@ -385,12 +395,12 @@ export class ResizeHandleManager {
|
|
|
385
395
|
if (!this.selectionBorder || !this.selectedElement) return;
|
|
386
396
|
|
|
387
397
|
const bounds = this._getTransformedBounds();
|
|
388
|
-
const padding =
|
|
398
|
+
const padding = this.selectionBorderPadding;
|
|
389
399
|
|
|
390
|
-
this.selectionBorder.setAttribute('x', bounds.x - padding);
|
|
391
|
-
this.selectionBorder.setAttribute('y', bounds.y - padding);
|
|
392
|
-
this.selectionBorder.setAttribute('width', bounds.width + padding
|
|
393
|
-
this.selectionBorder.setAttribute('height', bounds.height + padding
|
|
400
|
+
this.selectionBorder.setAttribute('x', bounds.x - padding.left);
|
|
401
|
+
this.selectionBorder.setAttribute('y', bounds.y - padding.top);
|
|
402
|
+
this.selectionBorder.setAttribute('width', bounds.width + padding.left + padding.right);
|
|
403
|
+
this.selectionBorder.setAttribute('height', bounds.height + padding.top + padding.bottom);
|
|
394
404
|
}
|
|
395
405
|
|
|
396
406
|
/**
|
|
@@ -50,6 +50,13 @@ export class PointerTool extends Tool {
|
|
|
50
50
|
this.dragStartPoint = null;
|
|
51
51
|
this.potentialDeselect = null;
|
|
52
52
|
this.hasSeparatedForDrag = false;
|
|
53
|
+
|
|
54
|
+
this.selectionBoundsPadding = {
|
|
55
|
+
top: options.selectionBoundsPaddingTop ?? options.selectionBoundsPaddingY ?? options.selectionBoundsPadding ?? 14,
|
|
56
|
+
right: options.selectionBoundsPaddingRight ?? options.selectionBoundsPaddingX ?? options.selectionBoundsPadding ?? 14,
|
|
57
|
+
bottom: options.selectionBoundsPaddingBottom ?? options.selectionBoundsPaddingY ?? options.selectionBoundsPadding ?? 14,
|
|
58
|
+
left: options.selectionBoundsPaddingLeft ?? options.selectionBoundsPaddingX ?? options.selectionBoundsPadding ?? 14
|
|
59
|
+
};
|
|
53
60
|
|
|
54
61
|
// Initialize resize handle manager for OMD visuals
|
|
55
62
|
this.resizeHandleManager = new ResizeHandleManager(canvas);
|
|
@@ -595,12 +602,12 @@ export class PointerTool extends Tool {
|
|
|
595
602
|
if (!hasPoints) return null;
|
|
596
603
|
|
|
597
604
|
// Add padding to match the visual box
|
|
598
|
-
const padding =
|
|
605
|
+
const padding = this.selectionBoundsPadding;
|
|
599
606
|
return {
|
|
600
|
-
x: minX - padding,
|
|
601
|
-
y: minY - padding,
|
|
602
|
-
width: (maxX + padding) - (minX - padding),
|
|
603
|
-
height: (maxY + padding) - (minY - padding)
|
|
607
|
+
x: minX - padding.left,
|
|
608
|
+
y: minY - padding.top,
|
|
609
|
+
width: (maxX + padding.right) - (minX - padding.left),
|
|
610
|
+
height: (maxY + padding.bottom) - (minY - padding.top)
|
|
604
611
|
};
|
|
605
612
|
}
|
|
606
613
|
|
package/package.json
CHANGED
package/src/omdShapes.js
CHANGED
|
@@ -2,6 +2,39 @@
|
|
|
2
2
|
import { omdColor } from "./omdColor.js";
|
|
3
3
|
import { jsvgGroup, jsvgPath, jsvgLine, jsvgTextLine, jsvgEllipse } from "@teachinglab/jsvg";
|
|
4
4
|
|
|
5
|
+
const DEFAULT_SHAPE_PADDING = 10;
|
|
6
|
+
const LABEL_SHAPE_PADDING = 38;
|
|
7
|
+
|
|
8
|
+
function getShapePadding(showLabels) {
|
|
9
|
+
return showLabels ? LABEL_SHAPE_PADDING : DEFAULT_SHAPE_PADDING;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function getClosedPolygonVertices(shapePath) {
|
|
13
|
+
const points = Array.isArray(shapePath?.points) ? shapePath.points : [];
|
|
14
|
+
if (points.length <= 1) return points.slice();
|
|
15
|
+
|
|
16
|
+
const first = points[0];
|
|
17
|
+
const last = points[points.length - 1];
|
|
18
|
+
const isClosed = first.x === last.x && first.y === last.y;
|
|
19
|
+
return isClosed ? points.slice(0, -1) : points.slice();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function getPolygonCentroid(points) {
|
|
23
|
+
if (!points.length) return { x: 0, y: 0 };
|
|
24
|
+
|
|
25
|
+
let sumX = 0;
|
|
26
|
+
let sumY = 0;
|
|
27
|
+
for (const point of points) {
|
|
28
|
+
sumX += point.x;
|
|
29
|
+
sumY += point.y;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
x: sumX / points.length,
|
|
34
|
+
y: sumY / points.length
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
5
38
|
export class omdRightTriangle extends jsvgGroup
|
|
6
39
|
{
|
|
7
40
|
constructor()
|
|
@@ -69,8 +102,9 @@ export class omdRightTriangle extends jsvgGroup
|
|
|
69
102
|
updateLayout()
|
|
70
103
|
{
|
|
71
104
|
// Center the triangle within the viewBox
|
|
72
|
-
const
|
|
73
|
-
const
|
|
105
|
+
const padding = getShapePadding(this.showLabels);
|
|
106
|
+
const offsetX = padding;
|
|
107
|
+
const offsetY = this.unitScale * this.verticalLeg + padding;
|
|
74
108
|
|
|
75
109
|
this.shapePath.clearPoints();
|
|
76
110
|
this.shapePath.addPoint(offsetX, offsetY);
|
|
@@ -92,8 +126,8 @@ export class omdRightTriangle extends jsvgGroup
|
|
|
92
126
|
}
|
|
93
127
|
|
|
94
128
|
// Set viewBox to center the shape
|
|
95
|
-
this.width = this.unitScale * this.horizontalLeg +
|
|
96
|
-
this.height = this.unitScale * this.verticalLeg +
|
|
129
|
+
this.width = this.unitScale * this.horizontalLeg + padding * 2;
|
|
130
|
+
this.height = this.unitScale * this.verticalLeg + padding * 2;
|
|
97
131
|
this.svgObject.setAttribute('viewBox', `0 0 ${this.width} ${this.height}`);
|
|
98
132
|
}
|
|
99
133
|
}
|
|
@@ -150,8 +184,9 @@ export class omdIsoscelesTriangle extends jsvgGroup
|
|
|
150
184
|
|
|
151
185
|
const baseWidth = this.unitScale * this.triangleBase;
|
|
152
186
|
const triangleHeight = this.unitScale * this.triangleHeight;
|
|
153
|
-
const
|
|
154
|
-
const
|
|
187
|
+
const padding = getShapePadding(this.showLabels);
|
|
188
|
+
const offsetX = padding;
|
|
189
|
+
const offsetY = triangleHeight + padding;
|
|
155
190
|
|
|
156
191
|
this.shapePath.addPoint( offsetX, offsetY );
|
|
157
192
|
this.shapePath.addPoint( offsetX + baseWidth, offsetY );
|
|
@@ -169,8 +204,8 @@ export class omdIsoscelesTriangle extends jsvgGroup
|
|
|
169
204
|
}
|
|
170
205
|
|
|
171
206
|
// Set dimensions and viewBox for API compatibility
|
|
172
|
-
this.width = this.unitScale * this.triangleBase +
|
|
173
|
-
this.height = this.unitScale * this.triangleHeight +
|
|
207
|
+
this.width = this.unitScale * this.triangleBase + padding * 2;
|
|
208
|
+
this.height = this.unitScale * this.triangleHeight + padding * 2;
|
|
174
209
|
this.svgObject.setAttribute('viewBox', `0 0 ${this.width} ${this.height}`);
|
|
175
210
|
}
|
|
176
211
|
}
|
|
@@ -222,8 +257,9 @@ export class omdRectangle extends jsvgGroup
|
|
|
222
257
|
updateLayout()
|
|
223
258
|
{
|
|
224
259
|
// Center the rectangle within the viewBox
|
|
225
|
-
const
|
|
226
|
-
const
|
|
260
|
+
const padding = getShapePadding(this.showLabels);
|
|
261
|
+
const offsetX = padding;
|
|
262
|
+
const offsetY = this.unitScale * this.rectHeight + padding;
|
|
227
263
|
|
|
228
264
|
this.shapePath.clearPoints();
|
|
229
265
|
this.shapePath.addPoint(offsetX, offsetY);
|
|
@@ -245,8 +281,8 @@ export class omdRectangle extends jsvgGroup
|
|
|
245
281
|
}
|
|
246
282
|
|
|
247
283
|
// Set viewBox
|
|
248
|
-
this.width = this.unitScale * this.rectWidth +
|
|
249
|
-
this.height = this.unitScale * this.rectHeight +
|
|
284
|
+
this.width = this.unitScale * this.rectWidth + padding * 2;
|
|
285
|
+
this.height = this.unitScale * this.rectHeight + padding * 2;
|
|
250
286
|
this.svgObject.setAttribute('viewBox', `0 0 ${this.width} ${this.height}`);
|
|
251
287
|
}
|
|
252
288
|
}
|
|
@@ -264,6 +300,7 @@ export class omdEllipse extends jsvgGroup
|
|
|
264
300
|
this.rectWidth = 10;
|
|
265
301
|
this.rectHeight = 5;
|
|
266
302
|
this.unitScale = 10;
|
|
303
|
+
this.showLabels = false;
|
|
267
304
|
|
|
268
305
|
this.shapePath = new jsvgEllipse();
|
|
269
306
|
this.shapePath.setWidthAndHeight( this.rectWidth*this.unitScale, this.rectHeight*this.unitScale );
|
|
@@ -272,6 +309,9 @@ export class omdEllipse extends jsvgGroup
|
|
|
272
309
|
this.shapePath.setFillColor( omdColor.lightGray );
|
|
273
310
|
this.addChild( this.shapePath );
|
|
274
311
|
|
|
312
|
+
this.labelsHolder = new jsvgGroup();
|
|
313
|
+
this.addChild( this.labelsHolder );
|
|
314
|
+
|
|
275
315
|
this.updateLayout();
|
|
276
316
|
}
|
|
277
317
|
|
|
@@ -286,6 +326,9 @@ export class omdEllipse extends jsvgGroup
|
|
|
286
326
|
if ( typeof data.unitScale != "undefined" )
|
|
287
327
|
this.unitScale = data.unitScale;
|
|
288
328
|
|
|
329
|
+
if ( typeof data.showLabels != "undefined" )
|
|
330
|
+
this.showLabels = data.showLabels;
|
|
331
|
+
|
|
289
332
|
this.updateLayout();
|
|
290
333
|
}
|
|
291
334
|
|
|
@@ -297,6 +340,19 @@ export class omdEllipse extends jsvgGroup
|
|
|
297
340
|
this.shapePath.setWidthAndHeight( ellipseWidth, ellipseHeight );
|
|
298
341
|
this.shapePath.setPosition( ellipseWidth * 0.5 + 10, ellipseHeight * 0.5 + 10 );
|
|
299
342
|
|
|
343
|
+
this.labelsHolder.removeAllChildren();
|
|
344
|
+
if ( this.showLabels )
|
|
345
|
+
{
|
|
346
|
+
const label = new jsvgTextLine();
|
|
347
|
+
label.setAlignment("center");
|
|
348
|
+
label.setFontFamily( "Albert Sans" );
|
|
349
|
+
label.setFontColor( "black" );
|
|
350
|
+
label.setFontSize( 12 );
|
|
351
|
+
label.setPosition( ellipseWidth * 0.5 + 10, ellipseHeight * 0.5 + 14 );
|
|
352
|
+
label.setText( `${this.rectWidth} × ${this.rectHeight}` );
|
|
353
|
+
this.labelsHolder.addChild( label );
|
|
354
|
+
}
|
|
355
|
+
|
|
300
356
|
// Set dimensions and viewBox for API compatibility
|
|
301
357
|
this.width = this.rectWidth * this.unitScale + 20;
|
|
302
358
|
this.height = this.rectHeight * this.unitScale + 20;
|
|
@@ -315,6 +371,7 @@ export class omdCircle extends jsvgGroup
|
|
|
315
371
|
|
|
316
372
|
this.radius = 5;
|
|
317
373
|
this.unitScale = 10;
|
|
374
|
+
this.showLabels = false;
|
|
318
375
|
|
|
319
376
|
this.shapePath = new jsvgEllipse();
|
|
320
377
|
this.shapePath.setWidthAndHeight( this.radius*this.unitScale, this.radius*this.unitScale );
|
|
@@ -323,6 +380,9 @@ export class omdCircle extends jsvgGroup
|
|
|
323
380
|
this.shapePath.setFillColor( omdColor.lightGray );
|
|
324
381
|
this.addChild( this.shapePath );
|
|
325
382
|
|
|
383
|
+
this.labelsHolder = new jsvgGroup();
|
|
384
|
+
this.addChild( this.labelsHolder );
|
|
385
|
+
|
|
326
386
|
this.updateLayout();
|
|
327
387
|
}
|
|
328
388
|
|
|
@@ -334,15 +394,49 @@ export class omdCircle extends jsvgGroup
|
|
|
334
394
|
if ( typeof data.unitScale != "undefined" )
|
|
335
395
|
this.unitScale = data.unitScale;
|
|
336
396
|
|
|
397
|
+
if ( typeof data.showLabels != "undefined" )
|
|
398
|
+
this.showLabels = data.showLabels;
|
|
399
|
+
|
|
337
400
|
this.updateLayout();
|
|
338
401
|
}
|
|
339
402
|
|
|
340
403
|
updateLayout()
|
|
341
404
|
{
|
|
342
405
|
const diameter = 2.0 * this.radius * this.unitScale;
|
|
406
|
+
const radiusPx = this.radius * this.unitScale;
|
|
407
|
+
const centerX = radiusPx + 10;
|
|
408
|
+
const centerY = radiusPx + 10;
|
|
343
409
|
|
|
344
410
|
this.shapePath.setWidthAndHeight( diameter, diameter );
|
|
345
|
-
this.shapePath.setPosition(
|
|
411
|
+
this.shapePath.setPosition( centerX, centerY );
|
|
412
|
+
|
|
413
|
+
this.labelsHolder.removeAllChildren();
|
|
414
|
+
if ( this.showLabels )
|
|
415
|
+
{
|
|
416
|
+
const angleRadians = -Math.PI / 6;
|
|
417
|
+
const endX = centerX + Math.cos(angleRadians) * radiusPx * 0.82;
|
|
418
|
+
const endY = centerY + Math.sin(angleRadians) * radiusPx * 0.82;
|
|
419
|
+
|
|
420
|
+
const radiusLine = new jsvgLine();
|
|
421
|
+
radiusLine.setStrokeColor("black");
|
|
422
|
+
radiusLine.setStrokeWidth(1.5);
|
|
423
|
+
radiusLine.setEndpoints(centerX, centerY, endX, endY);
|
|
424
|
+
this.labelsHolder.addChild(radiusLine);
|
|
425
|
+
|
|
426
|
+
const label = new jsvgTextLine();
|
|
427
|
+
label.setAlignment("center");
|
|
428
|
+
label.setFontFamily( "Albert Sans" );
|
|
429
|
+
label.setFontColor( "black" );
|
|
430
|
+
label.setFontSize( 12 );
|
|
431
|
+
label.svgObject.setAttribute('dominant-baseline', 'middle');
|
|
432
|
+
label.setRotation(angleRadians * 180 / Math.PI);
|
|
433
|
+
label.setPosition(
|
|
434
|
+
(centerX + endX) * 0.5 + 3,
|
|
435
|
+
(centerY + endY) * 0.5 - 4
|
|
436
|
+
);
|
|
437
|
+
label.setText( `r=${this.radius}` );
|
|
438
|
+
this.labelsHolder.addChild( label );
|
|
439
|
+
}
|
|
346
440
|
|
|
347
441
|
// Set dimensions and viewBox for API compatibility
|
|
348
442
|
this.width = 2.0 * this.radius * this.unitScale + 20;
|
|
@@ -400,6 +494,10 @@ export class omdRegularPolygon extends jsvgGroup
|
|
|
400
494
|
updateLayout()
|
|
401
495
|
{
|
|
402
496
|
this.shapePath.clearPoints();
|
|
497
|
+
const radiusPx = this.radius * this.unitScale;
|
|
498
|
+
const padding = this.showLabels ? 48 : 14;
|
|
499
|
+
const centerX = radiusPx + padding;
|
|
500
|
+
const centerY = radiusPx + padding;
|
|
403
501
|
|
|
404
502
|
var angleOffset = 0;
|
|
405
503
|
if ( this.numberOfSides % 2 == 1 )
|
|
@@ -413,8 +511,8 @@ export class omdRegularPolygon extends jsvgGroup
|
|
|
413
511
|
{
|
|
414
512
|
var A = -2.0 * Math.PI / this.numberOfSides * i;
|
|
415
513
|
A += angleOffset;
|
|
416
|
-
var pX = Math.cos(A) *
|
|
417
|
-
var pY = Math.sin(A) *
|
|
514
|
+
var pX = centerX + Math.cos(A) * radiusPx;
|
|
515
|
+
var pY = centerY + Math.sin(A) * radiusPx;
|
|
418
516
|
this.shapePath.addPoint( pX, pY );
|
|
419
517
|
}
|
|
420
518
|
|
|
@@ -432,9 +530,9 @@ export class omdRegularPolygon extends jsvgGroup
|
|
|
432
530
|
}
|
|
433
531
|
|
|
434
532
|
// Set dimensions and viewBox for API compatibility
|
|
435
|
-
this.width = 2.0 *
|
|
436
|
-
this.height = 2.0 *
|
|
437
|
-
this.svgObject.setAttribute('viewBox',
|
|
533
|
+
this.width = 2.0 * radiusPx + padding * 2;
|
|
534
|
+
this.height = 2.0 * radiusPx + padding * 2;
|
|
535
|
+
this.svgObject.setAttribute('viewBox', `0 0 ${this.width} ${this.height}`);
|
|
438
536
|
}
|
|
439
537
|
}
|
|
440
538
|
|
|
@@ -449,76 +547,77 @@ export class omdShapeLabelSet extends jsvgGroup
|
|
|
449
547
|
|
|
450
548
|
initializeWithShapePath( shapePath, labelTextArray=[] )
|
|
451
549
|
{
|
|
452
|
-
|
|
550
|
+
const polygonPoints = getClosedPolygonVertices(shapePath);
|
|
551
|
+
const centroid = getPolygonCentroid(polygonPoints);
|
|
453
552
|
|
|
454
553
|
// create lines
|
|
455
|
-
for(
|
|
554
|
+
for (let i = 0; i < polygonPoints.length; i++)
|
|
456
555
|
{
|
|
457
|
-
if ( i >= labelTextArray.length
|
|
556
|
+
if ( i >= labelTextArray.length )
|
|
557
|
+
continue;
|
|
558
|
+
|
|
559
|
+
const labelValue = labelTextArray[i];
|
|
560
|
+
const labelString = String(labelValue ?? "");
|
|
561
|
+
if ( labelString.length === 0 )
|
|
458
562
|
continue;
|
|
459
563
|
|
|
460
564
|
// get points
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
565
|
+
const point0 = polygonPoints[i];
|
|
566
|
+
const x0 = point0.x;
|
|
567
|
+
const y0 = point0.y;
|
|
464
568
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
569
|
+
const point1 = polygonPoints[(i + 1) % polygonPoints.length];
|
|
570
|
+
const x1 = point1.x;
|
|
571
|
+
const y1 = point1.y;
|
|
468
572
|
|
|
469
573
|
// get normalized vector
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
574
|
+
let dX = x1 - x0;
|
|
575
|
+
let dY = y1 - y0;
|
|
576
|
+
const L = Math.sqrt( dX*dX + dY*dY );
|
|
473
577
|
dX /= L;
|
|
474
578
|
dY /= L;
|
|
475
579
|
|
|
476
|
-
// get normal
|
|
477
|
-
|
|
478
|
-
|
|
580
|
+
// get outward normal based on the polygon centroid rather than path winding
|
|
581
|
+
const centerX = (x0 + x1) / 2.0;
|
|
582
|
+
const centerY = (y0 + y1) / 2.0;
|
|
583
|
+
let normalX = -1.0 * dY;
|
|
584
|
+
let normalY = dX;
|
|
585
|
+
const toMidX = centerX - centroid.x;
|
|
586
|
+
const toMidY = centerY - centroid.y;
|
|
587
|
+
if ( toMidX * normalX + toMidY * normalY < 0 )
|
|
588
|
+
{
|
|
589
|
+
normalX *= -1.0;
|
|
590
|
+
normalY *= -1.0;
|
|
591
|
+
}
|
|
479
592
|
|
|
480
593
|
// make line
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
594
|
+
const labelLine = new jsvgLine();
|
|
595
|
+
const newLineX0 = x0 + normalX * 10.0;
|
|
596
|
+
const newLineY0 = y0 + normalY * 10.0;
|
|
597
|
+
const newLineX1 = x1 + normalX * 10.0;
|
|
598
|
+
const newLineY1 = y1 + normalY * 10.0;
|
|
486
599
|
labelLine.setEndpoints( newLineX0, newLineY0, newLineX1, newLineY1 );
|
|
487
600
|
this.addChild( labelLine );
|
|
488
601
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
var angle = Math.atan2( dY, dX );
|
|
494
|
-
angle *= 180 / Math.PI;
|
|
495
|
-
angle += 180.0;
|
|
496
|
-
angle = angle % 360.0;
|
|
497
|
-
var originalAngle = angle;
|
|
498
|
-
|
|
499
|
-
// flip upside-down text
|
|
500
|
-
var offset = 0;
|
|
501
|
-
if ( angle > 90 && angle < 270 )
|
|
502
|
-
{
|
|
503
|
-
angle -= 180.0;
|
|
504
|
-
offset += 10.0;
|
|
505
|
-
}
|
|
602
|
+
let angle = Math.atan2( dY, dX ) * 180 / Math.PI;
|
|
603
|
+
if ( angle > 90 || angle < -90 )
|
|
604
|
+
angle += 180.0;
|
|
506
605
|
|
|
507
606
|
// label text
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
607
|
+
const textCenterX = centerX + normalX * 18.0;
|
|
608
|
+
const textCenterY = centerY + normalY * 18.0;
|
|
609
|
+
const labelText = new jsvgTextLine();
|
|
511
610
|
labelText.setAlignment("center");
|
|
512
611
|
labelText.setFontFamily( "Albert Sans" );
|
|
513
612
|
labelText.setFontColor( "black" );
|
|
514
613
|
labelText.setFontSize( 12 );
|
|
515
614
|
labelText.setPosition( textCenterX, textCenterY );
|
|
516
615
|
labelText.setRotation( angle );
|
|
616
|
+
labelText.svgObject.setAttribute('dominant-baseline', 'middle');
|
|
517
617
|
this.addChild( labelText );
|
|
518
618
|
|
|
519
|
-
labelText.setText(
|
|
619
|
+
labelText.setText( labelString );
|
|
520
620
|
}
|
|
521
621
|
}
|
|
522
622
|
|
|
523
623
|
}
|
|
524
|
-
|