Beispiel #1
0
        void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
        {
            SKImageInfo info    = args.Info;
            SKSurface   surface = args.Surface;
            SKCanvas    canvas  = surface.Canvas;

            canvas.Clear();

            // Draw path with cubic Bezier curve
            using (SKPath path = new SKPath())
            {
                path.MoveTo(touchPoints[0].Center);
                path.CubicTo(touchPoints[1].Center,
                             touchPoints[2].Center,
                             touchPoints[3].Center);

                canvas.DrawPath(path, strokePaint);

                // Get path length
                SKPathMeasure pathMeasure = new SKPathMeasure(path, false, 1);

                // Find new text size
                textPaint.TextSize = pathMeasure.Length / baseTextWidth * 10;

                // Draw text on path
                canvas.DrawTextOnPath(text, path, 0, 0, textPaint);
            }

            foreach (TouchPoint touchPoint in touchPoints)
            {
                touchPoint.Paint(canvas);
            }
        }
Beispiel #2
0
        public override Vector2?GetValue(Keyframe <Vector2?> keyframe, float keyframeProgress)
        {
            var pathKeyframe = (PathKeyframe)keyframe;
            var path         = pathKeyframe.Path;

            if (path == null || path.IsEmpty)
            {
                return(keyframe.StartValue);
            }

            if (ValueCallback != null)
            {
                var value = ValueCallback.GetValueInternal(pathKeyframe.StartFrame.Value, pathKeyframe.EndFrame.Value,
                                                           pathKeyframe.StartValue, pathKeyframe.EndValue, LinearCurrentKeyframeProgress,
                                                           keyframeProgress, Progress);
                if (value != null)
                {
                    return(value);
                }
            }

            if (_pathMeasureKeyframe != pathKeyframe)
            {
                _pathMeasure?.Dispose();
                _pathMeasure         = new SKPathMeasure(path);
                _pathMeasureKeyframe = pathKeyframe;
            }
            _pathMeasure.GetPositionAndTangent(keyframeProgress * _pathMeasure.Length, out var pos, out _);
            return(new Vector2(pos.X, pos.Y));
        }
Beispiel #3
0
        public void ConstructorDoesNotThrownOnNonNullPathArgument()
        {
            var path = new SKPath();
            var pm   = new SKPathMeasure(path);

            Assert.NotNull(pm);
        }
Beispiel #4
0
 private void Dispose(bool disposing)
 {
     if (_pathMeasure != null)
     {
         _pathMeasure.Dispose();
         _pathMeasure = null;
     }
 }
Beispiel #5
0
        private void DrawIntervalName(SKPath intervalPath, SKCanvas canvas, string currentIntName, float vOffset)
        {
            using (var intervalTextPaint = new SKPaint
            {
                Color = GetTextColor(),
                TextScaleX = 1.2f
            })
            {
                var pathMeasure = new SKPathMeasure(intervalPath);

                intervalTextPaint.TextSize  = (float)Device.GetNamedSize(NamedSize.Medium, typeof(Entry));
                intervalTextPaint.TextSize *= Device.RuntimePlatform == Device.Android
                    ? 2.5f
                    : 1f;
                float initialTextSize = intervalTextPaint.TextSize;
                SetIntervalTextSize(intervalTextPaint, pathMeasure.Length);

                //if the new text size is too small, just return
                if (IsIntervalTextSizeTooSmall(initialTextSize, intervalTextPaint.TextSize))
                {
                    return;
                }

                string intervalName           = currentIntName;
                int    aditionalCharsToRemove = 0;
                while (intervalTextPaint.MeasureText(intervalName) >= pathMeasure.Length * 0.8f)
                {
                    float charWidth     = intervalTextPaint.MeasureText(currentIntName) / currentIntName.Length;
                    float diff          = intervalTextPaint.MeasureText(currentIntName) - pathMeasure.Length * 0.8f;
                    int   charsToRemove = (int)Math.Floor(diff / charWidth) + aditionalCharsToRemove;
                    //just in case...
                    if (currentIntName.Length - charsToRemove < 1)
                    {
                        return;
                    }
                    intervalName = $"{currentIntName.Substring(0, currentIntName.Length - charsToRemove)}...";
                    aditionalCharsToRemove++;
                }

                float textWidth   = intervalTextPaint.MeasureText(intervalName);
                float nameHOffset = pathMeasure.Length / 4f - textWidth / 4f;

                canvas.DrawTextOnPath(intervalName, intervalPath, nameHOffset, vOffset, intervalTextPaint);
            }
        }
