@react-x11/components 0.1.0 → 0.2.1
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 +88 -0
- package/dist/internal/heights.d.ts.map +1 -0
- package/dist/internal/heights.js +203 -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/scroll.d.ts +62 -0
- package/dist/internal/scroll.d.ts.map +1 -0
- package/dist/internal/scroll.js +224 -0
- package/dist/internal/scroll.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 +890 -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 +751 -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 +222 -0
- package/src/internal/hx.ts +53 -0
- package/src/internal/scroll.ts +288 -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 +1270 -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 +1127 -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,982 @@
|
|
|
1
|
+
// The series renderers: data columns → drawing commands, with the mode
|
|
2
|
+
// decision that keeps every frame bounded by pixels.
|
|
3
|
+
//
|
|
4
|
+
// Two rules govern everything here:
|
|
5
|
+
//
|
|
6
|
+
// 1. **Cost scales with pixels, never with points.** Below DENSE_PPX points
|
|
7
|
+
// per pixel a series draws as a real stroked path (antialiased, curved,
|
|
8
|
+
// dotted); above it, each pixel column collapses to its min/max span
|
|
9
|
+
// through the pyramid and the whole series goes out as one `fillRects`
|
|
10
|
+
// batch. A million points in a 40px cell cost ~40 rectangles.
|
|
11
|
+
//
|
|
12
|
+
// 2. **Server-side commands by default, pixels when they win.** The command
|
|
13
|
+
// stream is bounded by the width (rule 1), so it is almost always far
|
|
14
|
+
// smaller than pushing the plot as an image. The one exception is a
|
|
15
|
+
// scatter so dense it covers most of the plot — rectangles then cost
|
|
16
|
+
// more bytes than the pixels do (8/cell vs 4/px), and the renderer
|
|
17
|
+
// flips to compositing a density image. The crossover is computed from
|
|
18
|
+
// those two numbers, not guessed.
|
|
19
|
+
//
|
|
20
|
+
// The renderers draw through a structural slice of ntk's context and take
|
|
21
|
+
// their caches through `RenderHost`, so they run identically against the
|
|
22
|
+
// real server, the recording mock, and the plain fakes in the tests.
|
|
23
|
+
|
|
24
|
+
import type { NumericColumn, MinMax, XIndex } from './data.js';
|
|
25
|
+
import {
|
|
26
|
+
lowerBound,
|
|
27
|
+
minMaxRange,
|
|
28
|
+
pyramidFor,
|
|
29
|
+
visibleIndexRange,
|
|
30
|
+
xIndexFor,
|
|
31
|
+
} from './data.js';
|
|
32
|
+
import type { BandScale, LinearScale } from './scale.js';
|
|
33
|
+
import type { ChartFrameStats, SeriesSpec } from './spec.js';
|
|
34
|
+
|
|
35
|
+
/** points per pixel above which a line/area stops stroking real segments
|
|
36
|
+
* and collapses to per-column spans */
|
|
37
|
+
export const DENSE_PPX = 2;
|
|
38
|
+
/** most points a sparse pass will ever stroke (DENSE_PPX × a wide plot) */
|
|
39
|
+
export const ROUND_JOIN_MAX = 256;
|
|
40
|
+
/** dots/points drawn as real circles; batched squares above, nothing once
|
|
41
|
+
* the grid takes over */
|
|
42
|
+
export const CIRCLE_MAX = 96;
|
|
43
|
+
export const DIRECT_SCATTER_MAX = 512;
|
|
44
|
+
/** bars that may keep their rounded tops — past this they go square into
|
|
45
|
+
* one batch */
|
|
46
|
+
export const BAR_RADIUS_MAX = 256;
|
|
47
|
+
|
|
48
|
+
export interface PlotRect {
|
|
49
|
+
x: number;
|
|
50
|
+
y: number;
|
|
51
|
+
width: number;
|
|
52
|
+
height: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The slice of ntk's 2d context the renderers need. Everything optional is
|
|
56
|
+
* feature-tested: the mock backend has most of it, the plain test fakes
|
|
57
|
+
* less, and a missing method degrades the drawing rather than throwing. */
|
|
58
|
+
export interface PlotContext {
|
|
59
|
+
fillStyle: unknown;
|
|
60
|
+
strokeStyle: unknown;
|
|
61
|
+
lineWidth: number;
|
|
62
|
+
globalAlpha?: number;
|
|
63
|
+
lineJoin?: string;
|
|
64
|
+
lineCap?: string;
|
|
65
|
+
save(): void;
|
|
66
|
+
restore(): void;
|
|
67
|
+
fillRect(x: number, y: number, w: number, h: number): void;
|
|
68
|
+
fillRects?(rects: number[]): void;
|
|
69
|
+
beginPath?(): void;
|
|
70
|
+
moveTo?(x: number, y: number): void;
|
|
71
|
+
lineTo?(x: number, y: number): void;
|
|
72
|
+
bezierCurveTo?(
|
|
73
|
+
x1: number,
|
|
74
|
+
y1: number,
|
|
75
|
+
x2: number,
|
|
76
|
+
y2: number,
|
|
77
|
+
x: number,
|
|
78
|
+
y: number,
|
|
79
|
+
): void;
|
|
80
|
+
arc?(x: number, y: number, r: number, a0: number, a1: number): void;
|
|
81
|
+
closePath?(): void;
|
|
82
|
+
stroke?(): void;
|
|
83
|
+
fill?(): void;
|
|
84
|
+
rect?(x: number, y: number, w: number, h: number): void;
|
|
85
|
+
clip?(): void;
|
|
86
|
+
drawImage?(image: unknown, dx: number, dy: number): void;
|
|
87
|
+
roundRect?(
|
|
88
|
+
x: number,
|
|
89
|
+
y: number,
|
|
90
|
+
w: number,
|
|
91
|
+
h: number,
|
|
92
|
+
radii: number | number[],
|
|
93
|
+
): void;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const canPath = (
|
|
97
|
+
ctx: PlotContext,
|
|
98
|
+
): ctx is PlotContext &
|
|
99
|
+
Required<Pick<PlotContext, 'beginPath' | 'moveTo' | 'lineTo'>> =>
|
|
100
|
+
typeof ctx.beginPath === 'function' &&
|
|
101
|
+
typeof ctx.moveTo === 'function' &&
|
|
102
|
+
typeof ctx.lineTo === 'function';
|
|
103
|
+
|
|
104
|
+
/** One batched fill for many rectangles, or the loop where the context has
|
|
105
|
+
* no batch — same pixels, more requests, which is the mock's documented
|
|
106
|
+
* contract too. */
|
|
107
|
+
function fillRects(ctx: PlotContext, rects: number[]): void {
|
|
108
|
+
if (typeof ctx.fillRects === 'function') {
|
|
109
|
+
ctx.fillRects(rects);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
for (let i = 0; i + 3 < rects.length; i += 4) {
|
|
113
|
+
ctx.fillRect(rects[i], rects[i + 1], rects[i + 2], rects[i + 3]);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Mutable accumulator behind `ChartFrameStats`. */
|
|
118
|
+
export interface FrameStatsSink {
|
|
119
|
+
pointsSpanned: number;
|
|
120
|
+
commands: number;
|
|
121
|
+
estimatedWireBytes: number;
|
|
122
|
+
series: ChartFrameStats['series'];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Estimated wire bytes per primitive — the numbers the mode policy
|
|
126
|
+
* compares. A rectangle is 8 bytes in a FillRectangles; a stroked segment
|
|
127
|
+
* extrudes to two triangles at 24 bytes each; an image pixel is 4. */
|
|
128
|
+
export const BYTES_PER_RECT = 8;
|
|
129
|
+
export const BYTES_PER_SEGMENT = 48;
|
|
130
|
+
export const BYTES_PER_PIXEL = 4;
|
|
131
|
+
|
|
132
|
+
// --- per-series input ------------------------------------------------------
|
|
133
|
+
|
|
134
|
+
/** A series' resolved geometry inputs, prepared by the node. */
|
|
135
|
+
export interface SeriesGeometry {
|
|
136
|
+
spec: SeriesSpec;
|
|
137
|
+
/** y values (or the stack top for this layer). */
|
|
138
|
+
y: NumericColumn;
|
|
139
|
+
/** The stack base: the layer below's tops, or a constant domain value. */
|
|
140
|
+
base: NumericColumn | number;
|
|
141
|
+
/** x column; null means "the index is the x value". */
|
|
142
|
+
x: NumericColumn | null;
|
|
143
|
+
/** Index metadata for x when there is a column. */
|
|
144
|
+
xIdx: XIndex | null;
|
|
145
|
+
/** Bars: which slot of how many this series takes within a band. */
|
|
146
|
+
group: { index: number; count: number };
|
|
147
|
+
/** Paint-ready colour (theme tokens already resolved). */
|
|
148
|
+
color: string;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export interface SeriesEnv {
|
|
152
|
+
ctx: PlotContext;
|
|
153
|
+
plot: PlotRect;
|
|
154
|
+
xScale: LinearScale | BandScale;
|
|
155
|
+
yScale: LinearScale;
|
|
156
|
+
stats: FrameStatsSink;
|
|
157
|
+
host: RenderHost;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Caches and capabilities only the retained node can provide. */
|
|
161
|
+
export interface RenderHost {
|
|
162
|
+
/** Per-series scatter occupancy grid, cached across frames. */
|
|
163
|
+
scatterGrid(id: string, key: string, n: number): ScatterGrid;
|
|
164
|
+
/**
|
|
165
|
+
* Composite a straight-RGBA image over the plot, preserving what is
|
|
166
|
+
* already painted underneath. False when this backend cannot (no
|
|
167
|
+
* XRender surface — the mock), in which case the caller uses rects.
|
|
168
|
+
* `contentKey` names what `fill` would produce: an unchanged key lets
|
|
169
|
+
* the host re-composite its retained surface without refilling or
|
|
170
|
+
* re-uploading a pixel.
|
|
171
|
+
*/
|
|
172
|
+
blitImage(
|
|
173
|
+
x: number,
|
|
174
|
+
y: number,
|
|
175
|
+
w: number,
|
|
176
|
+
h: number,
|
|
177
|
+
fill: (data: Uint8ClampedArray) => void,
|
|
178
|
+
contentKey?: string,
|
|
179
|
+
): boolean;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// --- helpers ---------------------------------------------------------------
|
|
183
|
+
|
|
184
|
+
const mm: MinMax = { min: 0, max: 0 };
|
|
185
|
+
|
|
186
|
+
function xValueAt(g: SeriesGeometry, i: number): number {
|
|
187
|
+
return g.x ? (g.x.values[i] as number) : i;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Pixel x for a data index — linear x maps the value, band x maps the
|
|
191
|
+
* index to its band center (a line over categories walks the centers). */
|
|
192
|
+
function pxAt(env: SeriesEnv, g: SeriesGeometry, i: number): number {
|
|
193
|
+
return env.xScale.kind === 'band'
|
|
194
|
+
? env.xScale.center(i)
|
|
195
|
+
: env.xScale.scale(xValueAt(g, i));
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** The visible index window for this series under the current x domain. */
|
|
199
|
+
export function visibleRange(
|
|
200
|
+
env: SeriesEnv,
|
|
201
|
+
g: SeriesGeometry,
|
|
202
|
+
): [number, number] {
|
|
203
|
+
const n = g.y.n;
|
|
204
|
+
if (env.xScale.kind === 'band') return [0, n];
|
|
205
|
+
if (!g.x || !g.xIdx) {
|
|
206
|
+
const i0 = Math.max(0, Math.floor(env.xScale.d0) - 1);
|
|
207
|
+
const i1 = Math.min(n, Math.ceil(env.xScale.d1) + 2);
|
|
208
|
+
return [i0, Math.max(i0, i1)];
|
|
209
|
+
}
|
|
210
|
+
return visibleIndexRange(
|
|
211
|
+
g.xIdx,
|
|
212
|
+
g.x.values,
|
|
213
|
+
Math.min(n, g.x.n),
|
|
214
|
+
env.xScale.d0,
|
|
215
|
+
env.xScale.d1,
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/** Last finite y at or before `i1-1`, looking back a bounded distance —
|
|
220
|
+
* the M4 "close" value that bridges adjacent columns. */
|
|
221
|
+
function lastFinite(values: ArrayLike<number>, i0: number, i1: number): number {
|
|
222
|
+
const stop = Math.max(i0, i1 - 16);
|
|
223
|
+
for (let i = i1 - 1; i >= stop; i--) {
|
|
224
|
+
const v = values[i];
|
|
225
|
+
if (!Number.isNaN(v)) return v;
|
|
226
|
+
}
|
|
227
|
+
return NaN;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Walk the pixel columns of the visible range, handing each column its
|
|
232
|
+
* exact index window. Uniform x advances arithmetically; sorted x binary
|
|
233
|
+
* searches each boundary (O(width · log n), bounded); the band case is
|
|
234
|
+
* plain proportional slicing. `cb` returns nothing; gaps come through as
|
|
235
|
+
* empty windows.
|
|
236
|
+
*/
|
|
237
|
+
function walkColumns(
|
|
238
|
+
env: SeriesEnv,
|
|
239
|
+
g: SeriesGeometry,
|
|
240
|
+
i0: number,
|
|
241
|
+
i1: number,
|
|
242
|
+
cb: (colPx: number, ia: number, ib: number) => void,
|
|
243
|
+
): void {
|
|
244
|
+
const { plot } = env;
|
|
245
|
+
const cols = Math.max(1, Math.round(plot.width));
|
|
246
|
+
if (env.xScale.kind === 'band' || !g.x || !g.xIdx || !g.xIdx.sorted) {
|
|
247
|
+
// proportional index slicing: exact for bands, and the honest bounded
|
|
248
|
+
// fallback for unsorted x (index order is all there is to draw)
|
|
249
|
+
const span = i1 - i0;
|
|
250
|
+
let prev = i0;
|
|
251
|
+
for (let c = 0; c < cols; c++) {
|
|
252
|
+
const ib = c + 1 >= cols ? i1 : i0 + Math.floor((span * (c + 1)) / cols);
|
|
253
|
+
cb(plot.x + c, prev, ib);
|
|
254
|
+
prev = ib;
|
|
255
|
+
}
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const xs = g.x.values;
|
|
259
|
+
const n = Math.min(g.y.n, g.x.n);
|
|
260
|
+
const idx = g.xIdx;
|
|
261
|
+
const scale = env.xScale as LinearScale;
|
|
262
|
+
const uniform = idx.uniform && idx.dx > 0;
|
|
263
|
+
let prev = i0;
|
|
264
|
+
for (let c = 0; c < cols; c++) {
|
|
265
|
+
let ib: number;
|
|
266
|
+
if (c + 1 >= cols) {
|
|
267
|
+
ib = i1;
|
|
268
|
+
} else {
|
|
269
|
+
const xRight = scale.invert(plot.x + c + 1);
|
|
270
|
+
ib = uniform
|
|
271
|
+
? Math.ceil((xRight - idx.x0) / idx.dx)
|
|
272
|
+
: lowerBound(xs, n, xRight);
|
|
273
|
+
if (ib < prev) ib = prev;
|
|
274
|
+
if (ib > i1) ib = i1;
|
|
275
|
+
}
|
|
276
|
+
cb(plot.x + c, prev, ib);
|
|
277
|
+
prev = ib;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// --- monotone curve --------------------------------------------------------
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Fritsch–Carlson monotone cubic tangents — the `curve="monotone"`
|
|
285
|
+
* recharts draws, so a smoothed series never overshoots its own points.
|
|
286
|
+
*/
|
|
287
|
+
function monotoneTangents(xs: number[], ys: number[]): number[] {
|
|
288
|
+
const m = xs.length;
|
|
289
|
+
const t = new Array<number>(m);
|
|
290
|
+
if (m < 2) return t.fill(0);
|
|
291
|
+
const s: number[] = [];
|
|
292
|
+
for (let i = 0; i < m - 1; i++) {
|
|
293
|
+
const h = xs[i + 1] - xs[i];
|
|
294
|
+
s.push(h === 0 ? 0 : (ys[i + 1] - ys[i]) / h);
|
|
295
|
+
}
|
|
296
|
+
t[0] = s[0];
|
|
297
|
+
t[m - 1] = s[m - 2];
|
|
298
|
+
for (let i = 1; i < m - 1; i++) {
|
|
299
|
+
t[i] = s[i - 1] * s[i] <= 0 ? 0 : (s[i - 1] + s[i]) / 2;
|
|
300
|
+
}
|
|
301
|
+
for (let i = 0; i < m - 1; i++) {
|
|
302
|
+
if (s[i] === 0) {
|
|
303
|
+
t[i] = 0;
|
|
304
|
+
t[i + 1] = 0;
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
const a = t[i] / s[i];
|
|
308
|
+
const b = t[i + 1] / s[i];
|
|
309
|
+
const len = a * a + b * b;
|
|
310
|
+
if (len > 9) {
|
|
311
|
+
const scale = 3 / Math.sqrt(len);
|
|
312
|
+
t[i] = scale * a * s[i];
|
|
313
|
+
t[i + 1] = scale * b * s[i];
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return t;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/** Emit one already-collected run of points into the current path. */
|
|
320
|
+
function emitRun(
|
|
321
|
+
ctx: PlotContext,
|
|
322
|
+
xs: number[],
|
|
323
|
+
ys: number[],
|
|
324
|
+
curve: SeriesSpec['curve'],
|
|
325
|
+
move: boolean,
|
|
326
|
+
): void {
|
|
327
|
+
const m = xs.length;
|
|
328
|
+
if (m === 0) return;
|
|
329
|
+
if (move) ctx.moveTo!(xs[0], ys[0]);
|
|
330
|
+
else ctx.lineTo!(xs[0], ys[0]);
|
|
331
|
+
if (curve === 'monotone' && m > 2 && ctx.bezierCurveTo) {
|
|
332
|
+
const t = monotoneTangents(xs, ys);
|
|
333
|
+
for (let i = 0; i < m - 1; i++) {
|
|
334
|
+
const h = (xs[i + 1] - xs[i]) / 3;
|
|
335
|
+
ctx.bezierCurveTo(
|
|
336
|
+
xs[i] + h,
|
|
337
|
+
ys[i] + t[i] * h,
|
|
338
|
+
xs[i + 1] - h,
|
|
339
|
+
ys[i + 1] - t[i + 1] * h,
|
|
340
|
+
xs[i + 1],
|
|
341
|
+
ys[i + 1],
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (curve === 'step') {
|
|
347
|
+
for (let i = 1; i < m; i++) {
|
|
348
|
+
ctx.lineTo!(xs[i], ys[i - 1]);
|
|
349
|
+
ctx.lineTo!(xs[i], ys[i]);
|
|
350
|
+
}
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
for (let i = 1; i < m; i++) ctx.lineTo!(xs[i], ys[i]);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// --- line / area -----------------------------------------------------------
|
|
357
|
+
|
|
358
|
+
/** Clamp a pixel span to the plot; null when it misses entirely. */
|
|
359
|
+
function clampSpan(
|
|
360
|
+
plot: PlotRect,
|
|
361
|
+
top: number,
|
|
362
|
+
bottom: number,
|
|
363
|
+
): [number, number] | null {
|
|
364
|
+
const y0 = Math.max(plot.y, top);
|
|
365
|
+
const y1 = Math.min(plot.y + plot.height, bottom);
|
|
366
|
+
if (y1 <= y0 - 0.5) return null;
|
|
367
|
+
return [y0, Math.max(y1, y0 + 1)];
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
function baseValueAt(g: SeriesGeometry, i: number): number {
|
|
371
|
+
return typeof g.base === 'number' ? g.base : (g.base.values[i] as number);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* A line or area series. Sparse: a stroked (and for areas, filled) path
|
|
376
|
+
* through the real points. Dense: per-column min/max spans bridged with the
|
|
377
|
+
* previous column's closing value, batched into one request — the M4
|
|
378
|
+
* rendering, which is pixel-identical to drawing every point.
|
|
379
|
+
*/
|
|
380
|
+
export function renderLineArea(env: SeriesEnv, g: SeriesGeometry): void {
|
|
381
|
+
const { ctx, plot, yScale, stats } = env;
|
|
382
|
+
const [i0, i1] = visibleRange(env, g);
|
|
383
|
+
const count = Math.max(0, i1 - i0);
|
|
384
|
+
stats.pointsSpanned += count;
|
|
385
|
+
const isArea = g.spec.type === 'area';
|
|
386
|
+
if (count < 2) {
|
|
387
|
+
stats.series.push({ id: g.spec.id, mode: 'skipped', points: count });
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const density = count / Math.max(1, plot.width);
|
|
392
|
+
if (density <= DENSE_PPX && canPath(ctx) && ctx.stroke) {
|
|
393
|
+
// ---- sparse: real geometry. Runs split at NaN, each carrying its own
|
|
394
|
+
// base edge so an area's return path is collected in the same walk.
|
|
395
|
+
//
|
|
396
|
+
// Points sharing (nearly) one pixel column collapse to a single
|
|
397
|
+
// ordered vertical pair — the same envelope the dense branch draws, so
|
|
398
|
+
// the two modes agree at their boundary, and a burst-heavy stream (a
|
|
399
|
+
// few samples per timestamp) strokes a third of the points for
|
|
400
|
+
// identical pixels. History worth keeping: this collapse began as a
|
|
401
|
+
// correctness workaround — ntk's stroke extruder emitted NaN join
|
|
402
|
+
// geometry on same-x sub-pixel hairpins (ntk#259; invisible on the
|
|
403
|
+
// headless server, origin-wedges on a real one), fixed in ntk 7.6.1
|
|
404
|
+
// (ntk#260, pinned via core ceb9da5) — and it still keeps any older
|
|
405
|
+
// extruder in an app's tree out of that input by construction.
|
|
406
|
+
const runsX: number[][] = [];
|
|
407
|
+
const runsY: number[][] = [];
|
|
408
|
+
const runsB: number[][] = [];
|
|
409
|
+
let xs: number[] = [];
|
|
410
|
+
let ys: number[] = [];
|
|
411
|
+
let bs: number[] = [];
|
|
412
|
+
const yv = g.y.values;
|
|
413
|
+
const flush = () => {
|
|
414
|
+
if (xs.length) {
|
|
415
|
+
runsX.push(xs);
|
|
416
|
+
runsY.push(ys);
|
|
417
|
+
runsB.push(bs);
|
|
418
|
+
xs = [];
|
|
419
|
+
ys = [];
|
|
420
|
+
bs = [];
|
|
421
|
+
}
|
|
422
|
+
};
|
|
423
|
+
// one pending pixel column: px, first/min/max y, the area base
|
|
424
|
+
const COL_EPS = 0.5;
|
|
425
|
+
let colPx = NaN;
|
|
426
|
+
let colFirst = 0;
|
|
427
|
+
let colMin = 0;
|
|
428
|
+
let colMax = 0;
|
|
429
|
+
let colBase = 0;
|
|
430
|
+
let colCount = 0;
|
|
431
|
+
const emitColumn = () => {
|
|
432
|
+
if (colCount === 0) return;
|
|
433
|
+
if (colCount === 1) {
|
|
434
|
+
xs.push(colPx);
|
|
435
|
+
ys.push(colFirst);
|
|
436
|
+
if (isArea) bs.push(colBase);
|
|
437
|
+
} else {
|
|
438
|
+
// enter at the extreme nearer the first sample, leave at the other:
|
|
439
|
+
// one vertical segment, no reversal inside the column
|
|
440
|
+
const enterMin =
|
|
441
|
+
Math.abs(colFirst - colMin) <= Math.abs(colFirst - colMax);
|
|
442
|
+
xs.push(colPx, colPx);
|
|
443
|
+
ys.push(enterMin ? colMin : colMax, enterMin ? colMax : colMin);
|
|
444
|
+
if (isArea) bs.push(colBase, colBase);
|
|
445
|
+
}
|
|
446
|
+
colCount = 0;
|
|
447
|
+
colPx = NaN;
|
|
448
|
+
};
|
|
449
|
+
for (let i = i0; i < i1; i++) {
|
|
450
|
+
const v = yv[i] as number;
|
|
451
|
+
const py = yScale.scale(v);
|
|
452
|
+
// isFinite, not isNaN: an index past a snapshot's end reads as
|
|
453
|
+
// undefined, and undefined is not NaN — both are gaps, not points
|
|
454
|
+
if (!Number.isFinite(py)) {
|
|
455
|
+
emitColumn();
|
|
456
|
+
flush();
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
const px = pxAt(env, g, i);
|
|
460
|
+
if (!Number.isFinite(px)) {
|
|
461
|
+
emitColumn();
|
|
462
|
+
flush();
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
if (colCount > 0 && Math.abs(px - colPx) < COL_EPS) {
|
|
466
|
+
if (py < colMin) colMin = py;
|
|
467
|
+
if (py > colMax) colMax = py;
|
|
468
|
+
colCount++;
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
emitColumn();
|
|
472
|
+
colPx = px;
|
|
473
|
+
colFirst = colMin = colMax = py;
|
|
474
|
+
colCount = 1;
|
|
475
|
+
if (isArea) {
|
|
476
|
+
const b = baseValueAt(g, i);
|
|
477
|
+
colBase = yScale.scale(Number.isNaN(b) ? 0 : b);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
emitColumn();
|
|
481
|
+
flush();
|
|
482
|
+
|
|
483
|
+
if (isArea && ctx.fill) {
|
|
484
|
+
// fill each run down to its base edge, walked back with the same
|
|
485
|
+
// curve — a stacked layer's base is the layer below's top, so the
|
|
486
|
+
// two paths coincide and the seam is exact
|
|
487
|
+
ctx.save();
|
|
488
|
+
if (ctx.globalAlpha !== undefined) ctx.globalAlpha = g.spec.fillOpacity;
|
|
489
|
+
ctx.fillStyle = g.color;
|
|
490
|
+
ctx.beginPath!();
|
|
491
|
+
for (let r = 0; r < runsX.length; r++) {
|
|
492
|
+
emitRun(ctx, runsX[r], runsY[r], g.spec.curve, true);
|
|
493
|
+
const backX = runsX[r].slice().reverse();
|
|
494
|
+
const backY = runsB[r].slice().reverse();
|
|
495
|
+
emitRun(ctx, backX, backY, g.spec.curve, false);
|
|
496
|
+
ctx.closePath?.();
|
|
497
|
+
}
|
|
498
|
+
ctx.fill();
|
|
499
|
+
ctx.restore();
|
|
500
|
+
stats.commands++;
|
|
501
|
+
stats.estimatedWireBytes += count * BYTES_PER_SEGMENT * 2;
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
ctx.save();
|
|
505
|
+
ctx.strokeStyle = g.color;
|
|
506
|
+
ctx.lineWidth = g.spec.strokeWidth;
|
|
507
|
+
if (count <= ROUND_JOIN_MAX) {
|
|
508
|
+
if (ctx.lineJoin !== undefined) ctx.lineJoin = 'round';
|
|
509
|
+
if (ctx.lineCap !== undefined) ctx.lineCap = 'round';
|
|
510
|
+
}
|
|
511
|
+
ctx.beginPath!();
|
|
512
|
+
for (let r = 0; r < runsX.length; r++) {
|
|
513
|
+
emitRun(ctx, runsX[r], runsY[r], g.spec.curve, true);
|
|
514
|
+
}
|
|
515
|
+
ctx.stroke();
|
|
516
|
+
ctx.restore();
|
|
517
|
+
stats.commands++;
|
|
518
|
+
stats.estimatedWireBytes += count * BYTES_PER_SEGMENT;
|
|
519
|
+
|
|
520
|
+
if (g.spec.dot !== false && g.spec.dot > 0) {
|
|
521
|
+
renderDots(env, runsX, runsY, g.spec.dot, g.color);
|
|
522
|
+
}
|
|
523
|
+
stats.series.push({ id: g.spec.id, mode: 'polyline', points: count });
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// ---- dense: per-column spans through the pyramid
|
|
528
|
+
const pyr = pyramidFor(g.y);
|
|
529
|
+
const yv = g.y.values;
|
|
530
|
+
const strokeRects: number[] = [];
|
|
531
|
+
const fillRectsArr: number[] = [];
|
|
532
|
+
const half = Math.max(0, (g.spec.strokeWidth - 1) / 2);
|
|
533
|
+
const baseConst =
|
|
534
|
+
typeof g.base === 'number' ? Math.round(yScale.scale(g.base)) : null;
|
|
535
|
+
const basePyr =
|
|
536
|
+
isArea && typeof g.base !== 'number' ? pyramidFor(g.base) : null;
|
|
537
|
+
let prevLast = NaN;
|
|
538
|
+
walkColumns(env, g, i0, i1, (colPx, ia, ib) => {
|
|
539
|
+
if (ib <= ia) {
|
|
540
|
+
prevLast = NaN;
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
minMaxRange(pyr, yv, ia, ib, mm);
|
|
544
|
+
if (mm.min > mm.max) {
|
|
545
|
+
prevLast = NaN;
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
const closing = lastFinite(yv, ia, ib);
|
|
549
|
+
let lo = mm.min;
|
|
550
|
+
let hi = mm.max;
|
|
551
|
+
if (!Number.isNaN(prevLast)) {
|
|
552
|
+
if (prevLast < lo) lo = prevLast;
|
|
553
|
+
if (prevLast > hi) hi = prevLast;
|
|
554
|
+
}
|
|
555
|
+
prevLast = closing;
|
|
556
|
+
const span = clampSpan(
|
|
557
|
+
env.plot,
|
|
558
|
+
Math.round(yScale.scale(hi) - half),
|
|
559
|
+
Math.round(yScale.scale(lo) + half),
|
|
560
|
+
);
|
|
561
|
+
if (span) strokeRects.push(colPx, span[0], 1, span[1] - span[0]);
|
|
562
|
+
|
|
563
|
+
if (isArea && !Number.isNaN(closing)) {
|
|
564
|
+
let basePx: number;
|
|
565
|
+
if (baseConst !== null) {
|
|
566
|
+
basePx = baseConst;
|
|
567
|
+
} else {
|
|
568
|
+
const baseCol = g.base as NumericColumn;
|
|
569
|
+
minMaxRange(basePyr!, baseCol.values, ia, ib, mm);
|
|
570
|
+
const baseClosing = lastFinite(baseCol.values, ia, ib);
|
|
571
|
+
basePx = Math.round(
|
|
572
|
+
yScale.scale(Number.isNaN(baseClosing) ? 0 : baseClosing),
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
const topPx = Math.round(yScale.scale(closing));
|
|
576
|
+
const fillSpan = clampSpan(
|
|
577
|
+
env.plot,
|
|
578
|
+
Math.min(topPx, basePx),
|
|
579
|
+
Math.max(topPx, basePx),
|
|
580
|
+
);
|
|
581
|
+
if (fillSpan) {
|
|
582
|
+
fillRectsArr.push(colPx, fillSpan[0], 1, fillSpan[1] - fillSpan[0]);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
if (isArea && fillRectsArr.length) {
|
|
588
|
+
ctx.save();
|
|
589
|
+
if (ctx.globalAlpha !== undefined) ctx.globalAlpha = g.spec.fillOpacity;
|
|
590
|
+
ctx.fillStyle = g.color;
|
|
591
|
+
fillRects(ctx, fillRectsArr);
|
|
592
|
+
ctx.restore();
|
|
593
|
+
stats.commands++;
|
|
594
|
+
stats.estimatedWireBytes += (fillRectsArr.length / 4) * BYTES_PER_RECT;
|
|
595
|
+
}
|
|
596
|
+
if (strokeRects.length) {
|
|
597
|
+
ctx.save();
|
|
598
|
+
ctx.fillStyle = g.color;
|
|
599
|
+
fillRects(ctx, strokeRects);
|
|
600
|
+
ctx.restore();
|
|
601
|
+
stats.commands++;
|
|
602
|
+
stats.estimatedWireBytes += (strokeRects.length / 4) * BYTES_PER_RECT;
|
|
603
|
+
}
|
|
604
|
+
stats.series.push({ id: g.spec.id, mode: 'columns', points: count });
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
function renderDots(
|
|
608
|
+
env: SeriesEnv,
|
|
609
|
+
runsX: number[][],
|
|
610
|
+
runsY: number[][],
|
|
611
|
+
r: number,
|
|
612
|
+
color: string,
|
|
613
|
+
): void {
|
|
614
|
+
const { ctx, stats } = env;
|
|
615
|
+
let total = 0;
|
|
616
|
+
for (const run of runsX) total += run.length;
|
|
617
|
+
if (total <= CIRCLE_MAX && ctx.arc && ctx.fill && ctx.beginPath) {
|
|
618
|
+
ctx.save();
|
|
619
|
+
ctx.fillStyle = color;
|
|
620
|
+
for (let k = 0; k < runsX.length; k++) {
|
|
621
|
+
for (let i = 0; i < runsX[k].length; i++) {
|
|
622
|
+
ctx.beginPath();
|
|
623
|
+
ctx.arc(runsX[k][i], runsY[k][i], r, 0, Math.PI * 2);
|
|
624
|
+
ctx.fill();
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
ctx.restore();
|
|
628
|
+
stats.commands += total;
|
|
629
|
+
stats.estimatedWireBytes += total * BYTES_PER_SEGMENT;
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
const rects: number[] = [];
|
|
633
|
+
for (let k = 0; k < runsX.length; k++) {
|
|
634
|
+
for (let i = 0; i < runsX[k].length; i++) {
|
|
635
|
+
rects.push(
|
|
636
|
+
Math.round(runsX[k][i] - r),
|
|
637
|
+
Math.round(runsY[k][i] - r),
|
|
638
|
+
Math.round(2 * r),
|
|
639
|
+
Math.round(2 * r),
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
ctx.save();
|
|
644
|
+
ctx.fillStyle = color;
|
|
645
|
+
fillRects(ctx, rects);
|
|
646
|
+
ctx.restore();
|
|
647
|
+
stats.commands++;
|
|
648
|
+
stats.estimatedWireBytes += (rects.length / 4) * BYTES_PER_RECT;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// --- bars ------------------------------------------------------------------
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Bars over a band scale. The normal case is one `fillRects` batch per
|
|
655
|
+
* series; rounded tops keep their radius only while the count stays small
|
|
656
|
+
* enough that per-bar paths are cheaper than they are pretty; and a series
|
|
657
|
+
* with more bars than pixels collapses to the same per-column envelope a
|
|
658
|
+
* dense line uses — a 100k-bar histogram is a silhouette either way.
|
|
659
|
+
*/
|
|
660
|
+
export function renderBars(env: SeriesEnv, g: SeriesGeometry): void {
|
|
661
|
+
const { ctx, yScale, stats } = env;
|
|
662
|
+
if (env.xScale.kind !== 'band') {
|
|
663
|
+
stats.series.push({ id: g.spec.id, mode: 'skipped', points: 0 });
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
const band = env.xScale;
|
|
667
|
+
const n = Math.min(g.y.n, band.count);
|
|
668
|
+
stats.pointsSpanned += n;
|
|
669
|
+
const yv = g.y.values;
|
|
670
|
+
|
|
671
|
+
if (band.bandwidth / g.group.count < 1 || n > env.plot.width * 2) {
|
|
672
|
+
// envelope: per-column span from the base to the tallest bar
|
|
673
|
+
const pyr = pyramidFor(g.y);
|
|
674
|
+
const rects: number[] = [];
|
|
675
|
+
const cols = Math.max(1, Math.round(env.plot.width));
|
|
676
|
+
const basePx = Math.round(
|
|
677
|
+
yScale.scale(typeof g.base === 'number' ? g.base : 0),
|
|
678
|
+
);
|
|
679
|
+
let prev = 0;
|
|
680
|
+
for (let c = 0; c < cols; c++) {
|
|
681
|
+
const ib = c + 1 >= cols ? n : Math.floor((n * (c + 1)) / cols);
|
|
682
|
+
if (ib > prev) {
|
|
683
|
+
minMaxRange(pyr, yv, prev, ib, mm);
|
|
684
|
+
if (mm.min <= mm.max) {
|
|
685
|
+
const hiPx = Math.round(yScale.scale(mm.max));
|
|
686
|
+
const loPx = Math.round(yScale.scale(Math.min(mm.min, 0)));
|
|
687
|
+
const span = clampSpan(
|
|
688
|
+
env.plot,
|
|
689
|
+
Math.min(hiPx, loPx, basePx),
|
|
690
|
+
Math.max(hiPx, loPx, basePx),
|
|
691
|
+
);
|
|
692
|
+
if (span) rects.push(env.plot.x + c, span[0], 1, span[1] - span[0]);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
prev = ib;
|
|
696
|
+
}
|
|
697
|
+
ctx.save();
|
|
698
|
+
ctx.fillStyle = g.color;
|
|
699
|
+
fillRects(ctx, rects);
|
|
700
|
+
ctx.restore();
|
|
701
|
+
stats.commands++;
|
|
702
|
+
stats.estimatedWireBytes += (rects.length / 4) * BYTES_PER_RECT;
|
|
703
|
+
stats.series.push({ id: g.spec.id, mode: 'columns', points: n });
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
const slot = band.bandwidth / g.group.count;
|
|
708
|
+
const gap = g.group.count > 1 && slot > 3 ? 1 : 0;
|
|
709
|
+
const w = Math.max(1, Math.round(slot - gap));
|
|
710
|
+
const rounded =
|
|
711
|
+
g.spec.barRadius > 0 &&
|
|
712
|
+
n <= BAR_RADIUS_MAX &&
|
|
713
|
+
canPath(ctx) &&
|
|
714
|
+
typeof ctx.roundRect === 'function' &&
|
|
715
|
+
typeof ctx.fill === 'function';
|
|
716
|
+
const rects: number[] = [];
|
|
717
|
+
ctx.save();
|
|
718
|
+
ctx.fillStyle = g.color;
|
|
719
|
+
for (let i = 0; i < n; i++) {
|
|
720
|
+
const v = yv[i] as number;
|
|
721
|
+
if (Number.isNaN(v)) continue;
|
|
722
|
+
const base = baseValueAt(g, i);
|
|
723
|
+
const x = Math.round(band.scale(i) + slot * g.group.index);
|
|
724
|
+
const y0 = yScale.scale(v);
|
|
725
|
+
const y1 = yScale.scale(Number.isNaN(base) ? 0 : base);
|
|
726
|
+
const top = Math.round(Math.min(y0, y1));
|
|
727
|
+
const h = Math.max(1, Math.round(Math.abs(y1 - y0)));
|
|
728
|
+
if (rounded) {
|
|
729
|
+
const r = Math.min(g.spec.barRadius, w / 2, h);
|
|
730
|
+
ctx.beginPath!();
|
|
731
|
+
// round the value end only — the stack seam and the axis stay square
|
|
732
|
+
const radii = y0 <= y1 ? [r, r, 0, 0] : [0, 0, r, r];
|
|
733
|
+
ctx.roundRect!(x, top, w, h, radii);
|
|
734
|
+
ctx.fill!();
|
|
735
|
+
stats.commands++;
|
|
736
|
+
stats.estimatedWireBytes += BYTES_PER_RECT * 3;
|
|
737
|
+
} else {
|
|
738
|
+
rects.push(x, top, w, h);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
if (rects.length) {
|
|
742
|
+
fillRects(ctx, rects);
|
|
743
|
+
stats.commands++;
|
|
744
|
+
stats.estimatedWireBytes += (rects.length / 4) * BYTES_PER_RECT;
|
|
745
|
+
}
|
|
746
|
+
ctx.restore();
|
|
747
|
+
stats.series.push({
|
|
748
|
+
id: g.spec.id,
|
|
749
|
+
mode: rounded ? 'rects' : 'bars',
|
|
750
|
+
points: n,
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// --- scatter ---------------------------------------------------------------
|
|
755
|
+
|
|
756
|
+
/** The occupancy grid a dense scatter reduces to: point counts per
|
|
757
|
+
* dot-sized cell, extended incrementally as data appends. */
|
|
758
|
+
export interface ScatterGrid {
|
|
759
|
+
key: string;
|
|
760
|
+
cell: number;
|
|
761
|
+
gw: number;
|
|
762
|
+
gh: number;
|
|
763
|
+
counts: Uint32Array;
|
|
764
|
+
occupied: number;
|
|
765
|
+
maxCount: number;
|
|
766
|
+
/** points consumed so far — the incremental cursor */
|
|
767
|
+
consumedN: number;
|
|
768
|
+
/** rects per alpha bucket, rebuilt only when the grid changed */
|
|
769
|
+
buckets: number[][] | null;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
export function makeScatterGrid(
|
|
773
|
+
key: string,
|
|
774
|
+
cell: number,
|
|
775
|
+
gw: number,
|
|
776
|
+
gh: number,
|
|
777
|
+
): ScatterGrid {
|
|
778
|
+
return {
|
|
779
|
+
key,
|
|
780
|
+
cell,
|
|
781
|
+
gw,
|
|
782
|
+
gh,
|
|
783
|
+
counts: new Uint32Array(gw * gh),
|
|
784
|
+
occupied: 0,
|
|
785
|
+
maxCount: 0,
|
|
786
|
+
consumedN: 0,
|
|
787
|
+
buckets: null,
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
const ALPHA_LEVELS = 8;
|
|
792
|
+
|
|
793
|
+
/** #rgb/#rrggbb/#rrggbbaa → [r,g,b,a?]; null for anything fancier, which
|
|
794
|
+
* simply keeps the rect path. */
|
|
795
|
+
export function parseHexColor(
|
|
796
|
+
color: string,
|
|
797
|
+
): [number, number, number, number] | null {
|
|
798
|
+
if (!color.startsWith('#')) return null;
|
|
799
|
+
const hex = color.slice(1);
|
|
800
|
+
const digit = (c: string) => parseInt(c, 16);
|
|
801
|
+
if (hex.length === 3) {
|
|
802
|
+
return [digit(hex[0]) * 17, digit(hex[1]) * 17, digit(hex[2]) * 17, 255];
|
|
803
|
+
}
|
|
804
|
+
if (hex.length === 6 || hex.length === 8) {
|
|
805
|
+
const r = parseInt(hex.slice(0, 2), 16);
|
|
806
|
+
const gg = parseInt(hex.slice(2, 4), 16);
|
|
807
|
+
const b = parseInt(hex.slice(4, 6), 16);
|
|
808
|
+
const a = hex.length === 8 ? parseInt(hex.slice(6, 8), 16) : 255;
|
|
809
|
+
if ([r, gg, b, a].some(Number.isNaN)) return null;
|
|
810
|
+
return [r, gg, b, a];
|
|
811
|
+
}
|
|
812
|
+
return null;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* A scatter series. A handful of points draw directly (circles, then one
|
|
817
|
+
* batch of squares); past that the series reduces to the occupancy grid —
|
|
818
|
+
* a million coincident points are one cell — rendered as per-alpha-level
|
|
819
|
+
* `fillRects` batches, or as one composited density image once rectangles
|
|
820
|
+
* would cost more bytes than pixels.
|
|
821
|
+
*/
|
|
822
|
+
export function renderScatter(env: SeriesEnv, g: SeriesGeometry): void {
|
|
823
|
+
const { ctx, plot, yScale, stats } = env;
|
|
824
|
+
const n = g.x ? Math.min(g.y.n, g.x.n) : g.y.n;
|
|
825
|
+
stats.pointsSpanned += n;
|
|
826
|
+
const size = Math.max(1, Math.round(g.spec.size));
|
|
827
|
+
const yv = g.y.values;
|
|
828
|
+
|
|
829
|
+
if (n <= DIRECT_SCATTER_MAX) {
|
|
830
|
+
const xs: number[] = [];
|
|
831
|
+
const ys: number[] = [];
|
|
832
|
+
for (let i = 0; i < n; i++) {
|
|
833
|
+
const v = yv[i] as number;
|
|
834
|
+
if (Number.isNaN(v)) continue;
|
|
835
|
+
const px = pxAt(env, g, i);
|
|
836
|
+
const py = yScale.scale(v);
|
|
837
|
+
if (px < plot.x || px > plot.x + plot.width) continue;
|
|
838
|
+
xs.push(px);
|
|
839
|
+
ys.push(py);
|
|
840
|
+
}
|
|
841
|
+
renderDots(env, [xs], [ys], size / 2 + 0.5, g.color);
|
|
842
|
+
stats.series.push({ id: g.spec.id, mode: 'rects', points: n });
|
|
843
|
+
return;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// ---- dense: occupancy grid
|
|
847
|
+
const cell = size;
|
|
848
|
+
const gw = Math.max(1, Math.ceil(plot.width / cell));
|
|
849
|
+
const gh = Math.max(1, Math.ceil(plot.height / cell));
|
|
850
|
+
const xScale = env.xScale;
|
|
851
|
+
const domKey =
|
|
852
|
+
xScale.kind === 'band' ? `b${xScale.count}` : `${xScale.d0},${xScale.d1}`;
|
|
853
|
+
const key = `${cell}|${gw}|${gh}|${domKey}|${yScale.d0},${yScale.d1}|${g.y.epoch}`;
|
|
854
|
+
const grid = env.host.scatterGrid(g.spec.id, key, n);
|
|
855
|
+
|
|
856
|
+
if (grid.consumedN < n) {
|
|
857
|
+
const kx = gw / plot.width;
|
|
858
|
+
const ky = gh / plot.height;
|
|
859
|
+
for (let i = grid.consumedN; i < n; i++) {
|
|
860
|
+
const v = yv[i] as number;
|
|
861
|
+
if (Number.isNaN(v)) continue;
|
|
862
|
+
const px = pxAt(env, g, i) - plot.x;
|
|
863
|
+
const py = yScale.scale(v) - plot.y;
|
|
864
|
+
const cx = Math.floor(px * kx);
|
|
865
|
+
const cy = Math.floor(py * ky);
|
|
866
|
+
if (cx < 0 || cx >= gw || cy < 0 || cy >= gh) continue;
|
|
867
|
+
const at = cy * gw + cx;
|
|
868
|
+
const before = grid.counts[at]++;
|
|
869
|
+
if (before === 0) grid.occupied++;
|
|
870
|
+
if (before + 1 > grid.maxCount) grid.maxCount = before + 1;
|
|
871
|
+
}
|
|
872
|
+
grid.consumedN = n;
|
|
873
|
+
grid.buckets = null;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
// rectangles vs pixels: the byte crossover, computed
|
|
877
|
+
const rectBytes = grid.occupied * BYTES_PER_RECT;
|
|
878
|
+
const imageBytes = plot.width * plot.height * BYTES_PER_PIXEL;
|
|
879
|
+
const rgb = parseHexColor(g.color);
|
|
880
|
+
if (rectBytes > imageBytes && rgb) {
|
|
881
|
+
const drawn = env.host.blitImage(
|
|
882
|
+
plot.x,
|
|
883
|
+
plot.y,
|
|
884
|
+
gw * cell,
|
|
885
|
+
gh * cell,
|
|
886
|
+
(data) => {
|
|
887
|
+
const [r, gg, b] = rgb;
|
|
888
|
+
for (let cy = 0; cy < gh; cy++) {
|
|
889
|
+
for (let cx = 0; cx < gw; cx++) {
|
|
890
|
+
const count = grid.counts[cy * gw + cx];
|
|
891
|
+
if (count === 0) continue;
|
|
892
|
+
const a = Math.round(
|
|
893
|
+
255 * (0.3 + 0.7 * Math.sqrt(count / grid.maxCount)),
|
|
894
|
+
);
|
|
895
|
+
for (let dy = 0; dy < cell; dy++) {
|
|
896
|
+
let at = ((cy * cell + dy) * gw * cell + cx * cell) * 4;
|
|
897
|
+
for (let dx = 0; dx < cell; dx++) {
|
|
898
|
+
data[at] = r;
|
|
899
|
+
data[at + 1] = gg;
|
|
900
|
+
data[at + 2] = b;
|
|
901
|
+
data[at + 3] = a;
|
|
902
|
+
at += 4;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
},
|
|
908
|
+
// same grid content + colour → the host recomposites its retained
|
|
909
|
+
// surface: no refill, no upload
|
|
910
|
+
`${grid.key}#${grid.consumedN}|${g.color}`,
|
|
911
|
+
);
|
|
912
|
+
if (drawn) {
|
|
913
|
+
stats.commands++;
|
|
914
|
+
stats.estimatedWireBytes += imageBytes;
|
|
915
|
+
stats.series.push({ id: g.spec.id, mode: 'image', points: n });
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
if (!grid.buckets) {
|
|
921
|
+
// Plot-LOCAL coordinates, translated at draw time. Nothing that lives
|
|
922
|
+
// across frames may bake in the plot's window position: every part of
|
|
923
|
+
// the cache key stays equal while a scroll or a section reflow moves
|
|
924
|
+
// the plot rect, and window-space buckets then redraw at the old
|
|
925
|
+
// origin — sliced flat by the series clip, or clipped away entirely.
|
|
926
|
+
const buckets: number[][] = Array.from({ length: ALPHA_LEVELS }, () => []);
|
|
927
|
+
for (let cy = 0; cy < gh; cy++) {
|
|
928
|
+
for (let cx = 0; cx < gw; cx++) {
|
|
929
|
+
const count = grid.counts[cy * gw + cx];
|
|
930
|
+
if (count === 0) continue;
|
|
931
|
+
const level = Math.min(
|
|
932
|
+
ALPHA_LEVELS - 1,
|
|
933
|
+
Math.floor(Math.sqrt(count / grid.maxCount) * ALPHA_LEVELS),
|
|
934
|
+
);
|
|
935
|
+
buckets[level].push(cx * cell, cy * cell, cell, cell);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
grid.buckets = buckets;
|
|
939
|
+
}
|
|
940
|
+
ctx.save();
|
|
941
|
+
ctx.fillStyle = g.color;
|
|
942
|
+
for (let level = 0; level < ALPHA_LEVELS; level++) {
|
|
943
|
+
const local = grid.buckets[level];
|
|
944
|
+
if (!local.length) continue;
|
|
945
|
+
if (ctx.globalAlpha !== undefined) {
|
|
946
|
+
ctx.globalAlpha = 0.3 + (0.7 * (level + 1)) / ALPHA_LEVELS;
|
|
947
|
+
}
|
|
948
|
+
// translate manually: ctx.translate would kick fillRects off ntk's
|
|
949
|
+
// single-FillRectangles fast path (it requires an identity transform)
|
|
950
|
+
const rects = new Array<number>(local.length);
|
|
951
|
+
for (let i = 0; i < local.length; i += 4) {
|
|
952
|
+
rects[i] = local[i] + plot.x;
|
|
953
|
+
rects[i + 1] = local[i + 1] + plot.y;
|
|
954
|
+
rects[i + 2] = local[i + 2];
|
|
955
|
+
rects[i + 3] = local[i + 3];
|
|
956
|
+
}
|
|
957
|
+
fillRects(ctx, rects);
|
|
958
|
+
stats.commands++;
|
|
959
|
+
stats.estimatedWireBytes += (rects.length / 4) * BYTES_PER_RECT;
|
|
960
|
+
}
|
|
961
|
+
ctx.restore();
|
|
962
|
+
stats.series.push({ id: g.spec.id, mode: 'columns', points: n });
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
/** One dispatch for the node's series loop. */
|
|
966
|
+
export function renderSeries(env: SeriesEnv, g: SeriesGeometry): void {
|
|
967
|
+
switch (g.spec.type) {
|
|
968
|
+
case 'line':
|
|
969
|
+
case 'area':
|
|
970
|
+
renderLineArea(env, g);
|
|
971
|
+
break;
|
|
972
|
+
case 'bar':
|
|
973
|
+
renderBars(env, g);
|
|
974
|
+
break;
|
|
975
|
+
case 'scatter':
|
|
976
|
+
renderScatter(env, g);
|
|
977
|
+
break;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
/** Re-exported for the node; keeps `data.js` out of its import list. */
|
|
982
|
+
export { pyramidFor, xIndexFor };
|