@xrn07/figure-renderer 0.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/LICENSE +21 -0
- package/README.md +162 -0
- package/dist/parse.d.ts +11 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +39 -0
- package/dist/react.d.ts +14 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +21 -0
- package/dist/render.d.ts +10 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +41 -0
- package/dist/renderers/bioTable.d.ts +3 -0
- package/dist/renderers/bioTable.d.ts.map +1 -0
- package/dist/renderers/bioTable.js +28 -0
- package/dist/renderers/circuit.d.ts +3 -0
- package/dist/renderers/circuit.d.ts.map +1 -0
- package/dist/renderers/circuit.js +237 -0
- package/dist/renderers/coordinatePlane.d.ts +3 -0
- package/dist/renderers/coordinatePlane.d.ts.map +1 -0
- package/dist/renderers/coordinatePlane.js +142 -0
- package/dist/renderers/forceDiagram.d.ts +3 -0
- package/dist/renderers/forceDiagram.d.ts.map +1 -0
- package/dist/renderers/forceDiagram.js +130 -0
- package/dist/renderers/geometry.d.ts +3 -0
- package/dist/renderers/geometry.d.ts.map +1 -0
- package/dist/renderers/geometry.js +173 -0
- package/dist/renderers/graph.d.ts +3 -0
- package/dist/renderers/graph.d.ts.map +1 -0
- package/dist/renderers/graph.js +137 -0
- package/dist/renderers/numberLine.d.ts +3 -0
- package/dist/renderers/numberLine.d.ts.map +1 -0
- package/dist/renderers/numberLine.js +98 -0
- package/dist/renderers/rayDiagram.d.ts +3 -0
- package/dist/renderers/rayDiagram.d.ts.map +1 -0
- package/dist/renderers/rayDiagram.js +181 -0
- package/dist/renderers/venn.d.ts +3 -0
- package/dist/renderers/venn.d.ts.map +1 -0
- package/dist/renderers/venn.js +60 -0
- package/dist/types.d.ts +225 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/utils/arrowMarker.d.ts +13 -0
- package/dist/utils/arrowMarker.d.ts.map +1 -0
- package/dist/utils/arrowMarker.js +48 -0
- package/dist/utils/coordTransform.d.ts +29 -0
- package/dist/utils/coordTransform.d.ts.map +1 -0
- package/dist/utils/coordTransform.js +38 -0
- package/dist/utils/gridLines.d.ts +23 -0
- package/dist/utils/gridLines.d.ts.map +1 -0
- package/dist/utils/gridLines.js +124 -0
- package/dist/utils/label.d.ts +30 -0
- package/dist/utils/label.d.ts.map +1 -0
- package/dist/utils/label.js +82 -0
- package/dist/utils/path.d.ts +21 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +72 -0
- package/dist/utils/shapes.d.ts +29 -0
- package/dist/utils/shapes.d.ts.map +1 -0
- package/dist/utils/shapes.js +78 -0
- package/dist/utils/svgTag.d.ts +11 -0
- package/dist/utils/svgTag.d.ts.map +1 -0
- package/dist/utils/svgTag.js +29 -0
- package/package.json +70 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Number line renderer
|
|
2
|
+
import { svgTag } from '../utils/svgTag';
|
|
3
|
+
import { line, circle, text } from '../utils/shapes';
|
|
4
|
+
export function renderNumberLine(dsl) {
|
|
5
|
+
const { width, height, range, ticks, marks, arrowEnds = 'both', title } = dsl;
|
|
6
|
+
const elements = [];
|
|
7
|
+
// Calculate padding and usable width
|
|
8
|
+
const padding = 60;
|
|
9
|
+
const usableWidth = width - 2 * padding;
|
|
10
|
+
const lineY = height / 2;
|
|
11
|
+
// Add arrow markers
|
|
12
|
+
elements.push(createArrowMarkers());
|
|
13
|
+
// Helper to convert value to SVG x-coordinate
|
|
14
|
+
const valueToX = (value) => {
|
|
15
|
+
const [min, max] = range;
|
|
16
|
+
const ratio = (value - min) / (max - min);
|
|
17
|
+
return padding + ratio * usableWidth;
|
|
18
|
+
};
|
|
19
|
+
// Draw main line with arrows
|
|
20
|
+
const x1 = valueToX(range[0]);
|
|
21
|
+
const x2 = valueToX(range[1]);
|
|
22
|
+
const lineAttrs = {
|
|
23
|
+
x1,
|
|
24
|
+
y1: lineY,
|
|
25
|
+
x2,
|
|
26
|
+
y2: lineY,
|
|
27
|
+
stroke: '#333',
|
|
28
|
+
'stroke-width': 2,
|
|
29
|
+
};
|
|
30
|
+
// Add arrow markers based on arrowEnds
|
|
31
|
+
if (arrowEnds === 'left' || arrowEnds === 'both') {
|
|
32
|
+
lineAttrs['marker-start'] = 'url(#arrow-start)';
|
|
33
|
+
}
|
|
34
|
+
if (arrowEnds === 'right' || arrowEnds === 'both') {
|
|
35
|
+
lineAttrs['marker-end'] = 'url(#arrow-end)';
|
|
36
|
+
}
|
|
37
|
+
elements.push(svgTag('line', lineAttrs, ''));
|
|
38
|
+
// Draw ticks
|
|
39
|
+
ticks.forEach(tick => {
|
|
40
|
+
const tickX = valueToX(tick);
|
|
41
|
+
elements.push(line(tickX, lineY - 10, tickX, lineY + 10, {
|
|
42
|
+
stroke: '#333',
|
|
43
|
+
'stroke-width': 2,
|
|
44
|
+
}));
|
|
45
|
+
// Add tick label
|
|
46
|
+
elements.push(text(tickX, lineY + 25, String(tick), {
|
|
47
|
+
'text-anchor': 'middle',
|
|
48
|
+
'font-size': 12,
|
|
49
|
+
fill: '#333',
|
|
50
|
+
}));
|
|
51
|
+
});
|
|
52
|
+
// Draw marks (points of interest)
|
|
53
|
+
marks.forEach(mark => {
|
|
54
|
+
const markX = valueToX(mark.value);
|
|
55
|
+
if (mark.style === 'open') {
|
|
56
|
+
elements.push(circle(markX, lineY, 6, {
|
|
57
|
+
fill: '#fff',
|
|
58
|
+
stroke: '#e53e3e',
|
|
59
|
+
'stroke-width': 2,
|
|
60
|
+
}));
|
|
61
|
+
}
|
|
62
|
+
else if (mark.style === 'closed') {
|
|
63
|
+
elements.push(circle(markX, lineY, 5, {
|
|
64
|
+
fill: '#e53e3e',
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// arrow style or default
|
|
69
|
+
elements.push(circle(markX, lineY, 5, {
|
|
70
|
+
fill: '#e53e3e',
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
// Add mark label
|
|
74
|
+
elements.push(text(markX, lineY - 15, mark.label, {
|
|
75
|
+
'text-anchor': 'middle',
|
|
76
|
+
'font-size': 11,
|
|
77
|
+
fill: '#e53e3e',
|
|
78
|
+
'font-weight': 'bold',
|
|
79
|
+
}));
|
|
80
|
+
});
|
|
81
|
+
const svg = svgTag('svg', {
|
|
82
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
83
|
+
xmlns: 'http://www.w3.org/2000/svg',
|
|
84
|
+
}, elements.join(''));
|
|
85
|
+
return svg;
|
|
86
|
+
}
|
|
87
|
+
function createArrowMarkers() {
|
|
88
|
+
return `
|
|
89
|
+
<defs>
|
|
90
|
+
<marker id="arrow-start" markerWidth="10" markerHeight="10" refX="2" refY="5" orient="auto">
|
|
91
|
+
<path d="M10,0 L0,5 L10,10" fill="#333" />
|
|
92
|
+
</marker>
|
|
93
|
+
<marker id="arrow-end" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto">
|
|
94
|
+
<path d="M0,0 L10,5 L0,10" fill="#333" />
|
|
95
|
+
</marker>
|
|
96
|
+
</defs>
|
|
97
|
+
`;
|
|
98
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rayDiagram.d.ts","sourceRoot":"","sources":["../../src/renderers/rayDiagram.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAuB,MAAM,UAAU,CAAC;AAInE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAwB3D"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// Ray diagram renderer
|
|
2
|
+
import { svgTag } from '../utils/svgTag';
|
|
3
|
+
import { line, rect, circle as svgCircle, ellipse, path, text } from '../utils/shapes';
|
|
4
|
+
export function renderRayDiagram(dsl) {
|
|
5
|
+
const { width, height, opticalElements, rays, title } = dsl;
|
|
6
|
+
const elements = [];
|
|
7
|
+
// Add arrow markers
|
|
8
|
+
elements.push(createRayMarkers());
|
|
9
|
+
// Render optical elements
|
|
10
|
+
opticalElements.forEach(element => {
|
|
11
|
+
elements.push(renderOpticalElement(element));
|
|
12
|
+
});
|
|
13
|
+
// Render rays
|
|
14
|
+
rays.forEach(ray => {
|
|
15
|
+
elements.push(renderRay(ray, opticalElements));
|
|
16
|
+
});
|
|
17
|
+
const svg = svgTag('svg', {
|
|
18
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
19
|
+
xmlns: 'http://www.w3.org/2000/svg',
|
|
20
|
+
}, elements.join(''));
|
|
21
|
+
return svg;
|
|
22
|
+
}
|
|
23
|
+
function renderOpticalElement(element) {
|
|
24
|
+
const { type, x, y } = element;
|
|
25
|
+
switch (type) {
|
|
26
|
+
case 'lens':
|
|
27
|
+
return renderLens(element);
|
|
28
|
+
case 'mirror':
|
|
29
|
+
return renderMirror(element);
|
|
30
|
+
case 'prism':
|
|
31
|
+
return renderPrism(element);
|
|
32
|
+
case 'screen':
|
|
33
|
+
return renderScreen(element);
|
|
34
|
+
default:
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function renderLens(element) {
|
|
39
|
+
const { x, y, width: w = 80, height: h = 10, focalLength, curvature = 'convex' } = element;
|
|
40
|
+
const elements = [];
|
|
41
|
+
// Draw lens shape (simplified as ellipse)
|
|
42
|
+
elements.push(ellipse(x, y, w / 2, h / 2, {
|
|
43
|
+
fill: 'rgba(173, 216, 230, 0.3)',
|
|
44
|
+
stroke: '#4682B4',
|
|
45
|
+
'stroke-width': 2,
|
|
46
|
+
}));
|
|
47
|
+
// Draw focal points if specified
|
|
48
|
+
if (focalLength) {
|
|
49
|
+
const f = Math.abs(focalLength);
|
|
50
|
+
const focalPoint1 = curvature === 'convex' ? x - f : x + f;
|
|
51
|
+
const focalPoint2 = curvature === 'convex' ? x + f : x - f;
|
|
52
|
+
elements.push(svgCircle(focalPoint1, y, 3, { fill: '#e53e3e' }));
|
|
53
|
+
elements.push(svgCircle(focalPoint2, y, 3, { fill: '#e53e3e' }));
|
|
54
|
+
elements.push(text(focalPoint1, y + 15, 'F', {
|
|
55
|
+
'text-anchor': 'middle',
|
|
56
|
+
'font-size': 12,
|
|
57
|
+
fill: '#e53e3e',
|
|
58
|
+
}));
|
|
59
|
+
elements.push(text(focalPoint2, y + 15, 'F\'', {
|
|
60
|
+
'text-anchor': 'middle',
|
|
61
|
+
'font-size': 12,
|
|
62
|
+
fill: '#e53e3e',
|
|
63
|
+
}));
|
|
64
|
+
}
|
|
65
|
+
// Draw optical axis
|
|
66
|
+
elements.push(line(x - w, y, x + w, y, {
|
|
67
|
+
stroke: '#666',
|
|
68
|
+
'stroke-width': 1,
|
|
69
|
+
'stroke-dasharray': '4,4',
|
|
70
|
+
}));
|
|
71
|
+
return svgTag('g', { class: 'lens' }, elements.join(''));
|
|
72
|
+
}
|
|
73
|
+
function renderMirror(element) {
|
|
74
|
+
const { x, y, width: w = 80, height: h = 5, curvature = 'flat' } = element;
|
|
75
|
+
const elements = [];
|
|
76
|
+
if (curvature === 'flat') {
|
|
77
|
+
// Flat mirror (line with hash marks on back)
|
|
78
|
+
elements.push(line(x, y - h / 2, x, y + h / 2, {
|
|
79
|
+
stroke: '#333',
|
|
80
|
+
'stroke-width': 3,
|
|
81
|
+
}));
|
|
82
|
+
// Add hash marks to indicate reflective side
|
|
83
|
+
for (let i = -h / 2; i <= h / 2; i += 8) {
|
|
84
|
+
elements.push(line(x, i, x + 8, i + 4, {
|
|
85
|
+
stroke: '#333',
|
|
86
|
+
'stroke-width': 1,
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
// Curved mirror
|
|
92
|
+
const radius = curvature === 'concave' ? w / 2 : -w / 2;
|
|
93
|
+
elements.push(path(`M ${x} ${y - h / 2} Q ${x + radius} ${y} ${x} ${y + h / 2}`, {
|
|
94
|
+
fill: 'none',
|
|
95
|
+
stroke: '#333',
|
|
96
|
+
'stroke-width': 3,
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
return svgTag('g', { class: 'mirror' }, elements.join(''));
|
|
100
|
+
}
|
|
101
|
+
function renderPrism(element) {
|
|
102
|
+
const { x, y, width: w = 60, height: h = 60 } = element;
|
|
103
|
+
const elements = [];
|
|
104
|
+
// Draw triangular prism
|
|
105
|
+
const points = [
|
|
106
|
+
[x, y - h / 2],
|
|
107
|
+
[x - w / 2, y + h / 2],
|
|
108
|
+
[x + w / 2, y + h / 2],
|
|
109
|
+
];
|
|
110
|
+
elements.push(svgTag('polygon', {
|
|
111
|
+
points: points.map(([px, py]) => `${px},${py}`).join(' '),
|
|
112
|
+
fill: 'rgba(200, 200, 255, 0.3)',
|
|
113
|
+
stroke: '#666',
|
|
114
|
+
'stroke-width': 2,
|
|
115
|
+
}, ''));
|
|
116
|
+
return svgTag('g', { class: 'prism' }, elements.join(''));
|
|
117
|
+
}
|
|
118
|
+
function renderScreen(element) {
|
|
119
|
+
const { x, y, width: w = 10, height: h = 100 } = element;
|
|
120
|
+
const elements = [];
|
|
121
|
+
// Draw screen as a vertical rectangle
|
|
122
|
+
elements.push(rect(x - w / 2, y - h / 2, w, h, {
|
|
123
|
+
fill: '#f5f5f5',
|
|
124
|
+
stroke: '#333',
|
|
125
|
+
'stroke-width': 2,
|
|
126
|
+
}));
|
|
127
|
+
// Add screen pattern
|
|
128
|
+
elements.push(line(x - w / 2, y - h / 2, x + w / 2, y + h / 2, {
|
|
129
|
+
stroke: '#999',
|
|
130
|
+
'stroke-width': 1,
|
|
131
|
+
}));
|
|
132
|
+
elements.push(line(x - w / 2, y + h / 2, x + w / 2, y - h / 2, {
|
|
133
|
+
stroke: '#999',
|
|
134
|
+
'stroke-width': 1,
|
|
135
|
+
}));
|
|
136
|
+
return svgTag('g', { class: 'screen' }, elements.join(''));
|
|
137
|
+
}
|
|
138
|
+
function renderRay(ray, opticalElements) {
|
|
139
|
+
const { startX, startY, angle, color = '#FFD700', label } = ray;
|
|
140
|
+
const elements = [];
|
|
141
|
+
// Calculate ray end point (extend to edge of diagram)
|
|
142
|
+
const angleRad = (angle * Math.PI) / 180;
|
|
143
|
+
const length = 500;
|
|
144
|
+
const endX = startX + length * Math.cos(angleRad);
|
|
145
|
+
const endY = startY - length * Math.sin(angleRad);
|
|
146
|
+
// Draw ray line
|
|
147
|
+
elements.push(line(startX, startY, endX, endY, {
|
|
148
|
+
stroke: color,
|
|
149
|
+
'stroke-width': 2.5,
|
|
150
|
+
'marker-end': `url(#ray-${color})`,
|
|
151
|
+
opacity: 0.8,
|
|
152
|
+
}));
|
|
153
|
+
// Add label
|
|
154
|
+
if (label) {
|
|
155
|
+
const labelX = startX + 30 * Math.cos(angleRad);
|
|
156
|
+
const labelY = startY - 30 * Math.sin(angleRad);
|
|
157
|
+
elements.push(text(labelX, labelY, label, {
|
|
158
|
+
'text-anchor': 'start',
|
|
159
|
+
'dominant-baseline': 'middle',
|
|
160
|
+
'font-size': 12,
|
|
161
|
+
fill: color,
|
|
162
|
+
'font-weight': 'bold',
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
return svgTag('g', { class: 'ray' }, elements.join(''));
|
|
166
|
+
}
|
|
167
|
+
function createRayMarkers() {
|
|
168
|
+
return `
|
|
169
|
+
<defs>
|
|
170
|
+
<marker id="ray-#FFD700" markerWidth="10" markerHeight="10" refX="9" refY="5" orient="auto">
|
|
171
|
+
<path d="M0,0 L10,5 L0,10" fill="#FFD700" />
|
|
172
|
+
</marker>
|
|
173
|
+
<marker id="ray-#FF6347" markerWidth="10" markerHeight="10" refX="9" refY="5" orient="auto">
|
|
174
|
+
<path d="M0,0 L10,5 L0,10" fill="#FF6347" />
|
|
175
|
+
</marker>
|
|
176
|
+
<marker id="ray-#32CD32" markerWidth="10" markerHeight="10" refX="9" refY="5" orient="auto">
|
|
177
|
+
<path d="M0,0 L10,5 L0,10" fill="#32CD32" />
|
|
178
|
+
</marker>
|
|
179
|
+
</defs>
|
|
180
|
+
`;
|
|
181
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"venn.d.ts","sourceRoot":"","sources":["../../src/renderers/venn.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAyB,MAAM,UAAU,CAAC;AAI/D,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAqB/C"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Venn diagram renderer
|
|
2
|
+
import { svgTag } from '../utils/svgTag';
|
|
3
|
+
import { circle as svgCircle, text } from '../utils/shapes';
|
|
4
|
+
export function renderVenn(dsl) {
|
|
5
|
+
const { width, height, circles, labels, title } = dsl;
|
|
6
|
+
const elements = [];
|
|
7
|
+
// Render circles with transparency
|
|
8
|
+
circles.forEach(vennCircle => {
|
|
9
|
+
elements.push(renderCircle(vennCircle));
|
|
10
|
+
});
|
|
11
|
+
// Render labels
|
|
12
|
+
labels.forEach(label => {
|
|
13
|
+
elements.push(renderLabel(label));
|
|
14
|
+
});
|
|
15
|
+
const svg = svgTag('svg', {
|
|
16
|
+
viewBox: `0 0 ${width} ${height}`,
|
|
17
|
+
xmlns: 'http://www.w3.org/2000/svg',
|
|
18
|
+
}, elements.join(''));
|
|
19
|
+
return svg;
|
|
20
|
+
}
|
|
21
|
+
function renderCircle(vennCircle) {
|
|
22
|
+
const { label, cx, cy, r, color } = vennCircle;
|
|
23
|
+
// Convert hex color to rgba for transparency
|
|
24
|
+
const rgb = hexToRgb(color);
|
|
25
|
+
const fillColor = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.3)`;
|
|
26
|
+
return svgTag('g', { class: 'venn-circle' }, svgCircle(cx, cy, r, {
|
|
27
|
+
fill: fillColor,
|
|
28
|
+
stroke: color,
|
|
29
|
+
'stroke-width': 2,
|
|
30
|
+
}) +
|
|
31
|
+
text(cx, cy, label, {
|
|
32
|
+
'text-anchor': 'middle',
|
|
33
|
+
'dominant-baseline': 'middle',
|
|
34
|
+
'font-size': 16,
|
|
35
|
+
'font-weight': 'bold',
|
|
36
|
+
fill: color,
|
|
37
|
+
}));
|
|
38
|
+
}
|
|
39
|
+
function renderLabel(label) {
|
|
40
|
+
const { text: labelText, x, y, region } = label;
|
|
41
|
+
return svgTag('g', { class: 'venn-label' }, text(x, y, labelText, {
|
|
42
|
+
'text-anchor': 'middle',
|
|
43
|
+
'dominant-baseline': 'middle',
|
|
44
|
+
'font-size': 14,
|
|
45
|
+
fill: '#333',
|
|
46
|
+
}));
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Convert hex color to RGB
|
|
50
|
+
*/
|
|
51
|
+
function hexToRgb(hex) {
|
|
52
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
53
|
+
return result
|
|
54
|
+
? {
|
|
55
|
+
r: parseInt(result[1], 16),
|
|
56
|
+
g: parseInt(result[2], 16),
|
|
57
|
+
b: parseInt(result[3], 16),
|
|
58
|
+
}
|
|
59
|
+
: { r: 0, g: 0, b: 0 };
|
|
60
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base figure DSL structure
|
|
3
|
+
*/
|
|
4
|
+
export interface FigureDSL {
|
|
5
|
+
type: FigureType;
|
|
6
|
+
width: number;
|
|
7
|
+
height: number;
|
|
8
|
+
title?: string;
|
|
9
|
+
alt?: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Supported figure types
|
|
13
|
+
*/
|
|
14
|
+
export type FigureType = 'circuit' | 'rayDiagram' | 'forceDiagram' | 'geometry' | 'coordinatePlane' | 'numberLine' | 'graph' | 'venn' | 'bioTable';
|
|
15
|
+
/**
|
|
16
|
+
* Circuit diagram DSL
|
|
17
|
+
*/
|
|
18
|
+
export interface CircuitDSL extends FigureDSL {
|
|
19
|
+
type: 'circuit';
|
|
20
|
+
components: CircuitComponent[];
|
|
21
|
+
}
|
|
22
|
+
export interface CircuitComponent {
|
|
23
|
+
type: 'battery' | 'resistor' | 'switch' | 'bulb' | 'wire' | 'ammeter' | 'voltmeter';
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
rotation?: number;
|
|
27
|
+
label?: string;
|
|
28
|
+
value?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Ray diagram DSL
|
|
32
|
+
*/
|
|
33
|
+
export interface RayDiagramDSL extends FigureDSL {
|
|
34
|
+
type: 'rayDiagram';
|
|
35
|
+
opticalElements: OpticalElement[];
|
|
36
|
+
rays: Ray[];
|
|
37
|
+
}
|
|
38
|
+
export interface OpticalElement {
|
|
39
|
+
type: 'lens' | 'mirror' | 'prism' | 'screen';
|
|
40
|
+
x: number;
|
|
41
|
+
y: number;
|
|
42
|
+
width?: number;
|
|
43
|
+
height?: number;
|
|
44
|
+
focalLength?: number;
|
|
45
|
+
curvature?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface Ray {
|
|
48
|
+
startX: number;
|
|
49
|
+
startY: number;
|
|
50
|
+
angle: number;
|
|
51
|
+
color?: string;
|
|
52
|
+
label?: string;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Force diagram DSL
|
|
56
|
+
*/
|
|
57
|
+
export interface ForceDiagramDSL extends FigureDSL {
|
|
58
|
+
type: 'forceDiagram';
|
|
59
|
+
object: PhysicalObject;
|
|
60
|
+
forces: Force[];
|
|
61
|
+
}
|
|
62
|
+
export interface PhysicalObject {
|
|
63
|
+
type: 'box' | 'sphere' | 'point';
|
|
64
|
+
x: number;
|
|
65
|
+
y: number;
|
|
66
|
+
width?: number;
|
|
67
|
+
height?: number;
|
|
68
|
+
label?: string;
|
|
69
|
+
}
|
|
70
|
+
export interface Force {
|
|
71
|
+
originX: number;
|
|
72
|
+
originY: number;
|
|
73
|
+
magnitude: number;
|
|
74
|
+
angle: number;
|
|
75
|
+
label: string;
|
|
76
|
+
color?: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Geometry DSL
|
|
80
|
+
*/
|
|
81
|
+
export interface GeometryDSL extends FigureDSL {
|
|
82
|
+
type: 'geometry';
|
|
83
|
+
shapes: GeometryShape[];
|
|
84
|
+
}
|
|
85
|
+
export type GeometryShape = {
|
|
86
|
+
type: 'line';
|
|
87
|
+
x1: number;
|
|
88
|
+
y1: number;
|
|
89
|
+
x2: number;
|
|
90
|
+
y2: number;
|
|
91
|
+
label?: string;
|
|
92
|
+
} | {
|
|
93
|
+
type: 'circle';
|
|
94
|
+
cx: number;
|
|
95
|
+
cy: number;
|
|
96
|
+
r: number;
|
|
97
|
+
label?: string;
|
|
98
|
+
} | {
|
|
99
|
+
type: 'rect';
|
|
100
|
+
x: number;
|
|
101
|
+
y: number;
|
|
102
|
+
width: number;
|
|
103
|
+
height: number;
|
|
104
|
+
label?: string;
|
|
105
|
+
} | {
|
|
106
|
+
type: 'triangle';
|
|
107
|
+
points: [number, number][];
|
|
108
|
+
label?: string;
|
|
109
|
+
} | {
|
|
110
|
+
type: 'angle';
|
|
111
|
+
vertex: [number, number];
|
|
112
|
+
rays: [[number, number], [number, number]];
|
|
113
|
+
label?: string;
|
|
114
|
+
};
|
|
115
|
+
/**
|
|
116
|
+
* Coordinate plane DSL
|
|
117
|
+
*/
|
|
118
|
+
export interface CoordinatePlaneDSL extends FigureDSL {
|
|
119
|
+
type: 'coordinatePlane';
|
|
120
|
+
xRange: [number, number];
|
|
121
|
+
yRange: [number, number];
|
|
122
|
+
showGrid?: boolean;
|
|
123
|
+
showLabels?: boolean;
|
|
124
|
+
elements: PlaneElement[];
|
|
125
|
+
}
|
|
126
|
+
export interface PlaneElement {
|
|
127
|
+
type: 'point' | 'line' | 'curve' | 'label';
|
|
128
|
+
data: PointElementData | LineElementData | CurveElementData | LabelElementData;
|
|
129
|
+
}
|
|
130
|
+
export interface PointElementData {
|
|
131
|
+
x: number;
|
|
132
|
+
y: number;
|
|
133
|
+
label?: string;
|
|
134
|
+
color?: string;
|
|
135
|
+
}
|
|
136
|
+
export interface LineElementData {
|
|
137
|
+
x1: number;
|
|
138
|
+
y1: number;
|
|
139
|
+
x2: number;
|
|
140
|
+
y2: number;
|
|
141
|
+
color?: string;
|
|
142
|
+
style?: 'solid' | 'dashed' | 'dotted';
|
|
143
|
+
}
|
|
144
|
+
export interface CurveElementData {
|
|
145
|
+
points: [number, number][];
|
|
146
|
+
color?: string;
|
|
147
|
+
style?: 'solid' | 'dashed' | 'dotted';
|
|
148
|
+
}
|
|
149
|
+
export interface LabelElementData {
|
|
150
|
+
x: number;
|
|
151
|
+
y: number;
|
|
152
|
+
text: string;
|
|
153
|
+
align?: 'left' | 'center' | 'right';
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Number line DSL
|
|
157
|
+
*/
|
|
158
|
+
export interface NumberLineDSL extends FigureDSL {
|
|
159
|
+
type: 'numberLine';
|
|
160
|
+
range: [number, number];
|
|
161
|
+
ticks: number[];
|
|
162
|
+
marks: NumberLineMark[];
|
|
163
|
+
arrowEnds?: 'left' | 'right' | 'both' | 'none';
|
|
164
|
+
}
|
|
165
|
+
export interface NumberLineMark {
|
|
166
|
+
value: number;
|
|
167
|
+
label: string;
|
|
168
|
+
style?: 'open' | 'closed' | 'arrow';
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Graph DSL
|
|
172
|
+
*/
|
|
173
|
+
export interface GraphDSL extends FigureDSL {
|
|
174
|
+
type: 'graph';
|
|
175
|
+
xRange: [number, number];
|
|
176
|
+
yRange: [number, number];
|
|
177
|
+
functions: GraphFunction[];
|
|
178
|
+
}
|
|
179
|
+
export interface GraphFunction {
|
|
180
|
+
equation: string;
|
|
181
|
+
color: string;
|
|
182
|
+
style?: 'solid' | 'dashed' | 'dotted';
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Venn diagram DSL
|
|
186
|
+
*/
|
|
187
|
+
export interface VennDSL extends FigureDSL {
|
|
188
|
+
type: 'venn';
|
|
189
|
+
circles: VennCircle[];
|
|
190
|
+
labels: VennLabel[];
|
|
191
|
+
}
|
|
192
|
+
export interface VennCircle {
|
|
193
|
+
label: string;
|
|
194
|
+
cx: number;
|
|
195
|
+
cy: number;
|
|
196
|
+
r: number;
|
|
197
|
+
color: string;
|
|
198
|
+
}
|
|
199
|
+
export interface VennLabel {
|
|
200
|
+
text: string;
|
|
201
|
+
x: number;
|
|
202
|
+
y: number;
|
|
203
|
+
region: string;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Biology table DSL
|
|
207
|
+
*/
|
|
208
|
+
export interface BioTableDSL extends FigureDSL {
|
|
209
|
+
type: 'bioTable';
|
|
210
|
+
columns: BioColumn[];
|
|
211
|
+
rows: BioRow[];
|
|
212
|
+
}
|
|
213
|
+
export interface BioColumn {
|
|
214
|
+
header: string;
|
|
215
|
+
width: number;
|
|
216
|
+
}
|
|
217
|
+
export interface BioRow {
|
|
218
|
+
cells: (string | BioCellImage)[];
|
|
219
|
+
}
|
|
220
|
+
export interface BioCellImage {
|
|
221
|
+
type: 'image';
|
|
222
|
+
src: string;
|
|
223
|
+
alt: string;
|
|
224
|
+
}
|
|
225
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate arrow marker definition for SVG
|
|
3
|
+
* @param id - Marker ID for referencing
|
|
4
|
+
* @param color - Arrow color
|
|
5
|
+
* @param size - Arrow size
|
|
6
|
+
* @returns SVG marker definition
|
|
7
|
+
*/
|
|
8
|
+
export declare function arrowMarker(id: string, color?: string, size?: number): string;
|
|
9
|
+
/**
|
|
10
|
+
* Generate multiple arrow markers with different colors
|
|
11
|
+
*/
|
|
12
|
+
export declare function createArrowMarkers(): string;
|
|
13
|
+
//# sourceMappingURL=arrowMarker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arrowMarker.d.ts","sourceRoot":"","sources":["../../src/utils/arrowMarker.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,GAAE,MAAe,EAAE,IAAI,GAAE,MAAW,GAAG,MAAM,CAkBzF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAiB3C"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Arrow marker utility
|
|
2
|
+
/**
|
|
3
|
+
* Generate arrow marker definition for SVG
|
|
4
|
+
* @param id - Marker ID for referencing
|
|
5
|
+
* @param color - Arrow color
|
|
6
|
+
* @param size - Arrow size
|
|
7
|
+
* @returns SVG marker definition
|
|
8
|
+
*/
|
|
9
|
+
export function arrowMarker(id, color = '#000', size = 10) {
|
|
10
|
+
return `
|
|
11
|
+
<defs>
|
|
12
|
+
<marker
|
|
13
|
+
id="${id}"
|
|
14
|
+
markerWidth="${size}"
|
|
15
|
+
markerHeight="${size}"
|
|
16
|
+
refX="${size - 2}"
|
|
17
|
+
refY="${size / 2}"
|
|
18
|
+
orient="auto"
|
|
19
|
+
>
|
|
20
|
+
<path
|
|
21
|
+
d="M0,0 L${size},${size / 2} L0,${size}"
|
|
22
|
+
fill="${color}"
|
|
23
|
+
/>
|
|
24
|
+
</marker>
|
|
25
|
+
</defs>
|
|
26
|
+
`;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Generate multiple arrow markers with different colors
|
|
30
|
+
*/
|
|
31
|
+
export function createArrowMarkers() {
|
|
32
|
+
return `
|
|
33
|
+
<defs>
|
|
34
|
+
<marker id="arrow-default" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto">
|
|
35
|
+
<path d="M0,0 L10,5 L0,10" fill="#000" />
|
|
36
|
+
</marker>
|
|
37
|
+
<marker id="arrow-red" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto">
|
|
38
|
+
<path d="M0,0 L10,5 L0,10" fill="#e53e3e" />
|
|
39
|
+
</marker>
|
|
40
|
+
<marker id="arrow-blue" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto">
|
|
41
|
+
<path d="M0,0 L10,5 L0,10" fill="#3182ce" />
|
|
42
|
+
</marker>
|
|
43
|
+
<marker id="arrow-green" markerWidth="10" markerHeight="10" refX="8" refY="5" orient="auto">
|
|
44
|
+
<path d="M0,0 L10,5 L0,10" fill="#38a169" />
|
|
45
|
+
</marker>
|
|
46
|
+
</defs>
|
|
47
|
+
`;
|
|
48
|
+
}
|