Код графического объекта Горизонтальная линия
//------------------------------------------------------------------------------ // // Графический объект HorizontalLine. Copyright (c) 2020 Ilya Smirnov. All rights reserved. // //------------------------------------------------------------------------------ using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.Serialization; using System.Windows; using System.Windows.Media; using TigerTrade.Chart.Alerts; using TigerTrade.Chart.Base; using TigerTrade.Chart.Base.Enums; using TigerTrade.Chart.Indicators.Common; using TigerTrade.Chart.Objects.Common; using TigerTrade.Chart.Objects.Enums; using TigerTrade.Core.Utils.Logging; using TigerTrade.Dx; using TigerTrade.Dx.Enums; namespace TigerTrade.Chart.Objects.Custom { [DataContract(Name = "HorizontalLineObject", Namespace = "http://schemas.datacontract.org/2004/07/TigerTrade.Chart.Objects.Custom")] [ChartObject("X_HorizontalLine", "Горизонтальная линия", 1, Type = typeof(HorizontalLineObject))] public class HorizontalLineObject : ObjectBase { [Category("Цена"), DisplayName("Цена")] public decimal Price { get => (decimal)ControlPoints[0].Y; set { if (value == (decimal)ControlPoints[0].Y) { return; } ControlPoints[0].Y = (double)value; OnPropertyChanged(); OnPropertyChanged(nameof(ControlPoints)); } } private ChartAlertSettings _alert; [DataMember(Name = "Alert")] [Category("Оповещение"), DisplayName("Оповещение")] public ChartAlertSettings Alert { get => _alert ?? (_alert = new ChartAlertSettings()); set { if (Equals(value, _alert)) { return; } _alert = value; OnPropertyChanged(); } } private int _alertMinDistance; [DataMember(Name = "AlertMinDistance")] [Category("Оповещение"), DisplayName("Мин. расстояние")] public int AlertMinDistance { get => _alertMinDistance; set { if (value == _alertMinDistance) { return; } _alertMinDistance = value; OnPropertyChanged(); } } private string _text; [DataMember(Name = "Text")] [Category("Текст"), DisplayName("Текст")] public string Text { get => _text; set { if (value == _text) { return; } _text = value; OnPropertyChanged(); } } private ObjectTextAlignment _textAlignment; [DataMember(Name = "TextAlignment")] [Category("Текст"), DisplayName("Расположение")] public ObjectTextAlignment TextAlignment { get => _textAlignment; set { if (value == _textAlignment) { return; } _textAlignment = value; OnPropertyChanged(); } } private int _fontSize; [DataMember(Name = "FontSize")] [Category("Текст"), DisplayName("Размер")] public int FontSize { get => _fontSize; set { value = Math.Max(10, Math.Min(100, value)); if (value == _fontSize) { return; } _fontSize = value; OnPropertyChanged(); } } private XBrush _lineBrush; private XPen _linePen; private XColor _lineColor; [DataMember(Name = "LineColor")] [Category("Линия"), DisplayName("Цвет линии")] public XColor LineColor { get => _lineColor; set { if (value == _lineColor) { return; } _lineColor = value; _lineBrush = new XBrush(_lineColor); _linePen = new XPen(_lineBrush, LineWidth, LineStyle); OnPropertyChanged(); } } private int _lineWidth; [DataMember(Name = "LineWidth")] [Category("Линия"), DisplayName("Толщина линии")] public int LineWidth { get => _lineWidth; set { value = Math.Max(1, Math.Min(10, value)); if (value == _lineWidth) { return; } _lineWidth = value; _linePen = new XPen(_lineBrush, _lineWidth, LineStyle); OnPropertyChanged(); } } private XDashStyle _lineStyle; [DataMember(Name = "LineStyle")] [Category("Линия"), DisplayName("Стиль линии")] public XDashStyle LineStyle { get => _lineStyle; set { if (value == _lineStyle) { return; } _lineStyle = value; _linePen = new XPen(_lineBrush, LineWidth, _lineStyle); OnPropertyChanged(); } } protected override int PenWidth => LineWidth; private Rect _lineRect; public HorizontalLineObject() { AlertMinDistance = 3; Text = ""; TextAlignment = ObjectTextAlignment.RightTop; FontSize = 14; LineColor = Colors.Black; LineWidth = 1; LineStyle = XDashStyle.Solid; } protected override void Draw(DxVisualQueue visual, ref List<ObjectLabelInfo> labels) { if (Canvas == null) { return; } var point = ToPoint(ControlPoints[0]); var startPoint = new Point(Canvas.Rect.Left, point.Y); var endPoint = new Point(Canvas.Rect.Right, point.Y); _lineRect = new Rect(startPoint, endPoint); if (Settings.TransformHorLines && Canvas.IsStock && Canvas.StockType == ChartStockType.Clusters) { var y = ControlPoints[0].Y; var step = DataProvider.Step; var price = (long)Math.Round(y / step); var y1 = GetY((price + .5) * step); var y2 = GetY((price - .5) * step); if (y2 - y1 > LineWidth + 2) { var brush = new XBrush(LineColor, LineColor.Alpha > 127 ? 127 : LineColor.Alpha); _lineRect = new Rect(new Point(startPoint.X, y1), new Point(endPoint.X, y2)); visual.FillRectangle(brush, _lineRect); DrawText(visual); labels.Add(new ObjectLabelInfo(price * step, y1, y2, LineColor)); return; } } visual.DrawLine(_linePen, startPoint, endPoint); DrawText(visual); labels.Add(new ObjectLabelInfo(ControlPoints[0].Y, LineColor)); } protected void DrawText(DxVisualQueue visual) { if (string.IsNullOrEmpty(Text) || TextAlignment == ObjectTextAlignment.Hide) { return; } var font = new XFont(Canvas.ChartFont.Name, FontSize); var textSize = font.GetSize(Text); var x = 0.0; var y = 0.0; var width = textSize.Width; switch (TextAlignment) { case ObjectTextAlignment.LeftTop: case ObjectTextAlignment.CenterTop: case ObjectTextAlignment.RightTop: y = _lineRect.Top - 4 - textSize.Height; break; case ObjectTextAlignment.LeftMiddle: case ObjectTextAlignment.CenterMiddle: case ObjectTextAlignment.RightMiddle: y = (_lineRect.Top + _lineRect.Bottom - textSize.Height) / 2.0; break; case ObjectTextAlignment.LeftBottom: case ObjectTextAlignment.CenterBottom: case ObjectTextAlignment.RightBottom: y = _lineRect.Bottom + 4; break; } switch (TextAlignment) { case ObjectTextAlignment.LeftTop: case ObjectTextAlignment.LeftMiddle: case ObjectTextAlignment.LeftBottom: x = _lineRect.X; break; case ObjectTextAlignment.CenterTop: case ObjectTextAlignment.CenterMiddle: case ObjectTextAlignment.CenterBottom: x = _lineRect.Right - (_lineRect.Width + width) / 2.0; x = Math.Max(x, _lineRect.Left); break; case ObjectTextAlignment.RightTop: case ObjectTextAlignment.RightMiddle: case ObjectTextAlignment.RightBottom: x = _lineRect.Right - width; x = Math.Max(x, _lineRect.Left); break; } var rect = new Rect(x, y, width, textSize.Height); visual.DrawString(Text, font, _lineBrush, rect); } public override void DrawControlPoints(DxVisualQueue visual) { if (_lineRect == Rect.Empty) { return; } var width = LineWidth / 2 + 4; var center = new Point((_lineRect.Left + _lineRect.Right) / 2.0, (_lineRect.Top + _lineRect.Bottom) / 2.0); var rect = new Rect(center, center); rect.Inflate(new Size(width, width)); visual.FillRectangle(Theme.ChartCpFillBrush, rect); visual.DrawRectangle(Theme.ChartCpLinePen, rect); } protected override bool InObject(int x, int y) { if (_lineRect == Rect.Empty) { return false; } var r = Rect.Inflate(_lineRect, new Size(0, 2)); return r.Contains(x, y); } protected override bool IsObjectOnChart() { return true; } public override void ApplyTheme(IChartTheme theme) { base.ApplyTheme(theme); LineColor = theme.ChartObjectLineColor; } public override void CopyTemplate(ObjectBase objectBase, bool style) { if (objectBase is HorizontalLineObject obj) { Alert.Copy(obj.Alert, !style); OnPropertyChanged(nameof(Alert)); AlertMinDistance = obj.AlertMinDistance; Text = obj.Text; TextAlignment = obj.TextAlignment; FontSize = obj.FontSize; LineColor = obj.LineColor; LineWidth = obj.LineWidth; LineStyle = obj.LineStyle; } base.CopyTemplate(objectBase, style); } private double _lastAlertValue; private int _lastAlertIndex; public override void CheckAlert(List<IndicatorBase> indicators) { if (!Alert.IsActive) { return; } try { foreach (var indicator in indicators) { if (indicator.CheckAlert(ControlPoints[0].Y, AlertMinDistance, ref _lastAlertIndex, ref _lastAlertValue)) { var message = $"{indicator.Name}: пересечение уровня {DataProvider.Symbol.FormatPrice((decimal) ControlPoints[0].Y)}."; AddAlert(Alert, message); } } } catch (Exception e) { LogManager.WriteError(e); } } } }