GithubHelp home page GithubHelp logo

escape-llc / yet-another-chart-component Goto Github PK

View Code? Open in Web Editor NEW
2.0 2.0 1.0 1.34 MB

Yet another chart component. Also a play on the venerable "yacc" compiler tool

License: Apache License 2.0

C# 100.00%
chart-component uwp chart charts charting-library chart-library xaml

yet-another-chart-component's Introduction

eScapeLLC.UWP.Charts

Yet another chart component. Also a play on the venerable "yacc" parser-generator tool. Yes, I've used it, and know all about LR(1) parsers!

YACC is moving to the Composition Layer! Follow our new repository for progress.

Demo It!

The demo application in the solution is available in Windows Store so you don't have to build it from source.

Get It!

From Package Manager Console:

   PM> Install-Package eScapeLLC.UWP.Charts

NuGet version

Package page on nuget.org

Or Build It

If you are rebuilding the demo application and/or test projects (e.g. because you forked or cloned this repo), you must re-generate the PFX file(s), because they are excluded from repository by .gitignore.

  • In Solution Explorer, double-click the app manifest file.
  • In the Manifest Designer, go to the Packaging tab.
  • Click on Choose Certificate.
  • Follow the instructions to make a new test certificate.
  • Build away!

Screen Shot

This is the current demo chart in the solution (subject to last-minute tweaking): yacc demo screen shot

API Documentation

The details of all the classes etc. used in YACC can be found at our documentation page in the API section.

More Info

Please check out the Wiki to learn more about the guts of YACC and rendering and linear algebra in general!

Please consult the other features of this github repository to find out the current state of affairs, or to contribute.

Nuget Releases

NuGet version

1.7.0

More features and fixes.

See the Milestone page.

1.6.0

More features and fixes.

See the Milestone page.

1.5.1

Disable experimental composition animations.

1.5.0

More features and fixes. Contains breaking changes so be sure to check the milestone page!

See the Milestone page.

1.4.1

Fixes due to sizing causing ArgumentException.

See the Milestone page.

1.4.0

More features and fixes.

See the Milestone page.

1.3.0

More features and fixes.

See the Milestone page.

1.2.0

More features and fixes.

Since we were more organized this release, please see the Milestone page.

1.1.0

Some breaking changes, sorry about that! As always, consult the demo chart XAML; it's currently the reference.

  • For each following item, see the Demo Chart XAML for details.
  • PathStyle et al is the biggest break.
    • make sure to apply a Style to your chart components, or you may get "invisible"!
  • HorizontalBand new decoration. Tracks two non-series values with a fill in between two horizontal rules.
  • Background new decoration. Basic fill/stroke path of data series area.
  • ValueAxisGrid is now its own decoration, and not part of the Axis component.
  • MarkerSeries now uses a normalized coordinate system (0..1, 0..1) for the marker geometry.
    • current the marker must be a Geometry.
    • marker center is (.5,.5).
  • Major fixes to the linear algebra for the graphics, primarily impacting MarkerSeries.
  • Lots of internal fixes/improvements you won't notice.
  • Other new properties. Sorry, rely on auto-complete in VS for now.

1.0.0

Initial release.

yet-another-chart-component's People

Contributors

dependabot[bot] avatar escape-llc avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar

Forkers

haukemarquardt

yet-another-chart-component's Issues

Label Selector

Summary

Be able to provide (via XAML) a callback for label creation logic.

Actual Behavior

Not possible. All labels are always generated using a single Style from the LabelStyle property.

Expected Behavior

Supply custom logic via LabelSelector property. This receives the ISeriesItem and evaluates whether it wants a label created for it, and if so, the Style, text, etc. for that label.

Additional Details

This just reuses the existing XAML concept of "selector" e.g. TemplateSelector with the difference this implementation can select "nothing".

Actually it will receive a context interface. Also need to include the Source component. Context will receive the info it needs to create a label, or provide the method for the receiver to create one.

Reuse IValueConverter

Since we are already using IValueConverter for the other conditional label features, it makes sense to stick to that technique for this also. In this case the targetType is bool and the converter returns whether to create the label.

This also allows the same instance to be used for both LabelFormatter and LabelSelector which can allow for consolidation of logic.

Incremental Updates

Summary

To better support #46 (and for better performance) we need ability to perform incremental updates on the ISeriesItemData being tracked by all of the Series.

Actual Behavior

The unit of refresh is currently the entire data source, which causes a complete rebuild of ItemState for every Series. While the UI elements are recycled, the ItemState is not.

