complete percentage coords refactor on ios

This commit is contained in:
Horcrux
2016-04-27 10:48:49 +08:00
parent 3ee04dbaed
commit cd77525a7b
8 changed files with 115 additions and 51 deletions

View File

@@ -12,7 +12,7 @@ import insertColorStopsIntoArray from '../lib/insertProcessor';
function RadialGradientGenerator(stops, fx, fy, rx, ry, cx, cy) {
var brushData = [RADIAL_GRADIENT, fx, fy, rx, ry, cx, cy];
insertColorStopsIntoArray(stops, brushData, 7, 0.5);
insertColorStopsIntoArray(stops, brushData, 7);
this._brush = brushData;
}

View File

@@ -10,6 +10,9 @@
#import <Foundation/Foundation.h>
@interface RNSVGBrush : NSObject
{
NSArray *_points;
}
/* @abstract */
- (instancetype)initWithArray:(NSArray *)data NS_DESIGNATED_INITIALIZER;
@@ -26,6 +29,8 @@
- (BOOL)applyStrokeColor:(CGContextRef)context;
- (CGFloat)getActualProp:(int)percent relative:(CGFloat)relative offset:(CGFloat)offset;
/**
* paint fills the context with a brush. The context is assumed to
* be clipped.

View File

@@ -29,6 +29,30 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
return NO;
}
- (CGFloat)getActualProp:(int)index relative:(CGFloat)relative offset:(CGFloat)offset
{
id coord = [_points objectAtIndex:index];
if ([coord isKindOfClass:[NSString class]]) {
__block float matched = [coord floatValue];
NSString *percentage = (NSString *)coord;
NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:@"^(\\-?\\d+(?:\\.\\d+)?)%$" options:0 error:NULL];
[regex enumerateMatchesInString:percentage
options:0
range:NSMakeRange(0, percentage.length)
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop)
{
matched = [[percentage substringWithRange:NSMakeRange(result.range.location, result.range.length)] floatValue];
matched = matched / 100 * relative + offset;
}];
return matched;
} else {
return [coord floatValue];
}
}
- (void)paint:(CGContextRef)context
{
// abstract

View File

@@ -14,11 +14,9 @@
@implementation RNSVGLinearGradient
{
CGGradientRef _gradient;
CGPoint _startPoint;
CGPoint _endPoint;
}
- (instancetype)initWithArray:(NSArray<NSNumber *> *)array
- (instancetype)initWithArray:(NSArray *)array
{
if ((self = [super initWithArray:array])) {
if (array.count < 5) {
@@ -26,8 +24,8 @@
self.class, NSStringFromSelector(_cmd), array);
return nil;
}
_startPoint = [RCTConvert CGPoint:array offset:1];
_endPoint = [RCTConvert CGPoint:array offset:3];
_points = [array subarrayWithRange:NSMakeRange(1, 4)];
_gradient = CGGradientRetain([RCTConvert CGGradient:array offset:5]);
}
return self;
@@ -42,7 +40,20 @@
{
CGGradientDrawingOptions extendOptions =
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
CGContextDrawLinearGradient(context, _gradient, _startPoint, _endPoint, extendOptions);
CGRect box = CGContextGetClipBoundingBox(context);
float height = CGRectGetHeight(box);
float width = CGRectGetWidth(box);
float midX = CGRectGetMidX(box);
float midY = CGRectGetMidY(box);
float offsetX = (midX - width / 2);
float offsetY = (midY - height / 2);
CGFloat x1 = [self getActualProp:0 relative:width offset:offsetX];
CGFloat y1 = [self getActualProp:1 relative:height offset:offsetY];
CGFloat x2 = [self getActualProp:2 relative:width offset:offsetX];
CGFloat y2 = [self getActualProp:3 relative:height offset:offsetY];
CGContextDrawLinearGradient(context, _gradient, CGPointMake(x1, y1), CGPointMake(x2, y2), extendOptions);
}
@end

View File

@@ -14,13 +14,9 @@
@implementation RNSVGRadialGradient
{
CGGradientRef _gradient;
CGPoint _focusPoint;
CGPoint _centerPoint;
CGFloat _radius;
CGFloat _radiusRatio;
}
- (instancetype)initWithArray:(NSArray<NSNumber *> *)array
- (instancetype)initWithArray:(NSArray *)array
{
if ((self = [super initWithArray:array])) {
if (array.count < 7) {
@@ -28,13 +24,23 @@
self.class, NSStringFromSelector(_cmd), array);
return nil;
}
_radius = [RCTConvert CGFloat:array[3]];
_radiusRatio = [RCTConvert CGFloat:array[4]] / _radius;
_focusPoint.x = [RCTConvert CGFloat:array[1]];
_focusPoint.y = [RCTConvert CGFloat:array[2]] / _radiusRatio;
_centerPoint.x = [RCTConvert CGFloat:array[5]];
_centerPoint.y = [RCTConvert CGFloat:array[6]] / _radiusRatio;
_gradient = CGGradientRetain([RCTConvert CGGradient:array offset:7]);
_points = [array subarrayWithRange:NSMakeRange(1, 6)];
NSMutableArray *gradient = [[NSMutableArray alloc] init];
int count = ([array count] - 7) / 5;
int startStops = [array count] - count;
for (int i = 0; i < count; i++) {
[gradient insertObject:[array objectAtIndex:(i * 4 + 7)] atIndex:(i * 4)];
[gradient insertObject:[array objectAtIndex:(i * 4 + 8)] atIndex:(i * 4 + 1)];
[gradient insertObject:[array objectAtIndex:(i * 4 + 9)] atIndex:(i * 4 + 2)];
[gradient insertObject:[array objectAtIndex:(i * 4 + 10)] atIndex:(i * 4 + 3)];
NSNumber *stop = [NSNumber numberWithFloat:[[array objectAtIndex:(startStops + (count - i - 1))] floatValue]];
[gradient insertObject:stop atIndex:i * 4 + 4];
}
_gradient = CGGradientRetain([RCTConvert CGGradient:gradient offset:0]);
}
return self;
}
@@ -46,10 +52,26 @@
- (void)paint:(CGContextRef)context
{
CGAffineTransform transform = CGAffineTransformMakeScale(1, _radiusRatio);
CGRect box = CGContextGetClipBoundingBox(context);
float height = CGRectGetHeight(box);
float width = CGRectGetWidth(box);
float midX = CGRectGetMidX(box);
float midY = CGRectGetMidY(box);
float offsetX = (midX - width / 2);
float offsetY = (midY - height / 2);
CGFloat rx = [self getActualProp:2 relative:width offset:0];
CGFloat ry = [self getActualProp:3 relative:height offset:0];
CGFloat fx = [self getActualProp:0 relative:width offset:offsetX];
CGFloat fy = [self getActualProp:1 relative:height offset:offsetY] / (ry / rx); // fx == fy
CGFloat cx = [self getActualProp:4 relative:width offset:offsetX];
CGFloat cy = [self getActualProp:5 relative:height offset:offsetY] / (ry / rx); // rx == ry
CGAffineTransform transform = CGAffineTransformMakeScale(1, ry / rx);
CGContextConcatCTM(context, transform);
CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
CGContextDrawRadialGradient(context, _gradient, _focusPoint, 0, _centerPoint, _radius, extendOptions);
CGContextDrawRadialGradient(context, _gradient, CGPointMake(fx, fy), 0, CGPointMake(cx, cy), rx, extendOptions);
}
@end

View File

@@ -161,6 +161,8 @@ RCT_ENUM_CONVERTER(RNSVGCGFCRule, (@{
case 2: // radial gradient
return [[RNSVGRadialGradient alloc] initWithArray:arr];
case 3: // pattern
// TODO:
return nil;
return [[RNSVGPattern alloc] initWithArray:arr];
default:
RCTLogError(@"Unknown brush type: %zd", type);

View File

@@ -31,7 +31,7 @@
CGFloat cx = [self getActualProp:@"cx" relative:width];
CGFloat cy = [self getActualProp:@"cy" relative:height];
CGFloat r = [self getActualProp:@"r" relative:height];
CGPathAddArc(path, nil, cx, cy, r, 0, 2*M_PI, YES);
CGPathAddArc(path, nil, cx, cy, r, -M_PI, M_PI, YES);
break;
}
case 1:

View File

@@ -11,7 +11,6 @@ function insertColorIntoArray(color, targetArray, atIndex) {
function insertColorsIntoArray(stops, targetArray, atIndex) {
let i = 0;
if ('length' in stops) {
while (i < stops.length) {
insertColorIntoArray(stops[i], targetArray, atIndex + i * 4);
@@ -28,27 +27,28 @@ function insertColorsIntoArray(stops, targetArray, atIndex) {
return atIndex + i * 4;
}
function insertColorStopsIntoArray(stops, targetArray, atIndex, multi = 1) {
let lastIndex = insertColorsIntoArray(stops, targetArray, atIndex, false);
insertOffsetsIntoArray(stops, targetArray, lastIndex, multi, false);
function insertColorStopsIntoArray(stops, targetArray, atIndex) {
let lastIndex = insertColorsIntoArray(stops, targetArray, atIndex);
insertOffsetsIntoArray(stops, targetArray, lastIndex);
}
function insertOffsetsIntoArray(stops, targetArray, atIndex, multi) {
function insertOffsetsIntoArray(stops, targetArray, atIndex) {
let offsetNumber;
let i = 0;
let arr = [];
if ('length' in stops) {
while (i < stops.length) {
offsetNumber = i / (stops.length - 1) * multi;
offsetNumber = i / (stops.length - 1);
targetArray[atIndex + i] = offsetNumber;
i++;
}
} else {
_.forEach(stops, (stop, offsetString) => {
offsetNumber = (+offsetString) * multi;
offsetNumber = (+offsetString);
arr.push(offsetNumber);
i++;
});
arr.sort();
targetArray.splice(atIndex, 0, ...arr);
}