/// <summary>
        /// Fast index of bar where max(bar[i].X) &lt;= x
        /// </summary>
        /// <returns>The index of the bar closest to X, where max(bar[i].X) &lt;= x.</returns>
        /// <param name="x">The x coordinate.</param>
        /// <param name="startIndex">starting index</param>
        public int FindByX(double x, int startIndex = -1)
        {
            if (startIndex < 0)
            {
                startIndex = this.winIndex;
            }

            return(HighLowItem.FindIndex(this.Items, x, startIndex));
        }
Beispiel #2
0
 /// <summary>
 /// Determines whether the point is valid.
 /// </summary>
 /// <param name="pt">The point.</param>
 /// <param name="xaxis">The x axis.</param>
 /// <param name="yaxis">The y axis.</param>
 /// <returns><c>true</c> if the specified point is valid; otherwise, <c>false</c>.</returns>
 public virtual bool IsValidItem(HighLowItem pt, Axis xaxis, Axis yaxis)
 {
     return(!double.IsNaN(pt.X) && !double.IsInfinity(pt.X) && !double.IsNaN(pt.High) &&
            !double.IsInfinity(pt.High) && !double.IsNaN(pt.Low) && !double.IsInfinity(pt.Low));
 }
        /// <summary>
        /// Renders the series on the specified rendering context.
        /// </summary>
        /// <param name="rc">The rendering context.</param>
        public override void Render(IRenderContext rc)
        {
            var nitems = this.Items.Count;
            var items  = this.Items;

            if (nitems == 0 || this.StrokeThickness <= 0 || this.LineStyle == LineStyle.None)
            {
                return;
            }

            this.VerifyAxes();

            var clippingRect = this.GetClippingRect();
            var dashArray    = this.LineStyle.GetDashArray();

            var datacandlewidth = (this.CandleWidth > 0) ? this.CandleWidth : this.minDx * 0.80;
            var candlewidth     =
                this.XAxis.Transform(items[0].X + datacandlewidth) -
                this.XAxis.Transform(items[0].X);

            // colors
            var fillUp   = this.GetSelectableFillColor(this.IncreasingColor);
            var fillDown = this.GetSelectableFillColor(this.DecreasingColor);
            var lineUp   = this.GetSelectableColor(this.IncreasingColor.ChangeIntensity(0.70));
            var lineDown = this.GetSelectableColor(this.DecreasingColor.ChangeIntensity(0.70));

            // determine render range
            var xmin = this.XAxis.ActualMinimum;
            var xmax = this.XAxis.ActualMaximum;

            this.winIndex = HighLowItem.FindIndex(items, xmin, this.winIndex);

            for (int i = this.winIndex; i < nitems; i++)
            {
                var bar = items[i];

                // if item beyond visible range, done
                if (bar.X > xmax)
                {
                    return;
                }

                // check to see whether is valid
                if (!this.IsValidItem(bar, this.XAxis, this.YAxis))
                {
                    continue;
                }

                var fillColor = bar.Close > bar.Open ? fillUp : fillDown;
                var lineColor = bar.Close > bar.Open ? lineUp : lineDown;

                var high = this.Transform(bar.X, bar.High);
                var low  = this.Transform(bar.X, bar.Low);

                var open  = this.Transform(bar.X, bar.Open);
                var close = this.Transform(bar.X, bar.Close);
                var max   = new ScreenPoint(open.X, Math.Max(open.Y, close.Y));
                var min   = new ScreenPoint(open.X, Math.Min(open.Y, close.Y));

                // Upper extent
                rc.DrawClippedLine(
                    clippingRect,
                    new[] { high, min },
                    0,
                    lineColor,
                    this.StrokeThickness,
                    dashArray,
                    this.LineJoin,
                    true);

                // Lower extent
                rc.DrawClippedLine(
                    clippingRect,
                    new[] { max, low },
                    0,
                    lineColor,
                    this.StrokeThickness,
                    dashArray,
                    this.LineJoin,
                    true);

                // Body
                var openLeft = open + new ScreenVector(-candlewidth * 0.5, 0);
                var rect     = new OxyRect(openLeft.X, min.Y, candlewidth, max.Y - min.Y);
                rc.DrawClippedRectangleAsPolygon(clippingRect, rect, fillColor, lineColor, this.StrokeThickness);
            }
        }
        /// <summary>
        /// Gets the point on the series that is nearest the specified point.
        /// </summary>
        /// <param name="point">The point.</param>
        /// <param name="interpolate">Interpolate the series if this flag is set to <c>true</c>.</param>
        /// <returns>A TrackerHitResult for the current hit.</returns>
        public override TrackerHitResult GetNearestPoint(ScreenPoint point, bool interpolate)
        {
            if (this.XAxis == null || this.YAxis == null || interpolate || this.Items.Count == 0)
            {
                return(null);
            }

            var nbars   = this.Items.Count;
            var xy      = this.InverseTransform(point);
            var targetX = xy.X;

            // punt if beyond start & end of series
            if (targetX > (this.Items[nbars - 1].X + this.minDx) || targetX < (this.Items[0].X - this.minDx))
            {
                return(null);
            }

            var pidx = HighLowItem.FindIndex(this.Items, targetX, this.winIndex);
            var nidx = ((pidx + 1) < this.Items.Count) ? pidx + 1 : pidx;

            Func <HighLowItem, double> distance = bar =>
            {
                var dx  = bar.X - xy.X;
                var dyo = bar.Open - xy.Y;
                var dyh = bar.High - xy.Y;
                var dyl = bar.Low - xy.Y;
                var dyc = bar.Close - xy.Y;

                var d2O = (dx * dx) + (dyo * dyo);
                var d2H = (dx * dx) + (dyh * dyh);
                var d2L = (dx * dx) + (dyl * dyl);
                var d2C = (dx * dx) + (dyc * dyc);

                return(Math.Min(d2O, Math.Min(d2H, Math.Min(d2L, d2C))));
            };

            // determine closest point
            var midx = distance(this.Items[pidx]) <= distance(this.Items[nidx]) ? pidx : nidx;
            var mbar = this.Items[midx];

            var hit = new DataPoint(mbar.X, mbar.Close);

            return(new TrackerHitResult
            {
                Series = this,
                DataPoint = hit,
                Position = this.Transform(hit),
                Item = mbar,
                Index = midx,
                Text = StringHelper.Format(
                    this.ActualCulture,
                    this.TrackerFormatString,
                    mbar,
                    this.Title,
                    this.XAxis.Title ?? DefaultXAxisTitle,
                    this.XAxis.GetValue(mbar.X),
                    this.YAxis.GetValue(mbar.High),
                    this.YAxis.GetValue(mbar.Low),
                    this.YAxis.GetValue(mbar.Open),
                    this.YAxis.GetValue(mbar.Close))
            });
        }
Beispiel #5
0
 /// <summary>
 /// Determines whether the point is valid.
 /// </summary>
 /// <param name="pt">The point.</param>
 /// <param name="xaxis">The x axis.</param>
 /// <param name="yaxis">The y axis.</param>
 /// <returns><c>true</c> if [is valid point] [the specified pt]; otherwise, <c>false</c>.</returns>
 public virtual bool IsValidItem(HighLowItem pt, Axis xaxis, Axis yaxis)
 {
     return !double.IsNaN(pt.X) && !double.IsInfinity(pt.X) && !double.IsNaN(pt.High)
            && !double.IsInfinity(pt.High) && !double.IsNaN(pt.Low) && !double.IsInfinity(pt.Low);
 }