Sequence

  1. In the "client" code.
    1. An ObservableCollection operation occurs.
    2. Note: the collection is modified immediately.
    3. A CollectionChanged event fires with a record of what happened.
  2. In the DataSource class.
    1. ItemsCollectionChanged handler executes and calls Refresh.
    2. Note: the EventArgs get dropped here.
    3. Refresh fires the RefreshRequested event.
  3. In the Chart class:
    1. The DataSource_RefreshRequested handler evaluates and dispatches to RenderComponents.
    2. The RenderComponents method determines whether to do a full or transforms render.

Expected Behavior

Once loaded, the DataSource should have methods to incrementally update the active state. This can be done in such a way as to allow #46 to kick in and animate changes to the displayed elements.

Sequence

The sequence is identical up to DataSource_RefreshRequested with the difference of carrying the EventArgs for the collection operation all the way to the Chart. Once there, additional logic evaluates the type of collection change, and dispatches accordingly.

Additional Details

Using the commands on the demo chart as an example, these are the operations under consideration:

  • delete (position, count)
  • insert (position, count, elements)
  • sliding window: delete at head and insert at tail (count, elements)

These can all be conducted in such a way as to minimize updates to the entire chart, and #46.

Complicated by ValueLabels

This component is a decoration and not part of the DSRP, but it does maintain state. Any data-management API must work in a way that accounts for all components maintaining state related to data source.

An additional complication is ValueLabels may only partially-populate its state, based on LabelSelector, leaving "holes". This may cause problems with list operations.

This will be handled by an additional layer of update events generated by ISeriesItemDataSource. Not sure how these will propagate yet. Direct connection via events is discouraged, so the RenderContext must be responsible for brokering these updates.

Complicated by DSRP

The DSRP creates two different "flavors" of rendering, and any incremental update must deal with setting the DSRP up such that this can be done.

This is being handled internally by each series type during the incremental update, with common methods refactored into superclass for reuse.

Complicated by CategoryAxis

Since the category axis presents labels for the x-axis, it must also support (some) incremental updates. Values can be removed directly, but become added indirectly (via DSRP calls). It may be simpler to have both add/remove occur indirectly, then CategoryAxis can be left out of this scheme.

This was handled in #52 CategoryAxis is now part of DSRP. This actually works out much nicer!

Rendering

The main interface key for incremental update is IRequireDataSourceUpdates then after that, whether it implements IRequireRender or IDataSourceRenderer, the latter of which must execute first. Once this is sorted out, it proceeds like a component refresh pass.

  • no layout
  • DSRP item (e.g. DataSeries) update
    • need a way to "trigger" the incremental update from Preamble
  • other item (e.g. ValueLabels) update
    • may need refactor because there are now two ways to add geometry
  • axis extent transfer
    • x-axis for sure has extents changed
    • y-axis may have extents changed
  • axis render
  • transforms

This currently doesn't account for DSRP components that do not implement incremental updates. It may become mandatory.

ObservableCollection events

These should be analyzed and transformed into finer-grained update operations. Currently any update causes a complete refresh.

If operations can be kept minimal, the state can be manipulated in the desired way. The primary overhead is the "relocation" phase, where values and geometry get updated as the state elements "slide" to their new relative position on the Chart. Geometry updates could be minimized or eliminated by creating "zero-relative" Geometry and using Canvas offset properties for "final" placement. Doing this also enables #46 much easier.

Enhanced Event Sequence

The important piece to provide is the data from the NotifyCollectionChangedEventArgs event, which gives the actual details of the modification. Once this is plumbed in, the rest of the sequence can be more selective in its response.

  • Reset: full render.
  • Add: incremental add render.
  • Remove: incremental delete render.
  • Replace: dk not sure what triggers this.
  • Move dk not sure what triggers this.

If "sense" cannot be made from the EventArgs treat it as a full render.

Axis label enhancements

Summary

The axis labels should have an option to disable or otherwise control which labels are generated.

Expected use case is for making spark line charts, which typically have little or no axis decoration.

Actual Behavior

Not possible.

Expected Behavior

Be able to supply the "standard" pipeline hooks as ValueLabels uses.

Additional Details

Need to track previously-generated labels, to make the label logic "easier".

Category Axis Label Placement

Summary

Currently the category axis labels "squish together" as the x-axis unit (XAU) gets smaller, eventually becoming an unreadable width.

Actual Behavior

Labels become increasingly narrow and unreadable.

Expected Behavior

As available space decreases,

  • switch to a multiple-row layout, so labels can truncate less, hopefully not at all.
  • drop labels e.g. every 2nd label.

Additional Details

In extreme case, many many rows would be required if the labels are long and the XAU is small.

Using the Width trigger in the Style will "turn off" XAU bounding, but without rotation, there will be overlay of texts. In this situation, it could determine which intermediate labels to drop. This could be in addition to using multiple rows. This may not work with rotated labels.

TextBlock Clipping

