简体   繁体   English

ItemsControl条形图缩放条形图

[英]ItemsControl Bar Chart Scaling of the bars

EDIT: added code 编辑:添加代码

Also since the DateTimes are not really Datetimes (sTrings in hh:mm:ss format) i decided to just use Strings instead and use TimeSpan to retrieve the totalMinutes. 此外,由于DateTimes不是真正的日期时间(shrings in hh:mm:ss format),我决定只使用字符串并使用TimeSpan来检索totalMinutes。

<ObjectDataProvider x:Key="odpLbGrafiek" ObjectType="{x:Type myClasses:GrafiekBar}" MethodName="GetDataGrafiek"/>

    <DataTemplate x:Key="GrafiekItemTemplate">
        <Border Width="Auto" Height="Auto">
            <Grid>
                <Rectangle StrokeThickness="0" Height="30"  
                           Margin="15" 
                           HorizontalAlignment="Right" 
                           VerticalAlignment="Bottom"
                           Width="{Binding Value}"
                           Fill="{Binding Fill}">
                    <Rectangle.LayoutTransform>
                        <ScaleTransform ScaleX="20" />
                    </Rectangle.LayoutTransform>
                </Rectangle>
            </Grid>
        </Border>
    </DataTemplate>

The Fill actually gives the size on the bar of the bar chart iself. 填充实际上给出了条形图上栏的大小。

The itemsControl: itemsControl:

<ItemsControl x:Name="icGrafiek"  
            Margin="20,3,0,0" 
            ItemsSource="{Binding Source={StaticResource odpLbGrafiek}}"
            ItemTemplate="{DynamicResource GrafiekItemTemplate}" 
            RenderTransformOrigin="1,0.5" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.RowSpan="6">
            <ItemsControl.RenderTransform>
                <TransformGroup>
                    <ScaleTransform ScaleY="-1" ScaleX="1"/>
                    <SkewTransform AngleY="0" AngleX="0"/>
                    <RotateTransform Angle="180"/>
                    <TranslateTransform/>
                </TransformGroup>
            </ItemsControl.RenderTransform>
        </ItemsControl>

The following method gets called in the databinding. 在数据绑定中调用以下方法。 There the bar.Value gives the value for the Width value in the datatemplate that gives the size of a bar. bar.Value给出了datatemplate中宽度值的值,该值给出了条形的大小。

    public ObservableCollection<GrafiekBar> GetDataGrafiek()
    {
        var converter = new System.Windows.Media.BrushConverter();

        Double maxValueStilstanden = GetLargestValueStilstanden();

        TimeSpan tsMaxValue = TimeSpan.Parse(maxValueStilstanden.ToString());
        totalMinutesMaxValue = tsMaxValue.TotalMinutes; 

        //calculate % of stilstanden Values
        foreach(String t in stilStandenList)
        {
            TimeSpan ts = TimeSpan.Parse(t);
            Double totalMin = ts.TotalMinutes;

            totalMin = totalMin / totalMinutesMaxValue * 100;

            valuesChartPercentage.Add(totalMin);
        }

        for (int j = 0; j < valuesChartPercentage.Count; j++)
        {
            GrafiekBar bar = new GrafiekBar();
            bar.Value = valuesChartPercentage[j];
            bar.Fill = converter.ConvertFromString(kleuren[j]) as Brush;
            listGrafiek.Add(bar);
        }

        return listGrafiek;
    }

Another problem is actually the Width (size of the bar). 另一个问题实际上是宽度(条的大小)。 I actually have to do * 10000 to get any visual of the bar itself. 我实际上必须做* 10000来获得酒吧本身的任何视觉效果。


I am using a ItemsControl that is styled so it looks like a bar chart. 我正在使用一个样式的ItemsControl ,所以它看起来像一个条形图。

So for example a array with 5 values going from 1 to 5 creates 5 bars with different bar sizes and with each a different colors. 因此,例如,具有从1到5的5个值的数组创建具有不同条尺寸的5个条,并且每个条具有不同的颜色。 Much alike the following example http://www.c-sharpcorner.com/uploadfile/mahesh/bar-chart-in-wpf/ 以下示例非常相似http://www.c-sharpcorner.com/uploadfile/mahesh/bar-chart-in-wpf/

The problem: 问题:

