fix text context and complete gradient js code

This commit is contained in:
Horcrux
2016-04-26 22:08:54 +08:00
parent 1baf00c034
commit 902bdcb1d0
17 changed files with 72 additions and 154 deletions

View File

@@ -164,7 +164,7 @@ class TextClipping extends Component{
fontWeight="bold" fontWeight="bold"
fill="red" fill="red"
stroke="blue" stroke="blue"
textAnchor="center" textAnchor="middle"
clipPath="url(#clip)" clipPath="url(#clip)"
>NOT THE FACE</Text> >NOT THE FACE</Text>
</Svg>; </Svg>;

View File

@@ -84,7 +84,7 @@ class GTransform extends Component{
y="75" y="75"
stroke="#600" stroke="#600"
fill="#600" fill="#600"
textAnchor="center" textAnchor="middle"
> >
Text grouped with shapes</Text> Text grouped with shapes</Text>
</G> </G>

View File

@@ -76,7 +76,7 @@ class StrokeDashoffset extends Component{
fontWeight="bold" fontWeight="bold"
x="100" x="100"
y="40" y="40"
textAnchor="center" textAnchor="middle"
strokeDasharray="100" strokeDasharray="100"
strokeDashoffset="60" strokeDashoffset="60"
>STROKE</Text> >STROKE</Text>

View File

@@ -22,7 +22,7 @@ class TextExample extends Component{
x="50" x="50"
y="9" y="9"
fill="red" fill="red"
textAnchor="center" textAnchor="middle"
>I love SVG!</Text> >I love SVG!</Text>
</Svg>; </Svg>;
} }
@@ -81,7 +81,7 @@ class TextFill extends Component{
fontWeight="bold" fontWeight="bold"
x="100" x="100"
y="20" y="20"
textAnchor="center" textAnchor="middle"
>FILL TEXT</Text> >FILL TEXT</Text>
</Svg>; </Svg>;
} }
@@ -109,7 +109,7 @@ class TextStroke extends Component{
fontWeight="bold" fontWeight="bold"
x="100" x="100"
y="20" y="20"
textAnchor="center" textAnchor="middle"
>STROKE TEXT</Text> >STROKE TEXT</Text>
</Svg>; </Svg>;
} }
@@ -148,7 +148,7 @@ const icon = <Svg
y="2" y="2"
fontSize="14" fontSize="14"
fontWeight="bold" fontWeight="bold"
textAnchor="center" textAnchor="middle"
fill="none" fill="none"
stroke="blue" stroke="blue"
></Text> ></Text>

View File