To do some of this, it requires a method to determine that a TextBlock is clipping its text. Hopefully this can be determined by examining the DesiredSize vs the ActualSize and noting any difference in size.

It would be best if this can be done without attaching any events like TextBlock.SizeChanged.

Series should ignore NaN

Summary

Series should refrain from generating Geometry for values that are double.NaN.

Actual Behavior

Not sure, generates Geometry with NaN as values.

Expected Behavior

A series should leave a "blank space" in positions where its value(s) are NaN.

Additional Details

This can be used purposefully to "make gaps" in the chart with special "filler" objects.

Themes

Summary

There's no good way to enforce setting of Style for all chart elements. This will cause apparent rendering failure, but the drawing is actually invisible due to lack of styling.

Actual Behavior

If you don't style something, it probably won't be visible.

Expected Behavior

Everything generated should have a default style applied to it.

Additional Details

Create a separate ChartTheme class that can be pre-loaded in generic.xaml so there are styles to use for every chart element.

Try to auto-allocate pre-defined colors for series when no styles are applied.

Also gives ability to set themes in deployment.

Style Selector

Summary

It would be beneficial if ValueLabel elements could be dynamically styled.

Actual Behavior

Not possible. All labels get the style from LabelStyle or the default from the Theme.

Expected Behavior

Have a StyleSelector property that takes an IValueConverter and uses that to produce a Style to apply to the element.

Additional Details

Create the necessary context interface and pass that in as the target parameter, and Style for the type parameter.

The StyleSelector is applied after the element is created and configured. This is in contrast to the LabelSelector which controls the initial creation of an element.

Chart Value Labels

Summary

Create a component that can display a single value, e.g. that produced by a chart decoration like HorizontalRule.

Actual Behavior

Not possible.

Expected Behavior

Instead of targeting a DataSeries this component targets another ChartComponent that exposes the correct interface for making labels.

Additional Details

Use the item state infrastructure so HorizonalRule etc. can expose data for labels that way. Can use axis-half-width in x-axis, and label-half-dimension in y-axis. This would place (0,0) in chart center with text centered over the y-value. Stick to half-dimension coordinate system for label placement as much as possible.

Each value gets exposed as a channel, so HorizontalBand has one series value with two channels.

Horizontal Band

Summary

Similar to the horizontal rule, have a component that presents a band as a filled rectangle of appropriate height.

Actual Behavior

No such component.

Expected Behavior

Display min/max limits with fill in between.

Additional Details

Needs same control properties as horizontal rule.

Value Label Positioning Errors

Summary

There is some error in positioning the FrameworkElement

  • on initiali entry to the visual tree,
  • when the element is recycled, and the text changes in a way where its ActualWidth changes.

Actual Behavior

Because the XAML Measure and Arrange cycle occurs in a separate unit-of-work, it's not possible to reliably ascertain its ActualSize in the UOW where InvalidateXXX are called.

This manifests itself as mis-positioned text labels; in particular, the Canvas.Left property may be set incorrectly, due to the race condition described above.

Expected Behavior

Bite the bullet and attach the SizeChanged event, and save enough bookkeeping to re-create the "real" positioning when that event actually fires.

Additional Details

If the size does not really change (even if Text does), the SizeChanged event does not fire. This provides a minor complication for Transforms; it must force a positioning "just in case" the event is not triggered.

Actually, it only requires to force a measure/arrange pass, if we are in a full render, otherwise it is sufficient to update the current position based on the transforms.

Integer values broken

Summary

When binding to a non-double value, you get Exception.

Actual Behavior

As described.

Expected Behavior

It should work by coercing values to double.

Additional Details

All series need this processing as necessary.

Value Label Clipping

Summary

Provide some control over whether and how value labels are clipped.

Advanced from #27.

Actual Behavior

Value labels currently have no clipping behavior.

Expected Behavior

There should be a mode whereby the labels are re-located if they fall "outside" the chart area. There are currently two choices (via ClipToSeriesArea), but there should be more choices

Now there should be these choices:

  • No clip: the TextBlock is allowed to overlap anything. Same as ClipToSeriesArea false.
  • Clip: the TextBlock is clipped to the series area. Same as ClipToSeriesArea true.
  • Nudge: the TextBlock is moved the minimum distance required to place it in the series area.
  • Extend: the value axis is extended enough units to prevent the label from clipping.

Could handle nudging the following ways:

  • actually expand axis extents to include the overflowing edge of label.
  • track "overflow" claims and allocates this extra space internally. this would have to cascade to data series area so that lines up, so probably not too doable.
  • build some padding into axes to account for the overflow area explicitly.

Additional Details

The Clip property for UIElement et al seem to apply to the internal coordinates, i.e. setting Path.Clip does not work this way, but clips the path against the given Rect as expected.

