diff --git a/Example/examples/Stroking.js b/Example/examples/Stroking.js index ffc76105..c62437f2 100644 --- a/Example/examples/Stroking.js +++ b/Example/examples/Stroking.js @@ -11,7 +11,8 @@ import Svg, { RadialGradient, Polyline, ClipPath, - Circle + Circle, + Text } from 'react-native-svg'; class StrokeExample extends Component{ @@ -28,7 +29,7 @@ class StrokeExample extends Component{ } class StrokeLinecap extends Component{ - static title = 'The stroke-linecap property defines different types of endings to an open path'; + static title = 'The strokeLinecap property defines different types of endings to an open path'; render() { return @@ -53,6 +54,36 @@ class StrokeDasharray extends Component{ } } +class StrokeDashoffset extends Component{ + static title = 'the strokeDashoffset attribute specifies the distance into the dash pattern to start the dash.'; + render() { + return + + STROKE + ; + } +} + class StrokePattern extends Component{ static title = 'Advanced stroke example.'; render() { @@ -110,7 +141,7 @@ const icon = ; -const samples = [StrokeExample, StrokeLinecap, StrokeDasharray, StrokePattern]; +const samples = [StrokeExample, StrokeLinecap, StrokeDasharray, StrokeDashoffset, StrokePattern]; export { icon, diff --git a/android/src/main/java/com/horcrux/svg/RNSVGPathShadowNode.java b/android/src/main/java/com/horcrux/svg/RNSVGPathShadowNode.java index c33f867d..c2c40498 100644 --- a/android/src/main/java/com/horcrux/svg/RNSVGPathShadowNode.java +++ b/android/src/main/java/com/horcrux/svg/RNSVGPathShadowNode.java @@ -53,6 +53,7 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode { private @Nullable float[] mFillColor; private @Nullable float[] mStrokeDash; private float mStrokeWidth = 1; + private float mStrokeDashoffset = 0; private int mStrokeLinecap = CAP_ROUND; private int mStrokeLinejoin = JOIN_ROUND; private int mFillRule = FILL_RULE_NONZERO; @@ -90,6 +91,13 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode { markUpdated(); } + @ReactProp(name = "strokeDashoffset", defaultFloat = 0f) + public void setStrokeDashoffset(float strokeWidth) { + mStrokeDashoffset = strokeWidth; + markUpdated(); + } + + @ReactProp(name = "fill") public void setFill(@Nullable ReadableArray fillColors) { mFillColor = PropHelper.toFloatArray(fillColors); @@ -222,8 +230,7 @@ public class RNSVGPathShadowNode extends RNSVGVirtualNode { setupPaint(paint, opacity, mStrokeColor); if (mStrokeDash != null && mStrokeDash.length > 0) { - // todo: dashoffset - paint.setPathEffect(new DashPathEffect(mStrokeDash, 0)); + paint.setPathEffect(new DashPathEffect(mStrokeDash, mStrokeDashoffset)); } return true; diff --git a/ios/RNSVGPath.m b/ios/RNSVGPath.m index a216d6c8..9f6e9867 100644 --- a/ios/RNSVGPath.m +++ b/ios/RNSVGPath.m @@ -59,9 +59,8 @@ CGContextSetLineJoin(context, self.strokeLinejoin); RNSVGCGFloatArray dash = self.strokeDash; - // TODO: render as web svgs do if (dash.count) { - CGContextSetLineDash(context, 0, dash.array, dash.count); + CGContextSetLineDash(context, self.strokeDashoffset, dash.array, dash.count); } if (!fillColor) { diff --git a/ios/RNSVGRenderable.h b/ios/RNSVGRenderable.h index 7acfd63a..c1664363 100644 --- a/ios/RNSVGRenderable.h +++ b/ios/RNSVGRenderable.h @@ -22,5 +22,6 @@ @property (nonatomic, assign) CGLineCap strokeLinecap; @property (nonatomic, assign) CGLineJoin strokeLinejoin; @property (nonatomic, assign) RNSVGCGFloatArray strokeDash; +@property (nonatomic, assign) CGFloat strokeDashoffset; @end diff --git a/ios/RNSVGRenderable.m b/ios/RNSVGRenderable.m index 3cdcfbda..a766abcb 100644 --- a/ios/RNSVGRenderable.m +++ b/ios/RNSVGRenderable.m @@ -52,6 +52,12 @@ _strokeDash = strokeDash; } +- (void)setStrokeDashoffset:(CGFloat)strokeDashoffset +{ + [self invalidate]; + _strokeDashoffset = strokeDashoffset; +} + - (void)dealloc { if (_strokeDash.array) { diff --git a/ios/RNSVGText.m b/ios/RNSVGText.m index 7f95f0a8..12ac6d13 100644 --- a/ios/RNSVGText.m +++ b/ios/RNSVGText.m @@ -84,8 +84,9 @@ static void RNSVGFreeTextFrame(RNSVGTextFrame frame) CGContextSetLineCap(context, self.strokeLinecap); CGContextSetLineJoin(context, self.strokeLinejoin); RNSVGCGFloatArray dash = self.strokeDash; + if (dash.count) { - CGContextSetLineDash(context, 0, dash.array, dash.count); + CGContextSetLineDash(context, self.strokeDashoffset, dash.array, dash.count); } if (![self.stroke applyStrokeColor:context]) { diff --git a/ios/ViewManagers/RNSVGRenderableManager.m b/ios/ViewManagers/RNSVGRenderableManager.m index e39591c6..9aeefa57 100644 --- a/ios/ViewManagers/RNSVGRenderableManager.m +++ b/ios/ViewManagers/RNSVGRenderableManager.m @@ -26,8 +26,9 @@ RCT_EXPORT_VIEW_PROPERTY(stroke, RNSVGBrush) RCT_EXPORT_VIEW_PROPERTY(strokeWidth, CGFloat) RCT_EXPORT_VIEW_PROPERTY(strokeLinecap, CGLineCap) RCT_EXPORT_VIEW_PROPERTY(strokeLinejoin, CGLineJoin) -RCT_EXPORT_VIEW_PROPERTY(strokeDash, RNSVGCGFloatArray) RCT_EXPORT_VIEW_PROPERTY(clipPath, CGPath) RCT_EXPORT_VIEW_PROPERTY(clipRule, RNSVGCGFCRule) +RCT_EXPORT_VIEW_PROPERTY(strokeDash, RNSVGCGFloatArray) +RCT_EXPORT_VIEW_PROPERTY(strokeDashoffset, CGFloat) @end diff --git a/lib/attributes.js b/lib/attributes.js index 4484ca0c..b447f75a 100644 --- a/lib/attributes.js +++ b/lib/attributes.js @@ -65,7 +65,8 @@ var RenderableAttributes = Object.assign({ fillRule: true, strokeDash: { diff: arrayDiffer - } + }, + strokeDashoffset: true }, NodeAttributes); var PathAttributes = Object.assign({ diff --git a/lib/extract/extractStroke.js b/lib/extract/extractStroke.js index 6e04be93..e8a0823a 100644 --- a/lib/extract/extractStroke.js +++ b/lib/extract/extractStroke.js @@ -45,12 +45,14 @@ function strokeFilter(props, dimensions) { strokeLinecap: caps[props.strokeLinecap] || 0, strokeLinejoin: joins[props.strokeLinejoin] || 0, strokeDash: strokeDasharray || null, - strokeWidth: strokeWidth || 1 + strokeWidth: strokeWidth || 1, + strokeDashoffset: strokeDasharray ? (+props.strokeDashoffset || 0) : null }; } export default function(props, dimensions) { let strokeProps = strokeFilter(props, dimensions); + return strokeProps ? { ...strokeProps, stroke: extractBrush(strokeProps.stroke, props)