wt-huatu 1.3.4
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 +223 -0
- package/component/HuatuComponentCache.js +89 -0
- package/component/HuatuComponentDef.js +249 -0
- package/component/HuatuComponentPlacement.js +172 -0
- package/component/HuatuComponentPort.js +58 -0
- package/component/IHuatuComponent.js +2 -0
- package/for-node/node-cli-funcs.js +36 -0
- package/geometry/AngDeg.js +68 -0
- package/geometry/Angle.js +77 -0
- package/geometry/Bezier.js +623 -0
- package/geometry/Circle.js +143 -0
- package/geometry/Ellipse.js +546 -0
- package/geometry/EllipticalArc.js +337 -0
- package/geometry/IGeometry.js +1 -0
- package/geometry/Intersection.js +601 -0
- package/geometry/Line.js +136 -0
- package/geometry/LineSeg.js +179 -0
- package/geometry/Point.js +88 -0
- package/geometry/PolyLine.js +97 -0
- package/geometry/Polygon.js +122 -0
- package/geometry/Rect.js +149 -0
- package/geometry/Ring.js +91 -0
- package/geometry/SegmentModel.js +206 -0
- package/geometry/Triangle.js +168 -0
- package/geometry/Vector.js +92 -0
- package/huatu/Huatu.js +4279 -0
- package/huatu/HuatuAngleMark.js +400 -0
- package/huatu/HuatuBlock.js +26 -0
- package/huatu/HuatuClipPath.js +29 -0
- package/huatu/HuatuCompDrawing.js +77 -0
- package/huatu/HuatuDimMark.js +579 -0
- package/huatu/HuatuDrawing.js +185 -0
- package/huatu/HuatuDrawingGroup.js +52 -0
- package/huatu/HuatuJob.js +347 -0
- package/huatu/HuatuLabel.js +311 -0
- package/huatu/HuatuLabelStyle.js +190 -0
- package/huatu/HuatuLayer.js +10 -0
- package/huatu/HuatuMarker.js +209 -0
- package/huatu/HuatuParser.js +435 -0
- package/huatu/HuatuPath.js +131 -0
- package/huatu/HuatuPathSeries.js +51 -0
- package/huatu/HuatuPattern.js +54 -0
- package/huatu/HuatuPoint.js +20 -0
- package/huatu/HuatuPointSeries.js +67 -0
- package/huatu/HuatuStyle.js +394 -0
- package/huatu/HuatuSymbol.js +81 -0
- package/huatu/HuatuSymbolArray.js +235 -0
- package/huatu/HuatuTransform.js +113 -0
- package/huatu/HuatuVar.js +17 -0
- package/huatu/HuatuYml.js +271 -0
- package/huatu/IHuatu.js +2 -0
- package/huatu/IHuatuYml.js +1 -0
- package/huatu/IndentParsingStack.js +82 -0
- package/index.d.ts +1747 -0
- package/index.js +247 -0
- package/math/Complex.js +72 -0
- package/math/Matrix.js +31 -0
- package/math/NumberRange.js +38 -0
- package/math/VarFuncs.js +24 -0
- package/math/WtMath.js +217 -0
- package/package.json +34 -0
- package/path/PathBezier2.js +75 -0
- package/path/PathBezier3.js +89 -0
- package/path/PathCircle.js +82 -0
- package/path/PathConfig.js +81 -0
- package/path/PathContinuousSegmentedPath.js +390 -0
- package/path/PathEllipse.js +99 -0
- package/path/PathEllipticalArc.js +111 -0
- package/path/PathGeneric.js +59 -0
- package/path/PathLine.js +75 -0
- package/path/PathLines.js +46 -0
- package/path/PathPolygon.js +142 -0
- package/path/PathPolyline.js +266 -0
- package/path/PathRect.js +125 -0
- package/path/PathRing.js +51 -0
- package/path/PathSegmentedPath.js +199 -0
- package/path/PathTriangle.js +90 -0
- package/presets/marker.js +37 -0
- package/presets/pattern.js +85 -0
- package/shape/SvgShapeArrowHead.js +92 -0
- package/shape/SvgShapeCircle.js +26 -0
- package/shape/SvgShapeCross.js +43 -0
- package/shape/SvgShapeEllipse.js +28 -0
- package/shape/SvgShapeGeneric.js +50 -0
- package/shape/SvgShapeHeart.js +40 -0
- package/shape/SvgShapeIsoscelesTriangle.js +52 -0
- package/shape/SvgShapePolygon.js +39 -0
- package/shape/SvgShapeRect.js +26 -0
- package/shape/SvgShapeRhombus.js +27 -0
- package/shape/SvgShapeStar.js +103 -0
- package/svg/ISvg.js +1 -0
- package/svg/SvgBBox.js +149 -0
- package/svg/SvgConstants.js +14 -0
- package/svg/SvgGradient.js +97 -0
- package/svg/SvgMarker.js +221 -0
- package/svg/SvgPattern.js +228 -0
- package/svg/SvgPoint.js +33 -0
- package/svg/SvgPointSet.js +41 -0
- package/templates/lines.js +35 -0
- package/tools/gen-id.js +2 -0
- package/tools/html.js +2 -0
- package/tools/katex.js +75 -0
- package/tools/rand-str.js +122 -0
- package/tools/regex.js +15 -0
- package/tools/utils.js +438 -0
- package/tools/webColor.js +700 -0
- package/wire/HuatuNet.js +22 -0
- package/wire/HuatuWire.js +415 -0
- package/wire/HuatuWireDrawing.js +17 -0
- package/wire/IHuatuWire.js +1 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { SvgMarker } from "../svg/SvgMarker.js";
|
|
2
|
+
import { SvgShapeArrowHeadSimpleAngle, SvgShapeArrowHeadSolidTriangle, SvgShapeArrowHeadSolidTwoTriangle } from "../shape/SvgShapeArrowHead.js";
|
|
3
|
+
import { fitNumInRange } from "../tools/utils.js";
|
|
4
|
+
import { WtMath } from "../math/WtMath.js";
|
|
5
|
+
import { SvgShapeCircle } from "../shape/SvgShapeCircle.js";
|
|
6
|
+
import { SvgShapeEllipse } from "../shape/SvgShapeEllipse.js";
|
|
7
|
+
import { SvgShapeRect } from "../shape/SvgShapeRect.js";
|
|
8
|
+
import { SvgShapeCross, SvgShapePlus } from "../shape/SvgShapeCross.js";
|
|
9
|
+
import { SvgShapeRhombus } from "../shape/SvgShapeRhombus.js";
|
|
10
|
+
import { SvgShapeIsoscelesTriangle } from "../shape/SvgShapeIsoscelesTriangle.js";
|
|
11
|
+
import { SvgShapeStar5, SvgShapeStarUnified } from "../shape/SvgShapeStar.js";
|
|
12
|
+
import { SvgShapePolygon } from "../shape/SvgShapePolygon.js";
|
|
13
|
+
import { genHex } from "../tools/gen-id.js";
|
|
14
|
+
export class HuatuMarker {
|
|
15
|
+
// The possible marker types that user could use when designing the marker
|
|
16
|
+
static TYPES = {
|
|
17
|
+
arrowSolid: ["arrow-solid", "arrowsolid", "solidarrow", "arrow"],
|
|
18
|
+
arrowDouble: ["arrow-double", "arrowdouble", "doublearrow"],
|
|
19
|
+
arrowSimple: ["arrow-simple", "arrowsimple", "simple-arrow", "simplearrow"],
|
|
20
|
+
circle: ["circle", "circ", "dot"],
|
|
21
|
+
triangle: ["triangle", "tri"],
|
|
22
|
+
ellipse: ["ellipse", "ell"],
|
|
23
|
+
rhombus: ["rhombus", "rhom"],
|
|
24
|
+
square: ["square", "sqr"],
|
|
25
|
+
rectangle: ["rectangle", "rect"],
|
|
26
|
+
star5: ["star", "star5", "5-star", "5star", "wujiaoxing"],
|
|
27
|
+
starU: ["staru", "star-u", "star-unified", "unifiedstar", "unified-star"],
|
|
28
|
+
plus: ["plus", "jiahao"],
|
|
29
|
+
cross: ["cross", "chacha", "cha"],
|
|
30
|
+
polygon: ["polygon", "plg", "duobianxing", "dbx"]
|
|
31
|
+
};
|
|
32
|
+
name;
|
|
33
|
+
marker;
|
|
34
|
+
primaryColor;
|
|
35
|
+
secondaryColor;
|
|
36
|
+
refCount = 0;
|
|
37
|
+
alwaysInDef = true;
|
|
38
|
+
magicId;
|
|
39
|
+
constructor(name, marker) {
|
|
40
|
+
this.name = name;
|
|
41
|
+
this.marker = marker;
|
|
42
|
+
this.magicId = genHex(8);
|
|
43
|
+
}
|
|
44
|
+
buildHtmlForDef() {
|
|
45
|
+
return this.marker.buildMarkerSvg(this.buildId(), this.primaryColor, this.secondaryColor);
|
|
46
|
+
}
|
|
47
|
+
buildId() {
|
|
48
|
+
return `mkr-${this.magicId}`;
|
|
49
|
+
}
|
|
50
|
+
static getAllMarkerTypeWords() {
|
|
51
|
+
const res = [];
|
|
52
|
+
for (const key in HuatuMarker.TYPES) {
|
|
53
|
+
res.push(...HuatuMarker.TYPES[key]);
|
|
54
|
+
}
|
|
55
|
+
return res;
|
|
56
|
+
}
|
|
57
|
+
static buildMarkerFromParams(name, params) {
|
|
58
|
+
if (!params.type)
|
|
59
|
+
return `Marker Type not specified!`;
|
|
60
|
+
const type = params.type.toLowerCase();
|
|
61
|
+
let shape;
|
|
62
|
+
let orient = 0;
|
|
63
|
+
let refX = 0, refY = 0;
|
|
64
|
+
let hasStroke = false, hasFill = false;
|
|
65
|
+
let fill = {};
|
|
66
|
+
let stroke = {};
|
|
67
|
+
let openDeg = params.degOpen ?? 46;
|
|
68
|
+
let len = params.len ? params.len
|
|
69
|
+
: params.size ? params.size
|
|
70
|
+
: params.width ? params.width
|
|
71
|
+
: 5;
|
|
72
|
+
let radius = params.r ? params.r
|
|
73
|
+
: params.size ? params.size / 2
|
|
74
|
+
: params.width ? params.width / 2
|
|
75
|
+
: params.height ? params.height / 2
|
|
76
|
+
: 6;
|
|
77
|
+
let w = params.width ? params.width
|
|
78
|
+
: params.size ? params.size
|
|
79
|
+
: params.len ? params.len
|
|
80
|
+
: 6;
|
|
81
|
+
let h = params.height ? params.height
|
|
82
|
+
: params.size ? params.size
|
|
83
|
+
: params.len ? params.len
|
|
84
|
+
: 6;
|
|
85
|
+
let rx = params.rx ? params.rx
|
|
86
|
+
: params.r ? params.r
|
|
87
|
+
: params.width ? params.width / 2
|
|
88
|
+
: params.height ? params.height / 2
|
|
89
|
+
: 6;
|
|
90
|
+
let ry = params.ry ? params.ry
|
|
91
|
+
: params.r ? params.r
|
|
92
|
+
: params.height ? params.height / 2
|
|
93
|
+
: params.width ? params.width / 2
|
|
94
|
+
: 6;
|
|
95
|
+
let size = params.size ? params.size
|
|
96
|
+
: params.width ? params.width
|
|
97
|
+
: params.height ? params.height
|
|
98
|
+
: 6;
|
|
99
|
+
if (HuatuMarker.TYPES.arrowSolid.includes(type)) {
|
|
100
|
+
orient = "auto-start-reverse";
|
|
101
|
+
shape = new SvgShapeArrowHeadSolidTriangle(fitNumInRange(len, 1, 200), fitNumInRange(openDeg, 10, 160), params.makeSmooth ? 0.1 : undefined);
|
|
102
|
+
refX = -0.5 / Math.tan(shape.angHalf);
|
|
103
|
+
hasFill = true;
|
|
104
|
+
}
|
|
105
|
+
else if (HuatuMarker.TYPES.arrowDouble.includes(type)) {
|
|
106
|
+
orient = "auto-start-reverse";
|
|
107
|
+
let len2Ratio;
|
|
108
|
+
if (params.k && WtMath.isIn0and1(params.k))
|
|
109
|
+
len2Ratio = fitNumInRange(params.k, 0, 1);
|
|
110
|
+
shape = new SvgShapeArrowHeadSolidTwoTriangle(fitNumInRange(len, 1, 200), fitNumInRange(openDeg, 10, 160), len2Ratio, params.makeSmooth ? 0.1 : undefined);
|
|
111
|
+
refX = -0.5 / Math.tan(shape.angHalf);
|
|
112
|
+
hasFill = true;
|
|
113
|
+
}
|
|
114
|
+
else if (HuatuMarker.TYPES.arrowSimple.includes(type)) {
|
|
115
|
+
orient = "auto-start-reverse";
|
|
116
|
+
shape = new SvgShapeArrowHeadSimpleAngle(fitNumInRange(len, 1, 200), fitNumInRange(openDeg, 10, 160), params.closeArrow, params.makeSmooth);
|
|
117
|
+
refX = -0.5 / Math.tan(shape.angHalf) + 0.5 / Math.sin(shape.angHalf);
|
|
118
|
+
hasStroke = true;
|
|
119
|
+
}
|
|
120
|
+
else if (HuatuMarker.TYPES.circle.includes(type)) {
|
|
121
|
+
shape = new SvgShapeCircle(fitNumInRange(radius, 0.2, 100));
|
|
122
|
+
hasStroke = true;
|
|
123
|
+
hasFill = true;
|
|
124
|
+
}
|
|
125
|
+
else if (HuatuMarker.TYPES.triangle.includes(type)) {
|
|
126
|
+
const dir = params.direction && ["up", "down", "left", "right"].includes(params.direction) ? params.direction : "up";
|
|
127
|
+
shape = new SvgShapeIsoscelesTriangle(fitNumInRange(w, 2, 100), fitNumInRange(h, 2, 100), dir);
|
|
128
|
+
hasFill = true;
|
|
129
|
+
hasStroke = true;
|
|
130
|
+
}
|
|
131
|
+
else if (HuatuMarker.TYPES.ellipse.includes(type)) {
|
|
132
|
+
orient = "auto";
|
|
133
|
+
shape = new SvgShapeEllipse(fitNumInRange(rx, 0.2, 100), fitNumInRange(ry, 0.2, 100));
|
|
134
|
+
hasFill = true;
|
|
135
|
+
hasStroke = true;
|
|
136
|
+
}
|
|
137
|
+
else if (HuatuMarker.TYPES.rhombus.includes(type)) {
|
|
138
|
+
shape = new SvgShapeRhombus(fitNumInRange(w, 0.2, 100), fitNumInRange(h, 0.2, 100));
|
|
139
|
+
hasFill = true;
|
|
140
|
+
hasStroke = true;
|
|
141
|
+
}
|
|
142
|
+
else if (HuatuMarker.TYPES.square.includes(type)) {
|
|
143
|
+
w = fitNumInRange(w, 0.2, 100);
|
|
144
|
+
shape = new SvgShapeRect(w, w);
|
|
145
|
+
hasFill = true;
|
|
146
|
+
hasStroke = true;
|
|
147
|
+
}
|
|
148
|
+
else if (HuatuMarker.TYPES.rectangle.includes(type)) {
|
|
149
|
+
shape = new SvgShapeRect(fitNumInRange(w, 0.2, 100), fitNumInRange(h, 0.2, 100));
|
|
150
|
+
hasFill = true;
|
|
151
|
+
hasStroke = true;
|
|
152
|
+
}
|
|
153
|
+
else if (HuatuMarker.TYPES.star5.includes(type)) {
|
|
154
|
+
shape = new SvgShapeStar5(fitNumInRange(size, 0.4, 100) / 2, params.centerEmpty);
|
|
155
|
+
hasFill = true;
|
|
156
|
+
hasStroke = true;
|
|
157
|
+
}
|
|
158
|
+
else if (HuatuMarker.TYPES.starU.includes(type)) {
|
|
159
|
+
if (!params.n)
|
|
160
|
+
return `Star angle count N must be presented!`;
|
|
161
|
+
let rIn = params.rIn ? params.rIn : params.r ? params.r : 10;
|
|
162
|
+
let rOut = params.rOut ? params.rOut : rIn * 1.2;
|
|
163
|
+
if (rOut < rIn) {
|
|
164
|
+
let x = rIn;
|
|
165
|
+
rIn = rOut;
|
|
166
|
+
rOut = x;
|
|
167
|
+
}
|
|
168
|
+
else if (rOut === rIn) {
|
|
169
|
+
rOut = rIn * 1.2;
|
|
170
|
+
}
|
|
171
|
+
let degOffset = params.degOffset ?? 0;
|
|
172
|
+
let rCorner = params.rx ? params.rx : params.ry ? params.ry : undefined;
|
|
173
|
+
shape = new SvgShapeStarUnified(fitNumInRange(params.n, 3, 30), rIn, rOut, degOffset, rCorner);
|
|
174
|
+
hasFill = true;
|
|
175
|
+
hasStroke = true;
|
|
176
|
+
}
|
|
177
|
+
else if (HuatuMarker.TYPES.plus.includes(type)) {
|
|
178
|
+
shape = new SvgShapePlus(fitNumInRange(w, 0.2, 100));
|
|
179
|
+
hasStroke = true;
|
|
180
|
+
}
|
|
181
|
+
else if (HuatuMarker.TYPES.cross.includes(type)) {
|
|
182
|
+
shape = new SvgShapeCross(fitNumInRange(w, 0.2, 100));
|
|
183
|
+
hasStroke = true;
|
|
184
|
+
}
|
|
185
|
+
else if (HuatuMarker.TYPES.polygon.includes(type)) {
|
|
186
|
+
if (!params.n)
|
|
187
|
+
return `Polygon side count N must be presented!`;
|
|
188
|
+
shape = new SvgShapePolygon(size, fitNumInRange(params.n, 3, 30));
|
|
189
|
+
hasFill = true;
|
|
190
|
+
hasStroke = true;
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
return `Marker type '${type}' is not defined!`;
|
|
194
|
+
}
|
|
195
|
+
if (hasStroke) {
|
|
196
|
+
if (params.strokeColor)
|
|
197
|
+
stroke.color = params.strokeColor;
|
|
198
|
+
if (params.strokeWidth)
|
|
199
|
+
stroke.width = params.strokeWidth;
|
|
200
|
+
}
|
|
201
|
+
if (hasFill) {
|
|
202
|
+
if (params.fillColor)
|
|
203
|
+
fill.color = params.fillColor;
|
|
204
|
+
if (params.fillOpacity)
|
|
205
|
+
fill.opacity = params.fillOpacity;
|
|
206
|
+
}
|
|
207
|
+
return new SvgMarker(`mkr-${name}`, shape, orient, refX, refY, stroke, fill);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
import { WT_REGEX } from "../tools/regex.js";
|
|
2
|
+
import { WtHuatu } from "./Huatu.js";
|
|
3
|
+
import { resolvePointLike } from "../tools/utils.js";
|
|
4
|
+
import { HuatuYml } from "./HuatuYml.js";
|
|
5
|
+
import { HuatuComponentCache } from "../component/HuatuComponentCache.js";
|
|
6
|
+
export function resolveHuatuSize(size) {
|
|
7
|
+
const wh = resolvePointLike(size);
|
|
8
|
+
if (wh &&
|
|
9
|
+
WT_REGEX.FLOAT_NUMBER.test(wh.x) &&
|
|
10
|
+
WT_REGEX.FLOAT_NUMBER.test(wh.y)) {
|
|
11
|
+
return {
|
|
12
|
+
width: parseFloat(wh.x),
|
|
13
|
+
height: parseFloat(wh.y)
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
export const FORBIDDEN_NAMES = [
|
|
19
|
+
"config",
|
|
20
|
+
"size", "title", "desc",
|
|
21
|
+
"viewbox", "viewarea", "viewbetween",
|
|
22
|
+
"vars",
|
|
23
|
+
"points", "shapes", "cpoints", "xpoints", "pointseries", "shapeseries",
|
|
24
|
+
"points2", "shapes2", "cpoints2", "xpoints2", "pointseries2", "shapeseries2",
|
|
25
|
+
"points3", "shapes3", "cpoints3", "xpoints3", "pointseries3", "shapeseries3",
|
|
26
|
+
"points4", "shapes4", "cpoints4", "xpoints4", "pointseries4", "shapeseries4",
|
|
27
|
+
"components", "placements",
|
|
28
|
+
"paths", "markers", "patterns", "clips",
|
|
29
|
+
"styles", "labelstyles",
|
|
30
|
+
"symbols", "blocks", "arrays", "layers",
|
|
31
|
+
"draw", "jobs",
|
|
32
|
+
"inputvars", "ports",
|
|
33
|
+
];
|
|
34
|
+
export function resolveYmlModelSync(ymlObj) {
|
|
35
|
+
const huatu = new WtHuatu();
|
|
36
|
+
if (!ymlObj)
|
|
37
|
+
return huatu;
|
|
38
|
+
// Copy the original object
|
|
39
|
+
const yml = HuatuYml.copyObj(ymlObj);
|
|
40
|
+
// Resolve meta data
|
|
41
|
+
if (yml.title)
|
|
42
|
+
huatu.title = yml.title;
|
|
43
|
+
if (yml.desc)
|
|
44
|
+
huatu.desc = yml.desc;
|
|
45
|
+
if (yml.size) {
|
|
46
|
+
const size = resolveHuatuSize(yml.size);
|
|
47
|
+
if (size) {
|
|
48
|
+
if (size.width > 0)
|
|
49
|
+
huatu.width = size.width;
|
|
50
|
+
if (size.height > 0)
|
|
51
|
+
huatu.height = size.height;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
huatu.resolvingErrors.push({
|
|
55
|
+
title: `Size input of [${yml.size}] cannot be resolved!`
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Resolve Global Config
|
|
60
|
+
if (yml.config) {
|
|
61
|
+
const cfg = WtHuatu.resolveConfig(yml.config);
|
|
62
|
+
// Inject the configuration into Global This
|
|
63
|
+
if (Object.keys(cfg).length > 0) {
|
|
64
|
+
huatu.config = cfg;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
// The unified named fields resolving function
|
|
68
|
+
const resolveNamedFields = (field, moduleName, resolveCall, acceptedTypes, ignoreNames) => {
|
|
69
|
+
const fieldVal = yml[field];
|
|
70
|
+
if (typeof fieldVal === "string") {
|
|
71
|
+
huatu.resolvingErrors.push({
|
|
72
|
+
title: `${moduleName} definition "${field}" is incorrect, please check!`,
|
|
73
|
+
});
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
if (fieldVal) {
|
|
77
|
+
for (const name in fieldVal) {
|
|
78
|
+
// Check Name
|
|
79
|
+
if (!WT_REGEX.VAR_NAME.test(name)) {
|
|
80
|
+
huatu.resolvingErrors.push({
|
|
81
|
+
title: `${moduleName} name '${name}' has incorrect format, please use only alphanumeric and underscore(_)!`
|
|
82
|
+
});
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const lcName = name.toLowerCase();
|
|
86
|
+
if (FORBIDDEN_NAMES.includes(lcName) && (!ignoreNames || !ignoreNames.includes(lcName))) {
|
|
87
|
+
huatu.resolvingErrors.push({
|
|
88
|
+
title: `${moduleName} name '${name}' is forbidden, please pick another one!`
|
|
89
|
+
});
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
// Check if definition empty
|
|
93
|
+
let isEmpty = false;
|
|
94
|
+
let notAccepted = false;
|
|
95
|
+
let val = fieldVal[name];
|
|
96
|
+
let valType = "string";
|
|
97
|
+
if (!val) {
|
|
98
|
+
isEmpty = true;
|
|
99
|
+
}
|
|
100
|
+
else if (typeof val === "string") {
|
|
101
|
+
valType = "string";
|
|
102
|
+
// Trim spaces
|
|
103
|
+
val = val.trim();
|
|
104
|
+
if (!val)
|
|
105
|
+
isEmpty = true;
|
|
106
|
+
else if (acceptedTypes && !acceptedTypes.includes("string"))
|
|
107
|
+
notAccepted = true;
|
|
108
|
+
}
|
|
109
|
+
else if (Array.isArray(val)) {
|
|
110
|
+
valType = "list";
|
|
111
|
+
// Make sure list items are strings
|
|
112
|
+
val = val.filter((x, idx) => {
|
|
113
|
+
if (typeof x !== "string") {
|
|
114
|
+
huatu.resolvingErrors.push({ title: `${moduleName} '${name}' has some invalid definition in the list (${idx + 1}-th item), please check!` });
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
return x.trim();
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
if (val.length < 1)
|
|
122
|
+
isEmpty = true;
|
|
123
|
+
else if (acceptedTypes && !acceptedTypes.includes("list"))
|
|
124
|
+
notAccepted = true;
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
valType = "object";
|
|
128
|
+
if (Object.keys(val).length < 1) {
|
|
129
|
+
isEmpty = true;
|
|
130
|
+
}
|
|
131
|
+
else if (acceptedTypes && !acceptedTypes.includes("object"))
|
|
132
|
+
notAccepted = true;
|
|
133
|
+
}
|
|
134
|
+
if (isEmpty) {
|
|
135
|
+
huatu.resolvingErrors.push({
|
|
136
|
+
title: `${moduleName} '${name}' has no definition (it is empty)!`
|
|
137
|
+
});
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (notAccepted) {
|
|
141
|
+
huatu.resolvingErrors.push({
|
|
142
|
+
title: `${moduleName} [${name}] cannot be defined as "${valType}"!`,
|
|
143
|
+
});
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
// Call the function and evaluate results
|
|
147
|
+
const errMsg = resolveCall.call(huatu, name, val);
|
|
148
|
+
if (errMsg.length > 1) {
|
|
149
|
+
huatu.resolvingErrors.push({
|
|
150
|
+
title: `${moduleName} [${name}] resolving failed`,
|
|
151
|
+
msgs: [...errMsg]
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
else if (errMsg.length === 1) {
|
|
155
|
+
huatu.resolvingErrors.push({
|
|
156
|
+
title: `${moduleName} [${name}] resolving failed: ${errMsg[0]}`,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
// Resolve Var, this is the first step;
|
|
163
|
+
resolveNamedFields("vars", "Var", huatu.resolveVar, ["string"]);
|
|
164
|
+
/** The first round to resolve points, shapes, cpoints, xpoints and series */
|
|
165
|
+
resolveNamedFields("points", "Point", huatu.resolvePoint, ["string"]);
|
|
166
|
+
resolveNamedFields("shapes", "Shape", huatu.resolveShape, ["string"]);
|
|
167
|
+
resolveNamedFields("cpoints", "Calculated Point", huatu.resolveCPoint, ["string"]);
|
|
168
|
+
resolveNamedFields("xpoints", "Intersection Point", huatu.resolveXPoint, ["string"]);
|
|
169
|
+
resolveNamedFields("pointSeries", "Point Series", huatu.resolvePointSeries, ["string"]);
|
|
170
|
+
resolveNamedFields("shapeSeries", "Shape Series", huatu.resolveShapeSeries, ["string"]);
|
|
171
|
+
/**
|
|
172
|
+
* Here add extra 3 round of resolving Shapes/CPoints/Xpoints, This is to make it possible
|
|
173
|
+
* that new shapes created based on the points calculated by intersection or from model.
|
|
174
|
+
*/
|
|
175
|
+
// Resolve Shapes, the second Round
|
|
176
|
+
resolveNamedFields("points2", "Point", huatu.resolvePoint, ["string"]);
|
|
177
|
+
resolveNamedFields("shapes2", "Shape", huatu.resolveShape, ["string"]);
|
|
178
|
+
resolveNamedFields("cpoints2", "Calculated Point", huatu.resolveCPoint, ["string"]);
|
|
179
|
+
resolveNamedFields("xpoints2", "Intersection Point", huatu.resolveXPoint, ["string"]);
|
|
180
|
+
resolveNamedFields("pointSeries2", "Point Series", huatu.resolvePointSeries, ["string"]);
|
|
181
|
+
resolveNamedFields("shapeSeries2", "Shape Series", huatu.resolveShapeSeries, ["string"]);
|
|
182
|
+
// Resolve Shapes, the third Round
|
|
183
|
+
resolveNamedFields("points3", "Point", huatu.resolvePoint, ["string"]);
|
|
184
|
+
resolveNamedFields("shapes3", "Shape", huatu.resolveShape, ["string"]);
|
|
185
|
+
resolveNamedFields("cpoints3", "Calculated Point", huatu.resolveCPoint, ["string"]);
|
|
186
|
+
resolveNamedFields("xpoints3", "Intersection Point", huatu.resolveXPoint, ["string"]);
|
|
187
|
+
resolveNamedFields("pointSeries3", "Point Series", huatu.resolvePointSeries, ["string"]);
|
|
188
|
+
resolveNamedFields("shapeSeries3", "Shape Series", huatu.resolveShapeSeries, ["string"]);
|
|
189
|
+
// Resolve Shapes, the fourth Round
|
|
190
|
+
resolveNamedFields("points4", "Point", huatu.resolvePoint, ["string"]);
|
|
191
|
+
resolveNamedFields("shapes4", "Shape", huatu.resolveShape, ["string"]);
|
|
192
|
+
resolveNamedFields("cpoints4", "Calculated Point", huatu.resolveCPoint, ["string"]);
|
|
193
|
+
resolveNamedFields("xpoints4", "Intersection Point", huatu.resolveXPoint, ["string"]);
|
|
194
|
+
resolveNamedFields("pointSeries4", "Point Series", huatu.resolvePointSeries, ["string"]);
|
|
195
|
+
resolveNamedFields("shapeSeries4", "Shape Series", huatu.resolveShapeSeries, ["string"]);
|
|
196
|
+
/** ========= Repeating Rounds ended ========= */
|
|
197
|
+
// Resolve Components
|
|
198
|
+
resolveNamedFields("components", "Component Definitions", huatu.resolveComponentDef, ["string", "object"]);
|
|
199
|
+
// Resolve Component Placement
|
|
200
|
+
resolveNamedFields("placements", "Component Placements", huatu.resolveComponentPlacement, ["string", "object"]);
|
|
201
|
+
// Resolve paths
|
|
202
|
+
resolveNamedFields("paths", "Path", huatu.resolvePath, ["string", 'list']);
|
|
203
|
+
// Resolve marker
|
|
204
|
+
resolveNamedFields("markers", "Marker", huatu.resolveMarker, ["string", "object"]);
|
|
205
|
+
// Resolve Pattern
|
|
206
|
+
resolveNamedFields("patterns", "Pattern", huatu.resolvePattern, ["string", "object"]);
|
|
207
|
+
// Resolve Clips
|
|
208
|
+
resolveNamedFields("clips", "Clip-Path", huatu.resolveClip, ["string", "list"]);
|
|
209
|
+
// Resolve styles
|
|
210
|
+
resolveNamedFields("styles", "Style", huatu.resolveStyle, ["string", "object"]);
|
|
211
|
+
// Resolve Label Styles
|
|
212
|
+
resolveNamedFields("labelStyles", "Label Style", huatu.resolveLabelStyle, ["string", "object"]);
|
|
213
|
+
// Resolve symbols
|
|
214
|
+
resolveNamedFields("symbols", "Symbol", huatu.resolveSymbol, ["string", "list"]);
|
|
215
|
+
// Resolve blocks
|
|
216
|
+
resolveNamedFields("blocks", "Block", huatu.resolveBlock, ["string", "list"]);
|
|
217
|
+
// Resolve arrays
|
|
218
|
+
resolveNamedFields("arrays", "Array", huatu.resolveArray, ["string", "object"]);
|
|
219
|
+
// Resolve Layers
|
|
220
|
+
resolveNamedFields("layers", "Layer", huatu.resolveLayer, ["string", "list"]);
|
|
221
|
+
// Resolve ViewBox
|
|
222
|
+
let vbDef = yml.viewBox || yml.viewArea || yml.viewBetween;
|
|
223
|
+
if (vbDef) {
|
|
224
|
+
let vb = huatu.resolveViewBoxFromDef(vbDef);
|
|
225
|
+
if (typeof vb === "string")
|
|
226
|
+
huatu.resolvingErrors.push({
|
|
227
|
+
title: `ViewBox Resolving Failed: ${vb}`
|
|
228
|
+
});
|
|
229
|
+
else if (vb)
|
|
230
|
+
huatu.viewBox = vb;
|
|
231
|
+
else {
|
|
232
|
+
huatu.warnings.push(`'${vbDef}' cannot resolve to a valid View Box!`);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Resolve Jobs, Including the global draw
|
|
236
|
+
if (yml.jobs && yml.jobs["draw"]) {
|
|
237
|
+
huatu.resolvingErrors.push({
|
|
238
|
+
title: `You cannot define a job named as 'draw', please place the 'draw' job at root!`
|
|
239
|
+
});
|
|
240
|
+
delete yml.jobs["draw"]; // Delete it
|
|
241
|
+
}
|
|
242
|
+
if (yml.draw) {
|
|
243
|
+
if (yml.jobs)
|
|
244
|
+
yml.jobs["draw"] = yml.draw;
|
|
245
|
+
else
|
|
246
|
+
yml.jobs = { draw: yml.draw };
|
|
247
|
+
}
|
|
248
|
+
resolveNamedFields("jobs", "Job", huatu.resolveJob, ["string", "list", "object"], ["draw"]);
|
|
249
|
+
huatu.draw = huatu.jobs.find(j => j.name === "draw");
|
|
250
|
+
// Return after resolving
|
|
251
|
+
return huatu;
|
|
252
|
+
}
|
|
253
|
+
export async function resolveYmlModel(ymlObj) {
|
|
254
|
+
if (!ymlObj)
|
|
255
|
+
return new WtHuatu();
|
|
256
|
+
// Prepare Components if any
|
|
257
|
+
await HuatuComponentCache.prepareComponents(ymlObj);
|
|
258
|
+
return resolveYmlModelSync(ymlObj);
|
|
259
|
+
}
|
|
260
|
+
export function resolveYmlModelOfComponent(ymlObj) {
|
|
261
|
+
const comp = new WtHuatu();
|
|
262
|
+
if (!ymlObj)
|
|
263
|
+
return comp;
|
|
264
|
+
// Copy the original object
|
|
265
|
+
const yml = HuatuYml.copyObj(ymlObj);
|
|
266
|
+
// Resolve meta data
|
|
267
|
+
if (yml.title)
|
|
268
|
+
comp.title = yml.title;
|
|
269
|
+
if (yml.desc)
|
|
270
|
+
comp.desc = yml.desc;
|
|
271
|
+
// The unified named fields resolving function
|
|
272
|
+
const resolveNamedFields = (field, moduleName, resolveCall, acceptedTypes, ignoreNames) => {
|
|
273
|
+
const fieldVal = yml[field];
|
|
274
|
+
if (typeof fieldVal === "string") {
|
|
275
|
+
comp.resolvingErrors.push({
|
|
276
|
+
title: `${moduleName} definition "${field}" is incorrect, please check!`,
|
|
277
|
+
});
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (fieldVal) {
|
|
281
|
+
for (const name in fieldVal) {
|
|
282
|
+
// Check Name
|
|
283
|
+
if (!WT_REGEX.VAR_NAME.test(name)) {
|
|
284
|
+
comp.resolvingErrors.push({
|
|
285
|
+
title: `${moduleName} name '${name}' has incorrect format, please use only alphanumeric and underscore(_)!`
|
|
286
|
+
});
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
const lcName = name.toLowerCase();
|
|
290
|
+
if (FORBIDDEN_NAMES.includes(lcName) && (!ignoreNames || !ignoreNames.includes(lcName))) {
|
|
291
|
+
comp.resolvingErrors.push({
|
|
292
|
+
title: `${moduleName} name '${name}' is forbidden, please pick another one!`
|
|
293
|
+
});
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
// Check if definition empty
|
|
297
|
+
let isEmpty = false;
|
|
298
|
+
let notAccepted = false;
|
|
299
|
+
let val = fieldVal[name];
|
|
300
|
+
let valType = "string";
|
|
301
|
+
if (!val) {
|
|
302
|
+
isEmpty = true;
|
|
303
|
+
}
|
|
304
|
+
else if (typeof val === "string") {
|
|
305
|
+
valType = "string";
|
|
306
|
+
// Trim spaces
|
|
307
|
+
val = val.trim();
|
|
308
|
+
if (!val)
|
|
309
|
+
isEmpty = true;
|
|
310
|
+
else if (acceptedTypes && !acceptedTypes.includes("string"))
|
|
311
|
+
notAccepted = true;
|
|
312
|
+
}
|
|
313
|
+
else if (Array.isArray(val)) {
|
|
314
|
+
valType = "list";
|
|
315
|
+
// Make sure list items are strings
|
|
316
|
+
val = val.filter((x, idx) => {
|
|
317
|
+
if (typeof x !== "string") {
|
|
318
|
+
comp.resolvingErrors.push({ title: `${moduleName} '${name}' has some invalid definition in the list (${idx + 1}-th item), please check!` });
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
return x.trim();
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
if (val.length < 1)
|
|
326
|
+
isEmpty = true;
|
|
327
|
+
else if (acceptedTypes && !acceptedTypes.includes("list"))
|
|
328
|
+
notAccepted = true;
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
valType = "object";
|
|
332
|
+
if (Object.keys(val).length < 1) {
|
|
333
|
+
isEmpty = true;
|
|
334
|
+
}
|
|
335
|
+
else if (acceptedTypes && !acceptedTypes.includes("object"))
|
|
336
|
+
notAccepted = true;
|
|
337
|
+
}
|
|
338
|
+
if (isEmpty) {
|
|
339
|
+
comp.resolvingErrors.push({
|
|
340
|
+
title: `${moduleName} '${name}' has no definition (it is empty)!`
|
|
341
|
+
});
|
|
342
|
+
continue;
|
|
343
|
+
}
|
|
344
|
+
if (notAccepted) {
|
|
345
|
+
comp.resolvingErrors.push({
|
|
346
|
+
title: `${moduleName} [${name}] cannot be defined as "${valType}"!`,
|
|
347
|
+
});
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
// Call the function and evaluate results
|
|
351
|
+
const errMsg = resolveCall.call(comp, name, val);
|
|
352
|
+
if (errMsg.length > 1) {
|
|
353
|
+
comp.resolvingErrors.push({
|
|
354
|
+
title: `${moduleName} [${name}] resolving failed`,
|
|
355
|
+
msgs: [...errMsg]
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
else if (errMsg.length === 1) {
|
|
359
|
+
comp.resolvingErrors.push({
|
|
360
|
+
title: `${moduleName} [${name}] resolving failed: ${errMsg[0]}`,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
// Resolve Var, this is the first step;
|
|
367
|
+
resolveNamedFields("vars", "Var", comp.resolveVar, ["string"]);
|
|
368
|
+
/** The first round to resolve points, shapes, cpoints, xpoints and series */
|
|
369
|
+
resolveNamedFields("points", "Point", comp.resolvePoint, ["string"]);
|
|
370
|
+
resolveNamedFields("shapes", "Shape", comp.resolveShape, ["string"]);
|
|
371
|
+
resolveNamedFields("cpoints", "Calculated Point", comp.resolveCPoint, ["string"]);
|
|
372
|
+
resolveNamedFields("xpoints", "Intersection Point", comp.resolveXPoint, ["string"]);
|
|
373
|
+
resolveNamedFields("pointSeries", "Point Series", comp.resolvePointSeries, ["string"]);
|
|
374
|
+
resolveNamedFields("shapeSeries", "Shape Series", comp.resolveShapeSeries, ["string"]);
|
|
375
|
+
/**
|
|
376
|
+
* Here add extra 3 round of resolving Shapes/CPoints/Xpoints, This is to make it possible
|
|
377
|
+
* that new shapes created based on the points calculated by intersection or from model.
|
|
378
|
+
*/
|
|
379
|
+
// Resolve Shapes, the second Round
|
|
380
|
+
resolveNamedFields("points2", "Point", comp.resolvePoint, ["string"]);
|
|
381
|
+
resolveNamedFields("shapes2", "Shape", comp.resolveShape, ["string"]);
|
|
382
|
+
resolveNamedFields("cpoints2", "Calculated Point", comp.resolveCPoint, ["string"]);
|
|
383
|
+
resolveNamedFields("xpoints2", "Intersection Point", comp.resolveXPoint, ["string"]);
|
|
384
|
+
resolveNamedFields("pointSeries2", "Point Series", comp.resolvePointSeries, ["string"]);
|
|
385
|
+
resolveNamedFields("shapeSeries2", "Shape Series", comp.resolveShapeSeries, ["string"]);
|
|
386
|
+
// Resolve Shapes, the third Round
|
|
387
|
+
resolveNamedFields("points3", "Point", comp.resolvePoint, ["string"]);
|
|
388
|
+
resolveNamedFields("shapes3", "Shape", comp.resolveShape, ["string"]);
|
|
389
|
+
resolveNamedFields("cpoints3", "Calculated Point", comp.resolveCPoint, ["string"]);
|
|
390
|
+
resolveNamedFields("xpoints3", "Intersection Point", comp.resolveXPoint, ["string"]);
|
|
391
|
+
resolveNamedFields("pointSeries3", "Point Series", comp.resolvePointSeries, ["string"]);
|
|
392
|
+
resolveNamedFields("shapeSeries3", "Shape Series", comp.resolveShapeSeries, ["string"]);
|
|
393
|
+
// Resolve Shapes, the fourth Round
|
|
394
|
+
resolveNamedFields("points4", "Point", comp.resolvePoint, ["string"]);
|
|
395
|
+
resolveNamedFields("shapes4", "Shape", comp.resolveShape, ["string"]);
|
|
396
|
+
resolveNamedFields("cpoints4", "Calculated Point", comp.resolveCPoint, ["string"]);
|
|
397
|
+
resolveNamedFields("xpoints4", "Intersection Point", comp.resolveXPoint, ["string"]);
|
|
398
|
+
resolveNamedFields("pointSeries4", "Point Series", comp.resolvePointSeries, ["string"]);
|
|
399
|
+
resolveNamedFields("shapeSeries4", "Shape Series", comp.resolveShapeSeries, ["string"]);
|
|
400
|
+
/** ========= Repeating Rounds ended ========= */
|
|
401
|
+
// Resolve paths
|
|
402
|
+
resolveNamedFields("paths", "Path", comp.resolvePath, ["string", 'list']);
|
|
403
|
+
// Resolve marker
|
|
404
|
+
resolveNamedFields("markers", "Marker", comp.resolveMarker, ["string", "object"]);
|
|
405
|
+
// Resolve Pattern
|
|
406
|
+
resolveNamedFields("patterns", "Pattern", comp.resolvePattern, ["string", "object"]);
|
|
407
|
+
// Resolve styles
|
|
408
|
+
resolveNamedFields("styles", "Style", comp.resolveStyle, ["string", "object"]);
|
|
409
|
+
// Resolve Label Styles
|
|
410
|
+
resolveNamedFields("labelStyles", "Label Style", comp.resolveLabelStyle, ["string", "object"]);
|
|
411
|
+
// Resolve ViewBox
|
|
412
|
+
let vbDef = yml.viewBox || yml.viewArea || yml.viewBetween;
|
|
413
|
+
if (vbDef) {
|
|
414
|
+
let vb = comp.resolveViewBoxFromDef(vbDef);
|
|
415
|
+
if (typeof vb === "string")
|
|
416
|
+
comp.resolvingErrors.push({
|
|
417
|
+
title: `ViewBox Resolving Failed: ${vb}`
|
|
418
|
+
});
|
|
419
|
+
else if (vb)
|
|
420
|
+
comp.viewBox = vb;
|
|
421
|
+
else {
|
|
422
|
+
comp.warnings.push(`'${vbDef}' cannot resolve to a valid View Box!`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
if (yml.draw) {
|
|
426
|
+
if (yml.jobs)
|
|
427
|
+
yml.jobs["draw"] = yml.draw;
|
|
428
|
+
else
|
|
429
|
+
yml.jobs = { draw: yml.draw };
|
|
430
|
+
}
|
|
431
|
+
resolveNamedFields("jobs", "Job", comp.resolveJob, ["string", "list", "object"], ["draw"]);
|
|
432
|
+
comp.draw = comp.jobs.find(j => j.name === "draw");
|
|
433
|
+
// Return after resolving
|
|
434
|
+
return comp;
|
|
435
|
+
}
|