Beispiel #1
0
        protected override void OnRender(DrawingContext drawingContext)
        {
            if (double.IsNaN(ActualWidth) || double.IsNaN(ActualHeight))
            {
                return;
            }

            if (!isRenderingNeeded && oldActualWidth == ActualWidth && oldActualHeight == ActualHeight)
            {
                return;
            }

            //Size has changed. Recreate all Visuals
            oldActualWidth    = ActualWidth;
            oldActualHeight   = ActualHeight;
            isRenderingNeeded = false;

            Visuals.Clear();
            Visuals.Add(crerateBackGroundVisual());
            foreach (Renderer renderer in renderers)
            {
                //////var xGridLineRenderer = renderer as XGridLineRenderer;
                //////if (xGridLineRenderer!=null) {
                //////  if (double.IsNaN(xGridLineRenderer.MinDisplayValueY) || double.IsNaN(xGridLineRenderer.MaxDisplayValueY)){
                //////    xGridLineRenderer.SetDisplayValueRangeY(xGridLineRenderer.YLegendScroller.MinDisplayValue, xGridLineRenderer.YLegendScroller.MaxDisplayValue);
                //////  }
                //////}
                Visuals.Add(renderer.CreateVisual(ActualWidth, ActualHeight));
            }
            TraceWpf.Line("PlotArea.OnRender: " + renderers.Count + " Renderer Visuals recreated");
        }
Beispiel #2
0
        //      ----------------

        protected override void OnProvideDefaultValues(out double displayValue, out double displayValueRange)
        {
            TraceWpf.Line(">>>>> LegendXDate.OnProvideDefaultValues()");
            DisplayDate       = DateTime.Now.AddDays(-7);
            displayValue      = DisplayDate.ToDouble();
            DisplayDateRange  = TimeSpan.FromDays(1);
            displayValueRange = DisplayDateRange.ToDouble();
        }
        public Chart2Plots1X2YLegendsWindow()
        {
            InitializeComponent();

            TestChart2Plots1X2YLegendsTraced.PlotAreaLower.Background = Brushes.LightGoldenrodYellow;
            TraceWpf.Line(">>>>> Chart2Plots1X2YLegendsWindow.fillDataSeries()");
            fillDataSeries();
        }
Beispiel #4
0
        public Chart4Plots1X4YLegendsWindow()
        {
            InitializeComponent();

            TestChart4Plots1X4YLegendsTraced.PlotArea1.Background = Brushes.SeaShell;
            TestChart4Plots1X4YLegendsTraced.PlotArea2.Background = Brushes.Cornsilk;
            TestChart4Plots1X4YLegendsTraced.PlotArea3.Background = Brushes.Honeydew;
            TraceWpf.Line(">>>>> Chart4Plots1X4YLegendsWindow.fillDataSeries()");
            fillDataSeries();
        }
Beispiel #5
0
 /// <summary>
 /// Removes all Renderers from PlotArea
 /// </summary>
 public void ClearRenderers()
 {
     renderers.Clear();
     if (Visuals.Count > firstRendererVisual)
     {
         TraceWpf.Line("PlotArea.ClearRenderers(), remove Visuals");
         //remove all renderer visuals, but leave background visual
         Visuals.RemoveRange(firstRendererVisual, Visuals.Count - firstRendererVisual);
     }
     else
     {
         TraceWpf.Line("PlotArea.ClearRenderers(), no Visuals");
     }
 }
Beispiel #6
0
        /// <summary>
        /// Adds one renderer to PlotArea
        /// </summary>
        /// <param name="renderer"></param>
        public void AddRenderer(Renderer renderer)
        {
            TraceWpf.Line("PlotArea.AddRenderer()");
            renderers.Add(renderer);
            renderer.RenderingRequested += renderer_RenderingRequested;
            //When a new renderer gets added, first the legends has to be calculated again, which might change the width of the legend and
            //in consequence also the width of the Plot-area
            isRenderingNeeded = true;
            InvalidateVisual();
            //////if (Visuals.Count<firstRendererVisual) {
            //////  //Background not added yet => onRender will get executed later, which will add the visuals for the Renderer;
            //////  //nothing to do now
            //////} else {
            //////  //Background Visual exists already. Other Visuals can be added.
            //////  Visuals.Add(renderer.Render(ActualWidth, ActualHeight));
            //////}

            RendererAdded?.Invoke(renderer);
        }
