Skip to content

Releases: hzblj/zyplot

@hzblj/zyplot@0.3.0

Choose a tag to compare

@github-actions github-actions released this 30 Jul 20:45
2c9cf6f

Minor Changes

  • 66541ab - Let the crosshair carry a label, so the text above it keeps up with the finger.

    crosshairStyle.labels takes one string per slot in data order — a time, a date, whatever
    the reading is called — and every renderer draws the one for the read slot above the plot,
    in the same pass that draws the line. labelColor and labelSize style it. The app still
    writes the words; the chart only places them.

    This is the one piece of scrub chrome worth taking back off the app. Everything else an
    overlay draws over a plot sits still long enough for onInteraction to place it — a card
    against a rule, a badge on an annotation — but a label pinned to the crosshair has to move
    with it, and a position that reaches JavaScript through a bridge and comes back as a
    re-render is a frame or two behind the line it belongs to. Reading the two together, the
    label visibly drags. Nothing about the overlay contract changes; this is one thing added to
    the side of it that was always going to lose that race.

  • 66541ab - Add fadeTo to the series fill, so the paint can thin towards the plot's floor.

    An even fill has two edges: the trace along its top, and a hard stop along the bottom of
    the plot that no data put there. On a chart with no axis to speak of the second one reads
    as a second line, and the eye keeps going back to it. fill({fadeTo: 0.12}) takes the fill
    down to a tenth of its strength by the floor, so it gathers under the trace and lets go.

    The three renderers get there differently. The SwiftUI and Compose canvases paint the dot
    grid a row at a time, which is the largest unit that can share an alpha — one path per dot
    would be thousands of draw calls a frame, and one path for the grid can only carry one.
    ECharts is given a tile as tall as the plot and repeated only across, because a tile that
    repeated vertically would restart the ramp every few pixels; that needs the plot height
    before the chart is measured, so it is computed from the same gutters the grid reserves and
    a chart given no height keeps an even fill rather than guessing at one.

  • 66541ab - Add marker.trail, a selection marker that lights the trace up to the reading.

    marker.segment brightens a window span steps either side of the mark under the finger,
    which reads as light moving along the data. That is the right shape when the reader is
    comparing a point against its neighbours, and the wrong one for a price chart, where the
    question is what has happened so far — everything before the finger is history, everything
    after it has not been reached yet.

    There was no way to say that: the window is symmetric in all three renderers, and
    dimOpacity fades the whole line at once. marker.trail lights from the first datum to the
    reading instead and leaves the rest at dimOpacity, on Swift Charts, the Compose canvas and
    the web. It takes neither span nor size — its far end is the reading and its near end is
    the start of the series, so there is nothing to size.

    Both stroke-lighting styles are drawn over the line rather than beside it, so both still
    need a dimOpacity to stand out from. The iOS and Android selection-marker views now treat
    a trail the way they already treated a segment, and draw no dot of their own on top of it.

  • 66541ab - Make transition: 'morph' do something on iOS and Android.

    ChartTransition has offered 'crossfade' | 'morph' since the contract was written, but
    only crossfade was ever implemented. Asking for a morph did not fall back to a crossfade —
    it fell through to no animation at all, and the plot cut from one dataset to the next.

    Both platforms now blend the two: the readings, the pinned axis domain, and the value a rule
    or a point sits at, so nothing on the plot jumps while the trace is on its way. Annotations
    are matched by id — one that exists on both sides slides, one that does not simply
    arrives. A morph needs the two sides to correspond, so where the series count or the
    reading count differs the new dataset is shown as it is: half a morph reads worse than none.

    animation({duration, easing}) times it, the same two that time the entrance and every
    other data change — so a morph is tuned from the props rather than from a curve baked into
    the renderer. 'spring' resolves to the eased curve: there is no closed form to sample at a
    fraction, and a transition that overshoots would carry the marks past their new values and
    back.

    The frames are produced rather than animated towards. SwiftUI and Compose both interpolate
    modifiers; a fraction fed to a data computation is set straight to its final value and
    the body runs once, which is an animation that never draws a frame. iOS runs the clock off a
    TimelineView, the way the traced reveal does, and parks the schedule whenever nothing is
    moving. Android reads the clock inside the canvas, so a morph costs a draw a frame rather
    than a recomposition of the chart around it.

    Implicit animation is switched off underneath the iOS morph — the chart's own update
    animation with it, which is the one that mattered. An animation keyed on the data is handed a
    new target on every frame of a morph and spends the whole morph chasing it: the trace is drawn
    from the frame directly and lands on time, while every mark Swift Charts owns arrives a beat
    late and keeps moving after the line has settled. The rule at the latest reading showed it
    worst — it hung at its old price and then slid down once the morph was already over. Compose
    draws straight from the frame it is given, so it never had the second animation to switch off.

    A morph cut short sets off from what is on screen rather than from the dataset the last one
    was heading for. A row of range buttons gets pressed in sequence, and snapping back to the
    window before to set off again is a jump nobody asked for.

    Two datasets only correspond if they agree on how many readings they have. A screen that
    switches between windows of different lengths — a day against a year — has to sample them
    into the same number of slots to be morphed between; otherwise this stays a crossfade.

    transition stays a native choice, and is now documented as one. The web renderer
    transitions a data change itself, mark by mark: the ones on both sides move, the ones on one
    side fade. That is a better answer to a changed axis than dissolving the whole plot, so a web
    chart does it whichever name it is given — including for the same animation object an app
    shares with its native screens.

  • 66541ab - Add fill to the series style: a dot-grid pattern, and a baseline other than the plot floor.

    fillOpacity was the whole vocabulary for the area under a line, and it only did anything on
    Chart.Area, where the fill runs to the bottom of the plot because there the fill is the
    quantity. Two things a price chart wants were unsayable.

    A fill can now close against a value — fill({baseline: latest}) — so the shape between the
    trace and that number is filled above the line and below it, and reads as distance from where
    the asset stands rather than as volume. And it can be laid down as a grid of dots rather than
    a flat wash — fill({pattern: 'dots', spacing: 3.4}) — which carries a fill across a pale
    background without the second, fainter chart a wash leaves behind it.

    fill lives on NativeChartSeriesStyle next to glow, so every entry point takes it, the
    web one included: a clipped dot path on the SwiftUI and Compose canvases, a repeating canvas
    pattern on ECharts. Opacity is still fillOpacity — one spelling — though a dot grid usually
    wants more of it than a wash, since most of what it covers stays bare.

    Giving a series a fill also paints an area under Chart.Line, where it is decoration rather
    than the quantity. Chart.Area is unchanged: it still fills by default, and a fill only
    overrides the pattern and the baseline.