Beispiel #6
0
        protected override void OnDrawSample(SKCanvas canvas, int width, int height)
        {
            canvas.Clear(SKColors.White);

            using (SKPaint paint = new SKPaint())
                using (SKPath path = new SKPath())
                {
                    paint.Style       = SKPaintStyle.Stroke;
                    paint.StrokeWidth = 10;
                    paint.IsAntialias = true;
                    paint.StrokeCap   = SKStrokeCap.Round;
                    paint.StrokeJoin  = SKStrokeJoin.Round;

                    path.MoveTo(20, 20);
                    path.LineTo(400, 50);
                    path.LineTo(80, 100);
                    path.LineTo(300, 150);

                    paint.Color = SampleMedia.Colors.XamarinDarkBlue;
                    canvas.DrawPath(path, paint);

                    using (var measure = new SKPathMeasure(path, false))
                        using (var dst = new SKPath())
                        {
                            var length = measure.Length;

                            dst.Reset();
                            measure.GetSegment(length * 0.05f, length * 0.2f, dst, true);
                            paint.Color = SampleMedia.Colors.XamarinPurple;
                            canvas.DrawPath(dst, paint);

                            dst.Reset();
                            measure.GetSegment(length * 0.2f, length * 0.8f, dst, true);
                            paint.Color = SampleMedia.Colors.XamarinGreen;
                            canvas.DrawPath(dst, paint);

                            dst.Reset();
                            measure.GetSegment(length * 0.8f, length * 0.95f, dst, true);
                            paint.Color = SampleMedia.Colors.XamarinLightBlue;
                            canvas.DrawPath(dst, paint);
                        }
                }
        }
Beispiel #7
0
        public void MeasuringSegementsWorks()
        {
            using (SKPath path = new SKPath())
            {
                path.MoveTo(10f, 10f);
                path.LineTo(110f, 10f);

                var measure = new SKPathMeasure(path);

                Assert.Equal(100f, measure.Length);

                var segment = new SKPath();
                var result  = measure.GetSegment(20, 50, segment, true);
                Assert.True(result);
                Assert.Equal(2, segment.PointCount);
                Assert.Equal(new SKPoint(30, 10), segment.Points [0]);
                Assert.Equal(new SKPoint(60, 10), segment.Points [1]);
            }
        }
Beispiel #8
0
        private PathInfo[] GetSKPaths(IEnumerable <int[][]> points, int totalPickPointCount)
        {
            var count       = points.Count();
            var skPaths     = new PathInfo[count];
            var pathMeasure = new SKPathMeasure();
            var index       = 0;

            foreach (var pathData in points)
            {
                var path = new SKPath();
                if (pathData[0].Length == 1)
                {
                    path.MoveTo(new SKPoint(pathData[0][0], pathData[1][0]));
                }
                else if (pathData[0].Length > 1)
                {
                    path.MoveTo(new SKPoint(pathData[0][0], pathData[1][0]));
                    for (int i = 1; i < pathData[0].Length; i++)
                    {
                        path.LineTo(new SKPoint(pathData[0][i], pathData[1][i]));
                    }
                }
                pathMeasure.SetPath(path, false);
                skPaths[index] = new PathInfo
                {
                    Path   = path,
                    Length = pathMeasure.Length
                };
                index++;
            }
            pathMeasure.Dispose();
            var totalLength = skPaths.Aggregate <PathInfo, double>(0, (current, item) => current + item.Length);

            for (int i = 0; i < skPaths.Length; i++)
            {
                if (skPaths[i].Length > 0)
                {
                    skPaths[i].PickPointCount = (int)Math.Round(skPaths[i].Length / totalLength * totalPickPointCount);
                }
            }
            return(skPaths);
        }
