@nice2dev/ui-math 1.0.11 → 1.0.12
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/dist/index.cjs +5 -5
- package/dist/index.mjs +411 -411
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -267,16 +267,16 @@ class MathEditorService {
|
|
|
267
267
|
}
|
|
268
268
|
/** Update equation */
|
|
269
269
|
updateEquation(t, r, a) {
|
|
270
|
-
const
|
|
271
|
-
if (!
|
|
270
|
+
const n = this.equations.get(t);
|
|
271
|
+
if (!n)
|
|
272
272
|
throw new Error(`Equation not found: ${t}`);
|
|
273
|
-
const
|
|
274
|
-
...
|
|
273
|
+
const o = {
|
|
274
|
+
...n,
|
|
275
275
|
latex: r,
|
|
276
|
-
label: a ??
|
|
276
|
+
label: a ?? n.label,
|
|
277
277
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
278
278
|
};
|
|
279
|
-
return this.equations.set(t,
|
|
279
|
+
return this.equations.set(t, o), o;
|
|
280
280
|
}
|
|
281
281
|
/** Delete equation */
|
|
282
282
|
deleteEquation(t) {
|
|
@@ -310,12 +310,12 @@ class MathEditorService {
|
|
|
310
310
|
/** Parse LaTeX and extract equations */
|
|
311
311
|
parseLatex(t) {
|
|
312
312
|
const r = [], a = /\\\[([\s\S]*?)\\\]/g;
|
|
313
|
-
let
|
|
314
|
-
for (; (
|
|
315
|
-
r.push(this.createEquation(
|
|
316
|
-
const
|
|
317
|
-
for (; (
|
|
318
|
-
const s =
|
|
313
|
+
let n;
|
|
314
|
+
for (; (n = a.exec(t)) !== null; )
|
|
315
|
+
r.push(this.createEquation(n[1].trim()));
|
|
316
|
+
const o = /\\begin\{equation\}([\s\S]*?)\\end\{equation\}/g;
|
|
317
|
+
for (; (n = o.exec(t)) !== null; ) {
|
|
318
|
+
const s = n[1].match(/\\label\{([^}]+)\}/), c = n[1].replace(/\\label\{[^}]+\}/, "").trim();
|
|
319
319
|
r.push(this.createEquation(c, s == null ? void 0 : s[1]));
|
|
320
320
|
}
|
|
321
321
|
return r;
|
|
@@ -353,8 +353,8 @@ const styles$3 = {
|
|
|
353
353
|
display: "flex",
|
|
354
354
|
gap: "8px",
|
|
355
355
|
padding: "8px",
|
|
356
|
-
borderBottom: "1px solid #e0e0e0",
|
|
357
|
-
backgroundColor: "#fafafa",
|
|
356
|
+
borderBottom: "1px solid var(--nice-border, #e0e0e0)",
|
|
357
|
+
backgroundColor: "var(--nice-bg-secondary, #fafafa)",
|
|
358
358
|
flexWrap: "wrap",
|
|
359
359
|
alignItems: "center"
|
|
360
360
|
},
|
|
@@ -365,9 +365,9 @@ const styles$3 = {
|
|
|
365
365
|
},
|
|
366
366
|
sidebar: {
|
|
367
367
|
width: "200px",
|
|
368
|
-
borderRight: "1px solid #e0e0e0",
|
|
368
|
+
borderRight: "1px solid var(--nice-border, #e0e0e0)",
|
|
369
369
|
overflow: "auto",
|
|
370
|
-
backgroundColor: "#f5f5f5"
|
|
370
|
+
backgroundColor: "var(--nice-bg-secondary, #f5f5f5)"
|
|
371
371
|
},
|
|
372
372
|
editor: {
|
|
373
373
|
flex: 1,
|
|
@@ -382,15 +382,15 @@ const styles$3 = {
|
|
|
382
382
|
padding: "12px",
|
|
383
383
|
fontFamily: "'JetBrains Mono', monospace",
|
|
384
384
|
fontSize: "14px",
|
|
385
|
-
border: "1px solid #ddd",
|
|
385
|
+
border: "1px solid var(--nice-border, #ddd)",
|
|
386
386
|
borderRadius: "4px",
|
|
387
387
|
resize: "vertical"
|
|
388
388
|
},
|
|
389
389
|
preview: {
|
|
390
390
|
marginTop: "16px",
|
|
391
391
|
padding: "20px",
|
|
392
|
-
backgroundColor: "#fff",
|
|
393
|
-
border: "1px solid #e0e0e0",
|
|
392
|
+
backgroundColor: "var(--nice-bg, #fff)",
|
|
393
|
+
border: "1px solid var(--nice-border, #e0e0e0)",
|
|
394
394
|
borderRadius: "4px",
|
|
395
395
|
minHeight: "60px",
|
|
396
396
|
fontSize: "20px",
|
|
@@ -398,7 +398,7 @@ const styles$3 = {
|
|
|
398
398
|
},
|
|
399
399
|
button: {
|
|
400
400
|
padding: "6px 12px",
|
|
401
|
-
backgroundColor: "#1976d2",
|
|
401
|
+
backgroundColor: "var(--nice-primary-hover, #1976d2)",
|
|
402
402
|
color: "white",
|
|
403
403
|
border: "none",
|
|
404
404
|
borderRadius: "4px",
|
|
@@ -413,16 +413,16 @@ const styles$3 = {
|
|
|
413
413
|
},
|
|
414
414
|
symbolButton: {
|
|
415
415
|
padding: "8px",
|
|
416
|
-
border: "1px solid #ddd",
|
|
416
|
+
border: "1px solid var(--nice-border, #ddd)",
|
|
417
417
|
borderRadius: "4px",
|
|
418
|
-
backgroundColor: "#fff",
|
|
418
|
+
backgroundColor: "var(--nice-bg, #fff)",
|
|
419
419
|
cursor: "pointer",
|
|
420
420
|
fontSize: "16px",
|
|
421
421
|
textAlign: "center"
|
|
422
422
|
},
|
|
423
423
|
categoryHeader: {
|
|
424
424
|
padding: "8px 12px",
|
|
425
|
-
backgroundColor: "#e0e0e0",
|
|
425
|
+
backgroundColor: "var(--nice-border, #e0e0e0)",
|
|
426
426
|
fontWeight: 600,
|
|
427
427
|
fontSize: "12px",
|
|
428
428
|
textTransform: "uppercase"
|
|
@@ -430,9 +430,9 @@ const styles$3 = {
|
|
|
430
430
|
canvas: {
|
|
431
431
|
width: "100%",
|
|
432
432
|
height: "200px",
|
|
433
|
-
border: "1px solid #ddd",
|
|
433
|
+
border: "1px solid var(--nice-border, #ddd)",
|
|
434
434
|
borderRadius: "4px",
|
|
435
|
-
backgroundColor: "#fff",
|
|
435
|
+
backgroundColor: "var(--nice-bg, #fff)",
|
|
436
436
|
cursor: "crosshair"
|
|
437
437
|
}
|
|
438
438
|
};
|
|
@@ -441,9 +441,9 @@ function NiceMathEditor({
|
|
|
441
441
|
initialLatex: t = "",
|
|
442
442
|
onChange: r,
|
|
443
443
|
className: a,
|
|
444
|
-
style:
|
|
444
|
+
style: n
|
|
445
445
|
}) {
|
|
446
|
-
const [
|
|
446
|
+
const [o, s] = useState(t), [c, l] = useState("input"), i = useRef(null), d = useCallback(
|
|
447
447
|
(y) => {
|
|
448
448
|
s(y), r == null || r(y);
|
|
449
449
|
},
|
|
@@ -452,15 +452,15 @@ function NiceMathEditor({
|
|
|
452
452
|
(y) => {
|
|
453
453
|
const g = i.current;
|
|
454
454
|
if (!g) {
|
|
455
|
-
d(
|
|
455
|
+
d(o + y);
|
|
456
456
|
return;
|
|
457
457
|
}
|
|
458
|
-
const m = g.selectionStart, p = g.selectionEnd, x =
|
|
458
|
+
const m = g.selectionStart, p = g.selectionEnd, x = o.slice(0, m) + y + o.slice(p);
|
|
459
459
|
d(x), setTimeout(() => {
|
|
460
460
|
g.focus(), g.selectionStart = g.selectionEnd = m + y.length;
|
|
461
461
|
}, 0);
|
|
462
462
|
},
|
|
463
|
-
[
|
|
463
|
+
[o, d]
|
|
464
464
|
), h = useCallback(
|
|
465
465
|
(y) => {
|
|
466
466
|
u(y.latex);
|
|
@@ -468,14 +468,14 @@ function NiceMathEditor({
|
|
|
468
468
|
[u]
|
|
469
469
|
), b = {
|
|
470
470
|
service: e,
|
|
471
|
-
latex:
|
|
471
|
+
latex: o,
|
|
472
472
|
setLatex: d,
|
|
473
473
|
insertSymbol: u,
|
|
474
474
|
insertTemplate: h,
|
|
475
475
|
mode: c,
|
|
476
476
|
setMode: l
|
|
477
477
|
};
|
|
478
|
-
return /* @__PURE__ */ jsx(MathEditorContext.Provider, { value: b, children: /* @__PURE__ */ jsxs("div", { className: a, style: { ...styles$3.container, ...
|
|
478
|
+
return /* @__PURE__ */ jsx(MathEditorContext.Provider, { value: b, children: /* @__PURE__ */ jsxs("div", { className: a, style: { ...styles$3.container, ...n }, children: [
|
|
479
479
|
/* @__PURE__ */ jsx(Toolbar$1, {}),
|
|
480
480
|
/* @__PURE__ */ jsxs("div", { style: styles$3.main, children: [
|
|
481
481
|
/* @__PURE__ */ jsx(SymbolPalette, {}),
|
|
@@ -484,19 +484,19 @@ function NiceMathEditor({
|
|
|
484
484
|
"textarea",
|
|
485
485
|
{
|
|
486
486
|
ref: i,
|
|
487
|
-
value:
|
|
487
|
+
value: o,
|
|
488
488
|
onChange: (y) => d(y.target.value),
|
|
489
489
|
placeholder: "Enter LaTeX equation...",
|
|
490
490
|
style: styles$3.input
|
|
491
491
|
}
|
|
492
492
|
),
|
|
493
|
-
/* @__PURE__ */ jsx(LatexPreview, { latex:
|
|
493
|
+
/* @__PURE__ */ jsx(LatexPreview, { latex: o })
|
|
494
494
|
] }) : /* @__PURE__ */ jsx(HandwritingCanvas, {}) })
|
|
495
495
|
] })
|
|
496
496
|
] }) });
|
|
497
497
|
}
|
|
498
498
|
function Toolbar$1() {
|
|
499
|
-
const { mode: e, setMode: t, latex: r, insertTemplate: a } = useMathEditor(), [
|
|
499
|
+
const { mode: e, setMode: t, latex: r, insertTemplate: a } = useMathEditor(), [n, o] = useState(!1);
|
|
500
500
|
return /* @__PURE__ */ jsxs("div", { style: styles$3.toolbar, children: [
|
|
501
501
|
/* @__PURE__ */ jsx(
|
|
502
502
|
"button",
|
|
@@ -504,7 +504,7 @@ function Toolbar$1() {
|
|
|
504
504
|
onClick: () => t("input"),
|
|
505
505
|
style: {
|
|
506
506
|
...styles$3.button,
|
|
507
|
-
backgroundColor: e === "input" ? "#1976d2" : "#9e9e9e"
|
|
507
|
+
backgroundColor: e === "input" ? "var(--nice-primary-hover, #1976d2)" : "var(--nice-text-secondary, #9e9e9e)"
|
|
508
508
|
},
|
|
509
509
|
children: "⌨️ LaTeX Input"
|
|
510
510
|
}
|
|
@@ -515,25 +515,25 @@ function Toolbar$1() {
|
|
|
515
515
|
onClick: () => t("handwriting"),
|
|
516
516
|
style: {
|
|
517
517
|
...styles$3.button,
|
|
518
|
-
backgroundColor: e === "handwriting" ? "#1976d2" : "#9e9e9e"
|
|
518
|
+
backgroundColor: e === "handwriting" ? "var(--nice-primary-hover, #1976d2)" : "var(--nice-text-secondary, #9e9e9e)"
|
|
519
519
|
},
|
|
520
520
|
children: "✏️ Handwriting"
|
|
521
521
|
}
|
|
522
522
|
),
|
|
523
|
-
/* @__PURE__ */ jsx("div", { style: { borderLeft: "1px solid #ccc", height: "24px", margin: "0 8px" } }),
|
|
523
|
+
/* @__PURE__ */ jsx("div", { style: { borderLeft: "1px solid var(--nice-border, #ccc)", height: "24px", margin: "0 8px" } }),
|
|
524
524
|
/* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
|
|
525
|
-
/* @__PURE__ */ jsx("button", { onClick: () =>
|
|
526
|
-
|
|
525
|
+
/* @__PURE__ */ jsx("button", { onClick: () => o(!n), style: styles$3.button, children: "📐 Templates ▾" }),
|
|
526
|
+
n && /* @__PURE__ */ jsx(
|
|
527
527
|
"div",
|
|
528
528
|
{
|
|
529
529
|
style: {
|
|
530
530
|
position: "absolute",
|
|
531
531
|
top: "100%",
|
|
532
532
|
left: 0,
|
|
533
|
-
backgroundColor: "#fff",
|
|
534
|
-
border: "1px solid #ddd",
|
|
533
|
+
backgroundColor: "var(--nice-bg, #fff)",
|
|
534
|
+
border: "1px solid var(--nice-border, #ddd)",
|
|
535
535
|
borderRadius: "4px",
|
|
536
|
-
boxShadow: "0 2px 8px rgba(0,0,0,0.15)",
|
|
536
|
+
boxShadow: "0 2px 8px var(--nice-overlay-15, rgba(0, 0, 0, 0.15))",
|
|
537
537
|
zIndex: 100,
|
|
538
538
|
width: "300px",
|
|
539
539
|
maxHeight: "400px",
|
|
@@ -546,18 +546,18 @@ function Toolbar$1() {
|
|
|
546
546
|
"div",
|
|
547
547
|
{
|
|
548
548
|
onClick: () => {
|
|
549
|
-
a(c),
|
|
549
|
+
a(c), o(!1);
|
|
550
550
|
},
|
|
551
551
|
style: {
|
|
552
552
|
padding: "8px 12px",
|
|
553
553
|
cursor: "pointer",
|
|
554
|
-
borderBottom: "1px solid #eee"
|
|
554
|
+
borderBottom: "1px solid var(--nice-border, #eee)"
|
|
555
555
|
},
|
|
556
|
-
onMouseOver: (l) => l.target.style.backgroundColor = "#f5f5f5",
|
|
556
|
+
onMouseOver: (l) => l.target.style.backgroundColor = "var(--nice-bg-secondary, #f5f5f5)",
|
|
557
557
|
onMouseOut: (l) => l.target.style.backgroundColor = "transparent",
|
|
558
558
|
children: [
|
|
559
559
|
/* @__PURE__ */ jsx("div", { style: { fontWeight: 500 }, children: c.name }),
|
|
560
|
-
/* @__PURE__ */ jsxs("div", { style: { fontSize: "12px", color: "#666", fontFamily: "monospace" }, children: [
|
|
560
|
+
/* @__PURE__ */ jsxs("div", { style: { fontSize: "12px", color: "var(--nice-text-secondary, #666)", fontFamily: "monospace" }, children: [
|
|
561
561
|
c.latex.substring(0, 40),
|
|
562
562
|
c.latex.length > 40 ? "..." : ""
|
|
563
563
|
] })
|
|
@@ -575,7 +575,7 @@ function Toolbar$1() {
|
|
|
575
575
|
"button",
|
|
576
576
|
{
|
|
577
577
|
onClick: () => navigator.clipboard.writeText(r),
|
|
578
|
-
style: { ...styles$3.button, backgroundColor: "#4caf50" },
|
|
578
|
+
style: { ...styles$3.button, backgroundColor: "var(--nice-success, #4caf50)" },
|
|
579
579
|
children: "📋 Copy LaTeX"
|
|
580
580
|
}
|
|
581
581
|
)
|
|
@@ -594,45 +594,45 @@ function SymbolPalette() {
|
|
|
594
594
|
"logic",
|
|
595
595
|
"calculus",
|
|
596
596
|
"matrices"
|
|
597
|
-
],
|
|
597
|
+
], n = getSymbolsByCategory(t);
|
|
598
598
|
return /* @__PURE__ */ jsxs("div", { style: styles$3.sidebar, children: [
|
|
599
|
-
/* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", padding: "8px", gap: "4px" }, children: a.map((
|
|
599
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", flexWrap: "wrap", padding: "8px", gap: "4px" }, children: a.map((o) => /* @__PURE__ */ jsx(
|
|
600
600
|
"button",
|
|
601
601
|
{
|
|
602
|
-
onClick: () => r(
|
|
602
|
+
onClick: () => r(o),
|
|
603
603
|
style: {
|
|
604
604
|
padding: "4px 8px",
|
|
605
605
|
fontSize: "11px",
|
|
606
|
-
border: "1px solid #ddd",
|
|
606
|
+
border: "1px solid var(--nice-border, #ddd)",
|
|
607
607
|
borderRadius: "4px",
|
|
608
|
-
backgroundColor: t ===
|
|
609
|
-
color: t ===
|
|
608
|
+
backgroundColor: t === o ? "var(--nice-primary-hover, #1976d2)" : "var(--nice-bg, #fff)",
|
|
609
|
+
color: t === o ? "var(--nice-bg, #fff)" : "var(--nice-text, #333)",
|
|
610
610
|
cursor: "pointer"
|
|
611
611
|
},
|
|
612
|
-
children:
|
|
612
|
+
children: o
|
|
613
613
|
},
|
|
614
|
-
|
|
614
|
+
o
|
|
615
615
|
)) }),
|
|
616
|
-
/* @__PURE__ */ jsx("div", { style: styles$3.symbolGrid, children:
|
|
616
|
+
/* @__PURE__ */ jsx("div", { style: styles$3.symbolGrid, children: n.map((o) => /* @__PURE__ */ jsx(
|
|
617
617
|
"button",
|
|
618
618
|
{
|
|
619
|
-
onClick: () => e(
|
|
619
|
+
onClick: () => e(o.latex),
|
|
620
620
|
style: styles$3.symbolButton,
|
|
621
|
-
title: `${
|
|
622
|
-
children:
|
|
621
|
+
title: `${o.name}: ${o.latex}`,
|
|
622
|
+
children: o.preview || o.latex
|
|
623
623
|
},
|
|
624
|
-
|
|
624
|
+
o.name
|
|
625
625
|
)) })
|
|
626
626
|
] });
|
|
627
627
|
}
|
|
628
628
|
function LatexPreview({ latex: e }) {
|
|
629
629
|
return /* @__PURE__ */ jsxs("div", { style: styles$3.preview, children: [
|
|
630
|
-
/* @__PURE__ */ jsx("div", { style: { fontSize: "12px", color: "#666", marginBottom: "8px" }, children: "Preview (requires KaTeX/MathJax integration):" }),
|
|
630
|
+
/* @__PURE__ */ jsx("div", { style: { fontSize: "12px", color: "var(--nice-text-secondary, #666)", marginBottom: "8px" }, children: "Preview (requires KaTeX/MathJax integration):" }),
|
|
631
631
|
/* @__PURE__ */ jsx("code", { style: { fontSize: "16px" }, children: e || "(empty)" })
|
|
632
632
|
] });
|
|
633
633
|
}
|
|
634
634
|
function HandwritingCanvas() {
|
|
635
|
-
const { setLatex: e, setMode: t } = useMathEditor(), r = useRef(null), [a,
|
|
635
|
+
const { setLatex: e, setMode: t } = useMathEditor(), r = useRef(null), [a, n] = useState([]), [o, s] = useState([]), [c, l] = useState(!1), [i, d] = useState(!1), u = (m) => {
|
|
636
636
|
const p = r.current;
|
|
637
637
|
if (!p)
|
|
638
638
|
return;
|
|
@@ -658,24 +658,24 @@ function HandwritingCanvas() {
|
|
|
658
658
|
pressure: m.pressure,
|
|
659
659
|
timestamp: Date.now()
|
|
660
660
|
};
|
|
661
|
-
if (s((f) => [...f, k]),
|
|
662
|
-
const f =
|
|
663
|
-
x.beginPath(), x.moveTo(f.x, f.y), x.lineTo(k.x, k.y), x.strokeStyle = "#000", x.lineWidth = 2, x.lineCap = "round", x.stroke();
|
|
661
|
+
if (s((f) => [...f, k]), o.length > 0) {
|
|
662
|
+
const f = o[o.length - 1];
|
|
663
|
+
x.beginPath(), x.moveTo(f.x, f.y), x.lineTo(k.x, k.y), x.strokeStyle = "var(--nice-text, #000)", x.lineWidth = 2, x.lineCap = "round", x.stroke();
|
|
664
664
|
}
|
|
665
665
|
}, b = () => {
|
|
666
666
|
if (c) {
|
|
667
|
-
if (l(!1),
|
|
667
|
+
if (l(!1), o.length > 1) {
|
|
668
668
|
const m = {
|
|
669
669
|
id: Date.now().toString(),
|
|
670
|
-
points: [...
|
|
670
|
+
points: [...o]
|
|
671
671
|
};
|
|
672
|
-
|
|
672
|
+
n((p) => [...p, m]);
|
|
673
673
|
}
|
|
674
674
|
s([]);
|
|
675
675
|
}
|
|
676
676
|
}, y = () => {
|
|
677
677
|
const m = r.current, p = m == null ? void 0 : m.getContext("2d");
|
|
678
|
-
p && m && p.clearRect(0, 0, m.width, m.height),
|
|
678
|
+
p && m && p.clearRect(0, 0, m.width, m.height), n([]);
|
|
679
679
|
}, g = async () => {
|
|
680
680
|
if (a.length !== 0) {
|
|
681
681
|
d(!0);
|
|
@@ -703,7 +703,7 @@ function HandwritingCanvas() {
|
|
|
703
703
|
}
|
|
704
704
|
),
|
|
705
705
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", marginTop: "12px" }, children: [
|
|
706
|
-
/* @__PURE__ */ jsx("button", { onClick: y, style: { ...styles$3.button, backgroundColor: "#f44336" }, children: "Clear" }),
|
|
706
|
+
/* @__PURE__ */ jsx("button", { onClick: y, style: { ...styles$3.button, backgroundColor: "var(--nice-danger, #f44336)" }, children: "Clear" }),
|
|
707
707
|
/* @__PURE__ */ jsx(
|
|
708
708
|
"button",
|
|
709
709
|
{
|
|
@@ -714,7 +714,7 @@ function HandwritingCanvas() {
|
|
|
714
714
|
}
|
|
715
715
|
)
|
|
716
716
|
] }),
|
|
717
|
-
/* @__PURE__ */ jsx("p", { style: { fontSize: "12px", color: "#666", marginTop: "8px" }, children: "Draw your equation above. Handwriting recognition requires external API integration." })
|
|
717
|
+
/* @__PURE__ */ jsx("p", { style: { fontSize: "12px", color: "var(--nice-text-secondary, #666)", marginTop: "8px" }, children: "Draw your equation above. Handwriting recognition requires external API integration." })
|
|
718
718
|
] });
|
|
719
719
|
}
|
|
720
720
|
const mathConstants = {
|
|
@@ -816,10 +816,10 @@ class ExpressionParser {
|
|
|
816
816
|
const a = r[1];
|
|
817
817
|
if (this.pos += a.length, this.expr[this.pos] === "(") {
|
|
818
818
|
this.pos++;
|
|
819
|
-
const
|
|
819
|
+
const n = [];
|
|
820
820
|
for (; this.expr[this.pos] !== ")" && this.pos < this.expr.length; )
|
|
821
|
-
|
|
822
|
-
return this.expr[this.pos] === ")" && this.pos++, { type: "call", name: a, args:
|
|
821
|
+
n.push(this.parseAddSub()), this.expr[this.pos] === "," && this.pos++;
|
|
822
|
+
return this.expr[this.pos] === ")" && this.pos++, { type: "call", name: a, args: n };
|
|
823
823
|
}
|
|
824
824
|
return { type: "variable", name: a };
|
|
825
825
|
}
|
|
@@ -836,18 +836,18 @@ class ExpressionParser {
|
|
|
836
836
|
case "unary":
|
|
837
837
|
return t.op === "-" ? -this.evaluate(t.arg, r) : this.evaluate(t.arg, r);
|
|
838
838
|
case "binary": {
|
|
839
|
-
const a = this.evaluate(t.left, r),
|
|
839
|
+
const a = this.evaluate(t.left, r), n = this.evaluate(t.right, r);
|
|
840
840
|
switch (t.op) {
|
|
841
841
|
case "+":
|
|
842
|
-
return a +
|
|
842
|
+
return a + n;
|
|
843
843
|
case "-":
|
|
844
|
-
return a -
|
|
844
|
+
return a - n;
|
|
845
845
|
case "*":
|
|
846
|
-
return a *
|
|
846
|
+
return a * n;
|
|
847
847
|
case "/":
|
|
848
|
-
return a /
|
|
848
|
+
return a / n;
|
|
849
849
|
case "^":
|
|
850
|
-
return Math.pow(a,
|
|
850
|
+
return Math.pow(a, n);
|
|
851
851
|
default:
|
|
852
852
|
return 0;
|
|
853
853
|
}
|
|
@@ -856,8 +856,8 @@ class ExpressionParser {
|
|
|
856
856
|
const a = mathFunctions[t.name];
|
|
857
857
|
if (!a)
|
|
858
858
|
throw new Error(`Unknown function: ${t.name}`);
|
|
859
|
-
const
|
|
860
|
-
return a(...
|
|
859
|
+
const n = t.args.map((o) => this.evaluate(o, r));
|
|
860
|
+
return a(...n);
|
|
861
861
|
}
|
|
862
862
|
default:
|
|
863
863
|
return 0;
|
|
@@ -897,8 +897,8 @@ class GraphService {
|
|
|
897
897
|
const a = this.plots.get(t);
|
|
898
898
|
if (!a)
|
|
899
899
|
throw new Error(`Plot not found: ${t}`);
|
|
900
|
-
const
|
|
901
|
-
return this.plots.set(t,
|
|
900
|
+
const n = { ...a, ...r, id: a.id };
|
|
901
|
+
return this.plots.set(t, n), n;
|
|
902
902
|
}
|
|
903
903
|
/** Remove a plot */
|
|
904
904
|
removePlot(t) {
|
|
@@ -913,12 +913,12 @@ class GraphService {
|
|
|
913
913
|
return this.plots.get(t);
|
|
914
914
|
}
|
|
915
915
|
/** Compute 2D function points */
|
|
916
|
-
compute2DFunction(t, r, a,
|
|
917
|
-
const
|
|
916
|
+
compute2DFunction(t, r, a, n) {
|
|
917
|
+
const o = this.parser.parse(t), s = [], c = (r.max - r.min) / a;
|
|
918
918
|
for (let l = 0; l <= a; l++) {
|
|
919
919
|
const i = r.min + l * c;
|
|
920
920
|
try {
|
|
921
|
-
const d =
|
|
921
|
+
const d = o({ x: i, ...n });
|
|
922
922
|
Number.isFinite(d) && s.push({ x: i, y: d });
|
|
923
923
|
} catch {
|
|
924
924
|
}
|
|
@@ -926,12 +926,12 @@ class GraphService {
|
|
|
926
926
|
return s;
|
|
927
927
|
}
|
|
928
928
|
/** Compute 2D parametric curve */
|
|
929
|
-
compute2DParametric(t, r, a,
|
|
930
|
-
const s = this.parser.parse(t), c = this.parser.parse(r), l = [], i = (a.max - a.min) /
|
|
931
|
-
for (let d = 0; d <=
|
|
929
|
+
compute2DParametric(t, r, a, n, o) {
|
|
930
|
+
const s = this.parser.parse(t), c = this.parser.parse(r), l = [], i = (a.max - a.min) / n;
|
|
931
|
+
for (let d = 0; d <= n; d++) {
|
|
932
932
|
const u = a.min + d * i;
|
|
933
933
|
try {
|
|
934
|
-
const h = s({ t: u, ...
|
|
934
|
+
const h = s({ t: u, ...o }), b = c({ t: u, ...o });
|
|
935
935
|
Number.isFinite(h) && Number.isFinite(b) && l.push({ x: h, y: b });
|
|
936
936
|
} catch {
|
|
937
937
|
}
|
|
@@ -939,12 +939,12 @@ class GraphService {
|
|
|
939
939
|
return l;
|
|
940
940
|
}
|
|
941
941
|
/** Compute 2D polar curve */
|
|
942
|
-
compute2DPolar(t, r, a,
|
|
943
|
-
const
|
|
942
|
+
compute2DPolar(t, r, a, n) {
|
|
943
|
+
const o = this.parser.parse(t), s = [], c = (r.max - r.min) / a;
|
|
944
944
|
for (let l = 0; l <= a; l++) {
|
|
945
945
|
const i = r.min + l * c;
|
|
946
946
|
try {
|
|
947
|
-
const d =
|
|
947
|
+
const d = o({ theta: i, t: i, ...n });
|
|
948
948
|
if (Number.isFinite(d)) {
|
|
949
949
|
const u = d * Math.cos(i), h = d * Math.sin(i);
|
|
950
950
|
s.push({ x: u, y: h });
|
|
@@ -955,14 +955,14 @@ class GraphService {
|
|
|
955
955
|
return s;
|
|
956
956
|
}
|
|
957
957
|
/** Compute 3D surface points */
|
|
958
|
-
compute3DSurface(t, r, a,
|
|
959
|
-
const s = this.parser.parse(t), c = [], l = (r.max - r.min) /
|
|
960
|
-
for (let d = 0; d <=
|
|
958
|
+
compute3DSurface(t, r, a, n, o) {
|
|
959
|
+
const s = this.parser.parse(t), c = [], l = (r.max - r.min) / n, i = (a.max - a.min) / n;
|
|
960
|
+
for (let d = 0; d <= n; d++) {
|
|
961
961
|
const u = [], h = r.min + d * l;
|
|
962
|
-
for (let b = 0; b <=
|
|
962
|
+
for (let b = 0; b <= n; b++) {
|
|
963
963
|
const y = a.min + b * i;
|
|
964
964
|
try {
|
|
965
|
-
const g = s({ x: h, y, ...
|
|
965
|
+
const g = s({ x: h, y, ...o });
|
|
966
966
|
Number.isFinite(g) ? u.push({ x: h, y, z: g }) : u.push({ x: h, y, z: 0 });
|
|
967
967
|
} catch {
|
|
968
968
|
u.push({ x: h, y, z: 0 });
|
|
@@ -973,16 +973,16 @@ class GraphService {
|
|
|
973
973
|
return c;
|
|
974
974
|
}
|
|
975
975
|
/** Export plot data as SVG */
|
|
976
|
-
exportSVG(t, r, a,
|
|
977
|
-
const s = a - 80, c =
|
|
978
|
-
`<svg xmlns="http://www.w3.org/2000/svg" width="${a}" height="${
|
|
976
|
+
exportSVG(t, r, a, n) {
|
|
977
|
+
const s = a - 80, c = n - 40 * 2, l = (u) => 40 + (u - r.xRange.min) / (r.xRange.max - r.xRange.min) * s, i = (u) => n - 40 - (u - r.yRange.min) / (r.yRange.max - r.yRange.min) * c, d = [
|
|
978
|
+
`<svg xmlns="http://www.w3.org/2000/svg" width="${a}" height="${n}">`,
|
|
979
979
|
`<rect width="100%" height="100%" fill="rgb(${r.backgroundColor.r},${r.backgroundColor.g},${r.backgroundColor.b})"/>`
|
|
980
980
|
];
|
|
981
981
|
if (r.showGrid) {
|
|
982
|
-
d.push('<g stroke="#ddd" stroke-width="0.5">');
|
|
982
|
+
d.push('<g stroke="var(--nice-border, #ddd)" stroke-width="0.5">');
|
|
983
983
|
for (let u = Math.ceil(r.xRange.min); u <= r.xRange.max; u++) {
|
|
984
984
|
const h = l(u);
|
|
985
|
-
d.push(`<line x1="${h}" y1="40" x2="${h}" y2="${
|
|
985
|
+
d.push(`<line x1="${h}" y1="40" x2="${h}" y2="${n - 40}"/>`);
|
|
986
986
|
}
|
|
987
987
|
for (let u = Math.ceil(r.yRange.min); u <= r.yRange.max; u++) {
|
|
988
988
|
const h = i(u);
|
|
@@ -991,9 +991,9 @@ class GraphService {
|
|
|
991
991
|
d.push("</g>");
|
|
992
992
|
}
|
|
993
993
|
if (r.showAxes) {
|
|
994
|
-
d.push('<g stroke="#333" stroke-width="1">');
|
|
994
|
+
d.push('<g stroke="var(--nice-text, #333)" stroke-width="1">');
|
|
995
995
|
const u = i(0), h = l(0);
|
|
996
|
-
d.push(`<line x1="40" y1="${u}" x2="${a - 40}" y2="${u}"/>`), d.push(`<line x1="${h}" y1="40" x2="${h}" y2="${
|
|
996
|
+
d.push(`<line x1="40" y1="${u}" x2="${a - 40}" y2="${u}"/>`), d.push(`<line x1="${h}" y1="40" x2="${h}" y2="${n - 40}"/>`), d.push("</g>");
|
|
997
997
|
}
|
|
998
998
|
for (const u of t.filter((h) => h.visible))
|
|
999
999
|
if (u.type === "2d-function") {
|
|
@@ -1006,27 +1006,27 @@ class GraphService {
|
|
|
1006
1006
|
}
|
|
1007
1007
|
}
|
|
1008
1008
|
return r.showLabels && (d.push(
|
|
1009
|
-
`<text x="${a / 2}" y="${
|
|
1009
|
+
`<text x="${a / 2}" y="${n - 10}" text-anchor="middle" font-size="12">x</text>`
|
|
1010
1010
|
), d.push(
|
|
1011
|
-
`<text x="10" y="${
|
|
1011
|
+
`<text x="10" y="${n / 2}" text-anchor="middle" font-size="12" transform="rotate(-90,10,${n / 2})">y</text>`
|
|
1012
1012
|
)), d.push("</svg>"), d.join(`
|
|
1013
1013
|
`);
|
|
1014
1014
|
}
|
|
1015
1015
|
/** Export as PNG (data URL) */
|
|
1016
|
-
async exportPNG(t, r, a,
|
|
1017
|
-
const
|
|
1016
|
+
async exportPNG(t, r, a, n) {
|
|
1017
|
+
const o = this.exportSVG(t, r, a, n);
|
|
1018
1018
|
return new Promise((s, c) => {
|
|
1019
1019
|
const l = new Image();
|
|
1020
1020
|
l.onload = () => {
|
|
1021
1021
|
const i = document.createElement("canvas");
|
|
1022
|
-
i.width = a, i.height =
|
|
1022
|
+
i.width = a, i.height = n;
|
|
1023
1023
|
const d = i.getContext("2d");
|
|
1024
1024
|
if (!d) {
|
|
1025
1025
|
c(new Error("Could not get canvas context"));
|
|
1026
1026
|
return;
|
|
1027
1027
|
}
|
|
1028
1028
|
d.drawImage(l, 0, 0), s(i.toDataURL("image/png"));
|
|
1029
|
-
}, l.onerror = c, l.src = "data:image/svg+xml;base64," + btoa(
|
|
1029
|
+
}, l.onerror = c, l.src = "data:image/svg+xml;base64," + btoa(o);
|
|
1030
1030
|
});
|
|
1031
1031
|
}
|
|
1032
1032
|
generateId() {
|
|
@@ -1135,7 +1135,7 @@ const styles$2 = {
|
|
|
1135
1135
|
},
|
|
1136
1136
|
sidebar: {
|
|
1137
1137
|
width: "280px",
|
|
1138
|
-
borderRight: "1px solid #e0e0e0",
|
|
1138
|
+
borderRight: "1px solid var(--nice-border, #e0e0e0)",
|
|
1139
1139
|
display: "flex",
|
|
1140
1140
|
flexDirection: "column",
|
|
1141
1141
|
overflow: "hidden"
|
|
@@ -1149,22 +1149,22 @@ const styles$2 = {
|
|
|
1149
1149
|
flex: 1,
|
|
1150
1150
|
display: "flex",
|
|
1151
1151
|
flexDirection: "column",
|
|
1152
|
-
backgroundColor: "#fff"
|
|
1152
|
+
backgroundColor: "var(--nice-bg, #fff)"
|
|
1153
1153
|
},
|
|
1154
1154
|
canvas: {
|
|
1155
1155
|
flex: 1,
|
|
1156
|
-
backgroundColor: "#fff"
|
|
1156
|
+
backgroundColor: "var(--nice-bg, #fff)"
|
|
1157
1157
|
},
|
|
1158
1158
|
toolbar: {
|
|
1159
1159
|
display: "flex",
|
|
1160
1160
|
gap: "8px",
|
|
1161
1161
|
padding: "8px",
|
|
1162
|
-
borderBottom: "1px solid #e0e0e0",
|
|
1162
|
+
borderBottom: "1px solid var(--nice-border, #e0e0e0)",
|
|
1163
1163
|
alignItems: "center"
|
|
1164
1164
|
},
|
|
1165
1165
|
button: {
|
|
1166
1166
|
padding: "6px 12px",
|
|
1167
|
-
backgroundColor: "#1976d2",
|
|
1167
|
+
backgroundColor: "var(--nice-primary-hover, #1976d2)",
|
|
1168
1168
|
color: "white",
|
|
1169
1169
|
border: "none",
|
|
1170
1170
|
borderRadius: "4px",
|
|
@@ -1173,16 +1173,16 @@ const styles$2 = {
|
|
|
1173
1173
|
},
|
|
1174
1174
|
input: {
|
|
1175
1175
|
padding: "6px 8px",
|
|
1176
|
-
border: "1px solid #ddd",
|
|
1176
|
+
border: "1px solid var(--nice-border, #ddd)",
|
|
1177
1177
|
borderRadius: "4px",
|
|
1178
1178
|
fontSize: "13px"
|
|
1179
1179
|
},
|
|
1180
1180
|
plotItem: {
|
|
1181
1181
|
padding: "8px",
|
|
1182
1182
|
marginBottom: "8px",
|
|
1183
|
-
border: "1px solid #e0e0e0",
|
|
1183
|
+
border: "1px solid var(--nice-border, #e0e0e0)",
|
|
1184
1184
|
borderRadius: "4px",
|
|
1185
|
-
backgroundColor: "#fafafa"
|
|
1185
|
+
backgroundColor: "var(--nice-bg-secondary, #fafafa)"
|
|
1186
1186
|
}
|
|
1187
1187
|
};
|
|
1188
1188
|
function NiceGraphPlotter({
|
|
@@ -1190,9 +1190,9 @@ function NiceGraphPlotter({
|
|
|
1190
1190
|
width: t = 800,
|
|
1191
1191
|
height: r = 600,
|
|
1192
1192
|
className: a,
|
|
1193
|
-
style:
|
|
1193
|
+
style: n
|
|
1194
1194
|
}) {
|
|
1195
|
-
const [
|
|
1195
|
+
const [o, s] = useState([]), [c, l] = useState({
|
|
1196
1196
|
xRange: { min: -10, max: 10 },
|
|
1197
1197
|
yRange: { min: -10, max: 10 },
|
|
1198
1198
|
zRange: { min: -5, max: 5 },
|
|
@@ -1233,7 +1233,7 @@ function NiceGraphPlotter({
|
|
|
1233
1233
|
[e, u]
|
|
1234
1234
|
), p = {
|
|
1235
1235
|
service: e,
|
|
1236
|
-
plots:
|
|
1236
|
+
plots: o,
|
|
1237
1237
|
view: c,
|
|
1238
1238
|
setView: h,
|
|
1239
1239
|
addPlot: y,
|
|
@@ -1243,7 +1243,7 @@ function NiceGraphPlotter({
|
|
|
1243
1243
|
setAnimation: b,
|
|
1244
1244
|
refresh: u
|
|
1245
1245
|
};
|
|
1246
|
-
return /* @__PURE__ */ jsx(GraphContext.Provider, { value: p, children: /* @__PURE__ */ jsxs("div", { className: a, style: { ...styles$2.container, ...
|
|
1246
|
+
return /* @__PURE__ */ jsx(GraphContext.Provider, { value: p, children: /* @__PURE__ */ jsxs("div", { className: a, style: { ...styles$2.container, ...n }, children: [
|
|
1247
1247
|
/* @__PURE__ */ jsxs("div", { style: styles$2.sidebar, children: [
|
|
1248
1248
|
/* @__PURE__ */ jsx(PlotControls, {}),
|
|
1249
1249
|
/* @__PURE__ */ jsx(PlotList, {})
|
|
@@ -1255,11 +1255,11 @@ function NiceGraphPlotter({
|
|
|
1255
1255
|
] }) });
|
|
1256
1256
|
}
|
|
1257
1257
|
function PlotControls() {
|
|
1258
|
-
const { addPlot: e } = useGraph(), [t, r] = useState("sin(x)"), [a,
|
|
1258
|
+
const { addPlot: e } = useGraph(), [t, r] = useState("sin(x)"), [a, n] = useState("2d-function"), [o, s] = useState("cos(x)"), c = () => {
|
|
1259
1259
|
e({
|
|
1260
1260
|
type: a,
|
|
1261
1261
|
expression: t,
|
|
1262
|
-
expressionY: a === "2d-parametric" ?
|
|
1262
|
+
expressionY: a === "2d-parametric" ? o : void 0,
|
|
1263
1263
|
color: {
|
|
1264
1264
|
r: Math.floor(Math.random() * 200),
|
|
1265
1265
|
g: Math.floor(Math.random() * 200),
|
|
@@ -1267,12 +1267,12 @@ function PlotControls() {
|
|
|
1267
1267
|
}
|
|
1268
1268
|
});
|
|
1269
1269
|
};
|
|
1270
|
-
return /* @__PURE__ */ jsxs("div", { style: { padding: "12px", borderBottom: "1px solid #e0e0e0" }, children: [
|
|
1270
|
+
return /* @__PURE__ */ jsxs("div", { style: { padding: "12px", borderBottom: "1px solid var(--nice-border, #e0e0e0)" }, children: [
|
|
1271
1271
|
/* @__PURE__ */ jsx("div", { style: { marginBottom: "8px" }, children: /* @__PURE__ */ jsxs(
|
|
1272
1272
|
"select",
|
|
1273
1273
|
{
|
|
1274
1274
|
value: a,
|
|
1275
|
-
onChange: (l) =>
|
|
1275
|
+
onChange: (l) => n(l.target.value),
|
|
1276
1276
|
style: { ...styles$2.input, width: "100%" },
|
|
1277
1277
|
children: [
|
|
1278
1278
|
/* @__PURE__ */ jsx("option", { value: "2d-function", children: "y = f(x)" }),
|
|
@@ -1296,7 +1296,7 @@ function PlotControls() {
|
|
|
1296
1296
|
"input",
|
|
1297
1297
|
{
|
|
1298
1298
|
type: "text",
|
|
1299
|
-
value:
|
|
1299
|
+
value: o,
|
|
1300
1300
|
onChange: (l) => s(l.target.value),
|
|
1301
1301
|
placeholder: "y(t) = ...",
|
|
1302
1302
|
style: { ...styles$2.input, width: "100%" }
|
|
@@ -1337,7 +1337,7 @@ function PlotControls() {
|
|
|
1337
1337
|
function PlotList() {
|
|
1338
1338
|
const { plots: e, removePlot: t, updatePlot: r } = useGraph();
|
|
1339
1339
|
return /* @__PURE__ */ jsxs("div", { style: styles$2.plotList, children: [
|
|
1340
|
-
e.length === 0 && /* @__PURE__ */ jsx("div", { style: { color: "#666", textAlign: "center", padding: "16px" }, children: "No plots added yet" }),
|
|
1340
|
+
e.length === 0 && /* @__PURE__ */ jsx("div", { style: { color: "var(--nice-text-secondary, #666)", textAlign: "center", padding: "16px" }, children: "No plots added yet" }),
|
|
1341
1341
|
e.map((a) => /* @__PURE__ */ jsxs("div", { style: styles$2.plotItem, children: [
|
|
1342
1342
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", marginBottom: "8px" }, children: [
|
|
1343
1343
|
/* @__PURE__ */ jsx(
|
|
@@ -1345,7 +1345,7 @@ function PlotList() {
|
|
|
1345
1345
|
{
|
|
1346
1346
|
type: "checkbox",
|
|
1347
1347
|
checked: a.visible,
|
|
1348
|
-
onChange: (
|
|
1348
|
+
onChange: (n) => r(a.id, { visible: n.target.checked })
|
|
1349
1349
|
}
|
|
1350
1350
|
),
|
|
1351
1351
|
/* @__PURE__ */ jsx(
|
|
@@ -1366,7 +1366,7 @@ function PlotList() {
|
|
|
1366
1366
|
onClick: () => t(a.id),
|
|
1367
1367
|
style: {
|
|
1368
1368
|
padding: "2px 6px",
|
|
1369
|
-
backgroundColor: "#f44336",
|
|
1369
|
+
backgroundColor: "var(--nice-danger, #f44336)",
|
|
1370
1370
|
color: "white",
|
|
1371
1371
|
border: "none",
|
|
1372
1372
|
borderRadius: "3px",
|
|
@@ -1377,7 +1377,7 @@ function PlotList() {
|
|
|
1377
1377
|
}
|
|
1378
1378
|
)
|
|
1379
1379
|
] }),
|
|
1380
|
-
/* @__PURE__ */ jsx("div", { style: { fontSize: "12px", color: "#666", fontFamily: "monospace" }, children: a.type === "2d-parametric" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1380
|
+
/* @__PURE__ */ jsx("div", { style: { fontSize: "12px", color: "var(--nice-text-secondary, #666)", fontFamily: "monospace" }, children: a.type === "2d-parametric" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1381
1381
|
"x(t) = ",
|
|
1382
1382
|
a.expression,
|
|
1383
1383
|
/* @__PURE__ */ jsx("br", {}),
|
|
@@ -1388,11 +1388,11 @@ function PlotList() {
|
|
|
1388
1388
|
] });
|
|
1389
1389
|
}
|
|
1390
1390
|
function GraphToolbar({ width: e, height: t }) {
|
|
1391
|
-
const { service: r, plots: a, view:
|
|
1392
|
-
const l = r.exportSVG(a,
|
|
1391
|
+
const { service: r, plots: a, view: n, setView: o } = useGraph(), s = () => {
|
|
1392
|
+
const l = r.exportSVG(a, n, e, t), i = new Blob([l], { type: "image/svg+xml" }), d = URL.createObjectURL(i), u = document.createElement("a");
|
|
1393
1393
|
u.href = d, u.download = "graph.svg", u.click(), URL.revokeObjectURL(d);
|
|
1394
1394
|
}, c = async () => {
|
|
1395
|
-
const l = await r.exportPNG(a,
|
|
1395
|
+
const l = await r.exportPNG(a, n, e, t), i = document.createElement("a");
|
|
1396
1396
|
i.href = l, i.download = "graph.png", i.click();
|
|
1397
1397
|
};
|
|
1398
1398
|
return /* @__PURE__ */ jsxs("div", { style: styles$2.toolbar, children: [
|
|
@@ -1403,8 +1403,8 @@ function GraphToolbar({ width: e, height: t }) {
|
|
|
1403
1403
|
"input",
|
|
1404
1404
|
{
|
|
1405
1405
|
type: "number",
|
|
1406
|
-
value:
|
|
1407
|
-
onChange: (l) =>
|
|
1406
|
+
value: n.xRange.min,
|
|
1407
|
+
onChange: (l) => o({ xRange: { ...n.xRange, min: Number(l.target.value) } }),
|
|
1408
1408
|
style: { ...styles$2.input, width: "50px" }
|
|
1409
1409
|
}
|
|
1410
1410
|
),
|
|
@@ -1414,8 +1414,8 @@ function GraphToolbar({ width: e, height: t }) {
|
|
|
1414
1414
|
"input",
|
|
1415
1415
|
{
|
|
1416
1416
|
type: "number",
|
|
1417
|
-
value:
|
|
1418
|
-
onChange: (l) =>
|
|
1417
|
+
value: n.xRange.max,
|
|
1418
|
+
onChange: (l) => o({ xRange: { ...n.xRange, max: Number(l.target.value) } }),
|
|
1419
1419
|
style: { ...styles$2.input, width: "50px" }
|
|
1420
1420
|
}
|
|
1421
1421
|
),
|
|
@@ -1428,8 +1428,8 @@ function GraphToolbar({ width: e, height: t }) {
|
|
|
1428
1428
|
"input",
|
|
1429
1429
|
{
|
|
1430
1430
|
type: "number",
|
|
1431
|
-
value:
|
|
1432
|
-
onChange: (l) =>
|
|
1431
|
+
value: n.yRange.min,
|
|
1432
|
+
onChange: (l) => o({ yRange: { ...n.yRange, min: Number(l.target.value) } }),
|
|
1433
1433
|
style: { ...styles$2.input, width: "50px" }
|
|
1434
1434
|
}
|
|
1435
1435
|
),
|
|
@@ -1439,8 +1439,8 @@ function GraphToolbar({ width: e, height: t }) {
|
|
|
1439
1439
|
"input",
|
|
1440
1440
|
{
|
|
1441
1441
|
type: "number",
|
|
1442
|
-
value:
|
|
1443
|
-
onChange: (l) =>
|
|
1442
|
+
value: n.yRange.max,
|
|
1443
|
+
onChange: (l) => o({ yRange: { ...n.yRange, max: Number(l.target.value) } }),
|
|
1444
1444
|
style: { ...styles$2.input, width: "50px" }
|
|
1445
1445
|
}
|
|
1446
1446
|
),
|
|
@@ -1451,8 +1451,8 @@ function GraphToolbar({ width: e, height: t }) {
|
|
|
1451
1451
|
"input",
|
|
1452
1452
|
{
|
|
1453
1453
|
type: "checkbox",
|
|
1454
|
-
checked:
|
|
1455
|
-
onChange: (l) =>
|
|
1454
|
+
checked: n.showGrid,
|
|
1455
|
+
onChange: (l) => o({ showGrid: l.target.checked })
|
|
1456
1456
|
}
|
|
1457
1457
|
),
|
|
1458
1458
|
"Grid"
|
|
@@ -1462,51 +1462,51 @@ function GraphToolbar({ width: e, height: t }) {
|
|
|
1462
1462
|
"input",
|
|
1463
1463
|
{
|
|
1464
1464
|
type: "checkbox",
|
|
1465
|
-
checked:
|
|
1466
|
-
onChange: (l) =>
|
|
1465
|
+
checked: n.showAxes,
|
|
1466
|
+
onChange: (l) => o({ showAxes: l.target.checked })
|
|
1467
1467
|
}
|
|
1468
1468
|
),
|
|
1469
1469
|
"Axes"
|
|
1470
1470
|
] }),
|
|
1471
1471
|
/* @__PURE__ */ jsx("div", { style: { flex: 1 } }),
|
|
1472
|
-
/* @__PURE__ */ jsx("button", { onClick: s, style: { ...styles$2.button, backgroundColor: "#4caf50" }, children: "📥 SVG" }),
|
|
1473
|
-
/* @__PURE__ */ jsx("button", { onClick: c, style: { ...styles$2.button, backgroundColor: "#ff9800" }, children: "📥 PNG" })
|
|
1472
|
+
/* @__PURE__ */ jsx("button", { onClick: s, style: { ...styles$2.button, backgroundColor: "var(--nice-success, #4caf50)" }, children: "📥 SVG" }),
|
|
1473
|
+
/* @__PURE__ */ jsx("button", { onClick: c, style: { ...styles$2.button, backgroundColor: "var(--nice-warning, #ff9800)" }, children: "📥 PNG" })
|
|
1474
1474
|
] });
|
|
1475
1475
|
}
|
|
1476
1476
|
function Canvas2D({ width: e, height: t }) {
|
|
1477
|
-
const r = useRef(null), { service: a, plots:
|
|
1477
|
+
const r = useRef(null), { service: a, plots: n, view: o, animation: s } = useGraph(), c = 40;
|
|
1478
1478
|
return useEffect(() => {
|
|
1479
1479
|
const l = r.current, i = l == null ? void 0 : l.getContext("2d");
|
|
1480
1480
|
if (!l || !i)
|
|
1481
1481
|
return;
|
|
1482
|
-
i.fillStyle = `rgb(${
|
|
1483
|
-
const d = e - c * 2, u = t - c * 2, h = (g) => c + (g -
|
|
1484
|
-
if (
|
|
1485
|
-
i.strokeStyle = "#e0e0e0", i.lineWidth = 0.5;
|
|
1486
|
-
for (let g = Math.ceil(
|
|
1482
|
+
i.fillStyle = `rgb(${o.backgroundColor.r},${o.backgroundColor.g},${o.backgroundColor.b})`, i.fillRect(0, 0, e, t);
|
|
1483
|
+
const d = e - c * 2, u = t - c * 2, h = (g) => c + (g - o.xRange.min) / (o.xRange.max - o.xRange.min) * d, b = (g) => t - c - (g - o.yRange.min) / (o.yRange.max - o.yRange.min) * u;
|
|
1484
|
+
if (o.showGrid) {
|
|
1485
|
+
i.strokeStyle = "var(--nice-border, #e0e0e0)", i.lineWidth = 0.5;
|
|
1486
|
+
for (let g = Math.ceil(o.xRange.min); g <= o.xRange.max; g++) {
|
|
1487
1487
|
const m = h(g);
|
|
1488
1488
|
i.beginPath(), i.moveTo(m, c), i.lineTo(m, t - c), i.stroke();
|
|
1489
1489
|
}
|
|
1490
|
-
for (let g = Math.ceil(
|
|
1490
|
+
for (let g = Math.ceil(o.yRange.min); g <= o.yRange.max; g++) {
|
|
1491
1491
|
const m = b(g);
|
|
1492
1492
|
i.beginPath(), i.moveTo(c, m), i.lineTo(e - c, m), i.stroke();
|
|
1493
1493
|
}
|
|
1494
1494
|
}
|
|
1495
|
-
if (
|
|
1496
|
-
i.strokeStyle = "#333", i.lineWidth = 1;
|
|
1495
|
+
if (o.showAxes) {
|
|
1496
|
+
i.strokeStyle = "var(--nice-text, #333)", i.lineWidth = 1;
|
|
1497
1497
|
const g = b(0);
|
|
1498
1498
|
i.beginPath(), i.moveTo(c, g), i.lineTo(e - c, g), i.stroke();
|
|
1499
1499
|
const m = h(0);
|
|
1500
|
-
if (i.beginPath(), i.moveTo(m, c), i.lineTo(m, t - c), i.stroke(),
|
|
1501
|
-
i.fillStyle = "#333", i.font = "12px sans-serif", i.textAlign = "center", i.fillText("x", e - c + 15, g + 4), i.fillText("y", m, c - 10), i.font = "10px sans-serif";
|
|
1502
|
-
for (let p = Math.ceil(
|
|
1500
|
+
if (i.beginPath(), i.moveTo(m, c), i.lineTo(m, t - c), i.stroke(), o.showLabels) {
|
|
1501
|
+
i.fillStyle = "var(--nice-text, #333)", i.font = "12px sans-serif", i.textAlign = "center", i.fillText("x", e - c + 15, g + 4), i.fillText("y", m, c - 10), i.font = "10px sans-serif";
|
|
1502
|
+
for (let p = Math.ceil(o.xRange.min); p <= o.xRange.max; p++)
|
|
1503
1503
|
p !== 0 && i.fillText(String(p), h(p), g + 15);
|
|
1504
|
-
for (let p = Math.ceil(
|
|
1504
|
+
for (let p = Math.ceil(o.yRange.min); p <= o.yRange.max; p++)
|
|
1505
1505
|
p !== 0 && (i.textAlign = "right", i.fillText(String(p), m - 5, b(p) + 4));
|
|
1506
1506
|
}
|
|
1507
1507
|
}
|
|
1508
1508
|
const y = s.isPlaying ? { [s.parameter]: s.currentValue } : {};
|
|
1509
|
-
for (const g of
|
|
1509
|
+
for (const g of n.filter((m) => m.visible)) {
|
|
1510
1510
|
const m = `rgb(${g.color.r},${g.color.g},${g.color.b})`;
|
|
1511
1511
|
i.strokeStyle = m, i.lineWidth = g.lineWidth || 2;
|
|
1512
1512
|
let p = [];
|
|
@@ -1514,7 +1514,7 @@ function Canvas2D({ width: e, height: t }) {
|
|
|
1514
1514
|
case "2d-function":
|
|
1515
1515
|
p = a.compute2DFunction(
|
|
1516
1516
|
g.expression,
|
|
1517
|
-
|
|
1517
|
+
o.xRange,
|
|
1518
1518
|
g.resolution || 200,
|
|
1519
1519
|
y
|
|
1520
1520
|
);
|
|
@@ -1551,7 +1551,7 @@ function Canvas2D({ width: e, height: t }) {
|
|
|
1551
1551
|
i.stroke();
|
|
1552
1552
|
}
|
|
1553
1553
|
}
|
|
1554
|
-
}, [
|
|
1554
|
+
}, [n, o, s, a, e, t]), /* @__PURE__ */ jsx("canvas", { ref: r, width: e, height: t, style: styles$2.canvas });
|
|
1555
1555
|
}
|
|
1556
1556
|
const UNITS = [
|
|
1557
1557
|
// Length
|
|
@@ -1826,7 +1826,7 @@ const UNITS = [
|
|
|
1826
1826
|
], MatrixOps = {
|
|
1827
1827
|
create(e, t, r = 0) {
|
|
1828
1828
|
const a = [];
|
|
1829
|
-
for (let
|
|
1829
|
+
for (let n = 0; n < e; n++)
|
|
1830
1830
|
a.push(new Array(t).fill(r));
|
|
1831
1831
|
return { rows: e, cols: t, data: a };
|
|
1832
1832
|
},
|
|
@@ -1841,8 +1841,8 @@ const UNITS = [
|
|
|
1841
1841
|
throw new Error("Matrix dimensions must match for addition");
|
|
1842
1842
|
const r = this.create(e.rows, e.cols);
|
|
1843
1843
|
for (let a = 0; a < e.rows; a++)
|
|
1844
|
-
for (let
|
|
1845
|
-
r.data[a][
|
|
1844
|
+
for (let n = 0; n < e.cols; n++)
|
|
1845
|
+
r.data[a][n] = e.data[a][n] + t.data[a][n];
|
|
1846
1846
|
return r;
|
|
1847
1847
|
},
|
|
1848
1848
|
subtract(e, t) {
|
|
@@ -1850,8 +1850,8 @@ const UNITS = [
|
|
|
1850
1850
|
throw new Error("Matrix dimensions must match for subtraction");
|
|
1851
1851
|
const r = this.create(e.rows, e.cols);
|
|
1852
1852
|
for (let a = 0; a < e.rows; a++)
|
|
1853
|
-
for (let
|
|
1854
|
-
r.data[a][
|
|
1853
|
+
for (let n = 0; n < e.cols; n++)
|
|
1854
|
+
r.data[a][n] = e.data[a][n] - t.data[a][n];
|
|
1855
1855
|
return r;
|
|
1856
1856
|
},
|
|
1857
1857
|
multiply(e, t) {
|
|
@@ -1859,19 +1859,19 @@ const UNITS = [
|
|
|
1859
1859
|
throw new Error("Matrix A columns must equal Matrix B rows for multiplication");
|
|
1860
1860
|
const r = this.create(e.rows, t.cols);
|
|
1861
1861
|
for (let a = 0; a < e.rows; a++)
|
|
1862
|
-
for (let
|
|
1863
|
-
let
|
|
1862
|
+
for (let n = 0; n < t.cols; n++) {
|
|
1863
|
+
let o = 0;
|
|
1864
1864
|
for (let s = 0; s < e.cols; s++)
|
|
1865
|
-
|
|
1866
|
-
r.data[a][
|
|
1865
|
+
o += e.data[a][s] * t.data[s][n];
|
|
1866
|
+
r.data[a][n] = o;
|
|
1867
1867
|
}
|
|
1868
1868
|
return r;
|
|
1869
1869
|
},
|
|
1870
1870
|
scalar(e, t) {
|
|
1871
1871
|
const r = this.create(e.rows, e.cols);
|
|
1872
1872
|
for (let a = 0; a < e.rows; a++)
|
|
1873
|
-
for (let
|
|
1874
|
-
r.data[a][
|
|
1873
|
+
for (let n = 0; n < e.cols; n++)
|
|
1874
|
+
r.data[a][n] = e.data[a][n] * t;
|
|
1875
1875
|
return r;
|
|
1876
1876
|
},
|
|
1877
1877
|
transpose(e) {
|
|
@@ -1895,14 +1895,14 @@ const UNITS = [
|
|
|
1895
1895
|
},
|
|
1896
1896
|
minor(e, t, r) {
|
|
1897
1897
|
const a = this.create(e.rows - 1, e.cols - 1);
|
|
1898
|
-
let
|
|
1899
|
-
for (let
|
|
1900
|
-
if (
|
|
1898
|
+
let n = 0;
|
|
1899
|
+
for (let o = 0; o < e.rows; o++) {
|
|
1900
|
+
if (o === t)
|
|
1901
1901
|
continue;
|
|
1902
1902
|
let s = 0;
|
|
1903
1903
|
for (let c = 0; c < e.cols; c++)
|
|
1904
|
-
c !== r && (a.data[
|
|
1905
|
-
|
|
1904
|
+
c !== r && (a.data[n][s] = e.data[o][c], s++);
|
|
1905
|
+
n++;
|
|
1906
1906
|
}
|
|
1907
1907
|
return a;
|
|
1908
1908
|
},
|
|
@@ -1911,10 +1911,10 @@ const UNITS = [
|
|
|
1911
1911
|
if (t === 0)
|
|
1912
1912
|
throw new Error("Matrix is singular, cannot compute inverse");
|
|
1913
1913
|
const r = e.rows, a = this.create(r, r);
|
|
1914
|
-
for (let
|
|
1915
|
-
for (let
|
|
1916
|
-
const s = Math.pow(-1,
|
|
1917
|
-
a.data[
|
|
1914
|
+
for (let n = 0; n < r; n++)
|
|
1915
|
+
for (let o = 0; o < r; o++) {
|
|
1916
|
+
const s = Math.pow(-1, n + o), c = this.determinant(this.minor(e, n, o));
|
|
1917
|
+
a.data[o][n] = s * c;
|
|
1918
1918
|
}
|
|
1919
1919
|
return this.scalar(a, 1 / t);
|
|
1920
1920
|
},
|
|
@@ -1929,11 +1929,11 @@ const UNITS = [
|
|
|
1929
1929
|
eigenvalues2x2(e) {
|
|
1930
1930
|
if (e.rows !== 2 || e.cols !== 2)
|
|
1931
1931
|
throw new Error("Only 2x2 matrices supported for eigenvalues");
|
|
1932
|
-
const t = e.data[0][0], r = e.data[0][1], a = e.data[1][0],
|
|
1932
|
+
const t = e.data[0][0], r = e.data[0][1], a = e.data[1][0], n = e.data[1][1], o = t + n, s = t * n - r * a, c = o * o - 4 * s;
|
|
1933
1933
|
if (c < 0)
|
|
1934
1934
|
throw new Error("Complex eigenvalues not supported");
|
|
1935
1935
|
const l = Math.sqrt(c);
|
|
1936
|
-
return [(
|
|
1936
|
+
return [(o + l) / 2, (o - l) / 2];
|
|
1937
1937
|
},
|
|
1938
1938
|
toString(e, t = 4) {
|
|
1939
1939
|
return e.data.map((r) => "[ " + r.map((a) => a.toFixed(t).padStart(10)).join(" ") + " ]").join(`
|
|
@@ -1951,25 +1951,25 @@ const UNITS = [
|
|
|
1951
1951
|
/** Numerical integration using Simpson's rule */
|
|
1952
1952
|
integrate(e, t, r, a = 1e3) {
|
|
1953
1953
|
a % 2 !== 0 && a++;
|
|
1954
|
-
const
|
|
1955
|
-
let
|
|
1954
|
+
const n = (r - t) / a;
|
|
1955
|
+
let o = e(t) + e(r);
|
|
1956
1956
|
for (let s = 1; s < a; s++) {
|
|
1957
|
-
const c = t + s *
|
|
1958
|
-
|
|
1957
|
+
const c = t + s * n;
|
|
1958
|
+
o += s % 2 === 0 ? 2 * e(c) : 4 * e(c);
|
|
1959
1959
|
}
|
|
1960
|
-
return
|
|
1960
|
+
return n / 3 * o;
|
|
1961
1961
|
},
|
|
1962
1962
|
/** Find root using Newton-Raphson method */
|
|
1963
1963
|
findRoot(e, t, r = 1e-10, a = 100) {
|
|
1964
|
-
let
|
|
1965
|
-
for (let
|
|
1966
|
-
const s = e(
|
|
1964
|
+
let n = t;
|
|
1965
|
+
for (let o = 0; o < a; o++) {
|
|
1966
|
+
const s = e(n);
|
|
1967
1967
|
if (Math.abs(s) < r)
|
|
1968
|
-
return
|
|
1969
|
-
const c = this.derivative(e,
|
|
1968
|
+
return n;
|
|
1969
|
+
const c = this.derivative(e, n);
|
|
1970
1970
|
if (c === 0)
|
|
1971
1971
|
throw new Error("Derivative is zero, Newton-Raphson failed");
|
|
1972
|
-
|
|
1972
|
+
n = n - s / c;
|
|
1973
1973
|
}
|
|
1974
1974
|
throw new Error("Newton-Raphson did not converge");
|
|
1975
1975
|
},
|
|
@@ -1986,8 +1986,8 @@ const UNITS = [
|
|
|
1986
1986
|
}
|
|
1987
1987
|
const r = e.match(/^(-?\d+\.?\d*)\*x\^(\d+)$/);
|
|
1988
1988
|
if (r) {
|
|
1989
|
-
const a = parseFloat(r[1]),
|
|
1990
|
-
return
|
|
1989
|
+
const a = parseFloat(r[1]), n = parseInt(r[2], 10), o = a * n;
|
|
1990
|
+
return n === 1 ? String(o) : n === 2 ? `${o}*x` : `${o}*x^${n - 1}`;
|
|
1991
1991
|
}
|
|
1992
1992
|
return e === "sin(x)" ? "cos(x)" : e === "cos(x)" ? "-sin(x)" : e === "e^x" || e === "exp(x)" ? "e^x" : e === "ln(x)" ? "1/x" : `d/dx(${e})`;
|
|
1993
1993
|
},
|
|
@@ -2011,8 +2011,8 @@ const UNITS = [
|
|
|
2011
2011
|
throw new Error("No real solutions (complex roots)");
|
|
2012
2012
|
if (a === 0)
|
|
2013
2013
|
return [-t / (2 * e)];
|
|
2014
|
-
const
|
|
2015
|
-
return [(-t +
|
|
2014
|
+
const n = Math.sqrt(a);
|
|
2015
|
+
return [(-t + n) / (2 * e), (-t - n) / (2 * e)];
|
|
2016
2016
|
}
|
|
2017
2017
|
};
|
|
2018
2018
|
class CalculatorService {
|
|
@@ -2080,20 +2080,20 @@ class CalculatorService {
|
|
|
2080
2080
|
}
|
|
2081
2081
|
/** Convert between number bases */
|
|
2082
2082
|
convertBase(e, t, r) {
|
|
2083
|
-
const a = { BIN: 2, OCT: 8, DEC: 10, HEX: 16 },
|
|
2084
|
-
if (isNaN(
|
|
2083
|
+
const a = { BIN: 2, OCT: 8, DEC: 10, HEX: 16 }, n = parseInt(e, a[t]);
|
|
2084
|
+
if (isNaN(n))
|
|
2085
2085
|
throw new Error("Invalid number for base conversion");
|
|
2086
|
-
return
|
|
2086
|
+
return n.toString(a[r]).toUpperCase();
|
|
2087
2087
|
}
|
|
2088
2088
|
/** Convert units */
|
|
2089
2089
|
convertUnits(e, t, r) {
|
|
2090
|
-
const a = UNITS.find((s) => s.symbol === t),
|
|
2091
|
-
if (!a || !
|
|
2090
|
+
const a = UNITS.find((s) => s.symbol === t), n = UNITS.find((s) => s.symbol === r);
|
|
2091
|
+
if (!a || !n)
|
|
2092
2092
|
throw new Error("Unknown unit");
|
|
2093
|
-
if (a.category !==
|
|
2093
|
+
if (a.category !== n.category)
|
|
2094
2094
|
throw new Error("Cannot convert between different unit categories");
|
|
2095
|
-
const
|
|
2096
|
-
return
|
|
2095
|
+
const o = a.toBase(e);
|
|
2096
|
+
return n.fromBase(o);
|
|
2097
2097
|
}
|
|
2098
2098
|
/** Get units by category */
|
|
2099
2099
|
getUnitsByCategory(e) {
|
|
@@ -2123,31 +2123,31 @@ const styles$1 = {
|
|
|
2123
2123
|
container: {
|
|
2124
2124
|
width: "400px",
|
|
2125
2125
|
fontFamily: "'Inter', sans-serif",
|
|
2126
|
-
backgroundColor: "#1e1e1e",
|
|
2126
|
+
backgroundColor: "var(--nice-bg, #1e1e1e)",
|
|
2127
2127
|
borderRadius: "12px",
|
|
2128
2128
|
overflow: "hidden",
|
|
2129
|
-
boxShadow: "0 4px 20px rgba(0,0,0,0.3)"
|
|
2129
|
+
boxShadow: "0 4px 20px var(--nice-overlay-30, rgba(0, 0, 0, 0.3))"
|
|
2130
2130
|
},
|
|
2131
2131
|
modeSelector: {
|
|
2132
2132
|
display: "flex",
|
|
2133
|
-
backgroundColor: "#2d2d2d"
|
|
2133
|
+
backgroundColor: "var(--nice-bg-secondary, #2d2d2d)"
|
|
2134
2134
|
},
|
|
2135
2135
|
modeButton: {
|
|
2136
2136
|
flex: 1,
|
|
2137
2137
|
padding: "8px",
|
|
2138
2138
|
border: "none",
|
|
2139
2139
|
backgroundColor: "transparent",
|
|
2140
|
-
color: "#888",
|
|
2140
|
+
color: "var(--nice-text-secondary, #888)",
|
|
2141
2141
|
fontSize: "11px",
|
|
2142
2142
|
cursor: "pointer"
|
|
2143
2143
|
},
|
|
2144
2144
|
display: {
|
|
2145
2145
|
padding: "20px",
|
|
2146
|
-
backgroundColor: "#252525",
|
|
2146
|
+
backgroundColor: "var(--nice-bg-secondary, #252525)",
|
|
2147
2147
|
minHeight: "80px"
|
|
2148
2148
|
},
|
|
2149
2149
|
displayText: {
|
|
2150
|
-
color: "#fff",
|
|
2150
|
+
color: "var(--nice-bg, #fff)",
|
|
2151
2151
|
fontSize: "32px",
|
|
2152
2152
|
fontFamily: "'JetBrains Mono', monospace",
|
|
2153
2153
|
textAlign: "right",
|
|
@@ -2157,21 +2157,21 @@ const styles$1 = {
|
|
|
2157
2157
|
display: "grid",
|
|
2158
2158
|
gridTemplateColumns: "repeat(4, 1fr)",
|
|
2159
2159
|
gap: "1px",
|
|
2160
|
-
backgroundColor: "#333",
|
|
2160
|
+
backgroundColor: "var(--nice-text, #333)",
|
|
2161
2161
|
padding: "1px"
|
|
2162
2162
|
},
|
|
2163
2163
|
key: {
|
|
2164
2164
|
padding: "20px",
|
|
2165
2165
|
border: "none",
|
|
2166
|
-
backgroundColor: "#3c3c3c",
|
|
2167
|
-
color: "#fff",
|
|
2166
|
+
backgroundColor: "var(--nice-border, #3c3c3c)",
|
|
2167
|
+
color: "var(--nice-bg, #fff)",
|
|
2168
2168
|
fontSize: "18px",
|
|
2169
2169
|
cursor: "pointer",
|
|
2170
2170
|
transition: "background-color 0.1s"
|
|
2171
2171
|
},
|
|
2172
2172
|
keyOperator: {
|
|
2173
|
-
backgroundColor: "#ff9f0a",
|
|
2174
|
-
color: "#000"
|
|
2173
|
+
backgroundColor: "var(--nice-warning, #ff9f0a)",
|
|
2174
|
+
color: "var(--nice-text, #000)"
|
|
2175
2175
|
},
|
|
2176
2176
|
keyFunction: {
|
|
2177
2177
|
backgroundColor: "#505050"
|
|
@@ -2182,25 +2182,25 @@ function NiceCalculator({
|
|
|
2182
2182
|
className: t,
|
|
2183
2183
|
style: r
|
|
2184
2184
|
}) {
|
|
2185
|
-
const [a,
|
|
2185
|
+
const [a, n] = useState("0"), [o, s] = useState("standard"), [c, l] = useState([]), [i, d] = useState(!1), u = useCallback(
|
|
2186
2186
|
(g) => {
|
|
2187
|
-
i && /[0-9.]/.test(g) ? (
|
|
2187
|
+
i && /[0-9.]/.test(g) ? (n(g), d(!1)) : (n((m) => m === "0" && g !== "." ? g : m + g), d(!1));
|
|
2188
2188
|
},
|
|
2189
2189
|
[i]
|
|
2190
2190
|
), h = useCallback(() => {
|
|
2191
|
-
|
|
2191
|
+
n("0"), d(!1);
|
|
2192
2192
|
}, []), b = useCallback(() => {
|
|
2193
2193
|
try {
|
|
2194
2194
|
const g = e.evaluate(a), m = e.format(g);
|
|
2195
|
-
e.addHistory(a, m,
|
|
2195
|
+
e.addHistory(a, m, o), l(e.getHistory()), n(m), d(!0);
|
|
2196
2196
|
} catch {
|
|
2197
|
-
|
|
2197
|
+
n("Error"), d(!0);
|
|
2198
2198
|
}
|
|
2199
|
-
}, [a,
|
|
2199
|
+
}, [a, o, e]), y = {
|
|
2200
2200
|
service: e,
|
|
2201
2201
|
display: a,
|
|
2202
|
-
setDisplay:
|
|
2203
|
-
mode:
|
|
2202
|
+
setDisplay: n,
|
|
2203
|
+
mode: o,
|
|
2204
2204
|
setMode: s,
|
|
2205
2205
|
history: c,
|
|
2206
2206
|
calculate: b,
|
|
@@ -2210,12 +2210,12 @@ function NiceCalculator({
|
|
|
2210
2210
|
return /* @__PURE__ */ jsx(CalculatorContext.Provider, { value: y, children: /* @__PURE__ */ jsxs("div", { className: t, style: { ...styles$1.container, ...r }, children: [
|
|
2211
2211
|
/* @__PURE__ */ jsx(ModeSelector, {}),
|
|
2212
2212
|
/* @__PURE__ */ jsx(Display, {}),
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2213
|
+
o === "standard" && /* @__PURE__ */ jsx(StandardKeypad, {}),
|
|
2214
|
+
o === "scientific" && /* @__PURE__ */ jsx(ScientificKeypad, {}),
|
|
2215
|
+
o === "programmer" && /* @__PURE__ */ jsx(ProgrammerKeypad, {}),
|
|
2216
|
+
o === "matrix" && /* @__PURE__ */ jsx(MatrixMode, {}),
|
|
2217
|
+
o === "calculus" && /* @__PURE__ */ jsx(CalculusMode, {}),
|
|
2218
|
+
o === "units" && /* @__PURE__ */ jsx(UnitsMode, {})
|
|
2219
2219
|
] }) });
|
|
2220
2220
|
}
|
|
2221
2221
|
function ModeSelector() {
|
|
@@ -2233,8 +2233,8 @@ function ModeSelector() {
|
|
|
2233
2233
|
onClick: () => t(a.id),
|
|
2234
2234
|
style: {
|
|
2235
2235
|
...styles$1.modeButton,
|
|
2236
|
-
backgroundColor: e === a.id ? "#1976d2" : "transparent",
|
|
2237
|
-
color: e === a.id ? "#fff" : "#888"
|
|
2236
|
+
backgroundColor: e === a.id ? "var(--nice-primary-hover, #1976d2)" : "transparent",
|
|
2237
|
+
color: e === a.id ? "var(--nice-bg, #fff)" : "var(--nice-text-secondary, #888)"
|
|
2238
2238
|
},
|
|
2239
2239
|
children: a.label
|
|
2240
2240
|
},
|
|
@@ -2246,11 +2246,11 @@ function Display() {
|
|
|
2246
2246
|
return /* @__PURE__ */ jsx("div", { style: styles$1.display, children: /* @__PURE__ */ jsx("div", { style: styles$1.displayText, children: e }) });
|
|
2247
2247
|
}
|
|
2248
2248
|
function StandardKeypad() {
|
|
2249
|
-
const { appendDigit: e, clear: t, calculate: r, setDisplay: a, display:
|
|
2249
|
+
const { appendDigit: e, clear: t, calculate: r, setDisplay: a, display: n } = useCalculator(), o = [
|
|
2250
2250
|
{ label: "AC", action: t, style: styles$1.keyFunction },
|
|
2251
2251
|
{
|
|
2252
2252
|
label: "±",
|
|
2253
|
-
action: () => a(
|
|
2253
|
+
action: () => a(n.startsWith("-") ? n.slice(1) : "-" + n),
|
|
2254
2254
|
style: styles$1.keyFunction
|
|
2255
2255
|
},
|
|
2256
2256
|
{ label: "%", action: () => e("/100"), style: styles$1.keyFunction },
|
|
@@ -2269,13 +2269,13 @@ function StandardKeypad() {
|
|
|
2269
2269
|
{ label: "+", action: () => e("+"), style: styles$1.keyOperator },
|
|
2270
2270
|
{ label: "0", action: () => e("0") },
|
|
2271
2271
|
{ label: ".", action: () => e(".") },
|
|
2272
|
-
{ label: "⌫", action: () => a(
|
|
2272
|
+
{ label: "⌫", action: () => a(n.length > 1 ? n.slice(0, -1) : "0") },
|
|
2273
2273
|
{ label: "=", action: r, style: styles$1.keyOperator }
|
|
2274
2274
|
];
|
|
2275
|
-
return /* @__PURE__ */ jsx("div", { style: styles$1.keypad, children:
|
|
2275
|
+
return /* @__PURE__ */ jsx("div", { style: styles$1.keypad, children: o.map((s, c) => /* @__PURE__ */ jsx("button", { onClick: s.action, style: { ...styles$1.key, ...s.style || {} }, children: s.label }, c)) });
|
|
2276
2276
|
}
|
|
2277
2277
|
function ScientificKeypad() {
|
|
2278
|
-
const { appendDigit: e, clear: t, calculate: r, setDisplay: a, display:
|
|
2278
|
+
const { appendDigit: e, clear: t, calculate: r, setDisplay: a, display: n } = useCalculator(), o = [
|
|
2279
2279
|
{ label: "sin", action: () => e("sin(") },
|
|
2280
2280
|
{ label: "cos", action: () => e("cos(") },
|
|
2281
2281
|
{ label: "tan", action: () => e("tan(") },
|
|
@@ -2295,7 +2295,7 @@ function ScientificKeypad() {
|
|
|
2295
2295
|
{ label: "AC", action: t }
|
|
2296
2296
|
];
|
|
2297
2297
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
2298
|
-
/* @__PURE__ */ jsx("div", { style: { ...styles$1.keypad, gridTemplateColumns: "repeat(5, 1fr)" }, children: [...
|
|
2298
|
+
/* @__PURE__ */ jsx("div", { style: { ...styles$1.keypad, gridTemplateColumns: "repeat(5, 1fr)" }, children: [...o, ...s, ...c].map((l, i) => /* @__PURE__ */ jsx(
|
|
2299
2299
|
"button",
|
|
2300
2300
|
{
|
|
2301
2301
|
onClick: l.action,
|
|
@@ -2308,26 +2308,26 @@ function ScientificKeypad() {
|
|
|
2308
2308
|
] });
|
|
2309
2309
|
}
|
|
2310
2310
|
function ProgrammerKeypad() {
|
|
2311
|
-
const { display: e, setDisplay: t, service: r } = useCalculator(), [a,
|
|
2311
|
+
const { display: e, setDisplay: t, service: r } = useCalculator(), [a, n] = useState("DEC"), o = (c) => {
|
|
2312
2312
|
try {
|
|
2313
2313
|
const l = r.convertBase(e, a, c);
|
|
2314
|
-
t(l),
|
|
2314
|
+
t(l), n(c);
|
|
2315
2315
|
} catch {
|
|
2316
2316
|
t("Error");
|
|
2317
2317
|
}
|
|
2318
2318
|
}, s = a === "HEX" ? ["A", "B", "C", "D", "E", "F"] : [];
|
|
2319
2319
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
2320
|
-
/* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "4px", padding: "8px", backgroundColor: "#252525" }, children: ["BIN", "OCT", "DEC", "HEX"].map((c) => /* @__PURE__ */ jsx(
|
|
2320
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "4px", padding: "8px", backgroundColor: "var(--nice-bg-secondary, #252525)" }, children: ["BIN", "OCT", "DEC", "HEX"].map((c) => /* @__PURE__ */ jsx(
|
|
2321
2321
|
"button",
|
|
2322
2322
|
{
|
|
2323
|
-
onClick: () =>
|
|
2323
|
+
onClick: () => o(c),
|
|
2324
2324
|
style: {
|
|
2325
2325
|
flex: 1,
|
|
2326
2326
|
padding: "8px",
|
|
2327
2327
|
border: "none",
|
|
2328
2328
|
borderRadius: "4px",
|
|
2329
|
-
backgroundColor: a === c ? "#1976d2" : "#3c3c3c",
|
|
2330
|
-
color: "#fff",
|
|
2329
|
+
backgroundColor: a === c ? "var(--nice-primary-hover, #1976d2)" : "var(--nice-border, #3c3c3c)",
|
|
2330
|
+
color: "var(--nice-bg, #fff)",
|
|
2331
2331
|
cursor: "pointer"
|
|
2332
2332
|
},
|
|
2333
2333
|
children: c
|
|
@@ -2375,14 +2375,14 @@ function ProgrammerKeypad() {
|
|
|
2375
2375
|
] });
|
|
2376
2376
|
}
|
|
2377
2377
|
function MatrixMode() {
|
|
2378
|
-
const [e, t] = useState(MatrixOps.create(2, 2)), [r, a] = useState(MatrixOps.create(2, 2)), [
|
|
2378
|
+
const [e, t] = useState(MatrixOps.create(2, 2)), [r, a] = useState(MatrixOps.create(2, 2)), [n, o] = useState(""), s = (l, i, d, u, h) => {
|
|
2379
2379
|
const b = { ...l, data: l.data.map((y) => [...y]) };
|
|
2380
2380
|
b.data[d][u] = parseFloat(h) || 0, i(b);
|
|
2381
2381
|
};
|
|
2382
|
-
return /* @__PURE__ */ jsxs("div", { style: { padding: "12px", backgroundColor: "#252525" }, children: [
|
|
2382
|
+
return /* @__PURE__ */ jsxs("div", { style: { padding: "12px", backgroundColor: "var(--nice-bg-secondary, #252525)" }, children: [
|
|
2383
2383
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "12px", marginBottom: "12px" }, children: [
|
|
2384
2384
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
2385
|
-
/* @__PURE__ */ jsx("div", { style: { color: "#888", marginBottom: "4px" }, children: "Matrix A" }),
|
|
2385
|
+
/* @__PURE__ */ jsx("div", { style: { color: "var(--nice-text-secondary, #888)", marginBottom: "4px" }, children: "Matrix A" }),
|
|
2386
2386
|
/* @__PURE__ */ jsx(
|
|
2387
2387
|
MatrixInput,
|
|
2388
2388
|
{
|
|
@@ -2392,7 +2392,7 @@ function MatrixMode() {
|
|
|
2392
2392
|
)
|
|
2393
2393
|
] }),
|
|
2394
2394
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
2395
|
-
/* @__PURE__ */ jsx("div", { style: { color: "#888", marginBottom: "4px" }, children: "Matrix B" }),
|
|
2395
|
+
/* @__PURE__ */ jsx("div", { style: { color: "var(--nice-text-secondary, #888)", marginBottom: "4px" }, children: "Matrix B" }),
|
|
2396
2396
|
/* @__PURE__ */ jsx(
|
|
2397
2397
|
MatrixInput,
|
|
2398
2398
|
{
|
|
@@ -2414,15 +2414,15 @@ function MatrixMode() {
|
|
|
2414
2414
|
{
|
|
2415
2415
|
onClick: () => {
|
|
2416
2416
|
try {
|
|
2417
|
-
|
|
2417
|
+
o(l.fn());
|
|
2418
2418
|
} catch (i) {
|
|
2419
|
-
|
|
2419
|
+
o(i.message);
|
|
2420
2420
|
}
|
|
2421
2421
|
},
|
|
2422
2422
|
style: {
|
|
2423
2423
|
padding: "8px 12px",
|
|
2424
|
-
backgroundColor: "#1976d2",
|
|
2425
|
-
color: "#fff",
|
|
2424
|
+
backgroundColor: "var(--nice-primary-hover, #1976d2)",
|
|
2425
|
+
color: "var(--nice-bg, #fff)",
|
|
2426
2426
|
border: "none",
|
|
2427
2427
|
borderRadius: "4px",
|
|
2428
2428
|
cursor: "pointer"
|
|
@@ -2431,7 +2431,7 @@ function MatrixMode() {
|
|
|
2431
2431
|
},
|
|
2432
2432
|
l.label
|
|
2433
2433
|
)) }),
|
|
2434
|
-
|
|
2434
|
+
n && /* @__PURE__ */ jsx("pre", { style: { color: "var(--nice-bg, #fff)", fontFamily: "monospace", whiteSpace: "pre-wrap" }, children: n })
|
|
2435
2435
|
] });
|
|
2436
2436
|
}
|
|
2437
2437
|
function MatrixInput({
|
|
@@ -2443,23 +2443,23 @@ function MatrixInput({
|
|
|
2443
2443
|
{
|
|
2444
2444
|
style: { display: "grid", gridTemplateColumns: `repeat(${e.cols}, 50px)`, gap: "4px" },
|
|
2445
2445
|
children: e.data.map(
|
|
2446
|
-
(r, a) => r.map((
|
|
2446
|
+
(r, a) => r.map((n, o) => /* @__PURE__ */ jsx(
|
|
2447
2447
|
"input",
|
|
2448
2448
|
{
|
|
2449
2449
|
type: "number",
|
|
2450
|
-
value:
|
|
2451
|
-
onChange: (s) => t(a,
|
|
2450
|
+
value: n,
|
|
2451
|
+
onChange: (s) => t(a, o, s.target.value),
|
|
2452
2452
|
style: {
|
|
2453
2453
|
width: "100%",
|
|
2454
2454
|
padding: "4px",
|
|
2455
2455
|
textAlign: "center",
|
|
2456
|
-
backgroundColor: "#3c3c3c",
|
|
2457
|
-
color: "#fff",
|
|
2458
|
-
border: "1px solid #555",
|
|
2456
|
+
backgroundColor: "var(--nice-border, #3c3c3c)",
|
|
2457
|
+
color: "var(--nice-bg, #fff)",
|
|
2458
|
+
border: "1px solid var(--nice-text-secondary, #555)",
|
|
2459
2459
|
borderRadius: "4px"
|
|
2460
2460
|
}
|
|
2461
2461
|
},
|
|
2462
|
-
`${a}-${
|
|
2462
|
+
`${a}-${o}`
|
|
2463
2463
|
))
|
|
2464
2464
|
)
|
|
2465
2465
|
}
|
|
@@ -2467,21 +2467,21 @@ function MatrixInput({
|
|
|
2467
2467
|
}
|
|
2468
2468
|
function CalculusMode() {
|
|
2469
2469
|
const [e, t] = useState("x^2"), [r, a] = useState("");
|
|
2470
|
-
return /* @__PURE__ */ jsxs("div", { style: { padding: "12px", backgroundColor: "#252525" }, children: [
|
|
2470
|
+
return /* @__PURE__ */ jsxs("div", { style: { padding: "12px", backgroundColor: "var(--nice-bg-secondary, #252525)" }, children: [
|
|
2471
2471
|
/* @__PURE__ */ jsx(
|
|
2472
2472
|
"input",
|
|
2473
2473
|
{
|
|
2474
2474
|
type: "text",
|
|
2475
2475
|
value: e,
|
|
2476
|
-
onChange: (
|
|
2476
|
+
onChange: (n) => t(n.target.value),
|
|
2477
2477
|
placeholder: "Enter expression (e.g., x^2, sin(x))",
|
|
2478
2478
|
style: {
|
|
2479
2479
|
width: "100%",
|
|
2480
2480
|
padding: "8px",
|
|
2481
2481
|
marginBottom: "12px",
|
|
2482
|
-
backgroundColor: "#3c3c3c",
|
|
2483
|
-
color: "#fff",
|
|
2484
|
-
border: "1px solid #555",
|
|
2482
|
+
backgroundColor: "var(--nice-border, #3c3c3c)",
|
|
2483
|
+
color: "var(--nice-bg, #fff)",
|
|
2484
|
+
border: "1px solid var(--nice-text-secondary, #555)",
|
|
2485
2485
|
borderRadius: "4px"
|
|
2486
2486
|
}
|
|
2487
2487
|
}
|
|
@@ -2493,8 +2493,8 @@ function CalculusMode() {
|
|
|
2493
2493
|
onClick: () => a(`d/dx(${e}) = ${CalculusOps.symbolicDerivative(e)}`),
|
|
2494
2494
|
style: {
|
|
2495
2495
|
padding: "8px 12px",
|
|
2496
|
-
backgroundColor: "#4caf50",
|
|
2497
|
-
color: "#fff",
|
|
2496
|
+
backgroundColor: "var(--nice-success, #4caf50)",
|
|
2497
|
+
color: "var(--nice-bg, #fff)",
|
|
2498
2498
|
border: "none",
|
|
2499
2499
|
borderRadius: "4px",
|
|
2500
2500
|
cursor: "pointer"
|
|
@@ -2508,8 +2508,8 @@ function CalculusMode() {
|
|
|
2508
2508
|
onClick: () => a(`∫(${e})dx = ${CalculusOps.symbolicIntegral(e)}`),
|
|
2509
2509
|
style: {
|
|
2510
2510
|
padding: "8px 12px",
|
|
2511
|
-
backgroundColor: "#2196f3",
|
|
2512
|
-
color: "#fff",
|
|
2511
|
+
backgroundColor: "var(--nice-primary, #2196f3)",
|
|
2512
|
+
color: "var(--nice-bg, #fff)",
|
|
2513
2513
|
border: "none",
|
|
2514
2514
|
borderRadius: "4px",
|
|
2515
2515
|
cursor: "pointer"
|
|
@@ -2522,10 +2522,10 @@ function CalculusMode() {
|
|
|
2522
2522
|
"div",
|
|
2523
2523
|
{
|
|
2524
2524
|
style: {
|
|
2525
|
-
color: "#fff",
|
|
2525
|
+
color: "var(--nice-bg, #fff)",
|
|
2526
2526
|
fontFamily: "monospace",
|
|
2527
2527
|
padding: "8px",
|
|
2528
|
-
backgroundColor: "#1e1e1e",
|
|
2528
|
+
backgroundColor: "var(--nice-bg, #1e1e1e)",
|
|
2529
2529
|
borderRadius: "4px"
|
|
2530
2530
|
},
|
|
2531
2531
|
children: r
|
|
@@ -2534,15 +2534,15 @@ function CalculusMode() {
|
|
|
2534
2534
|
] });
|
|
2535
2535
|
}
|
|
2536
2536
|
function UnitsMode() {
|
|
2537
|
-
const { service: e } = useCalculator(), [t, r] = useState("1"), [a,
|
|
2537
|
+
const { service: e } = useCalculator(), [t, r] = useState("1"), [a, n] = useState("m"), [o, s] = useState("ft"), [c, l] = useState("Length"), [i, d] = useState(""), u = e.getUnitCategories(), h = e.getUnitsByCategory(c), b = () => {
|
|
2538
2538
|
try {
|
|
2539
|
-
const y = e.convertUnits(parseFloat(t), a,
|
|
2540
|
-
d(`${t} ${a} = ${e.format(y)} ${
|
|
2539
|
+
const y = e.convertUnits(parseFloat(t), a, o);
|
|
2540
|
+
d(`${t} ${a} = ${e.format(y)} ${o}`);
|
|
2541
2541
|
} catch (y) {
|
|
2542
2542
|
d(y.message);
|
|
2543
2543
|
}
|
|
2544
2544
|
};
|
|
2545
|
-
return /* @__PURE__ */ jsxs("div", { style: { padding: "12px", backgroundColor: "#252525" }, children: [
|
|
2545
|
+
return /* @__PURE__ */ jsxs("div", { style: { padding: "12px", backgroundColor: "var(--nice-bg-secondary, #252525)" }, children: [
|
|
2546
2546
|
/* @__PURE__ */ jsx(
|
|
2547
2547
|
"select",
|
|
2548
2548
|
{
|
|
@@ -2550,15 +2550,15 @@ function UnitsMode() {
|
|
|
2550
2550
|
onChange: (y) => {
|
|
2551
2551
|
l(y.target.value);
|
|
2552
2552
|
const g = e.getUnitsByCategory(y.target.value);
|
|
2553
|
-
g.length >= 2 && (
|
|
2553
|
+
g.length >= 2 && (n(g[0].symbol), s(g[1].symbol));
|
|
2554
2554
|
},
|
|
2555
2555
|
style: {
|
|
2556
2556
|
width: "100%",
|
|
2557
2557
|
padding: "8px",
|
|
2558
2558
|
marginBottom: "12px",
|
|
2559
|
-
backgroundColor: "#3c3c3c",
|
|
2560
|
-
color: "#fff",
|
|
2561
|
-
border: "1px solid #555",
|
|
2559
|
+
backgroundColor: "var(--nice-border, #3c3c3c)",
|
|
2560
|
+
color: "var(--nice-bg, #fff)",
|
|
2561
|
+
border: "1px solid var(--nice-text-secondary, #555)",
|
|
2562
2562
|
borderRadius: "4px"
|
|
2563
2563
|
},
|
|
2564
2564
|
children: u.map((y) => /* @__PURE__ */ jsx("option", { value: y, children: y }, y))
|
|
@@ -2574,9 +2574,9 @@ function UnitsMode() {
|
|
|
2574
2574
|
style: {
|
|
2575
2575
|
flex: 1,
|
|
2576
2576
|
padding: "8px",
|
|
2577
|
-
backgroundColor: "#3c3c3c",
|
|
2578
|
-
color: "#fff",
|
|
2579
|
-
border: "1px solid #555",
|
|
2577
|
+
backgroundColor: "var(--nice-border, #3c3c3c)",
|
|
2578
|
+
color: "var(--nice-bg, #fff)",
|
|
2579
|
+
border: "1px solid var(--nice-text-secondary, #555)",
|
|
2580
2580
|
borderRadius: "4px"
|
|
2581
2581
|
}
|
|
2582
2582
|
}
|
|
@@ -2585,12 +2585,12 @@ function UnitsMode() {
|
|
|
2585
2585
|
"select",
|
|
2586
2586
|
{
|
|
2587
2587
|
value: a,
|
|
2588
|
-
onChange: (y) =>
|
|
2588
|
+
onChange: (y) => n(y.target.value),
|
|
2589
2589
|
style: {
|
|
2590
2590
|
padding: "8px",
|
|
2591
|
-
backgroundColor: "#3c3c3c",
|
|
2592
|
-
color: "#fff",
|
|
2593
|
-
border: "1px solid #555",
|
|
2591
|
+
backgroundColor: "var(--nice-border, #3c3c3c)",
|
|
2592
|
+
color: "var(--nice-bg, #fff)",
|
|
2593
|
+
border: "1px solid var(--nice-text-secondary, #555)",
|
|
2594
2594
|
borderRadius: "4px"
|
|
2595
2595
|
},
|
|
2596
2596
|
children: h.map((y) => /* @__PURE__ */ jsxs("option", { value: y.symbol, children: [
|
|
@@ -2603,18 +2603,18 @@ function UnitsMode() {
|
|
|
2603
2603
|
)
|
|
2604
2604
|
] }),
|
|
2605
2605
|
/* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: "8px", alignItems: "center", marginBottom: "12px" }, children: [
|
|
2606
|
-
/* @__PURE__ */ jsx("span", { style: { color: "#888" }, children: "→" }),
|
|
2606
|
+
/* @__PURE__ */ jsx("span", { style: { color: "var(--nice-text-secondary, #888)" }, children: "→" }),
|
|
2607
2607
|
/* @__PURE__ */ jsx(
|
|
2608
2608
|
"select",
|
|
2609
2609
|
{
|
|
2610
|
-
value:
|
|
2610
|
+
value: o,
|
|
2611
2611
|
onChange: (y) => s(y.target.value),
|
|
2612
2612
|
style: {
|
|
2613
2613
|
flex: 1,
|
|
2614
2614
|
padding: "8px",
|
|
2615
|
-
backgroundColor: "#3c3c3c",
|
|
2616
|
-
color: "#fff",
|
|
2617
|
-
border: "1px solid #555",
|
|
2615
|
+
backgroundColor: "var(--nice-border, #3c3c3c)",
|
|
2616
|
+
color: "var(--nice-bg, #fff)",
|
|
2617
|
+
border: "1px solid var(--nice-text-secondary, #555)",
|
|
2618
2618
|
borderRadius: "4px"
|
|
2619
2619
|
},
|
|
2620
2620
|
children: h.map((y) => /* @__PURE__ */ jsxs("option", { value: y.symbol, children: [
|
|
@@ -2633,8 +2633,8 @@ function UnitsMode() {
|
|
|
2633
2633
|
style: {
|
|
2634
2634
|
width: "100%",
|
|
2635
2635
|
padding: "12px",
|
|
2636
|
-
backgroundColor: "#ff9f0a",
|
|
2637
|
-
color: "#000",
|
|
2636
|
+
backgroundColor: "var(--nice-warning, #ff9f0a)",
|
|
2637
|
+
color: "var(--nice-text, #000)",
|
|
2638
2638
|
border: "none",
|
|
2639
2639
|
borderRadius: "4px",
|
|
2640
2640
|
fontSize: "16px",
|
|
@@ -2643,7 +2643,7 @@ function UnitsMode() {
|
|
|
2643
2643
|
children: "Convert"
|
|
2644
2644
|
}
|
|
2645
2645
|
),
|
|
2646
|
-
i && /* @__PURE__ */ jsx("div", { style: { marginTop: "12px", color: "#fff", fontSize: "18px", textAlign: "center" }, children: i })
|
|
2646
|
+
i && /* @__PURE__ */ jsx("div", { style: { marginTop: "12px", color: "var(--nice-bg, #fff)", fontSize: "18px", textAlign: "center" }, children: i })
|
|
2647
2647
|
] });
|
|
2648
2648
|
}
|
|
2649
2649
|
const GeoMath = {
|
|
@@ -2658,8 +2658,8 @@ const GeoMath = {
|
|
|
2658
2658
|
/** Angle between three points (vertex at p2) */
|
|
2659
2659
|
angle(e, t, r) {
|
|
2660
2660
|
const a = Math.atan2(e.y - t.y, e.x - t.x);
|
|
2661
|
-
let
|
|
2662
|
-
return
|
|
2661
|
+
let o = Math.atan2(r.y - t.y, r.x - t.x) - a;
|
|
2662
|
+
return o < 0 && (o += 2 * Math.PI), o;
|
|
2663
2663
|
},
|
|
2664
2664
|
/** Angle in degrees */
|
|
2665
2665
|
angleDegrees(e, t, r) {
|
|
@@ -2667,63 +2667,63 @@ const GeoMath = {
|
|
|
2667
2667
|
},
|
|
2668
2668
|
/** Point on line closest to given point */
|
|
2669
2669
|
closestPointOnLine(e, t, r) {
|
|
2670
|
-
const a = t.x - e.x,
|
|
2671
|
-
return { x: e.x +
|
|
2670
|
+
const a = t.x - e.x, n = t.y - e.y, o = ((r.x - e.x) * a + (r.y - e.y) * n) / (a * a + n * n);
|
|
2671
|
+
return { x: e.x + o * a, y: e.y + o * n };
|
|
2672
2672
|
},
|
|
2673
2673
|
/** Line-line intersection */
|
|
2674
2674
|
lineIntersection(e, t, r, a) {
|
|
2675
|
-
const
|
|
2676
|
-
if (Math.abs(
|
|
2675
|
+
const n = (e.x - t.x) * (r.y - a.y) - (e.y - t.y) * (r.x - a.x);
|
|
2676
|
+
if (Math.abs(n) < 1e-10)
|
|
2677
2677
|
return null;
|
|
2678
|
-
const
|
|
2678
|
+
const o = ((e.x - r.x) * (r.y - a.y) - (e.y - r.y) * (r.x - a.x)) / n;
|
|
2679
2679
|
return {
|
|
2680
|
-
x: e.x +
|
|
2681
|
-
y: e.y +
|
|
2680
|
+
x: e.x + o * (t.x - e.x),
|
|
2681
|
+
y: e.y + o * (t.y - e.y)
|
|
2682
2682
|
};
|
|
2683
2683
|
},
|
|
2684
2684
|
/** Circle-line intersection */
|
|
2685
2685
|
circleLineIntersection(e, t, r, a) {
|
|
2686
|
-
const
|
|
2686
|
+
const n = a.x - r.x, o = a.y - r.y, s = r.x - e.x, c = r.y - e.y, l = n * n + o * o, i = 2 * (s * n + c * o), d = s * s + c * c - t * t, u = i * i - 4 * l * d;
|
|
2687
2687
|
if (u < 0)
|
|
2688
2688
|
return [];
|
|
2689
2689
|
const h = Math.sqrt(u), b = (-i - h) / (2 * l), y = (-i + h) / (2 * l), g = [];
|
|
2690
|
-
return b >= 0 && b <= 1 && g.push({ x: r.x + b *
|
|
2690
|
+
return b >= 0 && b <= 1 && g.push({ x: r.x + b * n, y: r.y + b * o }), y >= 0 && y <= 1 && Math.abs(y - b) > 1e-10 && g.push({ x: r.x + y * n, y: r.y + y * o }), g;
|
|
2691
2691
|
},
|
|
2692
2692
|
/** Circle-circle intersection */
|
|
2693
2693
|
circleCircleIntersection(e, t, r, a) {
|
|
2694
|
-
const
|
|
2695
|
-
if (
|
|
2694
|
+
const n = this.distance(e, r);
|
|
2695
|
+
if (n > t + a || n < Math.abs(t - a) || n === 0)
|
|
2696
2696
|
return [];
|
|
2697
|
-
const
|
|
2697
|
+
const o = (t * t - a * a + n * n) / (2 * n), s = Math.sqrt(t * t - o * o), c = e.x + o * (r.x - e.x) / n, l = e.y + o * (r.y - e.y) / n;
|
|
2698
2698
|
return [
|
|
2699
|
-
{ x: c + s * (r.y - e.y) /
|
|
2700
|
-
{ x: c - s * (r.y - e.y) /
|
|
2699
|
+
{ x: c + s * (r.y - e.y) / n, y: l - s * (r.x - e.x) / n },
|
|
2700
|
+
{ x: c - s * (r.y - e.y) / n, y: l + s * (r.x - e.x) / n }
|
|
2701
2701
|
];
|
|
2702
2702
|
},
|
|
2703
2703
|
/** Perpendicular line through point */
|
|
2704
2704
|
perpendicularThrough(e, t, r) {
|
|
2705
2705
|
this.closestPointOnLine(e, t, r);
|
|
2706
|
-
const a = t.x - e.x,
|
|
2706
|
+
const a = t.x - e.x, n = t.y - e.y;
|
|
2707
2707
|
return {
|
|
2708
2708
|
p1: r,
|
|
2709
|
-
p2: { x: r.x -
|
|
2709
|
+
p2: { x: r.x - n, y: r.y + a }
|
|
2710
2710
|
};
|
|
2711
2711
|
},
|
|
2712
2712
|
/** Parallel line through point */
|
|
2713
2713
|
parallelThrough(e, t, r) {
|
|
2714
|
-
const a = t.x - e.x,
|
|
2714
|
+
const a = t.x - e.x, n = t.y - e.y;
|
|
2715
2715
|
return {
|
|
2716
2716
|
p1: r,
|
|
2717
|
-
p2: { x: r.x + a, y: r.y +
|
|
2717
|
+
p2: { x: r.x + a, y: r.y + n }
|
|
2718
2718
|
};
|
|
2719
2719
|
},
|
|
2720
2720
|
/** Angle bisector */
|
|
2721
2721
|
angleBisector(e, t, r) {
|
|
2722
|
-
const a = Math.atan2(e.y - t.y, e.x - t.x),
|
|
2723
|
-
let
|
|
2724
|
-
return Math.abs(
|
|
2725
|
-
x: t.x + Math.cos(
|
|
2726
|
-
y: t.y + Math.sin(
|
|
2722
|
+
const a = Math.atan2(e.y - t.y, e.x - t.x), n = Math.atan2(r.y - t.y, r.x - t.x);
|
|
2723
|
+
let o = (a + n) / 2;
|
|
2724
|
+
return Math.abs(n - a) > Math.PI && (o += Math.PI), {
|
|
2725
|
+
x: t.x + Math.cos(o),
|
|
2726
|
+
y: t.y + Math.sin(o)
|
|
2727
2727
|
};
|
|
2728
2728
|
},
|
|
2729
2729
|
/** Reflect point over line */
|
|
@@ -2736,10 +2736,10 @@ const GeoMath = {
|
|
|
2736
2736
|
},
|
|
2737
2737
|
/** Rotate point around center */
|
|
2738
2738
|
rotate(e, t, r) {
|
|
2739
|
-
const a = Math.cos(r),
|
|
2739
|
+
const a = Math.cos(r), n = Math.sin(r), o = e.x - t.x, s = e.y - t.y;
|
|
2740
2740
|
return {
|
|
2741
|
-
x: t.x +
|
|
2742
|
-
y: t.y +
|
|
2741
|
+
x: t.x + o * a - s * n,
|
|
2742
|
+
y: t.y + o * n + s * a
|
|
2743
2743
|
};
|
|
2744
2744
|
},
|
|
2745
2745
|
/** Translate point */
|
|
@@ -2758,8 +2758,8 @@ const GeoMath = {
|
|
|
2758
2758
|
let t = 0;
|
|
2759
2759
|
const r = e.length;
|
|
2760
2760
|
for (let a = 0; a < r; a++) {
|
|
2761
|
-
const
|
|
2762
|
-
t += e[a].x * e[
|
|
2761
|
+
const n = (a + 1) % r;
|
|
2762
|
+
t += e[a].x * e[n].y, t -= e[n].x * e[a].y;
|
|
2763
2763
|
}
|
|
2764
2764
|
return Math.abs(t) / 2;
|
|
2765
2765
|
},
|
|
@@ -2768,22 +2768,22 @@ const GeoMath = {
|
|
|
2768
2768
|
let t = 0;
|
|
2769
2769
|
const r = e.length;
|
|
2770
2770
|
for (let a = 0; a < r; a++) {
|
|
2771
|
-
const
|
|
2772
|
-
t += this.distance(e[a], e[
|
|
2771
|
+
const n = (a + 1) % r;
|
|
2772
|
+
t += this.distance(e[a], e[n]);
|
|
2773
2773
|
}
|
|
2774
2774
|
return t;
|
|
2775
2775
|
},
|
|
2776
2776
|
/** Triangle circumcenter */
|
|
2777
2777
|
circumcenter(e, t, r) {
|
|
2778
|
-
const a = 2 * (e.x * (t.y - r.y) + t.x * (r.y - e.y) + r.x * (e.y - t.y)),
|
|
2779
|
-
return { x:
|
|
2778
|
+
const a = 2 * (e.x * (t.y - r.y) + t.x * (r.y - e.y) + r.x * (e.y - t.y)), n = ((e.x ** 2 + e.y ** 2) * (t.y - r.y) + (t.x ** 2 + t.y ** 2) * (r.y - e.y) + (r.x ** 2 + r.y ** 2) * (e.y - t.y)) / a, o = ((e.x ** 2 + e.y ** 2) * (r.x - t.x) + (t.x ** 2 + t.y ** 2) * (e.x - r.x) + (r.x ** 2 + r.y ** 2) * (t.x - e.x)) / a;
|
|
2779
|
+
return { x: n, y: o };
|
|
2780
2780
|
},
|
|
2781
2781
|
/** Triangle incenter */
|
|
2782
2782
|
incenter(e, t, r) {
|
|
2783
|
-
const a = this.distance(e, t),
|
|
2783
|
+
const a = this.distance(e, t), n = this.distance(t, r), o = this.distance(r, e), s = a + n + o;
|
|
2784
2784
|
return {
|
|
2785
|
-
x: (
|
|
2786
|
-
y: (
|
|
2785
|
+
x: (n * e.x + o * t.x + a * r.x) / s,
|
|
2786
|
+
y: (n * e.y + o * t.y + a * r.y) / s
|
|
2787
2787
|
};
|
|
2788
2788
|
},
|
|
2789
2789
|
/** Triangle centroid */
|
|
@@ -2822,8 +2822,8 @@ class GeometryService {
|
|
|
2822
2822
|
deleteElement(t) {
|
|
2823
2823
|
var r;
|
|
2824
2824
|
this.elements.delete(t);
|
|
2825
|
-
for (const [a,
|
|
2826
|
-
(r =
|
|
2825
|
+
for (const [a, n] of this.elements)
|
|
2826
|
+
(r = n.dependencies) != null && r.includes(t) && this.deleteElement(a);
|
|
2827
2827
|
}
|
|
2828
2828
|
/** Get all elements */
|
|
2829
2829
|
getAllElements() {
|
|
@@ -2928,46 +2928,46 @@ class GeometryService {
|
|
|
2928
2928
|
}
|
|
2929
2929
|
/** Create midpoint */
|
|
2930
2930
|
createMidpoint(t, r) {
|
|
2931
|
-
const a = this.getPoint(t),
|
|
2932
|
-
if (!a || !
|
|
2931
|
+
const a = this.getPoint(t), n = this.getPoint(r);
|
|
2932
|
+
if (!a || !n)
|
|
2933
2933
|
return null;
|
|
2934
|
-
const
|
|
2934
|
+
const o = GeoMath.midpoint(a, n), s = this.createPoint(o.x, o.y);
|
|
2935
2935
|
return s.dependencies = [t, r], s.color = { r: 0, g: 150, b: 0 }, s;
|
|
2936
2936
|
}
|
|
2937
2937
|
/** Create perpendicular */
|
|
2938
2938
|
createPerpendicular(t, r, a) {
|
|
2939
|
-
const
|
|
2940
|
-
if (!
|
|
2939
|
+
const n = this.getPoint(t), o = this.getPoint(r), s = this.getPoint(a);
|
|
2940
|
+
if (!n || !o || !s)
|
|
2941
2941
|
return null;
|
|
2942
|
-
const c = GeoMath.perpendicularThrough(
|
|
2942
|
+
const c = GeoMath.perpendicularThrough(n, o, s), l = this.createPoint(c.p2.x, c.p2.y), i = this.createLine(a, l.id);
|
|
2943
2943
|
return i.dependencies = [t, r, a], i;
|
|
2944
2944
|
}
|
|
2945
2945
|
/** Create parallel */
|
|
2946
2946
|
createParallel(t, r, a) {
|
|
2947
|
-
const
|
|
2948
|
-
if (!
|
|
2947
|
+
const n = this.getPoint(t), o = this.getPoint(r), s = this.getPoint(a);
|
|
2948
|
+
if (!n || !o || !s)
|
|
2949
2949
|
return null;
|
|
2950
|
-
const c = GeoMath.parallelThrough(
|
|
2950
|
+
const c = GeoMath.parallelThrough(n, o, s), l = this.createPoint(c.p2.x, c.p2.y), i = this.createLine(a, l.id);
|
|
2951
2951
|
return i.dependencies = [t, r, a], i;
|
|
2952
2952
|
}
|
|
2953
2953
|
/** Create intersection point */
|
|
2954
2954
|
createIntersection(t, r) {
|
|
2955
|
-
const a = this.elements.get(t),
|
|
2956
|
-
if (!a || !
|
|
2955
|
+
const a = this.elements.get(t), n = this.elements.get(r);
|
|
2956
|
+
if (!a || !n)
|
|
2957
2957
|
return [];
|
|
2958
|
-
const
|
|
2958
|
+
const o = [], s = (i) => {
|
|
2959
2959
|
if (i.type === "line" || i.type === "segment" || i.type === "ray") {
|
|
2960
2960
|
const d = i, u = this.getPoint(d.point1Id ?? d.originId), h = this.getPoint(d.point2Id ?? d.throughId);
|
|
2961
2961
|
if (u && h)
|
|
2962
2962
|
return [u, h];
|
|
2963
2963
|
}
|
|
2964
2964
|
return null;
|
|
2965
|
-
}, c = s(a), l = s(
|
|
2965
|
+
}, c = s(a), l = s(n);
|
|
2966
2966
|
if (c && l) {
|
|
2967
2967
|
const i = GeoMath.lineIntersection(c[0], c[1], l[0], l[1]);
|
|
2968
2968
|
if (i) {
|
|
2969
2969
|
const d = this.createPoint(i.x, i.y);
|
|
2970
|
-
d.dependencies = [t, r], d.color = { r: 255, g: 0, b: 0 },
|
|
2970
|
+
d.dependencies = [t, r], d.color = { r: 255, g: 0, b: 0 }, o.push(d);
|
|
2971
2971
|
}
|
|
2972
2972
|
}
|
|
2973
2973
|
if (a.type === "circle" && l) {
|
|
@@ -2976,43 +2976,43 @@ class GeometryService {
|
|
|
2976
2976
|
const u = GeoMath.circleLineIntersection(d, i.radius, l[0], l[1]);
|
|
2977
2977
|
for (const h of u) {
|
|
2978
2978
|
const b = this.createPoint(h.x, h.y);
|
|
2979
|
-
b.dependencies = [t, r], b.color = { r: 255, g: 0, b: 0 },
|
|
2979
|
+
b.dependencies = [t, r], b.color = { r: 255, g: 0, b: 0 }, o.push(b);
|
|
2980
2980
|
}
|
|
2981
2981
|
}
|
|
2982
2982
|
}
|
|
2983
|
-
if (a.type === "circle" &&
|
|
2984
|
-
const i = a, d =
|
|
2983
|
+
if (a.type === "circle" && n.type === "circle") {
|
|
2984
|
+
const i = a, d = n, u = this.getPoint(i.centerId), h = this.getPoint(d.centerId);
|
|
2985
2985
|
if (u && h) {
|
|
2986
2986
|
const b = GeoMath.circleCircleIntersection(u, i.radius, h, d.radius);
|
|
2987
2987
|
for (const y of b) {
|
|
2988
2988
|
const g = this.createPoint(y.x, y.y);
|
|
2989
|
-
g.dependencies = [t, r], g.color = { r: 255, g: 0, b: 0 },
|
|
2989
|
+
g.dependencies = [t, r], g.color = { r: 255, g: 0, b: 0 }, o.push(g);
|
|
2990
2990
|
}
|
|
2991
2991
|
}
|
|
2992
2992
|
}
|
|
2993
|
-
return
|
|
2993
|
+
return o;
|
|
2994
2994
|
}
|
|
2995
2995
|
/** Calculate measurement */
|
|
2996
2996
|
calculateMeasurement(t, r) {
|
|
2997
2997
|
switch (t) {
|
|
2998
2998
|
case "distance": {
|
|
2999
|
-
const a = this.getPoint(r[0]),
|
|
3000
|
-
if (a &&
|
|
3001
|
-
return GeoMath.distance(a,
|
|
2999
|
+
const a = this.getPoint(r[0]), n = this.getPoint(r[1]);
|
|
3000
|
+
if (a && n)
|
|
3001
|
+
return GeoMath.distance(a, n);
|
|
3002
3002
|
break;
|
|
3003
3003
|
}
|
|
3004
3004
|
case "angle": {
|
|
3005
|
-
const a = this.getPoint(r[0]),
|
|
3006
|
-
if (a &&
|
|
3007
|
-
return GeoMath.angleDegrees(a,
|
|
3005
|
+
const a = this.getPoint(r[0]), n = this.getPoint(r[1]), o = this.getPoint(r[2]);
|
|
3006
|
+
if (a && n && o)
|
|
3007
|
+
return GeoMath.angleDegrees(a, n, o);
|
|
3008
3008
|
break;
|
|
3009
3009
|
}
|
|
3010
3010
|
case "area":
|
|
3011
3011
|
case "perimeter": {
|
|
3012
3012
|
const a = this.elements.get(r[0]);
|
|
3013
3013
|
if ((a == null ? void 0 : a.type) === "polygon") {
|
|
3014
|
-
const
|
|
3015
|
-
return t === "area" ? GeoMath.polygonArea(
|
|
3014
|
+
const n = a.pointIds.map((o) => this.getPoint(o)).filter(Boolean);
|
|
3015
|
+
return t === "area" ? GeoMath.polygonArea(n) : GeoMath.polygonPerimeter(n);
|
|
3016
3016
|
}
|
|
3017
3017
|
break;
|
|
3018
3018
|
}
|
|
@@ -3021,31 +3021,31 @@ class GeometryService {
|
|
|
3021
3021
|
}
|
|
3022
3022
|
/** Export to SVG */
|
|
3023
3023
|
exportSVG(t, r, a) {
|
|
3024
|
-
const
|
|
3024
|
+
const n = [
|
|
3025
3025
|
`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${r}" viewBox="0 0 ${t} ${r}">`
|
|
3026
3026
|
];
|
|
3027
|
-
|
|
3027
|
+
n.push(
|
|
3028
3028
|
`<rect width="100%" height="100%" fill="rgb(${a.backgroundColor.r},${a.backgroundColor.g},${a.backgroundColor.b})"/>`
|
|
3029
3029
|
);
|
|
3030
|
-
const
|
|
3030
|
+
const o = (s, c) => ({
|
|
3031
3031
|
x: t / 2 + (s - a.centerX) * a.scale,
|
|
3032
3032
|
y: r / 2 - (c - a.centerY) * a.scale
|
|
3033
3033
|
});
|
|
3034
3034
|
if (a.showGrid) {
|
|
3035
|
-
|
|
3035
|
+
n.push('<g stroke="var(--nice-border, #ddd)" stroke-width="0.5">');
|
|
3036
3036
|
for (let s = Math.floor(-t / 2 / a.scale + a.centerX); s <= t / 2 / a.scale + a.centerX; s += a.gridSpacing) {
|
|
3037
|
-
const c =
|
|
3038
|
-
|
|
3037
|
+
const c = o(s, 0);
|
|
3038
|
+
n.push(`<line x1="${c.x}" y1="0" x2="${c.x}" y2="${r}"/>`);
|
|
3039
3039
|
}
|
|
3040
3040
|
for (let s = Math.floor(-r / 2 / a.scale + a.centerY); s <= r / 2 / a.scale + a.centerY; s += a.gridSpacing) {
|
|
3041
|
-
const c =
|
|
3042
|
-
|
|
3041
|
+
const c = o(0, s);
|
|
3042
|
+
n.push(`<line x1="0" y1="${c.y}" x2="${t}" y2="${c.y}"/>`);
|
|
3043
3043
|
}
|
|
3044
|
-
|
|
3044
|
+
n.push("</g>");
|
|
3045
3045
|
}
|
|
3046
3046
|
if (a.showAxes) {
|
|
3047
|
-
const s =
|
|
3048
|
-
|
|
3047
|
+
const s = o(0, 0);
|
|
3048
|
+
n.push('<g stroke="var(--nice-text, #333)" stroke-width="1">'), n.push(`<line x1="0" y1="${s.y}" x2="${t}" y2="${s.y}"/>`), n.push(`<line x1="${s.x}" y1="0" x2="${s.x}" y2="${r}"/>`), n.push("</g>");
|
|
3049
3049
|
}
|
|
3050
3050
|
for (const s of this.getAllElements()) {
|
|
3051
3051
|
if (!s.visible)
|
|
@@ -3053,15 +3053,15 @@ class GeometryService {
|
|
|
3053
3053
|
const c = `rgb(${s.color.r},${s.color.g},${s.color.b})`;
|
|
3054
3054
|
switch (s.type) {
|
|
3055
3055
|
case "point": {
|
|
3056
|
-
const l =
|
|
3057
|
-
|
|
3056
|
+
const l = o(s.x, s.y);
|
|
3057
|
+
n.push(`<circle cx="${l.x}" cy="${l.y}" r="${s.size}" fill="${c}"/>`), s.label && n.push(`<text x="${l.x + 8}" y="${l.y - 8}" font-size="12">${s.label}</text>`);
|
|
3058
3058
|
break;
|
|
3059
3059
|
}
|
|
3060
3060
|
case "segment": {
|
|
3061
3061
|
const l = this.getPoint(s.point1Id), i = this.getPoint(s.point2Id);
|
|
3062
3062
|
if (l && i) {
|
|
3063
|
-
const d =
|
|
3064
|
-
|
|
3063
|
+
const d = o(l.x, l.y), u = o(i.x, i.y);
|
|
3064
|
+
n.push(
|
|
3065
3065
|
`<line x1="${d.x}" y1="${d.y}" x2="${u.x}" y2="${u.y}" stroke="${c}" stroke-width="${s.width}"/>`
|
|
3066
3066
|
);
|
|
3067
3067
|
}
|
|
@@ -3070,8 +3070,8 @@ class GeometryService {
|
|
|
3070
3070
|
case "circle": {
|
|
3071
3071
|
const l = this.getPoint(s.centerId);
|
|
3072
3072
|
if (l) {
|
|
3073
|
-
const i =
|
|
3074
|
-
|
|
3073
|
+
const i = o(l.x, l.y), d = s.radius * a.scale, u = s.fill ? `rgba(${s.fill.r},${s.fill.g},${s.fill.b},${s.fill.a ?? 0.2})` : "none";
|
|
3074
|
+
n.push(
|
|
3075
3075
|
`<circle cx="${i.x}" cy="${i.y}" r="${d}" fill="${u}" stroke="${c}" stroke-width="${s.width}"/>`
|
|
3076
3076
|
);
|
|
3077
3077
|
}
|
|
@@ -3080,8 +3080,8 @@ class GeometryService {
|
|
|
3080
3080
|
case "polygon": {
|
|
3081
3081
|
const l = s.pointIds.map((i) => this.getPoint(i)).filter(Boolean);
|
|
3082
3082
|
if (l.length > 0) {
|
|
3083
|
-
const d = l.map((h) =>
|
|
3084
|
-
|
|
3083
|
+
const d = l.map((h) => o(h.x, h.y)).map((h, b) => `${b === 0 ? "M" : "L"}${h.x},${h.y}`).join(" ") + " Z", u = s.fill ? `rgba(${s.fill.r},${s.fill.g},${s.fill.b},${s.fill.a ?? 0.2})` : "none";
|
|
3084
|
+
n.push(
|
|
3085
3085
|
`<path d="${d}" fill="${u}" stroke="${c}" stroke-width="${s.width}"/>`
|
|
3086
3086
|
);
|
|
3087
3087
|
}
|
|
@@ -3089,7 +3089,7 @@ class GeometryService {
|
|
|
3089
3089
|
}
|
|
3090
3090
|
}
|
|
3091
3091
|
}
|
|
3092
|
-
return
|
|
3092
|
+
return n.push("</svg>"), n.join(`
|
|
3093
3093
|
`);
|
|
3094
3094
|
}
|
|
3095
3095
|
generateId() {
|
|
@@ -3119,8 +3119,8 @@ const styles = {
|
|
|
3119
3119
|
},
|
|
3120
3120
|
toolbar: {
|
|
3121
3121
|
width: "50px",
|
|
3122
|
-
backgroundColor: "#f5f5f5",
|
|
3123
|
-
borderRight: "1px solid #e0e0e0",
|
|
3122
|
+
backgroundColor: "var(--nice-bg-secondary, #f5f5f5)",
|
|
3123
|
+
borderRight: "1px solid var(--nice-border, #e0e0e0)",
|
|
3124
3124
|
display: "flex",
|
|
3125
3125
|
flexDirection: "column",
|
|
3126
3126
|
padding: "8px 4px",
|
|
@@ -3150,13 +3150,13 @@ const styles = {
|
|
|
3150
3150
|
},
|
|
3151
3151
|
statusBar: {
|
|
3152
3152
|
height: "30px",
|
|
3153
|
-
backgroundColor: "#f5f5f5",
|
|
3154
|
-
borderTop: "1px solid #e0e0e0",
|
|
3153
|
+
backgroundColor: "var(--nice-bg-secondary, #f5f5f5)",
|
|
3154
|
+
borderTop: "1px solid var(--nice-border, #e0e0e0)",
|
|
3155
3155
|
padding: "0 12px",
|
|
3156
3156
|
display: "flex",
|
|
3157
3157
|
alignItems: "center",
|
|
3158
3158
|
fontSize: "12px",
|
|
3159
|
-
color: "#666"
|
|
3159
|
+
color: "var(--nice-text-secondary, #666)"
|
|
3160
3160
|
}
|
|
3161
3161
|
};
|
|
3162
3162
|
function NiceGeometry({
|
|
@@ -3164,9 +3164,9 @@ function NiceGeometry({
|
|
|
3164
3164
|
width: t = 800,
|
|
3165
3165
|
height: r = 600,
|
|
3166
3166
|
className: a,
|
|
3167
|
-
style:
|
|
3167
|
+
style: n
|
|
3168
3168
|
}) {
|
|
3169
|
-
const [
|
|
3169
|
+
const [o, s] = useState([]), [c, l] = useState("point"), [i, d] = useState([]), [u, h] = useState({
|
|
3170
3170
|
centerX: 0,
|
|
3171
3171
|
centerY: 0,
|
|
3172
3172
|
scale: 40,
|
|
@@ -3186,7 +3186,7 @@ function NiceGeometry({
|
|
|
3186
3186
|
}, [b]);
|
|
3187
3187
|
const g = {
|
|
3188
3188
|
service: e,
|
|
3189
|
-
elements:
|
|
3189
|
+
elements: o,
|
|
3190
3190
|
tool: c,
|
|
3191
3191
|
setTool: l,
|
|
3192
3192
|
view: u,
|
|
@@ -3195,7 +3195,7 @@ function NiceGeometry({
|
|
|
3195
3195
|
setSelectedIds: d,
|
|
3196
3196
|
refresh: b
|
|
3197
3197
|
};
|
|
3198
|
-
return /* @__PURE__ */ jsx(GeometryContext.Provider, { value: g, children: /* @__PURE__ */ jsxs("div", { className: a, style: { ...styles.container, ...
|
|
3198
|
+
return /* @__PURE__ */ jsx(GeometryContext.Provider, { value: g, children: /* @__PURE__ */ jsxs("div", { className: a, style: { ...styles.container, ...n }, children: [
|
|
3199
3199
|
/* @__PURE__ */ jsx(Toolbar, {}),
|
|
3200
3200
|
/* @__PURE__ */ jsxs("div", { style: styles.main, children: [
|
|
3201
3201
|
/* @__PURE__ */ jsx(Canvas, { width: t, height: r }),
|
|
@@ -3228,8 +3228,8 @@ function Toolbar() {
|
|
|
3228
3228
|
title: a.title,
|
|
3229
3229
|
style: {
|
|
3230
3230
|
...styles.toolButton,
|
|
3231
|
-
backgroundColor: e === a.id ? "#1976d2" : "transparent",
|
|
3232
|
-
color: e === a.id ? "#fff" : "#333"
|
|
3231
|
+
backgroundColor: e === a.id ? "var(--nice-primary-hover, #1976d2)" : "transparent",
|
|
3232
|
+
color: e === a.id ? "var(--nice-bg, #fff)" : "var(--nice-text, #333)"
|
|
3233
3233
|
},
|
|
3234
3234
|
children: a.icon
|
|
3235
3235
|
},
|
|
@@ -3237,7 +3237,7 @@ function Toolbar() {
|
|
|
3237
3237
|
)) });
|
|
3238
3238
|
}
|
|
3239
3239
|
function Canvas({ width: e, height: t }) {
|
|
3240
|
-
const r = useRef(null), { service: a, elements:
|
|
3240
|
+
const r = useRef(null), { service: a, elements: n, tool: o, view: s, selectedIds: c, setSelectedIds: l, refresh: i } = useGeometry(), [d, u] = useState([]), h = useCallback(
|
|
3241
3241
|
(m, p) => {
|
|
3242
3242
|
const x = (m - e / 2) / s.scale + s.centerX, w = -(p - t / 2) / s.scale + s.centerY;
|
|
3243
3243
|
return s.snapToGrid ? {
|
|
@@ -3259,7 +3259,7 @@ function Canvas({ width: e, height: t }) {
|
|
|
3259
3259
|
if (!p)
|
|
3260
3260
|
return;
|
|
3261
3261
|
const x = h(m.clientX - p.left, m.clientY - p.top);
|
|
3262
|
-
switch (
|
|
3262
|
+
switch (o) {
|
|
3263
3263
|
case "point": {
|
|
3264
3264
|
a.createPoint(x.x, x.y), i();
|
|
3265
3265
|
break;
|
|
@@ -3271,13 +3271,13 @@ function Canvas({ width: e, height: t }) {
|
|
|
3271
3271
|
if (k)
|
|
3272
3272
|
u((f) => {
|
|
3273
3273
|
const v = [...f, k.id];
|
|
3274
|
-
return v.length === 2 ? (
|
|
3274
|
+
return v.length === 2 ? (o === "segment" ? a.createSegment(v[0], v[1]) : o === "line" ? a.createLine(v[0], v[1]) : o === "ray" && a.createRay(v[0], v[1]), i(), []) : v;
|
|
3275
3275
|
});
|
|
3276
3276
|
else {
|
|
3277
3277
|
const f = a.createPoint(x.x, x.y);
|
|
3278
3278
|
u((v) => {
|
|
3279
3279
|
const C = [...v, f.id];
|
|
3280
|
-
return C.length === 2 ? (
|
|
3280
|
+
return C.length === 2 ? (o === "segment" ? a.createSegment(C[0], C[1]) : o === "line" ? a.createLine(C[0], C[1]) : o === "ray" && a.createRay(C[0], C[1]), i(), []) : C;
|
|
3281
3281
|
}), i();
|
|
3282
3282
|
}
|
|
3283
3283
|
break;
|
|
@@ -3322,9 +3322,9 @@ function Canvas({ width: e, height: t }) {
|
|
|
3322
3322
|
}
|
|
3323
3323
|
}
|
|
3324
3324
|
},
|
|
3325
|
-
[
|
|
3325
|
+
[o, a, i, h, d, l]
|
|
3326
3326
|
), g = (m) => {
|
|
3327
|
-
for (const x of
|
|
3327
|
+
for (const x of n)
|
|
3328
3328
|
if (x.type === "point" && GeoMath.distance(x, m) < 0.5)
|
|
3329
3329
|
return x;
|
|
3330
3330
|
};
|
|
@@ -3332,7 +3332,7 @@ function Canvas({ width: e, height: t }) {
|
|
|
3332
3332
|
const m = r.current, p = m == null ? void 0 : m.getContext("2d");
|
|
3333
3333
|
if (!(!m || !p)) {
|
|
3334
3334
|
if (p.fillStyle = `rgb(${s.backgroundColor.r},${s.backgroundColor.g},${s.backgroundColor.b})`, p.fillRect(0, 0, e, t), s.showGrid) {
|
|
3335
|
-
p.strokeStyle = "#e0e0e0", p.lineWidth = 0.5;
|
|
3335
|
+
p.strokeStyle = "var(--nice-border, #e0e0e0)", p.lineWidth = 0.5;
|
|
3336
3336
|
const x = s.gridSpacing * s.scale, w = (e / 2 - s.centerX * s.scale) % x, k = (t / 2 + s.centerY * s.scale) % x;
|
|
3337
3337
|
for (let f = w; f < e; f += x)
|
|
3338
3338
|
p.beginPath(), p.moveTo(f, 0), p.lineTo(f, t), p.stroke();
|
|
@@ -3341,16 +3341,16 @@ function Canvas({ width: e, height: t }) {
|
|
|
3341
3341
|
}
|
|
3342
3342
|
if (s.showAxes) {
|
|
3343
3343
|
const x = b(0, 0);
|
|
3344
|
-
p.strokeStyle = "#333", p.lineWidth = 1, p.beginPath(), p.moveTo(0, x.y), p.lineTo(e, x.y), p.stroke(), p.beginPath(), p.moveTo(x.x, 0), p.lineTo(x.x, t), p.stroke();
|
|
3344
|
+
p.strokeStyle = "var(--nice-text, #333)", p.lineWidth = 1, p.beginPath(), p.moveTo(0, x.y), p.lineTo(e, x.y), p.stroke(), p.beginPath(), p.moveTo(x.x, 0), p.lineTo(x.x, t), p.stroke();
|
|
3345
3345
|
}
|
|
3346
|
-
for (const x of
|
|
3346
|
+
for (const x of n) {
|
|
3347
3347
|
if (!x.visible)
|
|
3348
3348
|
continue;
|
|
3349
3349
|
const w = `rgb(${x.color.r},${x.color.g},${x.color.b})`, k = c.includes(x.id);
|
|
3350
3350
|
switch (x.type) {
|
|
3351
3351
|
case "point": {
|
|
3352
3352
|
const f = b(x.x, x.y);
|
|
3353
|
-
p.beginPath(), p.arc(f.x, f.y, k ? x.size + 2 : x.size, 0, 2 * Math.PI), p.fillStyle = k ? "#1976d2" : w, p.fill(), x.label && (p.fillStyle = "#333", p.font = "12px sans-serif", p.fillText(x.label, f.x + 8, f.y - 8));
|
|
3353
|
+
p.beginPath(), p.arc(f.x, f.y, k ? x.size + 2 : x.size, 0, 2 * Math.PI), p.fillStyle = k ? "var(--nice-primary-hover, #1976d2)" : w, p.fill(), x.label && (p.fillStyle = "var(--nice-text, #333)", p.font = "12px sans-serif", p.fillText(x.label, f.x + 8, f.y - 8));
|
|
3354
3354
|
break;
|
|
3355
3355
|
}
|
|
3356
3356
|
case "segment": {
|
|
@@ -3404,7 +3404,7 @@ function Canvas({ width: e, height: t }) {
|
|
|
3404
3404
|
}
|
|
3405
3405
|
}
|
|
3406
3406
|
}
|
|
3407
|
-
}, [
|
|
3407
|
+
}, [n, s, e, t, c, d, a, b]), /* @__PURE__ */ jsx(
|
|
3408
3408
|
"canvas",
|
|
3409
3409
|
{
|
|
3410
3410
|
ref: r,
|
|
@@ -3416,7 +3416,7 @@ function Canvas({ width: e, height: t }) {
|
|
|
3416
3416
|
);
|
|
3417
3417
|
}
|
|
3418
3418
|
function StatusBar({ width: e, height: t }) {
|
|
3419
|
-
const { tool: r, elements: a, view:
|
|
3419
|
+
const { tool: r, elements: a, view: n, service: o } = useGeometry(), [s, c] = useState(null), l = {
|
|
3420
3420
|
select: "Select",
|
|
3421
3421
|
point: "Point",
|
|
3422
3422
|
line: "Line",
|
|
@@ -3457,7 +3457,7 @@ function StatusBar({ width: e, height: t }) {
|
|
|
3457
3457
|
/* @__PURE__ */ jsx("span", { style: { margin: "0 16px" }, children: "|" }),
|
|
3458
3458
|
/* @__PURE__ */ jsxs("span", { children: [
|
|
3459
3459
|
"Scale: ",
|
|
3460
|
-
|
|
3460
|
+
n.scale.toFixed(1),
|
|
3461
3461
|
"x"
|
|
3462
3462
|
] })
|
|
3463
3463
|
] });
|