private void AddCurveToPoint(PointF point1, PointF point2, PointF point3) { Check(point1); Check(point2); Check(point3); #if __UNIFIED__ Control.AddCurveToPoint(point1.ToNS(), point2.ToNS(), point3.ToNS()); #else Control.AddCurveToPoint(point1.ToSD(), point2.ToSD(), point3.ToSD()); #endif }
private void Setup() { // set up events TouchUpInside += OnTapped; // create the check path var path = new CGPath(); path.MoveToPoint(5.07473346f, 20.2956615f); path.AddCurveToPoint(3.1031115f, 24.4497281f, 2f, 29.0960413f, 2f, 34f); path.AddCurveToPoint(2f, 51.673112f, 16.326888f, 66f, 34f, 66f); path.AddCurveToPoint(51.673112f, 66f, 66f, 51.673112f, 66f, 34f); path.AddCurveToPoint(66f, 16.326888f, 51.673112f, 2f, 34f, 2f); path.AddCurveToPoint(21.3077047f, 2f, 10.3412842f, 9.38934836f, 5.16807419f, 20.1007094f); path.AddLineToPoint(29.9939289f, 43.1625671f); path.AddLineToPoint(56.7161293f, 17.3530369f); shape.Path = path; circle.Path = path; check.Path = path; shape.StrokeColor = color.CGColor; circle.StrokeColor = skeletonColor.CGColor; check.StrokeColor = skeletonColor.CGColor; shape.StrokeStart = circleStrokeStart; shape.StrokeEnd = circleStrokeEnd; circle.StrokeStart = circleStrokeStart; circle.StrokeEnd = circleStrokeEnd; check.StrokeStart = checkStrokeStart; check.StrokeEnd = checkStrokeEnd; shape.LineWidth = lineWidth; circle.LineWidth = lineWidth; check.LineWidth = lineWidthBold; foreach (var layer in new[] { circle, check, shape }) { layer.FillColor = null; layer.MiterLimit = 4; layer.LineCap = CAShapeLayer.CapRound; layer.MasksToBounds = true; var strokingPath = layer.Path.CopyByStrokingPath(4f, CGLineCap.Round, CGLineJoin.Miter, 4f); layer.Bounds = strokingPath.BoundingBox; layer.Actions = NSDictionary.FromObjectsAndKeys( new[] { NSNull.Null, NSNull.Null, NSNull.Null }, new[] { "strokeStart", "strokeEnd", "transform" }); Layer.AddSublayer(layer); } }
private void AddCurveToPoint(PointF point1, PointF point2, PointF point3) { Check(point1); Check(point2); Check(point3); Control.AddCurveToPoint(point1.ToNS(), point2.ToNS(), point3.ToNS()); }
public static CGPath ToCGPath(this NSBezierPath nsPath) { var cgPath = new CGPath(); var points = null as CGPoint[]; for (int i = 0; i < nsPath.ElementCount; i++) { var type = nsPath.ElementAt(i, out points); switch (type) { case NSBezierPathElement.MoveTo: cgPath.MoveToPoint(points[0]); break; case NSBezierPathElement.LineTo: cgPath.AddLineToPoint(points[0]); break; case NSBezierPathElement.CurveTo: cgPath.AddCurveToPoint(cp1: points[0], cp2: points[1], point: points[2]); break; case NSBezierPathElement.ClosePath: cgPath.CloseSubpath(); break; } } return(cgPath); }
public static CGPath ToCGPath(this NSBezierPath bezierPath) { var path = new CGPath(); for (var i = 0; i < bezierPath.ElementCount; i++) { var type = bezierPath.ElementAt(i, out var points); switch (type) { case NSBezierPathElement.MoveTo: path.MoveToPoint(points[0]); break; case NSBezierPathElement.LineTo: path.AddLineToPoint(points[0]); break; case NSBezierPathElement.CurveTo: path.AddCurveToPoint(points[0], points[1], points[2]); break; case NSBezierPathElement.ClosePath: path.CloseSubpath(); break; } } return(path); }
public override void RelCurveTo(object backend, double dx1, double dy1, double dx2, double dy2, double dx3, double dy3) { CGPath path = (CGPath)backend; PointF p = path.CurrentPoint; path.AddCurveToPoint((float)(p.X + dx1), (float)(p.Y + dy1), (float)(p.X + dx2), (float)(p.Y + dy2), (float)(p.X + dx3), (float)(p.Y + dy3)); }
// Creates the path that we'll use to animate on. Once the path is created, it calls // DrawPathAsBackground to draw the path on the screen. protected void CreatePath() { // define our path PointF curve1StartPoint = new PointF(56, 104); PointF curve1ControlPoint1 = new PointF(50, 250); PointF curve1ControlPoint2 = new PointF(220, 450); PointF curve1EndPoint = new PointF(384, 450); PointF curve2ControlPoint1 = new PointF(500, 450); PointF curve2ControlPoint2 = new PointF(700, 650); PointF curve2EndPoint = new PointF(700, 900); animationPath.MoveToPoint(curve1StartPoint.X, curve1StartPoint.Y); animationPath.AddCurveToPoint(curve1ControlPoint1.X, curve1ControlPoint1.Y, curve1ControlPoint2.X, curve1ControlPoint2.Y, curve1EndPoint.X, curve1EndPoint.Y); animationPath.AddCurveToPoint(curve2ControlPoint1.X, curve2ControlPoint1.Y, curve2ControlPoint2.X, curve2ControlPoint2.Y, curve2EndPoint.X, curve2EndPoint.Y); // DrawPathAsBackground(); }
void PlotPath(GraphicsPath path) { float x1 = 0, y1 = 0, x2 = 0, y2 = 0, x3 = 0, y3 = 0; var points = path.PathPoints; var types = path.PathTypes; int bidx = 0; for (int i = 0; i < points.Length; i++) { var point = points [i]; var type = (PathPointType)types [i]; switch (type & PathPointType.PathTypeMask) { case PathPointType.Start: regionPath.MoveToPoint(point.ToCGPoint()); break; case PathPointType.Line: regionPath.AddLineToPoint(point.ToCGPoint()); break; case PathPointType.Bezier3: // collect 3 points switch (bidx++) { case 0: x1 = point.X; y1 = point.Y; break; case 1: x2 = point.X; y2 = point.Y; break; case 2: x3 = point.X; y3 = point.Y; break; } if (bidx == 3) { regionPath.AddCurveToPoint(x1, y1, x2, y2, x3, y3); bidx = 0; } break; default: throw new Exception("Inconsistent internal state, path type=" + type); } if ((type & PathPointType.CloseSubpath) != 0) { regionPath.CloseSubpath(); } } }
private void AppendCubicCurve(bool relative) { if (_operands.Count % 6 != 0) { throw new Exception("Invalid number of parameters for C command"); } for (int i = 0; i < _operands.Count; i += 6) { float x1 = _operands[i + 0]; float y1 = _operands[i + 1]; float x2 = _operands[i + 2]; float y2 = _operands[i + 3]; float x = _operands[i + 4]; float y = _operands[i + 5]; _spath.BezierCurveTo(x1, y1, x2, y2, x, y, relative); if (relative) { x1 += _posx; y1 += _posy; x2 += _posx; y2 += _posy; x += _posx; y += _posy; } #if OSX _cgpath.AddCurveToPoint(x1, y1, x2, y2, x, y); #endif _last_control_x = x2; _last_control_y = y2; _posx = x; _posy = y; _scaler.AddXYOperands(x1, y1); _scaler.AddXYOperands(x2, y2); _scaler.AddXYOperands(x, y); } _scaler.AddOperator('C'); }
private void CurveTo(bool isRelative) { var point = NewPoint(NextValue, NextValue, isRelative, false); var x = NextValue; var y = NextValue; var isQuad = char.IsLetter(_commandStack.Peek()[0]); var point2 = NewPoint(x, y, isRelative, isQuad); if (isQuad) { _path.AddQuadCurveToPoint(point.X, point.Y, point2.X, point2.Y); } else { var point3 = NewPoint(NextValue, NextValue, isRelative, true); _path.AddCurveToPoint(point, point2, point3); _lastCurveControlPoint = point2; } }
public static CGPath ToCGPath(this _BezierPath nSBezierPath) { #if __IOS__ return(nSBezierPath.CGPath); #elif __MACOS__ // Then draw the path elements. var numElements = nSBezierPath.ElementCount; if (numElements > 0) { var path = new CGPath(); var points = new CGPoint[3]; var didClosePath = true; for (var i = 0; i < numElements; i++) { switch (nSBezierPath.ElementAt(i, out points)) { case NSBezierPathElement.MoveTo: path.MoveToPoint(points[0].X, points[0].Y); break; case NSBezierPathElement.LineTo: path.AddLineToPoint(points[0].X, points[0].Y); didClosePath = false; break; case NSBezierPathElement.CurveTo: path.AddCurveToPoint(points[0].X, points[0].Y, points[1].X, points[1].Y, points[2].X, points[2].Y); didClosePath = false; break; case NSBezierPathElement.ClosePath: path.CloseSubpath(); didClosePath = true; break; } } // Be sure the path is closed or Quartz may not do valid hit detection. if (!didClosePath) { path.CloseSubpath(); } return(path); } return(new CGPath()); #endif }
// Creates the path that we'll use to animate on. Once the path is created, it calls // DrawPathAsBackground to draw the path on the screen. protected void CreatePath() { // define our path var curve1StartPoint = new PointF(56f, 104f); var curve1ControlPoint1 = new PointF(50f, 250f); var curve1ControlPoint2 = new PointF(220f, 450f); var curve1EndPoint = new PointF(384f, 450f); var curve2ControlPoint1 = new PointF(500f, 450f); var curve2ControlPoint2 = new PointF(700f, 650f); var curve2EndPoint = new PointF(700f, 900f); animationPath.MoveToPoint(curve1StartPoint.X, curve1StartPoint.Y); animationPath.AddCurveToPoint(curve1ControlPoint1.X, curve1ControlPoint1.Y, curve1ControlPoint2.X, curve1ControlPoint2.Y, curve1EndPoint.X, curve1EndPoint.Y); animationPath.AddCurveToPoint(curve2ControlPoint1.X, curve2ControlPoint1.Y, curve2ControlPoint2.X, curve2ControlPoint2.Y, curve2EndPoint.X, curve2EndPoint.Y); DrawPathAsBackground(); }
public ClockView () { // Set background to pink. this.BackgroundColor = UIColor.FromRGB (1.0f, 0.8f, 0.8f); // All paths are based on 100-unit clock radius // centered at (0, 0) // Define circle for tick marks. tickMarks = new CGPath (); tickMarks.AddEllipseInRect(new CGRect(-90, -90, 180, 180)); // Hour, minute, second hands defined to point straight up. // Define hour hand. hourHand = new CGPath (); hourHand.MoveToPoint (0, -60); hourHand.AddCurveToPoint (0, -30, 20, -30, 5, - 20); hourHand.AddLineToPoint (5, 0); hourHand.AddCurveToPoint (5, 7.5f, -5, 7.5f, -5, 0); hourHand.AddLineToPoint (-5, -20); hourHand.AddCurveToPoint (-20, -30, 0, -30, 0, -60); hourHand.CloseSubpath (); // Define minute hand. minuteHand = new CGPath (); minuteHand.MoveToPoint (0, -80); minuteHand.AddCurveToPoint (0, -75, 0, -70, 2.5f, -60); minuteHand.AddLineToPoint (2.5f, 0); minuteHand.AddCurveToPoint (2.5f, 5, -2.5f, 5, -2.5f, 0); minuteHand.AddLineToPoint (-2.5f, -60); minuteHand.AddCurveToPoint (0, -70, 0, -75, 0, -80); minuteHand.CloseSubpath (); // Define second hand. secondHand = new CGPath (); secondHand.MoveToPoint (0, 10); secondHand.AddLineToPoint(0, -80); }
public ClockView() { // Set background to pink. this.BackgroundColor = UIColor.FromRGB(1.0f, 0.8f, 0.8f); // All paths are based on 100-unit clock radius // centered at (0, 0) // Define circle for tick marks. tickMarks = new CGPath(); tickMarks.AddEllipseInRect(new CGRect(-90, -90, 180, 180)); // Hour, minute, second hands defined to point straight up. // Define hour hand. hourHand = new CGPath(); hourHand.MoveToPoint(0, -60); hourHand.AddCurveToPoint(0, -30, 20, -30, 5, -20); hourHand.AddLineToPoint(5, 0); hourHand.AddCurveToPoint(5, 7.5f, -5, 7.5f, -5, 0); hourHand.AddLineToPoint(-5, -20); hourHand.AddCurveToPoint(-20, -30, 0, -30, 0, -60); hourHand.CloseSubpath(); // Define minute hand. minuteHand = new CGPath(); minuteHand.MoveToPoint(0, -80); minuteHand.AddCurveToPoint(0, -75, 0, -70, 2.5f, -60); minuteHand.AddLineToPoint(2.5f, 0); minuteHand.AddCurveToPoint(2.5f, 5, -2.5f, 5, -2.5f, 0); minuteHand.AddLineToPoint(-2.5f, -60); minuteHand.AddCurveToPoint(0, -70, 0, -75, 0, -80); minuteHand.CloseSubpath(); // Define second hand. secondHand = new CGPath(); secondHand.MoveToPoint(0, 10); secondHand.AddLineToPoint(0, -80); }
CGPath iOSCreatePath(GraphicsPath p) { CGPath path = new CGPath(); for (int i = 0; i < p._segments.Count; i++) { { var ln = p._segments[i] as GraphicsPath._LineSegment; if (ln != null) { if (i == 0) { path.MoveToPoint(ln.x1, ln.y1); } else { path.AddLineToPoint(ln.x1, ln.y1); } path.AddLineToPoint(ln.x2, ln.y2); continue; } } { var bz = p._segments[i] as GraphicsPath._BezierSegment; if (bz != null) { if (i == 0) { path.MoveToPoint(bz.x1, bz.y1); } else { path.AddLineToPoint(bz.x1, bz.y1); } path.AddCurveToPoint( bz.x2, bz.y2, bz.x3, bz.y3, bz.x4, bz.y4); continue; } } } if (p._closed) { path.CloseSubpath(); } return(path); }
public static CGPath ToCGPath(this NSBezierPath path, bool closePath) { int i, numElements; // Need to begin a path here. CGPath cgpath = new CGPath(); // Then draw the path elements. numElements = (int)path.ElementCount; if (numElements > 0) { CGPoint [] points = new CGPoint [3]; bool didClosePath = true; for (i = 0; i < numElements; i++) { switch (path.ElementAt(i, out points)) { case NSBezierPathElement.MoveTo: cgpath.MoveToPoint(points [0].X, points [0].Y); break; case NSBezierPathElement.LineTo: cgpath.AddLineToPoint(points [0].X, points [0].Y); didClosePath = false; break; case NSBezierPathElement.CurveTo: cgpath.AddCurveToPoint(points [0], points [1], points [2]); didClosePath = false; break; case NSBezierPathElement.ClosePath: cgpath.CloseSubpath(); didClosePath = true; break; } } // Be sure the path is closed or Quartz may not do valid hit detection. if (!didClosePath && closePath) { cgpath.CloseSubpath(); } } return(cgpath); }
public void AddCurveToPoint() { var matrix = CGAffineTransform.MakeIdentity(); using (CGPath p1 = new CGPath()) using (CGPath p2 = new CGPath()) { Assert.IsTrue(p1.IsEmpty, "IsEmpty-1"); p1.MoveToPoint(0, 0); p1.AddCurveToPoint(1, 2, 3, 4, 5, 6); p2.MoveToPoint(0, 0); p2.AddCurveToPoint(matrix, 1, 2, 3, 4, 5, 6); Assert.IsFalse(p1.IsEmpty, "IsEmpty-2"); Assert.That(p1, Is.EqualTo(p2), "CGPathEqualToPath"); } }
void DrawPathOnLayer(CAShapeLayer layer) { var offset = Math.Abs(CurrentStartPosition.X - CurrentEndPosition.X) / 5; var ctrlPointA = new CGPoint(CurrentEndPosition.X - offset, CurrentStartPosition.Y); var ctrlPointB = new CGPoint(CurrentStartPosition.X + offset, CurrentEndPosition.Y); var path = new CGPath(); path.MoveToPoint(CurrentStartPosition); path.AddCurveToPoint( ctrlPointA.X, ctrlPointA.Y, ctrlPointB.X, ctrlPointB.Y, CurrentEndPosition.X, CurrentEndPosition.Y); layer.Path = path; }
private static CGPath AddBeziers(CGPath path, SKPoint[] controlPoints) { path.MoveToPoint(CG.Point(controlPoints[0])); for (int i = 0; i < controlPoints.Length - 2; i += 4) { if (i + 3 > controlPoints.Length - 1) { var cp = CG.Point(controlPoints[i + 1]); var p = CG.Point(controlPoints[i + 2]); path.AddQuadCurveToPoint(cp.X, cp.Y, p.X, p.Y); } else { path.AddCurveToPoint(CG.Point(controlPoints[i + 1]), CG.Point(controlPoints[i + 2]), CG.Point(controlPoints[i + 3])); } } return(path); }
//TODO: we should move this to a shared place public static CGPath ToCGPath(this NSBezierPath path) { var numElements = path.ElementCount; if (numElements == 0) { return(null); } CGPath result = new CGPath(); bool didClosePath = true; for (int i = 0; i < numElements; i++) { CGPoint[] points; var element = path.ElementAt(i, out points); if (element == NSBezierPathElement.MoveTo) { result.MoveToPoint(points[0].X, points[0].Y); } else if (element == NSBezierPathElement.LineTo) { result.AddLineToPoint(points[0].X, points[0].Y); didClosePath = false; } else if (element == NSBezierPathElement.CurveTo) { result.AddCurveToPoint(points[0].X, points[0].Y, points[1].X, points[1].Y, points[2].X, points[2].Y); didClosePath = false; } else if (element == NSBezierPathElement.ClosePath) { result.CloseSubpath(); } } // Be sure the path is closed or Quartz may not do valid hit detection. if (!didClosePath) { result.CloseSubpath(); } return(result); }
public static void DrawCurve(CGContext context, IEnumerable <CGPoint> points, LineStyle lineStyle, double intensity = 0.15f) { if ((points?.Count() ?? 0) < 2) { return; } var curvePath = new CGPath(); var pointsCount = points.Count(); var currentDx = new Func <int, CGPoint>((int arg) => points.ElementAt(arg + 1 < pointsCount ? arg + 1 : arg).Subtract(points.ElementAt(arg - 1)).Multiply(intensity)); var prevDx = new Func <int, CGPoint>((int arg) => points.ElementAt(arg).Subtract(points.ElementAt(arg - (arg > 1 ? 2 : 1))).Multiply(intensity)); var curveDirections = points .Skip(1) .Take(pointsCount - 1) .Select((CGPoint point, int index) => new { Point = point, Control1 = points.ElementAt(index).Add(prevDx(index + 1)), Control2 = point.Subtract(currentDx(index + 1)) }); curvePath.MoveToPoint(points.ElementAt(0)); foreach (var curve in curveDirections) { curvePath.AddCurveToPoint(curve.Control1, curve.Control2, curve.Point); } context.AddPath(curvePath); context.SetLineWidth(lineStyle.LineWidth); context.SetStrokeColor(lineStyle.Color.CGColor); context.StrokePath(); }
public void AddBezier(PointF start, PointF control1, PointF control2, PointF end) { ConnectTo(start); Control.AddCurveToPoint(control1.X, control1.Y, control2.X, control2.Y, end.X, end.Y); }
void drawLines () { layer.RemoveAllAnimations (); var dot = new CGRect (0, 0, lineWidth, lineWidth); nfloat x, y; CGPoint start = CGPoint.Empty; CGPoint end = CGPoint.Empty; // Draw curved graph line using (UIColor color = UIColor.White.ColorWithAlpha (0.25f), dotColor = UIColor.White.ColorWithAlpha (0.70f)) { //color.SetStroke (); //dotColor.SetFill (); //ctx.SetLineWidth (lineWidth); using (CGPath path = new CGPath ()) { var count = hourly ? HourlyTemps.Count : (Forecasts.Count * 2); for (int i = 0; i < count; i++) { // adjusted index var ai = i; double temp; if (hourly) { temp = HourlyTemps [ai]; } else { // reset start when switching from highs to lows if (i == Forecasts.Count) start = CGPoint.Empty; var highs = i < Forecasts.Count; ai = highs ? i : i - Forecasts.Count; temp = highs ? HighTemps [ai] : LowTemps [ai]; } var percent = ((nfloat)temp - scaleLow) / scaleRange; x = padding + inset + (ai * scaleX); y = graphRect.GetMaxY () - (graphRect.Height * percent); end = new CGPoint (x, y); if (!hourly) { dot.X = end.X - (lineWidth / 2); dot.Y = end.Y - (lineWidth / 2); path.AddEllipseInRect (dot); //ctx.AddEllipseInRect (dot); } if (start == CGPoint.Empty) { path.MoveToPoint (end); } else { path.MoveToPoint (start); if (hourly) { path.AddLineToPoint (end); } else { var diff = (end.X - start.X) / 2; path.AddCurveToPoint (end.X - diff, start.Y, start.X + diff, end.Y, end.X, end.Y); } } start = end; } // draw all dots to context //if (!hourly) ctx.DrawPath (CGPathDrawingMode.Fill); // add line path to context layer.Path = path; //ctx.AddPath (path); // draw lines //ctx.DrawPath (CGPathDrawingMode.Stroke); layer.LineWidth = lineWidth; layer.StrokeColor = color.CGColor; layer.FillColor = dotColor.CGColor; CABasicAnimation pathAnimation = new CABasicAnimation { KeyPath = "strokeEnd" }; pathAnimation.Duration = 1.0; pathAnimation.From = NSNumber.FromNFloat (0); pathAnimation.To = NSNumber.FromNFloat (1); layer.AddAnimation (pathAnimation, "strokeEndAnimation"); } } }
public static void DrawFilledCurvePath(CGContext context, IEnumerable <CGPoint> points, IEnumerable <CGPoint> pointsBottom, UIColor fillColor, double intensity = 0.15f, bool reverse = true) { var pointsBottomReversed = reverse ? pointsBottom.Reverse() : pointsBottom; if ((points?.Count() ?? 0) < 2) { return; } var fillPath = new CGPath(); var pointsCount = points.Count(); var currentDx = new Func <int, IEnumerable <CGPoint>, CGPoint>((int arg, IEnumerable <CGPoint> p) => p.ElementAt(arg + 1 < p.Count() ? arg + 1 : arg).Subtract(p.ElementAt(arg - 1)).Multiply(intensity)); var prevDx = new Func <int, IEnumerable <CGPoint>, CGPoint>((int arg, IEnumerable <CGPoint> p) => p.ElementAt(arg).Subtract(p.ElementAt(arg - (arg > 1 ? 2 : 1))).Multiply(intensity)); var curveDirections = points .Skip(1) .Take(pointsCount - 1) .Select((CGPoint point, int index) => new { Point = point, Control1 = points.ElementAt(index).Add(prevDx(index + 1, points)), Control2 = point.Subtract(currentDx(index + 1, points)) }); fillPath.MoveToPoint(points.ElementAt(0)); foreach (var curve in curveDirections) { fillPath.AddCurveToPoint(curve.Control1, curve.Control2, curve.Point); } pointsCount = pointsBottomReversed.Count(); fillPath.AddLineToPoint(pointsBottomReversed.ElementAt(0)); var curveDirectionsSecond = pointsBottomReversed .Skip(1) .Take(pointsCount - 1) .Select((CGPoint point, int index) => new { Point = point, Control1 = pointsBottomReversed.ElementAt(index).Add(prevDx(index + 1, pointsBottomReversed)), Control2 = point.Subtract(currentDx(index + 1, pointsBottomReversed)) }); foreach (var curve in curveDirectionsSecond) { fillPath.AddCurveToPoint(curve.Control1, curve.Control2, curve.Point); } fillPath.CloseSubpath(); context.AddPath(fillPath); fillColor.SetFill(); context.FillPath(); }
void drawLines() { layer.RemoveAllAnimations(); var dot = new CGRect(0, 0, lineWidth, lineWidth); nfloat x, y; CGPoint start = CGPoint.Empty; CGPoint end = CGPoint.Empty; // Draw curved graph line using (UIColor color = UIColor.White.ColorWithAlpha(0.25f), dotColor = UIColor.Clear) { using (CGPath path = new CGPath()) { var count = hourly ? HourlyTemps.Count : (Forecasts.Count * 2); for (int i = 0; i < count; i++) { // adjusted index var ai = i; double temp; if (hourly) { temp = HourlyTemps [ai]; } else { // reset start when switching from highs to lows if (i == Forecasts.Count) { start = CGPoint.Empty; } var highs = i < Forecasts.Count; ai = highs ? i : i - Forecasts.Count; temp = highs ? HighTemps [ai] : LowTemps [ai]; } var percent = ((nfloat)temp - scaleLow) / scaleRange; x = padding + inset + (ai * scaleX); y = graphRect.GetMaxY() - (graphRect.Height * percent); end = new CGPoint(x, y); if (!hourly) { dot.X = end.X - (lineWidth / 2); dot.Y = end.Y - (lineWidth / 2); path.AddEllipseInRect(dot); } if (start == CGPoint.Empty) { path.MoveToPoint(end); } else { path.MoveToPoint(start); if (hourly) { path.AddLineToPoint(end); } else { var diff = (end.X - start.X) / 2; path.AddCurveToPoint(end.X - diff, start.Y, start.X + diff, end.Y, end.X, end.Y); } } start = end; } // add line path to context layer.Path = path; layer.LineWidth = lineWidth; layer.StrokeColor = color.CGColor; layer.FillColor = dotColor.CGColor; CABasicAnimation pathAnimation = new CABasicAnimation { KeyPath = "strokeEnd" }; pathAnimation.Duration = 1.0; pathAnimation.From = NSNumber.FromNFloat(0); pathAnimation.To = NSNumber.FromNFloat(1); layer.AddAnimation(pathAnimation, "strokeEndAnimation"); } } }
public static CGPath ToCGPath( this PathF target) { var path = new CGPath(); int pointIndex = 0; int arcAngleIndex = 0; int arcClockwiseIndex = 0; foreach (var operation in target.PathOperations) { if (operation == PathOperation.MoveTo) { var point = target[pointIndex++]; path.MoveToPoint(point.X, point.Y); } else if (operation == PathOperation.Line) { var endPoint = target[pointIndex++]; path.AddLineToPoint(endPoint.X, endPoint.Y); } else if (operation == PathOperation.Quad) { var controlPoint = target[pointIndex++]; var endPoint = target[pointIndex++]; path.AddQuadCurveToPoint( controlPoint.X, controlPoint.Y, endPoint.X, endPoint.Y); } else if (operation == PathOperation.Cubic) { var controlPoint1 = target[pointIndex++]; var controlPoint2 = target[pointIndex++]; var endPoint = target[pointIndex++]; path.AddCurveToPoint( controlPoint1.X, controlPoint1.Y, controlPoint2.X, controlPoint2.Y, endPoint.X, endPoint.Y); } else if (operation == PathOperation.Arc) { var topLeft = target[pointIndex++]; var bottomRight = target[pointIndex++]; float startAngle = target.GetArcAngle(arcAngleIndex++); float endAngle = target.GetArcAngle(arcAngleIndex++); var clockwise = target.IsArcClockwise(arcClockwiseIndex++); var startAngleInRadians = GraphicsOperations.DegreesToRadians(-startAngle); var endAngleInRadians = GraphicsOperations.DegreesToRadians(-endAngle); while (startAngleInRadians < 0) { startAngleInRadians += (float)Math.PI * 2; } while (endAngleInRadians < 0) { endAngleInRadians += (float)Math.PI * 2; } var cx = (bottomRight.X + topLeft.X) / 2; var cy = (bottomRight.Y + topLeft.Y) / 2; var width = bottomRight.X - topLeft.X; var height = bottomRight.Y - topLeft.Y; var r = width / 2; var transform = CGAffineTransform.MakeTranslation(cx, cy); transform = CGAffineTransform.Multiply(CGAffineTransform.MakeScale(1, height / width), transform); path.AddArc(transform, 0, 0, r, startAngleInRadians, endAngleInRadians, !clockwise); } else if (operation == PathOperation.Close) { path.CloseSubpath(); } } return(path); }
public void DrawDropletPulledVer(CGContext canvas, string label, bool biggie, SKPoint c1, SKPoint c2, KDeviceHandler.Direction dir, float r, float r1, float neckX, float r2, float textStrokeWidth, SKPaint fillPaint, float strokeWidth, float accentStrokeWidth, Swipe swipe) { float ratio = ((r1 + r2) / 2) / r; //strokeWidth = strokeWidth * ratio; textStrokeWidth = textStrokeWidth * ratio; accentStrokeWidth = accentStrokeWidth * ratio; float lr = r1 - (strokeWidth + accentStrokeWidth) / 2.0f; float dr = r2 - (strokeWidth + accentStrokeWidth) / 2.0f; // place the neck in an Y-position proportional to the rate between r1 and r2, with m1+r1Y to the top leading to c1.Y, and m2+r2Y to the bot leading to c2.Y float m1 = (2 * r - (r1 + r2)) / (1 + r2 / r1); float m2 = m1 * r2 / r1; // position of the neck float nY = c1.Y + r1 + m1; float nX = c1.X; // Control points: a1*2 is on a line from nY,nX-neckX to c1.Y,c.X-r1 where it intersects c1.Y+r1; we divide it by 2 to make the curve smoother float a1 = (m1 * (r1 - neckX) / (r1 + m1)) / 2; float a2 = (m2 * (r2 - neckX) / (r2 + m2)) / 2; var path = new CGPath(); path.MoveToPoint(CG.Point(swipe % new SKPoint(c1.X - r1, c1.Y))); path.AddCurveToPoint(CG.Point(swipe % new SKPoint(c1.X - r1, c1.Y + 0.5f * r1)), CG.Point(swipe % new SKPoint(nX - (neckX + a1), c1.Y + r1)), CG.Point(swipe % new SKPoint(nX - neckX, nY))); path.AddCurveToPoint(CG.Point(swipe % new SKPoint(nX - (neckX + a2), c2.Y - r2)), CG.Point(swipe % new SKPoint(c2.X - r2, c2.Y - 0.5f * r2)), CG.Point(swipe % new SKPoint(c2.X - r2, c2.Y))); path.AddCurveToPoint(CG.Point(swipe % new SKPoint(c2.X - r2, c2.Y + 0.75f * r2)), CG.Point(swipe % new SKPoint(c2.X - 0.75f * r2, c2.Y + r2)), CG.Point(swipe % new SKPoint(c2.X, c2.Y + r2))); path.AddCurveToPoint(CG.Point(swipe % new SKPoint(c2.X + 0.75f * r2, c2.Y + r2)), CG.Point(swipe % new SKPoint(c2.X + r2, c2.Y + 0.75f * r2)), CG.Point(swipe % new SKPoint(c2.X + r2, c2.Y))); path.AddCurveToPoint(CG.Point(swipe % new SKPoint(c2.X + r2, c2.Y - 0.5f * r2)), CG.Point(swipe % new SKPoint(nX + (neckX + a2), c2.Y - r2)), CG.Point(swipe % new SKPoint(nX + neckX, nY))); path.AddCurveToPoint(CG.Point(swipe % new SKPoint(nX + (neckX + a1), c1.Y + r1)), CG.Point(swipe % new SKPoint(c1.X + r1, c1.Y + 0.5f * r1)), CG.Point(swipe % new SKPoint(c1.X + r1, c1.Y))); path.AddCurveToPoint(CG.Point(swipe % new SKPoint(c1.X + r1, c1.Y - 0.75f * r1)), CG.Point(swipe % new SKPoint(c1.X + 0.75f * r1, c1.Y - r1)), CG.Point(swipe % new SKPoint(c1.X, c1.Y - r1))); path.AddCurveToPoint(CG.Point(swipe % new SKPoint(c1.X - 0.75f * r1, c1.Y - r1)), CG.Point(swipe % new SKPoint(c1.X - r1, c1.Y - 0.75f * r1)), CG.Point(swipe % new SKPoint(c1.X - r1, c1.Y))); path.CloseSubpath(); var darkPath = new CGPath(); darkPath.MoveToPoint(CG.Point(swipe % new SKPoint(c2.X, c2.Y + dr))); darkPath.AddCurveToPoint(CG.Point(swipe % new SKPoint(c2.X + 0.75f * dr, c2.Y + dr)), CG.Point(swipe % new SKPoint(c2.X + dr, c2.Y + 0.75f * dr)), CG.Point(swipe % new SKPoint(c2.X + dr, c2.Y))); var lightPath = new CGPath(); lightPath.MoveToPoint(CG.Point(swipe % new SKPoint(c1.X, c1.Y - lr))); lightPath.AddCurveToPoint(CG.Point(swipe % new SKPoint(c1.X - 0.75f * lr, c1.Y - lr)), CG.Point(swipe % new SKPoint(c1.X - lr, c1.Y - 0.75f * lr)), CG.Point(swipe % new SKPoint(c1.X - lr, c1.Y))); using (var strokePaint = new SKPaint { Style = SKPaintStyle.Stroke, Color = new SKColor(0, 0, 0, 191), StrokeWidth = swipe % strokeWidth, IsAntialias = true }) using (var accentLightPaint = new SKPaint { Style = SKPaintStyle.Stroke, Color = new SKColor(255, 255, 255, 191), StrokeWidth = swipe % accentStrokeWidth, StrokeCap = SKStrokeCap.Round, IsAntialias = true }) using (var accentDarkPaint = new SKPaint { Style = SKPaintStyle.Stroke, Color = new SKColor(0, 0, 0, 95), StrokeWidth = swipe % accentStrokeWidth, StrokeCap = SKStrokeCap.Round, IsAntialias = true }) { canvas.AddPath(path); canvas.SetFillColor(CG.Color(fillPaint.Color)); canvas.FillPath(); canvas.AddPath(darkPath); canvas.SetStrokeColor(CG.Color(accentDarkPaint.Color)); canvas.SetLineWidth(accentDarkPaint.StrokeWidth); canvas.SetLineJoin(CG.LineJoin(accentDarkPaint.StrokeJoin)); canvas.SetLineCap(CG.LineCap(accentDarkPaint.StrokeCap)); canvas.StrokePath(); canvas.AddPath(lightPath); canvas.SetStrokeColor(CG.Color(accentLightPaint.Color)); canvas.SetLineWidth(accentLightPaint.StrokeWidth); canvas.SetLineJoin(CG.LineJoin(accentLightPaint.StrokeJoin)); canvas.SetLineCap(CG.LineCap(accentLightPaint.StrokeCap)); canvas.StrokePath(); canvas.AddPath(path); canvas.SetStrokeColor(CG.Color(strokePaint.Color)); canvas.SetLineWidth(strokePaint.StrokeWidth); canvas.SetLineJoin(CG.LineJoin(strokePaint.StrokeJoin)); canvas.SetLineCap(CG.LineCap(strokePaint.StrokeCap)); canvas.StrokePath(); } float rYtext = (r1 == r2) ? ((dir == KDeviceHandler.Direction.Top) ? r1 : r2) : (r1 > r2) ? r1 : r2; SKPoint cText = (r1 == r2) ? ((dir == KDeviceHandler.Direction.Top) ? c1 : c2) : (r1 > r2) ? c1 : c2; DrawDropletLabel(canvas, label, cText, rYtext, textStrokeWidth, biggie, swipe); }
public override void ObserveValue(NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context) { //base.ObserveValue(keyPath, ofObject, change, context); if (keyPath.ToString().ToLower() == "contentInset".ToLower()) { if (!_ignoreInset) { this.originalContentInset = (change["new"] as NSValue).UIEdgeInsetsValue; this.Frame = new RectangleF(0, -1 * (kTotalViewHeight + this.scrollView.ContentInset.Top), this.scrollView.Frame.Size.Width, kTotalViewHeight); } return; } if (!this.Enabled || this._ignoreOffset) return; float offset = (change["new"] as NSValue).PointFValue.Y + this.originalContentInset.Top; if (_refreshing) { if (offset != 0) { // keep thing pinned at the top CATransaction.Begin(); CATransaction.SetValueForKey(NSNumber.FromBoolean(true), CATransaction.DisableActionsKey); _shapeLayer.Position = new PointF(0, kMaxDistance + offset + kOpenedViewHeight); CATransaction.Commit(); this.activity.Center = new PointF((float)Math.Floor(this.Frame.Size.Width / 2), (float)Math.Min(offset + this.Frame.Size.Height + Math.Floor(kOpenedViewHeight / 2), this.Frame.Size.Height - kOpenedViewHeight / 2)); _ignoreInset = true; _ignoreOffset = true; if (offset < 0) { // set the inset depending on the situation if (offset >= kOpenedViewHeight * -1) { if (!this.scrollView.Dragging) { if (!_didSetInset) { _didSetInset = true; _hasSectionHeaders = false; if (this.scrollView is UITableView) { for (int i = 0; i < (this.scrollView as UITableView).NumberOfSections(); ++i) { if ((this.scrollView as UITableView).RectForHeaderInSection(i).Size.Height != 0) { _hasSectionHeaders = true; break; } } } } if (_hasSectionHeaders) this.scrollView.ContentInset = new UIEdgeInsets(Math.Min(offset * -1, kOpenedViewHeight) + this.originalContentInset.Top, this.originalContentInset.Left, this.originalContentInset.Bottom, this.originalContentInset.Right); else this.scrollView.ContentInset = new UIEdgeInsets(kOpenedViewHeight + this.originalContentInset.Top, this.originalContentInset.Left, this.originalContentInset.Bottom, this.originalContentInset.Right); } else if(_didSetInset && _hasSectionHeaders) { this.scrollView.ContentInset = new UIEdgeInsets(-1 * offset + this.originalContentInset.Top, this.originalContentInset.Left, this.originalContentInset.Bottom, this.originalContentInset.Right); } } } else if (_hasSectionHeaders) { this.scrollView.ContentInset = this.originalContentInset; } _ignoreInset = false; _ignoreOffset = false; } return; } else { // check if we can trigger a new refresh and if we can draw the control bool dontDraw = false; // line 230 if (!_canRefresh) { if (offset >= 0) { // we can refresh again after the control is scrolled out of view _canRefresh = true; _didSetInset = false; } else { dontDraw = true; } } else { if (offset >= 0) { // don't draw if the control is not visible dontDraw = true; } } if (offset > 0 && _lastOffset > offset && !this.scrollView.Tracking) { // if we are scrolling too fast, don't draw, and don't trigger unless the scrollView bounced back // removed behavior Heath //_canRefresh = false; //dontDraw = true; } if (dontDraw) { _shapeLayer.Path = null; _shapeLayer.ShadowPath = new CGPath(IntPtr.Zero); _arrowLayer.Path = null; _highlightLayer.Path = null; _lastOffset = offset; return; } } _lastOffset = offset; // line 260 bool triggered = false; CGPath path = new CGPath(); // calculate some useful points and values float verticalShift = (float)Math.Max(0, -1 * ((kMaxTopRadius + kMaxBottomRadius + kMaxTopPadding + kMaxBottomPadding) + offset)); float distance = (float)Math.Min(kMaxDistance, (float)Math.Abs(verticalShift)); float percentage = 1 - (distance / kMaxDistance); float currentTopPadding = lerp(kMinTopPadding, kMaxTopPadding, percentage); float currentTopRadius = lerp(kMinTopRadius, kMaxTopRadius, percentage); float currentBottomRadius = lerp(kMinBottomRadius, kMaxBottomRadius, percentage); float currentBottomPadding = lerp(kMinBottomPadding, kMaxBottomPadding, percentage); PointF bottomOrigin = new PointF((float)Math.Floor(this.Bounds.Size.Width / 2), this.Bounds.Size.Height - currentBottomPadding - currentBottomRadius); PointF topOrigin = PointF.Empty; if (distance == 0) { topOrigin = new PointF((float)Math.Floor(this.Bounds.Size.Width / 2), bottomOrigin.Y); } else { topOrigin = new PointF((float)Math.Floor(this.Bounds.Size.Width / 2), this.Bounds.Size.Height + offset + currentTopPadding + currentTopRadius); if (percentage == 0) { bottomOrigin.Y -= (float)Math.Abs(verticalShift) - kMaxDistance; triggered = true; } } // top semicircle path.AddArc(topOrigin.X, topOrigin.Y, currentTopRadius, 0, (float)Math.PI, true); // left curve PointF leftCp1 = new PointF(lerp((topOrigin.X - currentTopRadius), (bottomOrigin.X - currentBottomRadius), 0.1f), lerp(topOrigin.Y, bottomOrigin.Y, 0.2f)); PointF leftCp2 = new PointF(lerp((topOrigin.X - currentTopRadius), (bottomOrigin.X - currentBottomRadius), 0.9f), lerp(topOrigin.Y, bottomOrigin.Y, 0.2f)); PointF leftDestination = new PointF(bottomOrigin.X - currentBottomRadius, bottomOrigin.Y); path.AddCurveToPoint(leftCp1, leftCp2, leftDestination); // bottom semicircle path.AddArc(bottomOrigin.X, bottomOrigin.Y, currentBottomRadius, (float)Math.PI, 0, true); // right curve PointF rightCp2 = new PointF(lerp((topOrigin.X + currentTopRadius), (bottomOrigin.X + currentBottomRadius), 0.1f), lerp(topOrigin.Y, bottomOrigin.Y, 0.2f)); PointF rightCp1 = new PointF(lerp((topOrigin.X + currentTopRadius), (bottomOrigin.X + currentBottomRadius), 0.9f), lerp(topOrigin.Y, bottomOrigin.Y, 0.2f)); PointF rightDestination = new PointF(bottomOrigin.X + currentTopRadius, topOrigin.Y); path.AddCurveToPoint (rightCp1, rightCp2, rightDestination); path.CloseSubpath(); if (!triggered) // line 309 { // set paths _shapeLayer.Path = path; _shapeLayer.ShadowPath = path; // add the arrow shape float currentArrowSize = lerp(kMinArrowSize, kMaxArrowSize, percentage); float currentArrowRadius = lerp(kMinArrowRadius, kMaxArrowRadius, percentage); float arrowBigRadius = currentArrowRadius + (currentArrowSize / 2); float arrowSmallRadius = currentArrowRadius - (currentArrowSize / 2); CGPath arrowPath = new CGPath(); /* arrowPath.AddArc(topOrigin.X, topOrigin.Y, arrowBigRadius, 0, 3 * (float)Math.PI, false); arrowPath.AddLineToPoint(topOrigin.X, topOrigin.Y - arrowBigRadius - currentArrowSize); arrowPath.AddLineToPoint(topOrigin.X + (2 * currentArrowSize), topOrigin.Y - arrowBigRadius + (currentArrowSize / 2)); arrowPath.AddLineToPoint(topOrigin.X, topOrigin.Y - arrowBigRadius + (2 * currentArrowSize)); arrowPath.AddLineToPoint(topOrigin.X, topOrigin.Y - arrowBigRadius + currentArrowSize); arrowPath.AddArc(topOrigin.X, topOrigin.Y, arrowSmallRadius, 3 * (float)Math.PI, 0, true); */ arrowPath.AddArc (topOrigin.X, topOrigin.Y, arrowBigRadius, 0, 3 * (float) Math.PI / 2.0f, false); arrowPath.AddLineToPoint (topOrigin.X, topOrigin.Y - arrowBigRadius - currentArrowSize); arrowPath.AddLineToPoint (topOrigin.X + (2 * currentArrowSize), topOrigin.Y - arrowBigRadius + (currentArrowSize / 2.0f)); arrowPath.AddLineToPoint (topOrigin.X, topOrigin.Y - arrowBigRadius + (2 * currentArrowSize)); arrowPath.AddLineToPoint (topOrigin.X, topOrigin.Y - arrowBigRadius + currentArrowSize); arrowPath.AddArc (topOrigin.X, topOrigin.Y, arrowSmallRadius, 3 * (float) Math.PI / 2.0f, 0, true); arrowPath.CloseSubpath(); _arrowLayer.Path = arrowPath; _arrowLayer.FillRule = CAShapeLayer.FillRuleEvenOdd; arrowPath.Dispose(); // add the highlight shape CGPath highlightPath = new CGPath(); highlightPath.AddArc(topOrigin.X, topOrigin.Y, currentTopRadius, 0, (float)Math.PI, true); highlightPath.AddArc(topOrigin.X, topOrigin.Y + 1.25f, currentTopRadius, (float)Math.PI, 0, false); _highlightLayer.Path = highlightPath; _highlightLayer.FillRule = CAShapeLayer.FillRuleNonZero; highlightPath.Dispose(); } else { // start the shape disappearance animation float radius = lerp(kMinBottomRadius, kMaxBottomRadius, 0.2f); CABasicAnimation pathMorph = CABasicAnimation.FromKeyPath("path"); pathMorph.Duration = 0.15f; pathMorph.FillMode = CAFillMode.Forwards; pathMorph.RemovedOnCompletion = false; CGPath toPath = new CGPath(); toPath.AddArc(topOrigin.X, topOrigin.Y, radius, 0, (float)Math.PI, true); toPath.AddCurveToPoint(topOrigin.X - radius, topOrigin.Y, topOrigin.X - radius, topOrigin.Y, topOrigin.X - radius, topOrigin.Y); toPath.AddArc(topOrigin.X, topOrigin.Y, radius, (float)Math.PI, 0, true); toPath.AddCurveToPoint(topOrigin.X + radius, topOrigin.Y, topOrigin.X + radius, topOrigin.Y, topOrigin.X + radius, topOrigin.Y); toPath.CloseSubpath(); pathMorph.To = new NSValue(toPath.Handle); _shapeLayer.AddAnimation(pathMorph, null); CABasicAnimation shadowPathMorph = CABasicAnimation.FromKeyPath("shadowPath"); shadowPathMorph.Duration = 0.15f; shadowPathMorph.FillMode = CAFillMode.Forwards; shadowPathMorph.RemovedOnCompletion = false; shadowPathMorph.To = new NSValue(toPath.Handle); _shapeLayer.AddAnimation(shadowPathMorph, null); toPath.Dispose(); CABasicAnimation shapeAlphaAnimation = CABasicAnimation.FromKeyPath("opacity"); shapeAlphaAnimation.Duration = 0.1f; shapeAlphaAnimation.BeginTime = CAAnimation.CurrentMediaTime() + 0.1f; shapeAlphaAnimation.To = new NSNumber(0); shapeAlphaAnimation.FillMode = CAFillMode.Forwards; shapeAlphaAnimation.RemovedOnCompletion = false; _shapeLayer.AddAnimation(shapeAlphaAnimation, null); CABasicAnimation alphaAnimation = CABasicAnimation.FromKeyPath("opacity"); alphaAnimation.Duration = 0.1f; alphaAnimation.To = new NSNumber (0); alphaAnimation.FillMode = CAFillMode.Forwards; alphaAnimation.RemovedOnCompletion = false; _arrowLayer.AddAnimation(alphaAnimation, null); _highlightLayer.AddAnimation(alphaAnimation, null); CATransaction.Begin(); CATransaction.DisableActions = true; activity.Layer.Transform = CATransform3D.MakeScale(0.1f, 0.1f, 1f); CATransaction.Commit(); UIView.Animate (0.2f, 0.15f, UIViewAnimationOptions.CurveLinear, () => { activity.Alpha = 1; activity.Layer.Transform = CATransform3D.MakeScale(1, 1, 1); }, null); _refreshing = true; _canRefresh = false; this.SendActionForControlEvents(UIControlEvent.ValueChanged); if (this.Action != null) this.Action(); } path.Dispose(); }
public override void ObserveValue (NSString keyPath, NSObject ofObject, NSDictionary change, IntPtr context) { if (keyPath == "contentInset") { if (!_ignoreInset && !_ignoreInsetBlock) { OriginalContentInset = ((NSValue) change ["new"]).UIEdgeInsetsValue; Frame = (_vertical) ? new RectangleF (0, - (TotalViewHeight + ScrollView.ContentInset.Top), ScrollView.Bounds.Size.Width, TotalViewHeight) : new RectangleF (- (TotalViewHeight + ScrollView.ContentInset.Left), 0, TotalViewHeight, ScrollView.Bounds.Size.Height); } return; } if (!Enabled || _ignoreOffset) return; var newContentOffset = ((NSValue) change ["new"]).PointFValue; float offset; if (_vertical) { offset = newContentOffset.Y + OriginalContentInset.Top; } else { offset = newContentOffset.X + OriginalContentInset.Left; } if (_refreshing) { if (offset != 0) { // Keep thing pinned at the top CATransaction.Begin (); CATransaction.DisableActions = true; _shapeLayer.Position = (_vertical) ? new PointF (0, MaxDistance + offset + OpenedViewHeight) : new PointF (MaxDistance + offset + OpenedViewHeight, 0); CATransaction.Commit (); if (_vertical) { _activity.Center = new PointF ( (float) Math.Floor (Bounds.Width / 2.0f), Math.Min ( offset + Bounds.Height + (float) Math.Floor (OpenedViewHeight / 2.0f), Bounds.Height - OpenedViewHeight / 2.0f ) ); } else { _activity.Center = new PointF ( Math.Min ( offset + Bounds.Width + (float) Math.Floor (OpenedViewHeight / 2.0f), Bounds.Width - OpenedViewHeight / 2.0f ), (float) Math.Floor (Bounds.Height / 2.0f) ); } _ignoreInset = true; _ignoreOffset = true; if (offset < 0) { // Set the inset depending on the situation if (offset >= -OpenedViewHeight) { if (!ScrollView.Dragging) { if (!_didSetInset) { _didSetInset = true; _hasSectionHeaders = false; if (ScrollView is UITableView) { var tableView = (UITableView) ScrollView; for (var i = 0; i < tableView.NumberOfSections (); i++) { if (tableView.RectForHeaderInSection (i).Size.Height > 0) { _hasSectionHeaders = true; break; } } } } if (_hasSectionHeaders) { ScrollView.ContentInset = (_vertical) ? new UIEdgeInsets (Math.Min (-offset, OpenedViewHeight) + OriginalContentInset.Top, OriginalContentInset.Left, OriginalContentInset.Bottom, OriginalContentInset.Right) : new UIEdgeInsets (OriginalContentInset.Top, Math.Min (-offset, OpenedViewHeight) + OriginalContentInset.Left, OriginalContentInset.Bottom, OriginalContentInset.Right); } else { ScrollView.ContentInset = (_vertical) ? new UIEdgeInsets (OpenedViewHeight + OriginalContentInset.Top, OriginalContentInset.Left, OriginalContentInset.Bottom, OriginalContentInset.Right) : new UIEdgeInsets (OriginalContentInset.Top, OriginalContentInset.Left + OpenedViewHeight, OriginalContentInset.Bottom, OriginalContentInset.Right); } } else if (_didSetInset && _hasSectionHeaders) { ScrollView.ContentInset = (_vertical) ? new UIEdgeInsets (-offset + OriginalContentInset.Top, OriginalContentInset.Left, OriginalContentInset.Bottom, OriginalContentInset.Right) : new UIEdgeInsets (OriginalContentInset.Top, -offset + OriginalContentInset.Left, OriginalContentInset.Bottom, OriginalContentInset.Right); } } } else if (_hasSectionHeaders) { ScrollView.ContentInset = OriginalContentInset; } _ignoreInset = false; _ignoreOffset = false; } return; } else { // Check if we can trigger a new refresh and if we can draw the control bool dontDraw = false; if (!_canRefresh) { if (offset >= 0) { // We can refresh again after the control is scrolled out of view _canRefresh = true; _didSetInset = false; } else { dontDraw = true; } } else { if (offset >= 0) { // Don't draw if the control is not visible dontDraw = true; } } if (offset > 0 && _lastOffset > offset && !ScrollView.Tracking) { // If we are scrolling too fast, don't draw, and don't trigger unless the scrollView bounced back _canRefresh = false; dontDraw = true; } if (dontDraw) { _shapeLayer.Path = null; _shapeLayer.ShadowPath = new CGPath (IntPtr.Zero); _arrowLayer.Path = null; _highlightLayer.Path = null; _lastOffset = offset; return; } } _lastOffset = offset; bool triggered = false; CGPath path = new CGPath (); //Calculate some useful points and values var verticalShift = Math.Max (0, -((MaxTopRadius + MaxBottomRadius + MaxTopPadding + MaxBottomPadding) + offset)); var distance = Math.Min (MaxDistance, Math.Abs (verticalShift)); var percentage = 1 - (distance / MaxDistance); PointF headOrigin; float headRadius; if (_vertical) { float currentTopPadding = lerp (MinTopPadding, MaxTopPadding, percentage); float currentTopRadius = lerp (MinTopRadius, MaxTopRadius, percentage); float currentBottomRadius = lerp (MinBottomRadius, MaxBottomRadius, percentage); float currentBottomPadding = lerp (MinBottomPadding, MaxBottomPadding, percentage); var bottomOrigin = new PointF ((float) Math.Floor (Bounds.Width / 2.0f), Bounds.Height - currentBottomPadding - currentBottomRadius); var topOrigin = PointF.Empty; if (distance == 0) { topOrigin = new PointF ((float) Math.Floor (Bounds.Width / 2.0f), bottomOrigin.Y); } else { topOrigin = new PointF ((float) Math.Floor (Bounds.Width / 2.0f), Bounds.Height + offset + currentTopPadding + currentTopRadius); if (percentage == 0) { bottomOrigin.Y -= ((Math.Abs (verticalShift) - MaxDistance)); triggered = true; } } //Top semicircle path.AddArc (topOrigin.X, topOrigin.Y, currentTopRadius, 0, (float) Math.PI, true); //Left curve var leftCp1 = new PointF (lerp ((topOrigin.X - currentTopRadius), (bottomOrigin.X - currentBottomRadius), 0.1f), lerp (topOrigin.Y, bottomOrigin.Y, .2f)); var leftCp2 = new PointF (lerp ((topOrigin.X - currentTopRadius), (bottomOrigin.X - currentBottomRadius), 0.9f), lerp (topOrigin.Y, bottomOrigin.Y, .2f)); var leftDestination = new PointF (bottomOrigin.X - currentBottomRadius, bottomOrigin.Y); path.AddCurveToPoint (leftCp1, leftCp2, leftDestination); //Bottom semicircle path.AddArc (bottomOrigin.X, bottomOrigin.Y, currentBottomRadius, (float) Math.PI, 0, true); //Right curve var rightCp2 = new PointF (lerp ((topOrigin.X + currentTopRadius), (bottomOrigin.X + currentBottomRadius), 0.1f), lerp (topOrigin.Y, bottomOrigin.Y, .2f)); var rightCp1 = new PointF (lerp ((topOrigin.X + currentTopRadius), (bottomOrigin.X + currentBottomRadius), 0.9f), lerp (topOrigin.Y, bottomOrigin.Y, .2f)); var rightDestination = new PointF (bottomOrigin.X + currentTopRadius, topOrigin.Y); path.AddCurveToPoint (rightCp1, rightCp2, rightDestination); headOrigin = topOrigin; headRadius = currentTopRadius; } else { float currentLeftPadding = lerp (MinTopPadding, MaxTopPadding, percentage); float currentLeftRadius = lerp (MinTopRadius, MaxTopRadius, percentage); float currentRightRadius = lerp (MinBottomRadius, MaxBottomRadius, percentage); float currentRightPadding = lerp (MinBottomPadding, MaxBottomPadding, percentage); var rightOrigin = new PointF (Bounds.Width - currentRightPadding - currentRightRadius, (float) Math.Floor (Bounds.Height / 2.0f)); var leftOrigin = PointF.Empty; if (distance == 0) { leftOrigin = new PointF (rightOrigin.X, (float) Math.Floor (Bounds.Size.Height / 2.0f)); } else { leftOrigin = new PointF (Bounds.Size.Width + offset + currentLeftPadding + currentLeftRadius, (float) Math.Floor (Bounds.Height / 2.0f)); if (percentage == 0) { rightOrigin.X -= ((Math.Abs (verticalShift) - MaxDistance)); triggered = true; } } //Left cemicircle path.AddArc (leftOrigin.X, leftOrigin.Y, currentLeftRadius, (float) -Math.PI / 2.0f, (float) Math.PI / 2.0f, true); // Bottom curve var bottomCp1 = new PointF (lerp (leftOrigin.X, rightOrigin.X, .2f), lerp ((leftOrigin.Y + currentLeftRadius), (rightOrigin.Y + currentRightRadius), .1f)); var bottomCp2 = new PointF (lerp (leftOrigin.X, rightOrigin.X, .2f), lerp ((leftOrigin.Y + currentLeftRadius), (rightOrigin.Y + currentRightRadius), .9f)); var bottomDestination = new PointF (rightOrigin.X, rightOrigin.Y + currentRightRadius); path.AddCurveToPoint (bottomCp1, bottomCp2, bottomDestination); //Right semicircle path.AddArc (rightOrigin.X, rightOrigin.Y, currentRightRadius, (float) Math.PI / 2.0f, 3 * (float) Math.PI / 2.0f, true); //Top curve var topCp2 = new PointF (lerp (leftOrigin.X, rightOrigin.X, .2f), lerp ((leftOrigin.Y - currentLeftRadius), (rightOrigin.Y - currentRightRadius), .1f)); var topCp1 = new PointF (lerp (leftOrigin.X, rightOrigin.X, .2f), lerp ((leftOrigin.Y - currentLeftRadius), (rightOrigin.Y - currentRightRadius), .9f)); var topDestination = new PointF (leftOrigin.X, leftOrigin.Y - currentLeftRadius); path.AddCurveToPoint (topCp1, topCp2, topDestination); headOrigin = leftOrigin; headRadius = currentLeftRadius; } path.CloseSubpath (); if (!triggered) { // Set paths _shapeLayer.Path = path; _shapeLayer.ShadowPath = path; // Add the arrow shape var currentArrowSize = lerp (MinArrowSize, MaxArrowSize, percentage); var currentArrowRadius = lerp (MinArrowRadius, MaxArrowRadius, percentage); var arrowBigRadius = currentArrowRadius + (currentArrowSize / 2.0f); var arrowSmallRadius = currentArrowRadius - (currentArrowSize / 2.0f); var arrowPath = new CGPath (); arrowPath.AddArc (headOrigin.X, headOrigin.Y, arrowBigRadius, 0, 3 * (float) Math.PI / 2.0f, false); arrowPath.AddLineToPoint (headOrigin.X, headOrigin.Y - arrowBigRadius - currentArrowSize); arrowPath.AddLineToPoint (headOrigin.X + (2 * currentArrowSize), headOrigin.Y - arrowBigRadius + (currentArrowSize / 2.0f)); arrowPath.AddLineToPoint (headOrigin.X, headOrigin.Y - arrowBigRadius + (2 * currentArrowSize)); arrowPath.AddLineToPoint (headOrigin.X, headOrigin.Y - arrowBigRadius + currentArrowSize); arrowPath.AddArc (headOrigin.X, headOrigin.Y, arrowSmallRadius, 3 * (float) Math.PI / 2.0f, 0, true); arrowPath.CloseSubpath (); _arrowLayer.Path = arrowPath; _arrowLayer.FillRule = CAShapeLayer.FillRuleEvenOdd; arrowPath.Dispose (); // Add the highlight shape var highlightPath = new CGPath (); if (_vertical) { highlightPath.AddArc (headOrigin.X, headOrigin.Y, headRadius, 0, (float) Math.PI, true); highlightPath.AddArc (headOrigin.X, headOrigin.Y + 1.25f, headRadius, (float) Math.PI, 0, false); } else { highlightPath.AddArc (headOrigin.X, headOrigin.Y, headRadius, - (float) Math.PI / 2.0f, (float) Math.PI / 2.0f, true); highlightPath.AddArc (headOrigin.X + 1.25f, headOrigin.Y, headRadius, (float) Math.PI / 2.0f, - (float) Math.PI / 2.0f, false); } _highlightLayer.Path = highlightPath; _highlightLayer.FillRule = CAShapeLayer.FillRuleNonZero; highlightPath.Dispose (); } else { // Start the shape disappearance animation var radius = lerp (MinBottomRadius, MaxBottomRadius, .2f); var pathMorph = CABasicAnimation.FromKeyPath ("path"); pathMorph.Duration = .15f; pathMorph.FillMode = CAFillMode.Forwards; pathMorph.RemovedOnCompletion = false; var toPath = new CGPath (); if (_vertical) { toPath.AddArc (headOrigin.X, headOrigin.Y, radius, 0, (float)Math.PI, true); toPath.AddCurveToPoint (headOrigin.X - radius, headOrigin.Y, headOrigin.X - radius, headOrigin.Y, headOrigin.X - radius, headOrigin.Y); toPath.AddArc (headOrigin.X, headOrigin.Y, radius, (float) Math.PI, 0, true); toPath.AddCurveToPoint (headOrigin.X + radius, headOrigin.Y, headOrigin.X + radius, headOrigin.Y, headOrigin.X + radius, headOrigin.Y); } else { toPath.AddArc (headOrigin.X, headOrigin.Y, radius, - (float) Math.PI / 2.0f, (float) Math.PI / 2.0f, true); toPath.AddCurveToPoint (headOrigin.X, headOrigin.Y + radius, headOrigin.X, headOrigin.Y + radius, headOrigin.X, headOrigin.Y + radius); toPath.AddArc (headOrigin.X, headOrigin.Y, radius, (float) Math.PI / 2.0f, - (float) Math.PI / 2.0f, true); toPath.AddCurveToPoint (headOrigin.X, headOrigin.Y - radius, headOrigin.X, headOrigin.Y - radius, headOrigin.X, headOrigin.Y - radius); } toPath.CloseSubpath (); pathMorph.To = new NSValue (toPath.Handle); _shapeLayer.AddAnimation (pathMorph, null); var shadowPathMorph = CABasicAnimation.FromKeyPath ("shadowPath"); shadowPathMorph.Duration = .15f; shadowPathMorph.FillMode = CAFillMode.Forwards; shadowPathMorph.RemovedOnCompletion = false; shadowPathMorph.To = new NSValue (toPath.Handle); _shapeLayer.AddAnimation (shadowPathMorph, null); toPath.Dispose (); var shapeAlphaAnimation = CABasicAnimation.FromKeyPath ("opacity"); shapeAlphaAnimation.Duration = .1f; shapeAlphaAnimation.BeginTime = CABasicAnimation.CurrentMediaTime () + .1; shapeAlphaAnimation.To = new NSNumber (0); shapeAlphaAnimation.FillMode = CAFillMode.Forwards; shapeAlphaAnimation.RemovedOnCompletion = false; _shapeLayer.AddAnimation (shapeAlphaAnimation, null); var alphaAnimation = CABasicAnimation.FromKeyPath ("opacity"); alphaAnimation.Duration = .1f; alphaAnimation.To = new NSNumber (0); alphaAnimation.FillMode = CAFillMode.Forwards; alphaAnimation.RemovedOnCompletion = false; _arrowLayer.AddAnimation (alphaAnimation, null); _highlightLayer.AddAnimation (alphaAnimation, null); CATransaction.Begin (); CATransaction.DisableActions = true; _activity.Layer.Transform = CATransform3D.MakeScale (.1f, .1f, 1); CATransaction.Commit (); UIView.Animate (.2f, .15f, UIViewAnimationOptions.CurveLinear, () => { _activity.Alpha = 1; _activity.Layer.Transform = CATransform3D.MakeScale (1, 1, 1); }, null); _refreshing = true; _canRefresh = false; SendActionForControlEvents (UIControlEvent.ValueChanged); } path.Dispose (); }
public static CGPath AsCGPathFromSegment( this PathF target, int segmentIndex, float ppu, float zoom) { ppu = ppu * zoom; var path = new CGPath(); var type = target.GetSegmentType(segmentIndex); if (type == PathOperation.Line) { var pointIndex = target.GetSegmentPointIndex(segmentIndex); var startPoint = target[pointIndex - 1]; path.MoveToPoint(startPoint.X * ppu, startPoint.Y * ppu); var endPoint = target[pointIndex]; path.AddLineToPoint(endPoint.X * ppu, endPoint.Y * ppu); } else if (type == PathOperation.Quad) { var pointIndex = target.GetSegmentPointIndex(segmentIndex); var startPoint = target[pointIndex - 1]; path.MoveToPoint(startPoint.X * ppu, startPoint.Y * ppu); var controlPoint = target[pointIndex++]; var endPoint = target[pointIndex]; path.AddQuadCurveToPoint(controlPoint.X * ppu, controlPoint.Y * ppu, endPoint.X * ppu, endPoint.Y * ppu); } else if (type == PathOperation.Cubic) { var pointIndex = target.GetSegmentPointIndex(segmentIndex); var startPoint = target[pointIndex - 1]; path.MoveToPoint(startPoint.X * ppu, startPoint.Y * ppu); var controlPoint1 = target[pointIndex++]; var controlPoint2 = target[pointIndex++]; var endPoint = target[pointIndex]; path.AddCurveToPoint(controlPoint1.X * ppu, controlPoint1.Y * ppu, controlPoint2.X * ppu, controlPoint2.Y * ppu, endPoint.X * ppu, endPoint.Y * ppu); } else if (type == PathOperation.Arc) { target.GetSegmentInfo(segmentIndex, out var pointIndex, out var arcAngleIndex, out var arcClockwiseIndex); var topLeft = target[pointIndex++]; var bottomRight = target[pointIndex++]; var startAngle = target.GetArcAngle(arcAngleIndex++); var endAngle = target.GetArcAngle(arcAngleIndex++); var clockwise = target.GetArcClockwise(arcClockwiseIndex++); var startAngleInRadians = Geometry.DegreesToRadians(-startAngle); var endAngleInRadians = Geometry.DegreesToRadians(-endAngle); while (startAngleInRadians < 0) { startAngleInRadians += (float)Math.PI * 2; } while (endAngleInRadians < 0) { endAngleInRadians += (float)Math.PI * 2; } var cx = (bottomRight.X + topLeft.X) / 2; var cy = (bottomRight.Y + topLeft.Y) / 2; var width = bottomRight.X - topLeft.X; var height = bottomRight.Y - topLeft.Y; var r = width / 2; var transform = CGAffineTransform.MakeTranslation(cx * ppu, cy * ppu); transform = CGAffineTransform.Multiply(CGAffineTransform.MakeScale(1, height / width), transform); path.AddArc(transform, 0, 0, r * ppu, startAngleInRadians, endAngleInRadians, !clockwise); } return(path); }
public static CGPath AsRotatedCGPath(this PathF target, PointF center, float ppu, float zoom, float angle) { ppu = ppu * zoom; var path = new CGPath(); int pointIndex = 0; int arcAngleIndex = 0; int arcClockwiseIndex = 0; foreach (var type in target.SegmentTypes) { if (type == PathOperation.Move) { var point = target.GetRotatedPoint(pointIndex++, center, angle); path.MoveToPoint(point.X * ppu, point.Y * ppu); } else if (type == PathOperation.Line) { var endPoint = target.GetRotatedPoint(pointIndex++, center, angle); path.AddLineToPoint(endPoint.X * ppu, endPoint.Y * ppu); } else if (type == PathOperation.Quad) { var controlPoint = target.GetRotatedPoint(pointIndex++, center, angle); var endPoint = target.GetRotatedPoint(pointIndex++, center, angle); path.AddQuadCurveToPoint( controlPoint.X * ppu, controlPoint.Y * ppu, endPoint.X * ppu, endPoint.Y * ppu); } else if (type == PathOperation.Cubic) { var controlPoint1 = target.GetRotatedPoint(pointIndex++, center, angle); var controlPoint2 = target.GetRotatedPoint(pointIndex++, center, angle); var endPoint = target.GetRotatedPoint(pointIndex++, center, angle); path.AddCurveToPoint( controlPoint1.X * ppu, controlPoint1.Y * ppu, controlPoint2.X * ppu, controlPoint2.Y * ppu, endPoint.X * ppu, endPoint.Y * ppu); } else if (type == PathOperation.Arc) { var topLeft = target[pointIndex++]; var bottomRight = target[pointIndex++]; float startAngle = target.GetArcAngle(arcAngleIndex++); float endAngle = target.GetArcAngle(arcAngleIndex++); var clockwise = target.GetArcClockwise(arcClockwiseIndex++); var startAngleInRadians = Geometry.DegreesToRadians(-startAngle); var endAngleInRadians = Geometry.DegreesToRadians(-endAngle); while (startAngleInRadians < 0) { startAngleInRadians += (float)Math.PI * 2; } while (endAngleInRadians < 0) { endAngleInRadians += (float)Math.PI * 2; } var cx = (bottomRight.X + topLeft.X) / 2; var cy = (bottomRight.Y + topLeft.Y) / 2; var width = bottomRight.X - topLeft.X; var height = bottomRight.Y - topLeft.Y; var r = width / 2; var rotatedCenter = Geometry.RotatePoint(center, new PointF(cx, cy), angle); var transform = CGAffineTransform.MakeTranslation(rotatedCenter.X * ppu, rotatedCenter.Y * ppu); transform = CGAffineTransform.Multiply(CGAffineTransform.MakeScale(1, height / width), transform); path.AddArc(transform, 0, 0, r * ppu, startAngleInRadians, endAngleInRadians, !clockwise); } else if (type == PathOperation.Close) { path.CloseSubpath(); } } return(path); }
public static CGPath AsCGPath( this PathF target, float ox, float oy, float fx, float fy) { var path = new CGPath(); int pointIndex = 0; int arcAngleIndex = 0; int arcClockwiseIndex = 0; foreach (var type in target.SegmentTypes) { if (type == PathOperation.Move) { var point = target[pointIndex++]; path.MoveToPoint((ox + point.X * fx), (oy + point.Y * fy)); } else if (type == PathOperation.Line) { var endPoint = target[pointIndex++]; path.AddLineToPoint((ox + endPoint.X * fx), (oy + endPoint.Y * fy)); } else if (type == PathOperation.Quad) { var controlPoint = target[pointIndex++]; var endPoint = target[pointIndex++]; path.AddQuadCurveToPoint( (ox + controlPoint.X * fx), (oy + controlPoint.Y * fy), (ox + endPoint.X * fx), (oy + endPoint.Y * fy)); } else if (type == PathOperation.Cubic) { var controlPoint1 = target[pointIndex++]; var controlPoint2 = target[pointIndex++]; var endPoint = target[pointIndex++]; path.AddCurveToPoint( (ox + controlPoint1.X * fx), (oy + controlPoint1.Y * fy), (ox + controlPoint2.X * fx), (oy + controlPoint2.Y * fy), (ox + endPoint.X * fx), (oy + endPoint.Y * fy)); } else if (type == PathOperation.Arc) { var topLeft = target[pointIndex++]; var bottomRight = target[pointIndex++]; float startAngle = target.GetArcAngle(arcAngleIndex++); float endAngle = target.GetArcAngle(arcAngleIndex++); var clockwise = target.GetArcClockwise(arcClockwiseIndex++); var startAngleInRadians = Geometry.DegreesToRadians(-startAngle); var endAngleInRadians = Geometry.DegreesToRadians(-endAngle); while (startAngleInRadians < 0) { startAngleInRadians += (float)Math.PI * 2; } while (endAngleInRadians < 0) { endAngleInRadians += (float)Math.PI * 2; } var cx = (bottomRight.X + topLeft.X) / 2; var cy = (bottomRight.Y + topLeft.Y) / 2; var width = bottomRight.X - topLeft.X; var height = bottomRight.Y - topLeft.Y; var r = width / 2; var transform = CGAffineTransform.MakeTranslation(ox + cx, oy + cy); transform = CGAffineTransform.Multiply(CGAffineTransform.MakeScale(1, height / width), transform); path.AddArc(transform, 0, 0, r * fx, startAngleInRadians, endAngleInRadians, !clockwise); } else if (type == PathOperation.Close) { path.CloseSubpath(); } } return(path); }
public void DrawDroplet(CGContext canvas, string label, bool biggie, SKPoint center, float padRadius, float radius, float textStrokeWidth, SKPaint fillPaint, float strokeWidth, float accentStrokeWidth, Swipe swipe) { float ratio = radius / padRadius; //strokeWidth = strokeWidth * ratio; textStrokeWidth = textStrokeWidth * ratio; accentStrokeWidth = accentStrokeWidth * ratio; float pull = 0.75f; float accentRadius = radius - (strokeWidth + accentStrokeWidth) / 2.0f; var path = new CGPath(); path.MoveToPoint(CG.Point(swipe % new SKPoint(center.X, center.Y - radius))); // The parameters to CGPath.AddCurveToPoint are in the same order as in SKPath.CubicTo (despite what the Apple docs seem to say). path.AddCurveToPoint(CG.Point(swipe % new SKPoint(center.X + pull * radius, center.Y - radius)), CG.Point(swipe % new SKPoint(center.X + radius, center.Y - pull * radius)), CG.Point(swipe % new SKPoint(center.X + radius, center.Y))); path.AddCurveToPoint(CG.Point(swipe % new SKPoint(center.X + radius, center.Y + pull * radius)), CG.Point(swipe % new SKPoint(center.X + pull * radius, center.Y + radius)), CG.Point(swipe % new SKPoint(center.X, center.Y + radius))); path.AddCurveToPoint(CG.Point(swipe % new SKPoint(center.X - pull * radius, center.Y + radius)), CG.Point(swipe % new SKPoint(center.X - radius, center.Y + pull * radius)), CG.Point(swipe % new SKPoint(center.X - radius, center.Y))); path.AddCurveToPoint(CG.Point(swipe % new SKPoint(center.X - radius, center.Y - pull * radius)), CG.Point(swipe % new SKPoint(center.X - pull * radius, center.Y - radius)), CG.Point(swipe % new SKPoint(center.X, center.Y - radius))); path.CloseSubpath(); var darkPath = new CGPath(); darkPath.MoveToPoint(CG.Point(swipe % new SKPoint(center.X + accentRadius, center.Y))); darkPath.AddCurveToPoint(CG.Point(swipe % new SKPoint(center.X + accentRadius, center.Y + pull * accentRadius)), CG.Point(swipe % new SKPoint(center.X + pull * accentRadius, center.Y + accentRadius)), CG.Point(swipe % new SKPoint(center.X, center.Y + accentRadius))); var lightPath = new CGPath(); lightPath.MoveToPoint(CG.Point(swipe % new SKPoint(center.X - accentRadius, center.Y))); lightPath.AddCurveToPoint(CG.Point(swipe % new SKPoint(center.X - accentRadius, center.Y - pull * accentRadius)), CG.Point(swipe % new SKPoint(center.X - pull * accentRadius, center.Y - accentRadius)), CG.Point(swipe % new SKPoint(center.X, center.Y - accentRadius))); using (var strokePaint = new SKPaint { Style = SKPaintStyle.Stroke, Color = new SKColor(0, 0, 0, 191), StrokeWidth = swipe % strokeWidth, IsAntialias = true }) using (var accentLightPaint = new SKPaint { Style = SKPaintStyle.Stroke, Color = new SKColor(255, 255, 255, 191), StrokeWidth = swipe % accentStrokeWidth, StrokeCap = SKStrokeCap.Round, IsAntialias = true }) using (var accentDarkPaint = new SKPaint { Style = SKPaintStyle.Stroke, Color = new SKColor(0, 0, 0, 95), StrokeWidth = swipe % accentStrokeWidth, StrokeCap = SKStrokeCap.Round, IsAntialias = true }) { canvas.AddPath(path); canvas.SetFillColor(CG.Color(fillPaint.Color)); canvas.FillPath(); canvas.AddPath(darkPath); canvas.SetStrokeColor(CG.Color(accentDarkPaint.Color)); canvas.SetLineWidth(accentDarkPaint.StrokeWidth); canvas.SetLineJoin(CG.LineJoin(accentDarkPaint.StrokeJoin)); canvas.SetLineCap(CG.LineCap(accentDarkPaint.StrokeCap)); canvas.StrokePath(); canvas.AddPath(lightPath); canvas.SetStrokeColor(CG.Color(accentLightPaint.Color)); canvas.SetLineWidth(accentLightPaint.StrokeWidth); canvas.SetLineJoin(CG.LineJoin(accentLightPaint.StrokeJoin)); canvas.SetLineCap(CG.LineCap(accentLightPaint.StrokeCap)); canvas.StrokePath(); canvas.AddPath(path); canvas.SetStrokeColor(CG.Color(strokePaint.Color)); canvas.SetLineWidth(strokePaint.StrokeWidth); canvas.SetLineJoin(CG.LineJoin(strokePaint.StrokeJoin)); canvas.SetLineCap(CG.LineCap(strokePaint.StrokeCap)); canvas.StrokePath(); } DrawDropletLabel(canvas, label, center, radius, textStrokeWidth, biggie, swipe); }