mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-20 14:05:09 +00:00
complete percentage coords refactor on ios
This commit is contained in:
@@ -12,7 +12,7 @@ import insertColorStopsIntoArray from '../lib/insertProcessor';
|
|||||||
|
|
||||||
function RadialGradientGenerator(stops, fx, fy, rx, ry, cx, cy) {
|
function RadialGradientGenerator(stops, fx, fy, rx, ry, cx, cy) {
|
||||||
var brushData = [RADIAL_GRADIENT, 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;
|
this._brush = brushData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
@interface RNSVGBrush : NSObject
|
@interface RNSVGBrush : NSObject
|
||||||
|
{
|
||||||
|
NSArray *_points;
|
||||||
|
}
|
||||||
|
|
||||||
/* @abstract */
|
/* @abstract */
|
||||||
- (instancetype)initWithArray:(NSArray *)data NS_DESIGNATED_INITIALIZER;
|
- (instancetype)initWithArray:(NSArray *)data NS_DESIGNATED_INITIALIZER;
|
||||||
@@ -26,6 +29,8 @@
|
|||||||
|
|
||||||
- (BOOL)applyStrokeColor:(CGContextRef)context;
|
- (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
|
* paint fills the context with a brush. The context is assumed to
|
||||||
* be clipped.
|
* be clipped.
|
||||||
|
|||||||
@@ -29,6 +29,30 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||||||
return NO;
|
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
|
- (void)paint:(CGContextRef)context
|
||||||
{
|
{
|
||||||
// abstract
|
// abstract
|
||||||
|
|||||||
@@ -13,36 +13,47 @@
|
|||||||
|
|
||||||
@implementation RNSVGLinearGradient
|
@implementation RNSVGLinearGradient
|
||||||
{
|
{
|
||||||
CGGradientRef _gradient;
|
CGGradientRef _gradient;
|
||||||
CGPoint _startPoint;
|
|
||||||
CGPoint _endPoint;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithArray:(NSArray<NSNumber *> *)array
|
- (instancetype)initWithArray:(NSArray *)array
|
||||||
{
|
{
|
||||||
if ((self = [super initWithArray:array])) {
|
if ((self = [super initWithArray:array])) {
|
||||||
if (array.count < 5) {
|
if (array.count < 5) {
|
||||||
RCTLogError(@"-[%@ %@] expects 5 elements, received %@",
|
RCTLogError(@"-[%@ %@] expects 5 elements, received %@",
|
||||||
self.class, NSStringFromSelector(_cmd), array);
|
self.class, NSStringFromSelector(_cmd), array);
|
||||||
return nil;
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
_points = [array subarrayWithRange:NSMakeRange(1, 4)];
|
||||||
|
_gradient = CGGradientRetain([RCTConvert CGGradient:array offset:5]);
|
||||||
}
|
}
|
||||||
_startPoint = [RCTConvert CGPoint:array offset:1];
|
return self;
|
||||||
_endPoint = [RCTConvert CGPoint:array offset:3];
|
|
||||||
_gradient = CGGradientRetain([RCTConvert CGGradient:array offset:5]);
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
CGGradientRelease(_gradient);
|
CGGradientRelease(_gradient);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)paint:(CGContextRef)context
|
- (void)paint:(CGContextRef)context
|
||||||
{
|
{
|
||||||
CGGradientDrawingOptions extendOptions =
|
CGGradientDrawingOptions extendOptions =
|
||||||
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
|
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
|
@end
|
||||||
|
|||||||
@@ -13,43 +13,65 @@
|
|||||||
|
|
||||||
@implementation RNSVGRadialGradient
|
@implementation RNSVGRadialGradient
|
||||||
{
|
{
|
||||||
CGGradientRef _gradient;
|
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 ((self = [super initWithArray:array])) {
|
||||||
if (array.count < 7) {
|
if (array.count < 7) {
|
||||||
RCTLogError(@"-[%@ %@] expects 7 elements, received %@",
|
RCTLogError(@"-[%@ %@] expects 7 elements, received %@",
|
||||||
self.class, NSStringFromSelector(_cmd), array);
|
self.class, NSStringFromSelector(_cmd), array);
|
||||||
return nil;
|
return nil;
|
||||||
|
}
|
||||||
|
_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]);
|
||||||
}
|
}
|
||||||
_radius = [RCTConvert CGFloat:array[3]];
|
return self;
|
||||||
_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]);
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
- (void)dealloc
|
||||||
{
|
{
|
||||||
CGGradientRelease(_gradient);
|
CGGradientRelease(_gradient);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)paint:(CGContextRef)context
|
- (void)paint:(CGContextRef)context
|
||||||
{
|
{
|
||||||
CGAffineTransform transform = CGAffineTransformMakeScale(1, _radiusRatio);
|
|
||||||
CGContextConcatCTM(context, transform);
|
CGRect box = CGContextGetClipBoundingBox(context);
|
||||||
CGGradientDrawingOptions extendOptions = kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation;
|
float height = CGRectGetHeight(box);
|
||||||
CGContextDrawRadialGradient(context, _gradient, _focusPoint, 0, _centerPoint, _radius, extendOptions);
|
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, CGPointMake(fx, fy), 0, CGPointMake(cx, cy), rx, extendOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -161,6 +161,8 @@ RCT_ENUM_CONVERTER(RNSVGCGFCRule, (@{
|
|||||||
case 2: // radial gradient
|
case 2: // radial gradient
|
||||||
return [[RNSVGRadialGradient alloc] initWithArray:arr];
|
return [[RNSVGRadialGradient alloc] initWithArray:arr];
|
||||||
case 3: // pattern
|
case 3: // pattern
|
||||||
|
// TODO:
|
||||||
|
return nil;
|
||||||
return [[RNSVGPattern alloc] initWithArray:arr];
|
return [[RNSVGPattern alloc] initWithArray:arr];
|
||||||
default:
|
default:
|
||||||
RCTLogError(@"Unknown brush type: %zd", type);
|
RCTLogError(@"Unknown brush type: %zd", type);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
CGFloat cx = [self getActualProp:@"cx" relative:width];
|
CGFloat cx = [self getActualProp:@"cx" relative:width];
|
||||||
CGFloat cy = [self getActualProp:@"cy" relative:height];
|
CGFloat cy = [self getActualProp:@"cy" relative:height];
|
||||||
CGFloat r = [self getActualProp:@"r" 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;
|
break;
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ function insertColorIntoArray(color, targetArray, atIndex) {
|
|||||||
|
|
||||||
function insertColorsIntoArray(stops, targetArray, atIndex) {
|
function insertColorsIntoArray(stops, targetArray, atIndex) {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
if ('length' in stops) {
|
if ('length' in stops) {
|
||||||
while (i < stops.length) {
|
while (i < stops.length) {
|
||||||
insertColorIntoArray(stops[i], targetArray, atIndex + i * 4);
|
insertColorIntoArray(stops[i], targetArray, atIndex + i * 4);
|
||||||
@@ -28,27 +27,28 @@ function insertColorsIntoArray(stops, targetArray, atIndex) {
|
|||||||
return atIndex + i * 4;
|
return atIndex + i * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertColorStopsIntoArray(stops, targetArray, atIndex, multi = 1) {
|
function insertColorStopsIntoArray(stops, targetArray, atIndex) {
|
||||||
let lastIndex = insertColorsIntoArray(stops, targetArray, atIndex, false);
|
let lastIndex = insertColorsIntoArray(stops, targetArray, atIndex);
|
||||||
insertOffsetsIntoArray(stops, targetArray, lastIndex, multi, false);
|
insertOffsetsIntoArray(stops, targetArray, lastIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertOffsetsIntoArray(stops, targetArray, atIndex, multi) {
|
function insertOffsetsIntoArray(stops, targetArray, atIndex) {
|
||||||
let offsetNumber;
|
let offsetNumber;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let arr = [];
|
let arr = [];
|
||||||
if ('length' in stops) {
|
if ('length' in stops) {
|
||||||
while (i < stops.length) {
|
while (i < stops.length) {
|
||||||
offsetNumber = i / (stops.length - 1) * multi;
|
offsetNumber = i / (stops.length - 1);
|
||||||
targetArray[atIndex + i] = offsetNumber;
|
targetArray[atIndex + i] = offsetNumber;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_.forEach(stops, (stop, offsetString) => {
|
_.forEach(stops, (stop, offsetString) => {
|
||||||
offsetNumber = (+offsetString) * multi;
|
offsetNumber = (+offsetString);
|
||||||
arr.push(offsetNumber);
|
arr.push(offsetNumber);
|
||||||
i++;
|
i++;
|
||||||
});
|
});
|
||||||
|
|
||||||
arr.sort();
|
arr.sort();
|
||||||
targetArray.splice(atIndex, 0, ...arr);
|
targetArray.splice(atIndex, 0, ...arr);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user