mirror of
https://github.com/zoriya/react-native-svg.git
synced 2026-06-01 22:25:12 +00:00
Implement basic support for Pattern element
This commit is contained in:
@@ -9,6 +9,9 @@
|
||||
|
||||
package com.horcrux.svg;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Matrix;
|
||||
@@ -23,12 +26,14 @@ import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
|
||||
class Brush {
|
||||
private BrushType mType = BrushType.LINEAR_GRADIENT;
|
||||
private BrushType mType;
|
||||
private final ReadableArray mPoints;
|
||||
private ReadableArray mColors;
|
||||
private final boolean mUseObjectBoundingBox;
|
||||
private boolean mUseContentObjectBoundingBox;
|
||||
private Matrix mMatrix;
|
||||
private Rect mUserSpaceBoundingBox;
|
||||
PatternShadowNode mPattern;
|
||||
|
||||
Brush(BrushType type, ReadableArray points, BrushUnits units) {
|
||||
mType = type;
|
||||
@@ -36,6 +41,14 @@ class Brush {
|
||||
mUseObjectBoundingBox = units == BrushUnits.OBJECT_BOUNDING_BOX;
|
||||
}
|
||||
|
||||
void setContentUnits(BrushUnits units) {
|
||||
mUseContentObjectBoundingBox = units == BrushUnits.OBJECT_BOUNDING_BOX;
|
||||
}
|
||||
|
||||
void setPattern(PatternShadowNode pattern) {
|
||||
mPattern = pattern;
|
||||
}
|
||||
|
||||
enum BrushType {
|
||||
LINEAR_GRADIENT(0),
|
||||
RADIAL_GRADIENT(1),
|
||||
@@ -105,6 +118,35 @@ class Brush {
|
||||
float offsetX = rect.left;
|
||||
float offsetY = rect.top;
|
||||
|
||||
if (mType == BrushType.PATTERN) {
|
||||
double x = PropHelper.fromRelative(mPoints.getString(0), width, offsetX, scale, paint.getTextSize());
|
||||
double y = PropHelper.fromRelative(mPoints.getString(1), height, offsetY, scale, paint.getTextSize());
|
||||
double w = PropHelper.fromRelative(mPoints.getString(2), width, offsetX, scale, paint.getTextSize());
|
||||
double h = PropHelper.fromRelative(mPoints.getString(3), height, offsetY, scale, paint.getTextSize());
|
||||
|
||||
RectF vbRect = mPattern.getViewBox();
|
||||
RectF eRect = new RectF((float)x, (float)y, (float)w, (float)h);
|
||||
Matrix mViewBoxMatrix = ViewBox.getTransform(vbRect, eRect, mPattern.mAlign, mPattern.mMeetOrSlice);
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(
|
||||
(int) w,
|
||||
(int) h,
|
||||
Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
canvas.concat(mViewBoxMatrix);
|
||||
mPattern.draw(canvas, new Paint(), opacity);
|
||||
|
||||
Matrix patternMatrix = new Matrix();
|
||||
if (mMatrix != null) {
|
||||
patternMatrix.preConcat(mMatrix);
|
||||
}
|
||||
|
||||
BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
|
||||
bitmapShader.setLocalMatrix(patternMatrix);
|
||||
paint.setShader(bitmapShader);
|
||||
return;
|
||||
}
|
||||
|
||||
int stopsCount = mColors.size() / 5;
|
||||
int[] stopsColors = new int[stopsCount];
|
||||
float[] stops = new float[stopsCount];
|
||||
@@ -170,12 +212,5 @@ class Brush {
|
||||
radialGradient.setLocalMatrix(radialMatrix);
|
||||
paint.setShader(radialGradient);
|
||||
}
|
||||
// else {
|
||||
// todo: pattern support
|
||||
|
||||
//Shader mShader1 = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
|
||||
//paint.setShader(mShader1);
|
||||
//bitmap.recycle();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
|
||||
package com.horcrux.svg;
|
||||
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.RectF;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Shadow node for virtual Pattern definition view
|
||||
*/
|
||||
class PatternShadowNode extends GroupShadowNode {
|
||||
|
||||
private String mX;
|
||||
private String mY;
|
||||
private String mWidth;
|
||||
private String mHeight;
|
||||
private Brush.BrushUnits mPatternUnits;
|
||||
private Brush.BrushUnits mPatternContentUnits;
|
||||
|
||||
private float mMinX;
|
||||
private float mMinY;
|
||||
private float mVbWidth;
|
||||
private float mVbHeight;
|
||||
String mAlign;
|
||||
int mMeetOrSlice;
|
||||
|
||||
private static final float[] sRawMatrix = new float[]{
|
||||
1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1
|
||||
};
|
||||
private Matrix mMatrix = null;
|
||||
|
||||
@ReactProp(name = "x")
|
||||
public void setX(String x) {
|
||||
mX = x;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "y")
|
||||
public void setY(String y) {
|
||||
mY = y;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "patternwidth")
|
||||
public void setWidth(String width) {
|
||||
mWidth = width;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "patternheight")
|
||||
public void setHeight(String height) {
|
||||
mHeight = height;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "patternUnits")
|
||||
public void setPatternUnits(int patternUnits) {
|
||||
switch (patternUnits) {
|
||||
case 0:
|
||||
mPatternUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
||||
break;
|
||||
case 1:
|
||||
mPatternUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
||||
break;
|
||||
}
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "patternContentUnits")
|
||||
public void setPatternContentUnits(int patternContentUnits) {
|
||||
switch (patternContentUnits) {
|
||||
case 0:
|
||||
mPatternContentUnits = Brush.BrushUnits.OBJECT_BOUNDING_BOX;
|
||||
break;
|
||||
case 1:
|
||||
mPatternContentUnits = Brush.BrushUnits.USER_SPACE_ON_USE;
|
||||
break;
|
||||
}
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "patternTransform")
|
||||
public void setPatternTransform(@Nullable ReadableArray matrixArray) {
|
||||
if (matrixArray != null) {
|
||||
int matrixSize = PropHelper.toMatrixData(matrixArray, sRawMatrix, mScale);
|
||||
if (matrixSize == 6) {
|
||||
if (mMatrix == null) {
|
||||
mMatrix = new Matrix();
|
||||
}
|
||||
mMatrix.setValues(sRawMatrix);
|
||||
} else if (matrixSize != -1) {
|
||||
FLog.w(ReactConstants.TAG, "RNSVG: Transform matrices must be of size 6");
|
||||
}
|
||||
} else {
|
||||
mMatrix = null;
|
||||
}
|
||||
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "minX")
|
||||
public void setMinX(float minX) {
|
||||
mMinX = minX;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "minY")
|
||||
public void setMinY(float minY) {
|
||||
mMinY = minY;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "vbWidth")
|
||||
public void setVbWidth(float vbWidth) {
|
||||
mVbWidth = vbWidth;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "vbHeight")
|
||||
public void setVbHeight(float vbHeight) {
|
||||
mVbHeight = vbHeight;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "align")
|
||||
public void setAlign(String align) {
|
||||
mAlign = align;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
@ReactProp(name = "meetOrSlice")
|
||||
public void setMeetOrSlice(int meetOrSlice) {
|
||||
mMeetOrSlice = meetOrSlice;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
|
||||
RectF getViewBox() {
|
||||
return new RectF(mMinX * mScale, mMinY * mScale, (mMinX + mVbWidth) * mScale, (mMinY + mVbHeight) * mScale);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void saveDefinition() {
|
||||
if (mName != null) {
|
||||
WritableArray points = Arguments.createArray();
|
||||
points.pushString(mX);
|
||||
points.pushString(mY);
|
||||
points.pushString(mWidth);
|
||||
points.pushString(mHeight);
|
||||
|
||||
Brush brush = new Brush(Brush.BrushType.PATTERN, points, mPatternUnits);
|
||||
brush.setContentUnits(mPatternContentUnits);
|
||||
brush.setPattern(this);
|
||||
|
||||
if (mMatrix != null) {
|
||||
brush.setGradientTransform(mMatrix);
|
||||
}
|
||||
|
||||
SvgViewShadowNode svg = getSvgShadowNode();
|
||||
if (mPatternUnits == Brush.BrushUnits.USER_SPACE_ON_USE || mPatternContentUnits == Brush.BrushUnits.USER_SPACE_ON_USE) {
|
||||
brush.setUserSpaceBoundingBox(svg.getCanvasBounds());
|
||||
}
|
||||
|
||||
svg.defineBrush(brush, mName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,6 +49,7 @@ class RenderableViewManager<T extends VirtualNode> extends ViewGroupManager<Rend
|
||||
/* package */ private static final String CLASS_SYMBOL = "RNSVGSymbol";
|
||||
/* package */ private static final String CLASS_LINEAR_GRADIENT = "RNSVGLinearGradient";
|
||||
/* package */ private static final String CLASS_RADIAL_GRADIENT = "RNSVGRadialGradient";
|
||||
/* package */ private static final String CLASS_PATTERN = "RNSVGPattern";
|
||||
|
||||
private final String mClassName;
|
||||
|
||||
@@ -389,6 +390,76 @@ class RenderableViewManager<T extends VirtualNode> extends ViewGroupManager<Rend
|
||||
};
|
||||
}
|
||||
|
||||
static RenderableViewManager<PatternShadowNode> createPatternManager() {
|
||||
return new RenderableViewManager<PatternShadowNode>(CLASS_PATTERN) {
|
||||
|
||||
@ReactProp(name = "x")
|
||||
public void setX(RenderableView<PatternShadowNode> node, String x) {
|
||||
node.shadowNode.setX(x);
|
||||
}
|
||||
|
||||
@ReactProp(name = "y")
|
||||
public void setY(RenderableView<PatternShadowNode> node, String y) {
|
||||
node.shadowNode.setY(y);
|
||||
}
|
||||
|
||||
@ReactProp(name = "patternwidth")
|
||||
public void setWidth(RenderableView<PatternShadowNode> node, String width) {
|
||||
node.shadowNode.setWidth(width);
|
||||
}
|
||||
|
||||
@ReactProp(name = "patternheight")
|
||||
public void setHeight(RenderableView<PatternShadowNode> node, String height) {
|
||||
node.shadowNode.setHeight(height);
|
||||
}
|
||||
|
||||
@ReactProp(name = "patternUnits")
|
||||
public void setPatternUnits(RenderableView<PatternShadowNode> node, int patternUnits) {
|
||||
node.shadowNode.setPatternUnits(patternUnits);
|
||||
}
|
||||
|
||||
@ReactProp(name = "patternContentUnits")
|
||||
public void setPatternContentUnits(RenderableView<PatternShadowNode> node, int patternContentUnits) {
|
||||
node.shadowNode.setPatternContentUnits(patternContentUnits);
|
||||
}
|
||||
|
||||
@ReactProp(name = "patternTransform")
|
||||
public void setPatternTransform(RenderableView<PatternShadowNode> node, @Nullable ReadableArray matrixArray) {
|
||||
node.shadowNode.setPatternTransform(matrixArray);
|
||||
}
|
||||
|
||||
@ReactProp(name = "minX")
|
||||
public void setMinX(RenderableView<PatternShadowNode> node, float minX) {
|
||||
node.shadowNode.setMinX(minX);
|
||||
}
|
||||
|
||||
@ReactProp(name = "minY")
|
||||
public void setMinY(RenderableView<PatternShadowNode> node, float minY) {
|
||||
node.shadowNode.setMinY(minY);
|
||||
}
|
||||
|
||||
@ReactProp(name = "vbWidth")
|
||||
public void setVbWidth(RenderableView<PatternShadowNode> node, float vbWidth) {
|
||||
node.shadowNode.setVbWidth(vbWidth);
|
||||
}
|
||||
|
||||
@ReactProp(name = "vbHeight")
|
||||
public void setVbHeight(RenderableView<PatternShadowNode> node, float vbHeight) {
|
||||
node.shadowNode.setVbHeight(vbHeight);
|
||||
}
|
||||
|
||||
@ReactProp(name = "align")
|
||||
public void setAlign(RenderableView<PatternShadowNode> node, String align) {
|
||||
node.shadowNode.setAlign(align);
|
||||
}
|
||||
|
||||
@ReactProp(name = "meetOrSlice")
|
||||
public void setMeetOrSlice(RenderableView<PatternShadowNode> node, int meetOrSlice) {
|
||||
node.shadowNode.setMeetOrSlice(meetOrSlice);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static RenderableViewManager<LinearGradientShadowNode> createLinearGradientManager() {
|
||||
return new RenderableViewManager<LinearGradientShadowNode>(CLASS_LINEAR_GRADIENT) {
|
||||
|
||||
@@ -523,6 +594,8 @@ class RenderableViewManager<T extends VirtualNode> extends ViewGroupManager<Rend
|
||||
return new LinearGradientShadowNode();
|
||||
case CLASS_RADIAL_GRADIENT:
|
||||
return new RadialGradientShadowNode();
|
||||
case CLASS_PATTERN:
|
||||
return new PatternShadowNode();
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected type " + mClassName);
|
||||
}
|
||||
@@ -563,6 +636,8 @@ class RenderableViewManager<T extends VirtualNode> extends ViewGroupManager<Rend
|
||||
return LinearGradientShadowNode.class;
|
||||
case CLASS_RADIAL_GRADIENT:
|
||||
return RadialGradientShadowNode.class;
|
||||
case CLASS_PATTERN:
|
||||
return PatternShadowNode.class;
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected type " + mClassName);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ public class SvgPackage implements ReactPackage {
|
||||
RenderableViewManager.createSymbolManager(),
|
||||
RenderableViewManager.createLinearGradientManager(),
|
||||
RenderableViewManager.createRadialGradientManager(),
|
||||
RenderableViewManager.createPatternManager(),
|
||||
new SvgViewManager());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user