// 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(); 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 strT = cndl.t.ToString((CandlesSource.TimeFrame < 0) ? "G" : "g", Culture); string tooltipText = $"{strT}\nV= {MyNumberFormatting.VolumeToString(cndl.V, Culture, decimalSeparator, decimalSeparatorArray)}"; ((ToolTip)ToolTip).Content = tooltipText; }
//--------------------------------------------------------------------------------------------------------------------------------------- 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; }
// values[0] - Point CurrentMousePosition // values[1] - double VolumeHistogramHeight // values[2] - CandleExtremums visibleCandlesExtremums // values[3] - double VolumeHistogramTopMargin // values[4] - double VolumeHistogramBottomMargin // values[5] - CultureInfo candleChartCulture public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values == null || values.Length < 5 || (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)) { return(0.0); } Point currentMousePosition = (Point)values[0]; double volumeHistogramHeight = (double)values[1]; CandleExtremums visibleCandlesExtremums = (CandleExtremums)values[2]; double volumeHistogramTopMargin = (double)values[3]; double volumeHistogramBottomMargin = (double)values[4]; CultureInfo candleChartCulture = (CultureInfo)values[5]; string decimalSeparator = candleChartCulture.NumberFormat.NumberDecimalSeparator; char[] decimalSeparatorArray = decimalSeparator.ToCharArray(); double volume = (((visibleCandlesExtremums.VolumeHigh - (currentMousePosition.Y - volumeHistogramTopMargin) / (volumeHistogramHeight - volumeHistogramTopMargin - volumeHistogramBottomMargin) * visibleCandlesExtremums.VolumeHigh))); return(MyNumberFormatting.VolumeToLimitedLengthString(volume, candleChartCulture, decimalSeparator, decimalSeparatorArray)); }
//--------------------------------------------------------------------------------------------------------------------------------------- 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)); }
//--------------------------------------------------------------------------------------------------------------------------------------- protected override void OnRender(DrawingContext drawingContext) { //if (VisibleCandlesExtremums.VolumeHigh == long.MinValue) return; double textHeight = (new FormattedText("1,23", 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_LEFT_MARGIN; double tickLineEndX = chartPanelWidth + TICK_LINE_WIDTH; double chartHeight = ActualHeight - ChartBottomMargin - ChartTopMargin; if (chartHeight <= 0) { return; } double stepInVolumeUnits = VisibleCandlesExtremums.VolumeHigh * ((textHeight + GapBetweenTickLabels) / chartHeight); double stepInVolumeUnits_HPlace = MyWpfMath.HighestDecimalPlace(stepInVolumeUnits, out _); stepInVolumeUnits = Math.Ceiling(stepInVolumeUnits / stepInVolumeUnits_HPlace) * stepInVolumeUnits_HPlace; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ double chartHeight_candlesLHRange_Ratio = chartHeight / VisibleCandlesExtremums.VolumeHigh; string decimalSeparator = Culture.NumberFormat.NumberDecimalSeparator; char[] decimalSeparatorArray = decimalSeparator.ToCharArray(); void DrawVolumeTick(double volume) { string s = MyNumberFormatting.VolumeToLimitedLengthString(volume, Culture, decimalSeparator, decimalSeparatorArray); FormattedText priceTickFormattedText = new FormattedText(s, Culture, FlowDirection.LeftToRight, currentTypeFace, TickLabelFontSize, TickColor, VisualTreeHelper.GetDpi(this).PixelsPerDip); double y = ChartTopMargin + (VisibleCandlesExtremums.VolumeHigh - volume) * 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)); } } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ double theMostRoundVolume = MyWpfMath.HighestDecimalPlace(VisibleCandlesExtremums.VolumeHigh, out _); DrawVolumeTick(theMostRoundVolume); double maxVolumeThreshold = (VisibleCandlesExtremums.VolumeHigh + (ChartTopMargin - halfTextHeight) / chartHeight_candlesLHRange_Ratio); double minVolumeThreshold = (VisibleCandlesExtremums.VolumeHigh + (ChartTopMargin - ActualHeight + halfTextHeight) / chartHeight_candlesLHRange_Ratio); int step_i = 1; double next_tick; while ((next_tick = theMostRoundVolume + step_i * stepInVolumeUnits) < maxVolumeThreshold) { DrawVolumeTick(next_tick); step_i++; } step_i = 1; while ((next_tick = theMostRoundVolume - step_i * stepInVolumeUnits) > minVolumeThreshold) { DrawVolumeTick(next_tick); step_i++; } }