mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-08-16 02:44:58 +00:00
Implement strokeDasharray correctly.
Support units and percentages with whitespace separated and/or (possibly white-space surrounded) comma separated length lists.
This commit is contained in:
@@ -20,34 +20,11 @@ import com.facebook.react.bridge.WritableMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Contains static helper methods for accessing props.
|
||||
*/
|
||||
class PropHelper {
|
||||
|
||||
/**
|
||||
* Converts {@link ReadableArray} to an array of {@code float}. Returns newly created array.
|
||||
*
|
||||
* @return a {@code float[]} if converted successfully, or {@code null} if {@param value} was
|
||||
* {@code null}.
|
||||
*/
|
||||
|
||||
static
|
||||
@Nullable
|
||||
float[] toFloatArray(@Nullable ReadableArray value) {
|
||||
if (value != null) {
|
||||
int fromSize = value.size();
|
||||
float[] into = new float[fromSize];
|
||||
for (int i = 0; i < fromSize; i++) {
|
||||
into[i] = (float) value.getDouble(i);
|
||||
}
|
||||
return into;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static final int inputMatrixDataSize = 6;
|
||||
|
||||
/**
|
||||
|
||||
@@ -53,7 +53,7 @@ abstract public class RenderableShadowNode extends VirtualNode {
|
||||
private static final int FILL_RULE_NONZERO = 1;
|
||||
|
||||
public @Nullable ReadableArray mStroke;
|
||||
public @Nullable float[] mStrokeDasharray;
|
||||
public @Nullable String[] mStrokeDasharray;
|
||||
|
||||
public String mStrokeWidth = "1";
|
||||
public float mStrokeOpacity = 1;
|
||||
@@ -117,12 +117,14 @@ abstract public class RenderableShadowNode extends VirtualNode {
|
||||
|
||||
@ReactProp(name = "strokeDasharray")
|
||||
public void setStrokeDasharray(@Nullable ReadableArray strokeDasharray) {
|
||||
|
||||
mStrokeDasharray = PropHelper.toFloatArray(strokeDasharray);
|
||||
if (mStrokeDasharray != null && mStrokeDasharray.length > 0) {
|
||||
for (int i = 0; i < mStrokeDasharray.length; i++) {
|
||||
mStrokeDasharray[i] = mStrokeDasharray[i] * mScale;
|
||||
if (strokeDasharray != null) {
|
||||
int fromSize = strokeDasharray.size();
|
||||
mStrokeDasharray = new String[fromSize];
|
||||
for (int i = 0; i < fromSize; i++) {
|
||||
mStrokeDasharray[i] = strokeDasharray.getString(i);
|
||||
}
|
||||
} else {
|
||||
mStrokeDasharray = null;
|
||||
}
|
||||
markUpdated();
|
||||
}
|
||||
@@ -249,8 +251,13 @@ abstract public class RenderableShadowNode extends VirtualNode {
|
||||
paint.setStrokeWidth((float) strokeWidth);
|
||||
setupPaint(paint, opacity, mStroke);
|
||||
|
||||
if (mStrokeDasharray != null && mStrokeDasharray.length > 0) {
|
||||
paint.setPathEffect(new DashPathEffect(mStrokeDasharray, mStrokeDashoffset));
|
||||
if (mStrokeDasharray != null) {
|
||||
int length = mStrokeDasharray.length;
|
||||
float[] intervals = new float[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
intervals[i] = (float)relativeOnOther(mStrokeDasharray[i]);
|
||||
}
|
||||
paint.setPathEffect(new DashPathEffect(intervals, mStrokeDashoffset));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
const spaceReg = /\s+/;
|
||||
const commaReg = /,/g;
|
||||
|
||||
export default function (lengthList) {
|
||||
if (typeof lengthList === 'string') {
|
||||
return lengthList.trim().replace(commaReg, ' ').split(spaceReg);
|
||||
} else if (typeof lengthList === 'number') {
|
||||
return [`${lengthList}`];
|
||||
} else if (lengthList && typeof lengthList.map === 'function') {
|
||||
return lengthList.map(d => `${d}`);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import extractBrush from './extractBrush';
|
||||
import extractOpacity from './extractOpacity';
|
||||
import {strokeProps} from '../props';
|
||||
|
||||
const separator = /\s*,\s*/;
|
||||
import extractLengthList from "./extractLengthList";
|
||||
|
||||
const caps = {
|
||||
butt: 0,
|
||||
@@ -26,21 +25,22 @@ export default function(props, styleProperties) {
|
||||
});
|
||||
|
||||
const {stroke} = props;
|
||||
let strokeWidth = props.strokeWidth;
|
||||
let strokeDasharray = props.strokeDasharray;
|
||||
let {
|
||||
strokeWidth,
|
||||
strokeDasharray
|
||||
} = props;
|
||||
|
||||
if (!strokeDasharray || strokeDasharray === 'none') {
|
||||
strokeDasharray = null;
|
||||
} else if (typeof strokeDasharray === 'string') {
|
||||
strokeDasharray = strokeDasharray.split(separator).map(dash => +dash);
|
||||
}
|
||||
|
||||
// <dasharray> It's a list of comma and/or white space separated <length>s
|
||||
// and <percentage>s that specify the lengths of alternating dashes and gaps.
|
||||
// If an odd number of values is provided, then the list of values is repeated
|
||||
// to yield an even number of values. Thus, 5,3,2 is equivalent to 5,3,2,5,3,2.
|
||||
if (strokeDasharray && (strokeDasharray.length % 2) === 1) {
|
||||
strokeDasharray.concat(strokeDasharray);
|
||||
} else {
|
||||
// <dasharray> It's a list of comma and/or white space separated <length>s
|
||||
// and <percentage>s that specify the lengths of alternating dashes and gaps.
|
||||
// If an odd number of values is provided, then the list of values is repeated
|
||||
// to yield an even number of values. Thus, 5,3,2 is equivalent to 5,3,2,5,3,2.
|
||||
strokeDasharray = extractLengthList(strokeDasharray);
|
||||
if (strokeDasharray && (strokeDasharray.length % 2) === 1) {
|
||||
strokeDasharray.concat(strokeDasharray);
|
||||
}
|
||||
}
|
||||
|
||||
if (!strokeWidth || typeof strokeWidth !== 'string') {
|
||||
|
||||
@@ -2,12 +2,12 @@ import _ from 'lodash';
|
||||
//noinspection JSUnresolvedVariable
|
||||
import React, {Children} from 'react';
|
||||
import TSpan from '../../elements/TSpan';
|
||||
import extractLengthList from './extractLengthList';
|
||||
|
||||
const fontRegExp = /^\s*((?:(?:normal|bold|italic)\s+)*)(?:(\d+(?:\.\d+)?[ptexm%])*(?:\s*\/.*?)?\s+)?\s*"?([^"]*)/i;
|
||||
const fontFamilyPrefix = /^[\s"']*/;
|
||||
const fontFamilySuffix = /[\s"']*$/;
|
||||
const spaceReg = /\s+/;
|
||||
const commaReg = /,/g;
|
||||
const commaReg = /\s*,\s*/g;
|
||||
|
||||
const cachedFontObjectsFromString = {};
|
||||
|
||||
@@ -85,18 +85,6 @@ export function extractFont(props) {
|
||||
return _.defaults(ownedFont, font);
|
||||
}
|
||||
|
||||
function parseSVGLengthList(delta) {
|
||||
if (typeof delta === 'string') {
|
||||
return delta.trim().replace(commaReg, ' ').split(spaceReg);
|
||||
} else if (typeof delta === 'number') {
|
||||
return [delta.toString()];
|
||||
} else if (delta && typeof delta.map === 'function') {
|
||||
return delta.map(d => `${d}`);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export default function(props, container) {
|
||||
const {
|
||||
x,
|
||||
@@ -110,11 +98,11 @@ export default function(props, container) {
|
||||
children
|
||||
} = props;
|
||||
|
||||
const positionX = parseSVGLengthList(x);
|
||||
const positionY = parseSVGLengthList(y);
|
||||
const deltaX = parseSVGLengthList(dx);
|
||||
const deltaY = parseSVGLengthList(dy);
|
||||
rotate = parseSVGLengthList(rotate);
|
||||
const positionX = extractLengthList(x);
|
||||
const positionY = extractLengthList(y);
|
||||
const deltaX = extractLengthList(dx);
|
||||
const deltaY = extractLengthList(dy);
|
||||
rotate = extractLengthList(rotate);
|
||||
|
||||
let content = null;
|
||||
if (typeof children === 'string' || typeof children === 'number') {
|
||||
|
||||
+1
-1
@@ -41,7 +41,7 @@ const strokeProps = {
|
||||
stroke: PropTypes.string,
|
||||
strokeWidth: numberProp,
|
||||
strokeOpacity: numberProp,
|
||||
strokeDasharray: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.string]),
|
||||
strokeDasharray: PropTypes.oneOfType([PropTypes.arrayOf(numberProp), PropTypes.string]),
|
||||
strokeDashoffset: numberProp,
|
||||
strokeLinecap: PropTypes.oneOf(['butt', 'square', 'round']),
|
||||
strokeLinejoin: PropTypes.oneOf(['miter', 'bevel', 'round']),
|
||||
|
||||
Reference in New Issue
Block a user