The ClipToSeriesArea code does not seem to work properly when run on a Windows Phone Emulator not sure why.

Layout enhancements

Summary

The layout phase must be aware of the overall size of the Chart bounds, and refuse to allocate excessive space to claims.

This effect is acute when displaying on the small screen of a phone platform.

Actual Behavior

The claims for space may exceed the bounds, and ultimately generate an ArgumentException when attempting to create a Rect with negative size.

Even if there is no overflow, claims may result in an undesirably small data area.

Expected Behavior

The layout phase places limits on amount of space a claim makes, and only grants up to the limit. It should attempt to preserve majority of space for the data area.

There should also be error info generated.

Additional Details

Any IRequireLayout implementation must be able to detect whether it got short-changed on its claim, and react accordingly.

For example an axis may not have sufficient space to display labels, and may suppress them.

Series Value Labels

Summary

Currently no way to display value labels on chart.

Item Split

This item has been split; its continuation items are:

Related info has been moved there.

This item now only includes "simple" positioning, and none of the "other" functionality, which may get split into another item as well.

Actual Behavior

Not possible.

Expected Behavior

Architecture dictates this is a separate component (series value labels), which is tied to a data source but instead of managing and laying out a Path, it uses TextBlock.

This is an IDataSourceRenderer component (but not a DataSeries subclass), because it needs access to data source values.

Change

Make this a "true" decoration and add feature for series to expose item state they already maintain. This gives a better chance for filtering and styling, once all values are captured and axis extents known.

In IRequireRender, traverse the SeriesData property to access the series values and generate labels. Also eliminates most of the properties, which will come instead from the referenced IProvideSeriesData.

Simple Positioning

This adjusts the relative position of the TextBlock wrt the actual data point. LabelOffset determines final positioning, with TextBlock center point (0.0,0.0) and units of half-dimension of the TextBlock.

This uses the "sandwich" transform to compute the final coordinates needed for the Canvas attached properties. Label Canvas coordinates get recomputed in Transforms anyway, so no big deal.

Additional Details

Making this independent of the series gives precise control to layering, which can be important when multiple series are crowded together.

Grouping

It may be desirable to have a collection of series label items, or somehow link together the z-index order of multiple label series TextBlock elements.

Visibility Selector

To customize the display of labels, e.g. display first/min/max/last labels, allow for a Converter that can provide visibility information. Possibly provide some "built-in" ones, see example in earlier sentence.

Style Selector

Allow for a Converter that can provide Style information. May be the same implementation that handles Visibility.

Label Selector

Combine the above individual items into a single selector that controls all aspects of label generation.

Use Styles for "everything"

Summary

Move all the Path styling to Style dependency properties on components.

Actual Behavior

Have to manually set properties like Stroke and Fill on the components, and possibility to style anything on Path is easier than proxying the corresponding properties.

Expected Behavior

Have a property PathStyle that can have a Style attached to it for geometry.

Additional Details

None.

Series Hinted Positioning

Summary

This item is a continuation of the Value Label Series item, to implement series hinted positioning.

Any related information from that item has been advanced into this one.

Now goes with item 35, because hints will come from the item state, via auxiliary interface.

Actual Behavior

After completing the previous VLS item, this component now has the ability to perform "simple" placement of value labels, based on the "value location" like a TextBlock version of a marker.

Expected Behavior

Support the enhanced "series hinted placement" mode.

Additional Details

Retain the details related to this item, from the original.

Component can be linked to an existing ChartComponent, so it can obtain "hints" from it, in the form of geometry information, e.g. the Rectangle of a columns series bar, the "vectors" of adjacent points of a line series point.

The hint information is used to customize the positioning in a context-sensitive way, e.g. the "middle" of a bar. This is very important with stacked series types, where each sub-series has its own Geometry.

A ChartComponent should opt-in to providing hints, by implementing the IProvidePlacement interface. The labels component has a SourceName property to link it to the source.

In this mode, there are other properties that require values, like PlacementOffset. The most-likely meaning is altering the implied "start point" of the label placement, e.g. the "top end" of a rectangle bar, or "under" a line segment pointing "downwards".

Split series area

Summary

Allow subdivision of the series area for stacking multiple series with the same category axis.

Actual Behavior

Not possible.

Expected Behavior

Define subareas and use a property to link a ChartComponent to its area. Same for axes.

Additional Details

Since everything is tied to an area, just give that thing a Components collection to put the pieces in. Only thing that would site "outside" is the x-axis component.

Clipping to Data Region

Summary

Some ChartComponents clip to the data region, and some don't. Unify this behavior, and put it under user control.

Actual Behavior

E.g. the LineSeries does not apply a clip region to its path(s), but others do.

Expected Behavior

