private void AdjustDealCommentArrowAngle(ChartComment comment, MarketOrder order) { if (!order.TimeExit.HasValue) return; // получить основное направление // (продолжение линии open - close) var ptE = Conversion.WorldToScreen( new PointD(owner.StockSeries.GetDoubleIndexByTime(order.TimeEnter), order.PriceEnter), owner.StockPane.WorldRect, owner.StockPane.CanvasRect); var ptQ = Conversion.WorldToScreen( // ReSharper disable PossibleInvalidOperationException new PointD(owner.StockSeries.GetDoubleIndexByTime(order.TimeExit.Value), order.PriceExit.Value), // ReSharper restore PossibleInvalidOperationException owner.StockPane.WorldRect, owner.StockPane.CanvasRect); var ptPivot = Conversion.WorldToScreen(new PointD(comment.PivotIndex, comment.PivotPrice), owner.StockPane.WorldRect, owner.StockPane.CanvasRect); var ptStart = (Math.Abs(ptPivot.X - ptE.X) < Math.Abs(ptPivot.X - ptQ.X)) ? ptQ : ptE; var mainAngle = Math.Atan2(ptPivot.Y - ptStart.Y, ptPivot.X - ptStart.X) * 180 / Math.PI; // "округлить" угол mainAngle = Math.Round(mainAngle/15) * 15; // расставить направления по приоритету const int numAngles = 8; var angles = new double[numAngles]; angles[0] = mainAngle; for (var i = 0; i < numAngles / 2 - 1; i++) { var delta = (i + 1) * 360 / numAngles; angles[i * 2 + 1] = mainAngle + delta; angles[i * 2 + 2] = mainAngle - delta; } angles[numAngles - 1] = -mainAngle; // выбрать направление, для которого комментарий не вылезает за рамки экрана var foundAngle = false; var screenRect = seriesComment.Owner.CanvasRect; using (var gr = owner.CreateGraphics()) foreach (var angle in angles) { comment.ArrowAngle = angle; var commentRect = comment.GetCommentRectangle(gr, owner.StockPane.WorldRect, owner.StockPane.CanvasRect); // не вылез ли комментарий за пределы экрана? if (commentRect.Left < screenRect.Left || commentRect.Top < screenRect.Top || commentRect.Right > screenRect.Right || commentRect.Bottom > screenRect.Bottom) continue; foundAngle = true; break; } // угол поворота по-умолчанию if (!foundAngle) comment.ArrowAngle = angles[0]; }
private void DrawCommentForSelected(Graphics g, RectangleD worldRect, Rectangle canvasRect, PenStorage pens, BrushesStorage brushes) { if (string.IsNullOrEmpty(Comment)) return; var commentBox = new ChartComment { Color = LineColor, ColorFill = ShapeFillColor, Text = Comment, HideArrow = true, FillTransparency = 160 }; var textRect = commentBox.GetCommentRectangle(g, worldRect, canvasRect); // прикинуть, куда лучше захреначить комментарий - в центр или в конец // спроецировать координаты курсора на линию var cursorPoint = Owner.Owner.PointToClient(Control.MousePosition); var screenPoints = linePoints.Select(p => Conversion.WorldToScreenF(p, worldRect, canvasRect)).ToList(); var pivot = Geometry.GetProjectionPointOnLine(cursorPoint, screenPoints[0], screenPoints[1]); // пробуем два варианта размещения - привязываем левый верхний или // правый нижний углы комментария, смотрим, какой вариант ближе к центру экрана var potentialPivots = new [] { new PointF(pivot.X, pivot.Y + textRect.Height/2), new PointF(pivot.X - textRect.Width, pivot.Y - textRect.Height/2) }; var cx = canvasRect.Left + canvasRect.Width / 2; var cy = canvasRect.Top + canvasRect.Height / 2; var bestPivotIndex = potentialPivots.IndexOfMin(p => (p.X - cx)*(p.X - cx) + (p.Y - cy)*(p.Y - cy)); pivot = potentialPivots[bestPivotIndex]; var worldPivotPoint = Conversion.ScreenToWorld(pivot, worldRect, canvasRect); commentBox.PivotPrice = worldPivotPoint.Y; commentBox.PivotIndex = worldPivotPoint.X; // таки нарисовать using (var fonts = new FontStorage(Owner.Owner.Owner.Font)) commentBox.DrawComment(g, fonts, worldRect, canvasRect, pens, brushes, new List<Rectangle>()); }