Beispiel #9
0
        private SKPoint[] GetPathPoints(PathInfo info)
        {
            if (info.PickPointCount == 0)
            {
                return(null);
            }
            var points      = new SKPoint[info.PickPointCount];
            var pathMeasure = new SKPathMeasure();

            pathMeasure.SetPath(info.Path, false);
            var disGap  = info.Length / info.PickPointCount;
            var halfGap = disGap / 2;

            for (int i = 0; i < info.PickPointCount; i++)
            {
                pathMeasure.GetPosition(disGap * i + halfGap, out var pos);
                points[i] = pos;
            }
            pathMeasure.Dispose();
            info.Path.Dispose();
            return(points);
        }
        private static List <SKPoint> CreateCurvedPathPoints(SKPath path, float maxSegmentLength)
        {
            using (var m = new SKPathMeasure(path))
            {
                var len = m.Length;

                var numPoints = 3;
                if (maxSegmentLength > 0)
                {
                    numPoints = Math.Max(numPoints, (int)Math.Ceiling(len / maxSegmentLength));
                }

                var ring = new List <SKPoint>();
                for (var i = 0; i < numPoints; i++)
                {
                    SKPoint p;
                    m.GetPosition(len * i / numPoints, out p);
                    ring.Add(p);
                }

                return(ring);
            }
        }
        void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
        {
            SKImageInfo info    = args.Info;
            SKSurface   surface = args.Surface;
            SKCanvas    canvas  = surface.Canvas;

            canvas.Clear();

            using (SKPath pipePath = new SKPath())
            {
                pipePath.MoveTo(50, 50);
                pipePath.CubicTo(0, 1.25f * info.Height,
                                 info.Width - 0, 1.25f * info.Height,
                                 info.Width - 50, 50);

                canvas.DrawPath(pipePath, strokePaint);

                using (SKPathMeasure pathMeasure = new SKPathMeasure(pipePath))
                {
                    float length = pathMeasure.Length;

                    // Animate t from 0 to 1 every three seconds
                    TimeSpan timeSpan = new TimeSpan(DateTime.Now.Ticks);
                    float    t        = (float)(timeSpan.TotalSeconds % 5 / 5);

                    // t from 0 to 1 to 0 but slower at beginning and end
                    t = (float)((1 - Math.Cos(t * 2 * Math.PI)) / 2);

                    SKMatrix matrix;
                    pathMeasure.GetMatrix(t * length, out matrix,
                                          SKPathMeasureMatrixFlags.GetPositionAndTangent);

                    canvas.SetMatrix(matrix);
                    canvas.DrawPath(unicyclePath, strokePaint);
                }
            }
        }
