@design-core/core 0.0.6 → 50.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +4 -0
- package/.github/workflows/DesignCoreQA.yml +3 -0
- package/TODO.md +49 -6
- package/core/core/core.js +0 -3
- package/core/designCore.js +1 -1
- package/core/dimensions/alignedDimension.js +12 -11
- package/core/dimensions/angularDimension.js +38 -37
- package/core/dimensions/{baseCircularDimension.js → circularDimensionBase.js} +22 -21
- package/core/dimensions/diametricDimension.js +14 -13
- package/core/dimensions/dimension.js +62 -55
- package/core/dimensions/{baseDimension.js → dimensionBase.js} +73 -107
- package/core/dimensions/{baseLinearDimension.js → linearDimensionBase.js} +15 -14
- package/core/dimensions/radialDimension.js +12 -11
- package/core/dimensions/rotatedDimension.js +20 -19
- package/core/entities/arc.js +123 -156
- package/core/entities/arctext.js +222 -184
- package/core/entities/circle.js +77 -99
- package/core/entities/entity.js +114 -93
- package/core/entities/hatch.js +346 -273
- package/core/entities/insert.js +68 -83
- package/core/entities/line.js +21 -142
- package/core/entities/lwpolyline.js +16 -11
- package/core/entities/point.js +19 -19
- package/core/entities/polyline.js +7 -7
- package/core/entities/{basePolyline.js → polylineBase.js} +47 -299
- package/core/entities/rectangle.js +3 -1
- package/core/entities/solid.js +6 -15
- package/core/entities/text.js +190 -201
- package/core/lib/auxiliary/rubberBand.js +32 -0
- package/core/lib/auxiliary/selectionWindow.js +63 -0
- package/core/lib/auxiliary/snapPoint.js +113 -0
- package/core/lib/auxiliary/trackingLine.js +76 -0
- package/core/lib/boundingBox.js +11 -11
- package/core/lib/canvas.js +232 -168
- package/core/lib/clipboard.js +9 -3
- package/core/lib/colour.js +16 -0
- package/core/lib/commandLine.js +1 -6
- package/core/lib/commandManager.js +18 -8
- package/core/lib/constants.js +28 -0
- package/core/lib/dxf/dxf.js +15 -14
- package/core/lib/dxf/dxfIterator.js +2 -2
- package/core/lib/entityManager.js +33 -26
- package/core/lib/inputManager.js +36 -12
- package/core/lib/intersect.js +25 -0
- package/core/lib/matrix.js +1 -1
- package/core/lib/patterns.js +9 -2
- package/core/lib/plotOptions.js +67 -0
- package/core/lib/polylineUtils.js +75 -0
- package/core/lib/renderers/cairoRenderer.js +371 -0
- package/core/lib/renderers/canvasRenderer.js +315 -0
- package/core/lib/renderers/pdfRenderer.js +366 -0
- package/core/lib/renderers/rendererBase.js +284 -0
- package/core/lib/renderers/svgRenderer.js +343 -0
- package/core/lib/scene.js +28 -6
- package/core/lib/selectionManager.js +20 -20
- package/core/lib/settings.js +4 -2
- package/core/lib/snapping.js +4 -191
- package/core/lib/stateManager.js +30 -1
- package/core/lib/utils.js +26 -7
- package/core/properties/entityProperties.js +104 -0
- package/core/properties/property.js +106 -2
- package/core/properties/propertyManager.js +60 -44
- package/core/tables/block.js +50 -81
- package/core/tables/dimStyle.js +5 -5
- package/core/tables/endblk.js +1 -1
- package/core/tables/layer.js +8 -0
- package/core/tables/ltypeManager.js +1 -1
- package/core/tables/styleManagerBase.js +3 -2
- package/core/tables/tableManagerBase.js +8 -3
- package/core/tables/vport.js +2 -2
- package/core/tools/chamfer.js +117 -143
- package/core/tools/chamferFilletBase.js +138 -37
- package/core/tools/copy.js +11 -11
- package/core/tools/copybase.js +3 -3
- package/core/tools/copyclip.js +3 -3
- package/core/tools/cornerEntity.js +2 -2
- package/core/tools/cutclip.js +3 -3
- package/core/tools/explode.js +7 -7
- package/core/tools/extend.js +138 -25
- package/core/tools/fillet.js +92 -189
- package/core/tools/matchProp.js +3 -12
- package/core/tools/mirror.js +15 -14
- package/core/tools/move.js +8 -8
- package/core/tools/offset.js +31 -33
- package/core/tools/pasteclip.js +1 -1
- package/core/tools/purge.js +10 -10
- package/core/tools/rotate.js +19 -16
- package/core/tools/scale.js +7 -7
- package/core/tools/trim.js +271 -29
- package/core/tools/zoom.js +1 -1
- package/cspell.json +321 -0
- package/jest.config.js +6 -0
- package/package.json +5 -3
- package/test/dimensions/alignedDimension.test.js +17 -10
- package/test/dimensions/angularDimension.test.js +13 -13
- package/test/dimensions/diametricDimension.test.js +15 -15
- package/test/dimensions/dimension.test.js +12 -12
- package/test/dimensions/{baseDimension.test.js → dimensionBase.test.js} +73 -12
- package/test/dimensions/linearDimensionBase.test.js +62 -0
- package/test/dimensions/radialDimension.test.js +15 -15
- package/test/dimensions/rotatedDimension.test.js +18 -11
- package/test/entities/arc.test.js +83 -86
- package/test/entities/arctext.test.js +184 -57
- package/test/entities/circle.test.js +68 -96
- package/test/entities/entity.test.js +42 -8
- package/test/entities/hatch.test.js +569 -96
- package/test/entities/insert.test.js +99 -4
- package/test/entities/line.test.js +15 -41
- package/test/entities/lwpolyline.test.js +104 -0
- package/test/entities/point.test.js +3 -3
- package/test/entities/polyline.test.js +11 -0
- package/test/entities/{basePolyline.test.js → polylineBase.test.js} +192 -57
- package/test/entities/rectangle.test.js +11 -0
- package/test/entities/solid.test.js +1 -1
- package/test/entities/text.test.js +302 -77
- package/test/integration/exportIntegration.reference.dxf +9 -9
- package/test/integration/exportIntegration.test.js +5 -5
- package/test/integration/intersectionIntegration.test.js +4 -5
- package/test/integration/pdfRendererIntegration.reference.pdf +17709 -0
- package/test/integration/pdfRendererIntegration.test.js +61 -0
- package/test/integration/svgRendererIntegration.reference.svg +3343 -0
- package/test/integration/svgRendererIntegration.test.js +61 -0
- package/test/integration/userInputIntegration.reference.dxf +1165 -105
- package/test/integration/userInputIntegration.test.js +239 -132
- package/test/lib/boundingBox.test.js +3 -3
- package/test/lib/canvas.test.js +744 -125
- package/test/lib/constants.test.js +27 -0
- package/test/lib/entityManager.test.js +4 -4
- package/test/lib/inputManager.test.js +81 -20
- package/test/lib/intersect.test.js +83 -0
- package/test/lib/plotOptions.test.js +179 -0
- package/test/lib/rubberBand.test.js +84 -0
- package/test/lib/scene.test.js +9 -9
- package/test/lib/selectionManager.test.js +3 -3
- package/test/lib/settings.test.js +5 -6
- package/test/lib/snapping.test.js +72 -130
- package/test/lib/stateManager.test.js +7 -7
- package/test/lib/utils.test.js +36 -2
- package/test/properties/entityProperties.test.js +132 -0
- package/test/properties/property.test.js +53 -0
- package/test/properties/propertyManager.test.js +25 -25
- package/test/renderers/canvasRenderer.test.js +317 -0
- package/test/renderers/pdfRenderer.test.js +271 -0
- package/test/renderers/rendererBase.test.js +213 -0
- package/test/renderers/svgRenderer.test.js +326 -0
- package/test/tables/block.test.js +92 -13
- package/test/tables/endblk.test.js +2 -2
- package/test/tables/layer.test.js +30 -0
- package/test/tables/layerManager.test.js +2 -2
- package/test/test-helpers/hatchGridRenderer.js +180 -0
- package/test/test-helpers/test-helpers.js +158 -6
- package/test/tools/chamfer.test.js +273 -51
- package/test/tools/chamferFilletBase.test.js +125 -36
- package/test/tools/copy.test.js +8 -8
- package/test/tools/copybase.test.js +2 -2
- package/test/tools/copyclip.test.js +2 -2
- package/test/tools/cornerEntity.test.js +8 -8
- package/test/tools/cutclip.test.js +2 -2
- package/test/tools/erase.test.js +6 -6
- package/test/tools/explode.test.js +5 -5
- package/test/tools/extend.test.js +373 -42
- package/test/tools/fillet.test.js +230 -49
- package/test/tools/matchProp.test.js +11 -11
- package/test/tools/mirror.test.js +39 -39
- package/test/tools/move.test.js +7 -7
- package/test/tools/offset.test.js +222 -55
- package/test/tools/pasteclip.test.js +5 -5
- package/test/tools/purge.test.js +4 -4
- package/test/tools/rotate.test.js +39 -9
- package/test/tools/scale.test.js +33 -33
- package/test/tools/trim.test.js +579 -53
- package/test/tools/zoom.test.js +12 -12
- package/core/lib/selectionWindow.js +0 -83
package/core/entities/text.js
CHANGED
|
@@ -10,7 +10,8 @@ import { Flags } from '../properties/flags.js';
|
|
|
10
10
|
import { Property } from '../properties/property.js';
|
|
11
11
|
|
|
12
12
|
import { DesignCore } from '../designCore.js';
|
|
13
|
-
import { SnapPoint } from '../lib/
|
|
13
|
+
import { SnapPoint } from '../lib/auxiliary/snapPoint.js';
|
|
14
|
+
import { RubberBand } from '../lib/auxiliary/rubberBand.js';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Text Entity Class
|
|
@@ -19,35 +20,31 @@ import { SnapPoint } from '../lib/snapping.js';
|
|
|
19
20
|
export class Text extends Entity {
|
|
20
21
|
static type = 'Text';
|
|
21
22
|
|
|
23
|
+
static #charWidths = {
|
|
24
|
+
' ': 0.28, '!': 0.28, '"': 0.35, '#': 0.56, '$': 0.56, '%': 0.89, '&': 0.67, '\'': 0.19,
|
|
25
|
+
'(': 0.33, ')': 0.33, '*': 0.39, '+': 0.58, ',': 0.28, '-': 0.33, '.': 0.28, '/': 0.31,
|
|
26
|
+
'0': 0.56, '1': 0.56, '2': 0.56, '3': 0.56, '4': 0.56, '5': 0.56, '6': 0.56, '7': 0.56,
|
|
27
|
+
'8': 0.56, '9': 0.56, ':': 0.28, ';': 0.28, '<': 0.58, '=': 0.58, '>': 0.58, '?': 0.56,
|
|
28
|
+
'@': 1.02, 'A': 0.67, 'B': 0.67, 'C': 0.72, 'D': 0.72, 'E': 0.61, 'F': 0.56, 'G': 0.78,
|
|
29
|
+
'H': 0.72, 'I': 0.28, 'J': 0.39, 'K': 0.67, 'L': 0.56, 'M': 0.83, 'N': 0.72, 'O': 0.78,
|
|
30
|
+
'P': 0.61, 'Q': 0.78, 'R': 0.67, 'S': 0.56, 'T': 0.61, 'U': 0.72, 'V': 0.67, 'W': 0.94,
|
|
31
|
+
'X': 0.67, 'Y': 0.67, 'Z': 0.61, '[': 0.28, '\\': 0.31, ']': 0.28, '^': 0.47, '_': 0.56,
|
|
32
|
+
'`': 0.33, 'a': 0.56, 'b': 0.56, 'c': 0.50, 'd': 0.56, 'e': 0.56, 'f': 0.28, 'g': 0.56,
|
|
33
|
+
'h': 0.56, 'i': 0.22, 'j': 0.22, 'k': 0.50, 'l': 0.22, 'm': 0.83, 'n': 0.56, 'o': 0.56,
|
|
34
|
+
'p': 0.56, 'q': 0.56, 'r': 0.33, 's': 0.50, 't': 0.33, 'u': 0.56, 'v': 0.50, 'w': 0.72,
|
|
35
|
+
'x': 0.50, 'y': 0.50, 'z': 0.44, '{': 0.33, '|': 0.26, '}': 0.33, '~': 0.58,
|
|
36
|
+
};
|
|
37
|
+
|
|
22
38
|
/**
|
|
23
39
|
* Create a Text Entity
|
|
24
40
|
* @param {Array} data
|
|
25
41
|
*/
|
|
26
42
|
constructor(data) {
|
|
27
43
|
super(data);
|
|
28
|
-
this.string = '';
|
|
29
|
-
this.height = 2.5;
|
|
30
|
-
this.horizontalAlignment = 0;
|
|
31
|
-
this.verticalAlignment = 0;
|
|
32
|
-
this.styleName = 'STANDARD';
|
|
33
|
-
|
|
34
|
-
// hide inherited properties
|
|
35
|
-
// needs to be enumerable=false to not appear in the object props
|
|
36
|
-
Object.defineProperty(this, 'lineType', {
|
|
37
|
-
enumerable: false,
|
|
38
|
-
});
|
|
39
44
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// add rotation property with getter and setter
|
|
45
|
-
// needs to be enumerable to appear in the object props
|
|
46
|
-
Object.defineProperty(this, 'rotation', {
|
|
47
|
-
get: this.getRotation,
|
|
48
|
-
set: this.setRotation,
|
|
49
|
-
enumerable: true,
|
|
50
|
-
});
|
|
45
|
+
// Remove inherited properties not applicable to text
|
|
46
|
+
this.properties.remove(Property.Names.LINETYPE);
|
|
47
|
+
this.properties.remove(Property.Names.LINEWIDTH);
|
|
51
48
|
|
|
52
49
|
// needs to be non-enumerable as to not appear in the object props
|
|
53
50
|
Object.defineProperty(this, 'boundingRect', {
|
|
@@ -61,75 +58,71 @@ export class Text extends Entity {
|
|
|
61
58
|
writable: true,
|
|
62
59
|
});
|
|
63
60
|
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
enumerable: true,
|
|
61
|
+
// DXF Groupcode 1 - Text String
|
|
62
|
+
this.properties.add(Property.Names.STRING, {
|
|
63
|
+
type: Property.Type.STRING,
|
|
64
|
+
value: Property.loadValue([data?.string, data?.[1]], ''),
|
|
65
|
+
dxfCode: 1,
|
|
70
66
|
});
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
get: this.getUpsideDown,
|
|
77
|
-
set: this.setUpsideDown,
|
|
78
|
-
enumerable: true,
|
|
67
|
+
// DXF Groupcode 40 - Text Height
|
|
68
|
+
this.properties.add(Property.Names.HEIGHT, {
|
|
69
|
+
type: Property.Type.NUMBER,
|
|
70
|
+
value: Property.loadValue([data?.height, data?.[40]], 2.5),
|
|
71
|
+
dxfCode: 40,
|
|
79
72
|
});
|
|
80
|
-
|
|
81
|
-
if (data) {
|
|
82
|
-
// DXF Groupcode 11,21,31 - Second alignment point (optional, used for aligned, middle, or fit text)
|
|
83
|
-
if (data?.points?.length > 1) {
|
|
84
|
-
if (data.points[1].sequence == 11) {
|
|
85
|
-
this.points = [];
|
|
86
|
-
this.points.push(new Point(data.points[1].x, data.points[1].y));
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
// DXF Groupcode 1 - Text String
|
|
92
|
-
this.string = Property.loadValue([data?.string, data?.[1]], '');
|
|
93
73
|
// DXF Groupcode 7 - Text Style Name
|
|
94
|
-
this.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
// DXF Groupcode 50 - Text Rotation, angle in degrees
|
|
101
|
-
// if we get rotation data store this as a point[1] at an angle from point[0]
|
|
102
|
-
// this allows all the entities to be rotated by rotating the points i.e. not all entities have a rotation property
|
|
103
|
-
this.setRotation(Property.loadValue([data.rotation, data[50]], 0));
|
|
104
|
-
} else {
|
|
105
|
-
// create points[1] used to determine the text rotation
|
|
106
|
-
if (this.points.length && this.height !== undefined) {
|
|
107
|
-
this.points[1] = this.points[0].add(new Point(this.height, 0));
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
74
|
+
this.properties.add(Property.Names.STYLENAME, {
|
|
75
|
+
type: Property.Type.LIST,
|
|
76
|
+
value: Property.loadValue([data?.styleName, data?.[7]], 'STANDARD'),
|
|
77
|
+
dxfCode: 7,
|
|
78
|
+
options: () => DesignCore.StyleManager.getItems().map((s) => ({ display: s.name, value: s.name })),
|
|
79
|
+
});
|
|
112
80
|
// DXF Groupcode 72 - Horizontal Alignment
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
81
|
+
const hAlign = Property.loadValue([data?.horizontalAlignment, data?.[72]], 0);
|
|
82
|
+
this.properties.add(Property.Names.HORIZONTALALIGNMENT, {
|
|
83
|
+
type: Property.Type.LIST,
|
|
84
|
+
value: hAlign > 2 ? 1 : hAlign,
|
|
85
|
+
dxfCode: 72,
|
|
86
|
+
options: () => [{ display: 'Left', value: 0 }, { display: 'Centre', value: 1 }, { display: 'Right', value: 2 }],
|
|
87
|
+
});
|
|
88
|
+
// DXF Groupcode 73 - Vertical Alignment (0=Baseline; 1=Bottom; 2=Middle; 3=Top)
|
|
89
|
+
this.properties.add(Property.Names.VERTICALALIGNMENT, {
|
|
90
|
+
type: Property.Type.LIST,
|
|
91
|
+
value: Property.loadValue([data?.verticalAlignment, data?.[73]], 0),
|
|
92
|
+
dxfCode: 73,
|
|
93
|
+
options: () => [{ display: 'Baseline', value: 0 }, { display: 'Bottom', value: 1 }, { display: 'Middle', value: 2 }, { display: 'Top', value: 3 }],
|
|
94
|
+
});
|
|
95
|
+
// DXF Groupcode 71 - flags (bit-coded): 2=backward, 4=upsideDown
|
|
96
|
+
this.flags.setFlagValue(Property.loadValue([data?.flags, data?.[71]], 0));
|
|
124
97
|
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
|
|
98
|
+
// rotation: computed from angle between points[0] and points[1]
|
|
99
|
+
this.properties.add(Property.Names.ROTATION, {
|
|
100
|
+
type: Property.Type.NUMBER,
|
|
101
|
+
get: (entity) => entity.getRotation(),
|
|
102
|
+
set: (entity, angle) => entity.setRotation(angle),
|
|
103
|
+
dxfCode: 50,
|
|
104
|
+
});
|
|
105
|
+
// backwards: computed from flags bit 2
|
|
106
|
+
this.properties.add(Property.Names.BACKWARDS, {
|
|
107
|
+
type: Property.Type.BOOLEAN,
|
|
108
|
+
get: (entity) => entity.getBackwards(),
|
|
109
|
+
set: (entity, bool) => entity.setBackwards(bool),
|
|
110
|
+
dxfCode: 71,
|
|
111
|
+
});
|
|
112
|
+
// upsideDown: computed from flags bit 4
|
|
113
|
+
this.properties.add(Property.Names.UPSIDEDOWN, {
|
|
114
|
+
type: Property.Type.BOOLEAN,
|
|
115
|
+
get: (entity) => entity.getUpsideDown(),
|
|
116
|
+
set: (entity, bool) => entity.setUpsideDown(bool),
|
|
117
|
+
dxfCode: 71,
|
|
118
|
+
});
|
|
128
119
|
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
this.
|
|
120
|
+
// Named scalar rotation for internal API usage (DXF group code 50 is handled by fromDxf)
|
|
121
|
+
if (data?.rotation !== undefined && !this.points[1]) {
|
|
122
|
+
this.setRotation(data.rotation);
|
|
123
|
+
} else if (!this.points[1] && this.points.length && this.getProperty(Property.Names.HEIGHT) !== undefined) {
|
|
124
|
+
this.points[1] = this.points[0].add(new Point(this.getProperty(Property.Names.HEIGHT), 0));
|
|
125
|
+
}
|
|
133
126
|
}
|
|
134
127
|
|
|
135
128
|
/**
|
|
@@ -144,6 +137,34 @@ export class Text extends Entity {
|
|
|
144
137
|
return command;
|
|
145
138
|
}
|
|
146
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Normalise raw DXF data before construction
|
|
142
|
+
* @param {Object} data - raw DXF group code object
|
|
143
|
+
* @return {Object} normalised data with full points array and rotation encoded as points[1]
|
|
144
|
+
*
|
|
145
|
+
* Handles:
|
|
146
|
+
* - Group codes 11,21,31: when a second alignment point with sequence 11 is present it
|
|
147
|
+
* replaces points[0] as the text insertion point
|
|
148
|
+
* - Group code 50: rotation angle (degrees) is projected into points[1] so that all
|
|
149
|
+
* rotation logic in the entity works uniformly through the points array
|
|
150
|
+
*/
|
|
151
|
+
static fromDxf(data) {
|
|
152
|
+
// DXF group codes 11,21,31 - second alignment point overrides first when present
|
|
153
|
+
let points = data.points ? [...data.points] : [];
|
|
154
|
+
if (points.length > 1 && points[1]?.sequence == 11) {
|
|
155
|
+
points = [new Point(points[1].x, points[1].y)];
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// DXF group code 50 - text rotation angle in degrees
|
|
159
|
+
// project points[1] from the insertion point to encode rotation
|
|
160
|
+
if (data[50] !== undefined && points[0]) {
|
|
161
|
+
const height = data[40] ?? data.height ?? 2.5;
|
|
162
|
+
points[1] = points[0].project(Utils.degrees2radians(data[50]), height);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return { ...data, points };
|
|
166
|
+
}
|
|
167
|
+
|
|
147
168
|
/**
|
|
148
169
|
* Get the approximate width of the text
|
|
149
170
|
* @param {string} string - text string
|
|
@@ -153,9 +174,11 @@ export class Text extends Entity {
|
|
|
153
174
|
* Actual width depends on the font and style used
|
|
154
175
|
*/
|
|
155
176
|
static getApproximateWidth(string, textHeight) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
177
|
+
let width = 0;
|
|
178
|
+
for (const ch of string) {
|
|
179
|
+
width += (Text.#charWidths[ch] ?? 0.56) * textHeight;
|
|
180
|
+
}
|
|
181
|
+
return width;
|
|
159
182
|
}
|
|
160
183
|
|
|
161
184
|
/**
|
|
@@ -171,20 +194,20 @@ export class Text extends Entity {
|
|
|
171
194
|
|
|
172
195
|
// set the text style to the current style
|
|
173
196
|
const currentStyle = DesignCore.StyleManager.getCstyle();
|
|
174
|
-
this.
|
|
197
|
+
this.setProperty(Property.Names.STYLENAME, currentStyle);
|
|
175
198
|
|
|
176
199
|
// get properties from style
|
|
177
|
-
const style = DesignCore.StyleManager.getItemByName(this.
|
|
200
|
+
const style = DesignCore.StyleManager.getItemByName(this.getProperty(Property.Names.STYLENAME));
|
|
178
201
|
if (style?.textHeight) {
|
|
179
|
-
this.
|
|
202
|
+
this.setProperty(Property.Names.HEIGHT, style.textHeight);
|
|
180
203
|
}
|
|
181
204
|
|
|
182
|
-
this.
|
|
183
|
-
this.
|
|
205
|
+
this.setProperty(Property.Names.BACKWARDS, style.backwards);
|
|
206
|
+
this.setProperty(Property.Names.UPSIDEDOWN, style.upsideDown);
|
|
184
207
|
|
|
185
208
|
// Get the font size when the style has a variable height (textHeight === 0)
|
|
186
209
|
if (!style?.textHeight) {
|
|
187
|
-
const op2 = new PromptOptions(Strings.Input.HEIGHT, [Input.Type.NUMBER], [], this.
|
|
210
|
+
const op2 = new PromptOptions(Strings.Input.HEIGHT, [Input.Type.NUMBER], [], this.getProperty(Property.Names.HEIGHT));
|
|
188
211
|
while (true) {
|
|
189
212
|
const height = await DesignCore.Scene.inputManager.requestInput(op2);
|
|
190
213
|
if (height === undefined) return;
|
|
@@ -192,7 +215,7 @@ export class Text extends Entity {
|
|
|
192
215
|
DesignCore.Core.notify(`${this.type} - ${Strings.Error.NONZERO}`);
|
|
193
216
|
continue;
|
|
194
217
|
}
|
|
195
|
-
this.
|
|
218
|
+
this.setProperty(Property.Names.HEIGHT, height);
|
|
196
219
|
break;
|
|
197
220
|
}
|
|
198
221
|
}
|
|
@@ -209,7 +232,7 @@ export class Text extends Entity {
|
|
|
209
232
|
DesignCore.Scene.inputManager.reset();
|
|
210
233
|
return;
|
|
211
234
|
}
|
|
212
|
-
this.
|
|
235
|
+
this.setProperty(Property.Names.STRING, String(string));
|
|
213
236
|
|
|
214
237
|
DesignCore.Scene.inputManager.executeCommand(this);
|
|
215
238
|
} catch (err) {
|
|
@@ -225,17 +248,17 @@ export class Text extends Entity {
|
|
|
225
248
|
if (DesignCore.Scene.inputManager.promptOption.types.includes(Input.Type.STRING)) {
|
|
226
249
|
const data = {
|
|
227
250
|
points: this.points,
|
|
228
|
-
height: this.
|
|
229
|
-
rotation: this.
|
|
230
|
-
styleName: this.
|
|
251
|
+
height: this.getProperty(Property.Names.HEIGHT),
|
|
252
|
+
rotation: this.getProperty(Property.Names.ROTATION),
|
|
253
|
+
styleName: this.getProperty(Property.Names.STYLENAME),
|
|
231
254
|
string: DesignCore.CommandLine.command,
|
|
232
255
|
};
|
|
233
256
|
|
|
234
|
-
DesignCore.Scene.
|
|
257
|
+
DesignCore.Scene.previewEntities.create(this.type, data);
|
|
235
258
|
} else {
|
|
236
259
|
const mousePoint = DesignCore.Mouse.pointOnScene();
|
|
237
260
|
const points = [this.points.at(-1), mousePoint];
|
|
238
|
-
DesignCore.Scene.
|
|
261
|
+
DesignCore.Scene.auxiliaryEntities.add(new RubberBand(points));
|
|
239
262
|
}
|
|
240
263
|
}
|
|
241
264
|
}
|
|
@@ -251,8 +274,8 @@ export class Text extends Entity {
|
|
|
251
274
|
return;
|
|
252
275
|
}
|
|
253
276
|
|
|
254
|
-
if (this.
|
|
255
|
-
this.points[1] = this.points[0].project(Utils.degrees2radians(angle), this.
|
|
277
|
+
if (this.getProperty(Property.Names.HEIGHT) > 0) {
|
|
278
|
+
this.points[1] = this.points[0].project(Utils.degrees2radians(angle), this.getProperty(Property.Names.HEIGHT));
|
|
256
279
|
}
|
|
257
280
|
}
|
|
258
281
|
|
|
@@ -327,19 +350,19 @@ export class Text extends Entity {
|
|
|
327
350
|
5 = Fit (if vertical alignment = 0)
|
|
328
351
|
*/
|
|
329
352
|
|
|
330
|
-
switch (this.
|
|
353
|
+
switch (this.getProperty(Property.Names.HORIZONTALALIGNMENT)) {
|
|
331
354
|
case 0:
|
|
332
355
|
return 'left';
|
|
333
356
|
case 1:
|
|
334
|
-
return '
|
|
357
|
+
return 'centre';
|
|
335
358
|
case 2:
|
|
336
359
|
return 'right';
|
|
337
360
|
case 3:
|
|
338
|
-
return (this.
|
|
361
|
+
return (this.getProperty(Property.Names.VERTICALALIGNMENT) === 0 ? 'aligned' : 'left');
|
|
339
362
|
case 4:
|
|
340
|
-
return (this.
|
|
363
|
+
return (this.getProperty(Property.Names.VERTICALALIGNMENT) === 0 ? 'centre' : 'left');
|
|
341
364
|
case 5:
|
|
342
|
-
return (this.
|
|
365
|
+
return (this.getProperty(Property.Names.VERTICALALIGNMENT) === 0 ? 'fit' : 'left');
|
|
343
366
|
default:
|
|
344
367
|
return 'left';
|
|
345
368
|
}
|
|
@@ -356,7 +379,7 @@ export class Text extends Entity {
|
|
|
356
379
|
See the Group 72 and 73 integer codes table for clarification.
|
|
357
380
|
*/
|
|
358
381
|
|
|
359
|
-
switch (this.
|
|
382
|
+
switch (this.getProperty(Property.Names.VERTICALALIGNMENT)) {
|
|
360
383
|
case 0:
|
|
361
384
|
return 'alphabetic';
|
|
362
385
|
case 1:
|
|
@@ -380,88 +403,54 @@ export class Text extends Entity {
|
|
|
380
403
|
}
|
|
381
404
|
|
|
382
405
|
/**
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
*
|
|
406
|
+
* Return a character descriptor array for use with renderer.drawText().
|
|
407
|
+
* Coordinates are in scene space (Y-up). The renderer handles the Y-flip.
|
|
408
|
+
* upsideDownOffset and backwardsOffset are optional DXF-flag offsets in
|
|
409
|
+
* the local (post-rotation) text frame.
|
|
410
|
+
* @return {Array}
|
|
386
411
|
*/
|
|
387
|
-
|
|
388
|
-
if (this.
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
const rotation = Utils.degrees2radians(this.rotation);
|
|
400
|
-
ctx.rotate(-rotation);
|
|
401
|
-
|
|
402
|
-
if (this.upsideDown) {
|
|
403
|
-
const upsideDownOffset = corners[0].distance(corners[3]);
|
|
404
|
-
ctx.translate(0, -upsideDownOffset);
|
|
405
|
-
ctx.scale(1, -1);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (this.backwards) {
|
|
409
|
-
const backwardsOffset = corners[0].distance(corners[1]);
|
|
410
|
-
ctx.translate(backwardsOffset, 0);
|
|
411
|
-
ctx.scale(-1, 1);
|
|
412
|
-
}
|
|
412
|
+
toCharacters() {
|
|
413
|
+
if (this.getProperty(Property.Names.STRING).length === 0) return [];
|
|
414
|
+
const [bottomLeft, bottomRight, /* topRight */, topLeft] = this.getTextFrameCorners();
|
|
415
|
+
return [{
|
|
416
|
+
x: bottomLeft.x,
|
|
417
|
+
y: bottomLeft.y,
|
|
418
|
+
rotation: Utils.degrees2radians(this.getRotation()),
|
|
419
|
+
char: this.getProperty(Property.Names.STRING),
|
|
420
|
+
upsideDownOffset: this.getUpsideDown() ? bottomLeft.distance(topLeft) : 0,
|
|
421
|
+
backwardsOffset: this.getBackwards() ? bottomLeft.distance(bottomRight) : 0,
|
|
422
|
+
}];
|
|
423
|
+
}
|
|
413
424
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
ctx.setFontSize(this.height);
|
|
427
|
-
const drawTextRect = ctx.textExtents(String(this.string));
|
|
428
|
-
|
|
429
|
-
/* GJS Cairo needs additional support for font handling
|
|
430
|
-
https://www.cairographics.org/tutorial/#L1understandingtext
|
|
431
|
-
https://www.cairographics.org/manual/cairo-cairo-scaled-font-t.html#cairo-font-extents-t
|
|
432
|
-
|
|
433
|
-
This needs to be implemented in GJS:
|
|
434
|
-
https://gitlab.gnome.org/GNOME/gjs/-/blob/master/modules/cairo-context.cpp?ref_type=heads#L773
|
|
435
|
-
https://gitlab.gnome.org/GNOME/gjs/-/blob/master/modules/cairo-context.cpp?ref_type=heads#L780
|
|
436
|
-
*/
|
|
437
|
-
// Adjust the font size by the ratio of the desired height to the drawn height to get closer to the desired text height.
|
|
438
|
-
ctx.setFontSize(this.height * this.height / drawTextRect.height);
|
|
439
|
-
this.boundingRect = ctx.textExtents(String(this.string));
|
|
440
|
-
|
|
441
|
-
ctx.showText(String(this.string));
|
|
425
|
+
/**
|
|
426
|
+
* Draw the text entity
|
|
427
|
+
* @param {Object} renderer
|
|
428
|
+
*/
|
|
429
|
+
draw(renderer) {
|
|
430
|
+
if (this.getProperty(Property.Names.STRING).length === 0) return;
|
|
431
|
+
const style = DesignCore.StyleManager.getItemByName(this.getProperty(Property.Names.STYLENAME));
|
|
432
|
+
// Measure with the correct font before toCharacters() so that boundingRect
|
|
433
|
+
// (used for alignment offsets) is accurate on every paint pass.
|
|
434
|
+
const measured = renderer.measureText(this.getProperty(Property.Names.STRING), style?.font, this.getProperty(Property.Names.HEIGHT));
|
|
435
|
+
if (measured?.width) {
|
|
436
|
+
this.boundingRect = { width: measured.width, height: this.getProperty(Property.Names.HEIGHT) };
|
|
442
437
|
}
|
|
443
|
-
|
|
444
|
-
ctx.stroke();
|
|
445
|
-
ctx.restore(); // restore context before scale and translate
|
|
438
|
+
renderer.drawText(this.toCharacters(), style?.font, this.getProperty(Property.Names.HEIGHT));
|
|
446
439
|
|
|
447
440
|
/*
|
|
448
441
|
// debug draw the bounding box
|
|
449
442
|
const bb = this.boundingBox();
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
443
|
+
renderer.drawShape([
|
|
444
|
+
new Point(bb.xMin, bb.yMin),
|
|
445
|
+
new Point(bb.xMax, bb.yMin),
|
|
446
|
+
new Point(bb.xMax, bb.yMax),
|
|
447
|
+
new Point(bb.xMin, bb.yMax),
|
|
448
|
+
new Point(bb.xMin, bb.yMin),
|
|
449
|
+
]);
|
|
456
450
|
|
|
457
451
|
// debug draw the text frame
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
ctx.lineTo(frameCorners[1].x, frameCorners[1].y);
|
|
461
|
-
ctx.lineTo(frameCorners[2].x, frameCorners[2].y);
|
|
462
|
-
ctx.lineTo(frameCorners[3].x, frameCorners[3].y);
|
|
463
|
-
ctx.lineTo(frameCorners[0].x, frameCorners[0].y);
|
|
464
|
-
ctx.stroke();
|
|
452
|
+
const [fc0, fc1, fc2, fc3] = this.getTextFrameCorners();
|
|
453
|
+
renderer.drawShape([fc0, fc1, fc2, fc3, fc0]);
|
|
465
454
|
*/
|
|
466
455
|
}
|
|
467
456
|
|
|
@@ -471,9 +460,9 @@ export class Text extends Entity {
|
|
|
471
460
|
*/
|
|
472
461
|
dxf(file) {
|
|
473
462
|
file.writeGroupCode('0', 'TEXT');
|
|
474
|
-
file.writeGroupCode('5', this.
|
|
463
|
+
file.writeGroupCode('5', this.getProperty(Property.Names.HANDLE), DXFFile.Version.R2000); // Handle
|
|
475
464
|
file.writeGroupCode('100', 'AcDbEntity', DXFFile.Version.R2000);
|
|
476
|
-
file.writeGroupCode('8', this.
|
|
465
|
+
file.writeGroupCode('8', this.getProperty(Property.Names.LAYER));
|
|
477
466
|
file.writeGroupCode('100', 'AcDbText', DXFFile.Version.R2000);
|
|
478
467
|
|
|
479
468
|
const frameCorners = this.getTextFrameCorners();
|
|
@@ -483,22 +472,22 @@ export class Text extends Entity {
|
|
|
483
472
|
file.writeGroupCode('20', bottomLeft.y);
|
|
484
473
|
file.writeGroupCode('30', '0.0');
|
|
485
474
|
|
|
486
|
-
file.writeGroupCode('40', this.
|
|
487
|
-
file.writeGroupCode('1', this.
|
|
488
|
-
file.writeGroupCode('50', this.
|
|
475
|
+
file.writeGroupCode('40', this.getProperty(Property.Names.HEIGHT));
|
|
476
|
+
file.writeGroupCode('1', this.getProperty(Property.Names.STRING));
|
|
477
|
+
file.writeGroupCode('50', this.getRotation());
|
|
489
478
|
// file.writeGroupCode('7', 'STANDARD'); // TEXT STYLE
|
|
490
479
|
file.writeGroupCode('71', this.flags.getFlagValue()); // Text generation flags
|
|
491
|
-
file.writeGroupCode('72', this.
|
|
480
|
+
file.writeGroupCode('72', this.getProperty(Property.Names.HORIZONTALALIGNMENT)); // Horizontal alignment
|
|
492
481
|
|
|
493
|
-
if (this.
|
|
482
|
+
if (this.getProperty(Property.Names.HORIZONTALALIGNMENT) > 0 || this.getProperty(Property.Names.VERTICALALIGNMENT) > 0) {
|
|
494
483
|
file.writeGroupCode('11', this.points[0].x);
|
|
495
484
|
file.writeGroupCode('21', this.points[0].y);
|
|
496
485
|
file.writeGroupCode('31', '0.0');
|
|
497
486
|
}
|
|
498
487
|
|
|
499
488
|
file.writeGroupCode('100', 'AcDbText', DXFFile.Version.R2000);
|
|
500
|
-
if (this.
|
|
501
|
-
file.writeGroupCode('73', this.
|
|
489
|
+
if (this.getProperty(Property.Names.VERTICALALIGNMENT) !== 0) {
|
|
490
|
+
file.writeGroupCode('73', this.getProperty(Property.Names.VERTICALALIGNMENT)); // Vertical alignment
|
|
502
491
|
}
|
|
503
492
|
}
|
|
504
493
|
|
|
@@ -546,11 +535,11 @@ export class Text extends Entity {
|
|
|
546
535
|
const rect = this.getBoundingRect();
|
|
547
536
|
|
|
548
537
|
let offsetX = 0;
|
|
549
|
-
switch (this.
|
|
538
|
+
switch (this.getProperty(Property.Names.HORIZONTALALIGNMENT)) {
|
|
550
539
|
case 0: // left
|
|
551
540
|
offsetX = 0;
|
|
552
541
|
break;
|
|
553
|
-
case 1: //
|
|
542
|
+
case 1: // centre
|
|
554
543
|
offsetX = -rect.width / 2;
|
|
555
544
|
break;
|
|
556
545
|
case 2: // right
|
|
@@ -564,7 +553,7 @@ export class Text extends Entity {
|
|
|
564
553
|
}
|
|
565
554
|
|
|
566
555
|
let offsetY = 0;
|
|
567
|
-
switch (this.
|
|
556
|
+
switch (this.getProperty(Property.Names.VERTICALALIGNMENT)) {
|
|
568
557
|
case 0: // baseline
|
|
569
558
|
offsetY = 0; // see comments in draw method
|
|
570
559
|
break;
|
|
@@ -586,18 +575,18 @@ export class Text extends Entity {
|
|
|
586
575
|
const y0 = rect.y + offsetY;
|
|
587
576
|
|
|
588
577
|
// compute min/max depending on backwards/upsideDown (text direction)
|
|
589
|
-
const xmin = Math.min(x0, this.
|
|
590
|
-
const xmax = Math.max(x0, this.
|
|
591
|
-
const ymin = Math.min(y0, this.
|
|
592
|
-
const ymax = Math.max(y0, this.
|
|
578
|
+
const xmin = Math.min(x0, this.getBackwards() ? x0 - rect.width : x0 + rect.width);
|
|
579
|
+
const xmax = Math.max(x0, this.getBackwards() ? x0 - rect.width : x0 + rect.width);
|
|
580
|
+
const ymin = Math.min(y0, this.getUpsideDown() ? y0 - rect.height : y0 + rect.height);
|
|
581
|
+
const ymax = Math.max(y0, this.getUpsideDown() ? y0 - rect.height : y0 + rect.height);
|
|
593
582
|
|
|
594
583
|
let bottomLeft = new Point(xmin, ymin);
|
|
595
584
|
let bottomRight = new Point(xmax, ymin);
|
|
596
585
|
let topLeft = new Point(xmin, ymax);
|
|
597
586
|
let topRight = new Point(xmax, ymax);
|
|
598
587
|
|
|
599
|
-
if (this.
|
|
600
|
-
const angle = Utils.degrees2radians(this.
|
|
588
|
+
if (this.getRotation() !== 0) {
|
|
589
|
+
const angle = Utils.degrees2radians(this.getRotation());
|
|
601
590
|
bottomLeft = bottomLeft.rotate(this.points[0], angle);
|
|
602
591
|
bottomRight = bottomRight.rotate(this.points[0], angle);
|
|
603
592
|
topLeft = topLeft.rotate(this.points[0], angle);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { DesignCore } from '../../designCore.js';
|
|
2
|
+
|
|
3
|
+
/** RubberBand Class - rubber-band indicator line drawn between two or more points */
|
|
4
|
+
export class RubberBand {
|
|
5
|
+
/**
|
|
6
|
+
* Create a RubberBand
|
|
7
|
+
* @param {Point[]} points - two or more points defining the polyline
|
|
8
|
+
*/
|
|
9
|
+
constructor(points) {
|
|
10
|
+
this.points = points;
|
|
11
|
+
this.lineWidth = 1.5;
|
|
12
|
+
this.dashPattern = [12, 6];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Draw the rubber-band line
|
|
17
|
+
* @param {Object} renderer
|
|
18
|
+
* @param {number} scale
|
|
19
|
+
*/
|
|
20
|
+
draw(renderer, scale) {
|
|
21
|
+
if (this.points.length < 2) return;
|
|
22
|
+
|
|
23
|
+
const colour = DesignCore.Settings.rubberbandcolour;
|
|
24
|
+
const lineWidth = this.lineWidth / scale;
|
|
25
|
+
const scaledDash = this.dashPattern.map((x) => x / scale);
|
|
26
|
+
|
|
27
|
+
renderer.setColour(colour);
|
|
28
|
+
renderer.setLineWidth(lineWidth);
|
|
29
|
+
renderer.setDash(scaledDash, 0);
|
|
30
|
+
renderer.drawShape(this.points);
|
|
31
|
+
}
|
|
32
|
+
}
|