All ChartComponents that "draw" into the Data Region, must provide for a clipping region. A bool property ClipToDataRegion shall control this behavior.

Additional Details

In some cases, allowing for overflow of graphics is desired, if those overlaps are infrequent and small.

E.g. a LineSeries with a large StrokeThickness and round LineJoin and/or LineCap may clip the rounded line joins and/or caps, when the values are near the axis extents. Disabling ClipToDataRegion preserves the visual appearance. On the other hand, the series may draw significantly outside the data region.

E.g. a MarkerSeries does not account for the marker's size when mapping the value axis, so markers will clip at the axis extents. Disabling ClipToDataRegion allows full marker display, at the expense of overflow to adjacent UI elements.

Relax checks for DSRP

Summary

The Chart implementation currently checks for DataSeries before checking for the DSRP interfaces. This must be relaxed so any ChartComponent can connect to DSRP.

Actual Behavior

A new component must subclass DataSeries to connect DSRP, but the new ValueLabelSeries doesn't really need even that much, even though it implements IDataSourceRenderer.

Expected Behavior

Just implementing the DSRP interfaces is enough to get connected, there is no need to check for DataSeries beforehand.

Additional Details

Make sure this doesn't have negative impact on Chart internals and its render pipeline.

Style Generator

Summary

Have a way to dynamically style a path based on values in the series, or by a simple algorithm independent of the values.

Actual Behavior

Not possible.

Expected Behavior

A ChartComponent may have a StyleGenerator property that can assign "new" styles to elements. This also includes rotating through a finite set of styles.

Additional Details

An abstract class is used to represent the base of generators.

Not to be confused with a Style Selector, which takes in some state, and selects a Style based on information within the state.

Stacked Bar Series

Summary

Implement this series type. Positive values stack up, negative values stack down. Requires a collection of the individual items and their render parameters like Fill etc.

Actual Behavior

Not present.

Expected Behavior

Have a StackedColumn series component. It has a Stack collection, where each element describes the ValuePath and PathStyle etc. of that component of the stack. This essentially represents N series, conveniently arranged in a "stack" by values.

Positive values stack "up" from zero; negative values stack "down".

Additional Notes

Need multi-item support from the Legend subsystem, because this series type represents multiple values in one graphic.
There are also other series types that can use multi-item legends, e.g. PieSeries.

Paths

This must be multiple Shape elements stacked up, because Geometry cannot be styled.

Computed Values

Summary

Chart user should be able to "piggyback" their own calculations onto the built-in data traversal mechanism, e.g. a moving-average.

Actual Behavior

Not present.

Expected Behavior

Define the "function" via XAML, and somehow wire it into the yacc:Chart.DataSources element. Custom calculations should derive from a common base class.

Once wired in, a series can reference it in the usual way.

Additional Details

Integrate the calculated values via data binding.

Rotated Category Axis Labels

Summary

It should be straightforward to configure rotated category axis labels. Simplest example is rotated 90 degrees cw/ccw.

Actual Behavior

Mostly possible using only Style and configuring a RenderTransform with appropriate TransformGroup.

Labels clip as chart width becomes smaller, due to the Width forcing of CategoryAxis on its TextBlock labels.

Expected Behavior

Rotated labels should not clip as the XAU changes size.

Additional Details

To trigger this behavior, the chart author simply includes a Setter in the LabelStyle for the Width property, with the value Auto. The axis label layout logic uses this as a signal to alter the placement of labels for a RotateTransform. Also important, it keeps the layout from changing the Width property so the TextBlock does not clip as the XAU gets smaller.

Data area background

create a component that applies a background brush to the data area of the chart. if a full background is desired, just apply one to the Chart itself.

Series Item State

Summary

To facilitate a better implementation for labels, and to provide external access to the chart data, create a means for series components to share their collected state and geometry.

Actual Behavior

Not present.

Expected Behavior

An interface IProvideSeriesItemValues with property SeriesItemValues that's an IEnumerator<ISeriesItem> provides forward read-only access to items. Additional interfaces like ISeriesItemValue provide more details on the actual value(s).

Additional Details

Rewrite the labels to use this facility, instead of participating in DSRP. This will leverage the "processing" done by the series component, that's currently duplicated in labels.

Layers for component rendering

Summary

Things are finally getting too complex for an all-in-one-Canvas architecture. It's time to introduce Layers.

Actual Behavior

Everything piles into one Canvas element. Transforms are more complex, because they have a translate component. A component cannot easily work in NDC within that rectangle.

Expected Behavior

Introduce a Layer implementation for a proxy to the VT that ChartComponent subclasses can use. Everything VT-related goes through this implementation. A "degenerate" implementation can just proxy the existing organization, but a different implementation may provide a Canvas per component.

