tuiuiu.js 0.1.1 → 0.1.4-next.64ff654
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -36
- package/dist/atoms/button.d.ts.map +1 -1
- package/dist/atoms/button.js +17 -9
- package/dist/atoms/button.js.map +1 -1
- package/dist/atoms/text-input.d.ts +2 -0
- package/dist/atoms/text-input.d.ts.map +1 -1
- package/dist/atoms/text-input.js +13 -7
- package/dist/atoms/text-input.js.map +1 -1
- package/dist/atoms/tooltip.d.ts.map +1 -1
- package/dist/atoms/tooltip.js +2 -1
- package/dist/atoms/tooltip.js.map +1 -1
- package/dist/cli/commands/help.d.ts +5 -0
- package/dist/cli/commands/help.d.ts.map +1 -0
- package/dist/cli/commands/help.js +31 -0
- package/dist/cli/commands/help.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +11 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -0
- package/dist/cli/commands/mcp.js +21 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/storybook.d.ts +5 -0
- package/dist/cli/commands/storybook.d.ts.map +1 -0
- package/dist/cli/commands/storybook.js +9 -0
- package/dist/cli/commands/storybook.js.map +1 -0
- package/dist/cli/index.d.ts +14 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +50 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/error-boundary.d.ts.map +1 -1
- package/dist/core/error-boundary.js +2 -1
- package/dist/core/error-boundary.js.map +1 -1
- package/dist/core/hotkeys.d.ts +62 -0
- package/dist/core/hotkeys.d.ts.map +1 -0
- package/dist/core/hotkeys.js +0 -0
- package/dist/core/hotkeys.js.map +1 -0
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +9 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/screen.d.ts.map +1 -1
- package/dist/core/screen.js +2 -0
- package/dist/core/screen.js.map +1 -1
- package/dist/core/theme.d.ts +79 -0
- package/dist/core/theme.d.ts.map +1 -1
- package/dist/core/theme.js +358 -0
- package/dist/core/theme.js.map +1 -1
- package/dist/design-system/data-display/index.d.ts +9 -6
- package/dist/design-system/data-display/index.d.ts.map +1 -1
- package/dist/design-system/data-display/index.js +16 -7
- package/dist/design-system/data-display/index.js.map +1 -1
- package/dist/design-system/feedback/badge.d.ts +21 -4
- package/dist/design-system/feedback/badge.d.ts.map +1 -1
- package/dist/design-system/feedback/badge.js +15 -2
- package/dist/design-system/feedback/badge.js.map +1 -1
- package/dist/design-system/forms/index.d.ts +11 -8
- package/dist/design-system/forms/index.d.ts.map +1 -1
- package/dist/design-system/forms/index.js +19 -10
- package/dist/design-system/forms/index.js.map +1 -1
- package/dist/design-system/layout/index.d.ts +7 -4
- package/dist/design-system/layout/index.d.ts.map +1 -1
- package/dist/design-system/layout/index.js +18 -6
- package/dist/design-system/layout/index.js.map +1 -1
- package/dist/design-system/media/picture.d.ts.map +1 -1
- package/dist/design-system/media/picture.js +2 -1
- package/dist/design-system/media/picture.js.map +1 -1
- package/dist/design-system/overlays/index.d.ts +6 -3
- package/dist/design-system/overlays/index.d.ts.map +1 -1
- package/dist/design-system/overlays/index.js +9 -3
- package/dist/design-system/overlays/index.js.map +1 -1
- package/dist/design-system/visual/splash-screen.d.ts.map +1 -1
- package/dist/design-system/visual/splash-screen.js +38 -18
- package/dist/design-system/visual/splash-screen.js.map +1 -1
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/use-hotkeys.d.ts +153 -0
- package/dist/hooks/use-hotkeys.d.ts.map +1 -0
- package/dist/hooks/use-hotkeys.js +379 -0
- package/dist/hooks/use-hotkeys.js.map +1 -0
- package/dist/hooks/use-input.d.ts +2 -10
- package/dist/hooks/use-input.d.ts.map +1 -1
- package/dist/hooks/use-input.js +2 -287
- package/dist/hooks/use-input.js.map +1 -1
- package/dist/hooks/use-mouse.d.ts +5 -0
- package/dist/hooks/use-mouse.d.ts.map +1 -1
- package/dist/hooks/use-mouse.js +29 -11
- package/dist/hooks/use-mouse.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/docs-data.d.ts +31 -0
- package/dist/mcp/docs-data.d.ts.map +1 -0
- package/dist/mcp/docs-data.js +637 -0
- package/dist/mcp/docs-data.js.map +1 -0
- package/dist/mcp/index.d.ts +14 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +12 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +31 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +597 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/types.d.ts +114 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +16 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/molecules/autocomplete.d.ts.map +1 -1
- package/dist/molecules/autocomplete.js +2 -1
- package/dist/molecules/autocomplete.js.map +1 -1
- package/dist/molecules/calendar.d.ts.map +1 -1
- package/dist/molecules/calendar.js +5 -3
- package/dist/molecules/calendar.js.map +1 -1
- package/dist/molecules/data-viz/annotations.d.ts +75 -0
- package/dist/molecules/data-viz/annotations.d.ts.map +1 -0
- package/dist/molecules/data-viz/annotations.js +40 -0
- package/dist/molecules/data-viz/annotations.js.map +1 -0
- package/dist/molecules/data-viz/gantt-chart.d.ts +66 -0
- package/dist/molecules/data-viz/gantt-chart.d.ts.map +1 -0
- package/dist/molecules/data-viz/gantt-chart.js +134 -0
- package/dist/molecules/data-viz/gantt-chart.js.map +1 -0
- package/dist/molecules/data-viz/gauge.d.ts +2 -2
- package/dist/molecules/data-viz/gauge.d.ts.map +1 -1
- package/dist/molecules/data-viz/gauge.js +24 -8
- package/dist/molecules/data-viz/gauge.js.map +1 -1
- package/dist/molecules/data-viz/heatmap.d.ts +8 -2
- package/dist/molecules/data-viz/heatmap.d.ts.map +1 -1
- package/dist/molecules/data-viz/heatmap.js +41 -9
- package/dist/molecules/data-viz/heatmap.js.map +1 -1
- package/dist/molecules/data-viz/hooks.d.ts +264 -0
- package/dist/molecules/data-viz/hooks.d.ts.map +1 -0
- package/dist/molecules/data-viz/hooks.js +373 -0
- package/dist/molecules/data-viz/hooks.js.map +1 -0
- package/dist/molecules/data-viz/index.d.ts +14 -0
- package/dist/molecules/data-viz/index.d.ts.map +1 -1
- package/dist/molecules/data-viz/index.js +14 -0
- package/dist/molecules/data-viz/index.js.map +1 -1
- package/dist/molecules/data-viz/legend.d.ts +82 -0
- package/dist/molecules/data-viz/legend.d.ts.map +1 -0
- package/dist/molecules/data-viz/legend.js +146 -0
- package/dist/molecules/data-viz/legend.js.map +1 -0
- package/dist/molecules/data-viz/line-chart.d.ts.map +1 -1
- package/dist/molecules/data-viz/line-chart.js +48 -12
- package/dist/molecules/data-viz/line-chart.js.map +1 -1
- package/dist/molecules/data-viz/radar-chart.d.ts +61 -0
- package/dist/molecules/data-viz/radar-chart.d.ts.map +1 -0
- package/dist/molecules/data-viz/radar-chart.js +86 -0
- package/dist/molecules/data-viz/radar-chart.js.map +1 -0
- package/dist/molecules/data-viz/scatter-plot.d.ts +97 -0
- package/dist/molecules/data-viz/scatter-plot.d.ts.map +1 -0
- package/dist/molecules/data-viz/scatter-plot.js +205 -0
- package/dist/molecules/data-viz/scatter-plot.js.map +1 -0
- package/dist/molecules/data-viz/time-heatmap.d.ts +48 -0
- package/dist/molecules/data-viz/time-heatmap.d.ts.map +1 -0
- package/dist/molecules/data-viz/time-heatmap.js +145 -0
- package/dist/molecules/data-viz/time-heatmap.js.map +1 -0
- package/dist/molecules/select.d.ts +2 -0
- package/dist/molecules/select.d.ts.map +1 -1
- package/dist/molecules/select.js +4 -3
- package/dist/molecules/select.js.map +1 -1
- package/dist/molecules/tabs.d.ts.map +1 -1
- package/dist/molecules/tabs.js +14 -2
- package/dist/molecules/tabs.js.map +1 -1
- package/dist/organisms/command-palette.d.ts.map +1 -1
- package/dist/organisms/command-palette.js +2 -1
- package/dist/organisms/command-palette.js.map +1 -1
- package/dist/storybook/app.d.ts.map +1 -1
- package/dist/storybook/app.js +53 -44
- package/dist/storybook/app.js.map +1 -1
- package/dist/storybook/components/compare-view.d.ts.map +1 -1
- package/dist/storybook/components/compare-view.js +19 -18
- package/dist/storybook/components/compare-view.js.map +1 -1
- package/dist/storybook/components/log-viewer.d.ts.map +1 -1
- package/dist/storybook/components/log-viewer.js +9 -8
- package/dist/storybook/components/log-viewer.js.map +1 -1
- package/dist/storybook/components/preview.d.ts.map +1 -1
- package/dist/storybook/components/preview.js +34 -33
- package/dist/storybook/components/preview.js.map +1 -1
- package/dist/storybook/components/sidebar.d.ts.map +1 -1
- package/dist/storybook/components/sidebar.js +21 -20
- package/dist/storybook/components/sidebar.js.map +1 -1
- package/dist/storybook/stories/apps/index.d.ts.map +1 -1
- package/dist/storybook/stories/apps/index.js +306 -209
- package/dist/storybook/stories/apps/index.js.map +1 -1
- package/dist/storybook/stories/atoms/index.d.ts.map +1 -1
- package/dist/storybook/stories/atoms/index.js.map +1 -1
- package/dist/storybook/stories/molecules/index.d.ts +25 -0
- package/dist/storybook/stories/molecules/index.d.ts.map +1 -1
- package/dist/storybook/stories/molecules/index.js +402 -20
- package/dist/storybook/stories/molecules/index.js.map +1 -1
- package/dist/storybook/stories/organisms/index.d.ts.map +1 -1
- package/dist/storybook/stories/organisms/index.js +1 -1
- package/dist/storybook/stories/organisms/index.js.map +1 -1
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/system-data.d.ts +73 -0
- package/dist/utils/system-data.d.ts.map +1 -0
- package/dist/utils/system-data.js +367 -0
- package/dist/utils/system-data.js.map +1 -0
- package/dist/version.d.ts +43 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +82 -0
- package/dist/version.js.map +1 -0
- package/package.json +22 -22
- package/dist/components/canvas.d.ts +0 -322
- package/dist/components/canvas.d.ts.map +0 -1
- package/dist/components/canvas.js +0 -833
- package/dist/components/canvas.js.map +0 -1
- package/dist/components/code-block.d.ts +0 -75
- package/dist/components/code-block.d.ts.map +0 -1
- package/dist/components/code-block.js +0 -322
- package/dist/components/code-block.js.map +0 -1
- package/dist/components/components.d.ts +0 -122
- package/dist/components/components.d.ts.map +0 -1
- package/dist/components/components.js +0 -151
- package/dist/components/components.js.map +0 -1
- package/dist/components/data-viz/bar-chart.d.ts +0 -167
- package/dist/components/data-viz/bar-chart.d.ts.map +0 -1
- package/dist/components/data-viz/bar-chart.js +0 -375
- package/dist/components/data-viz/bar-chart.js.map +0 -1
- package/dist/components/data-viz/gauge.d.ts +0 -163
- package/dist/components/data-viz/gauge.d.ts.map +0 -1
- package/dist/components/data-viz/gauge.js +0 -451
- package/dist/components/data-viz/gauge.js.map +0 -1
- package/dist/components/data-viz/heatmap.d.ts +0 -154
- package/dist/components/data-viz/heatmap.d.ts.map +0 -1
- package/dist/components/data-viz/heatmap.js +0 -458
- package/dist/components/data-viz/heatmap.js.map +0 -1
- package/dist/components/data-viz/index.d.ts +0 -16
- package/dist/components/data-viz/index.d.ts.map +0 -1
- package/dist/components/data-viz/index.js +0 -16
- package/dist/components/data-viz/index.js.map +0 -1
- package/dist/components/data-viz/line-chart.d.ts +0 -157
- package/dist/components/data-viz/line-chart.d.ts.map +0 -1
- package/dist/components/data-viz/line-chart.js +0 -578
- package/dist/components/data-viz/line-chart.js.map +0 -1
- package/dist/components/data-viz/sparkline.d.ts +0 -156
- package/dist/components/data-viz/sparkline.d.ts.map +0 -1
- package/dist/components/data-viz/sparkline.js +0 -325
- package/dist/components/data-viz/sparkline.js.map +0 -1
- package/dist/components/grid.d.ts +0 -234
- package/dist/components/grid.d.ts.map +0 -1
- package/dist/components/grid.js +0 -719
- package/dist/components/grid.js.map +0 -1
- package/dist/components/index.d.ts +0 -33
- package/dist/components/index.d.ts.map +0 -1
- package/dist/components/index.js +0 -69
- package/dist/components/index.js.map +0 -1
- package/dist/components/markdown.d.ts +0 -52
- package/dist/components/markdown.d.ts.map +0 -1
- package/dist/components/markdown.js +0 -341
- package/dist/components/markdown.js.map +0 -1
- package/dist/components/modal.d.ts +0 -237
- package/dist/components/modal.d.ts.map +0 -1
- package/dist/components/modal.js +0 -396
- package/dist/components/modal.js.map +0 -1
- package/dist/components/progress-bar.d.ts +0 -89
- package/dist/components/progress-bar.d.ts.map +0 -1
- package/dist/components/progress-bar.js +0 -288
- package/dist/components/progress-bar.js.map +0 -1
- package/dist/components/select.d.ts +0 -114
- package/dist/components/select.d.ts.map +0 -1
- package/dist/components/select.js +0 -415
- package/dist/components/select.js.map +0 -1
- package/dist/components/spinner.d.ts +0 -71
- package/dist/components/spinner.d.ts.map +0 -1
- package/dist/components/spinner.js +0 -300
- package/dist/components/spinner.js.map +0 -1
- package/dist/components/split-panel.d.ts +0 -175
- package/dist/components/split-panel.d.ts.map +0 -1
- package/dist/components/split-panel.js +0 -322
- package/dist/components/split-panel.js.map +0 -1
- package/dist/components/table.d.ts +0 -103
- package/dist/components/table.d.ts.map +0 -1
- package/dist/components/table.js +0 -359
- package/dist/components/table.js.map +0 -1
- package/dist/components/text-input.d.ts +0 -79
- package/dist/components/text-input.d.ts.map +0 -1
- package/dist/components/text-input.js +0 -332
- package/dist/components/text-input.js.map +0 -1
- package/dist/design-system/data-display/calendar.d.ts +0 -141
- package/dist/design-system/data-display/calendar.d.ts.map +0 -1
- package/dist/design-system/data-display/calendar.js +0 -524
- package/dist/design-system/data-display/calendar.js.map +0 -1
- package/dist/design-system/data-display/code-block.d.ts +0 -75
- package/dist/design-system/data-display/code-block.d.ts.map +0 -1
- package/dist/design-system/data-display/code-block.js +0 -311
- package/dist/design-system/data-display/code-block.js.map +0 -1
- package/dist/design-system/data-display/data-table.d.ts +0 -173
- package/dist/design-system/data-display/data-table.d.ts.map +0 -1
- package/dist/design-system/data-display/data-table.js +0 -428
- package/dist/design-system/data-display/data-table.js.map +0 -1
- package/dist/design-system/data-display/markdown.d.ts +0 -52
- package/dist/design-system/data-display/markdown.d.ts.map +0 -1
- package/dist/design-system/data-display/markdown.js +0 -341
- package/dist/design-system/data-display/markdown.js.map +0 -1
- package/dist/design-system/data-display/table.d.ts +0 -103
- package/dist/design-system/data-display/table.d.ts.map +0 -1
- package/dist/design-system/data-display/table.js +0 -342
- package/dist/design-system/data-display/table.js.map +0 -1
- package/dist/design-system/data-display/tree.d.ts +0 -166
- package/dist/design-system/data-display/tree.d.ts.map +0 -1
- package/dist/design-system/data-display/tree.js +0 -428
- package/dist/design-system/data-display/tree.js.map +0 -1
- package/dist/design-system/forms/autocomplete.d.ts +0 -163
- package/dist/design-system/forms/autocomplete.d.ts.map +0 -1
- package/dist/design-system/forms/autocomplete.js +0 -455
- package/dist/design-system/forms/autocomplete.js.map +0 -1
- package/dist/design-system/forms/button.d.ts +0 -106
- package/dist/design-system/forms/button.d.ts.map +0 -1
- package/dist/design-system/forms/button.js +0 -170
- package/dist/design-system/forms/button.js.map +0 -1
- package/dist/design-system/forms/multi-select.d.ts +0 -102
- package/dist/design-system/forms/multi-select.d.ts.map +0 -1
- package/dist/design-system/forms/multi-select.js +0 -309
- package/dist/design-system/forms/multi-select.js.map +0 -1
- package/dist/design-system/forms/radio-group.d.ts +0 -88
- package/dist/design-system/forms/radio-group.d.ts.map +0 -1
- package/dist/design-system/forms/radio-group.js +0 -145
- package/dist/design-system/forms/radio-group.js.map +0 -1
- package/dist/design-system/forms/select.d.ts +0 -116
- package/dist/design-system/forms/select.d.ts.map +0 -1
- package/dist/design-system/forms/select.js +0 -441
- package/dist/design-system/forms/select.js.map +0 -1
- package/dist/design-system/forms/slider.d.ts +0 -134
- package/dist/design-system/forms/slider.d.ts.map +0 -1
- package/dist/design-system/forms/slider.js +0 -314
- package/dist/design-system/forms/slider.js.map +0 -1
- package/dist/design-system/forms/switch.d.ts +0 -99
- package/dist/design-system/forms/switch.d.ts.map +0 -1
- package/dist/design-system/forms/switch.js +0 -173
- package/dist/design-system/forms/switch.js.map +0 -1
- package/dist/design-system/forms/text-input.d.ts +0 -79
- package/dist/design-system/forms/text-input.d.ts.map +0 -1
- package/dist/design-system/forms/text-input.js +0 -344
- package/dist/design-system/forms/text-input.js.map +0 -1
- package/dist/design-system/layout/collapsible.d.ts +0 -166
- package/dist/design-system/layout/collapsible.d.ts.map +0 -1
- package/dist/design-system/layout/collapsible.js +0 -286
- package/dist/design-system/layout/collapsible.js.map +0 -1
- package/dist/design-system/layout/scroll-area.d.ts +0 -188
- package/dist/design-system/layout/scroll-area.d.ts.map +0 -1
- package/dist/design-system/layout/scroll-area.js +0 -348
- package/dist/design-system/layout/scroll-area.js.map +0 -1
- package/dist/design-system/layout/split-panel.d.ts +0 -183
- package/dist/design-system/layout/split-panel.d.ts.map +0 -1
- package/dist/design-system/layout/split-panel.js +0 -323
- package/dist/design-system/layout/split-panel.js.map +0 -1
- package/dist/design-system/layout/tabs.d.ts +0 -129
- package/dist/design-system/layout/tabs.d.ts.map +0 -1
- package/dist/design-system/layout/tabs.js +0 -373
- package/dist/design-system/layout/tabs.js.map +0 -1
- package/dist/design-system/overlays/command-palette.d.ts +0 -217
- package/dist/design-system/overlays/command-palette.d.ts.map +0 -1
- package/dist/design-system/overlays/command-palette.js +0 -443
- package/dist/design-system/overlays/command-palette.js.map +0 -1
- package/dist/design-system/overlays/modal.d.ts +0 -251
- package/dist/design-system/overlays/modal.d.ts.map +0 -1
- package/dist/design-system/overlays/modal.js +0 -461
- package/dist/design-system/overlays/modal.js.map +0 -1
- package/dist/design-system/overlays/overlay-stack.d.ts +0 -200
- package/dist/design-system/overlays/overlay-stack.d.ts.map +0 -1
- package/dist/design-system/overlays/overlay-stack.js +0 -341
- package/dist/design-system/overlays/overlay-stack.js.map +0 -1
- package/dist/design-system/primitives/box.d.ts +0 -16
- package/dist/design-system/primitives/box.d.ts.map +0 -1
- package/dist/design-system/primitives/box.js +0 -23
- package/dist/design-system/primitives/box.js.map +0 -1
- package/dist/design-system/primitives/divider.d.ts +0 -52
- package/dist/design-system/primitives/divider.d.ts.map +0 -1
- package/dist/design-system/primitives/divider.js +0 -72
- package/dist/design-system/primitives/divider.js.map +0 -1
- package/dist/design-system/primitives/helpers.d.ts +0 -10
- package/dist/design-system/primitives/helpers.d.ts.map +0 -1
- package/dist/design-system/primitives/helpers.js +0 -27
- package/dist/design-system/primitives/helpers.js.map +0 -1
- package/dist/design-system/primitives/index.d.ts +0 -11
- package/dist/design-system/primitives/index.d.ts.map +0 -1
- package/dist/design-system/primitives/index.js +0 -14
- package/dist/design-system/primitives/index.js.map +0 -1
- package/dist/design-system/primitives/slot.d.ts +0 -35
- package/dist/design-system/primitives/slot.d.ts.map +0 -1
- package/dist/design-system/primitives/slot.js +0 -17
- package/dist/design-system/primitives/slot.js.map +0 -1
- package/dist/design-system/primitives/spacer.d.ts +0 -34
- package/dist/design-system/primitives/spacer.d.ts.map +0 -1
- package/dist/design-system/primitives/spacer.js +0 -53
- package/dist/design-system/primitives/spacer.js.map +0 -1
- package/dist/design-system/primitives/text.d.ts +0 -12
- package/dist/design-system/primitives/text.d.ts.map +0 -1
- package/dist/design-system/primitives/text.js +0 -25
- package/dist/design-system/primitives/text.js.map +0 -1
- package/dist/design-system/primitives/utilities.d.ts +0 -70
- package/dist/design-system/primitives/utilities.d.ts.map +0 -1
- package/dist/design-system/primitives/utilities.js +0 -56
- package/dist/design-system/primitives/utilities.js.map +0 -1
- package/dist/storybook/cli.d.ts +0 -10
- package/dist/storybook/cli.d.ts.map +0 -1
- package/dist/storybook/cli.js +0 -14
- package/dist/storybook/cli.js.map +0 -1
|
@@ -1,833 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canvas Widget - 2D Drawing Canvas for Terminal
|
|
3
|
-
*
|
|
4
|
-
* Provides a canvas component for drawing shapes, lines, and graphics
|
|
5
|
-
* in the terminal. Supports multiple drawing modes:
|
|
6
|
-
* - Character mode: Uses ASCII/Unicode characters
|
|
7
|
-
* - Braille mode: Uses braille characters for 2x4 sub-character resolution
|
|
8
|
-
* - Block mode: Uses block characters for 2x2 sub-character resolution
|
|
9
|
-
*/
|
|
10
|
-
// =============================================================================
|
|
11
|
-
// Constants
|
|
12
|
-
// =============================================================================
|
|
13
|
-
/**
|
|
14
|
-
* Braille character patterns (2x4 dots)
|
|
15
|
-
* Each braille character represents 8 dots arranged as:
|
|
16
|
-
* [0] [3]
|
|
17
|
-
* [1] [4]
|
|
18
|
-
* [2] [5]
|
|
19
|
-
* [6] [7]
|
|
20
|
-
*/
|
|
21
|
-
const BRAILLE_BASE = 0x2800;
|
|
22
|
-
const BRAILLE_DOTS = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80];
|
|
23
|
-
/**
|
|
24
|
-
* Block character patterns (2x2)
|
|
25
|
-
* Uses Unicode block characters for better density
|
|
26
|
-
*/
|
|
27
|
-
export const BLOCK_CHARS = {
|
|
28
|
-
empty: ' ',
|
|
29
|
-
full: '█',
|
|
30
|
-
topHalf: '▀',
|
|
31
|
-
bottomHalf: '▄',
|
|
32
|
-
leftHalf: '▌',
|
|
33
|
-
rightHalf: '▐',
|
|
34
|
-
topLeft: '▘',
|
|
35
|
-
topRight: '▝',
|
|
36
|
-
bottomLeft: '▖',
|
|
37
|
-
bottomRight: '▗',
|
|
38
|
-
topLeftBottomRight: '▚',
|
|
39
|
-
topRightBottomLeft: '▞',
|
|
40
|
-
// Quarter blocks
|
|
41
|
-
topLeftBottomLeftBottomRight: '▙',
|
|
42
|
-
topLeftTopRightBottomLeft: '▛',
|
|
43
|
-
topLeftTopRightBottomRight: '▜',
|
|
44
|
-
topRightBottomLeftBottomRight: '▟',
|
|
45
|
-
};
|
|
46
|
-
/**
|
|
47
|
-
* Box drawing characters for lines
|
|
48
|
-
*/
|
|
49
|
-
export const LINE_CHARS = {
|
|
50
|
-
horizontal: '─',
|
|
51
|
-
vertical: '│',
|
|
52
|
-
topLeft: '┌',
|
|
53
|
-
topRight: '┐',
|
|
54
|
-
bottomLeft: '└',
|
|
55
|
-
bottomRight: '┘',
|
|
56
|
-
cross: '┼',
|
|
57
|
-
teeDown: '┬',
|
|
58
|
-
teeUp: '┴',
|
|
59
|
-
teeRight: '├',
|
|
60
|
-
teeLeft: '┤',
|
|
61
|
-
};
|
|
62
|
-
// =============================================================================
|
|
63
|
-
// Braille Utilities
|
|
64
|
-
// =============================================================================
|
|
65
|
-
/**
|
|
66
|
-
* Create a braille buffer for higher resolution drawing
|
|
67
|
-
*/
|
|
68
|
-
export function createBrailleBuffer(width, height) {
|
|
69
|
-
// Each character cell is 2x4 braille dots
|
|
70
|
-
const dotWidth = width * 2;
|
|
71
|
-
const dotHeight = height * 4;
|
|
72
|
-
const buffer = [];
|
|
73
|
-
for (let y = 0; y < dotHeight; y++) {
|
|
74
|
-
buffer.push(new Array(dotWidth).fill(false));
|
|
75
|
-
}
|
|
76
|
-
return buffer;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Set a dot in the braille buffer
|
|
80
|
-
*/
|
|
81
|
-
export function setBrailleDot(buffer, x, y, value = true) {
|
|
82
|
-
if (y >= 0 && y < buffer.length && x >= 0 && x < (buffer[0]?.length ?? 0)) {
|
|
83
|
-
buffer[y][x] = value;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Convert braille buffer to string output
|
|
88
|
-
*/
|
|
89
|
-
export function brailleBufferToString(buffer) {
|
|
90
|
-
const height = buffer.length;
|
|
91
|
-
const width = buffer[0]?.length ?? 0;
|
|
92
|
-
const charHeight = Math.ceil(height / 4);
|
|
93
|
-
const charWidth = Math.ceil(width / 2);
|
|
94
|
-
const lines = [];
|
|
95
|
-
for (let cy = 0; cy < charHeight; cy++) {
|
|
96
|
-
let line = '';
|
|
97
|
-
for (let cx = 0; cx < charWidth; cx++) {
|
|
98
|
-
let code = BRAILLE_BASE;
|
|
99
|
-
// Map 2x4 dots to braille pattern
|
|
100
|
-
const baseX = cx * 2;
|
|
101
|
-
const baseY = cy * 4;
|
|
102
|
-
// Left column (dots 0, 1, 2, 6)
|
|
103
|
-
if (buffer[baseY]?.[baseX])
|
|
104
|
-
code += BRAILLE_DOTS[0];
|
|
105
|
-
if (buffer[baseY + 1]?.[baseX])
|
|
106
|
-
code += BRAILLE_DOTS[1];
|
|
107
|
-
if (buffer[baseY + 2]?.[baseX])
|
|
108
|
-
code += BRAILLE_DOTS[2];
|
|
109
|
-
if (buffer[baseY + 3]?.[baseX])
|
|
110
|
-
code += BRAILLE_DOTS[6];
|
|
111
|
-
// Right column (dots 3, 4, 5, 7)
|
|
112
|
-
if (buffer[baseY]?.[baseX + 1])
|
|
113
|
-
code += BRAILLE_DOTS[3];
|
|
114
|
-
if (buffer[baseY + 1]?.[baseX + 1])
|
|
115
|
-
code += BRAILLE_DOTS[4];
|
|
116
|
-
if (buffer[baseY + 2]?.[baseX + 1])
|
|
117
|
-
code += BRAILLE_DOTS[5];
|
|
118
|
-
if (buffer[baseY + 3]?.[baseX + 1])
|
|
119
|
-
code += BRAILLE_DOTS[7];
|
|
120
|
-
line += String.fromCharCode(code);
|
|
121
|
-
}
|
|
122
|
-
lines.push(line);
|
|
123
|
-
}
|
|
124
|
-
return lines.join('\n');
|
|
125
|
-
}
|
|
126
|
-
// =============================================================================
|
|
127
|
-
// Block Utilities
|
|
128
|
-
// =============================================================================
|
|
129
|
-
/**
|
|
130
|
-
* Create a block buffer for 2x2 sub-character resolution
|
|
131
|
-
*/
|
|
132
|
-
export function createBlockBuffer(width, height) {
|
|
133
|
-
const blockWidth = width * 2;
|
|
134
|
-
const blockHeight = height * 2;
|
|
135
|
-
const buffer = [];
|
|
136
|
-
for (let y = 0; y < blockHeight; y++) {
|
|
137
|
-
buffer.push(new Array(blockWidth).fill(false));
|
|
138
|
-
}
|
|
139
|
-
return buffer;
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Set a pixel in the block buffer
|
|
143
|
-
*/
|
|
144
|
-
export function setBlockPixel(buffer, x, y, value = true) {
|
|
145
|
-
if (y >= 0 && y < buffer.length && x >= 0 && x < (buffer[0]?.length ?? 0)) {
|
|
146
|
-
buffer[y][x] = value;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Convert block buffer to string output
|
|
151
|
-
*/
|
|
152
|
-
export function blockBufferToString(buffer) {
|
|
153
|
-
const height = buffer.length;
|
|
154
|
-
const width = buffer[0]?.length ?? 0;
|
|
155
|
-
const charHeight = Math.ceil(height / 2);
|
|
156
|
-
const charWidth = Math.ceil(width / 2);
|
|
157
|
-
const lines = [];
|
|
158
|
-
for (let cy = 0; cy < charHeight; cy++) {
|
|
159
|
-
let line = '';
|
|
160
|
-
for (let cx = 0; cx < charWidth; cx++) {
|
|
161
|
-
const baseX = cx * 2;
|
|
162
|
-
const baseY = cy * 2;
|
|
163
|
-
const topLeft = buffer[baseY]?.[baseX] ?? false;
|
|
164
|
-
const topRight = buffer[baseY]?.[baseX + 1] ?? false;
|
|
165
|
-
const bottomLeft = buffer[baseY + 1]?.[baseX] ?? false;
|
|
166
|
-
const bottomRight = buffer[baseY + 1]?.[baseX + 1] ?? false;
|
|
167
|
-
// Map 2x2 pattern to block character
|
|
168
|
-
if (!topLeft && !topRight && !bottomLeft && !bottomRight) {
|
|
169
|
-
line += ' ';
|
|
170
|
-
}
|
|
171
|
-
else if (topLeft && topRight && bottomLeft && bottomRight) {
|
|
172
|
-
line += '█';
|
|
173
|
-
}
|
|
174
|
-
else if (topLeft && topRight && !bottomLeft && !bottomRight) {
|
|
175
|
-
line += '▀';
|
|
176
|
-
}
|
|
177
|
-
else if (!topLeft && !topRight && bottomLeft && bottomRight) {
|
|
178
|
-
line += '▄';
|
|
179
|
-
}
|
|
180
|
-
else if (topLeft && !topRight && bottomLeft && !bottomRight) {
|
|
181
|
-
line += '▌';
|
|
182
|
-
}
|
|
183
|
-
else if (!topLeft && topRight && !bottomLeft && bottomRight) {
|
|
184
|
-
line += '▐';
|
|
185
|
-
}
|
|
186
|
-
else if (topLeft && !topRight && !bottomLeft && !bottomRight) {
|
|
187
|
-
line += '▘';
|
|
188
|
-
}
|
|
189
|
-
else if (!topLeft && topRight && !bottomLeft && !bottomRight) {
|
|
190
|
-
line += '▝';
|
|
191
|
-
}
|
|
192
|
-
else if (!topLeft && !topRight && bottomLeft && !bottomRight) {
|
|
193
|
-
line += '▖';
|
|
194
|
-
}
|
|
195
|
-
else if (!topLeft && !topRight && !bottomLeft && bottomRight) {
|
|
196
|
-
line += '▗';
|
|
197
|
-
}
|
|
198
|
-
else if (topLeft && !topRight && !bottomLeft && bottomRight) {
|
|
199
|
-
line += '▚';
|
|
200
|
-
}
|
|
201
|
-
else if (!topLeft && topRight && bottomLeft && !bottomRight) {
|
|
202
|
-
line += '▞';
|
|
203
|
-
}
|
|
204
|
-
else if (topLeft && !topRight && bottomLeft && bottomRight) {
|
|
205
|
-
line += '▙';
|
|
206
|
-
}
|
|
207
|
-
else if (topLeft && topRight && bottomLeft && !bottomRight) {
|
|
208
|
-
line += '▛';
|
|
209
|
-
}
|
|
210
|
-
else if (topLeft && topRight && !bottomLeft && bottomRight) {
|
|
211
|
-
line += '▜';
|
|
212
|
-
}
|
|
213
|
-
else if (!topLeft && topRight && bottomLeft && bottomRight) {
|
|
214
|
-
line += '▟';
|
|
215
|
-
}
|
|
216
|
-
else {
|
|
217
|
-
line += '▒';
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
lines.push(line);
|
|
221
|
-
}
|
|
222
|
-
return lines.join('\n');
|
|
223
|
-
}
|
|
224
|
-
// =============================================================================
|
|
225
|
-
// Drawing Algorithms
|
|
226
|
-
// =============================================================================
|
|
227
|
-
/**
|
|
228
|
-
* Bresenham's line algorithm
|
|
229
|
-
* Returns all points along a line from (x0, y0) to (x1, y1)
|
|
230
|
-
*/
|
|
231
|
-
export function bresenhamLine(x0, y0, x1, y1) {
|
|
232
|
-
const points = [];
|
|
233
|
-
const dx = Math.abs(x1 - x0);
|
|
234
|
-
const dy = Math.abs(y1 - y0);
|
|
235
|
-
const sx = x0 < x1 ? 1 : -1;
|
|
236
|
-
const sy = y0 < y1 ? 1 : -1;
|
|
237
|
-
let err = dx - dy;
|
|
238
|
-
let x = x0;
|
|
239
|
-
let y = y0;
|
|
240
|
-
while (true) {
|
|
241
|
-
points.push({ x, y });
|
|
242
|
-
if (x === x1 && y === y1)
|
|
243
|
-
break;
|
|
244
|
-
const e2 = 2 * err;
|
|
245
|
-
if (e2 > -dy) {
|
|
246
|
-
err -= dy;
|
|
247
|
-
x += sx;
|
|
248
|
-
}
|
|
249
|
-
if (e2 < dx) {
|
|
250
|
-
err += dx;
|
|
251
|
-
y += sy;
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
return points;
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Midpoint circle algorithm
|
|
258
|
-
* Returns all points on the circumference of a circle
|
|
259
|
-
*/
|
|
260
|
-
export function midpointCircle(cx, cy, radius) {
|
|
261
|
-
const points = [];
|
|
262
|
-
if (radius <= 0) {
|
|
263
|
-
points.push({ x: cx, y: cy });
|
|
264
|
-
return points;
|
|
265
|
-
}
|
|
266
|
-
let x = radius;
|
|
267
|
-
let y = 0;
|
|
268
|
-
let d = 1 - radius;
|
|
269
|
-
const addCirclePoints = (px, py) => {
|
|
270
|
-
points.push({ x: cx + px, y: cy + py });
|
|
271
|
-
points.push({ x: cx - px, y: cy + py });
|
|
272
|
-
points.push({ x: cx + px, y: cy - py });
|
|
273
|
-
points.push({ x: cx - px, y: cy - py });
|
|
274
|
-
points.push({ x: cx + py, y: cy + px });
|
|
275
|
-
points.push({ x: cx - py, y: cy + px });
|
|
276
|
-
points.push({ x: cx + py, y: cy - px });
|
|
277
|
-
points.push({ x: cx - py, y: cy - px });
|
|
278
|
-
};
|
|
279
|
-
addCirclePoints(x, y);
|
|
280
|
-
while (x > y) {
|
|
281
|
-
y++;
|
|
282
|
-
if (d <= 0) {
|
|
283
|
-
d += 2 * y + 1;
|
|
284
|
-
}
|
|
285
|
-
else {
|
|
286
|
-
x--;
|
|
287
|
-
d += 2 * (y - x) + 1;
|
|
288
|
-
}
|
|
289
|
-
addCirclePoints(x, y);
|
|
290
|
-
}
|
|
291
|
-
return points;
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Fill circle using scanlines
|
|
295
|
-
*/
|
|
296
|
-
export function filledCircle(cx, cy, radius) {
|
|
297
|
-
const points = [];
|
|
298
|
-
for (let y = -radius; y <= radius; y++) {
|
|
299
|
-
const width = Math.floor(Math.sqrt(radius * radius - y * y));
|
|
300
|
-
for (let x = -width; x <= width; x++) {
|
|
301
|
-
points.push({ x: cx + x, y: cy + y });
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
return points;
|
|
305
|
-
}
|
|
306
|
-
/**
|
|
307
|
-
* Midpoint ellipse algorithm
|
|
308
|
-
*/
|
|
309
|
-
export function midpointEllipse(cx, cy, rx, ry) {
|
|
310
|
-
const points = [];
|
|
311
|
-
if (rx <= 0 || ry <= 0) {
|
|
312
|
-
points.push({ x: cx, y: cy });
|
|
313
|
-
return points;
|
|
314
|
-
}
|
|
315
|
-
const rx2 = rx * rx;
|
|
316
|
-
const ry2 = ry * ry;
|
|
317
|
-
let x = 0;
|
|
318
|
-
let y = ry;
|
|
319
|
-
let px = 0;
|
|
320
|
-
let py = 2 * rx2 * y;
|
|
321
|
-
const addEllipsePoints = (px, py) => {
|
|
322
|
-
points.push({ x: cx + px, y: cy + py });
|
|
323
|
-
points.push({ x: cx - px, y: cy + py });
|
|
324
|
-
points.push({ x: cx + px, y: cy - py });
|
|
325
|
-
points.push({ x: cx - px, y: cy - py });
|
|
326
|
-
};
|
|
327
|
-
addEllipsePoints(x, y);
|
|
328
|
-
// Region 1
|
|
329
|
-
let d1 = ry2 - rx2 * ry + 0.25 * rx2;
|
|
330
|
-
while (px < py) {
|
|
331
|
-
x++;
|
|
332
|
-
px += 2 * ry2;
|
|
333
|
-
if (d1 < 0) {
|
|
334
|
-
d1 += ry2 + px;
|
|
335
|
-
}
|
|
336
|
-
else {
|
|
337
|
-
y--;
|
|
338
|
-
py -= 2 * rx2;
|
|
339
|
-
d1 += ry2 + px - py;
|
|
340
|
-
}
|
|
341
|
-
addEllipsePoints(x, y);
|
|
342
|
-
}
|
|
343
|
-
// Region 2
|
|
344
|
-
let d2 = ry2 * (x + 0.5) * (x + 0.5) + rx2 * (y - 1) * (y - 1) - rx2 * ry2;
|
|
345
|
-
while (y > 0) {
|
|
346
|
-
y--;
|
|
347
|
-
py -= 2 * rx2;
|
|
348
|
-
if (d2 > 0) {
|
|
349
|
-
d2 += rx2 - py;
|
|
350
|
-
}
|
|
351
|
-
else {
|
|
352
|
-
x++;
|
|
353
|
-
px += 2 * ry2;
|
|
354
|
-
d2 += rx2 - py + px;
|
|
355
|
-
}
|
|
356
|
-
addEllipsePoints(x, y);
|
|
357
|
-
}
|
|
358
|
-
return points;
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* Arc points (portion of a circle)
|
|
362
|
-
*/
|
|
363
|
-
export function arcPoints(cx, cy, radius, startAngle, endAngle) {
|
|
364
|
-
const points = [];
|
|
365
|
-
// Convert to radians
|
|
366
|
-
const startRad = (startAngle * Math.PI) / 180;
|
|
367
|
-
const endRad = (endAngle * Math.PI) / 180;
|
|
368
|
-
// Calculate number of steps based on arc length
|
|
369
|
-
const arcLength = Math.abs(endRad - startRad) * radius;
|
|
370
|
-
const steps = Math.max(Math.ceil(arcLength), 20);
|
|
371
|
-
for (let i = 0; i <= steps; i++) {
|
|
372
|
-
const angle = startRad + (i / steps) * (endRad - startRad);
|
|
373
|
-
const x = Math.round(cx + radius * Math.cos(angle));
|
|
374
|
-
const y = Math.round(cy + radius * Math.sin(angle));
|
|
375
|
-
points.push({ x, y });
|
|
376
|
-
}
|
|
377
|
-
return points;
|
|
378
|
-
}
|
|
379
|
-
/**
|
|
380
|
-
* Bezier curve points (cubic)
|
|
381
|
-
*/
|
|
382
|
-
export function bezierCurve(p0, p1, p2, p3, steps = 50) {
|
|
383
|
-
const points = [];
|
|
384
|
-
for (let i = 0; i <= steps; i++) {
|
|
385
|
-
const t = i / steps;
|
|
386
|
-
const t2 = t * t;
|
|
387
|
-
const t3 = t2 * t;
|
|
388
|
-
const mt = 1 - t;
|
|
389
|
-
const mt2 = mt * mt;
|
|
390
|
-
const mt3 = mt2 * mt;
|
|
391
|
-
const x = Math.round(mt3 * p0.x + 3 * mt2 * t * p1.x + 3 * mt * t2 * p2.x + t3 * p3.x);
|
|
392
|
-
const y = Math.round(mt3 * p0.y + 3 * mt2 * t * p1.y + 3 * mt * t2 * p2.y + t3 * p3.y);
|
|
393
|
-
points.push({ x, y });
|
|
394
|
-
}
|
|
395
|
-
return points;
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* Quadratic bezier curve
|
|
399
|
-
*/
|
|
400
|
-
export function quadraticBezier(p0, p1, p2, steps = 50) {
|
|
401
|
-
const points = [];
|
|
402
|
-
for (let i = 0; i <= steps; i++) {
|
|
403
|
-
const t = i / steps;
|
|
404
|
-
const mt = 1 - t;
|
|
405
|
-
const x = Math.round(mt * mt * p0.x + 2 * mt * t * p1.x + t * t * p2.x);
|
|
406
|
-
const y = Math.round(mt * mt * p0.y + 2 * mt * t * p1.y + t * t * p2.y);
|
|
407
|
-
points.push({ x, y });
|
|
408
|
-
}
|
|
409
|
-
return points;
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* Polygon points (closed shape)
|
|
413
|
-
*/
|
|
414
|
-
export function polygonPoints(vertices) {
|
|
415
|
-
const points = [];
|
|
416
|
-
if (vertices.length < 2)
|
|
417
|
-
return points;
|
|
418
|
-
for (let i = 0; i < vertices.length; i++) {
|
|
419
|
-
const start = vertices[i];
|
|
420
|
-
const end = vertices[(i + 1) % vertices.length];
|
|
421
|
-
const linePoints = bresenhamLine(start.x, start.y, end.x, end.y);
|
|
422
|
-
points.push(...linePoints);
|
|
423
|
-
}
|
|
424
|
-
return points;
|
|
425
|
-
}
|
|
426
|
-
/**
|
|
427
|
-
* Filled polygon using scanline fill
|
|
428
|
-
*/
|
|
429
|
-
export function filledPolygon(vertices) {
|
|
430
|
-
const points = [];
|
|
431
|
-
if (vertices.length < 3)
|
|
432
|
-
return points;
|
|
433
|
-
// Find bounding box
|
|
434
|
-
let minY = Infinity;
|
|
435
|
-
let maxY = -Infinity;
|
|
436
|
-
for (const v of vertices) {
|
|
437
|
-
minY = Math.min(minY, v.y);
|
|
438
|
-
maxY = Math.max(maxY, v.y);
|
|
439
|
-
}
|
|
440
|
-
// Scanline fill
|
|
441
|
-
for (let y = minY; y <= maxY; y++) {
|
|
442
|
-
const intersections = [];
|
|
443
|
-
// Find all intersections with this scanline
|
|
444
|
-
for (let i = 0; i < vertices.length; i++) {
|
|
445
|
-
const v1 = vertices[i];
|
|
446
|
-
const v2 = vertices[(i + 1) % vertices.length];
|
|
447
|
-
// Check if edge crosses this scanline
|
|
448
|
-
if ((v1.y <= y && v2.y > y) || (v2.y <= y && v1.y > y)) {
|
|
449
|
-
// Calculate x intersection
|
|
450
|
-
const x = v1.x + ((y - v1.y) / (v2.y - v1.y)) * (v2.x - v1.x);
|
|
451
|
-
intersections.push(Math.round(x));
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
// Sort intersections
|
|
455
|
-
intersections.sort((a, b) => a - b);
|
|
456
|
-
// Fill between pairs of intersections
|
|
457
|
-
for (let i = 0; i < intersections.length; i += 2) {
|
|
458
|
-
const x1 = intersections[i];
|
|
459
|
-
const x2 = intersections[i + 1] ?? x1;
|
|
460
|
-
for (let x = x1; x <= x2; x++) {
|
|
461
|
-
points.push({ x, y });
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
return points;
|
|
466
|
-
}
|
|
467
|
-
/**
|
|
468
|
-
* Rectangle outline
|
|
469
|
-
*/
|
|
470
|
-
export function rectanglePoints(x, y, width, height) {
|
|
471
|
-
const points = [];
|
|
472
|
-
// Top edge
|
|
473
|
-
for (let i = 0; i < width; i++) {
|
|
474
|
-
points.push({ x: x + i, y });
|
|
475
|
-
}
|
|
476
|
-
// Bottom edge
|
|
477
|
-
for (let i = 0; i < width; i++) {
|
|
478
|
-
points.push({ x: x + i, y: y + height - 1 });
|
|
479
|
-
}
|
|
480
|
-
// Left edge (excluding corners)
|
|
481
|
-
for (let i = 1; i < height - 1; i++) {
|
|
482
|
-
points.push({ x, y: y + i });
|
|
483
|
-
}
|
|
484
|
-
// Right edge (excluding corners)
|
|
485
|
-
for (let i = 1; i < height - 1; i++) {
|
|
486
|
-
points.push({ x: x + width - 1, y: y + i });
|
|
487
|
-
}
|
|
488
|
-
return points;
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
|
-
* Filled rectangle
|
|
492
|
-
*/
|
|
493
|
-
export function filledRectangle(x, y, width, height) {
|
|
494
|
-
const points = [];
|
|
495
|
-
for (let dy = 0; dy < height; dy++) {
|
|
496
|
-
for (let dx = 0; dx < width; dx++) {
|
|
497
|
-
points.push({ x: x + dx, y: y + dy });
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
return points;
|
|
501
|
-
}
|
|
502
|
-
// =============================================================================
|
|
503
|
-
// Canvas Class
|
|
504
|
-
// =============================================================================
|
|
505
|
-
/**
|
|
506
|
-
* Canvas - 2D Drawing Canvas for Terminal
|
|
507
|
-
*
|
|
508
|
-
* @example
|
|
509
|
-
* ```typescript
|
|
510
|
-
* const canvas = createCanvas({ width: 40, height: 20 });
|
|
511
|
-
*
|
|
512
|
-
* // Draw shapes
|
|
513
|
-
* canvas.line(0, 0, 39, 19);
|
|
514
|
-
* canvas.circle(20, 10, 5);
|
|
515
|
-
* canvas.rect(5, 5, 10, 8, true);
|
|
516
|
-
*
|
|
517
|
-
* // Render to string
|
|
518
|
-
* const output = canvas.render();
|
|
519
|
-
* console.log(output);
|
|
520
|
-
* ```
|
|
521
|
-
*/
|
|
522
|
-
export class Canvas {
|
|
523
|
-
width;
|
|
524
|
-
height;
|
|
525
|
-
mode;
|
|
526
|
-
foreground;
|
|
527
|
-
background;
|
|
528
|
-
fillChar;
|
|
529
|
-
// Character mode buffer
|
|
530
|
-
charBuffer;
|
|
531
|
-
// Braille mode buffer (2x4 resolution per character)
|
|
532
|
-
brailleBuffer = null;
|
|
533
|
-
// Block mode buffer (2x2 resolution per character)
|
|
534
|
-
blockBuffer = null;
|
|
535
|
-
constructor(options) {
|
|
536
|
-
this.width = options.width;
|
|
537
|
-
this.height = options.height;
|
|
538
|
-
this.mode = options.mode ?? 'character';
|
|
539
|
-
this.foreground = options.foreground ?? null;
|
|
540
|
-
this.background = options.background ?? null;
|
|
541
|
-
this.fillChar = options.fillChar ?? '█';
|
|
542
|
-
// Initialize character buffer
|
|
543
|
-
this.charBuffer = [];
|
|
544
|
-
for (let y = 0; y < this.height; y++) {
|
|
545
|
-
this.charBuffer.push(new Array(this.width).fill(' '));
|
|
546
|
-
}
|
|
547
|
-
// Initialize mode-specific buffers
|
|
548
|
-
if (this.mode === 'braille') {
|
|
549
|
-
this.brailleBuffer = createBrailleBuffer(this.width, this.height);
|
|
550
|
-
}
|
|
551
|
-
else if (this.mode === 'block') {
|
|
552
|
-
this.blockBuffer = createBlockBuffer(this.width, this.height);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
/**
|
|
556
|
-
* Get canvas dimensions
|
|
557
|
-
*/
|
|
558
|
-
get dimensions() {
|
|
559
|
-
return { width: this.width, height: this.height };
|
|
560
|
-
}
|
|
561
|
-
/**
|
|
562
|
-
* Get effective resolution based on mode
|
|
563
|
-
*/
|
|
564
|
-
get resolution() {
|
|
565
|
-
switch (this.mode) {
|
|
566
|
-
case 'braille':
|
|
567
|
-
return { width: this.width * 2, height: this.height * 4 };
|
|
568
|
-
case 'block':
|
|
569
|
-
return { width: this.width * 2, height: this.height * 2 };
|
|
570
|
-
default:
|
|
571
|
-
return { width: this.width, height: this.height };
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* Clear the canvas
|
|
576
|
-
*/
|
|
577
|
-
clear() {
|
|
578
|
-
for (let y = 0; y < this.height; y++) {
|
|
579
|
-
this.charBuffer[y] = new Array(this.width).fill(' ');
|
|
580
|
-
}
|
|
581
|
-
if (this.brailleBuffer) {
|
|
582
|
-
this.brailleBuffer = createBrailleBuffer(this.width, this.height);
|
|
583
|
-
}
|
|
584
|
-
if (this.blockBuffer) {
|
|
585
|
-
this.blockBuffer = createBlockBuffer(this.width, this.height);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
/**
|
|
589
|
-
* Set a pixel/character at position
|
|
590
|
-
*/
|
|
591
|
-
setPixel(x, y, char) {
|
|
592
|
-
if (this.mode === 'character') {
|
|
593
|
-
if (x >= 0 && x < this.width && y >= 0 && y < this.height) {
|
|
594
|
-
this.charBuffer[y][x] = char ?? this.fillChar;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
else if (this.mode === 'braille' && this.brailleBuffer) {
|
|
598
|
-
setBrailleDot(this.brailleBuffer, x, y, true);
|
|
599
|
-
}
|
|
600
|
-
else if (this.mode === 'block' && this.blockBuffer) {
|
|
601
|
-
setBlockPixel(this.blockBuffer, x, y, true);
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
/**
|
|
605
|
-
* Get a character at position
|
|
606
|
-
*/
|
|
607
|
-
getPixel(x, y) {
|
|
608
|
-
if (x >= 0 && x < this.width && y >= 0 && y < this.height) {
|
|
609
|
-
return this.charBuffer[y][x];
|
|
610
|
-
}
|
|
611
|
-
return ' ';
|
|
612
|
-
}
|
|
613
|
-
/**
|
|
614
|
-
* Draw a line from (x0, y0) to (x1, y1)
|
|
615
|
-
*/
|
|
616
|
-
line(x0, y0, x1, y1, char) {
|
|
617
|
-
const points = bresenhamLine(Math.round(x0), Math.round(y0), Math.round(x1), Math.round(y1));
|
|
618
|
-
for (const p of points) {
|
|
619
|
-
this.setPixel(p.x, p.y, char);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
/**
|
|
623
|
-
* Draw a rectangle
|
|
624
|
-
*/
|
|
625
|
-
rect(x, y, width, height, filled = false, char) {
|
|
626
|
-
const points = filled
|
|
627
|
-
? filledRectangle(x, y, width, height)
|
|
628
|
-
: rectanglePoints(x, y, width, height);
|
|
629
|
-
for (const p of points) {
|
|
630
|
-
this.setPixel(p.x, p.y, char);
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
/**
|
|
634
|
-
* Draw a circle
|
|
635
|
-
*/
|
|
636
|
-
circle(cx, cy, radius, filled = false, char) {
|
|
637
|
-
const points = filled
|
|
638
|
-
? filledCircle(cx, cy, radius)
|
|
639
|
-
: midpointCircle(cx, cy, radius);
|
|
640
|
-
for (const p of points) {
|
|
641
|
-
this.setPixel(p.x, p.y, char);
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
/**
|
|
645
|
-
* Draw an ellipse
|
|
646
|
-
*/
|
|
647
|
-
ellipse(cx, cy, rx, ry, char) {
|
|
648
|
-
const points = midpointEllipse(cx, cy, rx, ry);
|
|
649
|
-
for (const p of points) {
|
|
650
|
-
this.setPixel(p.x, p.y, char);
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
/**
|
|
654
|
-
* Draw an arc
|
|
655
|
-
*/
|
|
656
|
-
arc(cx, cy, radius, startAngle, endAngle, char) {
|
|
657
|
-
const points = arcPoints(cx, cy, radius, startAngle, endAngle);
|
|
658
|
-
for (const p of points) {
|
|
659
|
-
this.setPixel(p.x, p.y, char);
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
/**
|
|
663
|
-
* Draw a polygon
|
|
664
|
-
*/
|
|
665
|
-
polygon(vertices, filled = false, char) {
|
|
666
|
-
const points = filled ? filledPolygon(vertices) : polygonPoints(vertices);
|
|
667
|
-
for (const p of points) {
|
|
668
|
-
this.setPixel(p.x, p.y, char);
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
/**
|
|
672
|
-
* Draw a cubic bezier curve
|
|
673
|
-
*/
|
|
674
|
-
bezier(p0, p1, p2, p3, char) {
|
|
675
|
-
const points = bezierCurve(p0, p1, p2, p3);
|
|
676
|
-
for (const p of points) {
|
|
677
|
-
this.setPixel(p.x, p.y, char);
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
/**
|
|
681
|
-
* Draw a quadratic bezier curve
|
|
682
|
-
*/
|
|
683
|
-
quadBezier(p0, p1, p2, char) {
|
|
684
|
-
const points = quadraticBezier(p0, p1, p2);
|
|
685
|
-
for (const p of points) {
|
|
686
|
-
this.setPixel(p.x, p.y, char);
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
/**
|
|
690
|
-
* Draw text at position
|
|
691
|
-
*/
|
|
692
|
-
text(x, y, str, style) {
|
|
693
|
-
if (y < 0 || y >= this.height)
|
|
694
|
-
return;
|
|
695
|
-
let startX = x;
|
|
696
|
-
// Handle alignment
|
|
697
|
-
if (style?.align === 'center') {
|
|
698
|
-
startX = x - Math.floor(str.length / 2);
|
|
699
|
-
}
|
|
700
|
-
else if (style?.align === 'right') {
|
|
701
|
-
startX = x - str.length + 1;
|
|
702
|
-
}
|
|
703
|
-
for (let i = 0; i < str.length; i++) {
|
|
704
|
-
const px = startX + i;
|
|
705
|
-
if (px >= 0 && px < this.width) {
|
|
706
|
-
this.charBuffer[y][px] = str[i];
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
/**
|
|
711
|
-
* Draw points from an array
|
|
712
|
-
*/
|
|
713
|
-
drawPoints(points, char) {
|
|
714
|
-
for (const p of points) {
|
|
715
|
-
this.setPixel(p.x, p.y, char);
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
/**
|
|
719
|
-
* Flood fill from a point
|
|
720
|
-
*/
|
|
721
|
-
floodFill(x, y, fillChar, targetChar) {
|
|
722
|
-
if (x < 0 || x >= this.width || y < 0 || y >= this.height)
|
|
723
|
-
return;
|
|
724
|
-
const target = targetChar ?? this.charBuffer[y][x];
|
|
725
|
-
if (target === fillChar)
|
|
726
|
-
return;
|
|
727
|
-
const stack = [{ x, y }];
|
|
728
|
-
const visited = new Set();
|
|
729
|
-
while (stack.length > 0) {
|
|
730
|
-
const p = stack.pop();
|
|
731
|
-
const key = `${p.x},${p.y}`;
|
|
732
|
-
if (visited.has(key))
|
|
733
|
-
continue;
|
|
734
|
-
if (p.x < 0 || p.x >= this.width || p.y < 0 || p.y >= this.height)
|
|
735
|
-
continue;
|
|
736
|
-
if (this.charBuffer[p.y][p.x] !== target)
|
|
737
|
-
continue;
|
|
738
|
-
visited.add(key);
|
|
739
|
-
this.charBuffer[p.y][p.x] = fillChar;
|
|
740
|
-
stack.push({ x: p.x + 1, y: p.y });
|
|
741
|
-
stack.push({ x: p.x - 1, y: p.y });
|
|
742
|
-
stack.push({ x: p.x, y: p.y + 1 });
|
|
743
|
-
stack.push({ x: p.x, y: p.y - 1 });
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
/**
|
|
747
|
-
* Render canvas to string
|
|
748
|
-
*/
|
|
749
|
-
render() {
|
|
750
|
-
if (this.mode === 'braille' && this.brailleBuffer) {
|
|
751
|
-
return brailleBufferToString(this.brailleBuffer);
|
|
752
|
-
}
|
|
753
|
-
if (this.mode === 'block' && this.blockBuffer) {
|
|
754
|
-
return blockBufferToString(this.blockBuffer);
|
|
755
|
-
}
|
|
756
|
-
// Character mode
|
|
757
|
-
return this.charBuffer.map((row) => row.join('')).join('\n');
|
|
758
|
-
}
|
|
759
|
-
/**
|
|
760
|
-
* Get canvas state
|
|
761
|
-
*/
|
|
762
|
-
getState() {
|
|
763
|
-
return {
|
|
764
|
-
width: this.width,
|
|
765
|
-
height: this.height,
|
|
766
|
-
mode: this.mode,
|
|
767
|
-
buffer: this.charBuffer.map((row) => [...row]),
|
|
768
|
-
foreground: this.foreground,
|
|
769
|
-
background: this.background,
|
|
770
|
-
};
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
// =============================================================================
|
|
774
|
-
// Factory Function
|
|
775
|
-
// =============================================================================
|
|
776
|
-
/**
|
|
777
|
-
* Create a new canvas
|
|
778
|
-
*/
|
|
779
|
-
export function createCanvas(options) {
|
|
780
|
-
return new Canvas(options);
|
|
781
|
-
}
|
|
782
|
-
// =============================================================================
|
|
783
|
-
// Utility Functions
|
|
784
|
-
// =============================================================================
|
|
785
|
-
/**
|
|
786
|
-
* Create a sparkline chart on a canvas
|
|
787
|
-
*/
|
|
788
|
-
export function drawSparkline(canvas, data, x, y, width, height, char = '█') {
|
|
789
|
-
if (data.length === 0)
|
|
790
|
-
return;
|
|
791
|
-
const min = Math.min(...data);
|
|
792
|
-
const max = Math.max(...data);
|
|
793
|
-
const range = max - min || 1;
|
|
794
|
-
const step = width / (data.length - 1 || 1);
|
|
795
|
-
for (let i = 0; i < data.length - 1; i++) {
|
|
796
|
-
const x0 = Math.round(x + i * step);
|
|
797
|
-
const y0 = Math.round(y + height - 1 - ((data[i] - min) / range) * (height - 1));
|
|
798
|
-
const x1 = Math.round(x + (i + 1) * step);
|
|
799
|
-
const y1 = Math.round(y + height - 1 - ((data[i + 1] - min) / range) * (height - 1));
|
|
800
|
-
canvas.line(x0, y0, x1, y1, char);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
/**
|
|
804
|
-
* Create a bar chart on a canvas
|
|
805
|
-
*/
|
|
806
|
-
export function drawBarChart(canvas, data, x, y, width, height, char = '█') {
|
|
807
|
-
if (data.length === 0)
|
|
808
|
-
return;
|
|
809
|
-
const max = Math.max(...data);
|
|
810
|
-
const barWidth = Math.floor(width / data.length);
|
|
811
|
-
for (let i = 0; i < data.length; i++) {
|
|
812
|
-
const barHeight = Math.round((data[i] / max) * (height - 1));
|
|
813
|
-
const barX = x + i * barWidth;
|
|
814
|
-
for (let dy = 0; dy < barHeight; dy++) {
|
|
815
|
-
for (let dx = 0; dx < barWidth - 1; dx++) {
|
|
816
|
-
canvas.setPixel(barX + dx, y + height - 1 - dy, char);
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
/**
|
|
822
|
-
* Create a scatter plot on a canvas
|
|
823
|
-
*/
|
|
824
|
-
export function drawScatterPlot(canvas, points, bounds, canvasBounds, char = '●') {
|
|
825
|
-
const { minX, maxX, minY, maxY } = bounds;
|
|
826
|
-
const { x, y, width, height } = canvasBounds;
|
|
827
|
-
for (const point of points) {
|
|
828
|
-
const px = x + Math.round(((point.x - minX) / (maxX - minX)) * (width - 1));
|
|
829
|
-
const py = y + height - 1 - Math.round(((point.y - minY) / (maxY - minY)) * (height - 1));
|
|
830
|
-
canvas.setPixel(px, py, char);
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
//# sourceMappingURL=canvas.js.map
|