My problem is with the scale sizing of the bars (the width property in this case, so int/double value are required). 我的问题是条形的缩放大小(在这种情况下为width属性,因此需要int / double值)。

  • My program records several DateTimes in HH:mm:ss format 我的程序以HH:mm:ss格式记录几个DateTimes
  • The bars should be scaled on these datetimes 应在这些日期时间缩放条形

For example i could have a bar with 01:22:11 or a bar with 00:01:11 up to a max amount of 6. 例如,我可以使用01:22:11的条形图或00:01:11的条形图,最大金额为6。

What would be the best approach of scaling these DateTime values to a certain double value? 将这些DateTime值缩放到某个double值的最佳方法是什么? This value will be used to give the size of a bar on the chart. 此值将用于给出图表上条形的大小。

Guess i am looking for some kind of calculation that calculates all my values just the same, so i do not suddenly get a value that is insanely large and goes out of my UI. 猜猜我正在寻找某种计算方法来计算我所有的值,所以我不会突然得到一个非常大的值并且超出我的UI。

The most clean solution would be that all bars are compared to each other and when one changes the other one grows / shrinks, but that is not required as of yet though unless its not as complicated as it sounds. 最干净的解决方案是将所有条形图相互比较,当一个条形图发生变化时,另一个条形图会增大/缩小,但这并不是必需的,尽管它不像听起来那么复杂。

The bar char itself does not need to be overly precise, it only serves to get a general picture of the situation. 条形码本身并不需要过于精确,它只能用于了解情况的一般情况。 The exact values will be written in a database. 确切的值将写入数据库中。

Any suggestions are most welcome! 欢迎任何建议!

Thanks PeterP. 谢谢PeterP。

Normalise. 规范化。

  • Convert total time to seconds. 将总时间转换为秒。
  • (Divide total available width by total time) = factorA (将总可用宽度除以总时间)= factorA
  • to find the proper width of each bar, multiply its time by factorA 要找到每个条的适当宽度,请将其时间乘以factorA

EDIT: pick a suitable date/time to measure zero from, or you could use just use the total seconds property of your DateTime objects 编辑:选择一个合适的日期/时间来测量零,或者你可以使用你的DateTime对象的总秒数属性

I would pick a base date, and make your collection graph the number of days/hours/minutes between the base date and the data date 我会选择一个基准日期,并使您的集合图表显示基准日期和数据日期之间的天数/小时/分钟数

You might even be able to do this with a converter, where you pass the base date in as a converter parameter. 您甚至可以使用转换器执行此操作,您可以将基准日期作为转换器参数传递。

Your two example dates ( 01:22:11 and 00:01:11 ) are actually times, so in that case I'd just graph the number of minutes since 0, so your actual data values to graph would be 82 and 1 你的两个例子日期( 01:22:1100:01:11 )实际上是时间,所以在这种情况下,我只是绘制了自0以来的分钟数,因此您对图表的实际数据值将为82和1

In response to your edit asking about scaling, you would be graphing everything as a percentage. 为了回应您关于缩放的编辑问题,您将以百分比形式绘制所有内容。 In that case, take the largest number and graph every other number based on a percentage of the largest number. 在这种情况下,请根据最大数字的百分比取最大数字并绘制每隔一个数字的图表。

So using your two example times, I would convert them to the numbers 82 and 1, take the larger number (82) as 100%, and return a list which contains the percentage of every number to 82, so the return list would contain 100% and 1.2% (1/82). 因此,使用您的两个示例时间,我将它们转换为数字82和1,将较大的数字(82)转换为100%,并返回包含每个数字的百分比的列表为82,因此返回列表将包含100 %和1.2%(1/82)。

You can still do this in either the ViewModel or an ItemsSource Converter (converter would take entire list as a parameter, and return an entire list for the return value) 您仍然可以在ViewModelItemsSource Converter中执行此操作(转换器将整个列表作为参数,并返回整个列表以返回值)


Edit 编辑

In response to your comments below, here is how I would set it up using a Converter on the ItemsSource . 为了回应您下面的评论,以下是我如何使用ItemsSource上的Converter进行设置。 A converter simply takes a data value, and converts it into another value which is specific to the display UI only. 转换器只需获取数据值,并将其转换为仅适用于显示UI的另一个值。

The initial XAML would look like this: 最初的XAML看起来像这样:

<ItemsControl ItemsSource="{Binding MyCollection, 
    Converter="{StaticResource MyTimeConverter}}" />