Patch Changes

  • 66541ab - Stop Android drawing grid rules for an axis that asked not to be drawn.

    yAxis={{visible: false}} took the labels off the Compose canvas and left the rules behind:
    drawGrid only ever consulted yAxis.grid, which defaults on, so a chart meant to be read
    off its marks alone came out with five grey lines across it — and only on Android, since
    Swift Charts and ECharts both drop a hidden axis' grid with the rest of it. A plot styled to
    bleed off the window showed the divergence at its clearest: the rules stopped short of the
    right edge, where the axis' end padding is.

    The grid now follows the axis. grid still turns the rules off on their own for an axis that
    is drawn, which is what a chart wanting labels without rules already passes.

  • 66541ab - Draw the Android crosshair and selection marker wherever the scrub reaches, not only where
    the finger happens to land inside the plot.

    Both asked whether the plot contained the pointer and drew nothing when it did not, while
    the reading itself is picked off the pointer's x alone and clamped into the plot on the way.
    So a finger in any of the four bands the plot is inset by — 20dp at the leading edge, 16dp
    at the top, 24dp under the marks — moved the trace, lit the trail and reported a reading,
    and put neither a line nor a mark nor a label on th...

Read more

@hzblj/zyplot@0.2.0

Choose a tag to compare

@github-actions github-actions released this 30 Jul 14:44
a5ee991