Beispiel #12
0
        public static HighlightPath Create(SKCanvasView skCanvasView, IList <View> layoutChildren, double strokeWidth)
        {
            var path = new SKPath();

            var highlightPath = new HighlightPath()
            {
                Path = path
            };

            strokeWidth = (float)skCanvasView.FromPixels(new Point(0, strokeWidth)).Y;

            foreach (View view in layoutChildren)
            {
                int       iStrokeDashCount = highlightPath.DashCount;
                Rectangle viewBounds       = skCanvasView.FromPixels(view.Bounds);

                if (!(view is Entry) && !(view is Button))
                {
                    continue;
                }

                if (path.Points.Length == 0)
                {
                    // Move path point at the left and below of the view
                    path.MoveTo(
                        x: (float)viewBounds.X,
                        y: (float)viewBounds.Y + (float)viewBounds.Height + (float)strokeWidth / 2);
                }

                float xCurr = path.LastPoint.X;
                float yCurr = path.LastPoint.Y;

                // Add arch for views except first one
                if (iStrokeDashCount > 0)
                {
                    float d         = iStrokeDashCount % 2 == 0 ? -1 : 1;
                    float arcHeight = (float)viewBounds.Y + (float)viewBounds.Height - path.LastPoint.Y + (float)strokeWidth / 2;
                    path.ArcTo(new SKRect(xCurr - arcHeight / 2, yCurr, xCurr + arcHeight / 2, yCurr + arcHeight), -90, 180 * d, false);
                }

                float dashOffset = new SKPathMeasure(path).Length;

                // Add line below the view
                // If it's not the first view, the start point is the end from arc end point
                //  and line direction is either to view start or view end
                path.LineTo((float)viewBounds.X + (float)viewBounds.Width * (iStrokeDashCount % 2 == 0 ? 1 : 0), path.LastPoint.Y);

                if (view is Button)
                {
                    xCurr = path.LastPoint.X;
                    yCurr = path.LastPoint.Y;

                    // Draw arc from below button to above button
                    float d         = iStrokeDashCount % 2 == 0 ? -1 : 1;
                    float arcHeight = (float)viewBounds.Height + (float)strokeWidth;
                    path.ArcTo(new SKRect(xCurr - arcHeight / 2, yCurr - arcHeight, xCurr + arcHeight / 2, yCurr), 90, 180 * d, false);

                    // Draw horizontal line above the button
                    path.LineTo(xCurr + (float)viewBounds.Width * d, path.LastPoint.Y);

                    // Draw arc pointing down
                    xCurr = path.LastPoint.X;
                    yCurr = path.LastPoint.Y;
                    path.ArcTo(new SKRect(xCurr - arcHeight / 2, yCurr, xCurr + arcHeight / 2, yCurr + arcHeight), -90, 180 * d, false);
                }

                float solidDashLength = new SKPathMeasure(path).Length - dashOffset;

                var strokeDash = new StrokeDash(
                    intervals: new float[] { solidDashLength, 0 },
                    phase: -dashOffset);

                highlightPath.SetDashForView(layoutChildren, view, strokeDash);
            }

            // Compute the 2nd value of interval, which is the length of remaining path
            float pathLength = new SKPathMeasure(path).Length;

            for (int i = 0; i < highlightPath.DashCount; ++i)
            {
                StrokeDash d = highlightPath.GetDash(i);
                d.Intervals[1] = pathLength - d.Intervals[0];
            }

            return(highlightPath);
        }
Beispiel #13
0
        internal static void ApplyTrimPathIfNeeded(ref SKPath path, float startValue, float endValue, float offsetValue)
        {
            LottieLog.BeginSection("applyTrimPathIfNeeded");
            SKPath tempPath = null;

            using (var pathMeasure = new SKPathMeasure(path))
            {
                var length = pathMeasure.Length;
                if (startValue == 1f && endValue == 0f)
                {
                    LottieLog.EndSection("applyTrimPathIfNeeded");
                    return;
                }
                if (length < 1f || Math.Abs(endValue - startValue - 1) < .01)
                {
                    LottieLog.EndSection("applyTrimPathIfNeeded");
                    return;
                }
                var start    = length * startValue;
                var end      = length * endValue;
                var newStart = Math.Min(start, end);
                var newEnd   = Math.Max(start, end);

                var offset = offsetValue * length;
                newStart += offset;
                newEnd   += offset;

                // If the trim path has rotated around the path, we need to shift it back.
                if (newStart >= length && newEnd >= length)
                {
                    newStart = MiscUtils.FloorMod(newStart, length);
                    newEnd   = MiscUtils.FloorMod(newEnd, length);
                }

                if (newStart < 0)
                {
                    newStart = MiscUtils.FloorMod(newStart, length);
                }
                if (newEnd < 0)
                {
                    newEnd = MiscUtils.FloorMod(newEnd, length);
                }

                // If the start and end are equals, return an empty path.
                if (newStart == newEnd)
                {
                    path.Reset();
                    LottieLog.EndSection("applyTrimPathIfNeeded");
                    return;
                }

                if (newStart >= newEnd)
                {
                    newStart -= length;
                }

                tempPath = new SKPath();
                pathMeasure.GetSegment(newStart, newEnd, tempPath, true);

                if (newEnd > length)
                {
                    var tempPath2 = new SKPath();
                    tempPath2.Reset();
                    pathMeasure.GetSegment(0, newEnd % length, tempPath2, true);
                    tempPath.AddPath(tempPath2);
                }
                else if (newStart < 0)
                {
                    var tempPath2 = new SKPath();
                    tempPath2.Reset();
                    pathMeasure.GetSegment(length + newStart, length, tempPath2, true);
                    tempPath.AddPath(tempPath2);
                }
            }
            path = tempPath;
            LottieLog.EndSection("applyTrimPathIfNeeded");
        }