New notification in the render pipeline; the IRequireLayoutComplete interface. This gives components opportunity to see their "final" layout Rect before rendering begins. The idea is the component can position and size its Layer accordingly there.

Additional Details

Instead of putting paths directly in via Context interfaces, they are managed through Layer. This gives a ChartComponent subclass a "container" to manage its VT element in, and the Chart can determine the packaging for the Layer.

Change IEnterLeaveContext to use Layer instead of directly implementing VT methods like Add.

The Chart must now cache a layer of information besides the Size.

  • the overall DefaultLayoutContext that corresponds to the Size.
  • allocated Layers a component has.

This can also be used during a transforms render or refresh request render.

Series Custom Labels

Summary

It would be beneficial to allow a DataSeries to expose additional domain values that can be used for labels.

Actual Behavior

Not possible. Labels can only be formatted directly from the underlying values.

Expected Behavior

The DataSeriesWithValue should have another property to specify the domain object path to a "custom label" value. This value is exposed within the channel for ValueLabels.

Additional Details

Value is treated as a simple String. No LabelFormatString is applied in this case.

Horizontal Rule

chart component for the "horizontal limit" type lines. these could be created by making additional values that are constant, but it's easier from a path standpoint to just build these directly. also provides opportunity for enhanced visuals.

Need to allow for:

  • controlling clipping, e.g. rule is "off the chart" due to data values
  • exposing to value axis, e.g. to ensure the rule is visible on the chart

Value Axis Enhancements

Summary

The value axis only presents on the vertical dimension (left/right) of a chart. Now that category axis can present on both dimensions of the chart, the value axis should follow suit.

Actual Behavior

The framework is unable to create charts that use a horizontal value axis, e.g. a timeline. A timeline can be "simulated" with a category axis, but the relative distance between dates is not depicted accurately.

The framework is unable to create additional horizontal chart types, e.g. bar histogram.

Expected Behavior

Framework provides value axis types for int long DateTime and numeric types in both orientations.

Additional Details

Each specialized continuous axis may provide properties that allow for easier customization, e.g. a DateTimeAxis may have calendar-related convenience methods.

Attempt to integrate the "orientation" into the series implementations, i.e. the ColumnSeries orients its geometry accordingly.

Marker template

Summary

Currently marker template is assumed to be a Geometry and a Path is created internally. Allow a marker to be any kind of visual element, e.g. Image, in addition to Path.

Actual Behavior

Must specify Geometry for the marker.

Expected Behavior

Would like to put an Image (or other UIElement) in and have it placed appropriately.

Using Path as a Marker

At minimum, directly specify a Path element to use as marker. In this case an internal one is not created, but the Data.Transform is still handled. These also get recycled in the usual way.

This is also the way to bypass the internal style mechanisms.

Additional Details

See if Path.RenderTransform does what we want, and then it can work for anything inside a DataTemplate.

Error Reporting

Summary

There are a number of places where execution "short circuits" due to null checks, e.g. a mis-configured axis name or binding path on a series. The chart developer won't have a good way to see these configuration errors.

Actual Behavior

Mysterious rendering failure with no clear feedback what happened.

Expected Behavior

An event handler or ObservableCollection that provides error feedback.

Additional Details

Try to use the Validator from DataAnnotations infrastructure, to surface that information.

Data Templates for Labels

Summary

Be able to supply a DataTemplate to create TextBlock (or more complex) elements.

Actual Behavior

There's a certain amount of hard-coded stuff when creating TextBlock elements in multiple places. This deprives user of an opportunity to control element creation.

Expected Behavior

Some kind of DataTemplate with a view model attached.

Additional Details

Making a DataTemplate gives opportunity to provide more "decoration" to a label, e.g. putting a Border around it, other visual elements, add triggers etc.

Unfortunately, this also requires supplying a view model to bind to, because ElementName bindings do not work in a DataTemplate. Still looking into what should go into that VM.

Enhance Demo

Summary

The next release of the Demo Application should contain examples of the new features.

Actual Behavior

As written.

Expected Behavior

As written.

Additional Details

Also show how to use x:Bind in addition to Binding.

Markers

Summary

Marker coordinate system is kludged, finish up the design.

Actual Behavior

Marker coordinates are hard-coded based on idk look in the code. The coordinates of one axis are dynamically adjusted in Transforms.

Expected Behavior

MarkerSeries has a MarkerOffset property, but no MarkerWidth to establish the "actual size" of the marker's bounding box. This should establish a "square" coordinate system in which markers can be specified in NDC. The bounding box should be centered on the data point. There may be a way to offset this, based on the marker's origin, which will default to (.5, .5) in NDC.

Additional Details