Minor Changes

  • 54b15f6 - Give an annotation label a chip and a side that keeps it readable. labelBackground paints
    a rounded fill behind the label, so a rule's value stays legible where the marks run
    through it, and labelPosition: 'auto' picks the side from where the rule sits: above it
    in the lower half of the plot, below it higher up. Fixed sides still win when named, so
    nothing changes for annotations that already pass 'top' or 'bottom'.

  • 54b15f6 - Let a rule annotation set its own thickness. width joins dash and color on
    ChartLineAnnotation, honoured on iOS, Android and the web — the line width was pinned at 1
    in the native drawing code, so a reference line could be dashed and coloured but never made
    heavier or lighter than the hairline it started as.

    Android drew both the width and the dash lengths in pixels while they are given in dp, which
    on a 3× screen made a dashed rule a third of its asked-for thickness with a third of its
    asked-for dash; both are scaled now.

  • 54b15f6 - Put your own component where an annotation lands, with annotationViews.

    The chart already reported where every annotation ended up, and an app that wanted a logo
    at the live reading or its own head on a rule had to take it from there: hold the geometry
    in state, absolutely position a view over the plot, keep the two in step. That work was the
    same every time, so it lives in the chart now. Key a node by the annotation's id and it is
    centred on the spot, moves with the data, and the mark the chart would have drawn there is
    left out — one prop instead of an overlay of your own.

    <Chart.Line
      annotations={[
        annotation.point({ id: "live", x: live.category, y: live.value }),
      ]}
      annotationViews={{ live: <LivePrice value={live.value} /> }}
      categories={categories}
      series={series}
    />

    The annotations you leave out keep the dot, glow and pulse the renderers draw, on all three
    platforms, and nothing about the built-in marks has changed. An annotation can also be an
    anchor and nothing else: hidden: true keeps it measured and reported in geometry while
    drawing none of it, which is what a view of your own placed by hand — a card following the
    finger, say — wants underneath it.

    Charts that draw annotations but had no pointer layer to measure them (Chart.Area,
    Chart.Bar, Chart.StackedBar on the web) now report geometry on the 'layout' phase
    like the rest, so the views land there too.

  • 54b15f6 - Report where the plot and its annotations ended up, so an app can draw its own overlays
    instead of the ones the chart bakes in. Native charts now emit a 'layout' phase carrying
    geometry — the plot's box and every annotation's position, in the chart view's own
    coordinate space — and useChartScrub returns it as geometry alongside the selection,
    which also carries the pointer's nativeX/nativeY now.

    That is enough to place any React component over the chart: your own badge on an event
    annotation instead of the built-in glyph-in-a-circle, your own card at the reading under
    the finger, a logo, a button, whatever the design asks for. Leave badge off the
    annotation and the chart draws only the rule, leaving the head to you.

  • 54b15f6 - Let every entry point hand over the whole contract, not most of it.

    @hzblj/zyplot/ios and @hzblj/zyplot/android re-exported the shared types and Chart, and
    then stopped: the builders and useLastReading are values, and export type * does not carry a
    value. So the import the documentation shows for a platform file — import {annotation, Chart} from '@hzblj/zyplot/ios' — resolved at the type level and came back undefined at runtime. Both
    entries now export the fifteen builders and useLastReading alongside useChartScrub, so a
    *.ios.tsx file needs one import rather than two.

    @hzblj/zyplot/web re-exported a hand-kept subset of the shared types, and several a web chart
    actually needs were missing from it: ChartCandlestickDatum and ChartCandlestickStyle, which
    Chart.Candlestick takes; ChartRangeAnnotation and ChartTextAnnotation, two of the four
    members of the union annotations is; StyledChartSeries, what the series builder returns;
    and the small unions the documented shapes are written in terms of — ChartSymbol,
    ChartAxisScale, ChartCoordinate, ChartSurfacePadding and the rest. Typing a candle array
    or a helper that returns a range annotation meant importing from @hzblj/zyplot-core directly.
    They are all re-exported now.

    Chart.TimeSeries was also the one web form whose list prop stayed mutable: its series is
    readonly Omit<ChartSeries, 'values'>[] now, like every other list the web charts take.

  • 54b15f6 - Two knobs for reading a candlestick chart. interaction.highlightBlend says how far the
    read mark is lifted towards interaction.highlightColor, so at 0.5 a red candle lights up
    red instead of turning white — a flat replacement threw the series colour away, which is the
    one thing a candle's colour is for. style.candleRadius rounds the candle body, and rounds
    the wick's caps with it so the wick does not read as a cut-off stub against a rounded body.

  • 54b15f6 - Let the mark under the pointer light up. interaction.highlightColor draws the read mark in
    its own colour, so a scrub reads as one candle lit rather than as every other candle merely
    dimmed — dimming alone leaves the read one in its resting colour, which is hard to pick out
    against a plot that has only lost a little contrast. Implemented for candlesticks on both
    platforms, alongside the dimOpacity fix that made the rest fade at all.

  • 54b15f6 - Draw with the theme's font on iOS and Android, and read the last three theme
    colours everywhere.

    theme.typography.fontFamily reached only the web renderer before: the native
    ones decoded colors and dropped typography on the floor, so a chart beside a
    <Text> in the app's own font drew its axis labels in the system one. Both now
    resolve the family the way their platform resolves text — iOS through the
    registered-font lookup behind UIFont(name:), Android through React Native's
    ReactFontManager, which covers assets/fonts, res/font and anything
    expo-font registered at runtime. A family the app never shipped falls back to
    the platform font, exactly as a canvas does on the web. It reaches every string
    either renderer draws: axis labels and titles, tick labels, annotation labels and
    badges, rule labels, the tooltip and the gauge reading.

    Three colours were also being decoded and then ignored:

    • axis now colours the tick marks on both platforms. Android drew no ticks at
      all until now, so its ticks axis option had nothing to switch off; it draws
      them beside every label the x and y axes place, an overlaid y axis excepted —
      it reserves no gutter for one to sit in.
    • surface now fills the tooltip card. It replaces the hardcoded near-black on
      Android and the system material on iOS, which is still what a chart with no
      surface in its theme gets.
    • background now paints the plot on Android when no plot.backgroundColor
      overrides it, the order iOS already resolved in.
  • 54b15f6 - Give each theme shape a name of its own. @hzblj/zyplot/web exported two
    incompatible types called ChartTheme — the wide palette Chart.Provider takes,
    and the narrower one a chart's own theme prop takes — and the explicit export
    won, so a value annotated ChartTheme was not assignable to the prop of the same
    name.

    There are now three, and the two wider ones are supersets of the portable one, so
    a single object can be passed to any of the three props:

    • ChartTheme is the portable subset: axis, categorical, grid, label,
      negative, positive, surface, track, and typography. Every key on it is
      one all four renderers draw with. Its colours are ChartThemeColors, exported
      for building a theme up in parts.
    • NativeChartTheme adds colors.background, the chart's own fill, which only a
      native surface paints. background has moved here off ChartTheme: the web
      renderer never drew it, and the box a web chart sits on is surface.background.
    • ChartProviderTheme adds border, diverging, muted and sequential — the
      palettes and greys that only a CSS variable can carry — and is what the web
      Chart.Provider takes.

    Chart.Provider also reads the flat negative and positive now, as the
    shorthand for diverging.negative and diverging.positive. Passing the
    five-key diverging object still wins over them, so setting both is not
    ambiguous.

  • 54b15f6 - Give the pulse on a live point a rhythm, and hand it over. pulse on a point annotation
    now takes a ChartPulsecolor, duration, interval, opacity, scale — as well as
    the true it took before, and true now means one bloom of 450 ms followed by a rest of
    1550 ms, at 2.2× the point's resting ring.

    That replaces a single 1.8 s expa...

