public static void DrawFormattedText(this Graphics g, float x, float y, BrushesStorage brushes, Color colorMain, string text, FontStorage fonts) { if (string.IsNullOrEmpty(text)) { return; } var lines = text.Split(lineSeparator, StringSplitOptions.RemoveEmptyEntries); var totalHeight = 0f; foreach (var line in lines) { FontStyle fontStyle; Color? fontColor; var pureLine = GetLineModifiers(line, out fontStyle, out fontColor); var font = fonts.GetFont(fontStyle); g.DrawString(pureLine, font, brushes.GetBrush(fontColor ?? colorMain), x, y + totalHeight); var dH = font.GetHeight(g); totalHeight += dH; } }
/// <summary> /// для простоты - каждая строка текста имеет свой формат /// необязательные модификаторы вида [b][i][u][#RRGGBB] идут _в начале_ строки /// [b][i][u][#ff00e6]This is a bold/italic/underlined magenta line of text /// </summary> public static SizeF MeasureFormattedText(this Graphics g, string text, FontStorage fonts) { if (string.IsNullOrEmpty(text)) { return(new SizeF(0, 0)); } var lines = text.Split(lineSeparator, StringSplitOptions.RemoveEmptyEntries); var totalHeight = 0f; var totalWidth = 0f; foreach (var line in lines) { FontStyle fontStyle; Color? fontColor; var pureLine = GetLineModifiers(line, out fontStyle, out fontColor); var font = fonts.GetFont(fontStyle); var dH = font.GetHeight(g); totalHeight += dH; if (string.IsNullOrEmpty(pureLine)) { continue; } var sz = g.MeasureString(pureLine, font); if (sz.Width > totalWidth) { totalWidth = sz.Width; } } return(new SizeF(totalWidth, totalHeight)); }
public Image CreateSample(Size sizeHint) { var series = Owner as SeriesComment; if (series == null) return null; var oldArrowLength = ArrowLength; var oldArrowAngle = ArrowAngle; ArrowLength = 20; ArrowAngle = 45 * Math.PI / 180; var result = new Bitmap(sizeHint.Width, sizeHint.Height); var fonts = new FontStorage(new Font(FontFamily.GenericSansSerif, 8)); var size = MeasureCommentBlock(Graphics.FromImage(result), fonts, string.IsNullOrEmpty(Text) ? "" : Text); if (!HideArrow) { size.Width += (float) (ArrowLength * Math.Cos(ArrowAngle)); size.Height += (float) (ArrowLength * Math.Sin(ArrowAngle)); } if (size.Width < sizeHint.Width) size.Width = sizeHint.Width; if (size.Height < sizeHint.Height) size.Height = sizeHint.Height; var canvasRect = new Rectangle(new Point(0, 0), size.ToSize()); result = new Bitmap(canvasRect.Width, canvasRect.Height); DrawComment(Graphics.FromImage(result), fonts, new RectangleD(PivotIndex, PivotPrice, 0, 0), canvasRect, new PenStorage(), new BrushesStorage(), null); ArrowLength = oldArrowLength; ArrowAngle = oldArrowAngle; return result; }
private void DrawComments(Graphics g, RectangleD worldRect, Rectangle canvasRect) { List<Rectangle> areasDrawn = null; // контроль перекрывающихся комментов if (hideSpannedComments) areasDrawn = new List<Rectangle>(); using (var fonts = new FontStorage(new Font(Chart.Font.FontFamily, fontSize, FontBold ? FontStyle.Bold : FontStyle.Regular))) using (var penStorage = new PenStorage()) using (var brushStorage = new BrushesStorage()) { for (var i = data.Count - 1; i >= 0; i--) { data[i].DrawComment(g, fonts, worldRect, canvasRect, penStorage, brushStorage, areasDrawn); if (!hideSpannedComments) continue; } } }
public RectangleF GetCommentRectangle(Graphics g, RectangleD worldRect, Rectangle canvasRect) { // точка привязки var ptPivot = Conversion.WorldToScreen(new PointD(PivotIndex, PivotPrice), worldRect, canvasRect); // вторая точка стрелки var angle = GetNormalizedArrowAngle(); var ptEnd = new PointD(ptPivot.X + ArrowLength * Math.Cos(angle), ptPivot.Y + ArrowLength * Math.Sin(angle)); var fontSize = Owner == null ? 8 : SeriesComment.FontSize; var fontStyle = SeriesComment.FontBold ? FontStyle.Bold : FontStyle.Regular; using (var fonts = new FontStorage(new Font(FontFamily.GenericSansSerif, fontSize, fontStyle))) { float top, left, width, height; GetTextAreaLeftTop(g, fonts, Text, arrowAngle, ptEnd, out left, out top, out width, out height); return new RectangleF(left, top, width, height); } }
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>()); }
/// <summary> /// определить координаты рамки с текстом, получив на входе /// нормализованный угол линии и конечную точку /// </summary> private void GetTextAreaLeftTop(Graphics g, FontStorage font, string commentText, double arrowAngle, PointD ptEnd, out float left, out float top, out float width, out float height) { const int textShift = 7; var textSz = MeasureCommentBlock(g, font, commentText); textSz.Width += textShift * 2; textSz.Height += textShift * 2; width = textSz.Width; height = textSz.Height; const double PI4 = .785398, PI34 = 2.356194, PI54 = 3.926991, PI74 = 5.497787; if (arrowAngle >= PI4 && arrowAngle < PI34) {// квадрат снизу left = (float)ptEnd.X - textSz.Width / 2; top = (float)ptEnd.Y; } else if (arrowAngle >= PI34 && arrowAngle < PI54) {// квадрат слева left = (float)ptEnd.X - textSz.Width; top = (float)ptEnd.Y - textSz.Height / 2; } else if (arrowAngle >= PI54 && arrowAngle < PI74) {// квадрат сверху left = (float)ptEnd.X - textSz.Width / 2; top = (float)ptEnd.Y - textSz.Height; } else {// квадрат справа left = (float)ptEnd.X; top = (float)ptEnd.Y - textSz.Height / 2; } }
public void DrawComment( Graphics g, FontStorage fonts, RectangleD worldRect, Rectangle canvasRect, PenStorage penStorage, BrushesStorage brushStorage, List<Rectangle> areasToCheck) { var oldMode = g.SmoothingMode; g.SmoothingMode = /*SmoothingMode.AntiAlias : */SmoothingMode.None; try { var brush = brushStorage.GetBrush(Color.FromArgb(FillTransparency, ColorFill)); // нормализовать угол стрелки var arrowAngle = GetNormalizedArrowAngle(); while (arrowAngle < 0) arrowAngle = Math.PI * 2 + arrowAngle; // точка привязки PointD ptPivot = Conversion.WorldToScreen(new PointD(PivotIndex, PivotPrice), worldRect, canvasRect); // вторая точка стрелки var ptEnd = new PointD(ptPivot.X + ArrowLength * Math.Cos(arrowAngle), ptPivot.Y + ArrowLength * Math.Sin(arrowAngle)); var commentText = string.IsNullOrEmpty(Text) ? "" : Text; var color = Color; commentText = GetColorByComment(commentText, ref color); ReplaceTextPatterns(); var dashStyle = IsBeingCreated ? DashStyle.Dash : DashStyle.Solid; var pen = penStorage.GetPen(color, Selected ? 3f : 1f, dashStyle); // посчитать координаты текста float top, left, width, height; GetTextAreaLeftTop(g, fonts, commentText, arrowAngle, ptEnd, out left, out top, out width, out height); // проверить пересечение с комментом if (areasToCheck != null) { var rectOwn = new Rectangle((int)top, (int)left, (int)width, (int)height); if (areasToCheck.Any(a => a.IntersectsWith(rectOwn))) return; areasToCheck.Add(rectOwn); } // нарисовать область с текстом if (!HideBox) DrawTextArea(pen, g, brush, left, top, width, height); // .. и сам текст DrawTextOrSymbol(commentText, brushStorage, fonts, ColorText, g, left, top, width, height); TextArea = new Rectangle((int)left + canvasRect.Left, (int)top, (int)width, (int)height); // нарисовать стрелку if (!HideArrow) { PointD pointArrowEnd; List<PointF> arrowPoints = GetArrowPoints(arrowAngle, ptPivot, out pointArrowEnd); // нарисовать палку g.DrawLine(pen, (float)pointArrowEnd.X, (float)pointArrowEnd.Y, (float)ptEnd.X, (float)ptEnd.Y); // нарисовать стрелочку g.FillPolygon(brush, arrowPoints.ToArray()); g.DrawPolygon(pen, arrowPoints.ToArray()); } // маркеры if (Selected) DrawMarkers(g, worldRect, canvasRect); } finally { g.SmoothingMode = oldMode; } }
private void DrawTextOrSymbol(string comment, BrushesStorage brushes, FontStorage fonts, Color commentColor, Graphics g, float left, float top, float width, float height) { const int textShift = 4; if (comment != null) if (comment.Contains(TemplateBuy) || comment.Contains(TemplateSell)) { var smb = symbolBuySell.Copy(); smb.Scale(SymbolBuySellWidth / smb.Width, SymbolBuySellHeight / smb.Height); if (comment.Contains(TemplateBuy)) { smb.Move2Point(new PointF(left + width / 2, top + height - textShift)); smb.PaintFills(Color.Blue); } if (comment.Contains(TemplateSell)) { smb.Rotate((float)-Math.PI); smb.Move2Point(new PointF(left + width / 2, top + textShift)); smb.PaintFills(Color.Red); } smb.Draw(g); return; } var text = string.IsNullOrEmpty(comment) ? "<пусто>" : comment; g.DrawFormattedText(left + textShift, top + textShift, brushes, commentColor, text, fonts); }
public SizeF MeasureCommentBlock(Graphics g, FontStorage fonts, string commentText) { if (commentText != null) if (commentText.Contains(TemplateBuy) || commentText.Contains(TemplateSell)) return new SizeF(SymbolBuySellWidth, SymbolBuySellHeight); var text = string.IsNullOrEmpty(commentText) ? "<пусто>" : commentText; return g.MeasureFormattedText(text, fonts); }
public RectangleF GetCommentRectangle(Graphics g, FontStorage fonts, RectangleD worldRect, Rectangle canvasRect) { // точка привязки var ptPivot = Conversion.WorldToScreen(new PointD(PivotIndex, PivotPrice), worldRect, canvasRect); // вторая точка стрелки var arrowAngle = GetNormalizedArrowAngle(); var ptEnd = new PointD(ptPivot.X + ArrowLength * Math.Cos(arrowAngle), ptPivot.Y + ArrowLength * Math.Sin(arrowAngle)); float top, left, width, height; GetTextAreaLeftTop(g, fonts, Text, arrowAngle, ptEnd, out left, out top, out width, out height); return new RectangleF(left, top, width, height); }