Skip to content

Commit

Permalink
feat(ios): implement marker rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
msand committed Sep 29, 2019
1 parent 61533c6 commit 589363d
Show file tree
Hide file tree
Showing 7 changed files with 291 additions and 18 deletions.
7 changes: 5 additions & 2 deletions ios/Elements/RNSVGMarker.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@

#import "RNSVGGroup.h"
#import "RNSVGLength.h"
#import "RNSVGMarkerPosition.h"

@interface RNSVGMarker : RNSVGGroup

@property (nonatomic, strong) RNSVGLength *refX;
@property (nonatomic, strong) RNSVGLength *refY;
@property (nonatomic, strong) RNSVGLength *markerWidth;
@property (nonatomic, strong) RNSVGLength *markerHeight;
@property (nonatomic, assign) NSString *markerUnits;
@property (nonatomic, assign) NSString *orient;
@property (nonatomic, strong) NSString *markerUnits;
@property (nonatomic, strong) NSString *orient;

@property (nonatomic, assign) CGFloat minX;
@property (nonatomic, assign) CGFloat minY;
Expand All @@ -18,4 +19,6 @@
@property (nonatomic, strong) NSString *align;
@property (nonatomic, assign) RNSVGVBMOS meetOrSlice;

- (void)renderMarker:(CGContextRef)context rect:(CGRect)rect position:(RNSVGMarkerPosition*)position strokeWidth:(CGFloat)strokeWidth;

@end
70 changes: 57 additions & 13 deletions ios/Elements/RNSVGMarker.m
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#import "RNSVGPainter.h"
#import "RNSVGBrushType.h"
#import "RNSVGNode.h"
#import "RNSVGViewBox.h"

@implementation RNSVGMarker

Expand All @@ -21,14 +22,20 @@ - (void)parseReference
{
self.dirty = false;
[self.svgView defineMarker:self markerName:self.name];
[self traverseSubviews:^(RNSVGNode *node) {
if ([node isKindOfClass:[RNSVGNode class]]) {
[node parseReference];
}
return YES;
}];
}

- (void)setX:(RNSVGLength *)refX
{
if ([refX isEqualTo:_refX]) {
return;
}

_refX = refX;
[self invalidate];
}
Expand All @@ -38,7 +45,7 @@ - (void)setY:(RNSVGLength *)refY
if ([refY isEqualTo:_refY]) {
return;
}

_refY = refY;
[self invalidate];
}
Expand All @@ -48,7 +55,7 @@ - (void)setMarkerWidth:(RNSVGLength *)markerWidth
if ([markerWidth isEqualTo:_markerWidth]) {
return;
}

_markerWidth = markerWidth;
[self invalidate];
}
Expand All @@ -58,17 +65,17 @@ - (void)setMarkerHeight:(RNSVGLength *)markerHeight
if ([markerHeight isEqualTo:_markerHeight]) {
return;
}

_markerHeight = markerHeight;
[self invalidate];
}

- (void)setMarkerUnits:(NSString *)markerUnits
{
if (markerUnits == _markerUnits) {
if ([_markerUnits isEqualToString:markerUnits]) {
return;
}

_markerUnits = markerUnits;
[self invalidate];
}
Expand All @@ -78,7 +85,7 @@ - (void)setOrient:(NSString *)orient
if ([orient isEqualToString:_orient]) {
return;
}

[self invalidate];
_orient = orient;
}
Expand All @@ -88,7 +95,7 @@ - (void)setMinX:(CGFloat)minX
if (minX == _minX) {
return;
}

[self invalidate];
_minX = minX;
}
Expand All @@ -98,7 +105,7 @@ - (void)setMinY:(CGFloat)minY
if (minY == _minY) {
return;
}

[self invalidate];
_minY = minY;
}
Expand All @@ -108,7 +115,7 @@ - (void)setVbWidth:(CGFloat)vbWidth
if (vbWidth == _vbWidth) {
return;
}

[self invalidate];
_vbWidth = vbWidth;
}
Expand All @@ -118,7 +125,7 @@ - (void)setVbHeight:(CGFloat)vbHeight
if (_vbHeight == vbHeight) {
return;
}

[self invalidate];
_vbHeight = vbHeight;
}
Expand All @@ -128,7 +135,7 @@ - (void)setAlign:(NSString *)align
if ([align isEqualToString:_align]) {
return;
}

[self invalidate];
_align = align;
}
Expand All @@ -138,10 +145,47 @@ - (void)setMeetOrSlice:(RNSVGVBMOS)meetOrSlice
if (meetOrSlice == _meetOrSlice) {
return;
}

[self invalidate];
_meetOrSlice = meetOrSlice;
}

