Missing DashOffset in Pen Style
See original GitHub issueHi, I’m wondering why the DashOffset is not present in Mapsui.Styles.Pen.
I need to create animations which uses XAML StrokeDashOffset or phase in SKPathEffect.CreateDash(dash, phase).
Please let me know if you think there’s easier ways to accomplish the following or if you would like a PR 😉

Mapsui.Styles.Pen
Property
/// <summary>
/// Stroke dash offset (phase)
/// </summary>
public float DashOffset { get; set; }
Mapsui.Rendering.Skia.PenStyleExtension
Optional parameter to specify phase
public static SKPathEffect ToSkia(this PenStyle penStyle, float width, float[] dashArray = null, float phase = 0f)
{
switch (penStyle)
{
case PenStyle.UserDefined:
// If dashArray is empty or not even, create sold dash
if (dashArray == null || dashArray.Length == 0 || dashArray.Length % 2 != 0)
return SKPathEffect.CreateDash(new float[0], 0);
// Multiply each dash entry with line width
float[] dash = new float[dashArray.Length];
for (var i = 0; i < dashArray.Length; i++)
{
dash[i] = dashArray[i] * width;
}
return SKPathEffect.CreateDash(dash, phase);
case PenStyle.Dash:
return SKPathEffect.CreateDash(new [] { width * 4f, width * 3f }, phase);
case PenStyle.Dot:
return SKPathEffect.CreateDash(new [] { width * 1f, width * 3f }, phase);
case PenStyle.DashDot:
return SKPathEffect.CreateDash(new [] { width * 4f, width * 3f, width * 1f, width * 3f }, phase);
case PenStyle.DashDotDot:
return SKPathEffect.CreateDash(new [] { width * 4f, width * 3f, width * 1f, width * 3f, width * 1f, width * 3f }, phase);
case PenStyle.LongDash:
return SKPathEffect.CreateDash(new [] { width * 8f, width * 3f }, phase);
case PenStyle.LongDashDot:
return SKPathEffect.CreateDash(new [] { width * 8f, width * 3f, width * 1f, width * 3f }, phase);
case PenStyle.ShortDash:
return SKPathEffect.CreateDash(new [] { width * 2f, width * 3f }, phase);
case PenStyle.ShortDashDot:
return SKPathEffect.CreateDash(new [] { width * 2f, width * 3f, width * 1f, width * 3f }, phase);
case PenStyle.ShortDashDotDot:
return SKPathEffect.CreateDash(new [] { width * 2f, width * 3f, width * 1f, width * 3f, width * 1f, width * 3f }, phase);
case PenStyle.ShortDot:
return SKPathEffect.CreateDash(new [] { width * 1f, width * 3f }, phase);
default:
return SKPathEffect.CreateDash(new float[0], phase);
}
}
}
Mapsui.Rendering.Skia.LineStringRenderer
Inherits value from VectorStyle
public static void Draw(SKCanvas canvas, IReadOnlyViewport viewport, IStyle style, IFeature feature, IGeometry geometry,
float opacity)
{
if (style is LabelStyle labelStyle)
{
var worldCenter = geometry.BoundingBox.Centroid;
var center = viewport.WorldToScreen(worldCenter);
LabelRenderer.Draw(canvas, labelStyle, feature, center, opacity);
}
else
{
var lineString = ((LineString) geometry).Vertices;
float lineWidth = 1;
var lineColor = new Color();
var vectorStyle = style as VectorStyle;
var strokeCap = PenStrokeCap.Butt;
var strokeJoin = StrokeJoin.Miter;
var strokeMiterLimit = 4f;
var strokeStyle = PenStyle.Solid;
float[] dashArray = null;
float dashOffset = 0f;
if (vectorStyle != null)
{
lineWidth = (float) vectorStyle.Line.Width;
lineColor = vectorStyle.Line.Color;
strokeCap = vectorStyle.Line.PenStrokeCap;
strokeJoin = vectorStyle.Line.StrokeJoin;
strokeMiterLimit = vectorStyle.Line.StrokeMiterLimit;
strokeStyle = vectorStyle.Line.PenStyle;
dashArray = vectorStyle.Line.DashArray;
dashOffset = vectorStyle.Line.DashOffset;
}
using (var path = lineString.ToSkiaPath(viewport, canvas.LocalClipBounds))
using (var paint = new SKPaint { IsAntialias = true })
{
paint.IsStroke = true;
paint.StrokeWidth = lineWidth;
paint.Color = lineColor.ToSkia(opacity);
paint.StrokeCap = strokeCap.ToSkia();
paint.StrokeJoin = strokeJoin.ToSkia();
paint.StrokeMiter = strokeMiterLimit;
if (strokeStyle != PenStyle.Solid)
paint.PathEffect = strokeStyle.ToSkia(lineWidth, dashArray, dashOffset);
else
paint.PathEffect = null;
canvas.DrawPath(path, paint);
}
}
}
Mapsui.Rendering.Xaml.LineStringRenderer
Inherits value from VectorStyle
public static class LineStringRenderer
{
public static System.Windows.Shapes.Shape RenderLineString(LineString lineString, IStyle style, IReadOnlyViewport viewport)
{
if (!(style is VectorStyle)) throw new ArgumentException("Style is not of type VectorStyle");
var vectorStyle = style as VectorStyle;
System.Windows.Shapes.Path path = CreateLineStringPath(vectorStyle);
path.Data = lineString.ToXaml();
path.RenderTransform = new MatrixTransform { Matrix = GeometryRenderer.CreateTransformMatrix(viewport) };
GeometryRenderer.CounterScaleLineWidth(path, viewport.Resolution);
return path;
}
public static System.Windows.Shapes.Path CreateLineStringPath(VectorStyle style)
{
var path = new System.Windows.Shapes.Path { Opacity = style.Opacity };
if (style.Outline != null)
{
//todo: render an outline around the line.
}
path.Stroke = new SolidColorBrush(style.Line.Color.ToXaml());
path.StrokeDashArray = style.Line.PenStyle.ToXaml(style.Line.DashArray);
path.StrokeDashOffset = style.Line.DashOffset;
var penStrokeCap = style.Line.PenStrokeCap.ToXaml();
path.StrokeEndLineCap = penStrokeCap;
path.StrokeStartLineCap = penStrokeCap;
path.StrokeLineJoin = style.Line.StrokeJoin.ToXaml();
path.StrokeMiterLimit = style.Line.StrokeMiterLimit;
path.Tag = style.Line.Width; // see #linewidthhack
path.IsHitTestVisible = false;
return path;
}
}
Issue Analytics
- State:
- Created 2 years ago
- Comments:5 (4 by maintainers)
Top Results From Across the Web
Stroke animation not happening
I am playing with CSS3 animation and dashoffset. This is the tutorial I have been following: https://jakearchibald.com/2013/animated-line- ...
Read more >stroke-dashoffset
The stroke-dashoffset property in CSS defines the location along an SVG path where the dash of a stroke will begin. The higher the...
Read more >DrawSVG progress 50%? - GSAP
Hi, I'm working on a animation for a circle that shows a "progress" between 0% and 100%. What I cannot understand is why...
Read more >CSS Animation of stroke-dashoffset from 0 to 100% does ...
The attached test case contains an animation that animates the stroke-dashoffset property. The keyframes rule looks like: @keyframes trolley-path-move { to ...
Read more >2020 SVG Animation | @keyframers 2.29.0 - YouTube
... https://cdpn.io/ pen /BayJqMX Skip around: 2:10 Animation overview 3:22 ... 2020 SVG Animation | Using pathLength=1 with stroke- dashoffset ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found

See #1157
Is this issue is solved? If yes, can you close it?