mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-01 14:15:03 +00:00
refactor shape elements add responder system.
refactor shape elements add responder system. Just iOS.
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Horcrux.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the MIT-style license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/*
|
||||
Erica Sadun, http://ericasadun.com
|
||||
iPhone Developer's Cookbook, 6.x Edition
|
||||
BSD License, Use at your own risk
|
||||
*/
|
||||
|
||||
#import "UIBezierPath-Points.h"
|
||||
|
||||
#define POINTSTRING(_CGPOINT_) (NSStringFromCGPoint(_CGPOINT_))
|
||||
#define VALUE(_INDEX_) [NSValue valueWithCGPoint:points[_INDEX_]]
|
||||
#define POINT(_INDEX_) [(NSValue *)[points objectAtIndex:_INDEX_] CGPointValue]
|
||||
|
||||
// Return distance between two points
|
||||
static float distance (CGPoint p1, CGPoint p2)
|
||||
{
|
||||
float dx = p2.x - p1.x;
|
||||
float dy = p2.y - p1.y;
|
||||
|
||||
return sqrt(dx*dx + dy*dy);
|
||||
}
|
||||
|
||||
@implementation UIBezierPath (Points)
|
||||
void getPointsFromBezier(void *info, const CGPathElement *element)
|
||||
{
|
||||
NSMutableArray *bezierPoints = (__bridge NSMutableArray *)info;
|
||||
CGPathElementType type = element->type;
|
||||
CGPoint *points = element->points;
|
||||
if (type != kCGPathElementCloseSubpath)
|
||||
{
|
||||
if ((type == kCGPathElementAddLineToPoint) ||
|
||||
(type == kCGPathElementMoveToPoint))
|
||||
[bezierPoints addObject:VALUE(0)];
|
||||
else if (type == kCGPathElementAddQuadCurveToPoint)
|
||||
[bezierPoints addObject:VALUE(1)];
|
||||
else if (type == kCGPathElementAddCurveToPoint)
|
||||
[bezierPoints addObject:VALUE(2)];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)points
|
||||
{
|
||||
NSMutableArray *points = [NSMutableArray array];
|
||||
CGPathApply(self.CGPath, (__bridge void *)points, getPointsFromBezier);
|
||||
return points;
|
||||
}
|
||||
|
||||
// Return a Bezier path buit with the supplied points
|
||||
+ (UIBezierPath *) pathWithPoints: (NSArray *) points
|
||||
{
|
||||
UIBezierPath *path = [UIBezierPath bezierPath];
|
||||
if (points.count == 0) return path;
|
||||
[path moveToPoint:POINT(0)];
|
||||
for (int i = 1; i < points.count; i++)
|
||||
[path addLineToPoint:POINT(i)];
|
||||
return path;
|
||||
}
|
||||
|
||||
- (CGFloat) length
|
||||
{
|
||||
NSArray *points = self.points;
|
||||
float totalPointLength = 0.0f;
|
||||
for (int i = 1; i < points.count; i++)
|
||||
totalPointLength += distance(POINT(i), POINT(i-1));
|
||||
return totalPointLength;
|
||||
}
|
||||
|
||||
- (NSArray *) pointPercentArray
|
||||
{
|
||||
// Use total length to calculate the percent of path consumed at each control point
|
||||
NSArray *points = self.points;
|
||||
int pointCount = points.count;
|
||||
|
||||
float totalPointLength = self.length;
|
||||
float distanceTravelled = 0.0f;
|
||||
|
||||
NSMutableArray *pointPercentArray = [NSMutableArray array];
|
||||
[pointPercentArray addObject:@(0.0)];
|
||||
|
||||
for (int i = 1; i < pointCount; i++)
|
||||
{
|
||||
distanceTravelled += distance(POINT(i), POINT(i-1));
|
||||
[pointPercentArray addObject:@(distanceTravelled / totalPointLength)];
|
||||
}
|
||||
|
||||
// Add a final item just to stop with. Probably not needed.
|
||||
[pointPercentArray addObject:[NSNumber numberWithFloat:1.1f]]; // 110%
|
||||
|
||||
return pointPercentArray;
|
||||
}
|
||||
|
||||
- (CGPoint) pointAtPercent: (CGFloat) percent withSlope: (CGPoint *) slope
|
||||
{
|
||||
NSArray *points = self.points;
|
||||
NSArray *percentArray = self.pointPercentArray;
|
||||
CFIndex lastPointIndex = points.count - 1;
|
||||
|
||||
if (!points.count) {
|
||||
return CGPointZero;
|
||||
}
|
||||
|
||||
// Check for 0% and 100%
|
||||
if (percent <= 0.0f) {
|
||||
return POINT(0);
|
||||
}
|
||||
if (percent >= 1.0f) {
|
||||
return POINT(lastPointIndex);
|
||||
}
|
||||
|
||||
// Find a corresponding pair of points in the path
|
||||
CFIndex index = 1;
|
||||
while ((index < percentArray.count) &&
|
||||
(percent > ((NSNumber *)percentArray[index]).floatValue)) {
|
||||
index++;
|
||||
}
|
||||
|
||||
// This should not happen.
|
||||
if (index > lastPointIndex) {
|
||||
return POINT(lastPointIndex);
|
||||
}
|
||||
|
||||
// Calculate the intermediate distance between the two points
|
||||
CGPoint point1 = POINT(index -1);
|
||||
CGPoint point2 = POINT(index);
|
||||
|
||||
float percent1 = [[percentArray objectAtIndex:index - 1] floatValue];
|
||||
float percent2 = [[percentArray objectAtIndex:index] floatValue];
|
||||
float percentOffset = (percent - percent1) / (percent2 - percent1);
|
||||
|
||||
float dx = point2.x - point1.x;
|
||||
float dy = point2.y - point1.y;
|
||||
|
||||
// Store dy, dx for retrieving arctan
|
||||
if (slope) {
|
||||
*slope = CGPointMake(dx, dy);
|
||||
}
|
||||
|
||||
// Calculate new point
|
||||
CGFloat newX = point1.x + (percentOffset * dx);
|
||||
CGFloat newY = point1.y + (percentOffset * dy);
|
||||
CGPoint targetPoint = CGPointMake(newX, newY);
|
||||
|
||||
return targetPoint;
|
||||
}
|
||||
|
||||
void getBezierElements(void *info, const CGPathElement *element)
|
||||
{
|
||||
NSMutableArray *bezierElements = (__bridge NSMutableArray *)info;
|
||||
CGPathElementType type = element->type;
|
||||
CGPoint *points = element->points;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case kCGPathElementCloseSubpath:
|
||||
[bezierElements addObject:@[@(type)]];
|
||||
break;
|
||||
case kCGPathElementMoveToPoint:
|
||||
case kCGPathElementAddLineToPoint:
|
||||
[bezierElements addObject:@[@(type), VALUE(0)]];
|
||||
break;
|
||||
case kCGPathElementAddQuadCurveToPoint:
|
||||
[bezierElements addObject:@[@(type), VALUE(0), VALUE(1)]];
|
||||
break;
|
||||
case kCGPathElementAddCurveToPoint:
|
||||
[bezierElements addObject:@[@(type), VALUE(0), VALUE(1), VALUE(2)]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *) bezierElements
|
||||
{
|
||||
NSMutableArray *elements = [NSMutableArray array];
|
||||
CGPathApply(self.CGPath, (__bridge void *)elements, getBezierElements);
|
||||
return elements;
|
||||
}
|
||||
|
||||
+ (UIBezierPath *) pathWithElements: (NSArray *) elements
|
||||
{
|
||||
UIBezierPath *path = [UIBezierPath bezierPath];
|
||||
if (elements.count == 0) return path;
|
||||
|
||||
for (NSArray *points in elements)
|
||||
{
|
||||
if (!points.count) continue;
|
||||
CGPathElementType elementType = [points[0] integerValue];
|
||||
switch (elementType)
|
||||
{
|
||||
case kCGPathElementCloseSubpath:
|
||||
[path closePath];
|
||||
break;
|
||||
case kCGPathElementMoveToPoint:
|
||||
if (points.count == 2)
|
||||
[path moveToPoint:POINT(1)];
|
||||
break;
|
||||
case kCGPathElementAddLineToPoint:
|
||||
if (points.count == 2)
|
||||
[path addLineToPoint:POINT(1)];
|
||||
break;
|
||||
case kCGPathElementAddQuadCurveToPoint:
|
||||
if (points.count == 3)
|
||||
[path addQuadCurveToPoint:POINT(2) controlPoint:POINT(1)];
|
||||
break;
|
||||
case kCGPathElementAddCurveToPoint:
|
||||
if (points.count == 4)
|
||||
[path addCurveToPoint:POINT(3) controlPoint1:POINT(1) controlPoint2:POINT(2)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
@end
|
||||
Reference in New Issue
Block a user