Beispiel #14
0
        public void EmptyConstructorDoesNotThrow()
        {
            var pm = new SKPathMeasure();

            Assert.NotNull(pm);
        }
Beispiel #15
0
        private void DrawIntervalDuration(SKRect rect, SKCanvas canvas, IntervalItemViewModel currentInterval)
        {
            float textSize        = (float)Device.GetNamedSize(NamedSize.Small, typeof(Entry)) * 1.5f;
            float durationVOffset = (float)Device.GetNamedSize(NamedSize.Small, typeof(Entry)) * 2f;

            switch (Device.RuntimePlatform)
            {
            case Device.Android:
                durationVOffset *= 2.5f;
                textSize        *= 2.5f;
                break;
            }

            //Here i create two text, one that will be drawn with a "transparent" color
            //and the other one that will be drawn over the "transparent" one
            string ciText          = TimeSpan.FromSeconds(currentInterval.TimeLeft).ToString(AppConstants.DefaultTimeSpanFormat);
            string replacementText = TimeSpan.FromSeconds(currentInterval.TimeLeft + 1).ToString(AppConstants.DefaultTimeSpanFormat);
            float  startAngle      = 0;
            float  sweepAngle      = 0;

            foreach (var interval in ViewModel.Intervals.OrderBy(i => i.Position))
            {
                sweepAngle = CalculateAngle(interval.Duration, ViewModel.GetTimerCycleTotalTime());
                if (interval.Position == currentInterval.Position)
                {
                    break;
                }
                startAngle += sweepAngle;
            }

            using (var path = new SKPath())
                using (var intervalTimePaint = new SKPaint())
                    using (var intervalTimeTransparentPaint = new SKPaint())
                    {
                        path.AddArc(rect, startAngle - 90f, sweepAngle);
                        var pathMeasure = new SKPathMeasure(path);

                        intervalTimePaint.Color                      = SKColor.Parse(currentInterval.Color);
                        intervalTimeTransparentPaint.Color           = GetAppBgColor();
                        intervalTimePaint.TextSize                   =
                            intervalTimeTransparentPaint.TextSize    = textSize;
                        intervalTimePaint.Style                      =
                            intervalTimeTransparentPaint.Style       = SKPaintStyle.StrokeAndFill;
                        intervalTimePaint.StrokeWidth                =
                            intervalTimeTransparentPaint.StrokeWidth = 2;

                        float initialTextSize = intervalTimePaint.TextSize;
                        SetIntervalTextSize(intervalTimePaint, pathMeasure.Length);
                        SetIntervalTextSize(intervalTimeTransparentPaint, pathMeasure.Length);

                        if (IsIntervalTextSizeTooSmall(initialTextSize, intervalTimePaint.TextSize))
                        {
                            return;
                        }
                        //intervalTimePaint.TextScaleX =
                        //    intervalTimeTransparentPaint.TextScaleX = pathMeasure.Length / pathMeasure.Length * 0.6f;

                        float durationWidth   = intervalTimePaint.MeasureText(ciText);
                        float durationHOffset = pathMeasure.Length / 4f - durationWidth / 4f;
                        //float durationHOffset = (float)(Math.PI * sweepAngle * radius / 360) - durationWidth / 2f;
                        //TODO: there is a small glitch with the colors here
                        //first we draw the "transparent" one
                        canvas.DrawTextOnPath(replacementText, path, durationHOffset, durationVOffset, intervalTimeTransparentPaint);
                        //and then the real one, with the corresponding color
                        canvas.DrawTextOnPath(ciText, path, durationHOffset, durationVOffset, intervalTimePaint);
                    }
        }