Read more

@hzblj/zyplot-core@0.3.0

Choose a tag to compare

@github-actions github-actions released this 30 Jul 20:45
2c9cf6f
@hzblj/zyplot-core@0.3.0

@hzblj/zyplot-core@0.2.0

Choose a tag to compare

@github-actions github-actions released this 30 Jul 14:44
a5ee991

Minor Changes

  • 54b15f6 - Give an annotation label a chip and a side that keeps it readable. labelBackground paints
    a rounded fill behind the label, so a rule's value stays legible where the marks run
    through it, and labelPosition: 'auto' picks the side from where the rule sits: above it
    in the lower half of the plot, below it higher up. Fixed sides still win when named, so
    nothing changes for annotations that already pass 'top' or 'bottom'.

  • 54b15f6 - Let a rule annotation set its own thickness. width joins dash and color on
    ChartLineAnnotation, honoured on iOS, Android and the web — the line width was pinned at 1
    in the native drawing code, so a reference line could be dashed and coloured but never made
    heavier or lighter than the hairline it started as.

    Android drew both the width and the dash lengths in pixels while they are given in dp, which
    on a 3× screen made a dashed rule a third of its asked-for thickness with a third of its
    asked-for dash; both are scaled now.

  • 54b15f6 - Put your own component where an annotation lands, with annotationViews.

    The chart already reported where every annotation ended up, and an app that wanted a logo
    at the live reading or its own head on a rule had to take it from there: hold the geometry
    in state, absolutely position a view over the plot, keep the two in step. That work was the
    same every time, so it lives in the chart now. Key a node by the annotation's id and it is
    centred on the spot, moves with the data, and the mark the chart would have drawn there is
    left out — one prop instead of an overlay of your own.

    <Chart.Line
      annotations={[
        annotation.point({ id: "live", x: live.category, y: live.value }),
      ]}
      annotationViews={{ live: <LivePrice value={live.value} /> }}
      categories={categories}
      series={series}
    />

    The annotations you leave out keep the dot, glow and pulse the renderers draw, on all three
    platforms, and nothing about the built-in marks has changed. An annotation can also be an
    anchor and nothing else: hidden: true keeps it measured and reported in geometry while
    drawing none of it, which is what a view of your own placed by hand — a card following the
    finger, say — wants underneath it.

    Charts that draw annotations but had no pointer layer to measure them (Chart.Area,
    Chart.Bar, Chart.StackedBar on the web) now report geometry on the 'layout' phase
    like the rest, so the views land there too.

  • 54b15f6 - Report where the plot and its annotations ended up, so an app can draw its own overlays
    instead of the ones the chart bakes in. Native charts now emit a 'layout' phase carrying
    geometry — the plot's box and every annotation's position, in the chart view's own
    coordinate space — and useChartScrub returns it as geometry alongside the selection,
    which also carries the pointer's nativeX/nativeY now.

    That is enough to place any React component over the chart: your own badge on an event
    annotation instead of the built-in glyph-in-a-circle, your own card at the reading under
    the finger, a logo, a button, whatever the design asks for. Leave badge off the
    annotation and the chart draws only the rule, leaving the head to you.

  • 54b15f6 - Two knobs for reading a candlestick chart. interaction.highlightBlend says how far the
    read mark is lifted towards interaction.highlightColor, so at 0.5 a red candle lights up
    red instead of turning white — a flat replacement threw the series colour away, which is the
    one thing a candle's colour is for. style.candleRadius rounds the candle body, and rounds
    the wick's caps with it so the wick does not read as a cut-off stub against a rounded body.

  • 54b15f6 - Let the mark under the pointer light up. interaction.highlightColor draws the read mark in
    its own colour, so a scrub reads as one candle lit rather than as every other candle merely
    dimmed — dimming alone leaves the read one in its resting colour, which is hard to pick out
    against a plot that has only lost a little contrast. Implemented for candlesticks on both
    platforms, alongside the dimOpacity fix that made the rest fade at all.

  • 54b15f6 - Draw with the theme's font on iOS and Android, and read the last three theme
    colours everywhere.

    theme.typography.fontFamily reached only the web renderer before: the native
    ones decoded colors and dropped typography on the floor, so a chart beside a
    <Text> in the app's own font drew its axis labels in the system one. Both now
    resolve the family the way their platform resolves text — iOS through the
    registered-font lookup behind UIFont(name:), Android through React Native's
    ReactFontManager, which covers assets/fonts, res/font and anything
    expo-font registered at runtime. A family the app never shipped falls back to
    the platform font, exactly as a canvas does on the web. It reaches every string
    either renderer draws: axis labels and titles, tick labels, annotation labels and
    badges, rule labels, the tooltip and the gauge reading.

    Three colours were also being decoded and then ignored:

    • axis now colours the tick marks on both platforms. Android drew no ticks at
      all until now, so its ticks axis option had nothing to switch off; it draws
      them beside every label the x and y axes place, an overlaid y axis excepted —
      it reserves no gutter for one to sit in.
    • surface now fills the tooltip card. It replaces the hardcoded near-black on
      Android and the system material on iOS, which is still what a chart with no
      surface in its theme gets.
    • background now paints the plot on Android when no plot.backgroundColor
      overrides it, the order iOS already resolved in.
  • 54b15f6 - Give each theme shape a name of its own. @hzblj/zyplot/web exported two
    incompatible types called ChartTheme — the wide palette Chart.Provider takes,
    and the narrower one a chart's own theme prop takes — and the explicit export
    won, so a value annotated ChartTheme was not assignable to the prop of the same
    name.

    There are now three, and the two wider ones are supersets of the portable one, so
    a single object can be passed to any of the three props:

    • ChartTheme is the portable subset: axis, categorical, grid, label,
      negative, positive, surface, track, and typography. Every key on it is
      one all four renderers draw with. Its colours are ChartThemeColors, exported
      for building a theme up in parts.
    • NativeChartTheme adds colors.background, the chart's own fill, which only a
      native surface paints. background has moved here off ChartTheme: the web
      renderer never drew it, and the box a web chart sits on is surface.background.
    • ChartProviderTheme adds border, diverging, muted and sequential — the
      palettes and greys that only a CSS variable can carry — and is what the web
      Chart.Provider takes.

    Chart.Provider also reads the flat negative and positive now, as the
    shorthand for diverging.negative and diverging.positive. Passing the
    five-key diverging object still wins over them, so setting both is not
    ambiguous.

  • 54b15f6 - Give the pulse on a live point a rhythm, and hand it over. pulse on a point annotation
    now takes a ChartPulsecolor, duration, interval, opacity, scale — as well as
    the true it took before, and true now means one bloom of 450 ms followed by a rest of
    1550 ms, at 2.2× the point's resting ring.

    That replaces a single 1.8 s expansion that faded to nothing with no rest between cycles:
    the ring spent almost the whole cycle nearly transparent, which read as no animation at
    all. The ring's colour is settable too, and falls back to the glow's colour and then to the
    point's own — on iOS a pulse with no glow used to inherit the glow's .clear and draw
    nothing at all.

    Android had no pulse to speak of — the parameter was threaded through the drawing code
    but nothing ever animated it — and now draws the same bloom off the same clock.

  • 54b15f6 - Make the data shapes one contract across web and native. The web entry point had
    its own copies of ChartSeries, ChartDatum, ChartTimePoints and the other
    per-form inputs, identical to the ones in @hzblj/zyplot-core except that their
    arrays were mutable. It now re-exports the core types, so a value typed once can be
    handed to a web chart and a native one.

    Every web chart prop that takes a list — series, categories, data, nodes,
    cells, groups, rows, values — now accepts a readonly array, as the native
    props and web's own Chart.Candlestick already did. Passing an as const array or
    the result of a readonly-returning selector no longer needs a cast.

  • 54b15f6 - Let the entrance name its own curve. reveal.draw and reveal.fade take an easing
    'ease-in' | 'ease-in-out' | 'ease-out' | 'linear' — and reveal.draw also takes a
    ...