@@ -9,7 +9,7 @@ import createReactNativeComponentClass from 'react-native/Libraries/ReactNative/
import Defs from './Defs'; import Defs from './Defs';
import _ from 'lodash'; import _ from 'lodash';
import {GroupAttributes} from '../lib/attributes'; import {GroupAttributes} from '../lib/attributes';
import {numberProp, shapeProps} from '../lib/props'; import {numberProp, contextProps, textProps} from '../lib/props';
import extractProps from '../lib/extract/extractProps'; import extractProps from '../lib/extract/extractProps';
@@ -19,11 +19,11 @@ class G extends Component{
static childContextTypes = { static childContextTypes = {
svgId: numberProp, svgId: numberProp,
isInGroup: PropTypes.bool, isInGroup: PropTypes.bool,
...shapeProps ...contextProps
}; };
getChildContext = () => { getChildContext = () => {
return _.reduce(shapeProps, (props, value, key) => { return _.reduce(contextProps, (props, value, key) => {
props[key] = this.props[key]; props[key] = this.props[key];
return props; return props;
}, { }, {

View File

@@ -5,7 +5,6 @@ import React, {
} from 'react-native'; } from 'react-native';
import {NativeGroup} from './G'; import {NativeGroup} from './G';
import {set, remove} from '../lib/extract/patterns'; import {set, remove} from '../lib/extract/patterns';
import percentFactory from '../lib/percentFactory';
import percentToFloat from '../lib/percentToFloat'; import percentToFloat from '../lib/percentToFloat';
import Stop from './Stop'; import Stop from './Stop';
import Color from 'color'; import Color from 'color';
@@ -28,7 +27,7 @@ class RadialGradient extends Component{
remove(this.id); remove(this.id);
}; };
render(distanceProps, fromPercent, fromNumber) { render(generator) {
let stops = {}; let stops = {};
Children.forEach(this.props.children, child => { Children.forEach(this.props.children, child => {
if (child.type === Stop && child.props.stopColor && child.props.offset) { if (child.type === Stop && child.props.stopColor && child.props.offset) {
@@ -37,13 +36,7 @@ class RadialGradient extends Component{
// add stop // add stop
stops[offset] = Color(child.props.stopColor).alpha(+child.props.stopOpacity); stops[offset] = Color(child.props.stopColor).alpha(+child.props.stopOpacity);
set(this.id, generator.bind(null, stops));
let factories = percentFactory(...distanceProps);
if (factories) {
set(this.id, fromPercent.bind(null, factories, stops));
} else {
set(this.id, fromNumber.bind(null, stops));
}
} else { } else {
console.warn(`'RadialGradient' can only receive 'Stop' elements as children`); console.warn(`'RadialGradient' can only receive 'Stop' elements as children`);
} }

View File

@@ -11,26 +11,7 @@ import {LINEAR_GRADIENT} from '../lib/extract/extractBrush';
import insertColorStopsIntoArray from '../lib/insertProcessor'; import insertColorStopsIntoArray from '../lib/insertProcessor';
function LinearGradientGenerator(stops, x1, y1, x2, y2) { function LinearGradientGenerator(stops, x1, y1, x2, y2) {
var type = LINEAR_GRADIENT; var brushData = [LINEAR_GRADIENT, x1, y1, x2, y2];
if (arguments.length < 5) {
var angle = ((x1 == null) ? 270 : x1) * Math.PI / 180;
var x = Math.cos(angle);
var y = -Math.sin(angle);
var l = (Math.abs(x) + Math.abs(y)) / 2;
x *= l; y *= l;
x1 = 0.5 - x;
x2 = 0.5 + x;
y1 = 0.5 - y;
y2 = 0.5 + y;
this._bb = true;
} else {
this._bb = false;
}
var brushData = [type, +x1, +y1, +x2, +y2];
insertColorStopsIntoArray(stops, brushData, 5); insertColorStopsIntoArray(stops, brushData, 5);
this._brush = brushData; this._brush = brushData;
} }
@@ -53,20 +34,9 @@ class LinearGradient extends Gradient{
x2, x2,
y2 y2
} = this.props; } = this.props;
let gradientProps = [x1, y1, x2, y2];
return super.render( return super.render(
gradientProps, (stops, opacity) => {
function (factories, stops, boundingBox, opacity) { return new LinearGradientGenerator(stopsOpacity(stops, opacity), ...[x1, y1, x2, y2]);
return new LinearGradientGenerator(
stopsOpacity(stops, opacity),
factories[0](boundingBox.width),
factories[1](boundingBox.height),
factories[2](boundingBox.width),
factories[3](boundingBox.height)
);
},
function (stops, opacity) {
return new LinearGradientGenerator(stopsOpacity(stops, opacity), ...gradientProps);
} }
); );
} }

View File

@@ -11,28 +11,7 @@ import insertColorStopsIntoArray from '../lib/insertProcessor';
function RadialGradientGenerator(stops, fx, fy, rx, ry, cx, cy) { function RadialGradientGenerator(stops, fx, fy, rx, ry, cx, cy) {
if (ry == null) { var brushData = [RADIAL_GRADIENT, fx, fy, rx, ry, cx, cy];
ry = rx;
}
if (cx == null) {
cx = fx;
}
if (cy == null) {
cy = fy;
}
if (fx == null) {
// As a convenience we allow the whole radial gradient to cover the
// bounding box. We should consider dropping this API.
fx = fy = rx = ry = cx = cy = 0.5;
this._bb = true;
} else {
this._bb = false;
}
// The ART API expects the radial gradient to be repeated at the edges.
// To simulate this we render the gradient twice as large and add double
// color stops. Ideally this API would become more restrictive so that this
// extra work isn't needed.
var brushData = [RADIAL_GRADIENT, +fx, +fy, +rx * 2, +ry * 2, +cx, +cy];
insertColorStopsIntoArray(stops, brushData, 7, 0.5); insertColorStopsIntoArray(stops, brushData, 7, 0.5);
this._brush = brushData; this._brush = brushData;
} }
@@ -60,24 +39,10 @@ class RadialGradient extends Gradient{
cy, cy,
r r
} = this.props; } = this.props;
let gradientProps = [fx, fy, rx || r, ry || r, cx, cy];
return super.render( return super.render(
gradientProps, (stops, opacity) => {
function (factories, stops, boundingBox, opacity) {
let {x1,y1,width, height} = boundingBox; return new RadialGradientGenerator(stopsOpacity(stops, opacity), ...[fx, fy, rx || r, ry || r, cx, cy]);
return new RadialGradientGenerator(
stopsOpacity(stops, opacity),
x1 + factories[0](width),
y1 + factories[1](height),
factories[2](width),
factories[3](height),
x1 + factories[4](width),
y1 + factories[5](height)
);
},
function (stops, opacity) {
return new RadialGradientGenerator(stopsOpacity(stops, opacity), ...gradientProps);
} }
); );
} }

View File

@@ -1,24 +1,41 @@
import React, { import React, {
Component Component,
PropTypes
} from 'react-native'; } from 'react-native';
import Defs from './Defs'; import Defs from './Defs';
import createReactNativeComponentClass from 'react-native/Libraries/ReactNative/createReactNativeComponentClass'; import createReactNativeComponentClass from 'react-native/Libraries/ReactNative/createReactNativeComponentClass';
import extractProps from '../lib/extract/extractProps'; import extractProps from '../lib/extract/extractProps';
import extractText from '../lib/extract/extractText'; import extractText from '../lib/extract/extractText';
import {TextAttributes} from '../lib/attributes'; import {TextAttributes} from '../lib/attributes';
import {numberProp} from '../lib/props'; import {numberProp, textProps, fillProps, strokeProps, pathProps} from '../lib/props';
class Text extends Component{ class Text extends Component{
static displayName = 'Text'; static displayName = 'Text';
static propTypes = { static propTypes = {
x: numberProp,
y: numberProp,
dx: numberProp, dx: numberProp,
dy: numberProp dy: numberProp,
...textProps,
...fillProps,
...strokeProps,
...pathProps
}; };
static contextTypes = {
...textProps,
...fillProps,
...strokeProps,
isInGroup: PropTypes.bool
};
render() { render() {
let {props} = this; let {props} = this;
if (this.context.isInGroup) {
props = _.defaults(this.context, props, {
isInGroup: null
});
}
let x = 0; let x = 0;
if (props.x) { if (props.x) {
x = props.dx ? +props.x + (+props.dx) : +props.x; x = props.dx ? +props.x + (+props.dx) : +props.x;

View File

@@ -20,6 +20,7 @@ class ViewBox extends Component{
x = viewbox.x; x = viewbox.x;
y = viewbox.y; y = viewbox.y;
} }
return <G return <G
{...this.props} {...this.props}
x={x} x={x}

View File

@@ -4,41 +4,11 @@ const LINEAR_GRADIENT = 1;
const RADIAL_GRADIENT = 2; const RADIAL_GRADIENT = 2;
const PATTERN = 3; const PATTERN = 3;
function applyBoundingBoxToBrushData(brushData, props) { export default function (colorOrBrush) {
let type = brushData[0];
let width = +props.width;
let height = +props.height;
if (type === LINEAR_GRADIENT) {
brushData[1] *= width;
brushData[2] *= height;
brushData[3] *= width;
brushData[4] *= height;
} else if (type === RADIAL_GRADIENT) {
brushData[1] *= width;
brushData[2] *= height;
brushData[3] *= width;
brushData[4] *= height;
brushData[5] *= width;
brushData[6] *= height;
} else if (type === PATTERN) {
// todo
}
}
export default function (colorOrBrush, props) {
if (!colorOrBrush) { if (!colorOrBrush) {
return null; return null;
} }
if (colorOrBrush._brush) { if (colorOrBrush._brush) {
if (colorOrBrush._bb) {
// The legacy API for Gradients allow for the bounding box to be used
// as a convenience for specifying gradient positions. This should be
// deprecated. It's not properly implemented in canvas mode. ReactART
// doesn't handle update to the bounding box correctly. That's why we
// mutate this so that if it's reused, we reuse the same resolved box.
applyBoundingBoxToBrushData(colorOrBrush._brush, props);
colorOrBrush._bb = false;
}
return colorOrBrush._brush; return colorOrBrush._brush;
} }
@@ -48,5 +18,6 @@ export default function (colorOrBrush, props) {
export { export {
LINEAR_GRADIENT, LINEAR_GRADIENT,
RADIAL_GRADIENT RADIAL_GRADIENT,
PATTERN
} }

View File

@@ -7,13 +7,13 @@ const fillRules = {
nonzero: 1 nonzero: 1
}; };
function fillFilter(props, dimensions) { function fillFilter(props) {
let {fill} = props; let {fill} = props;
if (fill === 'none') { if (fill === 'none') {
return null; return null;
} else if (fill) { } else if (fill) {
return patterns(fill, +props.fillOpacity, dimensions, props.svgId); return patterns(fill, +props.fillOpacity, props.svgId);
} else if (props.fill === undefined) { } else if (props.fill === undefined) {
let fillOpacity = +props.fillOpacity; let fillOpacity = +props.fillOpacity;
if (isNaN(fillOpacity)) { if (isNaN(fillOpacity)) {
@@ -25,8 +25,8 @@ function fillFilter(props, dimensions) {
} }
} }
export default function(props, dimensions) { export default function(props) {
let fill = extractBrush(fillFilter(props, dimensions), props); let fill = extractBrush(fillFilter(props), props);
let fillRule = fillRules[props.fillRule] === 0 ? 0 : 1; let fillRule = fillRules[props.fillRule] === 0 ? 0 : 1;
return { return {

View File

@@ -14,18 +14,16 @@ export default function(props, options = {stroke: true, join: true, transform: t
opacity: +props.opacity || 1 opacity: +props.opacity || 1
}; };
let dimensions = this.getBoundingBox ? this.getBoundingBox() : null;
if (props.clipPath) { if (props.clipPath) {
_.assign(extractedProps, extractClipping(props)); _.assign(extractedProps, extractClipping(props));
} }
if (options.stroke) { if (options.stroke) {
_.assign(extractedProps, extractStroke(props, dimensions)); _.assign(extractedProps, extractStroke(props));
} }
if (options.fill) { if (options.fill) {
_.assign(extractedProps, extractFill(props, dimensions)); _.assign(extractedProps, extractFill(props));
} }
if (options.transform) { if (options.transform) {

View File

@@ -15,7 +15,7 @@ const joins = {
round: 1 round: 1
}; };
function strokeFilter(props, dimensions) { function strokeFilter(props) {
let strokeWidth = +props.strokeWidth; let strokeWidth = +props.strokeWidth;
let {stroke} = props; let {stroke} = props;
if (!strokeWidth && !stroke) { if (!strokeWidth && !stroke) {
@@ -39,7 +39,7 @@ function strokeFilter(props, dimensions) {
// TODO: propTypes check // TODO: propTypes check
return { return {
stroke: patterns(stroke, +props.strokeOpacity, dimensions, props.svgId), stroke: patterns(stroke, +props.strokeOpacity, props.svgId),
strokeLinecap: caps[props.strokeLinecap] || 0, strokeLinecap: caps[props.strokeLinecap] || 0,
strokeLinejoin: joins[props.strokeLinejoin] || 0, strokeLinejoin: joins[props.strokeLinejoin] || 0,
strokeDasharray: strokeDasharray || null, strokeDasharray: strokeDasharray || null,
@@ -48,8 +48,8 @@ function strokeFilter(props, dimensions) {
}; };
} }
export default function(props, dimensions) { export default function(props) {
let strokeProps = strokeFilter(props, dimensions); let strokeProps = strokeFilter(props);
return strokeProps ? { return strokeProps ? {
...strokeProps, ...strokeProps,

View File

@@ -76,9 +76,9 @@ function extractFont(font) {
} }
const anchord = { const anchord = {
right: 1, end: 1,
center: 2, middle: 2,
left: 0 start: 0
}; };
export default function(props) { export default function(props) {

View File

@@ -23,7 +23,7 @@ export {
remove remove
} }
export default function(patternSting, opacity, dimensions, svgId) { export default function(patternSting, opacity, svgId) {
if (isGradient(patternSting)) { if (isGradient(patternSting)) {
return patternSting; return patternSting;
} }
@@ -40,12 +40,8 @@ export default function(patternSting, opacity, dimensions, svgId) {
let pattern = patterns[patternName]; let pattern = patterns[patternName];
if (pattern) { if (pattern) {
if (pattern.length === 2) {
return pattern(dimensions, opacity);
} else {
return pattern(opacity); return pattern(opacity);
} }
}
return null; return null;
} }

View File

@@ -26,8 +26,14 @@ const strokeProps = {
}; };
const textProps = { const textProps = {
textAnchor: PropTypes.oneOf(['right', 'center', 'left']), textAnchor: PropTypes.oneOf(['start', 'middle', 'end']),
path: PropTypes.string path: PropTypes.string,
fontFamily: PropTypes.string,
fontSize: numberProp,
fontWeight: PropTypes.string,
fontStyle: PropTypes.string,
font: PropTypes.object,
lines: numberProp
}; };
const transformProps = { const transformProps = {
@@ -78,13 +84,14 @@ const rectProps = {
ry: numberProp ry: numberProp
}; };
const shapeProps = { const contextProps = {
...circleProps, ...circleProps,
...ellipseProps, ...ellipseProps,
...lineProps, ...lineProps,
...rectProps, ...rectProps,
...fillProps, ...fillProps,
...strokeProps ...strokeProps,
...textProps
}; };
export { export {
@@ -98,6 +105,6 @@ export {
ellipseProps, ellipseProps,
lineProps, lineProps,
rectProps, rectProps,
shapeProps, contextProps,
pathProps pathProps
} }