Figure out how to use composite transform so we can avoid the re-computation in Transform of each marker's coordinates. Alternatively (less preferred), contain each marker in a Canvas which serves the purpose of resetting the coordinates.

Also see if we should change marker to a ControlTemplate instead of a DataTemplate. Or use a VM with the data template, and control coordinates that way.

Refresh optimization

Summary

When a value external to the DSRP changes, it causes too much recalculation.

Actual Behavior

For example, when a HorizontalRule.Value DP change triggers a refresh, other components get triggered as well. This is multiplied by number of such objects in the chart.

Expected Behavior

An instance of IDataSourceRenderer must not trigger a value refresh (the DataSource does), so we only need to consider instances of IRequireRender.

Since a data value changed, we need to re-run limit updates so the new value is accounted for, then run IRequireTransform phase on everything so they can adjust to (possibly) changed limits.

Additional Details

Need a parameter to the Refresh event, so sender can classify their request:

  • value dirty
  • transforms dirty
  • layout dirty

Each value may be handled specifically by receiver to optimize.

DP notify is an asynchronous context; receiver must dispatch update action on a separate unit of work.

ColumnSeries make Path per bar

Summary

The bar series should be able to put each bar into a separate path, so the Fill applies individually to bars, and not "spread out" across the entire chart, e.g. a linear gradient.

Actual Behavior

Since all bars are in one Path, the Fill applies across all of them.

Expected Behavior

Each bar has its own Fill applied separately.

Additional Details

Should be able to select the desired behavior, or make a different component.

Value Axis Grid Scaling

Summary

Implement axis scaling for gird lines/tick marks.

Actual Behavior

Currently the layout of grid is not optimized for small ranges.

Expected Behavior

Re-calculate the grid interval based on log_10(Range), then subtract one and re-exponentiation 10^(x) as the grid interval. This always attempts to have a uniform number (10) of grids on the chart, subject to "rounding" at the "ends".

Grid Interval Example

If the range is 10, then the grid interval is 1: log_10(10) = 1, 10^(1-1) = 10^0 = 1.

Additional Details

Zero should be the origin if min/max are different signs. Otherwise, start at the "nearest" multiple to range-center, according to the log calculation above.

Adjust for Grid Interval

May allow axis to "round up" its limits to nearest grid interval. This can be used to "force" a grid line at the axis extents.

With given example, the range is 10 but the min is -8.88, so the axis may round that "down" to the nearest grid interval, which is -9. At the other end the max is 2.22, so it may round that "up" to 3.

Pie Chart

Summary

Implement this chart type.

Actual Behavior

Not available.

Expected Behavior

Have a DataSeries that presents a collection of arc wedges arranged in a circle. Each wedge is proportional to its percent contribution to the total of all values.

Labels

Expose one item for each value presenting in the chart. Each item has two channels:

  • the value
  • the percent contribution

May want to apply a converter somewhere in the mix, maybe at the label component.

Legend

Because each data element is an implicit group, this component does not know the Legend items (nor their styles) ahead of time, unlike all other series types. Must implement IProvideLegendDynamic interface that the Chart will attach, so it can maintain its own LegendItems collection.

Additional Notes

Use StyleGenerator subclass to allocate colors to the wedges. Use the built-in list of brushes from Chart to start with.

HorizontalBand.Value2PathStyle

Summary

Add a separate Style for the second rule of the band. This is useful when the two rules "flip". May want to consider an alternate band style when this happens.

Actual Behavior

Both rules use the same Style.

Expected Behavior

Set the Value2PathStyle if a second style is desired, otherwise it will fall back to PathStyle for both rules.

Additional Details

None.

Cache layout state

Summary

Currently there is lots of re-calculation of layout information for "partial" renders that don't require a "real" layout pass.

Actual Behavior

Chart makes no effort to retain the information from previous layout passes.

Expected Behavior

Chart must be intelligent about retaining the layout state, to make it more efficient during partial renders.

Additional Details

In particular Layer info and layout Rect info should be cached for use any time a partial render is needed.

Label Format signature change

Summary

Having the two components of the LabelFormatter converter makes the logic inside the converter very "inconvenient" e.g. the "same" logic must be duplicated for each "branch" when returning both a Style and a new String.

Actual Behavior

IValueConverter must program separate branches for each value requested.

Expected Behavior

One call gets it all. Return a null in a "slot" to skip any modifications to that component.

Additional Details

Just going with Tuple<Style,String> as the targetType for the new call.

Also impacts #50 which will also use the new call scheme.

Breaking

  • in any LabelFormatter implementation, combine the two cases for Style and String into one case for Tuple<Style,String>
  • if previously handling only one of the two cases, supply null for the "missing" one.

Custom Value Formatter

Summary
It would be beneficial if a DataSeries or ValueLabels could generate formatted data in addition to any actual values.

