mirror of
https://github.com/zoriya/react-native-svg.git
synced 2025-12-20 22:05:14 +00:00
Implement support for em in dx and dy attributes and font props for G element
This commit is contained in:
@@ -53,6 +53,24 @@ public class GlyphContext {
|
|||||||
mYContext = new ArrayList<>();
|
mYContext = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void pushContext(@Nullable ReadableMap font) {
|
||||||
|
PointF location = mCurrentLocation;
|
||||||
|
|
||||||
|
mDeltaContext.add(mCurrentDelta);
|
||||||
|
|
||||||
|
mCurrentDelta = clonePointF(mCurrentDelta);
|
||||||
|
|
||||||
|
mLocationContext.add(location);
|
||||||
|
mFontContext.add(font);
|
||||||
|
mDeltaXContext.add(new ArrayList<Float>());
|
||||||
|
mDeltaYContext.add(new ArrayList<Float>());
|
||||||
|
mXContext.add(location.x);
|
||||||
|
mYContext.add(location.y);
|
||||||
|
|
||||||
|
mCurrentLocation = clonePointF(location);
|
||||||
|
mContextLength++;
|
||||||
|
}
|
||||||
|
|
||||||
public void pushContext(@Nullable ReadableMap font, @Nullable ReadableArray deltaX, @Nullable ReadableArray deltaY, @Nullable String positionX, @Nullable String positionY) {
|
public void pushContext(@Nullable ReadableMap font, @Nullable ReadableArray deltaX, @Nullable ReadableArray deltaY, @Nullable String positionX, @Nullable String positionY) {
|
||||||
PointF location = mCurrentLocation;
|
PointF location = mCurrentLocation;
|
||||||
|
|
||||||
@@ -194,10 +212,21 @@ public class GlyphContext {
|
|||||||
|
|
||||||
private ArrayList<Float> getFloatArrayListFromReadableArray(ReadableArray readableArray) {
|
private ArrayList<Float> getFloatArrayListFromReadableArray(ReadableArray readableArray) {
|
||||||
ArrayList<Float> arrayList = new ArrayList<>();
|
ArrayList<Float> arrayList = new ArrayList<>();
|
||||||
|
ReadableMap font = getGlyphFont();
|
||||||
|
float fontSize = (float)font.getDouble("fontSize");
|
||||||
|
|
||||||
if (readableArray != null) {
|
if (readableArray != null) {
|
||||||
for (int i = 0; i < readableArray.size(); i++) {
|
for (int i = 0; i < readableArray.size(); i++) {
|
||||||
arrayList.add((float)readableArray.getDouble(i));
|
switch (readableArray.getType(i)) {
|
||||||
|
case String:
|
||||||
|
String val = readableArray.getString(i);
|
||||||
|
arrayList.add(Float.valueOf(val.substring(0, val.length() - 2)) * fontSize);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Number:
|
||||||
|
arrayList.add((float)readableArray.getDouble(i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,11 @@ import android.graphics.Matrix;
|
|||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Path;
|
import android.graphics.Path;
|
||||||
import android.graphics.Point;
|
import android.graphics.Point;
|
||||||
|
import android.graphics.PointF;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
import com.facebook.react.uimanager.ReactShadowNode;
|
import com.facebook.react.uimanager.ReactShadowNode;
|
||||||
|
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||||
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
@@ -24,8 +27,70 @@ import javax.annotation.Nullable;
|
|||||||
* Shadow node for virtual Group view
|
* Shadow node for virtual Group view
|
||||||
*/
|
*/
|
||||||
public class GroupShadowNode extends RenderableShadowNode {
|
public class GroupShadowNode extends RenderableShadowNode {
|
||||||
|
protected @Nullable ReadableMap mFont;
|
||||||
|
|
||||||
|
private GlyphContext mGlyphContext;
|
||||||
|
private GroupShadowNode mTextRoot;
|
||||||
|
|
||||||
|
@ReactProp(name = "font")
|
||||||
|
public void setFont(@Nullable ReadableMap font) {
|
||||||
|
mFont = font;
|
||||||
|
markUpdated();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected GroupShadowNode getTextRoot() {
|
||||||
|
if (mTextRoot == null) {
|
||||||
|
mTextRoot = this;
|
||||||
|
|
||||||
|
while (mTextRoot != null) {
|
||||||
|
if (mTextRoot.getClass() == GroupShadowNode.class) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReactShadowNode parent = mTextRoot.getParent();
|
||||||
|
|
||||||
|
if (!(parent instanceof GroupShadowNode)) {
|
||||||
|
//todo: throw exception here
|
||||||
|
mTextRoot = null;
|
||||||
|
} else {
|
||||||
|
mTextRoot = (GroupShadowNode)parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return mTextRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setupGlyphContext() {
|
||||||
|
mGlyphContext = new GlyphContext(mScale, getCanvasWidth(), getCanvasHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected GlyphContext getGlyphContext() {
|
||||||
|
return mGlyphContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void pushGlyphContext() {
|
||||||
|
getTextRoot().getGlyphContext().pushContext(mFont);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void popGlyphContext() {
|
||||||
|
getTextRoot().getGlyphContext().popContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ReadableMap getFontFromContext() {
|
||||||
|
return getTextRoot().getGlyphContext().getGlyphFont();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PointF getGlyphPointFromContext(float offset, float glyphWidth) {
|
||||||
|
return getTextRoot().getGlyphContext().getNextGlyphPoint(offset, glyphWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PointF getGlyphDeltaFromContext() {
|
||||||
|
return getTextRoot().getGlyphContext().getNextGlyphDelta();
|
||||||
|
}
|
||||||
|
|
||||||
public void draw(final Canvas canvas, final Paint paint, final float opacity) {
|
public void draw(final Canvas canvas, final Paint paint, final float opacity) {
|
||||||
|
setupGlyphContext();
|
||||||
if (opacity > MIN_OPACITY_FOR_DRAW) {
|
if (opacity > MIN_OPACITY_FOR_DRAW) {
|
||||||
clip(canvas, paint);
|
clip(canvas, paint);
|
||||||
drawGroup(canvas, paint, opacity);
|
drawGroup(canvas, paint, opacity);
|
||||||
@@ -33,6 +98,7 @@ public class GroupShadowNode extends RenderableShadowNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void drawGroup(final Canvas canvas, final Paint paint, final float opacity) {
|
protected void drawGroup(final Canvas canvas, final Paint paint, final float opacity) {
|
||||||
|
pushGlyphContext();
|
||||||
final SvgViewShadowNode svg = getSvgShadowNode();
|
final SvgViewShadowNode svg = getSvgShadowNode();
|
||||||
final GroupShadowNode self = this;
|
final GroupShadowNode self = this;
|
||||||
traverseChildren(new NodeRunnable() {
|
traverseChildren(new NodeRunnable() {
|
||||||
@@ -57,6 +123,7 @@ public class GroupShadowNode extends RenderableShadowNode {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
popGlyphContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void drawPath(Canvas canvas, Paint paint, float opacity) {
|
protected void drawPath(Canvas canvas, Paint paint, float opacity) {
|
||||||
|
|||||||
@@ -43,10 +43,6 @@ public class TextShadowNode extends GroupShadowNode {
|
|||||||
private @Nullable ReadableArray mDeltaY;
|
private @Nullable ReadableArray mDeltaY;
|
||||||
private @Nullable String mPositionX;
|
private @Nullable String mPositionX;
|
||||||
private @Nullable String mPositionY;
|
private @Nullable String mPositionY;
|
||||||
private @Nullable ReadableMap mFont;
|
|
||||||
|
|
||||||
private GlyphContext mGlyphContext;
|
|
||||||
private TextShadowNode mTextRoot;
|
|
||||||
|
|
||||||
@ReactProp(name = "textAnchor", defaultInt = TEXT_ANCHOR_AUTO)
|
@ReactProp(name = "textAnchor", defaultInt = TEXT_ANCHOR_AUTO)
|
||||||
public void setTextAnchor(int textAnchor) {
|
public void setTextAnchor(int textAnchor) {
|
||||||
@@ -108,12 +104,6 @@ public class TextShadowNode extends GroupShadowNode {
|
|||||||
return groupPath;
|
return groupPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void drawGroup(Canvas canvas, Paint paint, float opacity) {
|
|
||||||
pushGlyphContext();
|
|
||||||
super.drawGroup(canvas, paint, opacity);
|
|
||||||
popGlyphContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
private int getTextAnchor() {
|
private int getTextAnchor() {
|
||||||
return mTextAnchor;
|
return mTextAnchor;
|
||||||
}
|
}
|
||||||
@@ -135,33 +125,6 @@ public class TextShadowNode extends GroupShadowNode {
|
|||||||
return anchor;
|
return anchor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TextShadowNode getTextRoot() {
|
|
||||||
if (mTextRoot == null) {
|
|
||||||
mTextRoot = this;
|
|
||||||
|
|
||||||
while (mTextRoot != null) {
|
|
||||||
if (mTextRoot.getClass() == TextShadowNode.class) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReactShadowNode parent = mTextRoot.getParent();
|
|
||||||
|
|
||||||
if (!(parent instanceof TextShadowNode)) {
|
|
||||||
//todo: throw exception here
|
|
||||||
mTextRoot = null;
|
|
||||||
} else {
|
|
||||||
mTextRoot = (TextShadowNode)parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mTextRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setupGlyphContext() {
|
|
||||||
mGlyphContext = new GlyphContext(mScale, getCanvasWidth(), getCanvasHeight());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void releaseCachedPath() {
|
protected void releaseCachedPath() {
|
||||||
traverseChildren(new NodeRunnable() {
|
traverseChildren(new NodeRunnable() {
|
||||||
public boolean run(VirtualNode node) {
|
public boolean run(VirtualNode node) {
|
||||||
@@ -180,30 +143,11 @@ public class TextShadowNode extends GroupShadowNode {
|
|||||||
return groupPath;
|
return groupPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected GlyphContext getGlyphContext() {
|
@Override
|
||||||
return mGlyphContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void pushGlyphContext() {
|
protected void pushGlyphContext() {
|
||||||
getTextRoot().getGlyphContext().pushContext(mFont, mDeltaX, mDeltaY, mPositionX, mPositionY);
|
getTextRoot().getGlyphContext().pushContext(mFont, mDeltaX, mDeltaY, mPositionX, mPositionY);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void popGlyphContext() {
|
|
||||||
getTextRoot().getGlyphContext().popContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ReadableMap getFontFromContext() {
|
|
||||||
return getTextRoot().getGlyphContext().getGlyphFont();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected PointF getGlyphPointFromContext(float offset, float glyphWidth) {
|
|
||||||
return getTextRoot().getGlyphContext().getNextGlyphPoint(offset, glyphWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected PointF getGlyphDeltaFromContext() {
|
|
||||||
return getTextRoot().getGlyphContext().getNextGlyphDelta();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Matrix getAlignMatrix(Path path) {
|
private Matrix getAlignMatrix(Path path) {
|
||||||
RectF box = new RectF();
|
RectF box = new RectF();
|
||||||
path.computeBounds(box, true);
|
path.computeBounds(box, true);
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import createReactNativeComponentClass from 'react-native/Libraries/Renderer/src/renderers/native/createReactNativeComponentClass';
|
import createReactNativeComponentClass from 'react-native/Libraries/Renderer/src/renderers/native/createReactNativeComponentClass';
|
||||||
import Shape from './Shape';
|
import Shape from './Shape';
|
||||||
import {pathProps} from '../lib/props';
|
import {pathProps, fontProps} from '../lib/props';
|
||||||
import {GroupAttributes} from '../lib/attributes';
|
import {GroupAttributes} from '../lib/attributes';
|
||||||
import extractProps from '../lib/extract/extractProps';
|
import extractProps from '../lib/extract/extractProps';
|
||||||
|
import {extractFont} from '../lib/extract/extractText';
|
||||||
|
|
||||||
export default class extends Shape{
|
export default class extends Shape{
|
||||||
static displayName = 'G';
|
static displayName = 'G';
|
||||||
|
|
||||||
static propTypes = pathProps;
|
static propTypes = {
|
||||||
|
...pathProps,
|
||||||
|
...fontProps,
|
||||||
|
};
|
||||||
|
|
||||||
setNativeProps = (...args) => {
|
setNativeProps = (...args) => {
|
||||||
this.root.setNativeProps(...args);
|
this.root.setNativeProps(...args);
|
||||||
@@ -19,6 +23,7 @@ export default class extends Shape{
|
|||||||
|
|
||||||
return <RNSVGGroup
|
return <RNSVGGroup
|
||||||
{...extractProps(props, this)}
|
{...extractProps(props, this)}
|
||||||
|
font={extractFont(props)}
|
||||||
ref={ele => {this.root = ele;}}
|
ref={ele => {this.root = ele;}}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|||||||
@@ -74,7 +74,12 @@ const RenderableAttributes = {
|
|||||||
...FillAndStrokeAttributes
|
...FillAndStrokeAttributes
|
||||||
};
|
};
|
||||||
|
|
||||||
const GroupAttributes = RenderableAttributes;
|
const GroupAttributes = {
|
||||||
|
font: {
|
||||||
|
diff: fontDiffer
|
||||||
|
},
|
||||||
|
...RenderableAttributes
|
||||||
|
};
|
||||||
|
|
||||||
const UseAttributes = {
|
const UseAttributes = {
|
||||||
href: true,
|
href: true,
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ function parseFontString(font) {
|
|||||||
return cachedFontObjectsFromString[font];
|
return cachedFontObjectsFromString[font];
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractFont(props) {
|
export function extractFont(props) {
|
||||||
let font = props.font;
|
let font = props.font;
|
||||||
let fontSize = +props.fontSize;
|
let fontSize = +props.fontSize;
|
||||||
|
|
||||||
@@ -68,8 +68,11 @@ function extractFont(props) {
|
|||||||
|
|
||||||
function parseDelta(delta) {
|
function parseDelta(delta) {
|
||||||
if (typeof delta === 'string') {
|
if (typeof delta === 'string') {
|
||||||
if (isNaN(+delta)) {
|
const trim = delta.trim();
|
||||||
return delta.trim().replace(commaReg, ' ').split(spaceReg).map(d => +d || 0);
|
if (trim.slice(-2) === 'em') {
|
||||||
|
return [trim];
|
||||||
|
} else if (isNaN(+delta)) {
|
||||||
|
return trim.replace(commaReg, ' ').split(spaceReg).map(d => +d || 0);
|
||||||
} else {
|
} else {
|
||||||
return [+delta];
|
return [+delta];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user