[ui] add the Chart layer: typed authoring spec lowering to SVG#1665
Open
fwbrasil wants to merge 5 commits into
Open
[ui] add the Chart layer: typed authoring spec lowering to SVG#1665fwbrasil wants to merge 5 commits into
fwbrasil wants to merge 5 commits into
Conversation
## Problem kyo-ui can render typed SVG, but there is no way to author a data visualization from a dataset. Today that means hand-computing scales, axes, layout, and legends and emitting raw `Svg.*` shapes, with no type-driven mapping of data fields to visual marks and no reactive or animated updates. ## Solution Add `Chart`, a pure immutable authoring spec (not a `UI` node) that lowers to an `Svg.Root`. The dataset fixes the row type, so field accessors like `x = _.month` infer with no annotations, and a `Plottable` typeclass derives the right scale per field (band scales for enums, linear for numbers, time for instants). Marks (bar, line, area, point, text, error bar, rule) are the visual vocabulary; axes, legends, layout, stacking, theming, scales, interaction, and transitions are applied by refinement methods that return a refined `Chart`. Because `Svg.Root` is itself `HtmlContent`, a lowered chart drops into any HTML container, and a chart bound to reactive data animates between states via SMIL. The public surface is `Chart.scala`; the scale inference, axis, layout, legend, mark, interaction, and transition machinery lives in `kyo.internal`, so the reviewable API is small relative to the diff. ## Notes - SVG layer: `Animate` gains `calcMode`/`keyTimes`/`keySplines` so chart transitions can drive spline-interpolated keyframes. - Renderer correctness: the session id and base path are interpolated into a `<script>` JS string but were escaped with the HTML-attribute escaper, the wrong context. They now use a JS-string escaper. Both values are server-controlled today (a random UUID and a configured base path), so this is hardening, not a vulnerability fix; the escaping is simply now correct for the context. - Demos renamed to the `*Demo.scala` convention, matching kyo-browser. - Test cleanup: removed compile-assertions that only restate language guarantees (a `sealed` type can't be extended, a `private` member isn't callable); every genuine designed-rejection contract test is kept. - `Svg.Paint`'s `Style.Color` conversion moves from a `given Conversion` to a plain `implicit def`, dropping the now-unneeded `import scala.language.implicitConversions` across the module.
Resolves conflicts introduced by #1664 (connection-bound reactive sessions): - HtmlRenderer: clientJs(jsStr(basePath)), combining #1664's dropped sessionId (the WebSocket owns the session) with #1665's jsStr JS-string escaping. - HtmlRendererTest: keep both added blocks (charts' JS-escaping tests + main's clientJs transport tests), adapting charts' tests to the 4-arg renderPage. - SvgReactiveTest: import scala.language.implicitConversions (UISession removed upstream; UIExchange unused in the merged body). - README: charts' demo list (matches the actual XDemo.scala files), with the stale "over SSE" corrected to "over the WebSocket". - ChartMorphTest: 4-arg renderPage (drop the sessionId argument). Validated: kyo-ui Test/compile clean; affected tests 116 passed, 0 failed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
kyo-ui can render typed SVG, but there is no way to author a data visualization from a dataset. Today that means hand-computing scales, axes, layout, and legends and emitting raw
Svg.*shapes, with no type-driven mapping of data fields to visual marks and no reactive or animated updates.Solution
Add
Chart, a pure immutable authoring spec (not aUInode) that lowers to anSvg.Root. The dataset fixes the row type, so field accessors likex = _.monthinfer with no annotations, and aPlottabletypeclass derives the right scale per field (band scales for enums, linear for numbers, time for instants). Marks (bar, line, area, point, text, error bar, rule) are the visual vocabulary; axes, legends, layout, stacking, theming, scales, interaction, and transitions are applied by refinement methods that return a refinedChart. BecauseSvg.Rootis itselfHtmlContent, a lowered chart drops into any HTML container, and a chart bound to reactive data animates between states via SMIL.The public surface is
Chart.scala; the scale inference, axis, layout, legend, mark, interaction, and transition machinery lives inkyo.internal, so the reviewable API is small relative to the diff.Notes
AnimategainscalcMode/keyTimes/keySplinesso chart transitions can drive spline-interpolated keyframes.<script>JS string but were escaped with the HTML-attribute escaper, the wrong context. They now use a JS-string escaper. Both values are server-controlled today (a random UUID and a configured base path), so this is hardening, not a vulnerability fix; the escaping is simply now correct for the context.*Demo.scalaconvention, matching kyo-browser.sealedtype can't be extended, aprivatemember isn't callable); every genuine designed-rejection contract test is kept.Svg.Paint'sStyle.Colorconversion moves from agiven Conversionto a plainimplicit def, dropping the now-unneededimport scala.language.implicitConversionsacross the module.