Actual Behavior

Limited to just the value as formatted by the LabelFormatString property, and this is on the "receiving" side of the data, so any opportunity to act on the original data source object is lost.

Expected Behavior

Additional Details

Attach this behavior to existing #45.

The Source data is available for traversal, but only via iteration, so "look ahead/back" type operations are very awkward. This makes it limiting to do from ValueLabels, even though it could just materialize any iterator if indexed operations are required. Doing it in ValueLabels also keeps everything in the "same element" and easier to keep track.

If done in the DataSeries this would have to be exposed as another value channel for ValueLabels to attach to its XAML labels DataContext. This would be a good feature on its own, to simply provide an additional custom field for labels.

"Formatted data" could take one of these forms:

  • a simple String value
  • the ISeriesItemValue that originated the label
  • the "original" data object to use as DataContext to a DataTemplate

Either way, the returned value is attached to the DataContext of whatever gets created for the label. Author must ensure their "formatter" output agrees with their choice of label XAML.

If not receiving a String the DataTemplateShim must expose the Original as another property in its VM, for access via LabelTemplate.

Series Last index clipping

Summary

The width of the last category axis column is not calculated correctly.

Actual Behavior

In the example chart, the last bar is truncated. Adjusting wider reveals it completely, adjusting narrower clips right then left bars become invisible.

Line and Marker are not affected.

Expected Behavior

No resize artifacts on the last column.

Additional Details

Appears only on bar series. It looks like category axis is not calculating maximum correctly.

Line Series and NaN

Summary

The LineSeries does not correctly handle multiple sequences of double.NaN in the series data.

Actual Behavior

Not sure, but probably stops generating geometry, or generates invalid geometry.

Expected Behavior

Render multiple line segments as required.

Additional Details

Will require one PathFigure for each segment. Currently only makes one.

Layout throws ArgumentException

Summary

On phone, the demo application triggers an ArgumentException in the Chart during layout, when the Padding exceeds the actual dimensions.

This occurs when clicking to open the sidebar panel, because it "shrinks" the Chart in one dimension beyond its padding.

Actual Behavior

Shrinking the Chart to a size where the Rect width and/or height becomes less than zero triggers an ArgumentException from the Rect constructor.

Expected Behavior

Not.

Additional Details

Precondition the constructor call. Specifically, ignore any padding when it would compromise the size of the Chart bounds.

Any layout issues should be reported to the error info handler.

Candlestick Series

Summary

An advanced presentation is a candlestick series, commonly used to visualize OHLC (open-high-low-close) data, e.g. stock market data.

A "stick" has the following elements:

  • upper shadow (high) line segment with optional tick mark
  • real body (open/close) rectangle
    • trend up (close gt open) fill color 1
    • trend down (close le open) fill color 2
  • lower shadow (low) line segment with optional tick mark

Actual Behavior

Not present.

Expected Behavior

New series type that accepts the four value members, and renders accordingly.

Additional Details

Check common usage for the actual visualization behavior, e.g. "reverse" polarity.

Enhance Demo

Summary

It's hard to work on new chart features by jamming everything into one chart.

Actual Behavior

Everything is jammed into one chart.

Expected Behavior

Be able to have multiple charts with more focused demos.

Additional Details

Some simple view-switching would be nice. Some real data would be nice too.

Legend

Provide an ObservableCollection for XAML binding to create a legend. This way no specialized chart component is necessary, and can be "overlaid" with the chart, via Canvas or RelativePanel.

The objects provide basic information for binding purposes: color, title. Additional VM data may be supplied by a LegendData property on the series component.

Layer Animations

Summary

It would be super-cool if the chart used animations.

Actual Behavior

Wishful thinking....

Expected Behavior

Sweet creamy goodness.

Additional Details

Initial experimentation with putting ImplicitAnimations in the Layer implementation were very promising, because the Canvas properties are implicitly animated via the Visual.Offset.

The result with the demo chart indicates that all the TextBlock and other elements that use the Canvas.Left and Canvas.Top attached properties are handled out-of-the-box. This was "fun" because you could see how the path-recycling was working, but the motion was not "coordinated" because of mismatch between the recycled items, and the ItemState that got re-generated for it.

All this leaves is to provide composition animations for everything that's a Path, because those are positioned via Transform and not Canvas. See #53 for more details on arranging Path to use Canvas offsets.

Handled by Layer

After more experimentation, it's determined the Layer implementations are the place to consolidate access to this feature. Then a ChartComponent subclass may have an IsCompositionEnabled property to control behavior on per-component basis. This cascades to the Layer creation on entry to the VT.

Narrow Scope

This item is now only going to cover the implementation of the Layer and not individual components. Still experimenting with how to specify; either regular DPs or use attached property mechanism.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.