- (void)renderMarker:(CGContextRef)context rect:(CGRect)rect position:(RNSVGMarkerPosition*)position strokeWidth:(CGFloat)strokeWidth
{
CGContextSaveGState(context);

CGPoint origin = [position origin];
CGAffineTransform transform = CGAffineTransformMakeTranslation(origin.x, origin.y);

float markerAngle = [@"auto" isEqualToString:_orient] ? -1 : [_orient doubleValue];
transform = CGAffineTransformRotate(transform, markerAngle == -1 ? [position angle] : markerAngle);

bool useStrokeWidth = [@"strokeWidth" isEqualToString:_markerUnits];
if (useStrokeWidth) {
transform = CGAffineTransformScale(transform, strokeWidth, strokeWidth);
}

CGContextConcatCTM(context, transform);

CGFloat width = [self relativeOnWidth:self.markerWidth];
CGFloat height = [self relativeOnHeight:self.markerHeight];
CGRect eRect = CGRectMake(0, 0, width, height);
if (self.align) {
CGAffineTransform viewBoxTransform = [RNSVGViewBox getTransform:CGRectMake(self.minX, self.minY, self.vbWidth, self.vbHeight)
eRect:eRect
align:self.align
meetOrSlice:self.meetOrSlice];
CGContextConcatCTM(context, viewBoxTransform);
}

CGFloat x = [self relativeOnWidth:self.refX];
CGFloat y = [self relativeOnHeight:self.refY];
CGContextTranslateCTM(context, -x, -y);

[self renderGroupTo:context rect:eRect];

CGContextRestoreGState(context);
}

@end

1 change: 1 addition & 0 deletions ios/RNSVGNode.m
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ - (instancetype)init
{
if (self = [super init]) {
self.opacity = 1;
self.matrix = CGAffineTransformIdentity;
self.transforms = CGAffineTransformIdentity;
self.invTransform = CGAffineTransformIdentity;
_merging = false;
Expand Down
34 changes: 34 additions & 0 deletions ios/RNSVGRenderable.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#import "RNSVGMask.h"
#import "RNSVGViewBox.h"
#import "RNSVGVectorEffect.h"
#import "RNSVGBezierElement.h"
#import "RNSVGMarker.h"
#import "RNSVGMarkerPosition.h"

@implementation RNSVGRenderable
{
Expand Down Expand Up @@ -277,6 +280,8 @@ - (void)renderTo:(CGContextRef)context rect:(CGRect)rect
[self endTransparencyLayer:context];

CGContextRestoreGState(context);

[self renderMarkers:context path:self.path rect:&rect];
}

- (void)prepareStrokeDash:(NSUInteger)count strokeDasharray:(NSArray<RNSVGLength *> *)strokeDasharray {
Expand All @@ -294,6 +299,35 @@ - (void)prepareStrokeDash:(NSUInteger)count strokeDasharray:(NSArray<RNSVGLength
}
}

- (void)renderMarkers:(CGContextRef)context path:(CGPathRef)path rect:(const CGRect *)rect {
RNSVGMarker *markerStart = (RNSVGMarker*)[self.svgView getDefinedMarker:self.markerStart];
RNSVGMarker *markerMid = (RNSVGMarker*)[self.svgView getDefinedMarker:self.markerMid];
RNSVGMarker *markerEnd = (RNSVGMarker*)[self.svgView getDefinedMarker:self.markerEnd];
if (markerStart || markerMid || markerEnd) {
NSArray<RNSVGMarkerPosition*>* positions = [RNSVGMarkerPosition fromCGPath:path];
CGFloat width = self.strokeWidth ? [self relativeOnOther:self.strokeWidth] : 1;
for (RNSVGMarkerPosition* position in positions) {
RNSVGMarkerType type = [position type];
switch (type) {
case kStartMarker:
[markerStart renderMarker:context rect:*rect position:position strokeWidth:width];
break;

case kMidMarker:
[markerMid renderMarker:context rect:*rect position:position strokeWidth:width];
break;

case kEndMarker:
[markerEnd renderMarker:context rect:*rect position:position strokeWidth:width];
break;

default:
break;
}
}
}
}

- (void)renderLayerTo:(CGContextRef)context rect:(CGRect)rect
{
CGPathRef path = self.path;
Expand Down
25 changes: 25 additions & 0 deletions ios/Utils/RNSVGMarkerPosition.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

typedef enum RNSVGMarkerType {
kStartMarker,
kMidMarker,
kEndMarker
} RNSVGMarkerType;

#define RNSVGNULLPOINT CGRectNull.origin

@interface RNSVGMarkerPosition : NSObject

// Element storage
@property (nonatomic, assign) RNSVGMarkerType type;
@property (nonatomic, assign) CGPoint origin;
@property (nonatomic, assign) float angle;

// Instance creation
+ (instancetype) markerPosition:(RNSVGMarkerType)type origin:(CGPoint)origin angle:(float)angle;

+ (NSArray<RNSVGMarkerPosition*>*) fromCGPath:(CGPathRef)path;

@end

0 comments on commit 589363d

Please sign in to comment.