protected void DrawHorizontalBezier(ILineDataSet dataSet) { float phaseY = Animator.PhaseY; var trans = Chart.GetTransformer(dataSet.AxisDependency); XBounds.Set(Chart, dataSet, Animator); CubicPath.Reset(); if (XBounds.Range >= 1) { var prev = ((IDataSet <Entry>)dataSet)[XBounds.Min]; var cur = prev; // let the spline start CubicPath.MoveTo(cur.X, cur.Y * phaseY); for (int j = XBounds.Min + 1; j <= XBounds.Range + XBounds.Min; j++) { prev = cur; cur = ((IDataSet <Entry>)dataSet)[j]; float cpx = (prev.X) + (cur.X - prev.X) / 2.0f; CubicPath.CubicTo( cpx, prev.Y * phaseY, cpx, cur.Y * phaseY, cur.X, cur.Y * phaseY); } } // if filled is enabled, close the path if (dataSet.DrawFilled) { CubicFillPath.Reset(); CubicFillPath.AddPath(CubicPath); // create a new path, this is bad for performance DrawCubicFill(BitmapCanvas, dataSet, CubicFillPath, trans, XBounds); } RenderPaint.Color = dataSet.Color; RenderPaint.Style = SKPaintStyle.Stroke; trans.PathValueToPixel(CubicPath); BitmapCanvas.DrawPath(CubicPath, RenderPaint); RenderPaint.PathEffect = null; }
/// <inheritdoc /> public override int GetHashCode() { unchecked // Overflow is fine, just wrap { var hashCode = 41; if (Type != null) { hashCode = hashCode * 59 + Type.GetHashCode(); } if (Visible != null) { hashCode = hashCode * 59 + Visible.GetHashCode(); } if (ShowLegend != null) { hashCode = hashCode * 59 + ShowLegend.GetHashCode(); } if (LegendGroup != null) { hashCode = hashCode * 59 + LegendGroup.GetHashCode(); } if (Opacity != null) { hashCode = hashCode * 59 + Opacity.GetHashCode(); } if (Name != null) { hashCode = hashCode * 59 + Name.GetHashCode(); } if (UId != null) { hashCode = hashCode * 59 + UId.GetHashCode(); } if (Ids != null) { hashCode = hashCode * 59 + Ids.GetHashCode(); } if (CustomData != null) { hashCode = hashCode * 59 + CustomData.GetHashCode(); } if (Meta != null) { hashCode = hashCode * 59 + Meta.GetHashCode(); } if (MetaArray != null) { hashCode = hashCode * 59 + MetaArray.GetHashCode(); } if (HoverInfo != null) { hashCode = hashCode * 59 + HoverInfo.GetHashCode(); } if (HoverInfoArray != null) { hashCode = hashCode * 59 + HoverInfoArray.GetHashCode(); } if (HoverLabel != null) { hashCode = hashCode * 59 + HoverLabel.GetHashCode(); } if (Stream != null) { hashCode = hashCode * 59 + Stream.GetHashCode(); } if (UiRevision != null) { hashCode = hashCode * 59 + UiRevision.GetHashCode(); } if (X != null) { hashCode = hashCode * 59 + X.GetHashCode(); } if (Y != null) { hashCode = hashCode * 59 + Y.GetHashCode(); } if (XY != null) { hashCode = hashCode * 59 + XY.GetHashCode(); } if (Indices != null) { hashCode = hashCode * 59 + Indices.GetHashCode(); } if (XBounds != null) { hashCode = hashCode * 59 + XBounds.GetHashCode(); } if (YBounds != null) { hashCode = hashCode * 59 + YBounds.GetHashCode(); } if (Text != null) { hashCode = hashCode * 59 + Text.GetHashCode(); } if (TextArray != null) { hashCode = hashCode * 59 + TextArray.GetHashCode(); } if (Marker != null) { hashCode = hashCode * 59 + Marker.GetHashCode(); } if (XAxis != null) { hashCode = hashCode * 59 + XAxis.GetHashCode(); } if (YAxis != null) { hashCode = hashCode * 59 + YAxis.GetHashCode(); } if (IdsSrc != null) { hashCode = hashCode * 59 + IdsSrc.GetHashCode(); } if (CustomDataSrc != null) { hashCode = hashCode * 59 + CustomDataSrc.GetHashCode(); } if (MetaSrc != null) { hashCode = hashCode * 59 + MetaSrc.GetHashCode(); } if (HoverInfoSrc != null) { hashCode = hashCode * 59 + HoverInfoSrc.GetHashCode(); } if (XSrc != null) { hashCode = hashCode * 59 + XSrc.GetHashCode(); } if (YSrc != null) { hashCode = hashCode * 59 + YSrc.GetHashCode(); } if (XYSrc != null) { hashCode = hashCode * 59 + XYSrc.GetHashCode(); } if (IndicesSrc != null) { hashCode = hashCode * 59 + IndicesSrc.GetHashCode(); } if (XBoundsSrc != null) { hashCode = hashCode * 59 + XBoundsSrc.GetHashCode(); } if (YBoundsSrc != null) { hashCode = hashCode * 59 + YBoundsSrc.GetHashCode(); } if (TextSrc != null) { hashCode = hashCode * 59 + TextSrc.GetHashCode(); } return(hashCode); } }
/// <inheritdoc /> public bool Equals([AllowNull] PointCloud other) { if (other == null) { return(false); } if (ReferenceEquals(this, other)) { return(true); } return (( Type == other.Type || Type != null && Type.Equals(other.Type) ) && ( Visible == other.Visible || Visible != null && Visible.Equals(other.Visible) ) && ( ShowLegend == other.ShowLegend || ShowLegend != null && ShowLegend.Equals(other.ShowLegend) ) && ( LegendGroup == other.LegendGroup || LegendGroup != null && LegendGroup.Equals(other.LegendGroup) ) && ( Opacity == other.Opacity || Opacity != null && Opacity.Equals(other.Opacity) ) && ( Name == other.Name || Name != null && Name.Equals(other.Name) ) && ( UId == other.UId || UId != null && UId.Equals(other.UId) ) && ( Equals(Ids, other.Ids) || Ids != null && other.Ids != null && Ids.SequenceEqual(other.Ids) ) && ( Equals(CustomData, other.CustomData) || CustomData != null && other.CustomData != null && CustomData.SequenceEqual(other.CustomData) ) && ( Meta == other.Meta || Meta != null && Meta.Equals(other.Meta) ) && ( Equals(MetaArray, other.MetaArray) || MetaArray != null && other.MetaArray != null && MetaArray.SequenceEqual(other.MetaArray) ) && ( HoverInfo == other.HoverInfo || HoverInfo != null && HoverInfo.Equals(other.HoverInfo) ) && ( Equals(HoverInfoArray, other.HoverInfoArray) || HoverInfoArray != null && other.HoverInfoArray != null && HoverInfoArray.SequenceEqual(other.HoverInfoArray) ) && ( HoverLabel == other.HoverLabel || HoverLabel != null && HoverLabel.Equals(other.HoverLabel) ) && ( Stream == other.Stream || Stream != null && Stream.Equals(other.Stream) ) && ( UiRevision == other.UiRevision || UiRevision != null && UiRevision.Equals(other.UiRevision) ) && ( Equals(X, other.X) || X != null && other.X != null && X.SequenceEqual(other.X) ) && ( Equals(Y, other.Y) || Y != null && other.Y != null && Y.SequenceEqual(other.Y) ) && ( Equals(XY, other.XY) || XY != null && other.XY != null && XY.SequenceEqual(other.XY) ) && ( Equals(Indices, other.Indices) || Indices != null && other.Indices != null && Indices.SequenceEqual(other.Indices) ) && ( Equals(XBounds, other.XBounds) || XBounds != null && other.XBounds != null && XBounds.SequenceEqual(other.XBounds) ) && ( Equals(YBounds, other.YBounds) || YBounds != null && other.YBounds != null && YBounds.SequenceEqual(other.YBounds) ) && ( Text == other.Text || Text != null && Text.Equals(other.Text) ) && ( Equals(TextArray, other.TextArray) || TextArray != null && other.TextArray != null && TextArray.SequenceEqual(other.TextArray) ) && ( Marker == other.Marker || Marker != null && Marker.Equals(other.Marker) ) && ( XAxis == other.XAxis || XAxis != null && XAxis.Equals(other.XAxis) ) && ( YAxis == other.YAxis || YAxis != null && YAxis.Equals(other.YAxis) ) && ( IdsSrc == other.IdsSrc || IdsSrc != null && IdsSrc.Equals(other.IdsSrc) ) && ( CustomDataSrc == other.CustomDataSrc || CustomDataSrc != null && CustomDataSrc.Equals(other.CustomDataSrc) ) && ( MetaSrc == other.MetaSrc || MetaSrc != null && MetaSrc.Equals(other.MetaSrc) ) && ( HoverInfoSrc == other.HoverInfoSrc || HoverInfoSrc != null && HoverInfoSrc.Equals(other.HoverInfoSrc) ) && ( XSrc == other.XSrc || XSrc != null && XSrc.Equals(other.XSrc) ) && ( YSrc == other.YSrc || YSrc != null && YSrc.Equals(other.YSrc) ) && ( XYSrc == other.XYSrc || XYSrc != null && XYSrc.Equals(other.XYSrc) ) && ( IndicesSrc == other.IndicesSrc || IndicesSrc != null && IndicesSrc.Equals(other.IndicesSrc) ) && ( XBoundsSrc == other.XBoundsSrc || XBoundsSrc != null && XBoundsSrc.Equals(other.XBoundsSrc) ) && ( YBoundsSrc == other.YBoundsSrc || YBoundsSrc != null && YBoundsSrc.Equals(other.YBoundsSrc) ) && ( TextSrc == other.TextSrc || TextSrc != null && TextSrc.Equals(other.TextSrc) )); }
protected void DrawCircles(SKCanvas c) { RenderPaint.Style = SKPaintStyle.Fill; float phaseY = Animator.PhaseY; var dataSets = ((Interfaces.DataProvider.ILineChartProvider)Chart).Data.DataSets; for (int i = 0; i < dataSets.Count; i++) { ILineDataSet dataSet = dataSets[i]; if (!dataSet.IsVisible || !dataSet.IsDrawCirclesEnabled || dataSet.EntryCount == 0) { continue; } CirclePaintInner.Color = dataSet.CircleHoleColor; Transformer trans = Chart.GetTransformer(dataSet.AxisDependency); XBounds.Set(Chart, dataSet, Animator); float circleRadius = dataSet.CircleRadius; float circleHoleRadius = dataSet.CircleHoleRadius; var drawCircleHole = dataSet.IsDrawCircleHoleEnabled && circleHoleRadius <circleRadius && circleHoleRadius> 0.0f; var drawTransparentCircleHole = drawCircleHole && dataSet.CircleHoleColor == SKColors.Empty; if (imageCaches.TryGetValue(dataSet, out DataSetImageCache imageCache) == false) { imageCache = new DataSetImageCache(); imageCaches.Add(dataSet, imageCache); } // only fill the cache with new bitmaps if a change is required if (imageCache.Init(dataSet)) { Fill(imageCache, dataSet, drawCircleHole, drawTransparentCircleHole); } int boundsRangeCount = XBounds.Range + XBounds.Min; for (int j = XBounds.Min; j <= boundsRangeCount; j++) { Entry e = ((IDataSet)dataSet)[j]; if (e == null) { break; } var pt = trans.PointValueToPixel(e.X, e.Y * phaseY); if (!ViewPortHandler.IsInBoundsRight(pt.X)) { break; } if (!ViewPortHandler.IsInBoundsLeft(pt.X) || !ViewPortHandler.IsInBoundsY(pt.Y)) { continue; } var circleBitmap = imageCache.GetBitmap(j); if (circleBitmap != null) { c.DrawBitmap(circleBitmap, pt.X - circleRadius, pt.Y - circleRadius, null); } } } }
public override void DrawValues(SKCanvas c) { if (IsDrawingValuesAllowed(Chart)) { var dataSets = ((Interfaces.DataProvider.ILineChartProvider)Chart).Data.DataSets; for (int i = 0; i < dataSets.Count; i++) { ILineDataSet dataSet = dataSets[i]; if (!ShouldDrawValues(dataSet) || dataSet.EntryCount < 1) { continue; } // apply the text-styling defined by the DataSet ApplyValueTextStyle(dataSet); Transformer trans = Chart.GetTransformer(dataSet.AxisDependency); // make sure the values do not interfear with the circles int valOffset = (int)(dataSet.CircleRadius * 1.75f); if (!dataSet.IsDrawCirclesEnabled) { valOffset /= 2; } XBounds.Set(Chart, dataSet, Animator); var positions = trans.GenerateTransformedValuesLine(dataSet, Animator.PhaseX, Animator .PhaseY, XBounds.Min, XBounds.Max); var iconsOffset = dataSet.IconsOffset.DpToPixel(); for (int j = 0; j < positions.Length; j++) { var pos = positions[j]; if (!ViewPortHandler.IsInBoundsRight(pos.X)) { break; } if (!ViewPortHandler.IsInBoundsLeft(pos.X) || !ViewPortHandler.IsInBoundsY(pos.Y)) { continue; } Entry entry = ((IDataSet)dataSet)[j + XBounds.Min]; if (dataSet.IsDrawValuesEnabled) { DrawValue(c, dataSet.ValueFormatter, entry.Y, entry, i, pos.X, pos.Y - valOffset, dataSet.ValueTextColorAt(j)); } if (entry.Icon != null && dataSet.IsDrawIconsEnabled) { entry.Icon.Draw( c, (int)(pos.X + iconsOffset.X), (int)(pos.Y + iconsOffset.Y)); } } } } }
protected void DrawCubicBezier(ILineDataSet lineDataSet) { float phaseY = Animator.PhaseY; Transformer trans = Chart.GetTransformer(lineDataSet.AxisDependency); XBounds.Set(Chart, lineDataSet, Animator); float intensity = lineDataSet.CubicIntensity; CubicPath.Reset(); IDataSet <Entry> dataSet = lineDataSet; if (XBounds.Range >= 1) { // Take an extra point from the left, and an extra from the right. // That's because we need 4 points for a cubic bezier (cubic=4), otherwise we get lines moving and doing weird stuff on the edges of the chart. // So in the starting `prev` and `cur`, go -2, -1 // And in the `lastIndex`, add +1 int firstIndex = XBounds.Min + 1; Entry prevPrev; Entry prev = dataSet[Math.Max(firstIndex - 2, 0)]; Entry cur = dataSet[Math.Max(firstIndex - 1, 0)]; Entry next = cur; int nextIndex = -1; if (cur == null) { return; } // let the spline start CubicPath.MoveTo(cur.X, cur.Y * phaseY); for (int j = XBounds.Min + 1; j <= XBounds.Range + XBounds.Min; j++) { prevPrev = prev; prev = cur; cur = nextIndex == j ? next : dataSet[j]; nextIndex = j + 1 < lineDataSet.EntryCount ? j + 1 : j; next = dataSet[nextIndex]; float prevDx = (cur.X - prevPrev.X) * intensity; float prevDy = (cur.Y - prevPrev.Y) * intensity; float curDx = (next.X - prev.X) * intensity; float curDy = (next.Y - prev.Y) * intensity; CubicPath.CubicTo(prev.X + prevDx, (prev.Y + prevDy) * phaseY, cur.X - curDx, (cur.Y - curDy) * phaseY, cur.X, cur.Y * phaseY); } } // if filled is enabled, close the path if (lineDataSet.DrawFilled) { CubicFillPath.Reset(); CubicFillPath.AddPath(CubicPath); DrawCubicFill(BitmapCanvas, lineDataSet, CubicFillPath, trans, XBounds); } RenderPaint.Color = lineDataSet.Color; RenderPaint.Style = SKPaintStyle.Stroke; trans.PathValueToPixel(CubicPath); BitmapCanvas.DrawPath(CubicPath, RenderPaint); RenderPaint.PathEffect = null; }
protected void DrawLinear(SKCanvas c, ILineDataSet lineDataSet) { int entryCount = lineDataSet.EntryCount; bool isDrawSteppedEnabled = lineDataSet.Mode == LineDataSet.LineMode.Stepped; int pointsPerEntryPair = isDrawSteppedEnabled ? 4 : 2; Transformer trans = Chart.GetTransformer(lineDataSet.AxisDependency); float phaseY = Animator.PhaseY; RenderPaint.Style = SKPaintStyle.Stroke; SKCanvas canvas; // if the data-set is dashed, draw on bitmap-canvas if (lineDataSet.IsDashedLineEnabled) { canvas = BitmapCanvas; } else { canvas = c; } XBounds.Set(Chart, lineDataSet, Animator); // if drawing filled is enabled if (lineDataSet.DrawFilled && entryCount > 0) { DrawLinearFill(c, lineDataSet, trans, XBounds); } // more than 1 color if (lineDataSet.Colors.Count > 1) { int numberOfFloats = pointsPerEntryPair; if (_lineBuffer.Length <= numberOfFloats) { _lineBuffer = new SKPoint[numberOfFloats]; } int max = XBounds.Min + XBounds.Range; IDataSet <Entry> dataSet = lineDataSet; for (int j = XBounds.Min; j < max; j++) { Entry e = dataSet[j]; if (e == null) { continue; } _lineBuffer[0] = new SKPoint(e.X, e.Y * phaseY); if (j < XBounds.Max) { e = dataSet[j + 1]; if (e == null) { break; } if (isDrawSteppedEnabled) { _lineBuffer[1] = new SKPoint(e.X, _lineBuffer[0].Y); _lineBuffer[2] = _lineBuffer[1]; _lineBuffer[3] = new SKPoint(e.X, e.Y * phaseY); } else { _lineBuffer[1] = new SKPoint(e.X, e.Y * phaseY); } } else { _lineBuffer[1] = _lineBuffer[0]; } var pts = trans.PointValuesToPixel(_lineBuffer); // Determine the start and end coordinates of the line, and make sure they differ. var firstCoordinate = pts[0]; var lastCoordinate = pts[numberOfFloats - 1]; if (firstCoordinate == lastCoordinate) { continue; } if (!ViewPortHandler.IsInBoundsRight(firstCoordinate.X)) { break; } // make sure the lines don't do shitty things outside // bounds if (!ViewPortHandler.IsInBoundsLeft(lastCoordinate.X) || !ViewPortHandler.IsInBoundsTop(Math.Max(firstCoordinate.Y, lastCoordinate.Y)) || !ViewPortHandler.IsInBoundsBottom(Math.Min(firstCoordinate.Y, lastCoordinate.Y))) { continue; } // get the color that is set for this line-segment RenderPaint.Color = lineDataSet.ColorAt(j); for (int i = 0; i < numberOfFloats; i += 2) { canvas.DrawLine(pts[i], pts[i + 1], RenderPaint); } } } else { // only one color per dataset if (_lineBuffer.Length < Math.Max(entryCount * pointsPerEntryPair, pointsPerEntryPair)) { _lineBuffer = new SKPoint[Math.Max(entryCount * pointsPerEntryPair, pointsPerEntryPair) * 2]; } Entry e1, e2; IDataSet <Entry> dataSet = lineDataSet; e1 = dataSet[XBounds.Min]; if (e1 != null) { int j = 0; for (int x = XBounds.Min; x <= XBounds.Range + XBounds.Min; x++) { e1 = dataSet[x == 0 ? 0 : (x - 1)]; e2 = dataSet[x]; if (e1 == null || e2 == null) { continue; } _lineBuffer[j++] = new SKPoint(e1.X, e1.Y * phaseY); if (isDrawSteppedEnabled) { _lineBuffer[j++] = new SKPoint(e2.X, e1.Y * phaseY); _lineBuffer[j++] = new SKPoint(e2.X, e1.Y * phaseY); } _lineBuffer[j++] = new SKPoint(e2.X, e2.Y * phaseY); } if (j > 0) { var pts = trans.PointValuesToPixel(_lineBuffer); int size = Math.Max((XBounds.Range + 1) * pointsPerEntryPair, pointsPerEntryPair); RenderPaint.Color = lineDataSet.Color; for (int i = 0; i < size; i += 2) { canvas.DrawLine(pts[i], pts[i + 1], RenderPaint); } } } } RenderPaint.PathEffect = null; }