WPF Polyline relative point values and stretch for drawing a graph

fillpolylinestretchwpf

I'm trying to create a pretty simple graphing component that consists of a series of Polylines within the same grid cell that represent graph lines. My strategy is to look at all the points in my set, determine the min and max, and then calculate a number between 0 to 1 accordingly and use Stretch="Fill" to stretch each Polyline to fill the grid cell. My desired effect would be that a point at 0,.5 would be vertically in the center of the cell, but in reality the Polyline gets stretched vertically to fill the entire cell depending on what the min and max Y value is. E.g. if .5 is my max and .7 is my min in the Polyline, then .5 will be clear at the top of the cell and .7 clear at the bottom, rather than .5 in the center and .7 7/10 to the bottom.

Here's a simple example with two Polylines and calculated points between 0 and 1. You'll notice the red Polyline is directly on top of the blue one, even though the red Y values are greater. The red Polyline should look the same as the blue, but be oriented slightly lower in the cell. However it's being stretched to fill the entire cell so it sits directly on top of the blue.

<Window x:Class="Test.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="100" Width="300">
<Grid>
    <Polyline
        Stretch="Fill"
        Stroke="Blue"
        Points="0,0 0.2,0 0.2,0.363636363636364 0.4,0.363636363636364 0.4,0.636363636363636 0.6,0.636363636363636 0.6,0.0909090909090909 0.8,0.0909090909090909 0.8,0 1,0" />
    <Polyline
        Stretch="Fill"
        Stroke="Red"
        Points="0,0.363636363636364 0.2,0.363636363636364 0.2,0.727272727272727 0.4,0.727272727272727 0.4,1 0.6,1 0.6,0.454545454545455 0.8,0.454545454545455 0.8,0.363636363636364 1,0.363636363636364" />
</Grid>

The reason I'm using 0 to 1 values is because I want the width and height of the grid cell to be easily changeable, e.g. via a slider or something to adjust the height of the graph, or dragging the window wider to adjust the width. So I tried to use this stretch strategy to achieve that instead of calculating pixel values w/out stretching.

Any advice on how to achieve this?

Thanks.

Best Answer

I had similar problem because I couldn't find an easy way to scale multiple shapes. Ended up using DrawingGroup with multiple GeometryDrawing inside. So they scale together. Here are your graphs with this approach. Looks bulky but should work fast. Plus you'll most likely populate line segments from code:

<Window x:Class="Polyline.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="100" Width="300">
    <Grid>
        <Image>
            <Image.Source>
                <DrawingImage>
                    <DrawingImage.Drawing>
                        <DrawingGroup>
                            <GeometryDrawing Brush="Transparent">
                                <GeometryDrawing.Geometry>
                                    <RectangleGeometry Rect="0,0,1,1">
                                        <RectangleGeometry.Transform>
                                            <ScaleTransform ScaleX="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Grid}}"
                                                            ScaleY="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Grid}}"/>
                                        </RectangleGeometry.Transform>
                                    </RectangleGeometry>
                                </GeometryDrawing.Geometry>
                            </GeometryDrawing>
                            <GeometryDrawing>
                                <GeometryDrawing.Pen>
                                    <Pen Brush="Blue" Thickness="1"/>
                                </GeometryDrawing.Pen>
                                <GeometryDrawing.Geometry>
                                    <PathGeometry>
                                        <PathGeometry.Transform>
                                            <ScaleTransform ScaleX="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Grid}}"
                                                            ScaleY="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Grid}}"/>
                                        </PathGeometry.Transform>
                                        <PathGeometry.Figures>
                                            <PathFigure StartPoint="0,0">
                                                <PathFigure.Segments>
                                                    <LineSegment Point="0.2,0"/>
                                                    <LineSegment Point="0.2,0.363636363636364"/>
                                                    <LineSegment Point="0.4,0.363636363636364"/>
                                                    <LineSegment Point="0.4,0.636363636363636"/>
                                                    <LineSegment Point="0.6,0.636363636363636"/>
                                                    <LineSegment Point="0.6,0.0909090909090909"/>
                                                    <LineSegment Point="0.8,0.0909090909090909"/>
                                                    <LineSegment Point="0.8,0"/>
                                                    <LineSegment Point="1,0"/>
                                                </PathFigure.Segments>
                                            </PathFigure>
                                        </PathGeometry.Figures>
                                    </PathGeometry>
                                </GeometryDrawing.Geometry>
                            </GeometryDrawing>
                            <GeometryDrawing>
                                <GeometryDrawing.Pen>
                                    <Pen Brush="Red" Thickness="1"/>
                                </GeometryDrawing.Pen>
                                <GeometryDrawing.Geometry>
                                    <PathGeometry>
                                        <PathGeometry.Transform>
                                            <ScaleTransform ScaleX="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Grid}}"
                                                            ScaleY="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Grid}}"/>
                                        </PathGeometry.Transform>
                                        <PathGeometry.Figures>
                                            <PathFigure StartPoint="0,0.363636363636364">
                                                <PathFigure.Segments>
                                                    <LineSegment Point="0.2,0.363636363636364"/>
                                                    <LineSegment Point="0.2,0.727272727272727"/>
                                                    <LineSegment Point="0.4,0.727272727272727"/>
                                                    <LineSegment Point="0.4,1"/>
                                                    <LineSegment Point="0.6,1"/>
                                                    <LineSegment Point="0.6,0.454545454545455"/>
                                                    <LineSegment Point="0.8,0.454545454545455"/>
                                                    <LineSegment Point="0.8,0.363636363636364"/>
                                                    <LineSegment Point="1,0.363636363636364"/>
                                                </PathFigure.Segments>
                                            </PathFigure>
                                        </PathGeometry.Figures>
                                    </PathGeometry>
                                </GeometryDrawing.Geometry>
                            </GeometryDrawing>
                        </DrawingGroup>
                    </DrawingImage.Drawing>
                </DrawingImage>
            </Image.Source>
        </Image>
    </Grid>

</Window>

You can remove first RectangleGeometry if you don't need graphs always scale between 0 and 1.

Related Topic