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.
Files changed (110) hide show
  1. package/Readme.md +223 -0
  2. package/component/HuatuComponentCache.js +89 -0
  3. package/component/HuatuComponentDef.js +249 -0
  4. package/component/HuatuComponentPlacement.js +172 -0
  5. package/component/HuatuComponentPort.js +58 -0
  6. package/component/IHuatuComponent.js +2 -0
  7. package/for-node/node-cli-funcs.js +36 -0
  8. package/geometry/AngDeg.js +68 -0
  9. package/geometry/Angle.js +77 -0
  10. package/geometry/Bezier.js +623 -0
  11. package/geometry/Circle.js +143 -0
  12. package/geometry/Ellipse.js +546 -0
  13. package/geometry/EllipticalArc.js +337 -0
  14. package/geometry/IGeometry.js +1 -0
  15. package/geometry/Intersection.js +601 -0
  16. package/geometry/Line.js +136 -0
  17. package/geometry/LineSeg.js +179 -0
  18. package/geometry/Point.js +88 -0
  19. package/geometry/PolyLine.js +97 -0
  20. package/geometry/Polygon.js +122 -0
  21. package/geometry/Rect.js +149 -0
  22. package/geometry/Ring.js +91 -0
  23. package/geometry/SegmentModel.js +206 -0
  24. package/geometry/Triangle.js +168 -0
  25. package/geometry/Vector.js +92 -0
  26. package/huatu/Huatu.js +4279 -0
  27. package/huatu/HuatuAngleMark.js +400 -0
  28. package/huatu/HuatuBlock.js +26 -0
  29. package/huatu/HuatuClipPath.js +29 -0
  30. package/huatu/HuatuCompDrawing.js +77 -0
  31. package/huatu/HuatuDimMark.js +579 -0
  32. package/huatu/HuatuDrawing.js +185 -0
  33. package/huatu/HuatuDrawingGroup.js +52 -0
  34. package/huatu/HuatuJob.js +347 -0
  35. package/huatu/HuatuLabel.js +311 -0
  36. package/huatu/HuatuLabelStyle.js +190 -0
  37. package/huatu/HuatuLayer.js +10 -0
  38. package/huatu/HuatuMarker.js +209 -0
  39. package/huatu/HuatuParser.js +435 -0
  40. package/huatu/HuatuPath.js +131 -0
  41. package/huatu/HuatuPathSeries.js +51 -0
  42. package/huatu/HuatuPattern.js +54 -0
  43. package/huatu/HuatuPoint.js +20 -0
  44. package/huatu/HuatuPointSeries.js +67 -0
  45. package/huatu/HuatuStyle.js +394 -0
  46. package/huatu/HuatuSymbol.js +81 -0
  47. package/huatu/HuatuSymbolArray.js +235 -0
  48. package/huatu/HuatuTransform.js +113 -0
  49. package/huatu/HuatuVar.js +17 -0
  50. package/huatu/HuatuYml.js +271 -0
  51. package/huatu/IHuatu.js +2 -0
  52. package/huatu/IHuatuYml.js +1 -0
  53. package/huatu/IndentParsingStack.js +82 -0
  54. package/index.d.ts +1747 -0
  55. package/index.js +247 -0
  56. package/math/Complex.js +72 -0
  57. package/math/Matrix.js +31 -0
  58. package/math/NumberRange.js +38 -0
  59. package/math/VarFuncs.js +24 -0
  60. package/math/WtMath.js +217 -0
  61. package/package.json +34 -0
  62. package/path/PathBezier2.js +75 -0
  63. package/path/PathBezier3.js +89 -0
  64. package/path/PathCircle.js +82 -0
  65. package/path/PathConfig.js +81 -0
  66. package/path/PathContinuousSegmentedPath.js +390 -0
  67. package/path/PathEllipse.js +99 -0
  68. package/path/PathEllipticalArc.js +111 -0
  69. package/path/PathGeneric.js +59 -0
  70. package/path/PathLine.js +75 -0
  71. package/path/PathLines.js +46 -0
  72. package/path/PathPolygon.js +142 -0
  73. package/path/PathPolyline.js +266 -0
  74. package/path/PathRect.js +125 -0
  75. package/path/PathRing.js +51 -0
  76. package/path/PathSegmentedPath.js +199 -0
  77. package/path/PathTriangle.js +90 -0
  78. package/presets/marker.js +37 -0
  79. package/presets/pattern.js +85 -0
  80. package/shape/SvgShapeArrowHead.js +92 -0
  81. package/shape/SvgShapeCircle.js +26 -0
  82. package/shape/SvgShapeCross.js +43 -0
  83. package/shape/SvgShapeEllipse.js +28 -0
  84. package/shape/SvgShapeGeneric.js +50 -0
  85. package/shape/SvgShapeHeart.js +40 -0
  86. package/shape/SvgShapeIsoscelesTriangle.js +52 -0
  87. package/shape/SvgShapePolygon.js +39 -0
  88. package/shape/SvgShapeRect.js +26 -0
  89. package/shape/SvgShapeRhombus.js +27 -0
  90. package/shape/SvgShapeStar.js +103 -0
  91. package/svg/ISvg.js +1 -0
  92. package/svg/SvgBBox.js +149 -0
  93. package/svg/SvgConstants.js +14 -0
  94. package/svg/SvgGradient.js +97 -0
  95. package/svg/SvgMarker.js +221 -0
  96. package/svg/SvgPattern.js +228 -0
  97. package/svg/SvgPoint.js +33 -0
  98. package/svg/SvgPointSet.js +41 -0
  99. package/templates/lines.js +35 -0
  100. package/tools/gen-id.js +2 -0
  101. package/tools/html.js +2 -0
  102. package/tools/katex.js +75 -0
  103. package/tools/rand-str.js +122 -0
  104. package/tools/regex.js +15 -0
  105. package/tools/utils.js +438 -0
  106. package/tools/webColor.js +700 -0
  107. package/wire/HuatuNet.js +22 -0
  108. package/wire/HuatuWire.js +415 -0
  109. package/wire/HuatuWireDrawing.js +17 -0
  110. package/wire/IHuatuWire.js +1 -0
@@ -0,0 +1,221 @@
1
+ /**
2
+ * The class implementation of SVG Line.
3
+ */
4
+ import { SvgShapeArrowHeadSimpleAngle, SvgShapeArrowHeadSolidTriangle, SvgShapeArrowHeadSolidTwoTriangle } from "../shape/SvgShapeArrowHead.js";
5
+ import { SvgShapeCross, SvgShapePlus } from "../shape/SvgShapeCross.js";
6
+ import { SvgShapeStar, SvgShapeStar5, SvgShapeStarUnified } from "../shape/SvgShapeStar.js";
7
+ import { SvgShapeCircle } from "../shape/SvgShapeCircle.js";
8
+ import { SvgShapeEllipse } from "../shape/SvgShapeEllipse.js";
9
+ import { SvgShapeHeart } from "../shape/SvgShapeHeart.js";
10
+ import { SvgShapeIsoscelesTriangle } from "../shape/SvgShapeIsoscelesTriangle.js";
11
+ import { SvgShapePolygon } from "../shape/SvgShapePolygon.js";
12
+ import { SvgShapeRect } from "../shape/SvgShapeRect.js";
13
+ import { SvgShapeRhombus } from "../shape/SvgShapeRhombus.js";
14
+ export class SvgMarker {
15
+ id;
16
+ units = "strokeWidth";
17
+ refX;
18
+ refY;
19
+ orient; // If use number, it means degrees
20
+ viewBox;
21
+ preserveAspectRatio;
22
+ stroke;
23
+ fill;
24
+ shape;
25
+ constructor(id, shape, orient, refX, refY, stroke, fill) {
26
+ this.id = `svg-mkr-${id}`;
27
+ this.orient = orient;
28
+ this.shape = shape;
29
+ this.refX = refX ?? 0;
30
+ this.refY = refY ?? 0;
31
+ if (stroke && this.shape.hasStroke) {
32
+ this.shape.setStroke(stroke);
33
+ this.stroke = { ...this.shape.stroke };
34
+ }
35
+ if (fill && this.shape.hasFill) {
36
+ this.shape.setFill(fill);
37
+ this.fill = { ...this.shape.fill };
38
+ }
39
+ this.viewBox = this.shape.getBBox(this.stroke?.width);
40
+ }
41
+ buildMarkerSvg(id, primaryColor, secondaryColor) {
42
+ id = id ?? this.id;
43
+ const fillColor = (this.shape.primaryColor === "fill" ? primaryColor : secondaryColor) ?? this.fill?.color;
44
+ const strokeColor = (this.shape.primaryColor === "stroke" ? primaryColor : secondaryColor) ?? this.stroke?.color;
45
+ const attrs = [
46
+ `id="${id}"`,
47
+ `viewBox="${this.viewBox.buildString()}"`,
48
+ `refX="${this.refX}"`,
49
+ `refY="${this.refY}"`,
50
+ `markerWidth="${this.viewBox.w}"`,
51
+ `markerHeight="${this.viewBox.h}"`,
52
+ `orient="${this.orient}"`,
53
+ ];
54
+ return `<marker ${attrs.join(" ")} >\n`
55
+ /** Here, the fill opacity and stoke width are not able to be set while building SVG */
56
+ + this.shape.buildHtml(fillColor, undefined, strokeColor, undefined)
57
+ + `\n</marker>`;
58
+ }
59
+ /** Static methods, and shortcut methods of build different markers, the only variant is the
60
+ * shape which is determined by different input parameters such as size, etc.
61
+ */
62
+ /** --- Circle --- */
63
+ static buildMarkerCircle(radius, fillColor, fillOpacity, strokeColor, strokeWidth) {
64
+ const shape = new SvgShapeCircle(radius);
65
+ return new SvgMarker("circ", shape, 0, 0, 0, {
66
+ color: strokeColor,
67
+ width: strokeWidth,
68
+ }, {
69
+ color: fillColor,
70
+ opacity: fillOpacity
71
+ });
72
+ }
73
+ /** --- Ellipse --- */
74
+ static buildMarkerEllipse(rx, ry, fillColor, fillOpacity, strokeColor, strokeWidth) {
75
+ const shape = new SvgShapeEllipse(rx, ry);
76
+ return new SvgMarker("ell", shape, 0, 0, 0, {
77
+ color: strokeColor,
78
+ width: strokeWidth,
79
+ }, {
80
+ color: fillColor,
81
+ opacity: fillOpacity
82
+ });
83
+ }
84
+ /** --- Rectangle --- */
85
+ static buildMarkerRect(w, h, fillColor, fillOpacity, strokeColor, strokeWidth) {
86
+ const shape = new SvgShapeRect(w, h);
87
+ return new SvgMarker("rect", shape, 0, 0, 0, {
88
+ color: strokeColor,
89
+ width: strokeWidth,
90
+ }, {
91
+ color: fillColor,
92
+ opacity: fillOpacity
93
+ });
94
+ }
95
+ /** --- Square --- */
96
+ static buildMarkerSquare(w, fillColor, fillOpacity, strokeColor, strokeWidth) {
97
+ const shape = new SvgShapeRect(w, w);
98
+ return new SvgMarker("square", shape, 0, 0, 0, {
99
+ color: strokeColor,
100
+ width: strokeWidth,
101
+ }, {
102
+ color: fillColor,
103
+ opacity: fillOpacity
104
+ });
105
+ }
106
+ /** --- Cross --- */
107
+ static buildMarkerCross(w, strokeColor, strokeWidth) {
108
+ const shape = new SvgShapeCross(w);
109
+ return new SvgMarker("cross", shape, 0, 0, 0, {
110
+ color: strokeColor,
111
+ width: strokeWidth,
112
+ });
113
+ }
114
+ /** --- Plus --- */
115
+ static buildMarkerPlus(w, strokeColor, strokeWidth) {
116
+ const shape = new SvgShapePlus(w);
117
+ return new SvgMarker("plus", shape, 0, 0, 0, {
118
+ color: strokeColor,
119
+ width: strokeWidth,
120
+ });
121
+ }
122
+ /** --- Polygon --- */
123
+ static buildMarkerPolygon(radius, edgeCount, fillColor, fillOpacity, strokeColor, strokeWidth) {
124
+ const shape = new SvgShapePolygon(radius, edgeCount);
125
+ return new SvgMarker("plg", shape, 0, 0, 0, {
126
+ color: strokeColor,
127
+ width: strokeWidth,
128
+ }, {
129
+ color: fillColor,
130
+ opacity: fillOpacity
131
+ });
132
+ }
133
+ /** --- Rhombus --- */
134
+ static buildMarkerRhombus(width, height, fillColor, fillOpacity, strokeColor, strokeWidth) {
135
+ const shape = new SvgShapeRhombus(width, height);
136
+ return new SvgMarker("rhombus", shape, 0, 0, 0, {
137
+ color: strokeColor,
138
+ width: strokeWidth,
139
+ }, {
140
+ color: fillColor,
141
+ opacity: fillOpacity
142
+ });
143
+ }
144
+ /** --- Isosceles Triangle --- */
145
+ static buildMarkerIsoscelesTriangle(width, height, direction, fillColor, fillOpacity, strokeColor, strokeWidth) {
146
+ const shape = new SvgShapeIsoscelesTriangle(width, height, direction);
147
+ return new SvgMarker("isotriang", shape, 0, 0, 0, {
148
+ color: strokeColor,
149
+ width: strokeWidth,
150
+ }, {
151
+ color: fillColor,
152
+ opacity: fillOpacity
153
+ });
154
+ }
155
+ /** --- Star made by simple axises --- */
156
+ static buildMarkerStar(size, axisCount, strokeColor, strokeWidth) {
157
+ const shape = new SvgShapeStar(size / 2, axisCount);
158
+ return new SvgMarker("star", shape, 0, 0, 0, {
159
+ color: strokeColor,
160
+ width: strokeWidth,
161
+ });
162
+ }
163
+ /** --- Standard 5-angle star --- */
164
+ static buildMarkerStar5(size, centerEmpty, fillColor, fillOpacity, strokeColor, strokeWidth) {
165
+ const shape = new SvgShapeStar5(size / 2, centerEmpty);
166
+ return new SvgMarker("star5", shape, 0, 0, 0, {
167
+ color: strokeColor,
168
+ width: strokeWidth,
169
+ }, {
170
+ color: fillColor,
171
+ opacity: fillOpacity
172
+ });
173
+ }
174
+ /** --- Unified Star-Like Markers --- */
175
+ static buildMarkerStarUnified(axisCount, rIn, rOut, degOffset, fillColor, fillOpacity, strokeColor, strokeWidth, roundRadius) {
176
+ const shape = new SvgShapeStarUnified(axisCount, rIn, rOut, degOffset, roundRadius);
177
+ return new SvgMarker("staru", shape, 0, 0, 0, {
178
+ color: strokeColor,
179
+ width: strokeWidth,
180
+ }, {
181
+ color: fillColor,
182
+ opacity: fillOpacity
183
+ });
184
+ }
185
+ /** --- Heart --- */
186
+ static buildMarkerHeart(h1, ctrlLen1, deg1, farPointX, farPointY, deg2, ctrlLen2, ctrlLen3, h2, deg3, ctrlLen4, fillColor, fillOpacity, strokeColor, strokeWidth) {
187
+ const shape = new SvgShapeHeart(h1, ctrlLen1, deg1, farPointX, farPointY, deg2, ctrlLen2, ctrlLen3, h2, deg3, ctrlLen4);
188
+ return new SvgMarker("heart", shape, 0, 0, 0, {
189
+ color: strokeColor,
190
+ width: strokeWidth,
191
+ }, {
192
+ color: fillColor,
193
+ opacity: fillOpacity
194
+ });
195
+ }
196
+ /** --- Arrow Head --- */
197
+ static buildArrowHead(type, length, openDeg, len2Ratio, makeSmooth, makeTriangle, color) {
198
+ if (type === "solid-angle") {
199
+ const shape = new SvgShapeArrowHeadSolidTriangle(length, openDeg, makeSmooth ? 0.4 : undefined);
200
+ return new SvgMarker("arrow-solid", shape, "auto-start-reverse", -0.5 / Math.tan(shape.angHalf), 0, undefined, color ? { color } : undefined /** Fill Color */);
201
+ }
202
+ else if (type === "solid-two-angle") {
203
+ const shape = new SvgShapeArrowHeadSolidTwoTriangle(length, openDeg, len2Ratio, makeSmooth ? 0.4 : undefined);
204
+ return new SvgMarker("arrow-solid-2", shape, "auto-start-reverse", -0.5 / Math.tan(shape.angHalf), 0, undefined, color ? { color } : undefined /** Fill Color */);
205
+ }
206
+ else {
207
+ const shape = new SvgShapeArrowHeadSimpleAngle(length, openDeg, makeTriangle, makeSmooth);
208
+ /** Here, the second 0.5 (half of 1) is derived from the fact that the default (and should always be)
209
+ * stroke width is 1 (same as line stroke) */
210
+ const refX = -0.5 / Math.tan(shape.angHalf) + 0.5 / Math.sin(shape.angHalf);
211
+ return new SvgMarker("arrow-simple", shape, "auto-start-reverse", refX, 0, color ? { color } : undefined);
212
+ }
213
+ }
214
+ /** The predefined markers */
215
+ static preDefines = {
216
+ "arrow-std": SvgMarker.buildArrowHead("solid-angle", 5.2, 42),
217
+ "arrow1": SvgMarker.buildArrowHead("solid-angle", 7, 38),
218
+ "arrow2": SvgMarker.buildArrowHead("solid-angle", 5, 30),
219
+ // TODO: add more as required
220
+ };
221
+ }
@@ -0,0 +1,228 @@
1
+ /**
2
+ * The class implementation of SVG Point.
3
+ */
4
+ import { fitNumInRange } from "../tools/utils.js";
5
+ import { AngDeg } from "../geometry/AngDeg.js";
6
+ import Line from "../geometry/Line.js";
7
+ import LineSeg from "../geometry/LineSeg.js";
8
+ import Point from "../geometry/Point.js";
9
+ import { SvgBBox } from "./SvgBBox.js";
10
+ import { PathRect } from "../path/PathRect.js";
11
+ import { PathLines } from "../path/PathLines.js";
12
+ import { PathCircle } from "../path/PathCircle.js";
13
+ export class SvgPattern {
14
+ id;
15
+ units = "userSpaceOnUse";
16
+ contentUnits;
17
+ x = 0;
18
+ y = 0;
19
+ width = 0;
20
+ height = 0;
21
+ paths = [];
22
+ viewBox;
23
+ constructor(id, x, y, width, height) {
24
+ this.id = id;
25
+ if (x)
26
+ this.x = x;
27
+ if (y)
28
+ this.y = y;
29
+ if (width)
30
+ this.width = width;
31
+ if (height)
32
+ this.height = height;
33
+ }
34
+ setUnits(units) {
35
+ this.units = units;
36
+ }
37
+ setContentUnits(units) {
38
+ // If there is a View Box defined, then the content unit should not be defined
39
+ if (this.viewBox)
40
+ return;
41
+ this.units = units;
42
+ }
43
+ setViewBox(box) {
44
+ this.viewBox = box;
45
+ }
46
+ addPaths(...paths) {
47
+ this.paths.push(...paths);
48
+ }
49
+ buildHtml(id) {
50
+ const attrs = [
51
+ `id="${id ?? this.id}"`,
52
+ `x="${this.x}"`,
53
+ `y="${this.y}"`,
54
+ `width="${this.width}"`,
55
+ `height="${this.height}"`
56
+ ];
57
+ if (this.units === "userSpaceOnUse")
58
+ attrs.push(`patternUnits="${this.units}"`);
59
+ if (this.contentUnits && this.viewBox)
60
+ attrs.push(`patternContentUnits="${this.contentUnits}"`);
61
+ if (this.viewBox)
62
+ attrs.push(`viewBox="${this.viewBox.buildString()}"`);
63
+ return `<pattern ${attrs.join(" ")} >\n`
64
+ + this.paths.map(p => p.buildHtml()).join("\n")
65
+ + `\n</pattern>`;
66
+ }
67
+ }
68
+ const buildRectFromViewBox = (vb, bg, bgOpacity) => {
69
+ const rect = PathRect.fromXYWH(vb.x, vb.y, vb.w, vb.h);
70
+ rect.fill = { color: bg };
71
+ if (bgOpacity) {
72
+ rect.fill.opacity = fitNumInRange(bgOpacity, 0, 1);
73
+ }
74
+ return rect;
75
+ };
76
+ export const buildLinePattern = (name, lineDensity, rotDeg, lineWeight, lineStyle, dashDensity, color, background, bgOpacity, opacity) => {
77
+ const buildLineSegAndViewBox = (lineDistance, rotDeg) => {
78
+ let wBox, hBox;
79
+ let path = new PathLines();
80
+ let deg = AngDeg.fitDeg(rotDeg);
81
+ deg = AngDeg.ang2Deg(deg);
82
+ if (deg > 180)
83
+ deg -= 180;
84
+ const degUsed = deg < 5
85
+ ? 0
86
+ : deg > 85 && deg < 95
87
+ ? 90
88
+ : deg > 175
89
+ ? 0
90
+ : deg;
91
+ let w, h;
92
+ let N = 8; // Here N should be odd integer
93
+ const idx = [...Array(N).keys()];
94
+ if (degUsed === 0) { // Horizontal Line
95
+ wBox = N * lineDistance;
96
+ hBox = N * lineDistance;
97
+ h = lineDistance / 2;
98
+ path.addLineSegs(...idx.map(i => LineSeg.fromXYs(-wBox / 2, (2 * i - N + 1) * h, wBox / 2, (2 * i - N + 1) * h)));
99
+ }
100
+ else if (degUsed === 90) { // Vertical Line
101
+ wBox = N * lineDistance;
102
+ hBox = N * lineDistance;
103
+ w = lineDistance / 2;
104
+ path.addLineSegs(...idx.map(i => LineSeg.fromXYs((2 * i - N + 1) * w, -hBox / 2, (2 * i - N + 1) * w, hBox / 2)));
105
+ }
106
+ else {
107
+ let angUsed = AngDeg.deg2Ang(degUsed);
108
+ w = lineDistance / Math.abs(Math.sin(angUsed)) / 2;
109
+ h = lineDistance / Math.abs(Math.cos(angUsed)) / 2;
110
+ let d = Math.sqrt(w ** 2 + h ** 2);
111
+ wBox = N * 2 * w;
112
+ hBox = N * 2 * h;
113
+ let lines = [...Array(2 * N).keys()]
114
+ .map(i => degUsed < 90
115
+ ? new Point(-wBox / 2, (N - 1 - 2 * i) * h)
116
+ : new Point(wBox / 2, (N - 1 - 2 * i) * h))
117
+ .map((p, i) => {
118
+ let len = (i >= N ? (2 * N) : (2 * i + 1)) * d;
119
+ return new Line(p, angUsed).buildSeg(-strokeWidth, len + strokeWidth);
120
+ });
121
+ path.addLineSegs(...lines);
122
+ }
123
+ return {
124
+ path,
125
+ viewBox: new SvgBBox(-wBox / 2, -hBox / 2, wBox, hBox)
126
+ };
127
+ };
128
+ // Fit Line Weight, it should be in 1 and 100
129
+ lineWeight = fitNumInRange(lineWeight, 1, 100);
130
+ let strokeWidth = lineWeight ** 1.4 * 0.02;
131
+ // Fit Density, it should be in 1 and 100
132
+ lineDensity = fitNumInRange(lineDensity, 1, 100);
133
+ let lineDistance = 40 / lineDensity + strokeWidth * 2;
134
+ // Fit DashDensity, it should be in 1 and 100
135
+ dashDensity = fitNumInRange(dashDensity, 1, 100);
136
+ let dashArray = [];
137
+ let lineCap;
138
+ if (lineStyle === "dotted") {
139
+ lineCap = "round";
140
+ let k = 100 / dashDensity;
141
+ dashArray.push(0, k * strokeWidth);
142
+ }
143
+ else if (lineStyle === "dashed") {
144
+ let k = 100 / dashDensity;
145
+ dashArray.push(k * 1.6 * strokeWidth, k ** 1.5 * 1.6 * strokeWidth);
146
+ }
147
+ const lines = buildLineSegAndViewBox(lineDistance, rotDeg);
148
+ const pattern = new SvgPattern(name, 0, 0, lines.viewBox.w, lines.viewBox.h);
149
+ if (background) {
150
+ pattern.addPaths(buildRectFromViewBox(lines.viewBox, background, bgOpacity));
151
+ }
152
+ lines.path.stroke = {
153
+ color: color ? color : "currentColor",
154
+ width: strokeWidth,
155
+ };
156
+ if (lineCap) {
157
+ lines.path.stroke.lineCap = lineCap;
158
+ }
159
+ if (dashArray.length > 0) {
160
+ lines.path.stroke.dashArray = dashArray;
161
+ }
162
+ if (opacity) {
163
+ lines.path.stroke.opacity = fitNumInRange(opacity, 0, 1);
164
+ }
165
+ pattern.viewBox = lines.viewBox;
166
+ pattern.addPaths(lines.path);
167
+ return pattern;
168
+ };
169
+ export const buildDotPattern = (name, dotDensity, dotSize, color, opacity, background, bgOpacity) => {
170
+ dotDensity = fitNumInRange(dotDensity, 1, 100);
171
+ dotSize = fitNumInRange(dotSize, 1, 100);
172
+ let r = dotSize * 0.2, d = r * (40 / dotDensity ** 0.56247); // Max density: 3r, min Density: 40r, this is half of the viewBox square side length
173
+ const vb = new SvgBBox(-d, -d, 2 * d, 2 * d);
174
+ const pattern = new SvgPattern(name, 0, 0, vb.w, vb.h);
175
+ const circ = new PathCircle(0, 0, r);
176
+ circ.fill = { color: color };
177
+ if (opacity) {
178
+ circ.fill.opacity = fitNumInRange(opacity, 0, 1);
179
+ }
180
+ pattern.viewBox = vb;
181
+ if (background) {
182
+ pattern.addPaths(buildRectFromViewBox(vb, background, bgOpacity));
183
+ }
184
+ pattern.addPaths(circ);
185
+ return pattern;
186
+ };
187
+ export const buildSquarePattern = (name, sqDensity, sqSize, color, opacity, background, bgOpacity) => {
188
+ sqDensity = fitNumInRange(sqDensity, 1, 100);
189
+ sqSize = fitNumInRange(sqSize, 1, 100);
190
+ let l = sqSize * 0.2, d = l * (40 / sqDensity ** 0.56247); // Max density: 3r, min Density: 40r, this is half of the viewBox square side length
191
+ const vb = new SvgBBox(-d, -d, 2 * d, 2 * d);
192
+ const pattern = new SvgPattern(name, 0, 0, vb.w, vb.h);
193
+ const sq = PathRect.fromXYWH(-l, -l, 2 * l, 2 * l);
194
+ sq.fill = { color: color };
195
+ if (opacity) {
196
+ sq.fill.opacity = fitNumInRange(opacity, 0, 1);
197
+ }
198
+ pattern.viewBox = vb;
199
+ if (background) {
200
+ pattern.addPaths(buildRectFromViewBox(vb, background, bgOpacity));
201
+ }
202
+ pattern.addPaths(sq);
203
+ return pattern;
204
+ };
205
+ export const buildGridPattern = (name, gridSize, lineWidth, color, bgColor, bgOpacity, opacity, sparseK) => {
206
+ gridSize = fitNumInRange(gridSize, 1, 100);
207
+ let d = Math.ceil(gridSize);
208
+ sparseK = fitNumInRange(sparseK ?? 1, 0.3, 30);
209
+ let len = d * (1 + sparseK);
210
+ const vb = new SvgBBox(-len / 2, -len / 2, len, len);
211
+ const lines = new PathLines();
212
+ lines.addLineSegs(LineSeg.fromXYs(-len / 2, -d / 2, len / 2, -d / 2), LineSeg.fromXYs(-len / 2, d / 2, len / 2, d / 2), LineSeg.fromXYs(-d / 2, -len / 2, -d / 2, len / 2), LineSeg.fromXYs(d / 2, -len / 2, d / 2, len / 2));
213
+ lineWidth = fitNumInRange(lineWidth, 1, 100);
214
+ lines.stroke = {
215
+ color: color,
216
+ width: lineWidth ** 1.4 * 0.02
217
+ };
218
+ if (opacity) {
219
+ lines.stroke.opacity = fitNumInRange(opacity, 0, 1);
220
+ }
221
+ const pattern = new SvgPattern(name, 0, 0, vb.w, vb.h);
222
+ pattern.viewBox = vb;
223
+ if (bgColor) {
224
+ pattern.addPaths(buildRectFromViewBox(vb, bgColor, bgOpacity));
225
+ }
226
+ pattern.addPaths(lines);
227
+ return pattern;
228
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * The class implementation of SVG Point.
3
+ */
4
+ import { SvgCsts } from "./SvgConstants.js";
5
+ export class SvgPoint {
6
+ x;
7
+ y;
8
+ constructor(x, y) {
9
+ this.x = x;
10
+ this.y = y;
11
+ }
12
+ toCoors(digits) {
13
+ const digitPlace = digits
14
+ ? (digits < SvgCsts.COORS_DIGITS_MIN ? SvgCsts.COORS_DIGITS_MIN : Math.round(digits))
15
+ : SvgCsts.COORS_DIGITS;
16
+ return `${this.x.toFixed(digitPlace)},${this.y.toFixed(digitPlace)}`;
17
+ }
18
+ moveBy(dx, dy) {
19
+ return new SvgPoint(this.x + dx, this.y + dy);
20
+ }
21
+ //======= Static Methods =====================================================
22
+ static from(p) {
23
+ return new SvgPoint(p.x, p.y);
24
+ }
25
+ static toCoors(p, digits) {
26
+ const digitPlace = digits
27
+ ? (digits < SvgCsts.COORS_DIGITS_MIN ? SvgCsts.COORS_DIGITS_MIN : Math.round(digits))
28
+ : SvgCsts.COORS_DIGITS;
29
+ return `${p.x.toFixed(digitPlace)},${p.y.toFixed(digitPlace)}`;
30
+ }
31
+ static ORIGIN = new SvgPoint(0, 0);
32
+ static ZERO = new SvgPoint(0, 0);
33
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * The class implementation of SVG Point.
3
+ */
4
+ import { SvgPoint } from "./SvgPoint.js";
5
+ export class SvgPointSet {
6
+ points = [];
7
+ constructor() {
8
+ }
9
+ add(...points) {
10
+ this.points.push(...points.map(p => SvgPoint.from(p)));
11
+ }
12
+ concat(set) {
13
+ this.add(...set.points);
14
+ return this;
15
+ }
16
+ //======= Static Methods =====================================================
17
+ static from(points) {
18
+ const set = new SvgPointSet();
19
+ set.points = points.map(p => SvgPoint.from(p));
20
+ return set;
21
+ }
22
+ static zipTwo(set1, set2) {
23
+ const set = new SvgPointSet();
24
+ const lenLonger = Math.max(set1.points.length, set2.points.length);
25
+ for (let i = 0; i < lenLonger; i++) {
26
+ if (i < set1.points.length) {
27
+ set.add(set1.points[i]);
28
+ }
29
+ if (i < set2.points.length) {
30
+ set.add(set2.points[i]);
31
+ }
32
+ }
33
+ return set;
34
+ }
35
+ static concatTwo(set1, set2) {
36
+ const set = new SvgPointSet();
37
+ set.add(...set1.points);
38
+ set.add(...set2.points);
39
+ return set;
40
+ }
41
+ }
@@ -0,0 +1,35 @@
1
+ import Point from "../geometry/Point.js";
2
+ import { SvgBBox } from "../svg/SvgBBox.js";
3
+ export class HuatuTemplateLines {
4
+ name = "lines";
5
+ chartHeight = 600;
6
+ chartWidth = 1000;
7
+ data = [];
8
+ constructor() {
9
+ }
10
+ buildHuatuYml() {
11
+ return "";
12
+ }
13
+ }
14
+ export const data2Points = (data, vbChart, xRange, yRange) => {
15
+ const xs = data.map(x => x.x);
16
+ const ys = data.map(x => x.y);
17
+ const xr = xRange ?? { min: Math.min(...xs), max: Math.max(...xs) };
18
+ const yr = yRange ?? { min: Math.min(...ys), max: Math.max(...ys) };
19
+ return data.map((d, i) => {
20
+ let dx = d.x >= xr.max ? xr.max : d.x <= xr.min ? xr.min : d.x, dy = d.y >= yr.max ? yr.max : d.y <= yr.min ? yr.min : d.y, x = vbChart.x + vbChart.w * (dx - xr.min) / (xr.max - xr.min), y = vbChart.y + vbChart.h - vbChart.h * (dy - yr.min) / (yr.max - yr.min);
21
+ return new Point(x, y);
22
+ });
23
+ };
24
+ const dat = [...Array(30).keys()].map(i => {
25
+ const theta = i * Math.PI / 12;
26
+ const r = 6 * theta;
27
+ return {
28
+ x: r * Math.cos(theta),
29
+ y: r * Math.sin(theta),
30
+ };
31
+ });
32
+ const points = data2Points(dat, new SvgBBox(0, -800, 1000, 800), undefined, undefined)
33
+ .map(p => `${p.x.toFixed(6)},${p.y.toFixed(6)}`)
34
+ .join(";");
35
+ console.log(points);
@@ -0,0 +1,2 @@
1
+ import { genRandStrOf } from "./rand-str.js";
2
+ export const genHex = (digits) => genRandStrOf("h", 8);
package/tools/html.js ADDED
@@ -0,0 +1,2 @@
1
+ // Build the CSS including tag
2
+ export const buildCssHtmlTag = (cssLoc) => `<link rel="stylesheet" href="${cssLoc}" />`;
package/tools/katex.js ADDED
@@ -0,0 +1,75 @@
1
+ import katex from "katex";
2
+ import "katex/contrib/mhchem";
3
+ export const renderKatexInline = (math) => {
4
+ try {
5
+ return katex.renderToString(math, {
6
+ displayMode: false,
7
+ output: "html",
8
+ });
9
+ }
10
+ catch (error) {
11
+ return `<span class='txt-error'>公式书写错误: ${math}</span>`;
12
+ }
13
+ };
14
+ export const renderKatexBlock = (math) => {
15
+ try {
16
+ const katexHtml = katex.renderToString(math, {
17
+ displayMode: true,
18
+ output: "html",
19
+ });
20
+ return `<div class="katex-block">${katexHtml}</div>`;
21
+ }
22
+ catch (error) {
23
+ return `<span class='txt-error'>公式书写错误: ${math}</span>`;
24
+ }
25
+ };
26
+ export const renderKatexInlineWithBlockForm = (math) => {
27
+ try {
28
+ const renderedHtml = katex.renderToString(math, {
29
+ displayMode: true,
30
+ output: "html",
31
+ });
32
+ const matched = /<span class="katex-display">([\s\S]+)<\/span>/i.exec(renderedHtml);
33
+ return matched ? matched[1] : renderedHtml;
34
+ }
35
+ catch (error) {
36
+ return `<span class='txt-error'>公式书写错误: ${math}</span>`;
37
+ }
38
+ };
39
+ export const renderKatexMixedText = (text) => {
40
+ const rawSegments = text.split(/(?<!\\)\$/); // Split label text with just the $ sign, but not escaped one \$
41
+ const rendered = [];
42
+ if (rawSegments[0].trim()) {
43
+ rendered.push(`<span>${rawSegments[0]}</span>`);
44
+ }
45
+ let dsStarted = false;
46
+ let textPending = '';
47
+ if (rawSegments.length >= 2) {
48
+ for (let i = 1; i < rawSegments.length; i++) {
49
+ if (!dsStarted) {
50
+ dsStarted = true;
51
+ if (textPending.trim()) {
52
+ rendered.push(`<span>${textPending}</span>`);
53
+ }
54
+ textPending = rawSegments[i];
55
+ }
56
+ else {
57
+ rendered.push(renderKatexInlineWithBlockForm(textPending));
58
+ dsStarted = false;
59
+ textPending = rawSegments[i];
60
+ }
61
+ }
62
+ if (dsStarted) {
63
+ textPending = '$' + textPending;
64
+ }
65
+ if (textPending) {
66
+ rendered.push(`<span>${textPending}</span>`);
67
+ }
68
+ }
69
+ return rendered.join("");
70
+ };
71
+ export const renderKatexMixedTextConditional = (text, renderKatex) => {
72
+ return renderKatex
73
+ ? renderKatexMixedText(text)
74
+ : `<span>${text}</span>`;
75
+ };