Exemple #1
0
        // values[0] - Point CurrentMousePosition
        // values[1] - double ChartAreaHeight
        // values[2] - CandleExtremums visibleCandlesExtremums
        // values[3] - double PriceChartTopMargin
        // values[4] - double PriceChartBottomMargin
        // values[5] - int MaxNumberOfFractionalDigitsInPrice
        // values[6] - CultureInfo candleChartCulture
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values == null || values.Length < 6 || (values[0]).GetType() != typeof(Point) || (values[1]).GetType() != typeof(double) || (values[2]).GetType() != typeof(CandleExtremums) ||
                (values[3]).GetType() != typeof(double) || (values[4]).GetType() != typeof(double) || (values[5]).GetType() != typeof(int))
            {
                return(true);
            }

            Point  currentMousePosition = (Point)values[0];
            double ChartAreaHeight      = (double)values[1];
            double priceLow             = ((CandleExtremums)values[2]).PriceLow;
            double priceHigh            = ((CandleExtremums)values[2]).PriceHigh;
            double chartTopMargin       = (double)values[3];
            double chartBottomMargin    = (double)values[4];
            int    maxNumberOfFractionalDigitsInPrice = (int)values[5];

            CultureInfo candleChartCulture = (CultureInfo)values[6];
            string      decimalSeparator   = candleChartCulture.NumberFormat.NumberDecimalSeparator;

            char[] decimalSeparatorArray = decimalSeparator.ToCharArray();

            double price             = Math.Round((priceHigh - (currentMousePosition.Y - chartTopMargin) / (ChartAreaHeight - chartTopMargin - chartBottomMargin) * (priceHigh - priceLow)), maxNumberOfFractionalDigitsInPrice);
            string priceNumberFormat = $"N{maxNumberOfFractionalDigitsInPrice}";

            return(MyNumberFormatting.PriceToString(price, priceNumberFormat, candleChartCulture, decimalSeparator, decimalSeparatorArray));
        }
        //---------------------------------------------------------------------------------------------------------------------------------------
        protected override void OnMouseMove(MouseEventArgs e)
        {
            string decimalSeparator = Culture.NumberFormat.NumberDecimalSeparator;

            char[] decimalSeparatorArray = decimalSeparator.ToCharArray();
            string priceNumberFormat     = $"N{MaxNumberOfFractionalDigitsInPrice}";

            Point mousePos = e.GetPosition(this);
            //Vector uv = new Vector(mousePos.X/ RenderSize.Width, mousePos.Y / RenderSize.Height);
            int     cndl_i      = VisibleCandlesRange.Start_i + (int)(mousePos.X / (CandleWidthAndGap.Width + CandleWidthAndGap.Gap));
            ICandle cndl        = CandlesSource[cndl_i];
            string  strO        = MyNumberFormatting.PriceToString(cndl.O, priceNumberFormat, Culture, decimalSeparator, decimalSeparatorArray);
            string  strH        = MyNumberFormatting.PriceToString(cndl.H, priceNumberFormat, Culture, decimalSeparator, decimalSeparatorArray);
            string  strL        = MyNumberFormatting.PriceToString(cndl.L, priceNumberFormat, Culture, decimalSeparator, decimalSeparatorArray);
            string  strC        = MyNumberFormatting.PriceToString(cndl.C, priceNumberFormat, Culture, decimalSeparator, decimalSeparatorArray);
            string  strV        = MyNumberFormatting.VolumeToString(cndl.V, Culture, decimalSeparator, decimalSeparatorArray);
            string  strT        = cndl.t.ToString((CandlesSource.TimeFrame < 0) ? "G" : "g", Culture);
            string  tooltipText = $"{strT}\nO= {strO}\nH= {strH}\nL= {strL}\nC= {strC}\nV= {strV}";

            ((ToolTip)ToolTip).Content = tooltipText;
        }
        //---------------------------------------------------------------------------------------------------------------------------------------
        protected override void OnRender(DrawingContext drawingContext)
        {
            double textHeight      = (new FormattedText("123", Culture, FlowDirection.LeftToRight, currentTypeFace, TickLabelFontSize, Brushes.Black, VisualTreeHelper.GetDpi(this).PixelsPerDip)).Height;
            double halfTextHeight  = textHeight / 2.0;
            double chartPanelWidth = ActualWidth - PriceAxisWidth;
            double tickLabelX      = chartPanelWidth + TICK_LINE_WIDTH + TICK_HORIZ_MARGIN;
            double tickLineEndX    = chartPanelWidth + TICK_LINE_WIDTH;
            double chartHeight     = ActualHeight - ChartBottomMargin - ChartTopMargin;

            double stepInRubles        = (VisibleCandlesExtremums.PriceHigh - VisibleCandlesExtremums.PriceLow) / chartHeight * (textHeight + GapBetweenTickLabels);
            double stepInRubles_HPlace = MyWpfMath.HighestDecimalPlace(stepInRubles, out int stepInRubles_HPow);

            stepInRubles = Math.Ceiling(stepInRubles / stepInRubles_HPlace) * stepInRubles_HPlace;
            MyWpfMath.HighestDecimalPlace(stepInRubles, out int stepInRublesHighestDecimalPow);
            string priceTickLabelNumberFormat    = (stepInRubles_HPow >= 0) ? "N0" : $"N{-stepInRubles_HPow}";
            string currentPriceLabelNumberFormat = $"N{MaxNumberOfFractionalDigitsInPrice}";

            double chartHeight_candlesLHRange_Ratio = chartHeight / (VisibleCandlesExtremums.PriceHigh - VisibleCandlesExtremums.PriceLow);

            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            string decimalSeparator = Culture.NumberFormat.NumberDecimalSeparator;

            char[] decimalSeparatorArray = decimalSeparator.ToCharArray();

            void DrawPriceTickLabel(double price, int priceStepHighestDecimalPow)
            {
                string        s = MyNumberFormatting.PriceToString(price, priceTickLabelNumberFormat, Culture, decimalSeparator, decimalSeparatorArray);
                FormattedText priceTickFormattedText = new FormattedText(s, Culture, FlowDirection.LeftToRight, currentTypeFace, TickLabelFontSize, TickColor, VisualTreeHelper.GetDpi(this).PixelsPerDip);
                double        y = ChartTopMargin + (VisibleCandlesExtremums.PriceHigh - price) * chartHeight_candlesLHRange_Ratio;

                drawingContext.DrawText(priceTickFormattedText, new Point(tickLabelX, y - halfTextHeight));
                drawingContext.DrawLine(tickPen, new Point(chartPanelWidth, y), new Point(tickLineEndX, y));

                if (IsGridlinesEnabled && GridlinesPen != null)
                {
                    drawingContext.DrawLine(GridlinesPen, new Point(0, y), new Point(chartPanelWidth, y));
                }
            }

            void DrawCurrentPriceLabel()
            {
                string        currentPriceString = MyNumberFormatting.PriceToString(CurrentPrice, currentPriceLabelNumberFormat, Culture, decimalSeparator, decimalSeparatorArray);
                FormattedText formattedText      = new FormattedText(currentPriceString, Culture, FlowDirection.LeftToRight, currentTypeFace, TickLabelFontSize, CurrentPriceLabelForeground, VisualTreeHelper.GetDpi(this).PixelsPerDip);
                double        formattedTextWidth = formattedText.Width;
                double        y = ChartTopMargin + (VisibleCandlesExtremums.PriceHigh - CurrentPrice) * chartHeight_candlesLHRange_Ratio;

                drawingContext.DrawRectangle(CurrentPriceLabelBackground, currentPriceLabelForegroundPen,
                                             new Rect(chartPanelWidth, y - halfTextHeight, formattedTextWidth + TICK_LINE_WIDTH + 2 * TICK_HORIZ_MARGIN, textHeight + 1.0));
                drawingContext.DrawLine(currentPriceLabelForegroundPen, new Point(chartPanelWidth, y), new Point(tickLineEndX, y));
                drawingContext.DrawText(formattedText, new Point(tickLabelX, y - halfTextHeight));
            }

            //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
            double theMostRoundPrice = MyWpfMath.TheMostRoundValueInsideRange(VisibleCandlesExtremums.PriceLow, VisibleCandlesExtremums.PriceHigh);

            DrawPriceTickLabel(theMostRoundPrice, stepInRublesHighestDecimalPow);

            double maxPriceThreshold = VisibleCandlesExtremums.PriceHigh + (ChartTopMargin - halfTextHeight) / chartHeight_candlesLHRange_Ratio;
            double minPriceThreshold = VisibleCandlesExtremums.PriceHigh + (ChartTopMargin - ActualHeight + halfTextHeight) / chartHeight_candlesLHRange_Ratio;

            int    step_i = 1;
            double next_tick;

            while ((next_tick = theMostRoundPrice + step_i * stepInRubles) < maxPriceThreshold)
            {
                DrawPriceTickLabel(next_tick, stepInRublesHighestDecimalPow);
                step_i++;
            }

            step_i = 1;
            while ((next_tick = theMostRoundPrice - step_i * stepInRubles) > minPriceThreshold)
            {
                DrawPriceTickLabel(next_tick, stepInRublesHighestDecimalPow);
                step_i++;
            }

            if (IsCurrentPriceLabelVisible && CurrentPrice >= VisibleCandlesExtremums.PriceLow && CurrentPrice <= VisibleCandlesExtremums.PriceHigh)
            {
                DrawCurrentPriceLabel();
            }

            // Горизонтальные линии на всю ширину разделяющая и окаймляющая панели времени и даты:
            //drawingContext.DrawLine(pen, new Point(0, 0), new Point(RenderSize.Width, 0));
            //drawingContext.DrawLine(pen, new Point(0, halfRenderSizeHeight), new Point(RenderSize.Width, halfRenderSizeHeight));
            //drawingContext.DrawLine(pen, new Point(0, RenderSize.Height), new Point(RenderSize.Width, RenderSize.Height));
        }