Read more

@hzblj/zyplot@0.1.1

Choose a tag to compare

@github-actions github-actions released this 28 Jul 19:17
d23f46d

Patch Changes

  • ab6e55e - Add repository metadata and a bundled LICENSE file to both published
    packages. npm verifies a provenance-signed publish against repository.url,
    so the missing field left @hzblj/zyplot-core unpublishable.
  • Updated dependencies [ab6e55e]:
    • @hzblj/zyplot-core@0.1.1

@hzblj/zyplot@0.1.0

Choose a tag to compare

@github-actions github-actions released this 28 Jul 19:10
4d7ba21

Minor Changes

  • 51e9ae3 - First public release.

    Cross-platform React charting behind one package and one shared TypeScript
    contract: ECharts and uPlot on web, Swift Charts on iOS, and Jetpack Compose on
    Android, with both native renderers reached through a single Expo Module named
    Zyplot.

Patch Changes

  • Updated dependencies [51e9ae3]:
    • @hzblj/zyplot-core@0.1.0

@hzblj/zyplot-core@0.1.1

Choose a tag to compare

@github-actions github-actions released this 28 Jul 19:17
d23f46d

Patch Changes

  • ab6e55e - Add repository metadata and a bundled LICENSE file to both published
    packages. npm verifies a provenance-signed publish against repository.url,
    so the missing field left @hzblj/zyplot-core unpublishable.