Beispiel #7
0
        /// <summary>
        /// Replaces the old Visual created by this Renderer with a new one
        /// </summary>
        void renderer_RenderingRequested(Renderer renderer)
        {
            if (Visuals.Count <= firstRendererVisual)
            {
                TraceWpf.Line("PlotArea.RenderingRequested(" + renderer.RendererId + "): delayed Visual");
                //Background not added yet => onRender will get executed later, which will add the visuals for the Renderer;
                //nothing to do now
            }
            else
            {
                TraceWpf.Line("PlotArea.RenderingRequested(" + renderer.RendererId + "): Visual updated");
                int rendererIndex = renderers.IndexOf(renderer);
                if (rendererIndex == -1)
                {
                    throw new Exception("RenderingRequested: renderer '" + renderer + "' not found in renderers (Count: " + renderers.Count + ").");
                }

                int visualIndex = firstRendererVisual + rendererIndex;
                Visuals.RemoveAt(visualIndex);
                Visuals.Insert(visualIndex, renderer.CreateVisual(ActualWidth, ActualHeight));
            }
        }
Beispiel #8
0
        protected override bool OnIsRecalculationNeeded(Size renderContentSize)
        {
            TraceWpf.Line(">>>>> LegendxDate.OnIsRecalculationNeeded()");
            //check first if DisplayValue has changed, which most likely comes from LegendScroller
            bool hasDisplayDateChanged = false;

            if (displayValueTracked != DisplayValue)
            {
                displayValueTracked   = DisplayValue;
                displayDateTracked    = DisplayDate = DisplayValue.ToDateTime();
                hasDisplayDateChanged = true;
            }
            if (displayValueRangeTracked != DisplayValueRange)
            {
                displayValueRangeTracked = DisplayValueRange;
                displayDateRangeTracked  = DisplayDateRange = displayValueRangeTracked.ToTimeSpan();
                hasDisplayDateChanged    = true;
            }
            if (!hasDisplayDateChanged)
            {
                //if DisplayValue (LegendScroller) hasn't changed, check if DisplayDate has been directly changed
                if (displayDateTracked != DisplayDate)
                {
                    displayDateTracked    = DisplayDate;
                    displayValueTracked   = DisplayValue = displayDateTracked.ToDouble();
                    hasDisplayDateChanged = true;
                }
                if (displayDateRangeTracked != DisplayDateRange)
                {
                    displayDateRangeTracked  = DisplayDateRange;
                    displayValueRangeTracked = DisplayValueRange = displayDateRangeTracked.ToDouble();
                    hasDisplayDateChanged    = true;
                }
            }

            return(base.OnIsRecalculationNeeded(renderContentSize) || hasDisplayDateChanged);//OnIsRecalculationNeeded needs to come first to guarantee its execution
        }
Beispiel #9
0
        private Size doArrangeOverride(Size arrangeBounds)
        {
            if (double.IsNaN(arrangeBounds.Width) || double.IsInfinity(arrangeBounds.Width) || arrangeBounds.Width < 0 ||
                double.IsNaN(arrangeBounds.Height) || double.IsInfinity(arrangeBounds.Height) || arrangeBounds.Height < 0)
            {
                //just curious if this ever happens.
                throw new Exception("Illegal dimensions of arrangeBounds: " + arrangeBounds);
            }

            Size adjustedBounds = arrangeBounds;

            if (isWidthInfinity || isHeightInfinity)
            {
                DependencyObject current = this;
                do
                {
                    current = VisualTreeHelper.GetParent(current);
                    if (current is UIElement parentUIElement)
                    {
                        double adjustedWidth, adjustedHeigth;
                        adjustedWidth  = isWidthInfinity ? parentUIElement.DesiredSize.Width : adjustedBounds.Width;
                        adjustedHeigth = isHeightInfinity ? parentUIElement.DesiredSize.Height : adjustedBounds.Height;
                        adjustedBounds = new Size(adjustedWidth, adjustedHeigth);
                        break;
                    }
                } while (current != null);
            }


            calculateBorderWidth(adjustedBounds, BorderPenThickness, Padding, out var borderWidth, out var contentAvailableWidth);

            calculateBorderHeight(adjustedBounds, BorderPenThickness, Padding, out var borderHeight, out var contentAvailableHeight);

            //arrange content within the size left, which might be 0.
            Size contentRequiredSize = ArrangeVisualsOverride(new Size(contentAvailableWidth, contentAvailableHeight));

            //draw background and border if necessary
            if (actualArrangeBounds != adjustedBounds || actualBackground != Background || actualBorderBrush != BorderBrush ||
                actualBorderPenThickness != BorderPenThickness)
            {
                //border and/or FrameWorkElementSize have changed. Redraw background
                actualArrangeBounds      = adjustedBounds;
                actualBackground         = Background;
                actualBorderBrush        = BorderBrush;
                actualBorderPenThickness = BorderPenThickness;
                //remove old BackgroundDrawingVisual
                if (visuals.Count > 0 && ((DrawingVisual)visuals[0]) == backgroundDrawingVisual)
                {
                    visuals.RemoveAt(0);
                }
                if (Background == null && BorderPenThickness <= 0 && Padding == thickness0)
                {
                    //no BackgroundDrawingVisual needed
                    backgroundDrawingVisual = null;
                    hasBackgroundVisual     = false;
                }
                else
                {
                    //create updated background
                    backgroundDrawingVisual = new DrawingVisual();
                    using (DrawingContext drawingContext = backgroundDrawingVisual.RenderOpen()) {
                        if (BorderPenThickness > 0)
                        {
                            if (TraceWpf.IsTracing)
                            {
                                TraceWpf.Line(this, "DrawBackgroundBorder(Width: " + actualArrangeBounds.Width + ", Height: " + actualArrangeBounds.Height + ", Border: " + BorderPenThickness + ")");
                            }
                            double halfBorderWidth = BorderPenThickness / 2.0;
                            var    drawingRect     = new Rect(halfBorderWidth, halfBorderWidth, actualArrangeBounds.Width - BorderPenThickness, actualArrangeBounds.Height - BorderPenThickness);
                            drawingContext.DrawRectangle(Background, new Pen(BorderBrush, BorderPenThickness), drawingRect);
                        }
                        else
                        {
                            if (TraceWpf.IsTracing)
                            {
                                TraceWpf.Line(this, "DrawBackground(Width: " + actualArrangeBounds.Width + ", Height: " + actualArrangeBounds.Height + ")");
                            }
                            drawingContext.DrawRectangle(Background, null, new Rect(0, 0, actualArrangeBounds.Width, actualArrangeBounds.Height));
                        }
                    }
                    visuals.Insert(0, backgroundDrawingVisual);
                    hasBackgroundVisual = true;
                }
            }

            //update DrawingVisual Offsets if necessary
            double offsetLeft = Math.Min(BorderPenThickness + Padding.Left, adjustedBounds.Width);
            double offsetTop  = Math.Min(BorderPenThickness + Padding.Top, adjustedBounds.Height);

            if (actualOffsetLeft != offsetLeft || actualOffsetTop != offsetTop)
            {
                //border size has changed => calculate new offset
                actualOffsetLeft = offsetLeft;
                actualOffsetTop  = offsetTop;
                offsetVector     = new Vector(offsetLeft, offsetTop);
                for (int visualIndex = 0; visualIndex < visuals.Count; visualIndex++)
                {
                    if (visualIndex == 0 && hasBackgroundVisual)
                    {
                        continue;
                    }

                    DrawingVisual updateVisual = (DrawingVisual)visuals[visualIndex];
                    if (updateVisual != null)
                    {
                        updateVisual.Offset = offsetVector;
                    }
                }
            }

            ContentSize = new Size(contentAvailableWidth, contentAvailableHeight);
            if (actualContentSize != ContentSize)
            {
                actualContentSize = ContentSize;
                if (ContentSizeChanged != null)
                {
                    hasContentSizeChanged = true;
                }
            }

            //report to the parent that at most arrangeBounds size was used.
            return(new Size(Math.Min(borderWidth + contentRequiredSize.Width, adjustedBounds.Width),
                            Math.Min(borderHeight + contentRequiredSize.Height, adjustedBounds.Height)));
        }
Beispiel #10
0
        /// <summary>
        /// Renders the chart graph to a Visual. The graphic gets scaled to the available height and width displaying only
        /// values between minValueDisplayX and minValueDisplayX. The actual values get cropped between minDisplayValueY
        /// and maxDisplayValueY.
        /// </summary>
        public Visual CreateVisual(double width, double height)
        {
            DrawingVisual drawingVisual = new DrawingVisual();

            bool areMinMaxDefined = !double.IsNaN(MinDisplayValues[0]) && !double.IsNaN(MaxDisplayValues[0]);

            if (MinDisplayValues.Length > 1)
            {
                areMinMaxDefined = areMinMaxDefined && !double.IsNaN(MinDisplayValues[0]) && !double.IsNaN(MaxDisplayValues[0]);
            }
            if (!areMinMaxDefined || double.IsNaN(width) || double.IsNaN(height) || width <= 0 || height <= 0)
            {
                string message = "Renderer" + RendererId + "(): empty Visual returned";
                if (DimensionX < MinDisplayValues.Length)
                {
                    message += ", MinDisplayValueX: " + MinDisplayValues[DimensionX] + ", MaxDisplayValueX: " + MaxDisplayValues[DimensionX];
                }
                if (DimensionY < MinDisplayValues.Length)
                {
                    message += ", MinDisplayValueY: " + MinDisplayValues[DimensionY] + ", MaxDisplayValueY: " + MaxDisplayValues[DimensionY] + "";
                }
                TraceWpf.Line(message);
                return(drawingVisual); //return an empty Visual, not null
            }

            if (DimensionMap[0] == DimensionX)
            {
                //if there is a DimensionX in DimensionMap, it must be the first entry per convention
                dimensionXIndex = 0;
                double differenceX = MaxDisplayValues[DimensionX] - MinDisplayValues[DimensionX];
                if (differenceX == 0)
                {
                    ScaleX = width;
                }
                else
                {
                    ScaleX = width / differenceX;
                }
            }
            else
            {
                //DimensionX not used
                dimensionXIndex = int.MinValue;
                ScaleX          = double.NaN;
            }

            if (DimensionMap[0] == DimensionY)
            {
                //if the DimensionMap has only 1 entry, only this one has to be checked
                dimensionYIndex = 0;
            }
            else if (DimensionMap.Length > 1 && DimensionMap[1] == DimensionY)
            {
                //if the DimensionMap has more than 1 entry, DimensionY is by convention the second entry in DimensionMap
                dimensionYIndex = 1;
            }
            if (dimensionYIndex > int.MinValue)
            {
                double differenceY = MaxDisplayValues[dimensionYIndex] - MinDisplayValues[dimensionYIndex];
                if (differenceY == 0)
                {
                    ScaleY = height;
                }
                else
                {
                    ScaleY = height / differenceY;
                }
            }
            else
            {
                //DimensionY not used
                dimensionYIndex = int.MinValue;
                ScaleY          = double.NaN;
            }

            using (DrawingContext drawingContext = drawingVisual.RenderOpen()) {
                OnCreateVisual(drawingContext, width, height, drawingVisual);
            }

            Rendered?.Invoke(this);
            return(drawingVisual);
        }