where MyCollection is an ObservableCollection<DateTime> , and MyTimeConverter does the following: 其中MyCollection是一个ObservableCollection<DateTime>MyTimeConverter执行以下操作:

  1. Cast the passed in value as ObservableCollection<DateTime> , since all converter parameters are passed in as object 将传入的valueObservableCollection<DateTime> ,因为所有转换器参数都作为object传入
  2. Loop through the collection and figure out the largest time 循环收集并找出最大的时间
  3. Take the largest time in the collection, and figure out how many minutes it has. 花费最多的时间在集合中,并计算它有多少分钟。 This will be your 100% value that you will base all the other times off of, so store the number of minutes your largest time has in a variable 这将是您基于所有其他时间的100%值,因此存储您的最大时间在变量中的分钟数
  4. Create a new List<decimal> for the return value 为返回值创建一个新的List<decimal>
  5. Loop through starting collection. 循环开始收集。 For each time in the collection, divide it by the "100% value" that you stored in step 3, which will give you the percentage of how long that bar should be compared to the largest value. 对于集合中的每一次,将其除以您在步骤3中存储的“100%值”,这将为您提供该条与最大值进行比较的百分比。 Add this percentage to the return List<decimal> 将此百分比添加到返回List<decimal>
  6. Return List<decimal> to the ItemsControl . List<decimal>返回到ItemsControl This List<decimal> will be used as the ItemsSource instead of the actual ObservableCollection<DateTime> List<decimal>将用作ItemsSource而不是实际的ObservableCollection<DateTime>

This means that your ItemsControl is now bound to a collection of decimals, where one value is 100% and will take the full width of the screen, all other values are scaled to the maximum value. 这意味着您的ItemsControl现在绑定到一个小数集合,其中一个值为100%并将占据屏幕的整个宽度,所有其他值都缩放到最大值。

Regarding your question about using a timer to update the collection, your timer should update the ObservableCollection<DateTime> called MyCollection that the ItemsControl is bound to. 关于使用计时器更新集合的问题,您的计时器应更新ItemsControl绑定的名为MyCollectionObservableCollection<DateTime> The timer should not know or care about the converter code at all. 定时器根本不应该知道或关心转换器代码。

For example, if your timer wants to re-create MyCollection with a whole new set of times, then it can, and the UI will automatically re-run the converter code and update the bar graph since ObservableCollections will tell the UI when the collection has changed and the UI needs to update. 例如,如果您的计时器想要用一整套新的时间重新创建MyCollection ,那么它就可以,并且UI将自动重新运行转换器代码并更新条形图,因为ObservableCollections将告诉UI何时集合具有已更改,UI需要更新。

As for the "base date" I was referring to in my comments below, if you were graphing a set of dates instead of times, you would want a baseline date so your graph doesn't stretch back to 1/1/0001 . 至于我在下面的评论中提到的“基准日期”,如果你要绘制一组日期而不是时间,你会想要一个基线日期,这样你的图表就不会延伸到1/1/0001 You don't want to use the minimum date since that will result in your lowest value showing up as 0 in your bar graph, so you would pass the Converter a specific date to use as the starting point in your graph. 您不希望使用最小日期,因为这将导致您的条形图中显示为0的最低值,因此您可以将Converter传递给特定日期以用作图表中的起始点。 If the base date was 1/1/12 and your largest date was 3/1/12, then your graph would stretch from 1/1/12 to 3/1/12. 如果基准日期是1/1/12并且您的最大日期是3/1/12,那么您的图表将从1/1/12延伸到3/1/12。

The base date would be used in step 3 and 5 of the converter. 基准日期将用于转换器的步骤3和5。 For example, instead of getting the number of minutes in the time, you might get the number of days between the base date and the data date. 例如,您可以获得基准日期和数据日期之间的天数,而不是获得当时的分钟数。

You could also calculate the base date in the converter, such as 10 days before the lowest date, although that might skew the graph more than you'd prefer depending on the data. 您还可以计算转换器中的基准日期,例如最低日期之前的10天,尽管根据数据的不同,这可能会使图表偏差超过您的偏好。

It sounds like you just need to keep track of the maximum of all values. 听起来你只需要跟踪所有值的最大值。 Then, scale each value according to this maximum: 然后,根据此最大值缩放每个值:

var scale = value / maximum;
var height = scale * ActualHeight;

Of course, the way you actually set the height of each item would likely be via a binding. 当然,实际设置每个项目高度的方式可能是通过绑定。

imho你整个条形图应该在后面有一个ViewModel,这个VM有逻辑来计算最大值,然后定义缩放。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM