@react-x11/components 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +979 -21
- package/dist/ansi/cast.d.ts +48 -0
- package/dist/ansi/cast.d.ts.map +1 -0
- package/dist/ansi/cast.js +135 -0
- package/dist/ansi/cast.js.map +1 -0
- package/dist/ansi/index.d.ts +10 -0
- package/dist/ansi/index.d.ts.map +1 -0
- package/dist/ansi/index.js +27 -0
- package/dist/ansi/index.js.map +1 -0
- package/dist/ansi/palette.d.ts +79 -0
- package/dist/ansi/palette.d.ts.map +1 -0
- package/dist/ansi/palette.js +155 -0
- package/dist/ansi/palette.js.map +1 -0
- package/dist/ansi/parse.d.ts +114 -0
- package/dist/ansi/parse.d.ts.map +1 -0
- package/dist/ansi/parse.js +687 -0
- package/dist/ansi/parse.js.map +1 -0
- package/dist/ansi/sgr.d.ts +87 -0
- package/dist/ansi/sgr.d.ts.map +1 -0
- package/dist/ansi/sgr.js +302 -0
- package/dist/ansi/sgr.js.map +1 -0
- package/dist/ansi/utf8.d.ts +15 -0
- package/dist/ansi/utf8.d.ts.map +1 -0
- package/dist/ansi/utf8.js +82 -0
- package/dist/ansi/utf8.js.map +1 -0
- package/dist/calendar/Calendar.d.ts +136 -0
- package/dist/calendar/Calendar.d.ts.map +1 -0
- package/dist/calendar/Calendar.js +460 -0
- package/dist/calendar/Calendar.js.map +1 -0
- package/dist/calendar/DatePicker.d.ts +52 -0
- package/dist/calendar/DatePicker.d.ts.map +1 -0
- package/dist/calendar/DatePicker.js +257 -0
- package/dist/calendar/DatePicker.js.map +1 -0
- package/dist/calendar/dates.d.ts +90 -0
- package/dist/calendar/dates.d.ts.map +1 -0
- package/dist/calendar/dates.js +236 -0
- package/dist/calendar/dates.js.map +1 -0
- package/dist/calendar/index.d.ts +8 -0
- package/dist/calendar/index.d.ts.map +1 -0
- package/dist/calendar/index.js +15 -0
- package/dist/calendar/index.js.map +1 -0
- package/dist/charts/components.d.ts +141 -0
- package/dist/charts/components.d.ts.map +1 -0
- package/dist/charts/components.js +580 -0
- package/dist/charts/components.js.map +1 -0
- package/dist/charts/data.d.ts +198 -0
- package/dist/charts/data.d.ts.map +1 -0
- package/dist/charts/data.js +616 -0
- package/dist/charts/data.js.map +1 -0
- package/dist/charts/hx.d.ts +21 -0
- package/dist/charts/hx.d.ts.map +1 -0
- package/dist/charts/hx.js +15 -0
- package/dist/charts/hx.js.map +1 -0
- package/dist/charts/index.d.ts +27 -0
- package/dist/charts/index.d.ts.map +1 -0
- package/dist/charts/index.js +38 -0
- package/dist/charts/index.js.map +1 -0
- package/dist/charts/node.d.ts +96 -0
- package/dist/charts/node.d.ts.map +1 -0
- package/dist/charts/node.js +720 -0
- package/dist/charts/node.js.map +1 -0
- package/dist/charts/render.d.ts +153 -0
- package/dist/charts/render.d.ts.map +1 -0
- package/dist/charts/render.js +762 -0
- package/dist/charts/render.js.map +1 -0
- package/dist/charts/scale.d.ts +42 -0
- package/dist/charts/scale.d.ts.map +1 -0
- package/dist/charts/scale.js +173 -0
- package/dist/charts/scale.js.map +1 -0
- package/dist/charts/spec.d.ts +91 -0
- package/dist/charts/spec.d.ts.map +1 -0
- package/dist/charts/spec.js +33 -0
- package/dist/charts/spec.js.map +1 -0
- package/dist/charts/timers.d.ts +6 -0
- package/dist/charts/timers.d.ts.map +1 -0
- package/dist/charts/timers.js +14 -0
- package/dist/charts/timers.js.map +1 -0
- package/dist/code/hx.d.ts +24 -0
- package/dist/code/hx.d.ts.map +1 -0
- package/dist/code/hx.js +25 -0
- package/dist/code/hx.js.map +1 -0
- package/dist/code/index.d.ts +45 -0
- package/dist/code/index.d.ts.map +1 -0
- package/dist/code/index.js +93 -0
- package/dist/code/index.js.map +1 -0
- package/dist/code-editor/completion.d.ts +26 -0
- package/dist/code-editor/completion.d.ts.map +1 -0
- package/dist/code-editor/completion.js +129 -0
- package/dist/code-editor/completion.js.map +1 -0
- package/dist/code-editor/doc.d.ts +35 -0
- package/dist/code-editor/doc.d.ts.map +1 -0
- package/dist/code-editor/doc.js +162 -0
- package/dist/code-editor/doc.js.map +1 -0
- package/dist/code-editor/hx.d.ts +13 -0
- package/dist/code-editor/hx.d.ts.map +1 -0
- package/dist/code-editor/hx.js +10 -0
- package/dist/code-editor/hx.js.map +1 -0
- package/dist/code-editor/index.d.ts +88 -0
- package/dist/code-editor/index.d.ts.map +1 -0
- package/dist/code-editor/index.js +401 -0
- package/dist/code-editor/index.js.map +1 -0
- package/dist/code-editor/node.d.ts +343 -0
- package/dist/code-editor/node.d.ts.map +1 -0
- package/dist/code-editor/node.js +1521 -0
- package/dist/code-editor/node.js.map +1 -0
- package/dist/code-language/hljs.d.ts +47 -0
- package/dist/code-language/hljs.d.ts.map +1 -0
- package/dist/code-language/hljs.js +211 -0
- package/dist/code-language/hljs.js.map +1 -0
- package/dist/code-language/index.d.ts +22 -0
- package/dist/code-language/index.d.ts.map +1 -0
- package/dist/code-language/index.js +20 -0
- package/dist/code-language/index.js.map +1 -0
- package/dist/code-language/languages/glsl.d.ts +4 -0
- package/dist/code-language/languages/glsl.d.ts.map +1 -0
- package/dist/code-language/languages/glsl.js +99 -0
- package/dist/code-language/languages/glsl.js.map +1 -0
- package/dist/code-language/languages/javascript.d.ts +10 -0
- package/dist/code-language/languages/javascript.d.ts.map +1 -0
- package/dist/code-language/languages/javascript.js +360 -0
- package/dist/code-language/languages/javascript.js.map +1 -0
- package/dist/code-language/languages/json.d.ts +4 -0
- package/dist/code-language/languages/json.d.ts.map +1 -0
- package/dist/code-language/languages/json.js +68 -0
- package/dist/code-language/languages/json.js.map +1 -0
- package/dist/code-language/languages/shell.d.ts +4 -0
- package/dist/code-language/languages/shell.d.ts.map +1 -0
- package/dist/code-language/languages/shell.js +189 -0
- package/dist/code-language/languages/shell.js.map +1 -0
- package/dist/code-language/languages/sql.d.ts +11 -0
- package/dist/code-language/languages/sql.d.ts.map +1 -0
- package/dist/code-language/languages/sql.js +133 -0
- package/dist/code-language/languages/sql.js.map +1 -0
- package/dist/code-language/lezer.d.ts +24 -0
- package/dist/code-language/lezer.d.ts.map +1 -0
- package/dist/code-language/lezer.js +148 -0
- package/dist/code-language/lezer.js.map +1 -0
- package/dist/code-language/registry.d.ts +19 -0
- package/dist/code-language/registry.d.ts.map +1 -0
- package/dist/code-language/registry.js +56 -0
- package/dist/code-language/registry.js.map +1 -0
- package/dist/code-language/runs.d.ts +35 -0
- package/dist/code-language/runs.d.ts.map +1 -0
- package/dist/code-language/runs.js +88 -0
- package/dist/code-language/runs.js.map +1 -0
- package/dist/code-language/stream.d.ts +70 -0
- package/dist/code-language/stream.d.ts.map +1 -0
- package/dist/code-language/stream.js +243 -0
- package/dist/code-language/stream.js.map +1 -0
- package/dist/code-language/textmate.d.ts +27 -0
- package/dist/code-language/textmate.d.ts.map +1 -0
- package/dist/code-language/textmate.js +86 -0
- package/dist/code-language/textmate.js.map +1 -0
- package/dist/code-language/theme.d.ts +26 -0
- package/dist/code-language/theme.d.ts.map +1 -0
- package/dist/code-language/theme.js +108 -0
- package/dist/code-language/theme.js.map +1 -0
- package/dist/code-language/timers.d.ts +7 -0
- package/dist/code-language/timers.d.ts.map +1 -0
- package/dist/code-language/timers.js +22 -0
- package/dist/code-language/timers.js.map +1 -0
- package/dist/code-language/types.d.ts +173 -0
- package/dist/code-language/types.d.ts.map +1 -0
- package/dist/code-language/types.js +41 -0
- package/dist/code-language/types.js.map +1 -0
- package/dist/codeblock/index.d.ts +69 -0
- package/dist/codeblock/index.d.ts.map +1 -0
- package/dist/codeblock/index.js +85 -0
- package/dist/codeblock/index.js.map +1 -0
- package/dist/color-picker/ColorField.d.ts +39 -0
- package/dist/color-picker/ColorField.d.ts.map +1 -0
- package/dist/color-picker/ColorField.js +239 -0
- package/dist/color-picker/ColorField.js.map +1 -0
- package/dist/color-picker/ColorPicker.d.ts +109 -0
- package/dist/color-picker/ColorPicker.d.ts.map +1 -0
- package/dist/color-picker/ColorPicker.js +757 -0
- package/dist/color-picker/ColorPicker.js.map +1 -0
- package/dist/color-picker/color.d.ts +105 -0
- package/dist/color-picker/color.d.ts.map +1 -0
- package/dist/color-picker/color.js +313 -0
- package/dist/color-picker/color.js.map +1 -0
- package/dist/color-picker/index.d.ts +8 -0
- package/dist/color-picker/index.d.ts.map +1 -0
- package/dist/color-picker/index.js +19 -0
- package/dist/color-picker/index.js.map +1 -0
- package/dist/desktop-calendar/eds.d.ts +102 -0
- package/dist/desktop-calendar/eds.d.ts.map +1 -0
- package/dist/desktop-calendar/eds.js +356 -0
- package/dist/desktop-calendar/eds.js.map +1 -0
- package/dist/desktop-calendar/ical.d.ts +63 -0
- package/dist/desktop-calendar/ical.d.ts.map +1 -0
- package/dist/desktop-calendar/ical.js +57 -0
- package/dist/desktop-calendar/ical.js.map +1 -0
- package/dist/desktop-calendar/index.d.ts +72 -0
- package/dist/desktop-calendar/index.d.ts.map +1 -0
- package/dist/desktop-calendar/index.js +213 -0
- package/dist/desktop-calendar/index.js.map +1 -0
- package/dist/embed/client.d.ts +121 -0
- package/dist/embed/client.d.ts.map +1 -0
- package/dist/embed/client.js +203 -0
- package/dist/embed/client.js.map +1 -0
- package/dist/embed/host.d.ts +96 -0
- package/dist/embed/host.d.ts.map +1 -0
- package/dist/embed/host.js +266 -0
- package/dist/embed/host.js.map +1 -0
- package/dist/embed/index.d.ts +5 -0
- package/dist/embed/index.d.ts.map +1 -0
- package/dist/embed/index.js +13 -0
- package/dist/embed/index.js.map +1 -0
- package/dist/embed/timers.d.ts +6 -0
- package/dist/embed/timers.d.ts.map +1 -0
- package/dist/embed/timers.js +16 -0
- package/dist/embed/timers.js.map +1 -0
- package/dist/flow/draw.d.ts +45 -0
- package/dist/flow/draw.d.ts.map +1 -0
- package/dist/flow/draw.js +295 -0
- package/dist/flow/draw.js.map +1 -0
- package/dist/flow/index.d.ts +64 -0
- package/dist/flow/index.d.ts.map +1 -0
- package/dist/flow/index.js +306 -0
- package/dist/flow/index.js.map +1 -0
- package/dist/flow/model.d.ts +158 -0
- package/dist/flow/model.d.ts.map +1 -0
- package/dist/flow/model.js +566 -0
- package/dist/flow/model.js.map +1 -0
- package/dist/flow/node.d.ts +429 -0
- package/dist/flow/node.d.ts.map +1 -0
- package/dist/flow/node.js +3025 -0
- package/dist/flow/node.js.map +1 -0
- package/dist/flow/paths.d.ts +43 -0
- package/dist/flow/paths.d.ts.map +1 -0
- package/dist/flow/paths.js +327 -0
- package/dist/flow/paths.js.map +1 -0
- package/dist/flow/types.d.ts +561 -0
- package/dist/flow/types.d.ts.map +1 -0
- package/dist/flow/types.js +2 -0
- package/dist/flow/types.js.map +1 -0
- package/dist/formula/hx.d.ts +24 -0
- package/dist/formula/hx.d.ts.map +1 -0
- package/dist/formula/hx.js +25 -0
- package/dist/formula/hx.js.map +1 -0
- package/dist/formula/index.d.ts +74 -0
- package/dist/formula/index.d.ts.map +1 -0
- package/dist/formula/index.js +155 -0
- package/dist/formula/index.js.map +1 -0
- package/dist/formula/katex.d.ts +78 -0
- package/dist/formula/katex.d.ts.map +1 -0
- package/dist/formula/katex.js +130 -0
- package/dist/formula/katex.js.map +1 -0
- package/dist/formula/layout.d.ts +103 -0
- package/dist/formula/layout.d.ts.map +1 -0
- package/dist/formula/layout.js +716 -0
- package/dist/formula/layout.js.map +1 -0
- package/dist/formula/node.d.ts +50 -0
- package/dist/formula/node.d.ts.map +1 -0
- package/dist/formula/node.js +351 -0
- package/dist/formula/node.js.map +1 -0
- package/dist/html/controls.d.ts +48 -0
- package/dist/html/controls.d.ts.map +1 -0
- package/dist/html/controls.js +195 -0
- package/dist/html/controls.js.map +1 -0
- package/dist/html/css/cascade.d.ts +51 -0
- package/dist/html/css/cascade.d.ts.map +1 -0
- package/dist/html/css/cascade.js +552 -0
- package/dist/html/css/cascade.js.map +1 -0
- package/dist/html/css/parse.d.ts +74 -0
- package/dist/html/css/parse.d.ts.map +1 -0
- package/dist/html/css/parse.js +464 -0
- package/dist/html/css/parse.js.map +1 -0
- package/dist/html/css/style.d.ts +142 -0
- package/dist/html/css/style.d.ts.map +1 -0
- package/dist/html/css/style.js +1145 -0
- package/dist/html/css/style.js.map +1 -0
- package/dist/html/css/ua.d.ts +5 -0
- package/dist/html/css/ua.d.ts.map +1 -0
- package/dist/html/css/ua.js +171 -0
- package/dist/html/css/ua.js.map +1 -0
- package/dist/html/css/values.d.ts +78 -0
- package/dist/html/css/values.d.ts.map +1 -0
- package/dist/html/css/values.js +330 -0
- package/dist/html/css/values.js.map +1 -0
- package/dist/html/dom.d.ts +112 -0
- package/dist/html/dom.d.ts.map +1 -0
- package/dist/html/dom.js +374 -0
- package/dist/html/dom.js.map +1 -0
- package/dist/html/hx.d.ts +24 -0
- package/dist/html/hx.d.ts.map +1 -0
- package/dist/html/hx.js +29 -0
- package/dist/html/hx.js.map +1 -0
- package/dist/html/index.d.ts +137 -0
- package/dist/html/index.d.ts.map +1 -0
- package/dist/html/index.js +339 -0
- package/dist/html/index.js.map +1 -0
- package/dist/html/layout/block.d.ts +58 -0
- package/dist/html/layout/block.d.ts.map +1 -0
- package/dist/html/layout/block.js +724 -0
- package/dist/html/layout/block.js.map +1 -0
- package/dist/html/layout/boxes.d.ts +261 -0
- package/dist/html/layout/boxes.d.ts.map +1 -0
- package/dist/html/layout/boxes.js +725 -0
- package/dist/html/layout/boxes.js.map +1 -0
- package/dist/html/layout/flex.d.ts +16 -0
- package/dist/html/layout/flex.d.ts.map +1 -0
- package/dist/html/layout/flex.js +242 -0
- package/dist/html/layout/flex.js.map +1 -0
- package/dist/html/layout/floats.d.ts +50 -0
- package/dist/html/layout/floats.d.ts.map +1 -0
- package/dist/html/layout/floats.js +110 -0
- package/dist/html/layout/floats.js.map +1 -0
- package/dist/html/layout/inline.d.ts +44 -0
- package/dist/html/layout/inline.d.ts.map +1 -0
- package/dist/html/layout/inline.js +700 -0
- package/dist/html/layout/inline.js.map +1 -0
- package/dist/html/layout/table.d.ts +5 -0
- package/dist/html/layout/table.d.ts.map +1 -0
- package/dist/html/layout/table.js +340 -0
- package/dist/html/layout/table.js.map +1 -0
- package/dist/html/node.d.ts +149 -0
- package/dist/html/node.d.ts.map +1 -0
- package/dist/html/node.js +861 -0
- package/dist/html/node.js.map +1 -0
- package/dist/html/paint.d.ts +48 -0
- package/dist/html/paint.d.ts.map +1 -0
- package/dist/html/paint.js +495 -0
- package/dist/html/paint.js.map +1 -0
- package/dist/html/resources.d.ts +48 -0
- package/dist/html/resources.d.ts.map +1 -0
- package/dist/html/resources.js +156 -0
- package/dist/html/resources.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +92 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/heights.d.ts +81 -0
- package/dist/internal/heights.d.ts.map +1 -0
- package/dist/internal/heights.js +193 -0
- package/dist/internal/heights.js.map +1 -0
- package/dist/internal/hx.d.ts +24 -0
- package/dist/internal/hx.d.ts.map +1 -0
- package/dist/internal/hx.js +27 -0
- package/dist/internal/hx.js.map +1 -0
- package/dist/internal/text.d.ts +6 -0
- package/dist/internal/text.d.ts.map +1 -0
- package/dist/internal/text.js +44 -0
- package/dist/internal/text.js.map +1 -0
- package/dist/internal/timers.d.ts +8 -0
- package/dist/internal/timers.d.ts.map +1 -0
- package/dist/internal/timers.js +22 -0
- package/dist/internal/timers.js.map +1 -0
- package/dist/internal/widget.d.ts +40 -0
- package/dist/internal/widget.d.ts.map +1 -0
- package/dist/internal/widget.js +44 -0
- package/dist/internal/widget.js.map +1 -0
- package/dist/markdown/ast.d.ts +126 -0
- package/dist/markdown/ast.d.ts.map +1 -0
- package/dist/markdown/ast.js +8 -0
- package/dist/markdown/ast.js.map +1 -0
- package/dist/markdown/hx.d.ts +24 -0
- package/dist/markdown/hx.d.ts.map +1 -0
- package/dist/markdown/hx.js +25 -0
- package/dist/markdown/hx.js.map +1 -0
- package/dist/markdown/index.d.ts +90 -0
- package/dist/markdown/index.d.ts.map +1 -0
- package/dist/markdown/index.js +413 -0
- package/dist/markdown/index.js.map +1 -0
- package/dist/markdown/parse.d.ts +8 -0
- package/dist/markdown/parse.d.ts.map +1 -0
- package/dist/markdown/parse.js +911 -0
- package/dist/markdown/parse.js.map +1 -0
- package/dist/markdown/spans.d.ts +20 -0
- package/dist/markdown/spans.d.ts.map +1 -0
- package/dist/markdown/spans.js +96 -0
- package/dist/markdown/spans.js.map +1 -0
- package/dist/media-player/backends.d.ts +64 -0
- package/dist/media-player/backends.d.ts.map +1 -0
- package/dist/media-player/backends.js +110 -0
- package/dist/media-player/backends.js.map +1 -0
- package/dist/media-player/control.d.ts +40 -0
- package/dist/media-player/control.d.ts.map +1 -0
- package/dist/media-player/control.js +44 -0
- package/dist/media-player/control.js.map +1 -0
- package/dist/media-player/hx.d.ts +24 -0
- package/dist/media-player/hx.d.ts.map +1 -0
- package/dist/media-player/hx.js +25 -0
- package/dist/media-player/hx.js.map +1 -0
- package/dist/media-player/index.d.ts +107 -0
- package/dist/media-player/index.d.ts.map +1 -0
- package/dist/media-player/index.js +219 -0
- package/dist/media-player/index.js.map +1 -0
- package/dist/media-player/mpv.d.ts +4 -0
- package/dist/media-player/mpv.d.ts.map +1 -0
- package/dist/media-player/mpv.js +120 -0
- package/dist/media-player/mpv.js.map +1 -0
- package/dist/media-player/vlc.d.ts +8 -0
- package/dist/media-player/vlc.d.ts.map +1 -0
- package/dist/media-player/vlc.js +83 -0
- package/dist/media-player/vlc.js.map +1 -0
- package/dist/richtext/index.d.ts +19 -0
- package/dist/richtext/index.d.ts.map +1 -0
- package/dist/richtext/index.js +4 -0
- package/dist/richtext/index.js.map +1 -0
- package/dist/richtext/links.d.ts +12 -0
- package/dist/richtext/links.d.ts.map +1 -0
- package/dist/richtext/links.js +64 -0
- package/dist/richtext/links.js.map +1 -0
- package/dist/richtext/menu.d.ts +11 -0
- package/dist/richtext/menu.d.ts.map +1 -0
- package/dist/richtext/menu.js +43 -0
- package/dist/richtext/menu.js.map +1 -0
- package/dist/richtext/node.d.ts +151 -0
- package/dist/richtext/node.d.ts.map +1 -0
- package/dist/richtext/node.js +255 -0
- package/dist/richtext/node.js.map +1 -0
- package/dist/richtext/runs.d.ts +92 -0
- package/dist/richtext/runs.d.ts.map +1 -0
- package/dist/richtext/runs.js +158 -0
- package/dist/richtext/runs.js.map +1 -0
- package/dist/table/hx.d.ts +24 -0
- package/dist/table/hx.d.ts.map +1 -0
- package/dist/table/hx.js +25 -0
- package/dist/table/hx.js.map +1 -0
- package/dist/table/index.d.ts +169 -0
- package/dist/table/index.d.ts.map +1 -0
- package/dist/table/index.js +844 -0
- package/dist/table/index.js.map +1 -0
- package/dist/table/rows.d.ts +136 -0
- package/dist/table/rows.d.ts.map +1 -0
- package/dist/table/rows.js +146 -0
- package/dist/table/rows.js.map +1 -0
- package/dist/terminal/backends.d.ts +105 -0
- package/dist/terminal/backends.d.ts.map +1 -0
- package/dist/terminal/backends.js +185 -0
- package/dist/terminal/backends.js.map +1 -0
- package/dist/terminal/hx.d.ts +24 -0
- package/dist/terminal/hx.d.ts.map +1 -0
- package/dist/terminal/hx.js +25 -0
- package/dist/terminal/hx.js.map +1 -0
- package/dist/terminal/index.d.ts +160 -0
- package/dist/terminal/index.d.ts.map +1 -0
- package/dist/terminal/index.js +344 -0
- package/dist/terminal/index.js.map +1 -0
- package/dist/terminal/title.d.ts +24 -0
- package/dist/terminal/title.d.ts.map +1 -0
- package/dist/terminal/title.js +129 -0
- package/dist/terminal/title.js.map +1 -0
- package/dist/terminal/vt/colors.d.ts +63 -0
- package/dist/terminal/vt/colors.d.ts.map +1 -0
- package/dist/terminal/vt/colors.js +203 -0
- package/dist/terminal/vt/colors.js.map +1 -0
- package/dist/terminal/vt/diff.d.ts +117 -0
- package/dist/terminal/vt/diff.d.ts.map +1 -0
- package/dist/terminal/vt/diff.js +358 -0
- package/dist/terminal/vt/diff.js.map +1 -0
- package/dist/terminal/vt/fonts.d.ts +92 -0
- package/dist/terminal/vt/fonts.d.ts.map +1 -0
- package/dist/terminal/vt/fonts.js +178 -0
- package/dist/terminal/vt/fonts.js.map +1 -0
- package/dist/terminal/vt/index.d.ts +78 -0
- package/dist/terminal/vt/index.d.ts.map +1 -0
- package/dist/terminal/vt/index.js +312 -0
- package/dist/terminal/vt/index.js.map +1 -0
- package/dist/terminal/vt/keys.d.ts +74 -0
- package/dist/terminal/vt/keys.d.ts.map +1 -0
- package/dist/terminal/vt/keys.js +309 -0
- package/dist/terminal/vt/keys.js.map +1 -0
- package/dist/terminal/vt/mouse.d.ts +44 -0
- package/dist/terminal/vt/mouse.d.ts.map +1 -0
- package/dist/terminal/vt/mouse.js +106 -0
- package/dist/terminal/vt/mouse.js.map +1 -0
- package/dist/terminal/vt/node.d.ts +246 -0
- package/dist/terminal/vt/node.d.ts.map +1 -0
- package/dist/terminal/vt/node.js +1068 -0
- package/dist/terminal/vt/node.js.map +1 -0
- package/dist/terminal/vt/pty.d.ts +81 -0
- package/dist/terminal/vt/pty.d.ts.map +1 -0
- package/dist/terminal/vt/pty.js +201 -0
- package/dist/terminal/vt/pty.js.map +1 -0
- package/dist/terminal/vt/renderer.d.ts +179 -0
- package/dist/terminal/vt/renderer.d.ts.map +1 -0
- package/dist/terminal/vt/renderer.js +357 -0
- package/dist/terminal/vt/renderer.js.map +1 -0
- package/dist/terminal/vt/timers.d.ts +6 -0
- package/dist/terminal/vt/timers.d.ts.map +1 -0
- package/dist/terminal/vt/timers.js +16 -0
- package/dist/terminal/vt/timers.js.map +1 -0
- package/dist/terminal/vt/xterm.d.ts +142 -0
- package/dist/terminal/vt/xterm.d.ts.map +1 -0
- package/dist/terminal/vt/xterm.js +32 -0
- package/dist/terminal/vt/xterm.js.map +1 -0
- package/dist/terminal-output/hx.d.ts +24 -0
- package/dist/terminal-output/hx.d.ts.map +1 -0
- package/dist/terminal-output/hx.js +25 -0
- package/dist/terminal-output/hx.js.map +1 -0
- package/dist/terminal-output/index.d.ts +92 -0
- package/dist/terminal-output/index.d.ts.map +1 -0
- package/dist/terminal-output/index.js +179 -0
- package/dist/terminal-output/index.js.map +1 -0
- package/dist/terminal-output/runs.d.ts +27 -0
- package/dist/terminal-output/runs.d.ts.map +1 -0
- package/dist/terminal-output/runs.js +66 -0
- package/dist/terminal-output/runs.js.map +1 -0
- package/dist/three/canvas.d.ts +46 -0
- package/dist/three/canvas.d.ts.map +1 -0
- package/dist/three/canvas.js +305 -0
- package/dist/three/canvas.js.map +1 -0
- package/dist/three/events.d.ts +64 -0
- package/dist/three/events.d.ts.map +1 -0
- package/dist/three/events.js +146 -0
- package/dist/three/events.js.map +1 -0
- package/dist/three/geometries.d.ts +89 -0
- package/dist/three/geometries.d.ts.map +1 -0
- package/dist/three/geometries.js +345 -0
- package/dist/three/geometries.js.map +1 -0
- package/dist/three/globals.d.ts +7 -0
- package/dist/three/globals.d.ts.map +1 -0
- package/dist/three/globals.js +20 -0
- package/dist/three/globals.js.map +1 -0
- package/dist/three/hx.d.ts +9 -0
- package/dist/three/hx.d.ts.map +1 -0
- package/dist/three/hx.js +10 -0
- package/dist/three/hx.js.map +1 -0
- package/dist/three/index.d.ts +22 -0
- package/dist/three/index.d.ts.map +1 -0
- package/dist/three/index.js +24 -0
- package/dist/three/index.js.map +1 -0
- package/dist/three/jsx-dev-runtime.d.ts +19 -0
- package/dist/three/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/three/jsx-dev-runtime.js +2 -0
- package/dist/three/jsx-dev-runtime.js.map +1 -0
- package/dist/three/jsx-runtime.d.ts +19 -0
- package/dist/three/jsx-runtime.d.ts.map +1 -0
- package/dist/three/jsx-runtime.js +2 -0
- package/dist/three/jsx-runtime.js.map +1 -0
- package/dist/three/jsx.d.ts +198 -0
- package/dist/three/jsx.d.ts.map +1 -0
- package/dist/three/jsx.js +2 -0
- package/dist/three/jsx.js.map +1 -0
- package/dist/three/materials.d.ts +125 -0
- package/dist/three/materials.d.ts.map +1 -0
- package/dist/three/materials.js +229 -0
- package/dist/three/materials.js.map +1 -0
- package/dist/three/math.d.ts +146 -0
- package/dist/three/math.d.ts.map +1 -0
- package/dist/three/math.js +464 -0
- package/dist/three/math.js.map +1 -0
- package/dist/three/objects.d.ts +185 -0
- package/dist/three/objects.d.ts.map +1 -0
- package/dist/three/objects.js +309 -0
- package/dist/three/objects.js.map +1 -0
- package/dist/three/passes.d.ts +54 -0
- package/dist/three/passes.d.ts.map +1 -0
- package/dist/three/passes.js +78 -0
- package/dist/three/passes.js.map +1 -0
- package/dist/three/postprocess.d.ts +85 -0
- package/dist/three/postprocess.d.ts.map +1 -0
- package/dist/three/postprocess.js +503 -0
- package/dist/three/postprocess.js.map +1 -0
- package/dist/three/raycast.d.ts +24 -0
- package/dist/three/raycast.d.ts.map +1 -0
- package/dist/three/raycast.js +138 -0
- package/dist/three/raycast.js.map +1 -0
- package/dist/three/reconciler.d.ts +48 -0
- package/dist/three/reconciler.d.ts.map +1 -0
- package/dist/three/reconciler.js +416 -0
- package/dist/three/reconciler.js.map +1 -0
- package/dist/three/renderer-direct.d.ts +102 -0
- package/dist/three/renderer-direct.d.ts.map +1 -0
- package/dist/three/renderer-direct.js +782 -0
- package/dist/three/renderer-direct.js.map +1 -0
- package/dist/three/renderer-indirect.d.ts +68 -0
- package/dist/three/renderer-indirect.d.ts.map +1 -0
- package/dist/three/renderer-indirect.js +438 -0
- package/dist/three/renderer-indirect.js.map +1 -0
- package/dist/three/store.d.ts +81 -0
- package/dist/three/store.d.ts.map +1 -0
- package/dist/three/store.js +110 -0
- package/dist/three/store.js.map +1 -0
- package/dist/timeline/hx.d.ts +18 -0
- package/dist/timeline/hx.d.ts.map +1 -0
- package/dist/timeline/hx.js +10 -0
- package/dist/timeline/hx.js.map +1 -0
- package/dist/timeline/index.d.ts +152 -0
- package/dist/timeline/index.d.ts.map +1 -0
- package/dist/timeline/index.js +383 -0
- package/dist/timeline/index.js.map +1 -0
- package/dist/tray-host/hx.d.ts +24 -0
- package/dist/tray-host/hx.d.ts.map +1 -0
- package/dist/tray-host/hx.js +25 -0
- package/dist/tray-host/hx.js.map +1 -0
- package/dist/tray-host/index.d.ts +110 -0
- package/dist/tray-host/index.d.ts.map +1 -0
- package/dist/tray-host/index.js +191 -0
- package/dist/tray-host/index.js.map +1 -0
- package/dist/tray-host/manager.d.ts +137 -0
- package/dist/tray-host/manager.d.ts.map +1 -0
- package/dist/tray-host/manager.js +462 -0
- package/dist/tray-host/manager.js.map +1 -0
- package/dist/tray-host/notify.d.ts +22 -0
- package/dist/tray-host/notify.d.ts.map +1 -0
- package/dist/tray-host/notify.js +74 -0
- package/dist/tray-host/notify.js.map +1 -0
- package/dist/tray-host/protocol.d.ts +106 -0
- package/dist/tray-host/protocol.d.ts.map +1 -0
- package/dist/tray-host/protocol.js +191 -0
- package/dist/tray-host/protocol.js.map +1 -0
- package/dist/tree/hx.d.ts +24 -0
- package/dist/tree/hx.d.ts.map +1 -0
- package/dist/tree/hx.js +25 -0
- package/dist/tree/hx.js.map +1 -0
- package/dist/tree/index.d.ts +221 -0
- package/dist/tree/index.d.ts.map +1 -0
- package/dist/tree/index.js +716 -0
- package/dist/tree/index.js.map +1 -0
- package/dist/tree/internal.d.ts +18 -0
- package/dist/tree/internal.d.ts.map +1 -0
- package/dist/tree/internal.js +66 -0
- package/dist/tree/internal.js.map +1 -0
- package/dist/tree/rows.d.ts +177 -0
- package/dist/tree/rows.d.ts.map +1 -0
- package/dist/tree/rows.js +179 -0
- package/dist/tree/rows.js.map +1 -0
- package/package.json +166 -12
- package/src/ansi/cast.ts +159 -0
- package/src/ansi/index.ts +53 -0
- package/src/ansi/palette.ts +226 -0
- package/src/ansi/parse.ts +780 -0
- package/src/ansi/sgr.ts +380 -0
- package/src/ansi/utf8.ts +84 -0
- package/src/calendar/Calendar.ts +744 -0
- package/src/calendar/DatePicker.ts +368 -0
- package/src/calendar/dates.ts +307 -0
- package/src/calendar/index.ts +51 -0
- package/src/charts/components.ts +864 -0
- package/src/charts/data.ts +776 -0
- package/src/charts/hx.ts +39 -0
- package/src/charts/index.ts +99 -0
- package/src/charts/node.ts +932 -0
- package/src/charts/render.ts +982 -0
- package/src/charts/scale.ts +214 -0
- package/src/charts/spec.ts +122 -0
- package/src/charts/timers.ts +24 -0
- package/src/code/hx.ts +51 -0
- package/src/code/index.ts +174 -0
- package/src/code-editor/completion.ts +161 -0
- package/src/code-editor/doc.ts +198 -0
- package/src/code-editor/hx.ts +26 -0
- package/src/code-editor/index.ts +615 -0
- package/src/code-editor/node.ts +1926 -0
- package/src/code-language/hljs.ts +302 -0
- package/src/code-language/index.ts +51 -0
- package/src/code-language/languages/glsl.ts +120 -0
- package/src/code-language/languages/javascript.ts +419 -0
- package/src/code-language/languages/json.ts +72 -0
- package/src/code-language/languages/shell.ts +221 -0
- package/src/code-language/languages/sql.ts +165 -0
- package/src/code-language/lezer.ts +190 -0
- package/src/code-language/registry.ts +66 -0
- package/src/code-language/runs.ts +128 -0
- package/src/code-language/stream.ts +306 -0
- package/src/code-language/textmate.ts +134 -0
- package/src/code-language/theme.ts +124 -0
- package/src/code-language/timers.ts +36 -0
- package/src/code-language/types.ts +252 -0
- package/src/codeblock/index.ts +146 -0
- package/src/color-picker/ColorField.ts +333 -0
- package/src/color-picker/ColorPicker.ts +1069 -0
- package/src/color-picker/color.ts +399 -0
- package/src/color-picker/index.ts +50 -0
- package/src/desktop-calendar/eds.ts +484 -0
- package/src/desktop-calendar/ical.ts +119 -0
- package/src/desktop-calendar/index.ts +287 -0
- package/src/embed/client.ts +311 -0
- package/src/embed/host.ts +432 -0
- package/src/embed/index.ts +33 -0
- package/src/embed/timers.ts +32 -0
- package/src/flow/draw.ts +418 -0
- package/src/flow/index.ts +473 -0
- package/src/flow/model.ts +687 -0
- package/src/flow/node.ts +3694 -0
- package/src/flow/paths.ts +403 -0
- package/src/flow/types.ts +634 -0
- package/src/formula/hx.ts +51 -0
- package/src/formula/index.ts +243 -0
- package/src/formula/katex.ts +209 -0
- package/src/formula/layout.ts +876 -0
- package/src/formula/node.ts +467 -0
- package/src/html/controls.ts +244 -0
- package/src/html/css/cascade.ts +606 -0
- package/src/html/css/parse.ts +500 -0
- package/src/html/css/style.ts +1371 -0
- package/src/html/css/ua.ts +174 -0
- package/src/html/css/values.ts +358 -0
- package/src/html/dom.ts +410 -0
- package/src/html/hx.ts +55 -0
- package/src/html/index.ts +545 -0
- package/src/html/layout/block.ts +876 -0
- package/src/html/layout/boxes.ts +981 -0
- package/src/html/layout/flex.ts +297 -0
- package/src/html/layout/floats.ts +125 -0
- package/src/html/layout/inline.ts +870 -0
- package/src/html/layout/table.ts +380 -0
- package/src/html/node.ts +967 -0
- package/src/html/paint.ts +605 -0
- package/src/html/resources.ts +214 -0
- package/src/index.ts +638 -0
- package/src/internal/heights.ts +211 -0
- package/src/internal/hx.ts +53 -0
- package/src/internal/text.ts +44 -0
- package/src/internal/timers.ts +44 -0
- package/src/internal/widget.ts +92 -0
- package/src/markdown/ast.ts +163 -0
- package/src/markdown/hx.ts +51 -0
- package/src/markdown/index.ts +686 -0
- package/src/markdown/parse.ts +1037 -0
- package/src/markdown/spans.ts +143 -0
- package/src/media-player/backends.ts +155 -0
- package/src/media-player/control.ts +70 -0
- package/src/media-player/hx.ts +51 -0
- package/src/media-player/index.ts +378 -0
- package/src/media-player/mpv.ts +146 -0
- package/src/media-player/vlc.ts +97 -0
- package/src/richtext/index.ts +42 -0
- package/src/richtext/links.ts +78 -0
- package/src/richtext/menu.ts +49 -0
- package/src/richtext/node.ts +406 -0
- package/src/richtext/runs.ts +253 -0
- package/src/table/hx.ts +51 -0
- package/src/table/index.ts +1219 -0
- package/src/table/rows.ts +275 -0
- package/src/terminal/backends.ts +242 -0
- package/src/terminal/hx.ts +51 -0
- package/src/terminal/index.ts +574 -0
- package/src/terminal/title.ts +172 -0
- package/src/terminal/vt/colors.ts +247 -0
- package/src/terminal/vt/diff.ts +467 -0
- package/src/terminal/vt/fonts.ts +233 -0
- package/src/terminal/vt/index.ts +443 -0
- package/src/terminal/vt/keys.ts +369 -0
- package/src/terminal/vt/mouse.ts +144 -0
- package/src/terminal/vt/node.ts +1242 -0
- package/src/terminal/vt/pty.ts +334 -0
- package/src/terminal/vt/renderer.ts +555 -0
- package/src/terminal/vt/timers.ts +31 -0
- package/src/terminal/vt/xterm.ts +193 -0
- package/src/terminal-output/hx.ts +51 -0
- package/src/terminal-output/index.ts +340 -0
- package/src/terminal-output/runs.ts +79 -0
- package/src/three/canvas.ts +451 -0
- package/src/three/events.ts +197 -0
- package/src/three/geometries.ts +429 -0
- package/src/three/globals.ts +34 -0
- package/src/three/hx.ts +22 -0
- package/src/three/index.ts +98 -0
- package/src/three/jsx-dev-runtime.ts +27 -0
- package/src/three/jsx-runtime.ts +38 -0
- package/src/three/jsx.ts +275 -0
- package/src/three/materials.ts +270 -0
- package/src/three/math.ts +585 -0
- package/src/three/objects.ts +397 -0
- package/src/three/passes.ts +90 -0
- package/src/three/postprocess.ts +677 -0
- package/src/three/raycast.ts +189 -0
- package/src/three/react-reconciler.d.ts +50 -0
- package/src/three/reconciler.ts +624 -0
- package/src/three/renderer-direct.ts +1055 -0
- package/src/three/renderer-indirect.ts +570 -0
- package/src/three/store.ts +207 -0
- package/src/timeline/hx.ts +31 -0
- package/src/timeline/index.ts +603 -0
- package/src/tray-host/hx.ts +51 -0
- package/src/tray-host/index.ts +331 -0
- package/src/tray-host/manager.ts +639 -0
- package/src/tray-host/notify.ts +102 -0
- package/src/tray-host/protocol.ts +235 -0
- package/src/tree/hx.ts +51 -0
- package/src/tree/index.ts +1087 -0
- package/src/tree/internal.ts +87 -0
- package/src/tree/rows.ts +334 -0
- package/src/index.d.ts +0 -2
- package/src/index.js +0 -9
- package/src/sparkline/index.d.ts +0 -29
- package/src/sparkline/index.js +0 -50
- package/src/sparkline/node.js +0 -72
|
@@ -0,0 +1,932 @@
|
|
|
1
|
+
// The retained node behind `<chartplot>`: one paint pass for the grid, the
|
|
2
|
+
// axes and every series, the render-host caches (scatter grids, the density
|
|
3
|
+
// image surface), and the hit-test answers the tooltip layer asks through a
|
|
4
|
+
// ref.
|
|
5
|
+
//
|
|
6
|
+
// The perf-relevant structure, in one place:
|
|
7
|
+
//
|
|
8
|
+
// - **Nothing happens off-paint.** Pyramids, x indexes and stack tops are
|
|
9
|
+
// built by the first paint that needs them and extended incrementally;
|
|
10
|
+
// a `ChartData` append while this node is entirely outside its window's
|
|
11
|
+
// viewport does not even schedule a frame — scrolling back repaints
|
|
12
|
+
// from current data anyway.
|
|
13
|
+
// - **The scales are computed once per (geometry, data, spec, theme) and
|
|
14
|
+
// memoized**, so a hover asking `hitAt` between frames costs a lookup,
|
|
15
|
+
// not a re-derivation.
|
|
16
|
+
// - **Formatters and stats callbacks ride identity-stable props** (the
|
|
17
|
+
// component layer keeps one mutable object), so re-renders of the React
|
|
18
|
+
// tree above contribute no damage of their own. The hover overlays do
|
|
19
|
+
// overlap the plot, so their damage strips repaint this node — at its
|
|
20
|
+
// usual pixel-bounded cost, which is the actual guarantee: a hover
|
|
21
|
+
// frame is O(width) commands whatever the point count.
|
|
22
|
+
|
|
23
|
+
import { Node } from 'react-x11/node';
|
|
24
|
+
import type {
|
|
25
|
+
Context2D,
|
|
26
|
+
MeasureConstraints,
|
|
27
|
+
MeasuredSize,
|
|
28
|
+
} from 'react-x11/node';
|
|
29
|
+
import type { Style } from 'react-x11/style';
|
|
30
|
+
import { Surface } from 'react-x11/ntk';
|
|
31
|
+
|
|
32
|
+
import type {
|
|
33
|
+
ChartDataLike,
|
|
34
|
+
ChartSourceData,
|
|
35
|
+
NumericColumn,
|
|
36
|
+
ResolvedColumn,
|
|
37
|
+
} from './data.js';
|
|
38
|
+
import {
|
|
39
|
+
buildStackTops,
|
|
40
|
+
isChartDataLike,
|
|
41
|
+
minMaxRange,
|
|
42
|
+
nearestIndex,
|
|
43
|
+
numericColumn,
|
|
44
|
+
pyramidFor,
|
|
45
|
+
resolveColumn,
|
|
46
|
+
xIndexFor,
|
|
47
|
+
} from './data.js';
|
|
48
|
+
import type { BandScale, LinearScale } from './scale.js';
|
|
49
|
+
import {
|
|
50
|
+
bandScale,
|
|
51
|
+
formatNumberTick,
|
|
52
|
+
formatTimeTick,
|
|
53
|
+
linearScale,
|
|
54
|
+
linearTicks,
|
|
55
|
+
niceDomain,
|
|
56
|
+
timeTicks,
|
|
57
|
+
} from './scale.js';
|
|
58
|
+
import type { ChartFrameStats, PlotSpec, SeriesSpec } from './spec.js';
|
|
59
|
+
import { resolveThemeColor } from './spec.js';
|
|
60
|
+
import type {
|
|
61
|
+
FrameStatsSink,
|
|
62
|
+
PlotContext,
|
|
63
|
+
PlotRect,
|
|
64
|
+
RenderHost,
|
|
65
|
+
ScatterGrid,
|
|
66
|
+
SeriesGeometry,
|
|
67
|
+
} from './render.js';
|
|
68
|
+
import { canPath, makeScatterGrid, renderSeries } from './render.js';
|
|
69
|
+
import { microtask, now } from './timers.js';
|
|
70
|
+
|
|
71
|
+
/** The element name — registration key, node kind and JSX tag alike. */
|
|
72
|
+
export const ELEMENT = 'chartplot';
|
|
73
|
+
|
|
74
|
+
/** Formatter channel. The component layer keeps ONE mutable object per
|
|
75
|
+
* chart and updates its fields, so the prop's identity never changes and a
|
|
76
|
+
* formatter defined inline never damages the plot. */
|
|
77
|
+
export interface ChartFormatters {
|
|
78
|
+
x?: (value: number | string) => string;
|
|
79
|
+
y?: (value: number) => string;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface ChartPlotProps {
|
|
83
|
+
spec: PlotSpec;
|
|
84
|
+
data: ChartSourceData;
|
|
85
|
+
formatters?: ChartFormatters;
|
|
86
|
+
/** Reported once per painted frame, off the paint stack. */
|
|
87
|
+
onFrameStats?: (stats: ChartFrameStats) => void;
|
|
88
|
+
style?: Style | Style[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** What the tooltip layer gets for a pointer position. */
|
|
92
|
+
export interface ChartHit {
|
|
93
|
+
index: number;
|
|
94
|
+
/** The x value at that index — a label for band axes. */
|
|
95
|
+
xValue: number | string;
|
|
96
|
+
/** Snap position for the crosshair, window coordinates. */
|
|
97
|
+
px: number;
|
|
98
|
+
/** The x domain's width (0 for band axes) — what a time-axis tooltip
|
|
99
|
+
* sizes its default header format to, exactly as the ticks do. */
|
|
100
|
+
xSpan: number;
|
|
101
|
+
plot: PlotRect;
|
|
102
|
+
points: {
|
|
103
|
+
id: string;
|
|
104
|
+
label: string;
|
|
105
|
+
color: string;
|
|
106
|
+
value: number;
|
|
107
|
+
py: number;
|
|
108
|
+
}[];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export type NtkApp = ConstructorParameters<typeof Node>[2];
|
|
112
|
+
|
|
113
|
+
/** The slice of ntk's font service axis labels go through. Absent on the
|
|
114
|
+
* mock backend, and every use below treats that as "skip the text". */
|
|
115
|
+
interface FontsLike {
|
|
116
|
+
layout(
|
|
117
|
+
content: string,
|
|
118
|
+
style: Record<string, unknown>,
|
|
119
|
+
): {
|
|
120
|
+
width: number;
|
|
121
|
+
height: number;
|
|
122
|
+
draw(ctx: unknown, x: number, y: number): void;
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
interface SurfaceLike {
|
|
127
|
+
getContext(name: string): {
|
|
128
|
+
createImageData(
|
|
129
|
+
w: number,
|
|
130
|
+
h: number,
|
|
131
|
+
): {
|
|
132
|
+
width: number;
|
|
133
|
+
height: number;
|
|
134
|
+
data: Uint8ClampedArray;
|
|
135
|
+
};
|
|
136
|
+
putImageData(data: unknown, x: number, y: number): void;
|
|
137
|
+
destroy?(): void;
|
|
138
|
+
};
|
|
139
|
+
destroy(): void;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
type SurfaceCtor = new (
|
|
143
|
+
app: unknown,
|
|
144
|
+
options: { width: number; height: number },
|
|
145
|
+
) => SurfaceLike;
|
|
146
|
+
|
|
147
|
+
// `react-x11/ntk` types loosely on purpose; older ntk has no Surface at all
|
|
148
|
+
const SurfaceClass = (Surface ?? null) as unknown as SurfaceCtor | null;
|
|
149
|
+
|
|
150
|
+
const MIN_PAINT_PX = 8;
|
|
151
|
+
const PAD_TOP = 6;
|
|
152
|
+
const PAD_RIGHT = 8;
|
|
153
|
+
const TICK_GAP = 6;
|
|
154
|
+
const X_AXIS_HEIGHT = 22;
|
|
155
|
+
const LABEL_CACHE_MAX = 256;
|
|
156
|
+
|
|
157
|
+
interface AxisTick {
|
|
158
|
+
/** position in window px along the tick's axis */
|
|
159
|
+
px: number;
|
|
160
|
+
label: string;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Everything derived from (abs, data, spec, theme): scales, gutters,
|
|
164
|
+
* ticks, per-series geometry. One computation serves paint and hitAt. */
|
|
165
|
+
interface Layout {
|
|
166
|
+
key: string;
|
|
167
|
+
plot: PlotRect;
|
|
168
|
+
xScale: LinearScale | BandScale;
|
|
169
|
+
yScale: LinearScale;
|
|
170
|
+
xTicks: AxisTick[];
|
|
171
|
+
yTicks: AxisTick[];
|
|
172
|
+
geoms: SeriesGeometry[];
|
|
173
|
+
/** the x column (band labels / hit values), when there is one */
|
|
174
|
+
xCol: ResolvedColumn | null;
|
|
175
|
+
prepMs: number;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
interface StackEntry {
|
|
179
|
+
/** identity key of the member columns + their epochs */
|
|
180
|
+
epochKey: string;
|
|
181
|
+
builtN: number;
|
|
182
|
+
layers: Float64Array[];
|
|
183
|
+
/** stable pyramid-cache hosts, one per layer */
|
|
184
|
+
hosts: object[];
|
|
185
|
+
/** bumped on rebuild so wrapped columns invalidate their pyramids */
|
|
186
|
+
rebuilds: number;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
export class ChartPlotNode extends Node {
|
|
190
|
+
private _layoutCache: Layout | null = null;
|
|
191
|
+
private _labelLayouts = new Map<
|
|
192
|
+
string,
|
|
193
|
+
{
|
|
194
|
+
width: number;
|
|
195
|
+
height: number;
|
|
196
|
+
draw(ctx: unknown, x: number, y: number): void;
|
|
197
|
+
}
|
|
198
|
+
>();
|
|
199
|
+
private _scatterGrids = new Map<string, ScatterGrid>();
|
|
200
|
+
private _stacks = new Map<string, StackEntry>();
|
|
201
|
+
private _unsubscribe: (() => void) | null = null;
|
|
202
|
+
private _image: {
|
|
203
|
+
w: number;
|
|
204
|
+
h: number;
|
|
205
|
+
surface: SurfaceLike;
|
|
206
|
+
sctx: ReturnType<SurfaceLike['getContext']>;
|
|
207
|
+
data: { width: number; height: number; data: Uint8ClampedArray };
|
|
208
|
+
/** what the surface currently holds — a repaint with the same content
|
|
209
|
+
* (a crosshair moving over a dense scatter) is one composite, no
|
|
210
|
+
* refill and no re-upload */
|
|
211
|
+
contentKey: string;
|
|
212
|
+
} | null = null;
|
|
213
|
+
|
|
214
|
+
constructor(props: Record<string, unknown>, app: NtkApp) {
|
|
215
|
+
super(ELEMENT, props, app);
|
|
216
|
+
this.a11yRole = 'img';
|
|
217
|
+
this._subscribeData(props.data);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private _props(): Partial<ChartPlotProps> {
|
|
221
|
+
return this.props as unknown as Partial<ChartPlotProps>;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
override applyProps(
|
|
225
|
+
nextProps: Record<string, unknown>,
|
|
226
|
+
prevProps: Record<string, unknown>,
|
|
227
|
+
): void {
|
|
228
|
+
if (nextProps.data !== prevProps.data) {
|
|
229
|
+
this._subscribeData(nextProps.data);
|
|
230
|
+
}
|
|
231
|
+
super.applyProps(nextProps, prevProps);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private _subscribeData(data: unknown): void {
|
|
235
|
+
this._unsubscribe?.();
|
|
236
|
+
this._unsubscribe = null;
|
|
237
|
+
if (data && isChartDataLike(data as ChartSourceData)) {
|
|
238
|
+
this._unsubscribe = (data as ChartDataLike).subscribe(() => {
|
|
239
|
+
if (this.destroyed) return;
|
|
240
|
+
// A chart nobody can see skips even the invalidation: scrolling it
|
|
241
|
+
// back into view repaints from current data, so no frame is owed.
|
|
242
|
+
if (this._fullyOffscreen()) return;
|
|
243
|
+
this.invalidate(false, this, 'content');
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Entirely outside the owning window, by public geometry alone. Core
|
|
250
|
+
* culls the *paint* of offscreen nodes on its own; this is only about
|
|
251
|
+
* skipping the invalidation a streaming append would otherwise schedule.
|
|
252
|
+
* Conservative: any doubt answers "maybe visible".
|
|
253
|
+
*/
|
|
254
|
+
private _fullyOffscreen(): boolean {
|
|
255
|
+
const root = this.root;
|
|
256
|
+
if (!root || root === this) return true;
|
|
257
|
+
const win = root.abs;
|
|
258
|
+
const a = this.abs;
|
|
259
|
+
if (!win || !a || win.width <= 0) return false;
|
|
260
|
+
return (
|
|
261
|
+
a.x + a.width <= 0 ||
|
|
262
|
+
a.y + a.height <= 0 ||
|
|
263
|
+
a.x >= win.width ||
|
|
264
|
+
a.y >= win.height
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
override destroySubtree(): void {
|
|
269
|
+
this._unsubscribe?.();
|
|
270
|
+
this._unsubscribe = null;
|
|
271
|
+
this._image?.sctx.destroy?.();
|
|
272
|
+
this._image?.surface.destroy();
|
|
273
|
+
this._image = null;
|
|
274
|
+
super.destroySubtree();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/** A chart with no styled size still shows up usefully — the HTML canvas
|
|
278
|
+
* default, scaled a little. Flex sizing overrides it as usual. */
|
|
279
|
+
override measureContent(constraints: MeasureConstraints): MeasuredSize {
|
|
280
|
+
return {
|
|
281
|
+
width: Math.min(480, constraints.width),
|
|
282
|
+
height: Math.min(260, constraints.height),
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// --- data plumbing -------------------------------------------------------
|
|
287
|
+
|
|
288
|
+
private _dataVersion(spec: PlotSpec, data: ChartSourceData): string {
|
|
289
|
+
// cheap and exact: every column's (epoch, n) — appends and window
|
|
290
|
+
// shifts both land here, so the layout memo can key on it
|
|
291
|
+
const parts: string[] = [];
|
|
292
|
+
const seen = new Set<string>();
|
|
293
|
+
const push = (key: string | null) => {
|
|
294
|
+
if (!key || seen.has(key)) return;
|
|
295
|
+
seen.add(key);
|
|
296
|
+
const col = resolveColumn(data, key);
|
|
297
|
+
parts.push(col ? `${key}=${col.epoch}:${col.n}` : `${key}=∅`);
|
|
298
|
+
};
|
|
299
|
+
push(spec.x.key);
|
|
300
|
+
for (const s of spec.series) push(s.id);
|
|
301
|
+
return parts.join(',');
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/** Wrap a stack layer as a column with a stable cache host, so its
|
|
305
|
+
* pyramid survives the layer array being reallocated by growth. */
|
|
306
|
+
private _stackColumn(
|
|
307
|
+
entry: StackEntry,
|
|
308
|
+
layer: number,
|
|
309
|
+
n: number,
|
|
310
|
+
): NumericColumn {
|
|
311
|
+
return {
|
|
312
|
+
values: entry.layers[layer],
|
|
313
|
+
n,
|
|
314
|
+
host: entry.hosts[layer],
|
|
315
|
+
epoch: entry.rebuilds,
|
|
316
|
+
numeric: true,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Cumulative tops for a stack group, extended incrementally on append
|
|
322
|
+
* and rebuilt when membership or history changes.
|
|
323
|
+
*/
|
|
324
|
+
private _stackTops(
|
|
325
|
+
stackId: string,
|
|
326
|
+
members: { id: string; col: NumericColumn }[],
|
|
327
|
+
): StackEntry {
|
|
328
|
+
const epochKey = members.map((m) => `${m.id}:${m.col.epoch}`).join('|');
|
|
329
|
+
const n = members.reduce((min, m) => Math.min(min, m.col.n), Infinity);
|
|
330
|
+
let entry = this._stacks.get(stackId);
|
|
331
|
+
if (!entry || entry.epochKey !== epochKey) {
|
|
332
|
+
entry = {
|
|
333
|
+
epochKey,
|
|
334
|
+
builtN: 0,
|
|
335
|
+
layers: members.map(() => new Float64Array(0)),
|
|
336
|
+
hosts: members.map(() => ({})),
|
|
337
|
+
rebuilds: (entry?.rebuilds ?? 0) + 1,
|
|
338
|
+
};
|
|
339
|
+
this._stacks.set(stackId, entry);
|
|
340
|
+
}
|
|
341
|
+
if (entry.builtN < n) {
|
|
342
|
+
if (entry.builtN === 0) {
|
|
343
|
+
entry.layers = buildStackTops(
|
|
344
|
+
members.map((m) => m.col.values),
|
|
345
|
+
n,
|
|
346
|
+
);
|
|
347
|
+
} else {
|
|
348
|
+
for (let j = 0; j < members.length; j++) {
|
|
349
|
+
const old = entry.layers[j];
|
|
350
|
+
const next = new Float64Array(n);
|
|
351
|
+
next.set(old.subarray(0, entry.builtN));
|
|
352
|
+
entry.layers[j] = next;
|
|
353
|
+
}
|
|
354
|
+
for (let i = entry.builtN; i < n; i++) {
|
|
355
|
+
let below = 0;
|
|
356
|
+
for (let j = 0; j < members.length; j++) {
|
|
357
|
+
const v = members[j].col.values[i] as number;
|
|
358
|
+
below += Number.isNaN(v) ? 0 : v;
|
|
359
|
+
entry.layers[j][i] = below;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
entry.builtN = n;
|
|
364
|
+
}
|
|
365
|
+
return entry;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// --- layout --------------------------------------------------------------
|
|
369
|
+
|
|
370
|
+
private _themeRecord(): Record<string, unknown> | null {
|
|
371
|
+
return this.theme;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
private _color(token: string, fallback: string): string {
|
|
375
|
+
const v = resolveThemeColor(token, this._themeRecord());
|
|
376
|
+
return v === '#888888' && token.startsWith('$') ? fallback : v;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/** Measure one label through the font service, cached. Null without a
|
|
380
|
+
* font service (the mock backend) — callers fall back to fixed gutters. */
|
|
381
|
+
private _label(
|
|
382
|
+
text: string,
|
|
383
|
+
size: number,
|
|
384
|
+
color: string,
|
|
385
|
+
): {
|
|
386
|
+
width: number;
|
|
387
|
+
height: number;
|
|
388
|
+
draw(ctx: unknown, x: number, y: number): void;
|
|
389
|
+
} | null {
|
|
390
|
+
const key = `${size}|${color}|${text}`;
|
|
391
|
+
const hit = this._labelLayouts.get(key);
|
|
392
|
+
if (hit) return hit;
|
|
393
|
+
const fonts = (this.app as { fonts?: FontsLike } | null)?.fonts;
|
|
394
|
+
if (!fonts) return null;
|
|
395
|
+
const ts = this.resolvedTextStyle();
|
|
396
|
+
const layout = fonts.layout(text, {
|
|
397
|
+
family: ts.family,
|
|
398
|
+
size,
|
|
399
|
+
weight: ts.weight,
|
|
400
|
+
style: ts.style,
|
|
401
|
+
color,
|
|
402
|
+
});
|
|
403
|
+
if (this._labelLayouts.size >= LABEL_CACHE_MAX) this._labelLayouts.clear();
|
|
404
|
+
this._labelLayouts.set(key, layout);
|
|
405
|
+
return layout;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
private _layout(): Layout | null {
|
|
409
|
+
const { spec, data, formatters } = this._props();
|
|
410
|
+
if (!spec || !data) return null;
|
|
411
|
+
const box = this.contentBox();
|
|
412
|
+
if (box.width < MIN_PAINT_PX || box.height < MIN_PAINT_PX) return null;
|
|
413
|
+
|
|
414
|
+
const dataVersion = this._dataVersion(spec, data);
|
|
415
|
+
const key = [
|
|
416
|
+
box.x,
|
|
417
|
+
box.y,
|
|
418
|
+
box.width,
|
|
419
|
+
box.height,
|
|
420
|
+
dataVersion,
|
|
421
|
+
// spec is memoized by the component layer, so identity is enough —
|
|
422
|
+
// but it is an object, so it goes into the key by a WeakRef-free
|
|
423
|
+
// trick: the cache also stores the reference and compares it below
|
|
424
|
+
].join('|');
|
|
425
|
+
const cached = this._layoutCache;
|
|
426
|
+
if (
|
|
427
|
+
cached &&
|
|
428
|
+
cached.key === key &&
|
|
429
|
+
this._cachedSpec === spec &&
|
|
430
|
+
this._cachedTheme === this.theme
|
|
431
|
+
) {
|
|
432
|
+
return cached;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const t0 = now();
|
|
436
|
+
const theme = this._themeRecord();
|
|
437
|
+
const labelSize = Math.max(
|
|
438
|
+
9,
|
|
439
|
+
Math.round(this.resolvedTextStyle().size * 0.8),
|
|
440
|
+
);
|
|
441
|
+
const labelColor = this._color('$textMuted', '#777777');
|
|
442
|
+
|
|
443
|
+
// -- columns
|
|
444
|
+
const xCol = spec.x.key ? resolveColumn(data, spec.x.key) : null;
|
|
445
|
+
const xNum = numericColumn(xCol);
|
|
446
|
+
const xIdx = xNum ? xIndexFor(xNum) : null;
|
|
447
|
+
|
|
448
|
+
// series → raw columns (missing columns drop the series this frame)
|
|
449
|
+
const raw: { spec: SeriesSpec; col: NumericColumn }[] = [];
|
|
450
|
+
for (const s of spec.series) {
|
|
451
|
+
const col = numericColumn(resolveColumn(data, s.id));
|
|
452
|
+
if (col) raw.push({ spec: s, col });
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// -- x kind
|
|
456
|
+
const anyBar = raw.some((r) => r.spec.type === 'bar');
|
|
457
|
+
let xKind: 'band' | 'linear' | 'time';
|
|
458
|
+
if (spec.x.type === 'band') xKind = 'band';
|
|
459
|
+
else if (spec.x.type === 'time') xKind = 'time';
|
|
460
|
+
else if (spec.x.type === 'linear') xKind = 'linear';
|
|
461
|
+
else xKind = anyBar || (xCol !== null && !xCol.numeric) ? 'band' : 'linear';
|
|
462
|
+
|
|
463
|
+
// -- stacks: replace y with cumulative tops, base with the layer below
|
|
464
|
+
const stackGroups = new Map<string, { id: string; col: NumericColumn }[]>();
|
|
465
|
+
for (const r of raw) {
|
|
466
|
+
if (!r.spec.stackId || (r.spec.type !== 'bar' && r.spec.type !== 'area'))
|
|
467
|
+
continue;
|
|
468
|
+
const list = stackGroups.get(r.spec.stackId) ?? [];
|
|
469
|
+
list.push({ id: r.spec.id, col: r.col });
|
|
470
|
+
stackGroups.set(r.spec.stackId, list);
|
|
471
|
+
}
|
|
472
|
+
// bar slots: stacked bars share one, everything else gets its own
|
|
473
|
+
const barSlots: string[] = [];
|
|
474
|
+
for (const r of raw) {
|
|
475
|
+
if (r.spec.type !== 'bar') continue;
|
|
476
|
+
const slot = r.spec.stackId ?? r.spec.id;
|
|
477
|
+
if (!barSlots.includes(slot)) barSlots.push(slot);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const geoms: SeriesGeometry[] = [];
|
|
481
|
+
let yMin = Infinity;
|
|
482
|
+
let yMax = -Infinity;
|
|
483
|
+
const seenStackLayer = new Map<string, number>();
|
|
484
|
+
for (const r of raw) {
|
|
485
|
+
let y: NumericColumn = r.col;
|
|
486
|
+
let base: NumericColumn | number = 0;
|
|
487
|
+
const stacked =
|
|
488
|
+
r.spec.stackId && (r.spec.type === 'bar' || r.spec.type === 'area')
|
|
489
|
+
? stackGroups.get(r.spec.stackId)
|
|
490
|
+
: undefined;
|
|
491
|
+
if (stacked && stacked.length > 1) {
|
|
492
|
+
const entry = this._stackTops(r.spec.stackId!, stacked);
|
|
493
|
+
const layer = seenStackLayer.get(r.spec.stackId!) ?? 0;
|
|
494
|
+
seenStackLayer.set(r.spec.stackId!, layer + 1);
|
|
495
|
+
const n = entry.builtN;
|
|
496
|
+
y = this._stackColumn(entry, layer, n);
|
|
497
|
+
base = layer > 0 ? this._stackColumn(entry, layer - 1, n) : 0;
|
|
498
|
+
}
|
|
499
|
+
// y extent through the pyramid: O(1) after the first build, and the
|
|
500
|
+
// build is the prep dense paint needs anyway
|
|
501
|
+
if (y.n > 0) {
|
|
502
|
+
const pyr = pyramidFor(y);
|
|
503
|
+
const mm = { min: 0, max: 0 };
|
|
504
|
+
minMaxRange(pyr, y.values, 0, y.n, mm);
|
|
505
|
+
if (mm.min <= mm.max) {
|
|
506
|
+
if (mm.min < yMin) yMin = mm.min;
|
|
507
|
+
if (mm.max > yMax) yMax = mm.max;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
const grounded =
|
|
511
|
+
r.spec.type === 'bar' ||
|
|
512
|
+
(r.spec.type === 'area' && typeof base === 'number');
|
|
513
|
+
if (grounded) {
|
|
514
|
+
if (yMin > 0) yMin = 0;
|
|
515
|
+
if (yMax < 0) yMax = 0;
|
|
516
|
+
}
|
|
517
|
+
geoms.push({
|
|
518
|
+
spec: r.spec,
|
|
519
|
+
y,
|
|
520
|
+
base,
|
|
521
|
+
x: xKind === 'band' ? null : xNum,
|
|
522
|
+
xIdx: xKind === 'band' ? null : xIdx,
|
|
523
|
+
group: {
|
|
524
|
+
index: Math.max(0, barSlots.indexOf(r.spec.stackId ?? r.spec.id)),
|
|
525
|
+
count: Math.max(1, barSlots.length),
|
|
526
|
+
},
|
|
527
|
+
color: resolveThemeColor(r.spec.color, theme),
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// -- y domain and ticks
|
|
532
|
+
const [autoY0, autoY1] = niceDomain(yMin, yMax, spec.y.ticks);
|
|
533
|
+
const yD0 = spec.y.domain[0] === 'auto' ? autoY0 : spec.y.domain[0];
|
|
534
|
+
const yD1 = spec.y.domain[1] === 'auto' ? autoY1 : spec.y.domain[1];
|
|
535
|
+
const fmtY = formatters?.y ?? formatNumberTick;
|
|
536
|
+
const yTickValues = spec.y.hide ? [] : linearTicks(yD0, yD1, spec.y.ticks);
|
|
537
|
+
const yTickLabels = yTickValues.map((v) => fmtY(v));
|
|
538
|
+
|
|
539
|
+
// -- gutters (the y gutter measures its own labels; fixed on the mock)
|
|
540
|
+
let left = 0;
|
|
541
|
+
if (!spec.y.hide) {
|
|
542
|
+
if (spec.y.width !== 'auto') {
|
|
543
|
+
left = spec.y.width;
|
|
544
|
+
} else {
|
|
545
|
+
let max = 0;
|
|
546
|
+
for (const text of yTickLabels) {
|
|
547
|
+
const l = this._label(text, labelSize, labelColor);
|
|
548
|
+
if (!l) {
|
|
549
|
+
max = 34;
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
if (l.width > max) max = l.width;
|
|
553
|
+
}
|
|
554
|
+
left = Math.ceil(max) + TICK_GAP + 2;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
const bottom = spec.x.hide ? 0 : spec.x.height || X_AXIS_HEIGHT;
|
|
558
|
+
const plot: PlotRect = {
|
|
559
|
+
x: box.x + left,
|
|
560
|
+
y: box.y + PAD_TOP,
|
|
561
|
+
width: Math.max(1, box.width - left - PAD_RIGHT),
|
|
562
|
+
height: Math.max(1, box.height - PAD_TOP - bottom),
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
const yScale = linearScale(yD0, yD1, plot.y + plot.height, plot.y);
|
|
566
|
+
const yTicks: AxisTick[] = yTickValues.map((v, i) => ({
|
|
567
|
+
px: yScale.scale(v),
|
|
568
|
+
label: yTickLabels[i],
|
|
569
|
+
}));
|
|
570
|
+
|
|
571
|
+
// -- x scale and ticks
|
|
572
|
+
let xScale: LinearScale | BandScale;
|
|
573
|
+
let xTicks: AxisTick[] = [];
|
|
574
|
+
const fmtX = formatters?.x;
|
|
575
|
+
if (xKind === 'band') {
|
|
576
|
+
const n = xCol ? xCol.n : (geoms[0]?.y.n ?? 0);
|
|
577
|
+
xScale = bandScale(n, plot.x, plot.x + plot.width);
|
|
578
|
+
if (!spec.x.hide && n > 0) {
|
|
579
|
+
// at most `ticks` evenly-strided band labels
|
|
580
|
+
const step = Math.max(1, Math.ceil(n / Math.max(1, spec.x.ticks)));
|
|
581
|
+
for (let i = 0; i < n; i += step) {
|
|
582
|
+
const value = xCol ? xCol.values[i] : i;
|
|
583
|
+
const label = fmtX ? fmtX(value as number | string) : String(value);
|
|
584
|
+
xTicks.push({ px: xScale.center(i), label });
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
} else {
|
|
588
|
+
let d0: number;
|
|
589
|
+
let d1: number;
|
|
590
|
+
if (xNum && xIdx && xIdx.min <= xIdx.max) {
|
|
591
|
+
d0 = xIdx.min;
|
|
592
|
+
d1 = xIdx.max;
|
|
593
|
+
} else {
|
|
594
|
+
d0 = 0;
|
|
595
|
+
d1 = Math.max(1, (geoms[0]?.y.n ?? 1) - 1);
|
|
596
|
+
}
|
|
597
|
+
if (spec.x.domain[0] !== 'auto') d0 = spec.x.domain[0];
|
|
598
|
+
if (spec.x.domain[1] !== 'auto') d1 = spec.x.domain[1];
|
|
599
|
+
if (d0 === d1) [d0, d1] = niceDomain(d0, d1);
|
|
600
|
+
xScale = linearScale(d0, d1, plot.x, plot.x + plot.width);
|
|
601
|
+
if (!spec.x.hide) {
|
|
602
|
+
const values =
|
|
603
|
+
xKind === 'time'
|
|
604
|
+
? timeTicks(d0, d1, spec.x.ticks)
|
|
605
|
+
: linearTicks(d0, d1, spec.x.ticks);
|
|
606
|
+
const span = d1 - d0;
|
|
607
|
+
xTicks = values.map((v) => ({
|
|
608
|
+
px: xScale.scale(v),
|
|
609
|
+
label: fmtX
|
|
610
|
+
? fmtX(v)
|
|
611
|
+
: xKind === 'time'
|
|
612
|
+
? formatTimeTick(v, span)
|
|
613
|
+
: formatNumberTick(v),
|
|
614
|
+
}));
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
const layout: Layout = {
|
|
619
|
+
key,
|
|
620
|
+
plot,
|
|
621
|
+
xScale,
|
|
622
|
+
yScale,
|
|
623
|
+
xTicks,
|
|
624
|
+
yTicks,
|
|
625
|
+
geoms,
|
|
626
|
+
xCol,
|
|
627
|
+
prepMs: now() - t0,
|
|
628
|
+
};
|
|
629
|
+
this._layoutCache = layout;
|
|
630
|
+
this._cachedSpec = spec;
|
|
631
|
+
this._cachedTheme = this.theme;
|
|
632
|
+
return layout;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
private _cachedSpec: PlotSpec | undefined;
|
|
636
|
+
private _cachedTheme: Record<string, unknown> | null | undefined;
|
|
637
|
+
|
|
638
|
+
// --- render host ---------------------------------------------------------
|
|
639
|
+
|
|
640
|
+
private _host(): RenderHost {
|
|
641
|
+
return {
|
|
642
|
+
scatterGrid: (id, key, _n) => {
|
|
643
|
+
let grid = this._scatterGrids.get(id);
|
|
644
|
+
if (!grid || grid.key !== key) {
|
|
645
|
+
const [cell, gw, gh] = key.split('|');
|
|
646
|
+
grid = makeScatterGrid(key, Number(cell), Number(gw), Number(gh));
|
|
647
|
+
this._scatterGrids.set(id, grid);
|
|
648
|
+
}
|
|
649
|
+
return grid;
|
|
650
|
+
},
|
|
651
|
+
blitImage: (x, y, w, h, fill, contentKey) => {
|
|
652
|
+
const app = this.app as {
|
|
653
|
+
display?: { Render?: unknown };
|
|
654
|
+
} | null;
|
|
655
|
+
if (!SurfaceClass || !app?.display?.Render) return false;
|
|
656
|
+
const ctx = this._paintCtx;
|
|
657
|
+
if (!ctx || typeof ctx.drawImage !== 'function') return false;
|
|
658
|
+
try {
|
|
659
|
+
if (this._image && (this._image.w !== w || this._image.h !== h)) {
|
|
660
|
+
this._image.sctx.destroy?.();
|
|
661
|
+
this._image.surface.destroy();
|
|
662
|
+
this._image = null;
|
|
663
|
+
}
|
|
664
|
+
if (!this._image) {
|
|
665
|
+
const surface = new SurfaceClass(this.app, { width: w, height: h });
|
|
666
|
+
const sctx = surface.getContext('2d');
|
|
667
|
+
this._image = {
|
|
668
|
+
w,
|
|
669
|
+
h,
|
|
670
|
+
surface,
|
|
671
|
+
sctx,
|
|
672
|
+
data: sctx.createImageData(w, h),
|
|
673
|
+
contentKey: '',
|
|
674
|
+
};
|
|
675
|
+
}
|
|
676
|
+
const img = this._image;
|
|
677
|
+
// an unchanged content key means the retained surface already
|
|
678
|
+
// holds these pixels: a repaint (a crosshair crossing the plot)
|
|
679
|
+
// is one composite, not a megabyte re-upload
|
|
680
|
+
if (!contentKey || img.contentKey !== contentKey) {
|
|
681
|
+
img.data.data.fill(0);
|
|
682
|
+
fill(img.data.data);
|
|
683
|
+
img.sctx.putImageData(img.data, 0, 0);
|
|
684
|
+
img.contentKey = contentKey ?? '';
|
|
685
|
+
}
|
|
686
|
+
ctx.drawImage!(img.surface, x, y);
|
|
687
|
+
return true;
|
|
688
|
+
} catch {
|
|
689
|
+
// a server that refuses the pixmap: the rect path is still right
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
},
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
private _paintCtx: PlotContext | null = null;
|
|
697
|
+
|
|
698
|
+
// --- painting ------------------------------------------------------------
|
|
699
|
+
|
|
700
|
+
override paint(ctx: Context2D): void {
|
|
701
|
+
super.paint(ctx);
|
|
702
|
+
const t0 = now();
|
|
703
|
+
const layout = this._layout();
|
|
704
|
+
if (!layout) return;
|
|
705
|
+
const c = ctx as PlotContext;
|
|
706
|
+
if (typeof c.fillRect !== 'function') return;
|
|
707
|
+
this._paintCtx = c;
|
|
708
|
+
|
|
709
|
+
const stats: FrameStatsSink = {
|
|
710
|
+
pointsSpanned: 0,
|
|
711
|
+
commands: 0,
|
|
712
|
+
estimatedWireBytes: 0,
|
|
713
|
+
series: [],
|
|
714
|
+
};
|
|
715
|
+
const { spec } = this._props();
|
|
716
|
+
const { plot } = layout;
|
|
717
|
+
|
|
718
|
+
this._paintGridAndAxes(c, layout, stats);
|
|
719
|
+
|
|
720
|
+
// one rectangular clip around the series pass: server-side fast paths
|
|
721
|
+
// stay available, and sparse strokes cannot escape the plot
|
|
722
|
+
const clipped =
|
|
723
|
+
canPath(c) &&
|
|
724
|
+
typeof c.rect === 'function' &&
|
|
725
|
+
typeof c.clip === 'function';
|
|
726
|
+
if (clipped) {
|
|
727
|
+
c.save();
|
|
728
|
+
c.beginPath?.();
|
|
729
|
+
c.rect?.(plot.x, plot.y, plot.width, plot.height);
|
|
730
|
+
c.clip?.();
|
|
731
|
+
}
|
|
732
|
+
const env = {
|
|
733
|
+
ctx: c,
|
|
734
|
+
plot,
|
|
735
|
+
xScale: layout.xScale,
|
|
736
|
+
yScale: layout.yScale,
|
|
737
|
+
stats,
|
|
738
|
+
host: this._host(),
|
|
739
|
+
};
|
|
740
|
+
for (const geom of layout.geoms) renderSeries(env, geom);
|
|
741
|
+
if (clipped) c.restore();
|
|
742
|
+
this._paintCtx = null;
|
|
743
|
+
|
|
744
|
+
const onFrameStats = spec ? this._props().onFrameStats : undefined;
|
|
745
|
+
if (onFrameStats) {
|
|
746
|
+
const report: ChartFrameStats = {
|
|
747
|
+
prepMs: layout.prepMs,
|
|
748
|
+
paintMs: now() - t0,
|
|
749
|
+
pointsSpanned: stats.pointsSpanned,
|
|
750
|
+
commands: stats.commands,
|
|
751
|
+
estimatedWireBytes: stats.estimatedWireBytes,
|
|
752
|
+
series: stats.series,
|
|
753
|
+
};
|
|
754
|
+
microtask(() => {
|
|
755
|
+
if (!this.destroyed) onFrameStats(report);
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
private _paintGridAndAxes(
|
|
761
|
+
ctx: PlotContext,
|
|
762
|
+
layout: Layout,
|
|
763
|
+
stats: FrameStatsSink,
|
|
764
|
+
): void {
|
|
765
|
+
const { spec } = this._props();
|
|
766
|
+
if (!spec) return;
|
|
767
|
+
const { plot, xTicks, yTicks } = layout;
|
|
768
|
+
const lineColor = this._color('$border', '#cccccc');
|
|
769
|
+
const labelColor = this._color('$textMuted', '#777777');
|
|
770
|
+
const labelSize = Math.max(
|
|
771
|
+
9,
|
|
772
|
+
Math.round(this.resolvedTextStyle().size * 0.8),
|
|
773
|
+
);
|
|
774
|
+
|
|
775
|
+
// grid: 1px rules batched into one request per direction
|
|
776
|
+
if (spec.grid) {
|
|
777
|
+
const rects: number[] = [];
|
|
778
|
+
if (spec.grid.horizontal) {
|
|
779
|
+
for (const t of yTicks) {
|
|
780
|
+
const y = Math.round(t.px);
|
|
781
|
+
if (y > plot.y && y < plot.y + plot.height) {
|
|
782
|
+
rects.push(plot.x, y, plot.width, 1);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
if (spec.grid.vertical) {
|
|
787
|
+
for (const t of xTicks) {
|
|
788
|
+
const x = Math.round(t.px);
|
|
789
|
+
if (x > plot.x && x < plot.x + plot.width) {
|
|
790
|
+
rects.push(x, plot.y, 1, plot.height);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
if (rects.length) {
|
|
795
|
+
ctx.save();
|
|
796
|
+
ctx.fillStyle = lineColor;
|
|
797
|
+
if (ctx.globalAlpha !== undefined) ctx.globalAlpha = 0.45;
|
|
798
|
+
if (typeof ctx.fillRects === 'function') ctx.fillRects(rects);
|
|
799
|
+
else {
|
|
800
|
+
for (let i = 0; i + 3 < rects.length; i += 4) {
|
|
801
|
+
ctx.fillRect(rects[i], rects[i + 1], rects[i + 2], rects[i + 3]);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
ctx.restore();
|
|
805
|
+
stats.commands++;
|
|
806
|
+
stats.estimatedWireBytes += (rects.length / 4) * 8;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// axis lines
|
|
811
|
+
const axisRects: number[] = [];
|
|
812
|
+
if (!spec.x.hide) {
|
|
813
|
+
axisRects.push(plot.x, plot.y + plot.height, plot.width, 1);
|
|
814
|
+
}
|
|
815
|
+
if (!spec.y.hide) axisRects.push(plot.x - 1, plot.y, 1, plot.height + 1);
|
|
816
|
+
if (axisRects.length) {
|
|
817
|
+
ctx.save();
|
|
818
|
+
ctx.fillStyle = lineColor;
|
|
819
|
+
if (typeof ctx.fillRects === 'function') ctx.fillRects(axisRects);
|
|
820
|
+
else {
|
|
821
|
+
for (let i = 0; i + 3 < axisRects.length; i += 4) {
|
|
822
|
+
ctx.fillRect(
|
|
823
|
+
axisRects[i],
|
|
824
|
+
axisRects[i + 1],
|
|
825
|
+
axisRects[i + 2],
|
|
826
|
+
axisRects[i + 3],
|
|
827
|
+
);
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
ctx.restore();
|
|
831
|
+
stats.commands++;
|
|
832
|
+
stats.estimatedWireBytes += (axisRects.length / 4) * 8;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// labels: glyphs are cached server-side, layouts cached here
|
|
836
|
+
if (!spec.y.hide) {
|
|
837
|
+
for (const t of yTicks) {
|
|
838
|
+
const l = this._label(t.label, labelSize, labelColor);
|
|
839
|
+
if (!l) continue;
|
|
840
|
+
l.draw(ctx, plot.x - TICK_GAP - l.width, t.px - l.height / 2);
|
|
841
|
+
stats.commands++;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
if (!spec.x.hide) {
|
|
845
|
+
const baseY = plot.y + plot.height + 4;
|
|
846
|
+
let lastRight = -Infinity;
|
|
847
|
+
for (const t of xTicks) {
|
|
848
|
+
const l = this._label(t.label, labelSize, labelColor);
|
|
849
|
+
if (!l) continue;
|
|
850
|
+
const x = t.px - l.width / 2;
|
|
851
|
+
// drop labels that would collide rather than letting them smear
|
|
852
|
+
if (x < lastRight + 4) continue;
|
|
853
|
+
lastRight = x + l.width;
|
|
854
|
+
l.draw(ctx, x, baseY);
|
|
855
|
+
stats.commands++;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// --- the tooltip's questions --------------------------------------------
|
|
861
|
+
|
|
862
|
+
/** The plot rectangle in window coordinates, for overlay positioning. */
|
|
863
|
+
plotRect(): PlotRect | null {
|
|
864
|
+
return this._layout()?.plot ?? null;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* What is under a window-coordinate pointer x: the snapped index, its x
|
|
869
|
+
* value, and every series' value and pixel position there. Null outside
|
|
870
|
+
* the data or before layout. O(log n) against sorted data.
|
|
871
|
+
*/
|
|
872
|
+
hitAt(winX: number): ChartHit | null {
|
|
873
|
+
const layout = this._layout();
|
|
874
|
+
const { spec } = this._props();
|
|
875
|
+
if (!layout || !spec || layout.geoms.length === 0) return null;
|
|
876
|
+
const { plot, xScale, yScale } = layout;
|
|
877
|
+
const clamped = Math.max(plot.x, Math.min(plot.x + plot.width, winX));
|
|
878
|
+
|
|
879
|
+
let index: number;
|
|
880
|
+
let px: number;
|
|
881
|
+
let xValue: number | string;
|
|
882
|
+
if (xScale.kind === 'band') {
|
|
883
|
+
index = xScale.indexAt(clamped);
|
|
884
|
+
if (index < 0) return null;
|
|
885
|
+
px = xScale.center(index);
|
|
886
|
+
xValue = layout.xCol
|
|
887
|
+
? (layout.xCol.values[index] as number | string)
|
|
888
|
+
: index;
|
|
889
|
+
} else {
|
|
890
|
+
const xv = xScale.invert(clamped);
|
|
891
|
+
const g0 = layout.geoms[0];
|
|
892
|
+
if (g0.x && g0.xIdx) {
|
|
893
|
+
index = nearestIndex(
|
|
894
|
+
g0.xIdx,
|
|
895
|
+
g0.x.values,
|
|
896
|
+
Math.min(g0.x.n, g0.y.n),
|
|
897
|
+
xv,
|
|
898
|
+
);
|
|
899
|
+
if (index < 0) return null;
|
|
900
|
+
xValue = g0.x.values[index] as number;
|
|
901
|
+
px = xScale.scale(xValue);
|
|
902
|
+
} else {
|
|
903
|
+
index = Math.max(0, Math.min(g0.y.n - 1, Math.round(xv)));
|
|
904
|
+
xValue = index;
|
|
905
|
+
px = xScale.scale(index);
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
const points: ChartHit['points'] = [];
|
|
910
|
+
for (const geom of layout.geoms) {
|
|
911
|
+
// the tooltip reports the raw series value, not the stack top
|
|
912
|
+
const rawCol = numericColumn(
|
|
913
|
+
resolveColumn(this._props().data as ChartSourceData, geom.spec.id),
|
|
914
|
+
);
|
|
915
|
+
if (!rawCol || index >= rawCol.n) continue;
|
|
916
|
+
const value = rawCol.values[index] as number;
|
|
917
|
+
if (Number.isNaN(value)) continue;
|
|
918
|
+
// the marker sits on what is painted — the stack top for stacked series
|
|
919
|
+
const painted = geom.y.values[index] as number;
|
|
920
|
+
points.push({
|
|
921
|
+
id: geom.spec.id,
|
|
922
|
+
label: geom.spec.label,
|
|
923
|
+
color: geom.color,
|
|
924
|
+
value,
|
|
925
|
+
py: yScale.scale(Number.isNaN(painted) ? value : painted),
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
if (points.length === 0) return null;
|
|
929
|
+
const xSpan = xScale.kind === 'band' ? 0 : xScale.d1 - xScale.d0;
|
|
930
|
+
return { index, xValue, px, xSpan, plot, points };
|
|
931
|
+
}
|
|
932
|
+
}
|