Beispiel #11
0
        /// <summary>
        /// Updates the scrollbar to their values. Inheritors should call
        /// CalculateScrollBarValues latest during Arrange()
        /// </summary>
        protected void CalculateScrollBarValues()
        {
            if (double.IsInfinity(MinValue) || double.IsInfinity(MaxValue) || double.IsInfinity(DisplayValue) || double.IsInfinity(DisplayValueRange))
            {
                if (isExceptionThrown)
                {
                    return;
                }

                isExceptionThrown = true;
                throw new ApplicationException("Infinity is not supported: MinValue " + MinValue + ", MaxValue " + MaxValue +
                                               ", DisplayValue " + DisplayValue + ", DisplayRange " + DisplayValueRange + ".");
            }

            //if max value range is not set (yet), use some default values to display something, in case it remains empty. It helps the
            //user to understand the GUI better, if he can see the legend even he has no data selected yet to be displayed
            if (MinValue == minValueInit || MaxValue == maxValueInit)
            {
                //there are no values. Use some default values
                MinValue = 0;
                MaxValue = 10;
            }

            double maxValueRange = MaxValue - MinValue;

            if (maxValueRange < 0)
            {
                if (isExceptionThrown)
                {
                    return;
                }

                isExceptionThrown = true;
                throw new ApplicationException("MaxValue " + MaxValue + " - MinValue " + MinValue + " should be greater 0, but was " + maxValueRange + ".");
            }
            if (maxValueRange == 0)
            {
                //Min and Max are the same. This happens when the graphic displays only 1 record. In this case, the
                //range must be increased, otherwise nothing would get displayed.
                if (MinValue == 0)
                {
                    MinValue = -1;
                    MaxValue = 1;
                }
                else if (MinValue > 0)
                {
                    MaxValue = MinValue * 2;
                    MinValue = 0;
                }
                else
                {
                    MinValue *= 2;
                    MaxValue  = 0;
                }
                maxValueRange = MaxValue - MinValue;
            }

            //ensure that DisplayValue and DisplayValueRange define a range between MinValue and MaxValue, otherwise
            //correct them accordingly. This correction is done without error message, since scrolling and zooming can
            //lead to illegal values
            if (DisplayValue == displayValueInit || DisplayValueRange == displayValueRangeInit || DisplayValueRange <= 0)
            {
                DisplayValue      = MinValue;
                DisplayValueRange = maxValueRange;
            }
            if (DisplayValue < MinValue)
            {
                DisplayValue = MinValue;
            }
            if (DisplayValueRange >= (maxValueRange) * 0.99)
            {
                //when nearly everything needs to be displayed, display everything
                DisplayValueRange = maxValueRange;
            }
            bool canZoomIn;
            bool canZoomOut;

            if (DisplayValueRange >= maxValueRange)
            {
                DisplayValueRange = maxValueRange;
                canZoomOut        = false;
                canZoomIn         = true;
            }
            else
            {
                canZoomOut = true;
                if (DisplayValueRange < (maxValueRange / ZoomInLimit))
                {
                    //limit zooming in to 1 million times
                    DisplayValueRange = maxValueRange / ZoomInLimit;
                    canZoomIn         = false;
                }
                else
                {
                    canZoomIn = true;
                }
            }
            if (DisplayValue + DisplayValueRange > MaxValue)
            {
                DisplayValue = MaxValue - DisplayValueRange;
            }
            updateZoomState(canZoomIn, canZoomOut);

            isExceptionThrown = false;

            if (!areNewMinMax && minValueTracked == MinValue && displayValueTracked == DisplayValue && displayValueRangeTracked == DisplayValueRange &&
                maxValueTracked == MaxValue)
            {
                return;                    //nothing to do
            }
            //update the tracked values, they might have changed
            minValueTracked          = MinValue;
            displayValueTracked      = DisplayValue;
            displayValueRangeTracked = DisplayValueRange;
            maxValueTracked          = MaxValue;

            //set scrollbar values
            isArranging       = true;
            ScrollBar.Minimum = MinValue;
            ScrollBar.Maximum = MaxValue - DisplayValueRange;
            if (ScrollBar.Orientation == Orientation.Horizontal)
            {
                ScrollBar.Value = DisplayValue;
            }
            else
            {
                ScrollBar.Value = ScrollBar.Minimum + ScrollBar.Maximum - DisplayValue;
            }
            double largeChange = DisplayValueRange;

            if (ScrollBar.LargeChange != largeChange)
            {
                ScrollBar.LargeChange  = largeChange;
                ScrollBar.SmallChange  = largeChange / largeSmallChangeRatio;
                ScrollBar.ViewportSize = largeChange;
            }
            isArranging  = false;
            areNewMinMax = false;
            TraceWpf.Line(">>>>> LegendScroller.CalculateScrollBarValues(): Copy to legend.MinValue");
            legend.MinValue          = minValueTracked;
            legend.DisplayValue      = displayValueTracked;
            legend.DisplayValueRange = displayValueRangeTracked;
            legend.MaxValue          = maxValueTracked;
        }